From 79af7d3c0053eb4d7fc673c449ef65c8f594233b Mon Sep 17 00:00:00 2001 From: Yuriy Toporovskyy Date: Thu, 5 Aug 2021 17:47:19 -0400 Subject: [PATCH 001/293] Make the maximum amount of vmem available for skinning related things configurable at runtime Signed-off-by: Yuriy Toporovskyy --- .../SkinnedMeshOutputStreamManager.cpp | 33 ++++++++++++++++++- .../SkinnedMeshOutputStreamManager.h | 3 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp index c4eac30431..ffbe850160 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include @@ -72,11 +74,36 @@ namespace AZ creator.End(m_bufferAsset); } + AZ_CVAR( + int, + r_skinnedMeshInstanceMemoryPoolSize, + 256, + nullptr, + AZ::ConsoleFunctorFlags::NeedsReload, + "The amount of memory in Mb available for all actor skinning data. Note that this must only be set once at application startup" + ); + void SkinnedMeshOutputStreamManager::Init() { + } + + void SkinnedMeshOutputStreamManager::EnsureInit() const + { + const_cast(this)->EnsureInit(); + } + + void SkinnedMeshOutputStreamManager::EnsureInit() + { + if (!m_needsInit) + { + return; + } + m_needsInit = false; + // 256mb supports roughly 42 character instances at 100,000 vertices per character x 64 bytes per vertex (12 byte position + 12 byte previous frame position + 12 byte normal + 16 byte tangent + 12 byte bitangent) // This includes only the output of the skinning compute shader, not the input buffers or bone transforms - m_sizeInBytes = 256u * (1024u * 1024u); + const AZ::u64 sizeInMb = r_skinnedMeshInstanceMemoryPoolSize; + m_sizeInBytes = AZ::GetMax(sizeInMb, 256ull) * (1024u * 1024u); CalculateAlignment(); @@ -90,6 +117,8 @@ namespace AZ RHI::VirtualAddress result; { AZStd::lock_guard lock(m_allocatorMutex); + + EnsureInit(); result = m_freeListAllocator.Allocate(byteCount, m_alignment); } @@ -129,11 +158,13 @@ namespace AZ Data::Asset SkinnedMeshOutputStreamManager::GetBufferAsset() const { + EnsureInit(); return m_bufferAsset; } Data::Instance SkinnedMeshOutputStreamManager::GetBuffer() { + EnsureInit(); if (!m_buffer) { m_buffer = RPI::Buffer::FindOrCreate(m_bufferAsset); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h index 3cec34a2e2..6009a62362 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h @@ -46,6 +46,8 @@ namespace AZ // SystemTickBus void OnSystemTick() override; + void EnsureInit() const; + void EnsureInit(); void GarbageCollect(); void CalculateAlignment(); void CreateBufferAsset(); @@ -58,6 +60,7 @@ namespace AZ size_t m_sizeInBytes = 0; bool m_memoryWasFreed = false; bool m_broadcastMemoryAvailableEvent = false; + bool m_needsInit = true; }; } // namespace Render } // namespace AZ From 5cee8d18929c10b2bd67cbaaab0554e916360648 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 10 Sep 2021 10:59:40 -0700 Subject: [PATCH 002/293] stubbed out refactor of version explorer Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Windows/MainWindow.cpp | 71 -- .../Code/Editor/View/Windows/MainWindow.h | 3 - .../Windows/Tools/UpgradeTool/FileSaver.cpp | 1023 +++++++++++++++++ .../Windows/Tools/UpgradeTool/FileSaver.h | 180 +++ .../Windows/Tools/UpgradeTool/Modifier.cpp | 1023 +++++++++++++++++ .../View/Windows/Tools/UpgradeTool/Modifier.h | 167 +++ .../Windows/Tools/UpgradeTool/Scanner.cpp | 1023 +++++++++++++++++ .../View/Windows/Tools/UpgradeTool/Scanner.h | 167 +++ .../Windows/Tools/UpgradeTool/UpgradeTool.cpp | 697 ----------- .../Windows/Tools/UpgradeTool/UpgradeTool.h | 149 --- .../Windows/Tools/UpgradeTool/UpgradeTool.ui | 260 ----- .../Tools/UpgradeTool/VersionExplorer.h | 10 +- .../Tools/UpgradeTool/VersionExplorerLog.cpp | 1023 +++++++++++++++++ .../Tools/UpgradeTool/VersionExplorerLog.h | 167 +++ .../Tools/UpgradeTool/VersionExplorerTraits.h | 19 + .../Code/scriptcanvasgem_editor_files.cmake | 11 +- 16 files changed, 4803 insertions(+), 1190 deletions(-) create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h delete mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp delete mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h delete mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.ui create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index fbe03ffc0a..856cceb508 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -704,78 +704,7 @@ namespace ScriptCanvasEditor m_autoSaveTimer.setSingleShot(true); connect(&m_autoSaveTimer, &QTimer::timeout, this, &MainWindow::OnAutoSave); - UpdateMenuState(false); - - PromptForUpgrade(); - } - - void MainWindow::PromptForUpgrade() - { - static bool displayUpgradePrompt = false; // Set to true if you need the upgrade dialog to show up on ScriptCanvas editor open - if (displayUpgradePrompt && m_showUpgradeTool) - { - QTimer::singleShot(1.f, this, [this]() - { - UpgradeTool* upgradeTool = aznew UpgradeTool(this); - - QPoint centerPoint = frameGeometry().center(); - - upgradeTool->adjustSize(); - upgradeTool->move(centerPoint.x() - upgradeTool->width() / 2, centerPoint.y() - upgradeTool->height() / 2); - - if (upgradeTool->exec() == QDialog::Accepted) - { - // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - QString message = QObject::tr("%1 Graph(s) upgraded
%2 graph(s) did not require upgrade").arg(upgradeTool->UpgradedGraphCount()).arg(upgradeTool->SkippedGraphCount()); - if (assetsThatNeedManualInspection > 0) - { - message.append(QObject::tr("
%1 graph(s) that need manual corrections. You will be prompted to review them after you close this dialog.
").arg(assetsThatNeedManualInspection)); - } - - // Report - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string outputFileName = AZStd::string::format("@devroot@/ScriptCanvasUpgradeReport.html"); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZStd::string urlToReport = AZStd::string::format("For more information see the Upgrade Report.", resolvedBuffer); - message.append(QObject::tr("
%1").arg(urlToReport.c_str())); - - // Backup - if (upgradeTool->HasBackup()) - { - AZStd::string outputFileName2 = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP"); - - AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName2.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - - AZStd::string backupPath = AZStd::string::format("
Open the Backup Folder.", resolvedBuffer); - message.append(QObject::tr("%1").arg(backupPath.c_str())); - } - - // Done upgrading, show details - QMessageBox mb(QMessageBox::Information, - QObject::tr("Upgrade Complete"), - message, - QMessageBox::Ok, this); - mb.setTextFormat(Qt::RichText); - - centerPoint = frameGeometry().center(); - - mb.adjustSize(); - mb.move(centerPoint.x() - width() / 2, centerPoint.y() - height() / 2); - - mb.exec(); - - // If there are graphs that need manual correction, show the helper - if (assetsThatNeedManualInspection > 0) - { - UpgradeHelper* upgradeHelper = new UpgradeHelper(this); - upgradeHelper->show(); - } - } - - }); - } } MainWindow::~MainWindow() diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index d11d2f0052..ed00254677 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -51,7 +51,6 @@ #include -#include #include #if SCRIPTCANVAS_EDITOR @@ -806,7 +805,5 @@ namespace ScriptCanvasEditor Workspace* m_workspace; void OnSaveCallback(bool saveSuccess, AZ::Data::AssetPtr, AZ::Data::AssetId previousFileAssetId); - - void PromptForUpgrade(); }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp new file mode 100644 index 0000000000..eb182ed291 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -0,0 +1,1023 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace VersionExplorerCpp +{ + class FileEventHandler + : public AZ::IO::FileIOEventBus::Handler + { + public: + int m_errorCode = 0; + AZStd::string m_fileName; + + FileEventHandler() + { + BusConnect(); + } + + ~FileEventHandler() + { + BusDisconnect(); + } + + void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override + { + m_errorCode = errorCode; + + if (fileName) + { + m_fileName = fileName; + } + } + }; +} + +namespace ScriptCanvasEditor +{ + EditorKeepAlive::EditorKeepAlive() + { + ISystem* system = nullptr; + CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); + + m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); + + if (m_edKeepEditorActive) + { + m_keepEditorActive = m_edKeepEditorActive->GetIVal(); + m_edKeepEditorActive->Set(1); + } + } + + EditorKeepAlive::~EditorKeepAlive() + { + if (m_edKeepEditorActive) + { + m_edKeepEditorActive->Set(m_keepEditorActive); + } + } + + VersionExplorer::VersionExplorer(QWidget* parent /*= nullptr*/) + : AzQtComponents::StyledDialog(parent) + , m_ui(new Ui::VersionExplorer()) + { + m_ui->setupUi(this); + + m_ui->tableWidget->horizontalHeader()->setVisible(false); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); + m_ui->tableWidget->setColumnWidth(3, 22); + + m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + + connect(m_ui->scanButton, &QPushButton::pressed, this, &VersionExplorer::OnScan); + connect(m_ui->closeButton, &QPushButton::pressed, this, &VersionExplorer::OnClose); + connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &VersionExplorer::OnUpgradeAll); + + m_ui->progressBar->setValue(0); + m_ui->progressBar->setVisible(false); + + m_keepEditorAlive = AZStd::make_unique(); + m_inspectingAsset = m_assetsToInspect.end(); + + } + + VersionExplorer::~VersionExplorer() + { + AZ::SystemTickBus::Handler::BusDisconnect(); + + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + + } + + void VersionExplorer::Log(const char* format, ...) + { + if (m_ui->verbose->isChecked()) + { + char sBuffer[2048]; + va_list ArgList; + va_start(ArgList, format); + azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); + sBuffer[sizeof(sBuffer) - 1] = '\0'; + va_end(ArgList); + + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); + } + } + + void VersionExplorer::OnClose() + { + reject(); + } + + bool VersionExplorer::IsUpgrading() const + { + return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; + } + + void VersionExplorer::OnSystemTick() + { + switch (m_state) + { + case ProcessState::Scan: + + if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) + { + m_inProgress = true; + AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; + m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); + m_currentAsset.BlockUntilLoadComplete(); + if (m_currentAsset.IsReady()) + { + // The asset is ready, grab its info + m_inProgress = true; + InspectAsset(m_currentAsset, assetToUpgrade); + } + else + { + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem + ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + ++m_currentAssetRowIndex; + + Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); + ++m_failedAssets; + ScanComplete(m_currentAsset); + } + } + break; + + case ProcessState::Upgrade: + { + AZStd::lock_guard lock(m_mutex); + if (m_upgradeComplete) + { + ++m_upgradeAssetIndex; + m_inProgress = false; + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + + if (m_scriptCanvasEntity) + { + m_scriptCanvasEntity->Deactivate(); + m_scriptCanvasEntity = nullptr; + } + + GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); + + if (!m_isUpgradingSingleGraph) + { + if (m_inProgressAsset != m_assetsToUpgrade.end()) + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + } + + if (m_inProgressAsset == m_assetsToUpgrade.end()) + { + FinalizeUpgrade(); + } + } + else + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + m_inProgress = false; + m_state = ProcessState::Inactive; + m_settingsCache.reset(); + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + } + + m_isUpgradingSingleGraph = false; + + if (m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(false); + } + + m_upgradeComplete = false; + } + + if (!IsUpgrading() && m_state == ProcessState::Upgrade) + { + AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); + // Make the backup + if (errorMessage.empty()) + { + Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); + QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); + spinner->SetIsBusy(true); + } + } + + // Upgrade the graph + UpgradeGraph(*m_inProgressAsset); + } + else + { + Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); + GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); + } + + } + break; + } + default: + break; + } + + FlushLogs(); + + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::SystemTickBus::ExecuteQueuedEvents(); + } + + // Backup + + void VersionExplorer::OnUpgradeAll() + { + m_state = ProcessState::Upgrade; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + AZ::Interface::Get()->SetIsUpgrading(true); + AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); + m_inProgressAsset = m_assetsToUpgrade.begin(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + m_keepEditorAlive = AZStd::make_unique(); + } + + AZStd::string VersionExplorer::BackupGraph(const AZ::Data::Asset& asset) + { + if (!m_ui->makeBackupCheckbox->isChecked()) + { + // considered a success + return ""; + } + + QDateTime theTime = QDateTime::currentDateTime(); + QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); + + AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); + char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); + backupPath = backupPathCStr; + + if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + { + if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); + return "Failed to create backup folder"; + } + } + + AZStd::string devRoot = "@devroot@"; + AZStd::string devAssets = "@devassets@"; + + char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); + + char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); + + AZStd::string relativePath = devAssetsCStr; + AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AZStd::string sourceFilePath; + + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound{}; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); + if (sourceInfoFound) + { + AZStd::string assetPath; + AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); + + sourceFilePath = assetPath; + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); + return "Failed to find source file"; + } + + devRoot = devRootCStr; + AzFramework::StringFunc::Path::Normalize(devRoot); + + relativePath = sourceFilePath; + AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AzFramework::StringFunc::Path::Normalize(relativePath); + AzFramework::StringFunc::Path::Normalize(backupPath); + + AZStd::string targetFilePath = backupPath; + targetFilePath += relativePath; + + if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return "Failed to copy source file to backup location"; + } + + Log("VersionExplorer::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return ""; + } + + void VersionExplorer::UpgradeGraph(const AZ::Data::Asset& asset) + { + m_inProgress = true; + m_upgradeComplete = false; + Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); + m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); + m_scriptCanvasEntity = nullptr; + + UpgradeNotifications::Bus::Handler::BusConnect(); + + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" + , azrtti_typeid().template ToString().c_str()); + + if (!scriptCanvasAsset) + { + return; + } + + AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "VersionExplorer::UpgradeGraph The Script Canvas asset must have a valid entity"); + if (!scriptCanvasEntity) + { + return; + } + + AZ::Entity* queryEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); + if (queryEntity) + { + if (queryEntity->GetState() == AZ::Entity::State::Active) + { + queryEntity->Deactivate(); + } + + scriptCanvasEntity = queryEntity; + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) + { + scriptCanvasEntity->Init(); + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) + { + scriptCanvasEntity->Activate(); + } + + AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + if (graphComponent) + { + m_scriptCanvasEntity = scriptCanvasEntity; + + graphComponent->UpgradeGraph + ( asset + , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_ui->verbose->isChecked()); + } + } + + AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); + } + + void VersionExplorer::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + if (!fullPathFound) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); + } + + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + this->OnSourceFileReleased(asset); + }); + streamer->QueueRequest(flushRequest); + } + + void VersionExplorer::OnSourceFileReleased(AZ::Data::Asset asset) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + m_tmpFileName.clear(); + AZStd::string tmpFileName; + // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); + return; + } + + bool tempSavedSucceeded = false; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); + if (fileStream.IsOpen()) + { + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasEditor::ScriptCanvasAssetHandler handler; + tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + } + + fileStream.Close(); + } + + // attempt to remove temporary file no matter what + m_tmpFileName = tmpFileName; + if (!tempSavedSucceeded) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); + return; + } + + using SCCommandBus = AzToolsFramework::SourceControlCommandBus; + SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, + [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) + { + constexpr const size_t k_maxAttemps = 10; + + if (!info.IsReadOnly()) + { + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + if (m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + int result = QMessageBox::No; + if (!m_overwriteAll) + { + QMessageBox mb(QMessageBox::Warning, + QObject::tr("Failed to Save Upgraded File"), + QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), + QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); + + result = mb.exec(); + if (result == QMessageBox::YesToAll) + { + m_overwriteAll = true; + } + } + + if (result == QMessageBox::Yes || m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + } + } + }); + } + + void VersionExplorer::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target + , size_t remainingAttempts) + { + VersionExplorerCpp::FileEventHandler fileEventHandler; + + if (remainingAttempts == 0) + { + // all attempts failed, give up + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); + GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); + } + else if (remainingAttempts == 2) + { + // before the final attempt, flush all caches + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); + streamer->SetRequestCompleteCallback(flushRequest + , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction( + [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + else + { + // the actual move attempt + auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); + if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) + { + m_tmpFileName.clear(); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + // Bump the slice asset up in the asset processor's queue. + AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, asset]() + { + GraphUpgradeComplete(asset, OperationResult::Success, ""); + }); + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + } + } + + void VersionExplorer::GraphUpgradeComplete + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + AZStd::lock_guard lock(m_mutex); + m_upgradeComplete = true; + m_upgradeResult = result; + m_upgradeMessage = message; + m_upgradeAsset = asset; + + if (!m_tmpFileName.empty()) + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); + + if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) + { + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); + } + } + + if (m_upgradeResult == OperationResult::Failure) + { + AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); + } + + m_tmpFileName.clear(); + } + + void VersionExplorer::GraphUpgradeCompleteUIUpdate + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + QString text = asset.GetHint().c_str(); + QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); + + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); + QString assetName = asset.GetHint().c_str(); + + if (label->text().compare(assetName) == 0) + { + m_ui->tableWidget->removeCellWidget(row, ColumnAction); + m_ui->tableWidget->removeCellWidget(row, ColumnStatus); + + QToolButton* doneButton = new QToolButton(this); + doneButton->setToolTip("Upgrade complete"); + if (result == OperationResult::Success) + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); + } + else + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); + doneButton->setToolTip(message.data()); + } + + m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); + } + } + } + } + + void VersionExplorer::FinalizeUpgrade() + { + Log("FinalizeUpgrade!"); + m_inProgress = false; + m_assetsToUpgrade.clear(); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(true); + m_keepEditorAlive.reset(); + m_ui->progressBar->setVisible(false); + + // Manual correction + size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); + if (assetsThatNeedManualInspection > 0) + { + m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); + } + else + { + m_ui->spinner->SetText("Upgrade complete."); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Interface::Get()->SetIsUpgrading(false); + m_settingsCache.reset(); + } + + // Scanning + + void VersionExplorer::OnScan() + { + m_assetsToUpgrade.clear(); + m_assetsToInspect.clear(); + m_ui->tableWidget->setRowCount(0); + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); + m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); + DoScan(); + } + + void VersionExplorer::DoScan() + { + m_state = ProcessState::Scan; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + + AZ::SystemTickBus::Handler::BusConnect(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + + if (!m_assetsToInspect.empty()) + { + m_discoveredAssets = m_assetsToInspect.size(); + m_failedAssets = 0; + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + m_ui->progressFrame->setVisible(true); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); + m_ui->progressBar->setValue(0); + + m_ui->spinner->SetIsBusy(true); + m_ui->spinner->SetBusyIconSize(32); + + m_ui->scanButton->setEnabled(false); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(false); + + m_inspectingAsset = m_assetsToInspect.begin(); + m_keepEditorAlive = AZStd::make_unique(); + } + } + + void VersionExplorer::BackupComplete() + { + m_currentAssetRowIndex = 0; + m_ui->progressBar->setValue(0); + DoScan(); + } + + void VersionExplorer::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) + { + Log("InspectAsset: %s", asset.GetHint().c_str()); + AZ::Entity* scriptCanvasEntity = nullptr; + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + if (!scriptCanvasAsset) + { + Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); + return; + } + + scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); + } + + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); + bool forceUpgrade = m_ui->forceUpgrade->isChecked(); + ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); + + + if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) + { + ScanComplete(asset); + Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); + return; + } + + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + + if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) + { + m_assetsToUpgrade.push_back(asset); + + AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); + spinner->SetBusyIconSize(16); + + QPushButton* rowGoToButton = new QPushButton(this); + rowGoToButton->setText("Upgrade"); + rowGoToButton->setEnabled(false); + + connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { + + AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { + // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda + UpgradeSingle(rowGoToButton, spinner, assetInfo); + }); + + AZ::SystemTickBus::ExecuteQueuedEvents(); + + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); + } + + char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; + AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); + AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); + AZ::StringFunc::Path::Normalize(path); + + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + QByteArray assetNameUtf8 = asset.GetHint().c_str(); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); + + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); + + QToolButton* browseButton = new QToolButton(this); + browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); + browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); + + QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); + connect(browseButton, &QPushButton::clicked, [absolutePath] { + AzQtComponents::ShowFileOnDesktop(absolutePath); + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); + ScanComplete(asset); + ++m_inspectedAssets; + ++m_currentAssetRowIndex; + } + + void VersionExplorer::UpgradeSingle + ( QPushButton* rowGoToButton + , AzQtComponents::StyledBusyLabel* spinner + , AZ::Data::AssetInfo assetInfo) + { + AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset + ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + + if (asset) + { + asset.BlockUntilLoadComplete(); + + if (asset.IsReady()) + { + AZ::Interface::Get()->SetIsUpgrading(true); + m_isUpgradingSingleGraph = true; + m_logs.clear(); + m_ui->textEdit->clear(); + spinner->SetIsBusy(true); + rowGoToButton->setEnabled(false); + + m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() + , [asset](const UpgradeAssets::value_type& assetToUpgrade) + { + return assetToUpgrade.GetId() == asset.GetId(); + }); + + m_state = ProcessState::Upgrade; + AZ::SystemTickBus::Handler::BusConnect(); + } + } + } + + void VersionExplorer::ScanComplete(const AZ::Data::Asset& asset) + { + Log("ScanComplete: %s", asset.GetHint().c_str()); + m_inProgress = false; + m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); + m_ui->scanButton->setEnabled(true); + + m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); + FlushLogs(); + + if (m_inspectingAsset == m_assetsToInspect.end()) + { + AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + } + } + + void VersionExplorer::FinalizeScan() + { + Log("FinalizeScan()"); + + m_ui->spinner->SetIsBusy(false); + m_ui->onlyShowOutdated->setEnabled(true); + + // Enable all the Upgrade buttons + for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) + { + QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); + if (button) + { + button->setEnabled(true); + } + } + + QString spinnerText = QStringLiteral("Scan Complete"); + if (m_assetsToUpgrade.empty()) + { + spinnerText.append(" - No graphs require upgrade!"); + } + else + { + spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" + , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); + } + + + m_ui->spinner->SetText(spinnerText); + m_ui->progressBar->setVisible(false); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + + m_keepEditorAlive.reset(); + m_settingsCache.reset(); + m_state = ProcessState::Inactive; + } + + void VersionExplorer::FlushLogs() + { + if (m_logs.empty()) + { + return; + } + + const QTextCursor oldCursor = m_ui->textEdit->textCursor(); + QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); + + m_ui->textEdit->moveCursor(QTextCursor::End); + QTextCursor textCursor = m_ui->textEdit->textCursor(); + + while (!m_logs.empty()) + { + auto line = "\n" + m_logs.front(); + + m_logs.pop_front(); + + textCursor.insertText(line.c_str()); + } + + scrollBar->setValue(scrollBar->maximum()); + m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); + + } + + bool VersionExplorer::CaptureLogFromTraceBus(const char* window, const char* message) + { + if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) + { + return true; + } + + AZStd::string msg = message; + if (msg.ends_with("\n")) + { + msg = msg.substr(0, msg.size() - 1); + } + + m_logs.push_back(msg); + return m_ui->updateReportingOnly->isChecked(); + } + + bool VersionExplorer::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Error): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool VersionExplorer::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Warning): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool VersionExplorer::OnException(const char* message) + { + AZStd::string msg = AZStd::string::format("(Exception): %s", message); + return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); + } + + bool VersionExplorer::OnPrintf(const char* window, const char* message) + { + return CaptureLogFromTraceBus(window, message); + } + + void VersionExplorer::closeEvent(QCloseEvent* event) + { + m_keepEditorAlive.reset(); + + AzQtComponents::StyledDialog::closeEvent(event); + } + +#include + +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h new file mode 100644 index 0000000000..acb28a7dba --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING + +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif + +class QPushButton; + +namespace Ui +{ + class VersionExplorer; +} + +namespace AzQtComponents +{ + class StyledBusyLabel; +} + +namespace ScriptCanvasEditor +{ + //! Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow + //! the upgrade tool to work even if the editor is not in the foreground + class EditorKeepAlive + { + public: + EditorKeepAlive(); + ~EditorKeepAlive(); + + private: + int m_keepEditorActive; + ICVar* m_edKeepEditorActive; + }; + + //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog + class VersionExplorer + : public AzQtComponents::StyledDialog + , private AZ::SystemTickBus::Handler + , private UpgradeNotifications::Bus::Handler + , private AZ::Debug::TraceMessageBus::Handler + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(VersionExplorer, AZ::SystemAllocator, 0); + + explicit VersionExplorer(QWidget* parent = nullptr); + ~VersionExplorer(); + + private: + + static constexpr int ColumnAsset = 0; + static constexpr int ColumnAction = 1; + static constexpr int ColumnBrowse = 2; + static constexpr int ColumnStatus = 3; + + void OnScan(); + void OnClose(); + + enum class ProcessState + { + Inactive, + Backup, + Scan, + Upgrade, + }; + ProcessState m_state = ProcessState::Inactive; + + void DoScan(); + void ScanComplete(const AZ::Data::Asset&); + + void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); + + void OnUpgradeAll(); + + // SystemTickBus::Handler + void OnSystemTick() override; + // + + // AZ::Debug::TranceMessageBus::Handler + bool OnException(const char* /*message*/) override; + bool OnPrintf(const char* /*window*/, const char* /*message*/) override; + bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + // + + bool CaptureLogFromTraceBus(const char* window, const char* message); + + enum class OperationResult + { + Success, + Failure, + }; + + void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); + + bool IsUpgrading() const; + + bool m_inProgress = false; + // scan fields + size_t m_currentAssetRowIndex = 0; + size_t m_inspectedAssets = 0; + size_t m_failedAssets = 0; + size_t m_discoveredAssets = 0; + + IUpgradeRequests::AssetList m_assetsToInspect; + IUpgradeRequests::AssetList::iterator m_inspectingAsset; + using UpgradeAssets = AZStd::vector>; + UpgradeAssets m_assetsToUpgrade; + UpgradeAssets::iterator m_inProgressAsset; + + AZ::Data::Asset m_currentAsset; + + AZStd::unique_ptr m_ui; + + AZStd::unique_ptr m_settingsCache; + + // upgrade fields + AZStd::recursive_mutex m_mutex; + bool m_upgradeComplete = false; + AZ::Data::Asset m_upgradeAsset; + int m_upgradeAssetIndex = 0; + OperationResult m_upgradeResult; + AZStd::string m_upgradeMessage; + AZStd::string m_tmpFileName; + + AZStd::unique_ptr m_keepEditorAlive; + + AZStd::deque m_logs; + + AZ::Entity* m_scriptCanvasEntity = nullptr; + + bool m_isUpgradingSingleGraph = false; + + void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); + + void FlushLogs(); + + void FinalizeUpgrade(); + void FinalizeScan(); + + void BackupComplete(); + AZStd::string BackupGraph(const AZ::Data::Asset&); + void UpgradeGraph(const AZ::Data::Asset&); + + void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); + void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; + + void OnSourceFileReleased(AZ::Data::Asset asset); + + void closeEvent(QCloseEvent* event) override; + + bool m_overwriteAll = false; + void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); + + void Log(const char* format, ...); + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp new file mode 100644 index 0000000000..b96a5c6d0c --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -0,0 +1,1023 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace VersionExplorerCpp +{ + class FileEventHandler + : public AZ::IO::FileIOEventBus::Handler + { + public: + int m_errorCode = 0; + AZStd::string m_fileName; + + FileEventHandler() + { + BusConnect(); + } + + ~FileEventHandler() + { + BusDisconnect(); + } + + void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override + { + m_errorCode = errorCode; + + if (fileName) + { + m_fileName = fileName; + } + } + }; +} + +namespace ScriptCanvasEditor +{ + EditorKeepAlive::EditorKeepAlive() + { + ISystem* system = nullptr; + CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); + + m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); + + if (m_edKeepEditorActive) + { + m_keepEditorActive = m_edKeepEditorActive->GetIVal(); + m_edKeepEditorActive->Set(1); + } + } + + EditorKeepAlive::~EditorKeepAlive() + { + if (m_edKeepEditorActive) + { + m_edKeepEditorActive->Set(m_keepEditorActive); + } + } + + Modifier::Modifier(QWidget* parent /*= nullptr*/) + : AzQtComponents::StyledDialog(parent) + , m_ui(new Ui::Modifier()) + { + m_ui->setupUi(this); + + m_ui->tableWidget->horizontalHeader()->setVisible(false); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); + m_ui->tableWidget->setColumnWidth(3, 22); + + m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + + connect(m_ui->scanButton, &QPushButton::pressed, this, &Modifier::OnScan); + connect(m_ui->closeButton, &QPushButton::pressed, this, &Modifier::OnClose); + connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &Modifier::OnUpgradeAll); + + m_ui->progressBar->setValue(0); + m_ui->progressBar->setVisible(false); + + m_keepEditorAlive = AZStd::make_unique(); + m_inspectingAsset = m_assetsToInspect.end(); + + } + + Modifier::~Modifier() + { + AZ::SystemTickBus::Handler::BusDisconnect(); + + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + + } + + void Modifier::Log(const char* format, ...) + { + if (m_ui->verbose->isChecked()) + { + char sBuffer[2048]; + va_list ArgList; + va_start(ArgList, format); + azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); + sBuffer[sizeof(sBuffer) - 1] = '\0'; + va_end(ArgList); + + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); + } + } + + void Modifier::OnClose() + { + reject(); + } + + bool Modifier::IsUpgrading() const + { + return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; + } + + void Modifier::OnSystemTick() + { + switch (m_state) + { + case ProcessState::Scan: + + if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) + { + m_inProgress = true; + AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; + m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); + m_currentAsset.BlockUntilLoadComplete(); + if (m_currentAsset.IsReady()) + { + // The asset is ready, grab its info + m_inProgress = true; + InspectAsset(m_currentAsset, assetToUpgrade); + } + else + { + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem + ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + ++m_currentAssetRowIndex; + + Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); + ++m_failedAssets; + ScanComplete(m_currentAsset); + } + } + break; + + case ProcessState::Upgrade: + { + AZStd::lock_guard lock(m_mutex); + if (m_upgradeComplete) + { + ++m_upgradeAssetIndex; + m_inProgress = false; + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + + if (m_scriptCanvasEntity) + { + m_scriptCanvasEntity->Deactivate(); + m_scriptCanvasEntity = nullptr; + } + + GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); + + if (!m_isUpgradingSingleGraph) + { + if (m_inProgressAsset != m_assetsToUpgrade.end()) + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + } + + if (m_inProgressAsset == m_assetsToUpgrade.end()) + { + FinalizeUpgrade(); + } + } + else + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + m_inProgress = false; + m_state = ProcessState::Inactive; + m_settingsCache.reset(); + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + } + + m_isUpgradingSingleGraph = false; + + if (m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(false); + } + + m_upgradeComplete = false; + } + + if (!IsUpgrading() && m_state == ProcessState::Upgrade) + { + AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); + // Make the backup + if (errorMessage.empty()) + { + Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); + QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); + spinner->SetIsBusy(true); + } + } + + // Upgrade the graph + UpgradeGraph(*m_inProgressAsset); + } + else + { + Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); + GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); + } + + } + break; + } + default: + break; + } + + FlushLogs(); + + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::SystemTickBus::ExecuteQueuedEvents(); + } + + // Backup + + void Modifier::OnUpgradeAll() + { + m_state = ProcessState::Upgrade; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + AZ::Interface::Get()->SetIsUpgrading(true); + AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); + m_inProgressAsset = m_assetsToUpgrade.begin(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + m_keepEditorAlive = AZStd::make_unique(); + } + + AZStd::string Modifier::BackupGraph(const AZ::Data::Asset& asset) + { + if (!m_ui->makeBackupCheckbox->isChecked()) + { + // considered a success + return ""; + } + + QDateTime theTime = QDateTime::currentDateTime(); + QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); + + AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); + char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); + backupPath = backupPathCStr; + + if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + { + if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); + return "Failed to create backup folder"; + } + } + + AZStd::string devRoot = "@devroot@"; + AZStd::string devAssets = "@devassets@"; + + char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); + + char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); + + AZStd::string relativePath = devAssetsCStr; + AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AZStd::string sourceFilePath; + + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound{}; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); + if (sourceInfoFound) + { + AZStd::string assetPath; + AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); + + sourceFilePath = assetPath; + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Modifier::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); + return "Failed to find source file"; + } + + devRoot = devRootCStr; + AzFramework::StringFunc::Path::Normalize(devRoot); + + relativePath = sourceFilePath; + AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AzFramework::StringFunc::Path::Normalize(relativePath); + AzFramework::StringFunc::Path::Normalize(backupPath); + + AZStd::string targetFilePath = backupPath; + targetFilePath += relativePath; + + if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Modifier::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return "Failed to copy source file to backup location"; + } + + Log("Modifier::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return ""; + } + + void Modifier::UpgradeGraph(const AZ::Data::Asset& asset) + { + m_inProgress = true; + m_upgradeComplete = false; + Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); + m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); + m_scriptCanvasEntity = nullptr; + + UpgradeNotifications::Bus::Handler::BusConnect(); + + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" + , azrtti_typeid().template ToString().c_str()); + + if (!scriptCanvasAsset) + { + return; + } + + AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "Modifier::UpgradeGraph The Script Canvas asset must have a valid entity"); + if (!scriptCanvasEntity) + { + return; + } + + AZ::Entity* queryEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); + if (queryEntity) + { + if (queryEntity->GetState() == AZ::Entity::State::Active) + { + queryEntity->Deactivate(); + } + + scriptCanvasEntity = queryEntity; + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) + { + scriptCanvasEntity->Init(); + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) + { + scriptCanvasEntity->Activate(); + } + + AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + if (graphComponent) + { + m_scriptCanvasEntity = scriptCanvasEntity; + + graphComponent->UpgradeGraph + ( asset + , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_ui->verbose->isChecked()); + } + } + + AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); + } + + void Modifier::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + if (!fullPathFound) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); + } + + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + this->OnSourceFileReleased(asset); + }); + streamer->QueueRequest(flushRequest); + } + + void Modifier::OnSourceFileReleased(AZ::Data::Asset asset) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + m_tmpFileName.clear(); + AZStd::string tmpFileName; + // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); + return; + } + + bool tempSavedSucceeded = false; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); + if (fileStream.IsOpen()) + { + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasEditor::ScriptCanvasAssetHandler handler; + tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + } + + fileStream.Close(); + } + + // attempt to remove temporary file no matter what + m_tmpFileName = tmpFileName; + if (!tempSavedSucceeded) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); + return; + } + + using SCCommandBus = AzToolsFramework::SourceControlCommandBus; + SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, + [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) + { + constexpr const size_t k_maxAttemps = 10; + + if (!info.IsReadOnly()) + { + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + if (m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + int result = QMessageBox::No; + if (!m_overwriteAll) + { + QMessageBox mb(QMessageBox::Warning, + QObject::tr("Failed to Save Upgraded File"), + QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), + QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); + + result = mb.exec(); + if (result == QMessageBox::YesToAll) + { + m_overwriteAll = true; + } + } + + if (result == QMessageBox::Yes || m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + } + } + }); + } + + void Modifier::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target + , size_t remainingAttempts) + { + VersionExplorerCpp::FileEventHandler fileEventHandler; + + if (remainingAttempts == 0) + { + // all attempts failed, give up + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); + GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); + } + else if (remainingAttempts == 2) + { + // before the final attempt, flush all caches + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); + streamer->SetRequestCompleteCallback(flushRequest + , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction( + [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + else + { + // the actual move attempt + auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); + if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) + { + m_tmpFileName.clear(); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + // Bump the slice asset up in the asset processor's queue. + AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, asset]() + { + GraphUpgradeComplete(asset, OperationResult::Success, ""); + }); + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + } + } + + void Modifier::GraphUpgradeComplete + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + AZStd::lock_guard lock(m_mutex); + m_upgradeComplete = true; + m_upgradeResult = result; + m_upgradeMessage = message; + m_upgradeAsset = asset; + + if (!m_tmpFileName.empty()) + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); + + if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) + { + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); + } + } + + if (m_upgradeResult == OperationResult::Failure) + { + AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); + } + + m_tmpFileName.clear(); + } + + void Modifier::GraphUpgradeCompleteUIUpdate + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + QString text = asset.GetHint().c_str(); + QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); + + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); + QString assetName = asset.GetHint().c_str(); + + if (label->text().compare(assetName) == 0) + { + m_ui->tableWidget->removeCellWidget(row, ColumnAction); + m_ui->tableWidget->removeCellWidget(row, ColumnStatus); + + QToolButton* doneButton = new QToolButton(this); + doneButton->setToolTip("Upgrade complete"); + if (result == OperationResult::Success) + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); + } + else + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); + doneButton->setToolTip(message.data()); + } + + m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); + } + } + } + } + + void Modifier::FinalizeUpgrade() + { + Log("FinalizeUpgrade!"); + m_inProgress = false; + m_assetsToUpgrade.clear(); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(true); + m_keepEditorAlive.reset(); + m_ui->progressBar->setVisible(false); + + // Manual correction + size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); + if (assetsThatNeedManualInspection > 0) + { + m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); + } + else + { + m_ui->spinner->SetText("Upgrade complete."); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Interface::Get()->SetIsUpgrading(false); + m_settingsCache.reset(); + } + + // Scanning + + void Modifier::OnScan() + { + m_assetsToUpgrade.clear(); + m_assetsToInspect.clear(); + m_ui->tableWidget->setRowCount(0); + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); + m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); + DoScan(); + } + + void Modifier::DoScan() + { + m_state = ProcessState::Scan; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + + AZ::SystemTickBus::Handler::BusConnect(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + + if (!m_assetsToInspect.empty()) + { + m_discoveredAssets = m_assetsToInspect.size(); + m_failedAssets = 0; + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + m_ui->progressFrame->setVisible(true); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); + m_ui->progressBar->setValue(0); + + m_ui->spinner->SetIsBusy(true); + m_ui->spinner->SetBusyIconSize(32); + + m_ui->scanButton->setEnabled(false); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(false); + + m_inspectingAsset = m_assetsToInspect.begin(); + m_keepEditorAlive = AZStd::make_unique(); + } + } + + void Modifier::BackupComplete() + { + m_currentAssetRowIndex = 0; + m_ui->progressBar->setValue(0); + DoScan(); + } + + void Modifier::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) + { + Log("InspectAsset: %s", asset.GetHint().c_str()); + AZ::Entity* scriptCanvasEntity = nullptr; + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + if (!scriptCanvasAsset) + { + Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); + return; + } + + scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); + } + + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); + bool forceUpgrade = m_ui->forceUpgrade->isChecked(); + ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); + + + if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) + { + ScanComplete(asset); + Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); + return; + } + + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + + if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) + { + m_assetsToUpgrade.push_back(asset); + + AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); + spinner->SetBusyIconSize(16); + + QPushButton* rowGoToButton = new QPushButton(this); + rowGoToButton->setText("Upgrade"); + rowGoToButton->setEnabled(false); + + connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { + + AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { + // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda + UpgradeSingle(rowGoToButton, spinner, assetInfo); + }); + + AZ::SystemTickBus::ExecuteQueuedEvents(); + + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); + } + + char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; + AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); + AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); + AZ::StringFunc::Path::Normalize(path); + + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + QByteArray assetNameUtf8 = asset.GetHint().c_str(); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); + + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); + + QToolButton* browseButton = new QToolButton(this); + browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); + browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); + + QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); + connect(browseButton, &QPushButton::clicked, [absolutePath] { + AzQtComponents::ShowFileOnDesktop(absolutePath); + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); + ScanComplete(asset); + ++m_inspectedAssets; + ++m_currentAssetRowIndex; + } + + void Modifier::UpgradeSingle + ( QPushButton* rowGoToButton + , AzQtComponents::StyledBusyLabel* spinner + , AZ::Data::AssetInfo assetInfo) + { + AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset + ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + + if (asset) + { + asset.BlockUntilLoadComplete(); + + if (asset.IsReady()) + { + AZ::Interface::Get()->SetIsUpgrading(true); + m_isUpgradingSingleGraph = true; + m_logs.clear(); + m_ui->textEdit->clear(); + spinner->SetIsBusy(true); + rowGoToButton->setEnabled(false); + + m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() + , [asset](const UpgradeAssets::value_type& assetToUpgrade) + { + return assetToUpgrade.GetId() == asset.GetId(); + }); + + m_state = ProcessState::Upgrade; + AZ::SystemTickBus::Handler::BusConnect(); + } + } + } + + void Modifier::ScanComplete(const AZ::Data::Asset& asset) + { + Log("ScanComplete: %s", asset.GetHint().c_str()); + m_inProgress = false; + m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); + m_ui->scanButton->setEnabled(true); + + m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); + FlushLogs(); + + if (m_inspectingAsset == m_assetsToInspect.end()) + { + AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + } + } + + void Modifier::FinalizeScan() + { + Log("FinalizeScan()"); + + m_ui->spinner->SetIsBusy(false); + m_ui->onlyShowOutdated->setEnabled(true); + + // Enable all the Upgrade buttons + for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) + { + QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); + if (button) + { + button->setEnabled(true); + } + } + + QString spinnerText = QStringLiteral("Scan Complete"); + if (m_assetsToUpgrade.empty()) + { + spinnerText.append(" - No graphs require upgrade!"); + } + else + { + spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" + , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); + } + + + m_ui->spinner->SetText(spinnerText); + m_ui->progressBar->setVisible(false); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + + m_keepEditorAlive.reset(); + m_settingsCache.reset(); + m_state = ProcessState::Inactive; + } + + void Modifier::FlushLogs() + { + if (m_logs.empty()) + { + return; + } + + const QTextCursor oldCursor = m_ui->textEdit->textCursor(); + QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); + + m_ui->textEdit->moveCursor(QTextCursor::End); + QTextCursor textCursor = m_ui->textEdit->textCursor(); + + while (!m_logs.empty()) + { + auto line = "\n" + m_logs.front(); + + m_logs.pop_front(); + + textCursor.insertText(line.c_str()); + } + + scrollBar->setValue(scrollBar->maximum()); + m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); + + } + + bool Modifier::CaptureLogFromTraceBus(const char* window, const char* message) + { + if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) + { + return true; + } + + AZStd::string msg = message; + if (msg.ends_with("\n")) + { + msg = msg.substr(0, msg.size() - 1); + } + + m_logs.push_back(msg); + return m_ui->updateReportingOnly->isChecked(); + } + + bool Modifier::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Error): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool Modifier::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Warning): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool Modifier::OnException(const char* message) + { + AZStd::string msg = AZStd::string::format("(Exception): %s", message); + return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); + } + + bool Modifier::OnPrintf(const char* window, const char* message) + { + return CaptureLogFromTraceBus(window, message); + } + + void Modifier::closeEvent(QCloseEvent* event) + { + m_keepEditorAlive.reset(); + + AzQtComponents::StyledDialog::closeEvent(event); + } + +#include + +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h new file mode 100644 index 0000000000..5f379d682a --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING + +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif + +class QPushButton; + +namespace Ui +{ + class Modifier; +} + +namespace AzQtComponents +{ + class StyledBusyLabel; +} + +namespace ScriptCanvasEditor +{ + //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog + class Modifier + : public AzQtComponents::StyledDialog + , private AZ::SystemTickBus::Handler + , private UpgradeNotifications::Bus::Handler + , private AZ::Debug::TraceMessageBus::Handler + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(Modifier, AZ::SystemAllocator, 0); + + explicit Modifier(QWidget* parent = nullptr); + ~Modifier(); + + private: + + static constexpr int ColumnAsset = 0; + static constexpr int ColumnAction = 1; + static constexpr int ColumnBrowse = 2; + static constexpr int ColumnStatus = 3; + + void OnScan(); + void OnClose(); + + enum class ProcessState + { + Inactive, + Backup, + Scan, + Upgrade, + }; + ProcessState m_state = ProcessState::Inactive; + + void DoScan(); + void ScanComplete(const AZ::Data::Asset&); + + void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); + + void OnUpgradeAll(); + + // SystemTickBus::Handler + void OnSystemTick() override; + // + + // AZ::Debug::TranceMessageBus::Handler + bool OnException(const char* /*message*/) override; + bool OnPrintf(const char* /*window*/, const char* /*message*/) override; + bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + // + + bool CaptureLogFromTraceBus(const char* window, const char* message); + + enum class OperationResult + { + Success, + Failure, + }; + + void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); + + bool IsUpgrading() const; + + bool m_inProgress = false; + // scan fields + size_t m_currentAssetRowIndex = 0; + size_t m_inspectedAssets = 0; + size_t m_failedAssets = 0; + size_t m_discoveredAssets = 0; + + IUpgradeRequests::AssetList m_assetsToInspect; + IUpgradeRequests::AssetList::iterator m_inspectingAsset; + using UpgradeAssets = AZStd::vector>; + UpgradeAssets m_assetsToUpgrade; + UpgradeAssets::iterator m_inProgressAsset; + + AZ::Data::Asset m_currentAsset; + + AZStd::unique_ptr m_ui; + + AZStd::unique_ptr m_settingsCache; + + // upgrade fields + AZStd::recursive_mutex m_mutex; + bool m_upgradeComplete = false; + AZ::Data::Asset m_upgradeAsset; + int m_upgradeAssetIndex = 0; + OperationResult m_upgradeResult; + AZStd::string m_upgradeMessage; + AZStd::string m_tmpFileName; + + AZStd::unique_ptr m_keepEditorAlive; + + AZStd::deque m_logs; + + AZ::Entity* m_scriptCanvasEntity = nullptr; + + bool m_isUpgradingSingleGraph = false; + + void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); + + void FlushLogs(); + + void FinalizeUpgrade(); + void FinalizeScan(); + + void BackupComplete(); + AZStd::string BackupGraph(const AZ::Data::Asset&); + void UpgradeGraph(const AZ::Data::Asset&); + + void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); + void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; + + void OnSourceFileReleased(AZ::Data::Asset asset); + + void closeEvent(QCloseEvent* event) override; + + bool m_overwriteAll = false; + void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); + + void Log(const char* format, ...); + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp new file mode 100644 index 0000000000..29f5f8f530 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -0,0 +1,1023 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace VersionExplorerCpp +{ + class FileEventHandler + : public AZ::IO::FileIOEventBus::Handler + { + public: + int m_errorCode = 0; + AZStd::string m_fileName; + + FileEventHandler() + { + BusConnect(); + } + + ~FileEventHandler() + { + BusDisconnect(); + } + + void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override + { + m_errorCode = errorCode; + + if (fileName) + { + m_fileName = fileName; + } + } + }; +} + +namespace ScriptCanvasEditor +{ + EditorKeepAlive::EditorKeepAlive() + { + ISystem* system = nullptr; + CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); + + m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); + + if (m_edKeepEditorActive) + { + m_keepEditorActive = m_edKeepEditorActive->GetIVal(); + m_edKeepEditorActive->Set(1); + } + } + + EditorKeepAlive::~EditorKeepAlive() + { + if (m_edKeepEditorActive) + { + m_edKeepEditorActive->Set(m_keepEditorActive); + } + } + + Scanner::Scanner(QWidget* parent /*= nullptr*/) + : AzQtComponents::StyledDialog(parent) + , m_ui(new Ui::Scanner()) + { + m_ui->setupUi(this); + + m_ui->tableWidget->horizontalHeader()->setVisible(false); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); + m_ui->tableWidget->setColumnWidth(3, 22); + + m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + + connect(m_ui->scanButton, &QPushButton::pressed, this, &Scanner::OnScan); + connect(m_ui->closeButton, &QPushButton::pressed, this, &Scanner::OnClose); + connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &Scanner::OnUpgradeAll); + + m_ui->progressBar->setValue(0); + m_ui->progressBar->setVisible(false); + + m_keepEditorAlive = AZStd::make_unique(); + m_inspectingAsset = m_assetsToInspect.end(); + + } + + Scanner::~Scanner() + { + AZ::SystemTickBus::Handler::BusDisconnect(); + + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + + } + + void Scanner::Log(const char* format, ...) + { + if (m_ui->verbose->isChecked()) + { + char sBuffer[2048]; + va_list ArgList; + va_start(ArgList, format); + azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); + sBuffer[sizeof(sBuffer) - 1] = '\0'; + va_end(ArgList); + + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); + } + } + + void Scanner::OnClose() + { + reject(); + } + + bool Scanner::IsUpgrading() const + { + return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; + } + + void Scanner::OnSystemTick() + { + switch (m_state) + { + case ProcessState::Scan: + + if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) + { + m_inProgress = true; + AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; + m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); + m_currentAsset.BlockUntilLoadComplete(); + if (m_currentAsset.IsReady()) + { + // The asset is ready, grab its info + m_inProgress = true; + InspectAsset(m_currentAsset, assetToUpgrade); + } + else + { + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem + ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + ++m_currentAssetRowIndex; + + Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); + ++m_failedAssets; + ScanComplete(m_currentAsset); + } + } + break; + + case ProcessState::Upgrade: + { + AZStd::lock_guard lock(m_mutex); + if (m_upgradeComplete) + { + ++m_upgradeAssetIndex; + m_inProgress = false; + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + + if (m_scriptCanvasEntity) + { + m_scriptCanvasEntity->Deactivate(); + m_scriptCanvasEntity = nullptr; + } + + GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); + + if (!m_isUpgradingSingleGraph) + { + if (m_inProgressAsset != m_assetsToUpgrade.end()) + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + } + + if (m_inProgressAsset == m_assetsToUpgrade.end()) + { + FinalizeUpgrade(); + } + } + else + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + m_inProgress = false; + m_state = ProcessState::Inactive; + m_settingsCache.reset(); + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + } + + m_isUpgradingSingleGraph = false; + + if (m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(false); + } + + m_upgradeComplete = false; + } + + if (!IsUpgrading() && m_state == ProcessState::Upgrade) + { + AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); + // Make the backup + if (errorMessage.empty()) + { + Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); + QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); + spinner->SetIsBusy(true); + } + } + + // Upgrade the graph + UpgradeGraph(*m_inProgressAsset); + } + else + { + Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); + GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); + } + + } + break; + } + default: + break; + } + + FlushLogs(); + + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::SystemTickBus::ExecuteQueuedEvents(); + } + + // Backup + + void Scanner::OnUpgradeAll() + { + m_state = ProcessState::Upgrade; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + AZ::Interface::Get()->SetIsUpgrading(true); + AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); + m_inProgressAsset = m_assetsToUpgrade.begin(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + m_keepEditorAlive = AZStd::make_unique(); + } + + AZStd::string Scanner::BackupGraph(const AZ::Data::Asset& asset) + { + if (!m_ui->makeBackupCheckbox->isChecked()) + { + // considered a success + return ""; + } + + QDateTime theTime = QDateTime::currentDateTime(); + QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); + + AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); + char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); + backupPath = backupPathCStr; + + if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + { + if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); + return "Failed to create backup folder"; + } + } + + AZStd::string devRoot = "@devroot@"; + AZStd::string devAssets = "@devassets@"; + + char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); + + char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); + + AZStd::string relativePath = devAssetsCStr; + AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AZStd::string sourceFilePath; + + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound{}; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); + if (sourceInfoFound) + { + AZStd::string assetPath; + AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); + + sourceFilePath = assetPath; + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Scanner::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); + return "Failed to find source file"; + } + + devRoot = devRootCStr; + AzFramework::StringFunc::Path::Normalize(devRoot); + + relativePath = sourceFilePath; + AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AzFramework::StringFunc::Path::Normalize(relativePath); + AzFramework::StringFunc::Path::Normalize(backupPath); + + AZStd::string targetFilePath = backupPath; + targetFilePath += relativePath; + + if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Scanner::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return "Failed to copy source file to backup location"; + } + + Log("Scanner::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return ""; + } + + void Scanner::UpgradeGraph(const AZ::Data::Asset& asset) + { + m_inProgress = true; + m_upgradeComplete = false; + Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); + m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); + m_scriptCanvasEntity = nullptr; + + UpgradeNotifications::Bus::Handler::BusConnect(); + + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" + , azrtti_typeid().template ToString().c_str()); + + if (!scriptCanvasAsset) + { + return; + } + + AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "Scanner::UpgradeGraph The Script Canvas asset must have a valid entity"); + if (!scriptCanvasEntity) + { + return; + } + + AZ::Entity* queryEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); + if (queryEntity) + { + if (queryEntity->GetState() == AZ::Entity::State::Active) + { + queryEntity->Deactivate(); + } + + scriptCanvasEntity = queryEntity; + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) + { + scriptCanvasEntity->Init(); + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) + { + scriptCanvasEntity->Activate(); + } + + AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + if (graphComponent) + { + m_scriptCanvasEntity = scriptCanvasEntity; + + graphComponent->UpgradeGraph + ( asset + , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_ui->verbose->isChecked()); + } + } + + AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); + } + + void Scanner::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + if (!fullPathFound) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); + } + + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + this->OnSourceFileReleased(asset); + }); + streamer->QueueRequest(flushRequest); + } + + void Scanner::OnSourceFileReleased(AZ::Data::Asset asset) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + m_tmpFileName.clear(); + AZStd::string tmpFileName; + // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); + return; + } + + bool tempSavedSucceeded = false; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); + if (fileStream.IsOpen()) + { + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasEditor::ScriptCanvasAssetHandler handler; + tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + } + + fileStream.Close(); + } + + // attempt to remove temporary file no matter what + m_tmpFileName = tmpFileName; + if (!tempSavedSucceeded) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); + return; + } + + using SCCommandBus = AzToolsFramework::SourceControlCommandBus; + SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, + [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) + { + constexpr const size_t k_maxAttemps = 10; + + if (!info.IsReadOnly()) + { + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + if (m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + int result = QMessageBox::No; + if (!m_overwriteAll) + { + QMessageBox mb(QMessageBox::Warning, + QObject::tr("Failed to Save Upgraded File"), + QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), + QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); + + result = mb.exec(); + if (result == QMessageBox::YesToAll) + { + m_overwriteAll = true; + } + } + + if (result == QMessageBox::Yes || m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + } + } + }); + } + + void Scanner::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target + , size_t remainingAttempts) + { + VersionExplorerCpp::FileEventHandler fileEventHandler; + + if (remainingAttempts == 0) + { + // all attempts failed, give up + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); + GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); + } + else if (remainingAttempts == 2) + { + // before the final attempt, flush all caches + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); + streamer->SetRequestCompleteCallback(flushRequest + , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction( + [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + else + { + // the actual move attempt + auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); + if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) + { + m_tmpFileName.clear(); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + // Bump the slice asset up in the asset processor's queue. + AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, asset]() + { + GraphUpgradeComplete(asset, OperationResult::Success, ""); + }); + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + } + } + + void Scanner::GraphUpgradeComplete + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + AZStd::lock_guard lock(m_mutex); + m_upgradeComplete = true; + m_upgradeResult = result; + m_upgradeMessage = message; + m_upgradeAsset = asset; + + if (!m_tmpFileName.empty()) + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); + + if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) + { + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); + } + } + + if (m_upgradeResult == OperationResult::Failure) + { + AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); + } + + m_tmpFileName.clear(); + } + + void Scanner::GraphUpgradeCompleteUIUpdate + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + QString text = asset.GetHint().c_str(); + QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); + + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); + QString assetName = asset.GetHint().c_str(); + + if (label->text().compare(assetName) == 0) + { + m_ui->tableWidget->removeCellWidget(row, ColumnAction); + m_ui->tableWidget->removeCellWidget(row, ColumnStatus); + + QToolButton* doneButton = new QToolButton(this); + doneButton->setToolTip("Upgrade complete"); + if (result == OperationResult::Success) + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); + } + else + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); + doneButton->setToolTip(message.data()); + } + + m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); + } + } + } + } + + void Scanner::FinalizeUpgrade() + { + Log("FinalizeUpgrade!"); + m_inProgress = false; + m_assetsToUpgrade.clear(); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(true); + m_keepEditorAlive.reset(); + m_ui->progressBar->setVisible(false); + + // Manual correction + size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); + if (assetsThatNeedManualInspection > 0) + { + m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); + } + else + { + m_ui->spinner->SetText("Upgrade complete."); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Interface::Get()->SetIsUpgrading(false); + m_settingsCache.reset(); + } + + // Scanning + + void Scanner::OnScan() + { + m_assetsToUpgrade.clear(); + m_assetsToInspect.clear(); + m_ui->tableWidget->setRowCount(0); + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); + m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); + DoScan(); + } + + void Scanner::DoScan() + { + m_state = ProcessState::Scan; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + + AZ::SystemTickBus::Handler::BusConnect(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + + if (!m_assetsToInspect.empty()) + { + m_discoveredAssets = m_assetsToInspect.size(); + m_failedAssets = 0; + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + m_ui->progressFrame->setVisible(true); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); + m_ui->progressBar->setValue(0); + + m_ui->spinner->SetIsBusy(true); + m_ui->spinner->SetBusyIconSize(32); + + m_ui->scanButton->setEnabled(false); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(false); + + m_inspectingAsset = m_assetsToInspect.begin(); + m_keepEditorAlive = AZStd::make_unique(); + } + } + + void Scanner::BackupComplete() + { + m_currentAssetRowIndex = 0; + m_ui->progressBar->setValue(0); + DoScan(); + } + + void Scanner::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) + { + Log("InspectAsset: %s", asset.GetHint().c_str()); + AZ::Entity* scriptCanvasEntity = nullptr; + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + if (!scriptCanvasAsset) + { + Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); + return; + } + + scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); + } + + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); + bool forceUpgrade = m_ui->forceUpgrade->isChecked(); + ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); + + + if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) + { + ScanComplete(asset); + Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); + return; + } + + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + + if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) + { + m_assetsToUpgrade.push_back(asset); + + AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); + spinner->SetBusyIconSize(16); + + QPushButton* rowGoToButton = new QPushButton(this); + rowGoToButton->setText("Upgrade"); + rowGoToButton->setEnabled(false); + + connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { + + AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { + // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda + UpgradeSingle(rowGoToButton, spinner, assetInfo); + }); + + AZ::SystemTickBus::ExecuteQueuedEvents(); + + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); + } + + char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; + AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); + AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); + AZ::StringFunc::Path::Normalize(path); + + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + QByteArray assetNameUtf8 = asset.GetHint().c_str(); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); + + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); + + QToolButton* browseButton = new QToolButton(this); + browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); + browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); + + QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); + connect(browseButton, &QPushButton::clicked, [absolutePath] { + AzQtComponents::ShowFileOnDesktop(absolutePath); + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); + ScanComplete(asset); + ++m_inspectedAssets; + ++m_currentAssetRowIndex; + } + + void Scanner::UpgradeSingle + ( QPushButton* rowGoToButton + , AzQtComponents::StyledBusyLabel* spinner + , AZ::Data::AssetInfo assetInfo) + { + AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset + ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + + if (asset) + { + asset.BlockUntilLoadComplete(); + + if (asset.IsReady()) + { + AZ::Interface::Get()->SetIsUpgrading(true); + m_isUpgradingSingleGraph = true; + m_logs.clear(); + m_ui->textEdit->clear(); + spinner->SetIsBusy(true); + rowGoToButton->setEnabled(false); + + m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() + , [asset](const UpgradeAssets::value_type& assetToUpgrade) + { + return assetToUpgrade.GetId() == asset.GetId(); + }); + + m_state = ProcessState::Upgrade; + AZ::SystemTickBus::Handler::BusConnect(); + } + } + } + + void Scanner::ScanComplete(const AZ::Data::Asset& asset) + { + Log("ScanComplete: %s", asset.GetHint().c_str()); + m_inProgress = false; + m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); + m_ui->scanButton->setEnabled(true); + + m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); + FlushLogs(); + + if (m_inspectingAsset == m_assetsToInspect.end()) + { + AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + } + } + + void Scanner::FinalizeScan() + { + Log("FinalizeScan()"); + + m_ui->spinner->SetIsBusy(false); + m_ui->onlyShowOutdated->setEnabled(true); + + // Enable all the Upgrade buttons + for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) + { + QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); + if (button) + { + button->setEnabled(true); + } + } + + QString spinnerText = QStringLiteral("Scan Complete"); + if (m_assetsToUpgrade.empty()) + { + spinnerText.append(" - No graphs require upgrade!"); + } + else + { + spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" + , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); + } + + + m_ui->spinner->SetText(spinnerText); + m_ui->progressBar->setVisible(false); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + + m_keepEditorAlive.reset(); + m_settingsCache.reset(); + m_state = ProcessState::Inactive; + } + + void Scanner::FlushLogs() + { + if (m_logs.empty()) + { + return; + } + + const QTextCursor oldCursor = m_ui->textEdit->textCursor(); + QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); + + m_ui->textEdit->moveCursor(QTextCursor::End); + QTextCursor textCursor = m_ui->textEdit->textCursor(); + + while (!m_logs.empty()) + { + auto line = "\n" + m_logs.front(); + + m_logs.pop_front(); + + textCursor.insertText(line.c_str()); + } + + scrollBar->setValue(scrollBar->maximum()); + m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); + + } + + bool Scanner::CaptureLogFromTraceBus(const char* window, const char* message) + { + if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) + { + return true; + } + + AZStd::string msg = message; + if (msg.ends_with("\n")) + { + msg = msg.substr(0, msg.size() - 1); + } + + m_logs.push_back(msg); + return m_ui->updateReportingOnly->isChecked(); + } + + bool Scanner::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Error): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool Scanner::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Warning): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool Scanner::OnException(const char* message) + { + AZStd::string msg = AZStd::string::format("(Exception): %s", message); + return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); + } + + bool Scanner::OnPrintf(const char* window, const char* message) + { + return CaptureLogFromTraceBus(window, message); + } + + void Scanner::closeEvent(QCloseEvent* event) + { + m_keepEditorAlive.reset(); + + AzQtComponents::StyledDialog::closeEvent(event); + } + +#include + +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h new file mode 100644 index 0000000000..574b2b2503 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING + +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif + +class QPushButton; + +namespace Ui +{ + class Scanner; +} + +namespace AzQtComponents +{ + class StyledBusyLabel; +} + +namespace ScriptCanvasEditor +{ + //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog + class Scanner + : public AzQtComponents::StyledDialog + , private AZ::SystemTickBus::Handler + , private UpgradeNotifications::Bus::Handler + , private AZ::Debug::TraceMessageBus::Handler + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(Scanner, AZ::SystemAllocator, 0); + + explicit Scanner(QWidget* parent = nullptr); + ~Scanner(); + + private: + + static constexpr int ColumnAsset = 0; + static constexpr int ColumnAction = 1; + static constexpr int ColumnBrowse = 2; + static constexpr int ColumnStatus = 3; + + void OnScan(); + void OnClose(); + + enum class ProcessState + { + Inactive, + Backup, + Scan, + Upgrade, + }; + ProcessState m_state = ProcessState::Inactive; + + void DoScan(); + void ScanComplete(const AZ::Data::Asset&); + + void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); + + void OnUpgradeAll(); + + // SystemTickBus::Handler + void OnSystemTick() override; + // + + // AZ::Debug::TranceMessageBus::Handler + bool OnException(const char* /*message*/) override; + bool OnPrintf(const char* /*window*/, const char* /*message*/) override; + bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + // + + bool CaptureLogFromTraceBus(const char* window, const char* message); + + enum class OperationResult + { + Success, + Failure, + }; + + void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); + + bool IsUpgrading() const; + + bool m_inProgress = false; + // scan fields + size_t m_currentAssetRowIndex = 0; + size_t m_inspectedAssets = 0; + size_t m_failedAssets = 0; + size_t m_discoveredAssets = 0; + + IUpgradeRequests::AssetList m_assetsToInspect; + IUpgradeRequests::AssetList::iterator m_inspectingAsset; + using UpgradeAssets = AZStd::vector>; + UpgradeAssets m_assetsToUpgrade; + UpgradeAssets::iterator m_inProgressAsset; + + AZ::Data::Asset m_currentAsset; + + AZStd::unique_ptr m_ui; + + AZStd::unique_ptr m_settingsCache; + + // upgrade fields + AZStd::recursive_mutex m_mutex; + bool m_upgradeComplete = false; + AZ::Data::Asset m_upgradeAsset; + int m_upgradeAssetIndex = 0; + OperationResult m_upgradeResult; + AZStd::string m_upgradeMessage; + AZStd::string m_tmpFileName; + + AZStd::unique_ptr m_keepEditorAlive; + + AZStd::deque m_logs; + + AZ::Entity* m_scriptCanvasEntity = nullptr; + + bool m_isUpgradingSingleGraph = false; + + void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); + + void FlushLogs(); + + void FinalizeUpgrade(); + void FinalizeScan(); + + void BackupComplete(); + AZStd::string BackupGraph(const AZ::Data::Asset&); + void UpgradeGraph(const AZ::Data::Asset&); + + void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); + void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; + + void OnSourceFileReleased(AZ::Data::Asset asset); + + void closeEvent(QCloseEvent* event) override; + + bool m_overwriteAll = false; + void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); + + void Log(const char* format, ...); + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp deleted file mode 100644 index 5e6858c993..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -#include "UpgradeTool.h" - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include "UpgradeHelper.h" - -namespace ScriptCanvasEditor -{ - UpgradeTool::UpgradeTool(QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent) - , m_ui(new Ui::UpgradeTool()) - { - m_ui->setupUi(this); - - AzQtComponents::CheckBox::applyToggleSwitchStyle(m_ui->doNotAskCheckbox); - AzQtComponents::CheckBox::applyToggleSwitchStyle(m_ui->makeBackupCheckbox); - - m_ui->progressFrame->setVisible(false); - - connect(m_ui->upgradeButton, &QPushButton::pressed, this, &UpgradeTool::OnUpgrade); - connect(m_ui->notNowButton, &QPushButton::pressed, this, &UpgradeTool::OnNoThanks); - - UpgradeNotifications::Bus::Handler::BusConnect(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - - resize(700, 100); - } - - void UpgradeTool::OnNoThanks() - { - DisconnectBuses(); - - UpdateSettings(); - - reject(); - } - - void UpgradeTool::UpdateSettings() - { - auto userSettings = AZ::UserSettings::CreateFind(AZ_CRC("ScriptCanvasPreviewSettings", 0x1c5a2965), AZ::UserSettings::CT_LOCAL); - if (userSettings) - { - userSettings->m_showUpgradeDialog = !m_ui->doNotAskCheckbox->isChecked(); - - AZ::UserSettingsOwnerRequestBus::Event(AZ::UserSettings::CT_LOCAL, &AZ::UserSettingsOwnerRequests::SaveSettings); - } - } - - UpgradeTool::~UpgradeTool() - { - DisconnectBuses(); - } - - void UpgradeTool::DisconnectBuses() - { - UpgradeNotifications::Bus::Handler::BusDisconnect(); - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::MultiHandler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - } - - void UpgradeTool::closeEvent(QCloseEvent* event) - { - // m_keepEditorAlive.reset(); - - DisconnectBuses(); - - UpgradeNotifications::Bus::Broadcast(&UpgradeNotifications::OnUpgradeCancelled); - - AzQtComponents::StyledDialog::closeEvent(event); - } - - bool UpgradeTool::HasBackup() const - { - return m_ui->makeBackupCheckbox->isChecked(); - } - - void UpgradeTool::OnUpgrade() - { - setWindowFlag(Qt::WindowCloseButtonHint, false); - - // m_keepEditorAlive = AZStd::make_unique(); - - UpdateSettings(); - - UpgradeNotifications::Bus::Broadcast(&UpgradeNotifications::OnUpgradeStart); - - m_assetsToUpgrade.clear(); - - IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); - m_assetsToUpgrade = upgradeRequests->GetAssetsToUpgrade(); - - AZ::SystemTickBus::Handler::BusConnect(); - - if (m_ui->makeBackupCheckbox->isChecked()) - { - if (!DoBackup()) - { - // There was a problem, ask if the user wants to keep going or abort - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Backup Failed"), - QObject::tr("Failed to backup your Script Canvas graphs, do you want to proceed with upgrade?"), - QMessageBox::Yes | QMessageBox::No, this); - - if (mb.exec() == QMessageBox::Yes) - { - DoUpgrade(); - } - } - } - else - { - DoUpgrade(); - } - } - - bool UpgradeTool::DoBackup() - { - if (!m_assetsToUpgrade.empty()) - { - m_state = UpgradeState::Backup; - - m_inProgressAsset = m_assetsToUpgrade.begin(); - - m_ui->progressFrame->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - - m_ui->spinner->SetIsBusy(true); - m_ui->spinner->SetBusyIconSize(32); - - m_ui->upgradeButton->setEnabled(false); - m_ui->notNowButton->setEnabled(false); - m_ui->doNotAskCheckbox->setEnabled(false); - m_ui->makeBackupCheckbox->setEnabled(false); - - // Make the folder for the backup - - QDateTime theTime = QDateTime::currentDateTime(); - QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - - m_backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(m_backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - m_backupPath = backupPathCStr; - - if (!AZ::IO::FileIOBase::GetInstance()->Exists(m_backupPath.c_str())) - { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(m_backupPath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Error("Script Canvas", false, "Failed to create backup folder %s", m_backupPath.c_str()); - - return false; - } - } - } - - return true; - } - - void UpgradeTool::BackupComplete() - { - m_currentAssetIndex = 0; - m_ui->progressBar->setValue(0); - - DoUpgrade(); - } - - void UpgradeTool::DoUpgrade() - { - m_state = UpgradeState::Upgrade; - - if (!m_assetsToUpgrade.empty()) - { - m_ui->progressFrame->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - - m_ui->spinner->SetIsBusy(true); - m_ui->spinner->SetBusyIconSize(32); - - m_ui->upgradeButton->setEnabled(false); - m_ui->notNowButton->setEnabled(false); - m_ui->doNotAskCheckbox->setEnabled(false); - m_ui->makeBackupCheckbox->setEnabled(false); - - m_inProgressAsset = m_assetsToUpgrade.begin(); - } - } - - void UpgradeTool::OnAssetReady(AZ::Data::Asset asset) - { - // Start asset upgrade job when current asset is unassigned only - // If current asset is present, there is ongoing progress handling this asset already - if (IsOnReadyAssetForCurrentProcess(asset.GetId())) - { - m_inProgress = true; - m_currentAsset = asset; - m_scriptCanvasEntity = AssetUpgradeJob(asset); - if (!m_scriptCanvasEntity) - { - ResetUpgradeCurrentAsset(); - } - } - } - - void UpgradeTool::OnAssetError(AZ::Data::Asset asset) - { - // Reset upgrade target when script canvas entity is unassigned only. - // If script canvas entity is present, we should let the conversion progress finish itself. - if (IsCurrentProcessFreeToAbort(asset.GetId())) - { - AZ_TracePrintf("Script Canvas", "Asset fails to get load: %s\n", asset.GetHint().c_str()); - ResetUpgradeCurrentAsset(); - } - } - - void UpgradeTool::OnAssetUnloaded(const AZ::Data::AssetId assetId, const AZ::Data::AssetType) - { - // Reset upgrade target when script canvas entity is unassigned only. - // If script canvas entity is present, we should let the conversion progress finish itself. - if (IsCurrentProcessFreeToAbort(assetId)) - { - AZ_TracePrintf("Script Canvas", "Asset gets unloaded: %s\n", m_inProgressAsset->m_relativePath.c_str()); - ResetUpgradeCurrentAsset(); - } - } - - - void UpgradeTool::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool skipped /*=false*/) - { - if (!skipped) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - - AZStd::string tmpFileName; - bool tmpFilesaved = false; - - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) - { - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - - if (fileStream.IsOpen()) - { - if (asset.GetType() == azrtti_typeid()) - { - tmpFilesaved = AZ::Utils::SaveObjectToStream(fileStream, AZ::DataStream::ST_XML, &asset.GetAs()->GetScriptCanvasData()); - } - - fileStream.Close(); - } - - using SCCommandBus = AzToolsFramework::SourceControlCommandBus; - SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, - [this, &asset, fullPath, tmpFileName, tmpFilesaved](bool /*success*/, const AzToolsFramework::SourceControlFileInfo& info) - { - if (!info.IsReadOnly()) - { - if (tmpFilesaved) - { - PerformMove(asset, tmpFileName, fullPath); - } - } - else - { - if (m_overwriteAll) - { - MakeWriteable(info); - - if (tmpFilesaved) - { - PerformMove(asset, tmpFileName, fullPath); - } - } - else - { - int result = QMessageBox::No; - if (!m_overwriteAll) - { - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Failed to Save Upgraded File"), - QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); - - result = mb.exec(); - if (result == QMessageBox::YesToAll) - { - m_overwriteAll = true; - } - } - - if (result == QMessageBox::Yes || m_overwriteAll) - { - MakeWriteable(info); - - if (tmpFilesaved) - { - PerformMove(asset, tmpFileName, fullPath); - } - } - - } - } - }); - } - } - else - { - // We skipped the upgrade (it's up to date), just mark it complete - AZ::SystemTickBus::QueueFunction([this, asset]() { UpgradeComplete(asset, true); }); - - } - - } - - void UpgradeTool::MakeWriteable(const AzToolsFramework::SourceControlFileInfo& info) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - } - - void UpgradeTool::PerformMove(AZ::Data::Asset& asset, const AZStd::string& source, const AZStd::string& target) - { - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) - { - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - - AZ::SystemTickBus::QueueFunction([this, &asset]() { UpgradeComplete(asset); }); - } - else - { - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, &asset, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction([this, &asset, source, target]() { RetryMove(asset, source, target); }); - }); - streamer->QueueRequest(flushRequest); - } - } - - bool UpgradeTool::IsOnReadyAssetForCurrentProcess(const AZ::Data::AssetId& assetId) - { - return !m_currentAsset && m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgressAsset->m_assetId == assetId; - } - - bool UpgradeTool::IsCurrentProcessFreeToAbort(const AZ::Data::AssetId& assetId) - { - return !m_scriptCanvasEntity && m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgressAsset->m_assetId == assetId; - } - - bool UpgradeTool::IsUpgradeCompleteForAllAssets() - { - return !m_inProgress && !m_currentAsset && !m_scriptCanvasEntity && m_inProgressAsset == m_assetsToUpgrade.end(); - } - - bool UpgradeTool::IsUpgradeCompleteForCurrentAsset() - { - return !m_inProgress && !m_currentAsset && !m_scriptCanvasEntity && m_inProgressAsset != m_assetsToUpgrade.end(); - } - - void UpgradeTool::ResetUpgradeCurrentAsset() - { - AZ::Data::AssetBus::MultiHandler::BusDisconnect(m_currentAsset.GetId()); - - if (m_scriptCanvasEntity) - { - m_scriptCanvasEntity->Deactivate(); - m_scriptCanvasEntity = nullptr; - } - - if (m_inProgressAsset != m_assetsToUpgrade.end()) - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - } - - m_currentAsset.Release(); - m_currentAsset = {}; - m_inProgress = false; - } - - void UpgradeTool::OnSystemTick() - { - switch (m_state) - { - case UpgradeTool::UpgradeState::Upgrade: - - if (IsUpgradeCompleteForCurrentAsset()) - { - m_inProgress = true; - AZ::Data::AssetInfo& assetToUpgrade = *m_inProgressAsset; - - if (!AZ::Data::AssetBus::MultiHandler::BusIsConnectedId(assetToUpgrade.m_assetId)) - { - AZ::Data::AssetBus::MultiHandler::BusConnect(assetToUpgrade.m_assetId); - } - - auto asset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::Default); - asset.BlockUntilLoadComplete(); - - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(assetToUpgrade.m_relativePath); - streamer->SetRequestCompleteCallback(flushRequest, []([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - }); - streamer->QueueRequest(flushRequest); - - if (asset.IsReady() || asset.GetStatus() == AZ::Data::AssetData::AssetStatus::ReadyPreNotify) - { - m_currentAsset = asset; - m_scriptCanvasEntity = AssetUpgradeJob(asset); - if (!m_scriptCanvasEntity) - { - ResetUpgradeCurrentAsset(); - } - } - - m_ui->spinner->SetText(QObject::tr("%1").arg(assetToUpgrade.m_relativePath.c_str())); - } - else if (IsUpgradeCompleteForAllAssets()) - { - FinalizeUpgrade(); - } - break; - - case UpgradeTool::UpgradeState::Backup: - - if (m_inProgressAsset != m_assetsToUpgrade.end()) - { - AZ::Data::AssetInfo& assetToBackup = *m_inProgressAsset; - - m_ui->spinner->SetText(QObject::tr("%1").arg(assetToBackup.m_relativePath.c_str())); - - BackupAsset(assetToBackup); - - m_ui->progressBar->setValue(aznumeric_cast(++m_currentAssetIndex)); - } - else - { - BackupComplete(); - } - break; - - default: - break; - } - - AZ::Data::AssetManager::Instance().DispatchEvents(); - AZ::SystemTickBus::ExecuteQueuedEvents(); - - } - - void UpgradeTool::BackupAsset(const AZ::Data::AssetInfo& assetInfo) - { - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - - // Using this to get the watch folder - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo2; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetInfo.m_relativePath.c_str(), assetInfo2, watchFolder); - if (sourceInfoFound) - { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; - } - - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string targetFilePath; - AzFramework::StringFunc::Path::Join(m_backupPath.c_str(), relativePath.c_str(), targetFilePath); - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Error) - { - AZStd::string filename; - AzFramework::StringFunc::Path::GetFileName(sourceFilePath.c_str(), filename); - AZ_TracePrintf("Script Canvas", "Backup: %s -> %s\n", filename.c_str(), targetFilePath.c_str()); - } - else - { - AZ_TracePrintf("Script Canvas", "(Error) Failed to create backup: %s -> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - } - - ++m_inProgressAsset; - } - - void UpgradeTool::UpgradeComplete(const AZ::Data::Asset& asset, bool skipped /*= false*/) - { - m_ui->progressBar->setValue(aznumeric_cast(++m_currentAssetIndex)); - - ResetUpgradeCurrentAsset(); - - if (!skipped) - { - AZStd::string filename; - AzFramework::StringFunc::Path::GetFileName(asset.GetHint().c_str(), filename); - AZ_TracePrintf("Script Canvas", "%s -> Upgraded and Saved!\n", filename.c_str()); - } - } - - void UpgradeTool::FinalizeUpgrade() - { - setWindowFlag(Qt::WindowCloseButtonHint, true); - - AZ::SystemTickBus::Handler::BusDisconnect(); - - m_currentAsset = {}; - - SaveLog(); - - UpgradeNotifications::Bus::Broadcast(&UpgradeNotifications::OnUpgradeComplete); - - AZ_TracePrintf("Script Canvas", "\nUpgrade Complete!\n"); - - DisconnectBuses(); - - accept(); - } - - void UpgradeTool::SaveLog() - { - AZStd::string outputFileName = AZStd::string::format("@devroot@/ScriptCanvasUpgradeReport.html"); - - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - - AZStd::string endPath = resolvedBuffer; - AZ::StringFunc::Path::Normalize(endPath); - - AZ::IO::SystemFile outputFile; - if (!outputFile.Open(endPath.c_str(), - AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY)) - { - AZ_Error("Script Canvas", false, "Failed to open file for writing: %s", endPath.c_str()); - return; - } - - QDateTime theTime = QDateTime::currentDateTime(); - AZStd::string timeStamp = theTime.toString("yyyy-MM-dd [HH.mm.ss]").toUtf8().data(); - - AZStd::string header = "\n\n\n\n\n"; - header.append(AZStd::string::format("Log captured: %s
\n", timeStamp.c_str()).c_str()); - - outputFile.Write(header.c_str(), header.size()); - for (auto& log : m_logs) - { - AZStd::string logText = AZStd::string::format("%s
", log.c_str()); - AzFramework::StringFunc::Replace(logText, "\n", "
\n"); - outputFile.Write(logText.data(), logText.size()); - } - AZStd::string footer = "\n\n"; - outputFile.Write(footer.c_str(), footer.size()); - - - - outputFile.Close(); - } - - AZ::Entity* UpgradeTool::AssetUpgradeJob(AZ::Data::Asset&) - { - return nullptr; - } - - void UpgradeTool::RetryMove(AZ::Data::Asset& asset, const AZStd::string& source, const AZStd::string& target) - { - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) - { - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - - AZ::SystemTickBus::QueueFunction([this, &asset]() { UpgradeComplete(asset); }); - } - else - { - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, &asset, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction([this, &asset, source, target]() { RetryMove(asset, source, target); }); - }); - streamer->QueueRequest(flushRequest); - - - //AZ::SystemTickBus::QueueFunction([this, &asset, source, target]() { RetryMove(asset, source, target); }); - } - } - - void UpgradeTool::CaptureLogFromTraceBus(const char* /*window*/, const char* message) - { - AZStd::string msg = message; - if (msg.ends_with("\n")) - { - msg = msg.substr(0, msg.size() - 1); - } - - m_logs.push_back(msg); - } - - bool UpgradeTool::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Error): %s
", message); - CaptureLogFromTraceBus(window, msg.c_str()); - - return false; - } - - bool UpgradeTool::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Warning): %s
", message); - CaptureLogFromTraceBus(window, msg.c_str()); - - return false; - } - - bool UpgradeTool::OnException(const char* message) - { - AZStd::string msg = AZStd::string::format("(Exception): %s
", message); - CaptureLogFromTraceBus("Script Canvas", msg.c_str()); - - return false; - } - - bool UpgradeTool::OnPrintf(const char* window, const char* message) - { - CaptureLogFromTraceBus(window, message); - return false; - } - -#include - -} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h deleted file mode 100644 index be00198457..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h +++ /dev/null @@ -1,149 +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 - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include - -AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -#include -#include - -#include - -#include - -#include - -#include -#include -#include -#endif - -class QPushButton; - -namespace Ui -{ - class UpgradeTool; -} - -namespace ScriptCanvasEditor -{ - class KeepEditorAlive; - - //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog - class UpgradeTool - : public AzQtComponents::StyledDialog - , private AZ::SystemTickBus::Handler - , private AZ::Data::AssetBus::MultiHandler - , private UpgradeNotifications::Bus::Handler - , private AZ::Debug::TraceMessageBus::Handler - { - Q_OBJECT - - public: - AZ_CLASS_ALLOCATOR(UpgradeTool, AZ::SystemAllocator, 0); - - UpgradeTool(QWidget* parent = nullptr); - ~UpgradeTool(); - - size_t& UpgradedGraphCount() { return m_upgradedAssets; } - size_t& SkippedGraphCount() { return m_skippedAssets; } - - bool HasBackup() const; - - private: - - bool IsOnReadyAssetForCurrentProcess(const AZ::Data::AssetId& assetId); - bool IsCurrentProcessFreeToAbort(const AZ::Data::AssetId& assetId); - bool IsUpgradeCompleteForAllAssets(); - bool IsUpgradeCompleteForCurrentAsset(); - void ResetUpgradeCurrentAsset(); - - void OnUpgrade(); - void OnNoThanks(); - void UpdateSettings(); - - enum class UpgradeState - { - Inactive, - Backup, - Upgrade - }; - UpgradeState m_state = UpgradeState::Inactive; - - bool DoBackup(); - void BackupAsset(const AZ::Data::AssetInfo& assetInfo); - void BackupComplete(); - - void DoUpgrade(); - void UpgradeComplete(const AZ::Data::Asset&, bool skipped = false); - - AZ::Entity* AssetUpgradeJob(AZ::Data::Asset& asset); - - // SystemTickBus::Handler - void OnSystemTick() override; - // - - // AssetBus::Handler - void OnAssetReady(AZ::Data::Asset asset) override; - void OnAssetError(AZ::Data::Asset asset) override; - void OnAssetUnloaded(const AZ::Data::AssetId assetId, const AZ::Data::AssetType assetType) override; - // - - // AZ::Debug::TranceMessageBus::Handler - bool OnException(const char* /*message*/) override; - bool OnPrintf(const char* /*window*/, const char* /*message*/) override; - bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - // - - void CaptureLogFromTraceBus(const char* window, const char* message); - - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; - - void RetryMove(AZ::Data::Asset& asset, const AZStd::string& source, const AZStd::string& target); - - void SaveLog(); - - bool m_inProgress = false; - size_t m_currentAssetIndex = 0; - - size_t m_upgradedAssets = 0; - size_t m_skippedAssets = 0; - - IUpgradeRequests::AssetList m_assetsToUpgrade; - IUpgradeRequests::AssetList::iterator m_inProgressAsset; - - AZ::Data::Asset m_currentAsset; - - AZStd::unique_ptr m_ui; - AZStd::recursive_mutex m_mutex; - - // AZStd::unique_ptr m_keepEditorAlive; - - AZStd::vector m_logs; - - AZ::Entity* m_scriptCanvasEntity = nullptr; - - AZStd::string m_backupPath; - - void FinalizeUpgrade(); - void DisconnectBuses(); - - void closeEvent(QCloseEvent* event) override; - - bool m_overwriteAll = false; - void MakeWriteable(const AzToolsFramework::SourceControlFileInfo& info); - void PerformMove(AZ::Data::Asset& asset, const AZStd::string& source, const AZStd::string& target); - }; -} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.ui deleted file mode 100644 index 78a63ce727..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.ui +++ /dev/null @@ -1,260 +0,0 @@ - - - UpgradeTool - - - Qt::WindowModal - - - - 0 - 0 - 801 - 328 - - - - - 0 - 0 - - - - Script Canvas Upgrade - - - - 5 - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - - - - - 0 - 0 - - - - <html><head/><body><p>Script Canvas graphs are now compiled into Lua by the Asset Processor! In order to complete this upgrade, all graphs in your current project must be updated.</p><p>This upgrading is making changes to the underlying Script Canvas graph format. Depending on the number of scripts you've created this process could take a few minutes to complete. </p><p>This upgrade is required for any projects saved on 1.26 or earlier.</p><p>If you choose &quot;Not now&quot;, your project may not work correctly.</p></body></html> - - - false - - - true - - - - - - - - 0 - 80 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - - 0 - 0 - - - - - 0 - 0 - - - - false - - - background-color: rgb(47, 47, 47); - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - 0 - 0 - - - - - 32 - 32 - - - - false - - - - - - - - 0 - 0 - - - - - - - 24 - - - true - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 0 - - - - - - - - - - - - Backup my source graphs - - - true - - - - - - - Do not ask me again - - - - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Upgrade - - - - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Not now - - - false - - - - - - - - - - - - - - - - AzQtComponents::StyledBusyLabel - QWidget -
AzQtComponents/Components/StyledBusyLabel.h
- 1 -
-
- - -
diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h index acb28a7dba..7ce1920dbb 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h @@ -10,21 +10,17 @@ #if !defined(Q_MOC_RUN) #include - AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") #include AZ_POP_DISABLE_WARNING - #include #include +#include #include - +#include +#include #include #include - -#include -#include -#include #endif class QPushButton; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp new file mode 100644 index 0000000000..6c9acea25c --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp @@ -0,0 +1,1023 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace VersionExplorerCpp +{ + class FileEventHandler + : public AZ::IO::FileIOEventBus::Handler + { + public: + int m_errorCode = 0; + AZStd::string m_fileName; + + FileEventHandler() + { + BusConnect(); + } + + ~FileEventHandler() + { + BusDisconnect(); + } + + void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override + { + m_errorCode = errorCode; + + if (fileName) + { + m_fileName = fileName; + } + } + }; +} + +namespace ScriptCanvasEditor +{ + EditorKeepAlive::EditorKeepAlive() + { + ISystem* system = nullptr; + CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); + + m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); + + if (m_edKeepEditorActive) + { + m_keepEditorActive = m_edKeepEditorActive->GetIVal(); + m_edKeepEditorActive->Set(1); + } + } + + EditorKeepAlive::~EditorKeepAlive() + { + if (m_edKeepEditorActive) + { + m_edKeepEditorActive->Set(m_keepEditorActive); + } + } + + VersionExplorerLog::VersionExplorerLog(QWidget* parent /*= nullptr*/) + : AzQtComponents::StyledDialog(parent) + , m_ui(new Ui::VersionExplorerLog()) + { + m_ui->setupUi(this); + + m_ui->tableWidget->horizontalHeader()->setVisible(false); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); + m_ui->tableWidget->setColumnWidth(3, 22); + + m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + + connect(m_ui->scanButton, &QPushButton::pressed, this, &VersionExplorerLog::OnScan); + connect(m_ui->closeButton, &QPushButton::pressed, this, &VersionExplorerLog::OnClose); + connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &VersionExplorerLog::OnUpgradeAll); + + m_ui->progressBar->setValue(0); + m_ui->progressBar->setVisible(false); + + m_keepEditorAlive = AZStd::make_unique(); + m_inspectingAsset = m_assetsToInspect.end(); + + } + + VersionExplorerLog::~VersionExplorerLog() + { + AZ::SystemTickBus::Handler::BusDisconnect(); + + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + + } + + void VersionExplorerLog::Log(const char* format, ...) + { + if (m_ui->verbose->isChecked()) + { + char sBuffer[2048]; + va_list ArgList; + va_start(ArgList, format); + azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); + sBuffer[sizeof(sBuffer) - 1] = '\0'; + va_end(ArgList); + + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); + } + } + + void VersionExplorerLog::OnClose() + { + reject(); + } + + bool VersionExplorerLog::IsUpgrading() const + { + return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; + } + + void VersionExplorerLog::OnSystemTick() + { + switch (m_state) + { + case ProcessState::Scan: + + if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) + { + m_inProgress = true; + AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; + m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); + m_currentAsset.BlockUntilLoadComplete(); + if (m_currentAsset.IsReady()) + { + // The asset is ready, grab its info + m_inProgress = true; + InspectAsset(m_currentAsset, assetToUpgrade); + } + else + { + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem + ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + ++m_currentAssetRowIndex; + + Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); + ++m_failedAssets; + ScanComplete(m_currentAsset); + } + } + break; + + case ProcessState::Upgrade: + { + AZStd::lock_guard lock(m_mutex); + if (m_upgradeComplete) + { + ++m_upgradeAssetIndex; + m_inProgress = false; + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + + if (m_scriptCanvasEntity) + { + m_scriptCanvasEntity->Deactivate(); + m_scriptCanvasEntity = nullptr; + } + + GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); + + if (!m_isUpgradingSingleGraph) + { + if (m_inProgressAsset != m_assetsToUpgrade.end()) + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + } + + if (m_inProgressAsset == m_assetsToUpgrade.end()) + { + FinalizeUpgrade(); + } + } + else + { + m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + m_inProgress = false; + m_state = ProcessState::Inactive; + m_settingsCache.reset(); + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + } + + m_isUpgradingSingleGraph = false; + + if (m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(false); + } + + m_upgradeComplete = false; + } + + if (!IsUpgrading() && m_state == ProcessState::Upgrade) + { + AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); + // Make the backup + if (errorMessage.empty()) + { + Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); + QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); + spinner->SetIsBusy(true); + } + } + + // Upgrade the graph + UpgradeGraph(*m_inProgressAsset); + } + else + { + Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); + GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); + } + + } + break; + } + default: + break; + } + + FlushLogs(); + + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::SystemTickBus::ExecuteQueuedEvents(); + } + + // Backup + + void VersionExplorerLog::OnUpgradeAll() + { + m_state = ProcessState::Upgrade; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + AZ::Interface::Get()->SetIsUpgrading(true); + AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); + m_inProgressAsset = m_assetsToUpgrade.begin(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + m_keepEditorAlive = AZStd::make_unique(); + } + + AZStd::string VersionExplorerLog::BackupGraph(const AZ::Data::Asset& asset) + { + if (!m_ui->makeBackupCheckbox->isChecked()) + { + // considered a success + return ""; + } + + QDateTime theTime = QDateTime::currentDateTime(); + QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); + + AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); + char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); + backupPath = backupPathCStr; + + if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + { + if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); + return "Failed to create backup folder"; + } + } + + AZStd::string devRoot = "@devroot@"; + AZStd::string devAssets = "@devassets@"; + + char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); + + char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); + + AZStd::string relativePath = devAssetsCStr; + AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AZStd::string sourceFilePath; + + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound{}; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); + if (sourceInfoFound) + { + AZStd::string assetPath; + AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); + + sourceFilePath = assetPath; + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorerLog::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); + return "Failed to find source file"; + } + + devRoot = devRootCStr; + AzFramework::StringFunc::Path::Normalize(devRoot); + + relativePath = sourceFilePath; + AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } + + AzFramework::StringFunc::Path::Normalize(relativePath); + AzFramework::StringFunc::Path::Normalize(backupPath); + + AZStd::string targetFilePath = backupPath; + targetFilePath += relativePath; + + if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorerLog::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return "Failed to copy source file to backup location"; + } + + Log("VersionExplorerLog::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return ""; + } + + void VersionExplorerLog::UpgradeGraph(const AZ::Data::Asset& asset) + { + m_inProgress = true; + m_upgradeComplete = false; + Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); + m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); + m_scriptCanvasEntity = nullptr; + + UpgradeNotifications::Bus::Handler::BusConnect(); + + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" + , azrtti_typeid().template ToString().c_str()); + + if (!scriptCanvasAsset) + { + return; + } + + AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "VersionExplorerLog::UpgradeGraph The Script Canvas asset must have a valid entity"); + if (!scriptCanvasEntity) + { + return; + } + + AZ::Entity* queryEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); + if (queryEntity) + { + if (queryEntity->GetState() == AZ::Entity::State::Active) + { + queryEntity->Deactivate(); + } + + scriptCanvasEntity = queryEntity; + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) + { + scriptCanvasEntity->Init(); + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) + { + scriptCanvasEntity->Activate(); + } + + AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + if (graphComponent) + { + m_scriptCanvasEntity = scriptCanvasEntity; + + graphComponent->UpgradeGraph + ( asset + , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_ui->verbose->isChecked()); + } + } + + AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); + } + + void VersionExplorerLog::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + if (!fullPathFound) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); + } + + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + this->OnSourceFileReleased(asset); + }); + streamer->QueueRequest(flushRequest); + } + + void VersionExplorerLog::OnSourceFileReleased(AZ::Data::Asset asset) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + m_tmpFileName.clear(); + AZStd::string tmpFileName; + // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); + return; + } + + bool tempSavedSucceeded = false; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); + if (fileStream.IsOpen()) + { + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasEditor::ScriptCanvasAssetHandler handler; + tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + } + + fileStream.Close(); + } + + // attempt to remove temporary file no matter what + m_tmpFileName = tmpFileName; + if (!tempSavedSucceeded) + { + GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); + return; + } + + using SCCommandBus = AzToolsFramework::SourceControlCommandBus; + SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, + [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) + { + constexpr const size_t k_maxAttemps = 10; + + if (!info.IsReadOnly()) + { + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + if (m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + int result = QMessageBox::No; + if (!m_overwriteAll) + { + QMessageBox mb(QMessageBox::Warning, + QObject::tr("Failed to Save Upgraded File"), + QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), + QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); + + result = mb.exec(); + if (result == QMessageBox::YesToAll) + { + m_overwriteAll = true; + } + } + + if (result == QMessageBox::Yes || m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + } + } + }); + } + + void VersionExplorerLog::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target + , size_t remainingAttempts) + { + VersionExplorerCpp::FileEventHandler fileEventHandler; + + if (remainingAttempts == 0) + { + // all attempts failed, give up + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); + GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); + } + else if (remainingAttempts == 2) + { + // before the final attempt, flush all caches + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); + streamer->SetRequestCompleteCallback(flushRequest + , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction( + [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + else + { + // the actual move attempt + auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); + if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) + { + m_tmpFileName.clear(); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + // Bump the slice asset up in the asset processor's queue. + AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, asset]() + { + GraphUpgradeComplete(asset, OperationResult::Success, ""); + }); + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + } + } + + void VersionExplorerLog::GraphUpgradeComplete + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + AZStd::lock_guard lock(m_mutex); + m_upgradeComplete = true; + m_upgradeResult = result; + m_upgradeMessage = message; + m_upgradeAsset = asset; + + if (!m_tmpFileName.empty()) + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); + + if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) + { + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); + } + } + + if (m_upgradeResult == OperationResult::Failure) + { + AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); + } + + m_tmpFileName.clear(); + } + + void VersionExplorerLog::GraphUpgradeCompleteUIUpdate + ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + QString text = asset.GetHint().c_str(); + QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); + + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); + QString assetName = asset.GetHint().c_str(); + + if (label->text().compare(assetName) == 0) + { + m_ui->tableWidget->removeCellWidget(row, ColumnAction); + m_ui->tableWidget->removeCellWidget(row, ColumnStatus); + + QToolButton* doneButton = new QToolButton(this); + doneButton->setToolTip("Upgrade complete"); + if (result == OperationResult::Success) + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); + } + else + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); + doneButton->setToolTip(message.data()); + } + + m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); + } + } + } + } + + void VersionExplorerLog::FinalizeUpgrade() + { + Log("FinalizeUpgrade!"); + m_inProgress = false; + m_assetsToUpgrade.clear(); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(true); + m_keepEditorAlive.reset(); + m_ui->progressBar->setVisible(false); + + // Manual correction + size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); + if (assetsThatNeedManualInspection > 0) + { + m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); + } + else + { + m_ui->spinner->SetText("Upgrade complete."); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::Interface::Get()->SetIsUpgrading(false); + m_settingsCache.reset(); + } + + // Scanning + + void VersionExplorerLog::OnScan() + { + m_assetsToUpgrade.clear(); + m_assetsToInspect.clear(); + m_ui->tableWidget->setRowCount(0); + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); + m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); + DoScan(); + } + + void VersionExplorerLog::DoScan() + { + m_state = ProcessState::Scan; + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + + AZ::SystemTickBus::Handler::BusConnect(); + AZ::Debug::TraceMessageBus::Handler::BusConnect(); + + if (!m_assetsToInspect.empty()) + { + m_discoveredAssets = m_assetsToInspect.size(); + m_failedAssets = 0; + m_inspectedAssets = 0; + m_currentAssetRowIndex = 0; + m_ui->progressFrame->setVisible(true); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); + m_ui->progressBar->setValue(0); + + m_ui->spinner->SetIsBusy(true); + m_ui->spinner->SetBusyIconSize(32); + + m_ui->scanButton->setEnabled(false); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(false); + + m_inspectingAsset = m_assetsToInspect.begin(); + m_keepEditorAlive = AZStd::make_unique(); + } + } + + void VersionExplorerLog::BackupComplete() + { + m_currentAssetRowIndex = 0; + m_ui->progressBar->setValue(0); + DoScan(); + } + + void VersionExplorerLog::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) + { + Log("InspectAsset: %s", asset.GetHint().c_str()); + AZ::Entity* scriptCanvasEntity = nullptr; + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + if (!scriptCanvasAsset) + { + Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); + return; + } + + scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); + } + + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + + bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); + bool forceUpgrade = m_ui->forceUpgrade->isChecked(); + ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); + + + if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) + { + ScanComplete(asset); + Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); + return; + } + + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + + if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) + { + m_assetsToUpgrade.push_back(asset); + + AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); + spinner->SetBusyIconSize(16); + + QPushButton* rowGoToButton = new QPushButton(this); + rowGoToButton->setText("Upgrade"); + rowGoToButton->setEnabled(false); + + connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { + + AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { + // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda + UpgradeSingle(rowGoToButton, spinner, assetInfo); + }); + + AZ::SystemTickBus::ExecuteQueuedEvents(); + + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); + } + + char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; + AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); + AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); + AZ::StringFunc::Path::Normalize(path); + + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + QByteArray assetNameUtf8 = asset.GetHint().c_str(); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); + + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); + + QToolButton* browseButton = new QToolButton(this); + browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); + browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); + + QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); + connect(browseButton, &QPushButton::clicked, [absolutePath] { + AzQtComponents::ShowFileOnDesktop(absolutePath); + }); + + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); + ScanComplete(asset); + ++m_inspectedAssets; + ++m_currentAssetRowIndex; + } + + void VersionExplorerLog::UpgradeSingle + ( QPushButton* rowGoToButton + , AzQtComponents::StyledBusyLabel* spinner + , AZ::Data::AssetInfo assetInfo) + { + AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset + ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + + if (asset) + { + asset.BlockUntilLoadComplete(); + + if (asset.IsReady()) + { + AZ::Interface::Get()->SetIsUpgrading(true); + m_isUpgradingSingleGraph = true; + m_logs.clear(); + m_ui->textEdit->clear(); + spinner->SetIsBusy(true); + rowGoToButton->setEnabled(false); + + m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() + , [asset](const UpgradeAssets::value_type& assetToUpgrade) + { + return assetToUpgrade.GetId() == asset.GetId(); + }); + + m_state = ProcessState::Upgrade; + AZ::SystemTickBus::Handler::BusConnect(); + } + } + } + + void VersionExplorerLog::ScanComplete(const AZ::Data::Asset& asset) + { + Log("ScanComplete: %s", asset.GetHint().c_str()); + m_inProgress = false; + m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); + m_ui->scanButton->setEnabled(true); + + m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); + FlushLogs(); + + if (m_inspectingAsset == m_assetsToInspect.end()) + { + AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + } + } + + void VersionExplorerLog::FinalizeScan() + { + Log("FinalizeScan()"); + + m_ui->spinner->SetIsBusy(false); + m_ui->onlyShowOutdated->setEnabled(true); + + // Enable all the Upgrade buttons + for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) + { + QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); + if (button) + { + button->setEnabled(true); + } + } + + QString spinnerText = QStringLiteral("Scan Complete"); + if (m_assetsToUpgrade.empty()) + { + spinnerText.append(" - No graphs require upgrade!"); + } + else + { + spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" + , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); + } + + + m_ui->spinner->SetText(spinnerText); + m_ui->progressBar->setVisible(false); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } + + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + UpgradeNotifications::Bus::Handler::BusDisconnect(); + + m_keepEditorAlive.reset(); + m_settingsCache.reset(); + m_state = ProcessState::Inactive; + } + + void VersionExplorerLog::FlushLogs() + { + if (m_logs.empty()) + { + return; + } + + const QTextCursor oldCursor = m_ui->textEdit->textCursor(); + QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); + + m_ui->textEdit->moveCursor(QTextCursor::End); + QTextCursor textCursor = m_ui->textEdit->textCursor(); + + while (!m_logs.empty()) + { + auto line = "\n" + m_logs.front(); + + m_logs.pop_front(); + + textCursor.insertText(line.c_str()); + } + + scrollBar->setValue(scrollBar->maximum()); + m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); + + } + + bool VersionExplorerLog::CaptureLogFromTraceBus(const char* window, const char* message) + { + if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) + { + return true; + } + + AZStd::string msg = message; + if (msg.ends_with("\n")) + { + msg = msg.substr(0, msg.size() - 1); + } + + m_logs.push_back(msg); + return m_ui->updateReportingOnly->isChecked(); + } + + bool VersionExplorerLog::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Error): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool VersionExplorerLog::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) + { + AZStd::string msg = AZStd::string::format("(Warning): %s", message); + return CaptureLogFromTraceBus(window, msg.c_str()); + } + + bool VersionExplorerLog::OnException(const char* message) + { + AZStd::string msg = AZStd::string::format("(Exception): %s", message); + return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); + } + + bool VersionExplorerLog::OnPrintf(const char* window, const char* message) + { + return CaptureLogFromTraceBus(window, message); + } + + void VersionExplorerLog::closeEvent(QCloseEvent* event) + { + m_keepEditorAlive.reset(); + + AzQtComponents::StyledDialog::closeEvent(event); + } + +#include + +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h new file mode 100644 index 0000000000..498b2f7745 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING + +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif + +class QPushButton; + +namespace Ui +{ + class VersionExplorerLog; +} + +namespace AzQtComponents +{ + class StyledBusyLabel; +} + +namespace ScriptCanvasEditor +{ + //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog + class VersionExplorerLog + : public AzQtComponents::StyledDialog + , private AZ::SystemTickBus::Handler + , private UpgradeNotifications::Bus::Handler + , private AZ::Debug::TraceMessageBus::Handler + { + Q_OBJECT + + public: + AZ_CLASS_ALLOCATOR(VersionExplorerLog, AZ::SystemAllocator, 0); + + explicit VersionExplorerLog(QWidget* parent = nullptr); + ~VersionExplorerLog(); + + private: + + static constexpr int ColumnAsset = 0; + static constexpr int ColumnAction = 1; + static constexpr int ColumnBrowse = 2; + static constexpr int ColumnStatus = 3; + + void OnScan(); + void OnClose(); + + enum class ProcessState + { + Inactive, + Backup, + Scan, + Upgrade, + }; + ProcessState m_state = ProcessState::Inactive; + + void DoScan(); + void ScanComplete(const AZ::Data::Asset&); + + void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); + + void OnUpgradeAll(); + + // SystemTickBus::Handler + void OnSystemTick() override; + // + + // AZ::Debug::TranceMessageBus::Handler + bool OnException(const char* /*message*/) override; + bool OnPrintf(const char* /*window*/, const char* /*message*/) override; + bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + // + + bool CaptureLogFromTraceBus(const char* window, const char* message); + + enum class OperationResult + { + Success, + Failure, + }; + + void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); + + bool IsUpgrading() const; + + bool m_inProgress = false; + // scan fields + size_t m_currentAssetRowIndex = 0; + size_t m_inspectedAssets = 0; + size_t m_failedAssets = 0; + size_t m_discoveredAssets = 0; + + IUpgradeRequests::AssetList m_assetsToInspect; + IUpgradeRequests::AssetList::iterator m_inspectingAsset; + using UpgradeAssets = AZStd::vector>; + UpgradeAssets m_assetsToUpgrade; + UpgradeAssets::iterator m_inProgressAsset; + + AZ::Data::Asset m_currentAsset; + + AZStd::unique_ptr m_ui; + + AZStd::unique_ptr m_settingsCache; + + // upgrade fields + AZStd::recursive_mutex m_mutex; + bool m_upgradeComplete = false; + AZ::Data::Asset m_upgradeAsset; + int m_upgradeAssetIndex = 0; + OperationResult m_upgradeResult; + AZStd::string m_upgradeMessage; + AZStd::string m_tmpFileName; + + AZStd::unique_ptr m_keepEditorAlive; + + AZStd::deque m_logs; + + AZ::Entity* m_scriptCanvasEntity = nullptr; + + bool m_isUpgradingSingleGraph = false; + + void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); + + void FlushLogs(); + + void FinalizeUpgrade(); + void FinalizeScan(); + + void BackupComplete(); + AZStd::string BackupGraph(const AZ::Data::Asset&); + void UpgradeGraph(const AZ::Data::Asset&); + + void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); + void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; + + void OnSourceFileReleased(AZ::Data::Asset asset); + + void closeEvent(QCloseEvent* event) override; + + bool m_overwriteAll = false; + void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); + + void Log(const char* format, ...); + }; +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h new file mode 100644 index 0000000000..4bed23c74e --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h @@ -0,0 +1,19 @@ +#include + +namespace ScriptCanvasEditor +{ + class VersionExplorerNotificationsTraits : public AZ::EBusTraits + { + public: + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusHandlerPolicy::Multiple; + using BusIdType = VersionExplorerNotificationsTraits*; + }; + using VersionExplorerNotificationsBus = AZ:EBus; + + class VersionExplorerRequestsTraits : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy = AZ::EBusHandlerPolicy::Single; + }; + using VersionExplorerRequestsBus = AZ:EBus; +} diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 52b1cc4772..dbffe99afd 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -262,12 +262,17 @@ set(FILES Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui - Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp - Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h - Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.ui + Editor/View/Windows/Tools/UpgradeTool/Scanner.h + Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp + Editor/View/Windows/Tools/UpgradeTool/Modifier.h + Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp + Editor/View/Windows/Tools/UpgradeTool/FileSaver.h + Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.ui + Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h + Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp Editor/Framework/ScriptCanvasGraphUtilities.inl Editor/Framework/ScriptCanvasGraphUtilities.h Editor/Framework/ScriptCanvasTraceUtilities.h From 30d27f23eee9de032a7aaa4750324f9be36ca78a Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 10 Sep 2021 12:52:54 -0700 Subject: [PATCH 003/293] rename version explorer to view Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/{VersionExplorer.cpp => View.cpp} | 0 .../View/Windows/Tools/UpgradeTool/{VersionExplorer.h => View.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/{VersionExplorer.cpp => View.cpp} (100%) rename Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/{VersionExplorer.h => View.h} (100%) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp similarity index 100% rename from Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp rename to Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h similarity index 100% rename from Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h rename to Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h From e558e7b0ffcc098dd1b4ff2e90fcc481af1e6997 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 10 Sep 2021 12:54:25 -0700 Subject: [PATCH 004/293] rename version explorer ui to view Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/{VersionExplorer.ui => View.ui} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/{VersionExplorer.ui => View.ui} (100%) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui similarity index 100% rename from Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.ui rename to Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui From e0f93ea159d7e7dfc4f641c2b797e87253cf9340 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 10 Sep 2021 13:19:55 -0700 Subject: [PATCH 005/293] view traits wip before rename Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Tools/UpgradeTool/VersionExplorerTraits.h | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h index 4bed23c74e..2b23c711dd 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h @@ -2,18 +2,21 @@ namespace ScriptCanvasEditor { - class VersionExplorerNotificationsTraits : public AZ::EBusTraits + namespace VersionExplorer { - public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusHandlerPolicy::Multiple; - using BusIdType = VersionExplorerNotificationsTraits*; - }; - using VersionExplorerNotificationsBus = AZ:EBus; + class RequestsTraits : public AZ::EBusTraits + { + public: + static const AZ::EBusAddressPolicy HandlerPolicy = AZ::EBusAddressPolicy::Single; + }; + using RequestsBus = AZ::EBus; - class VersionExplorerRequestsTraits : public AZ::EBusTraits - { - public: - static const AZ::EBusHandlerPolicy = AZ::EBusHandlerPolicy::Single; - }; - using VersionExplorerRequestsBus = AZ:EBus; + class NotificationsTraits : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + using BusIdType = NotificationsTraits*; + }; + using NotificationsBus = AZ::EBus; + } } From b6eb9123e545052cd2f35f8d2d21db22b9dcf2b5 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 10 Sep 2021 19:38:28 -0700 Subject: [PATCH 006/293] version explorer refactor wip Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Windows/MainWindow.cpp | 4 +- .../Code/Editor/View/Windows/MainWindow.h | 2 +- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 980 +---------- .../Windows/Tools/UpgradeTool/FileSaver.h | 167 +- .../View/Windows/Tools/UpgradeTool/Model.cpp | 25 + .../View/Windows/Tools/UpgradeTool/Model.h | 33 + .../Windows/Tools/UpgradeTool/ModelTraits.h | 31 + .../Windows/Tools/UpgradeTool/Modifier.cpp | 1005 +---------- .../View/Windows/Tools/UpgradeTool/Modifier.h | 154 +- .../Windows/Tools/UpgradeTool/Scanner.cpp | 1005 +---------- .../View/Windows/Tools/UpgradeTool/Scanner.h | 154 +- .../Tools/UpgradeTool/VersionExplorerLog.cpp | 1004 +---------- .../Tools/UpgradeTool/VersionExplorerLog.h | 172 +- .../Tools/UpgradeTool/VersionExplorerTraits.h | 22 - .../View/Windows/Tools/UpgradeTool/View.cpp | 1493 ++++++++--------- .../View/Windows/Tools/UpgradeTool/View.h | 206 ++- .../View/Windows/Tools/UpgradeTool/View.ui | 4 +- .../Windows/Tools/UpgradeTool/ViewTraits.h | 26 + .../Code/scriptcanvasgem_editor_files.cmake | 26 +- 19 files changed, 1024 insertions(+), 5489 deletions(-) create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h delete mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 856cceb508..33a58c18a7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -134,7 +134,7 @@ #include #include #include -#include +#include #include @@ -3436,7 +3436,7 @@ namespace ScriptCanvasEditor void MainWindow::RunUpgradeTool() { - VersionExplorer* versionExplorer = aznew VersionExplorer(this); + auto versionExplorer = aznew VersionExplorer::View(this); versionExplorer->exec(); // Manual correction diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index ed00254677..54557c3691 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -51,7 +51,7 @@ #include -#include +#include #if SCRIPTCANVAS_EDITOR #include diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index eb182ed291..7a7c4fe5a3 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -6,35 +6,10 @@ * */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -namespace VersionExplorerCpp +namespace FileSaverCpp { class FileEventHandler : public AZ::IO::FileIOEventBus::Handler @@ -67,957 +42,8 @@ namespace VersionExplorerCpp namespace ScriptCanvasEditor { - EditorKeepAlive::EditorKeepAlive() - { - ISystem* system = nullptr; - CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); - - m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); - - if (m_edKeepEditorActive) - { - m_keepEditorActive = m_edKeepEditorActive->GetIVal(); - m_edKeepEditorActive->Set(1); - } - } - - EditorKeepAlive::~EditorKeepAlive() - { - if (m_edKeepEditorActive) - { - m_edKeepEditorActive->Set(m_keepEditorActive); - } - } - - VersionExplorer::VersionExplorer(QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent) - , m_ui(new Ui::VersionExplorer()) - { - m_ui->setupUi(this); - - m_ui->tableWidget->horizontalHeader()->setVisible(false); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); - m_ui->tableWidget->setColumnWidth(3, 22); - - m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); - m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); - - connect(m_ui->scanButton, &QPushButton::pressed, this, &VersionExplorer::OnScan); - connect(m_ui->closeButton, &QPushButton::pressed, this, &VersionExplorer::OnClose); - connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &VersionExplorer::OnUpgradeAll); - - m_ui->progressBar->setValue(0); - m_ui->progressBar->setVisible(false); - - m_keepEditorAlive = AZStd::make_unique(); - m_inspectingAsset = m_assetsToInspect.end(); - - } - - VersionExplorer::~VersionExplorer() - { - AZ::SystemTickBus::Handler::BusDisconnect(); - - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - - } - - void VersionExplorer::Log(const char* format, ...) - { - if (m_ui->verbose->isChecked()) - { - char sBuffer[2048]; - va_list ArgList; - va_start(ArgList, format); - azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); - sBuffer[sizeof(sBuffer) - 1] = '\0'; - va_end(ArgList); - - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); - } - } - - void VersionExplorer::OnClose() - { - reject(); - } - - bool VersionExplorer::IsUpgrading() const - { - return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; - } - - void VersionExplorer::OnSystemTick() - { - switch (m_state) - { - case ProcessState::Scan: - - if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) - { - m_inProgress = true; - AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; - m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); - m_currentAsset.BlockUntilLoadComplete(); - if (m_currentAsset.IsReady()) - { - // The asset is ready, grab its info - m_inProgress = true; - InspectAsset(m_currentAsset, assetToUpgrade); - } - else - { - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem - ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - ++m_currentAssetRowIndex; - - Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); - ++m_failedAssets; - ScanComplete(m_currentAsset); - } - } - break; - - case ProcessState::Upgrade: - { - AZStd::lock_guard lock(m_mutex); - if (m_upgradeComplete) - { - ++m_upgradeAssetIndex; - m_inProgress = false; - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - - if (m_scriptCanvasEntity) - { - m_scriptCanvasEntity->Deactivate(); - m_scriptCanvasEntity = nullptr; - } - - GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); - - if (!m_isUpgradingSingleGraph) - { - if (m_inProgressAsset != m_assetsToUpgrade.end()) - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - } - - if (m_inProgressAsset == m_assetsToUpgrade.end()) - { - FinalizeUpgrade(); - } - } - else - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - m_inProgress = false; - m_state = ProcessState::Inactive; - m_settingsCache.reset(); - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - } - - m_isUpgradingSingleGraph = false; - - if (m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(false); - } - - m_upgradeComplete = false; - } - - if (!IsUpgrading() && m_state == ProcessState::Upgrade) - { - AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); - // Make the backup - if (errorMessage.empty()) - { - Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); - QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); - spinner->SetIsBusy(true); - } - } - - // Upgrade the graph - UpgradeGraph(*m_inProgressAsset); - } - else - { - Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); - GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); - } - - } - break; - } - default: - break; - } - - FlushLogs(); - - AZ::Data::AssetManager::Instance().DispatchEvents(); - AZ::SystemTickBus::ExecuteQueuedEvents(); - } - - // Backup - - void VersionExplorer::OnUpgradeAll() - { - m_state = ProcessState::Upgrade; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - AZ::Interface::Get()->SetIsUpgrading(true); - AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); - m_inProgressAsset = m_assetsToUpgrade.begin(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - AZ::SystemTickBus::Handler::BusConnect(); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - m_keepEditorAlive = AZStd::make_unique(); - } - - AZStd::string VersionExplorer::BackupGraph(const AZ::Data::Asset& asset) - { - if (!m_ui->makeBackupCheckbox->isChecked()) - { - // considered a success - return ""; - } - - QDateTime theTime = QDateTime::currentDateTime(); - QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; - - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) - { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); - return "Failed to create backup folder"; - } - } - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); - if (sourceInfoFound) - { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); - return "Failed to find source file"; - } - - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return "Failed to copy source file to backup location"; - } - - Log("VersionExplorer::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return ""; - } - - void VersionExplorer::UpgradeGraph(const AZ::Data::Asset& asset) - { - m_inProgress = true; - m_upgradeComplete = false; - Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); - m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); - m_scriptCanvasEntity = nullptr; - - UpgradeNotifications::Bus::Handler::BusConnect(); - - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "VersionExplorer::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) - { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - if (graphComponent) - { - m_scriptCanvasEntity = scriptCanvasEntity; - - graphComponent->UpgradeGraph - ( asset - , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_ui->verbose->isChecked()); - } - } - - AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); - } - - void VersionExplorer::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - if (!fullPathFound) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); - } - - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - this->OnSourceFileReleased(asset); - }); - streamer->QueueRequest(flushRequest); - } - - void VersionExplorer::OnSourceFileReleased(AZ::Data::Asset asset) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - m_tmpFileName.clear(); - AZStd::string tmpFileName; - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); - return; - } - - bool tempSavedSucceeded = false; - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); - } - - fileStream.Close(); - } - - // attempt to remove temporary file no matter what - m_tmpFileName = tmpFileName; - if (!tempSavedSucceeded) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); - return; - } - - using SCCommandBus = AzToolsFramework::SourceControlCommandBus; - SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, - [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - constexpr const size_t k_maxAttemps = 10; - - if (!info.IsReadOnly()) - { - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - if (m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - int result = QMessageBox::No; - if (!m_overwriteAll) - { - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Failed to Save Upgraded File"), - QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); - - result = mb.exec(); - if (result == QMessageBox::YesToAll) - { - m_overwriteAll = true; - } - } - - if (result == QMessageBox::Yes || m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - } - } - }); - } - - void VersionExplorer::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target - , size_t remainingAttempts) - { - VersionExplorerCpp::FileEventHandler fileEventHandler; - - if (remainingAttempts == 0) - { - // all attempts failed, give up - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); - GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); - } - else if (remainingAttempts == 2) - { - // before the final attempt, flush all caches - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); - streamer->SetRequestCompleteCallback(flushRequest - , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction( - [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - else - { - // the actual move attempt - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) - { - m_tmpFileName.clear(); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - AZ::SystemTickBus::QueueFunction([this, asset]() - { - GraphUpgradeComplete(asset, OperationResult::Success, ""); - }); - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - } - } - - void VersionExplorer::GraphUpgradeComplete - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + namespace VersionExplorer { - AZStd::lock_guard lock(m_mutex); - m_upgradeComplete = true; - m_upgradeResult = result; - m_upgradeMessage = message; - m_upgradeAsset = asset; - if (!m_tmpFileName.empty()) - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); - - if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) - { - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); - } - } - - if (m_upgradeResult == OperationResult::Failure) - { - AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); - } - - m_tmpFileName.clear(); } - - void VersionExplorer::GraphUpgradeCompleteUIUpdate - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - QString text = asset.GetHint().c_str(); - QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); - - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); - QString assetName = asset.GetHint().c_str(); - - if (label->text().compare(assetName) == 0) - { - m_ui->tableWidget->removeCellWidget(row, ColumnAction); - m_ui->tableWidget->removeCellWidget(row, ColumnStatus); - - QToolButton* doneButton = new QToolButton(this); - doneButton->setToolTip("Upgrade complete"); - if (result == OperationResult::Success) - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); - } - else - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); - doneButton->setToolTip(message.data()); - } - - m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); - } - } - } - } - - void VersionExplorer::FinalizeUpgrade() - { - Log("FinalizeUpgrade!"); - m_inProgress = false; - m_assetsToUpgrade.clear(); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(true); - m_keepEditorAlive.reset(); - m_ui->progressBar->setVisible(false); - - // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - if (assetsThatNeedManualInspection > 0) - { - m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); - } - else - { - m_ui->spinner->SetText("Upgrade complete."); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Interface::Get()->SetIsUpgrading(false); - m_settingsCache.reset(); - } - - // Scanning - - void VersionExplorer::OnScan() - { - m_assetsToUpgrade.clear(); - m_assetsToInspect.clear(); - m_ui->tableWidget->setRowCount(0); - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); - m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); - DoScan(); - } - - void VersionExplorer::DoScan() - { - m_state = ProcessState::Scan; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - - AZ::SystemTickBus::Handler::BusConnect(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - - if (!m_assetsToInspect.empty()) - { - m_discoveredAssets = m_assetsToInspect.size(); - m_failedAssets = 0; - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - m_ui->progressFrame->setVisible(true); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); - m_ui->progressBar->setValue(0); - - m_ui->spinner->SetIsBusy(true); - m_ui->spinner->SetBusyIconSize(32); - - m_ui->scanButton->setEnabled(false); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(false); - - m_inspectingAsset = m_assetsToInspect.begin(); - m_keepEditorAlive = AZStd::make_unique(); - } - } - - void VersionExplorer::BackupComplete() - { - m_currentAssetRowIndex = 0; - m_ui->progressBar->setValue(0); - DoScan(); - } - - void VersionExplorer::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) - { - Log("InspectAsset: %s", asset.GetHint().c_str()); - AZ::Entity* scriptCanvasEntity = nullptr; - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) - { - Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); - return; - } - - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); - } - - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); - bool forceUpgrade = m_ui->forceUpgrade->isChecked(); - ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); - - - if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) - { - ScanComplete(asset); - Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); - return; - } - - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - - if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) - { - m_assetsToUpgrade.push_back(asset); - - AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); - spinner->SetBusyIconSize(16); - - QPushButton* rowGoToButton = new QPushButton(this); - rowGoToButton->setText("Upgrade"); - rowGoToButton->setEnabled(false); - - connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { - - AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { - // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda - UpgradeSingle(rowGoToButton, spinner, assetInfo); - }); - - AZ::SystemTickBus::ExecuteQueuedEvents(); - - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); - } - - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); - - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - QByteArray assetNameUtf8 = asset.GetHint().c_str(); - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); - - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); - - QToolButton* browseButton = new QToolButton(this); - browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); - browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); - - QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); - connect(browseButton, &QPushButton::clicked, [absolutePath] { - AzQtComponents::ShowFileOnDesktop(absolutePath); - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); - ScanComplete(asset); - ++m_inspectedAssets; - ++m_currentAssetRowIndex; - } - - void VersionExplorer::UpgradeSingle - ( QPushButton* rowGoToButton - , AzQtComponents::StyledBusyLabel* spinner - , AZ::Data::AssetInfo assetInfo) - { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - - if (asset) - { - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) - { - AZ::Interface::Get()->SetIsUpgrading(true); - m_isUpgradingSingleGraph = true; - m_logs.clear(); - m_ui->textEdit->clear(); - spinner->SetIsBusy(true); - rowGoToButton->setEnabled(false); - - m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() - , [asset](const UpgradeAssets::value_type& assetToUpgrade) - { - return assetToUpgrade.GetId() == asset.GetId(); - }); - - m_state = ProcessState::Upgrade; - AZ::SystemTickBus::Handler::BusConnect(); - } - } - } - - void VersionExplorer::ScanComplete(const AZ::Data::Asset& asset) - { - Log("ScanComplete: %s", asset.GetHint().c_str()); - m_inProgress = false; - m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - m_ui->scanButton->setEnabled(true); - - m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); - FlushLogs(); - - if (m_inspectingAsset == m_assetsToInspect.end()) - { - AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - } - } - - void VersionExplorer::FinalizeScan() - { - Log("FinalizeScan()"); - - m_ui->spinner->SetIsBusy(false); - m_ui->onlyShowOutdated->setEnabled(true); - - // Enable all the Upgrade buttons - for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) - { - QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); - if (button) - { - button->setEnabled(true); - } - } - - QString spinnerText = QStringLiteral("Scan Complete"); - if (m_assetsToUpgrade.empty()) - { - spinnerText.append(" - No graphs require upgrade!"); - } - else - { - spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" - , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); - } - - - m_ui->spinner->SetText(spinnerText); - m_ui->progressBar->setVisible(false); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - - m_keepEditorAlive.reset(); - m_settingsCache.reset(); - m_state = ProcessState::Inactive; - } - - void VersionExplorer::FlushLogs() - { - if (m_logs.empty()) - { - return; - } - - const QTextCursor oldCursor = m_ui->textEdit->textCursor(); - QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); - - m_ui->textEdit->moveCursor(QTextCursor::End); - QTextCursor textCursor = m_ui->textEdit->textCursor(); - - while (!m_logs.empty()) - { - auto line = "\n" + m_logs.front(); - - m_logs.pop_front(); - - textCursor.insertText(line.c_str()); - } - - scrollBar->setValue(scrollBar->maximum()); - m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); - - } - - bool VersionExplorer::CaptureLogFromTraceBus(const char* window, const char* message) - { - if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) - { - return true; - } - - AZStd::string msg = message; - if (msg.ends_with("\n")) - { - msg = msg.substr(0, msg.size() - 1); - } - - m_logs.push_back(msg); - return m_ui->updateReportingOnly->isChecked(); - } - - bool VersionExplorer::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Error): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool VersionExplorer::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Warning): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool VersionExplorer::OnException(const char* message) - { - AZStd::string msg = AZStd::string::format("(Exception): %s", message); - return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); - } - - bool VersionExplorer::OnPrintf(const char* window, const char* message) - { - return CaptureLogFromTraceBus(window, message); - } - - void VersionExplorer::closeEvent(QCloseEvent* event) - { - m_keepEditorAlive.reset(); - - AzQtComponents::StyledDialog::closeEvent(event); - } - -#include - } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h index acb28a7dba..e1ab92acbc 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -8,173 +8,16 @@ #pragma once -#if !defined(Q_MOC_RUN) -#include - -AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -#include -#include -#include - -#include #include -#include -#include -#include -#endif - -class QPushButton; - -namespace Ui -{ - class VersionExplorer; -} - -namespace AzQtComponents -{ - class StyledBusyLabel; -} - namespace ScriptCanvasEditor { - //! Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow - //! the upgrade tool to work even if the editor is not in the foreground - class EditorKeepAlive + namespace VersionExplorer { - public: - EditorKeepAlive(); - ~EditorKeepAlive(); - - private: - int m_keepEditorActive; - ICVar* m_edKeepEditorActive; - }; - - //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog - class VersionExplorer - : public AzQtComponents::StyledDialog - , private AZ::SystemTickBus::Handler - , private UpgradeNotifications::Bus::Handler - , private AZ::Debug::TraceMessageBus::Handler - { - Q_OBJECT - - public: - AZ_CLASS_ALLOCATOR(VersionExplorer, AZ::SystemAllocator, 0); - - explicit VersionExplorer(QWidget* parent = nullptr); - ~VersionExplorer(); - - private: - - static constexpr int ColumnAsset = 0; - static constexpr int ColumnAction = 1; - static constexpr int ColumnBrowse = 2; - static constexpr int ColumnStatus = 3; - - void OnScan(); - void OnClose(); - - enum class ProcessState - { - Inactive, - Backup, - Scan, - Upgrade, - }; - ProcessState m_state = ProcessState::Inactive; - - void DoScan(); - void ScanComplete(const AZ::Data::Asset&); - - void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); - - void OnUpgradeAll(); - - // SystemTickBus::Handler - void OnSystemTick() override; - // - - // AZ::Debug::TranceMessageBus::Handler - bool OnException(const char* /*message*/) override; - bool OnPrintf(const char* /*window*/, const char* /*message*/) override; - bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - // - - bool CaptureLogFromTraceBus(const char* window, const char* message); - - enum class OperationResult + class FileSaver { - Success, - Failure, + public: + AZ_CLASS_ALLOCATOR(FileSaver, AZ::SystemAllocator, 0); }; - - void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); - - bool IsUpgrading() const; - - bool m_inProgress = false; - // scan fields - size_t m_currentAssetRowIndex = 0; - size_t m_inspectedAssets = 0; - size_t m_failedAssets = 0; - size_t m_discoveredAssets = 0; - - IUpgradeRequests::AssetList m_assetsToInspect; - IUpgradeRequests::AssetList::iterator m_inspectingAsset; - using UpgradeAssets = AZStd::vector>; - UpgradeAssets m_assetsToUpgrade; - UpgradeAssets::iterator m_inProgressAsset; - - AZ::Data::Asset m_currentAsset; - - AZStd::unique_ptr m_ui; - - AZStd::unique_ptr m_settingsCache; - - // upgrade fields - AZStd::recursive_mutex m_mutex; - bool m_upgradeComplete = false; - AZ::Data::Asset m_upgradeAsset; - int m_upgradeAssetIndex = 0; - OperationResult m_upgradeResult; - AZStd::string m_upgradeMessage; - AZStd::string m_tmpFileName; - - AZStd::unique_ptr m_keepEditorAlive; - - AZStd::deque m_logs; - - AZ::Entity* m_scriptCanvasEntity = nullptr; - - bool m_isUpgradingSingleGraph = false; - - void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); - - void FlushLogs(); - - void FinalizeUpgrade(); - void FinalizeScan(); - - void BackupComplete(); - AZStd::string BackupGraph(const AZ::Data::Asset&); - void UpgradeGraph(const AZ::Data::Asset&); - - void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; - - void OnSourceFileReleased(AZ::Data::Asset asset); - - void closeEvent(QCloseEvent* event) override; - - bool m_overwriteAll = false; - void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); - - void Log(const char* format, ...); - }; + } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp new file mode 100644 index 0000000000..710d6863f5 --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -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 + * + */ + +#include + +namespace ModifierCpp +{ + +} + +namespace ScriptCanvasEditor +{ + namespace VersionExplorer + { + const AZStd::vector* Model::GetLogs() + { + return &m_log.GetEntries(); + } + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h new file mode 100644 index 0000000000..44da70e85c --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once +#include +#include +#include + +namespace ScriptCanvasEditor +{ + namespace VersionExplorer + { + //! Handles model change requests, state queries; sends state change notifications + class Model + : public ModelRequestsBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(Model, AZ::SystemAllocator, 0); + + const AZStd::vector* GetLogs(); + + private: + Log m_log; + + AZStd::unique_ptr m_settingsCache; + }; + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h new file mode 100644 index 0000000000..e66cdac13e --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +namespace ScriptCanvasEditor +{ + namespace VersionExplorer + { + class ModelRequestsTraits + : public AZ::EBusTraits + { + public: + virtual const AZStd::vector* GetLogs(); + }; + using ModelRequestsBus = AZ::EBus; + + class ModelNotificationsTraits + : public AZ::EBusTraits + { + public: + }; + using ModelNotificationsBus = AZ::EBus; + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index b96a5c6d0c..a0067e1a5f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -6,1018 +6,17 @@ * */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -namespace VersionExplorerCpp +namespace ModifierCpp { - class FileEventHandler - : public AZ::IO::FileIOEventBus::Handler - { - public: - int m_errorCode = 0; - AZStd::string m_fileName; - - FileEventHandler() - { - BusConnect(); - } - ~FileEventHandler() - { - BusDisconnect(); - } - - void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override - { - m_errorCode = errorCode; - - if (fileName) - { - m_fileName = fileName; - } - } - }; } namespace ScriptCanvasEditor { - EditorKeepAlive::EditorKeepAlive() - { - ISystem* system = nullptr; - CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); - - m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); - - if (m_edKeepEditorActive) - { - m_keepEditorActive = m_edKeepEditorActive->GetIVal(); - m_edKeepEditorActive->Set(1); - } - } - - EditorKeepAlive::~EditorKeepAlive() - { - if (m_edKeepEditorActive) - { - m_edKeepEditorActive->Set(m_keepEditorActive); - } - } - - Modifier::Modifier(QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent) - , m_ui(new Ui::Modifier()) - { - m_ui->setupUi(this); - - m_ui->tableWidget->horizontalHeader()->setVisible(false); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); - m_ui->tableWidget->setColumnWidth(3, 22); - - m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); - m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); - - connect(m_ui->scanButton, &QPushButton::pressed, this, &Modifier::OnScan); - connect(m_ui->closeButton, &QPushButton::pressed, this, &Modifier::OnClose); - connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &Modifier::OnUpgradeAll); - - m_ui->progressBar->setValue(0); - m_ui->progressBar->setVisible(false); - - m_keepEditorAlive = AZStd::make_unique(); - m_inspectingAsset = m_assetsToInspect.end(); - - } - - Modifier::~Modifier() - { - AZ::SystemTickBus::Handler::BusDisconnect(); - - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - - } - - void Modifier::Log(const char* format, ...) + namespace VersionExplorer { - if (m_ui->verbose->isChecked()) - { - char sBuffer[2048]; - va_list ArgList; - va_start(ArgList, format); - azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); - sBuffer[sizeof(sBuffer) - 1] = '\0'; - va_end(ArgList); - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); - } - } - - void Modifier::OnClose() - { - reject(); - } - - bool Modifier::IsUpgrading() const - { - return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; - } - - void Modifier::OnSystemTick() - { - switch (m_state) - { - case ProcessState::Scan: - - if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) - { - m_inProgress = true; - AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; - m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); - m_currentAsset.BlockUntilLoadComplete(); - if (m_currentAsset.IsReady()) - { - // The asset is ready, grab its info - m_inProgress = true; - InspectAsset(m_currentAsset, assetToUpgrade); - } - else - { - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem - ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - ++m_currentAssetRowIndex; - - Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); - ++m_failedAssets; - ScanComplete(m_currentAsset); - } - } - break; - - case ProcessState::Upgrade: - { - AZStd::lock_guard lock(m_mutex); - if (m_upgradeComplete) - { - ++m_upgradeAssetIndex; - m_inProgress = false; - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - - if (m_scriptCanvasEntity) - { - m_scriptCanvasEntity->Deactivate(); - m_scriptCanvasEntity = nullptr; - } - - GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); - - if (!m_isUpgradingSingleGraph) - { - if (m_inProgressAsset != m_assetsToUpgrade.end()) - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - } - - if (m_inProgressAsset == m_assetsToUpgrade.end()) - { - FinalizeUpgrade(); - } - } - else - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - m_inProgress = false; - m_state = ProcessState::Inactive; - m_settingsCache.reset(); - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - } - - m_isUpgradingSingleGraph = false; - - if (m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(false); - } - - m_upgradeComplete = false; - } - - if (!IsUpgrading() && m_state == ProcessState::Upgrade) - { - AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); - // Make the backup - if (errorMessage.empty()) - { - Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); - QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); - spinner->SetIsBusy(true); - } - } - - // Upgrade the graph - UpgradeGraph(*m_inProgressAsset); - } - else - { - Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); - GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); - } - - } - break; - } - default: - break; - } - - FlushLogs(); - - AZ::Data::AssetManager::Instance().DispatchEvents(); - AZ::SystemTickBus::ExecuteQueuedEvents(); - } - - // Backup - - void Modifier::OnUpgradeAll() - { - m_state = ProcessState::Upgrade; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - AZ::Interface::Get()->SetIsUpgrading(true); - AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); - m_inProgressAsset = m_assetsToUpgrade.begin(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - AZ::SystemTickBus::Handler::BusConnect(); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - m_keepEditorAlive = AZStd::make_unique(); } - - AZStd::string Modifier::BackupGraph(const AZ::Data::Asset& asset) - { - if (!m_ui->makeBackupCheckbox->isChecked()) - { - // considered a success - return ""; - } - - QDateTime theTime = QDateTime::currentDateTime(); - QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; - - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) - { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); - return "Failed to create backup folder"; - } - } - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); - if (sourceInfoFound) - { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Modifier::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); - return "Failed to find source file"; - } - - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Modifier::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return "Failed to copy source file to backup location"; - } - - Log("Modifier::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return ""; - } - - void Modifier::UpgradeGraph(const AZ::Data::Asset& asset) - { - m_inProgress = true; - m_upgradeComplete = false; - Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); - m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); - m_scriptCanvasEntity = nullptr; - - UpgradeNotifications::Bus::Handler::BusConnect(); - - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "Modifier::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) - { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - if (graphComponent) - { - m_scriptCanvasEntity = scriptCanvasEntity; - - graphComponent->UpgradeGraph - ( asset - , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_ui->verbose->isChecked()); - } - } - - AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); - } - - void Modifier::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - if (!fullPathFound) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); - } - - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - this->OnSourceFileReleased(asset); - }); - streamer->QueueRequest(flushRequest); - } - - void Modifier::OnSourceFileReleased(AZ::Data::Asset asset) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - m_tmpFileName.clear(); - AZStd::string tmpFileName; - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); - return; - } - - bool tempSavedSucceeded = false; - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); - } - - fileStream.Close(); - } - - // attempt to remove temporary file no matter what - m_tmpFileName = tmpFileName; - if (!tempSavedSucceeded) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); - return; - } - - using SCCommandBus = AzToolsFramework::SourceControlCommandBus; - SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, - [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - constexpr const size_t k_maxAttemps = 10; - - if (!info.IsReadOnly()) - { - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - if (m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - int result = QMessageBox::No; - if (!m_overwriteAll) - { - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Failed to Save Upgraded File"), - QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); - - result = mb.exec(); - if (result == QMessageBox::YesToAll) - { - m_overwriteAll = true; - } - } - - if (result == QMessageBox::Yes || m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - } - } - }); - } - - void Modifier::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target - , size_t remainingAttempts) - { - VersionExplorerCpp::FileEventHandler fileEventHandler; - - if (remainingAttempts == 0) - { - // all attempts failed, give up - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); - GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); - } - else if (remainingAttempts == 2) - { - // before the final attempt, flush all caches - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); - streamer->SetRequestCompleteCallback(flushRequest - , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction( - [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - else - { - // the actual move attempt - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) - { - m_tmpFileName.clear(); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - AZ::SystemTickBus::QueueFunction([this, asset]() - { - GraphUpgradeComplete(asset, OperationResult::Success, ""); - }); - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - } - } - - void Modifier::GraphUpgradeComplete - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - AZStd::lock_guard lock(m_mutex); - m_upgradeComplete = true; - m_upgradeResult = result; - m_upgradeMessage = message; - m_upgradeAsset = asset; - - if (!m_tmpFileName.empty()) - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); - - if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) - { - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); - } - } - - if (m_upgradeResult == OperationResult::Failure) - { - AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); - } - - m_tmpFileName.clear(); - } - - void Modifier::GraphUpgradeCompleteUIUpdate - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - QString text = asset.GetHint().c_str(); - QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); - - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); - QString assetName = asset.GetHint().c_str(); - - if (label->text().compare(assetName) == 0) - { - m_ui->tableWidget->removeCellWidget(row, ColumnAction); - m_ui->tableWidget->removeCellWidget(row, ColumnStatus); - - QToolButton* doneButton = new QToolButton(this); - doneButton->setToolTip("Upgrade complete"); - if (result == OperationResult::Success) - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); - } - else - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); - doneButton->setToolTip(message.data()); - } - - m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); - } - } - } - } - - void Modifier::FinalizeUpgrade() - { - Log("FinalizeUpgrade!"); - m_inProgress = false; - m_assetsToUpgrade.clear(); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(true); - m_keepEditorAlive.reset(); - m_ui->progressBar->setVisible(false); - - // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - if (assetsThatNeedManualInspection > 0) - { - m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); - } - else - { - m_ui->spinner->SetText("Upgrade complete."); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Interface::Get()->SetIsUpgrading(false); - m_settingsCache.reset(); - } - - // Scanning - - void Modifier::OnScan() - { - m_assetsToUpgrade.clear(); - m_assetsToInspect.clear(); - m_ui->tableWidget->setRowCount(0); - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); - m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); - DoScan(); - } - - void Modifier::DoScan() - { - m_state = ProcessState::Scan; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - - AZ::SystemTickBus::Handler::BusConnect(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - - if (!m_assetsToInspect.empty()) - { - m_discoveredAssets = m_assetsToInspect.size(); - m_failedAssets = 0; - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - m_ui->progressFrame->setVisible(true); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); - m_ui->progressBar->setValue(0); - - m_ui->spinner->SetIsBusy(true); - m_ui->spinner->SetBusyIconSize(32); - - m_ui->scanButton->setEnabled(false); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(false); - - m_inspectingAsset = m_assetsToInspect.begin(); - m_keepEditorAlive = AZStd::make_unique(); - } - } - - void Modifier::BackupComplete() - { - m_currentAssetRowIndex = 0; - m_ui->progressBar->setValue(0); - DoScan(); - } - - void Modifier::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) - { - Log("InspectAsset: %s", asset.GetHint().c_str()); - AZ::Entity* scriptCanvasEntity = nullptr; - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) - { - Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); - return; - } - - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); - } - - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); - bool forceUpgrade = m_ui->forceUpgrade->isChecked(); - ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); - - - if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) - { - ScanComplete(asset); - Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); - return; - } - - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - - if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) - { - m_assetsToUpgrade.push_back(asset); - - AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); - spinner->SetBusyIconSize(16); - - QPushButton* rowGoToButton = new QPushButton(this); - rowGoToButton->setText("Upgrade"); - rowGoToButton->setEnabled(false); - - connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { - - AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { - // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda - UpgradeSingle(rowGoToButton, spinner, assetInfo); - }); - - AZ::SystemTickBus::ExecuteQueuedEvents(); - - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); - } - - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); - - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - QByteArray assetNameUtf8 = asset.GetHint().c_str(); - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); - - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); - - QToolButton* browseButton = new QToolButton(this); - browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); - browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); - - QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); - connect(browseButton, &QPushButton::clicked, [absolutePath] { - AzQtComponents::ShowFileOnDesktop(absolutePath); - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); - ScanComplete(asset); - ++m_inspectedAssets; - ++m_currentAssetRowIndex; - } - - void Modifier::UpgradeSingle - ( QPushButton* rowGoToButton - , AzQtComponents::StyledBusyLabel* spinner - , AZ::Data::AssetInfo assetInfo) - { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - - if (asset) - { - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) - { - AZ::Interface::Get()->SetIsUpgrading(true); - m_isUpgradingSingleGraph = true; - m_logs.clear(); - m_ui->textEdit->clear(); - spinner->SetIsBusy(true); - rowGoToButton->setEnabled(false); - - m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() - , [asset](const UpgradeAssets::value_type& assetToUpgrade) - { - return assetToUpgrade.GetId() == asset.GetId(); - }); - - m_state = ProcessState::Upgrade; - AZ::SystemTickBus::Handler::BusConnect(); - } - } - } - - void Modifier::ScanComplete(const AZ::Data::Asset& asset) - { - Log("ScanComplete: %s", asset.GetHint().c_str()); - m_inProgress = false; - m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - m_ui->scanButton->setEnabled(true); - - m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); - FlushLogs(); - - if (m_inspectingAsset == m_assetsToInspect.end()) - { - AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - } - } - - void Modifier::FinalizeScan() - { - Log("FinalizeScan()"); - - m_ui->spinner->SetIsBusy(false); - m_ui->onlyShowOutdated->setEnabled(true); - - // Enable all the Upgrade buttons - for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) - { - QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); - if (button) - { - button->setEnabled(true); - } - } - - QString spinnerText = QStringLiteral("Scan Complete"); - if (m_assetsToUpgrade.empty()) - { - spinnerText.append(" - No graphs require upgrade!"); - } - else - { - spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" - , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); - } - - - m_ui->spinner->SetText(spinnerText); - m_ui->progressBar->setVisible(false); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - - m_keepEditorAlive.reset(); - m_settingsCache.reset(); - m_state = ProcessState::Inactive; - } - - void Modifier::FlushLogs() - { - if (m_logs.empty()) - { - return; - } - - const QTextCursor oldCursor = m_ui->textEdit->textCursor(); - QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); - - m_ui->textEdit->moveCursor(QTextCursor::End); - QTextCursor textCursor = m_ui->textEdit->textCursor(); - - while (!m_logs.empty()) - { - auto line = "\n" + m_logs.front(); - - m_logs.pop_front(); - - textCursor.insertText(line.c_str()); - } - - scrollBar->setValue(scrollBar->maximum()); - m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); - - } - - bool Modifier::CaptureLogFromTraceBus(const char* window, const char* message) - { - if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) - { - return true; - } - - AZStd::string msg = message; - if (msg.ends_with("\n")) - { - msg = msg.substr(0, msg.size() - 1); - } - - m_logs.push_back(msg); - return m_ui->updateReportingOnly->isChecked(); - } - - bool Modifier::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Error): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool Modifier::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Warning): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool Modifier::OnException(const char* message) - { - AZStd::string msg = AZStd::string::format("(Exception): %s", message); - return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); - } - - bool Modifier::OnPrintf(const char* window, const char* message) - { - return CaptureLogFromTraceBus(window, message); - } - - void Modifier::closeEvent(QCloseEvent* event) - { - m_keepEditorAlive.reset(); - - AzQtComponents::StyledDialog::closeEvent(event); - } - -#include - } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index 5f379d682a..e5a40ff096 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -8,160 +8,16 @@ #pragma once -#if !defined(Q_MOC_RUN) -#include - -AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -#include -#include -#include - -#include #include -#include -#include -#include -#endif - -class QPushButton; - -namespace Ui -{ - class Modifier; -} - -namespace AzQtComponents -{ - class StyledBusyLabel; -} - namespace ScriptCanvasEditor { - //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog - class Modifier - : public AzQtComponents::StyledDialog - , private AZ::SystemTickBus::Handler - , private UpgradeNotifications::Bus::Handler - , private AZ::Debug::TraceMessageBus::Handler + namespace VersionExplorer { - Q_OBJECT - - public: - AZ_CLASS_ALLOCATOR(Modifier, AZ::SystemAllocator, 0); - - explicit Modifier(QWidget* parent = nullptr); - ~Modifier(); - - private: - - static constexpr int ColumnAsset = 0; - static constexpr int ColumnAction = 1; - static constexpr int ColumnBrowse = 2; - static constexpr int ColumnStatus = 3; - - void OnScan(); - void OnClose(); - - enum class ProcessState + class Modifier { - Inactive, - Backup, - Scan, - Upgrade, + public: + AZ_CLASS_ALLOCATOR(Modifier, AZ::SystemAllocator, 0); }; - ProcessState m_state = ProcessState::Inactive; - - void DoScan(); - void ScanComplete(const AZ::Data::Asset&); - - void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); - - void OnUpgradeAll(); - - // SystemTickBus::Handler - void OnSystemTick() override; - // - - // AZ::Debug::TranceMessageBus::Handler - bool OnException(const char* /*message*/) override; - bool OnPrintf(const char* /*window*/, const char* /*message*/) override; - bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - // - - bool CaptureLogFromTraceBus(const char* window, const char* message); - - enum class OperationResult - { - Success, - Failure, - }; - - void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); - - bool IsUpgrading() const; - - bool m_inProgress = false; - // scan fields - size_t m_currentAssetRowIndex = 0; - size_t m_inspectedAssets = 0; - size_t m_failedAssets = 0; - size_t m_discoveredAssets = 0; - - IUpgradeRequests::AssetList m_assetsToInspect; - IUpgradeRequests::AssetList::iterator m_inspectingAsset; - using UpgradeAssets = AZStd::vector>; - UpgradeAssets m_assetsToUpgrade; - UpgradeAssets::iterator m_inProgressAsset; - - AZ::Data::Asset m_currentAsset; - - AZStd::unique_ptr m_ui; - - AZStd::unique_ptr m_settingsCache; - - // upgrade fields - AZStd::recursive_mutex m_mutex; - bool m_upgradeComplete = false; - AZ::Data::Asset m_upgradeAsset; - int m_upgradeAssetIndex = 0; - OperationResult m_upgradeResult; - AZStd::string m_upgradeMessage; - AZStd::string m_tmpFileName; - - AZStd::unique_ptr m_keepEditorAlive; - - AZStd::deque m_logs; - - AZ::Entity* m_scriptCanvasEntity = nullptr; - - bool m_isUpgradingSingleGraph = false; - - void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); - - void FlushLogs(); - - void FinalizeUpgrade(); - void FinalizeScan(); - - void BackupComplete(); - AZStd::string BackupGraph(const AZ::Data::Asset&); - void UpgradeGraph(const AZ::Data::Asset&); - - void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; - - void OnSourceFileReleased(AZ::Data::Asset asset); - - void closeEvent(QCloseEvent* event) override; - - bool m_overwriteAll = false; - void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); - - void Log(const char* format, ...); - }; + } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index 29f5f8f530..f74c27004b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -6,1018 +6,17 @@ * */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -namespace VersionExplorerCpp +namespace ScannerCpp { - class FileEventHandler - : public AZ::IO::FileIOEventBus::Handler - { - public: - int m_errorCode = 0; - AZStd::string m_fileName; - - FileEventHandler() - { - BusConnect(); - } - ~FileEventHandler() - { - BusDisconnect(); - } - - void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override - { - m_errorCode = errorCode; - - if (fileName) - { - m_fileName = fileName; - } - } - }; } namespace ScriptCanvasEditor { - EditorKeepAlive::EditorKeepAlive() - { - ISystem* system = nullptr; - CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); - - m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); - - if (m_edKeepEditorActive) - { - m_keepEditorActive = m_edKeepEditorActive->GetIVal(); - m_edKeepEditorActive->Set(1); - } - } - - EditorKeepAlive::~EditorKeepAlive() - { - if (m_edKeepEditorActive) - { - m_edKeepEditorActive->Set(m_keepEditorActive); - } - } - - Scanner::Scanner(QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent) - , m_ui(new Ui::Scanner()) - { - m_ui->setupUi(this); - - m_ui->tableWidget->horizontalHeader()->setVisible(false); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); - m_ui->tableWidget->setColumnWidth(3, 22); - - m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); - m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); - - connect(m_ui->scanButton, &QPushButton::pressed, this, &Scanner::OnScan); - connect(m_ui->closeButton, &QPushButton::pressed, this, &Scanner::OnClose); - connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &Scanner::OnUpgradeAll); - - m_ui->progressBar->setValue(0); - m_ui->progressBar->setVisible(false); - - m_keepEditorAlive = AZStd::make_unique(); - m_inspectingAsset = m_assetsToInspect.end(); - - } - - Scanner::~Scanner() - { - AZ::SystemTickBus::Handler::BusDisconnect(); - - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - - } - - void Scanner::Log(const char* format, ...) + namespace VersionExplorer { - if (m_ui->verbose->isChecked()) - { - char sBuffer[2048]; - va_list ArgList; - va_start(ArgList, format); - azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); - sBuffer[sizeof(sBuffer) - 1] = '\0'; - va_end(ArgList); - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); - } - } - - void Scanner::OnClose() - { - reject(); - } - - bool Scanner::IsUpgrading() const - { - return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; - } - - void Scanner::OnSystemTick() - { - switch (m_state) - { - case ProcessState::Scan: - - if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) - { - m_inProgress = true; - AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; - m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); - m_currentAsset.BlockUntilLoadComplete(); - if (m_currentAsset.IsReady()) - { - // The asset is ready, grab its info - m_inProgress = true; - InspectAsset(m_currentAsset, assetToUpgrade); - } - else - { - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem - ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - ++m_currentAssetRowIndex; - - Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); - ++m_failedAssets; - ScanComplete(m_currentAsset); - } - } - break; - - case ProcessState::Upgrade: - { - AZStd::lock_guard lock(m_mutex); - if (m_upgradeComplete) - { - ++m_upgradeAssetIndex; - m_inProgress = false; - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - - if (m_scriptCanvasEntity) - { - m_scriptCanvasEntity->Deactivate(); - m_scriptCanvasEntity = nullptr; - } - - GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); - - if (!m_isUpgradingSingleGraph) - { - if (m_inProgressAsset != m_assetsToUpgrade.end()) - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - } - - if (m_inProgressAsset == m_assetsToUpgrade.end()) - { - FinalizeUpgrade(); - } - } - else - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - m_inProgress = false; - m_state = ProcessState::Inactive; - m_settingsCache.reset(); - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - } - - m_isUpgradingSingleGraph = false; - - if (m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(false); - } - - m_upgradeComplete = false; - } - - if (!IsUpgrading() && m_state == ProcessState::Upgrade) - { - AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); - // Make the backup - if (errorMessage.empty()) - { - Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); - QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); - spinner->SetIsBusy(true); - } - } - - // Upgrade the graph - UpgradeGraph(*m_inProgressAsset); - } - else - { - Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); - GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); - } - - } - break; - } - default: - break; - } - - FlushLogs(); - - AZ::Data::AssetManager::Instance().DispatchEvents(); - AZ::SystemTickBus::ExecuteQueuedEvents(); - } - - // Backup - - void Scanner::OnUpgradeAll() - { - m_state = ProcessState::Upgrade; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - AZ::Interface::Get()->SetIsUpgrading(true); - AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); - m_inProgressAsset = m_assetsToUpgrade.begin(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - AZ::SystemTickBus::Handler::BusConnect(); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - m_keepEditorAlive = AZStd::make_unique(); } - - AZStd::string Scanner::BackupGraph(const AZ::Data::Asset& asset) - { - if (!m_ui->makeBackupCheckbox->isChecked()) - { - // considered a success - return ""; - } - - QDateTime theTime = QDateTime::currentDateTime(); - QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; - - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) - { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); - return "Failed to create backup folder"; - } - } - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); - if (sourceInfoFound) - { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Scanner::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); - return "Failed to find source file"; - } - - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Scanner::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return "Failed to copy source file to backup location"; - } - - Log("Scanner::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return ""; - } - - void Scanner::UpgradeGraph(const AZ::Data::Asset& asset) - { - m_inProgress = true; - m_upgradeComplete = false; - Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); - m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); - m_scriptCanvasEntity = nullptr; - - UpgradeNotifications::Bus::Handler::BusConnect(); - - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "Scanner::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) - { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - if (graphComponent) - { - m_scriptCanvasEntity = scriptCanvasEntity; - - graphComponent->UpgradeGraph - ( asset - , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_ui->verbose->isChecked()); - } - } - - AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); - } - - void Scanner::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - if (!fullPathFound) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); - } - - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - this->OnSourceFileReleased(asset); - }); - streamer->QueueRequest(flushRequest); - } - - void Scanner::OnSourceFileReleased(AZ::Data::Asset asset) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - m_tmpFileName.clear(); - AZStd::string tmpFileName; - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); - return; - } - - bool tempSavedSucceeded = false; - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); - } - - fileStream.Close(); - } - - // attempt to remove temporary file no matter what - m_tmpFileName = tmpFileName; - if (!tempSavedSucceeded) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); - return; - } - - using SCCommandBus = AzToolsFramework::SourceControlCommandBus; - SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, - [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - constexpr const size_t k_maxAttemps = 10; - - if (!info.IsReadOnly()) - { - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - if (m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - int result = QMessageBox::No; - if (!m_overwriteAll) - { - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Failed to Save Upgraded File"), - QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); - - result = mb.exec(); - if (result == QMessageBox::YesToAll) - { - m_overwriteAll = true; - } - } - - if (result == QMessageBox::Yes || m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - } - } - }); - } - - void Scanner::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target - , size_t remainingAttempts) - { - VersionExplorerCpp::FileEventHandler fileEventHandler; - - if (remainingAttempts == 0) - { - // all attempts failed, give up - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); - GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); - } - else if (remainingAttempts == 2) - { - // before the final attempt, flush all caches - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); - streamer->SetRequestCompleteCallback(flushRequest - , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction( - [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - else - { - // the actual move attempt - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) - { - m_tmpFileName.clear(); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - AZ::SystemTickBus::QueueFunction([this, asset]() - { - GraphUpgradeComplete(asset, OperationResult::Success, ""); - }); - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - } - } - - void Scanner::GraphUpgradeComplete - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - AZStd::lock_guard lock(m_mutex); - m_upgradeComplete = true; - m_upgradeResult = result; - m_upgradeMessage = message; - m_upgradeAsset = asset; - - if (!m_tmpFileName.empty()) - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); - - if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) - { - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); - } - } - - if (m_upgradeResult == OperationResult::Failure) - { - AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); - } - - m_tmpFileName.clear(); - } - - void Scanner::GraphUpgradeCompleteUIUpdate - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - QString text = asset.GetHint().c_str(); - QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); - - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); - QString assetName = asset.GetHint().c_str(); - - if (label->text().compare(assetName) == 0) - { - m_ui->tableWidget->removeCellWidget(row, ColumnAction); - m_ui->tableWidget->removeCellWidget(row, ColumnStatus); - - QToolButton* doneButton = new QToolButton(this); - doneButton->setToolTip("Upgrade complete"); - if (result == OperationResult::Success) - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); - } - else - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); - doneButton->setToolTip(message.data()); - } - - m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); - } - } - } - } - - void Scanner::FinalizeUpgrade() - { - Log("FinalizeUpgrade!"); - m_inProgress = false; - m_assetsToUpgrade.clear(); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(true); - m_keepEditorAlive.reset(); - m_ui->progressBar->setVisible(false); - - // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - if (assetsThatNeedManualInspection > 0) - { - m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); - } - else - { - m_ui->spinner->SetText("Upgrade complete."); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Interface::Get()->SetIsUpgrading(false); - m_settingsCache.reset(); - } - - // Scanning - - void Scanner::OnScan() - { - m_assetsToUpgrade.clear(); - m_assetsToInspect.clear(); - m_ui->tableWidget->setRowCount(0); - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); - m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); - DoScan(); - } - - void Scanner::DoScan() - { - m_state = ProcessState::Scan; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - - AZ::SystemTickBus::Handler::BusConnect(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - - if (!m_assetsToInspect.empty()) - { - m_discoveredAssets = m_assetsToInspect.size(); - m_failedAssets = 0; - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - m_ui->progressFrame->setVisible(true); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); - m_ui->progressBar->setValue(0); - - m_ui->spinner->SetIsBusy(true); - m_ui->spinner->SetBusyIconSize(32); - - m_ui->scanButton->setEnabled(false); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(false); - - m_inspectingAsset = m_assetsToInspect.begin(); - m_keepEditorAlive = AZStd::make_unique(); - } - } - - void Scanner::BackupComplete() - { - m_currentAssetRowIndex = 0; - m_ui->progressBar->setValue(0); - DoScan(); - } - - void Scanner::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) - { - Log("InspectAsset: %s", asset.GetHint().c_str()); - AZ::Entity* scriptCanvasEntity = nullptr; - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) - { - Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); - return; - } - - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); - } - - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); - bool forceUpgrade = m_ui->forceUpgrade->isChecked(); - ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); - - - if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) - { - ScanComplete(asset); - Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); - return; - } - - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - - if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) - { - m_assetsToUpgrade.push_back(asset); - - AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); - spinner->SetBusyIconSize(16); - - QPushButton* rowGoToButton = new QPushButton(this); - rowGoToButton->setText("Upgrade"); - rowGoToButton->setEnabled(false); - - connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { - - AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { - // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda - UpgradeSingle(rowGoToButton, spinner, assetInfo); - }); - - AZ::SystemTickBus::ExecuteQueuedEvents(); - - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); - } - - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); - - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - QByteArray assetNameUtf8 = asset.GetHint().c_str(); - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); - - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); - - QToolButton* browseButton = new QToolButton(this); - browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); - browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); - - QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); - connect(browseButton, &QPushButton::clicked, [absolutePath] { - AzQtComponents::ShowFileOnDesktop(absolutePath); - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); - ScanComplete(asset); - ++m_inspectedAssets; - ++m_currentAssetRowIndex; - } - - void Scanner::UpgradeSingle - ( QPushButton* rowGoToButton - , AzQtComponents::StyledBusyLabel* spinner - , AZ::Data::AssetInfo assetInfo) - { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - - if (asset) - { - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) - { - AZ::Interface::Get()->SetIsUpgrading(true); - m_isUpgradingSingleGraph = true; - m_logs.clear(); - m_ui->textEdit->clear(); - spinner->SetIsBusy(true); - rowGoToButton->setEnabled(false); - - m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() - , [asset](const UpgradeAssets::value_type& assetToUpgrade) - { - return assetToUpgrade.GetId() == asset.GetId(); - }); - - m_state = ProcessState::Upgrade; - AZ::SystemTickBus::Handler::BusConnect(); - } - } - } - - void Scanner::ScanComplete(const AZ::Data::Asset& asset) - { - Log("ScanComplete: %s", asset.GetHint().c_str()); - m_inProgress = false; - m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - m_ui->scanButton->setEnabled(true); - - m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); - FlushLogs(); - - if (m_inspectingAsset == m_assetsToInspect.end()) - { - AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - } - } - - void Scanner::FinalizeScan() - { - Log("FinalizeScan()"); - - m_ui->spinner->SetIsBusy(false); - m_ui->onlyShowOutdated->setEnabled(true); - - // Enable all the Upgrade buttons - for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) - { - QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); - if (button) - { - button->setEnabled(true); - } - } - - QString spinnerText = QStringLiteral("Scan Complete"); - if (m_assetsToUpgrade.empty()) - { - spinnerText.append(" - No graphs require upgrade!"); - } - else - { - spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" - , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); - } - - - m_ui->spinner->SetText(spinnerText); - m_ui->progressBar->setVisible(false); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - - m_keepEditorAlive.reset(); - m_settingsCache.reset(); - m_state = ProcessState::Inactive; - } - - void Scanner::FlushLogs() - { - if (m_logs.empty()) - { - return; - } - - const QTextCursor oldCursor = m_ui->textEdit->textCursor(); - QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); - - m_ui->textEdit->moveCursor(QTextCursor::End); - QTextCursor textCursor = m_ui->textEdit->textCursor(); - - while (!m_logs.empty()) - { - auto line = "\n" + m_logs.front(); - - m_logs.pop_front(); - - textCursor.insertText(line.c_str()); - } - - scrollBar->setValue(scrollBar->maximum()); - m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); - - } - - bool Scanner::CaptureLogFromTraceBus(const char* window, const char* message) - { - if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) - { - return true; - } - - AZStd::string msg = message; - if (msg.ends_with("\n")) - { - msg = msg.substr(0, msg.size() - 1); - } - - m_logs.push_back(msg); - return m_ui->updateReportingOnly->isChecked(); - } - - bool Scanner::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Error): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool Scanner::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Warning): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool Scanner::OnException(const char* message) - { - AZStd::string msg = AZStd::string::format("(Exception): %s", message); - return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); - } - - bool Scanner::OnPrintf(const char* window, const char* message) - { - return CaptureLogFromTraceBus(window, message); - } - - void Scanner::closeEvent(QCloseEvent* event) - { - m_keepEditorAlive.reset(); - - AzQtComponents::StyledDialog::closeEvent(event); - } - -#include - } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h index 574b2b2503..19642a07f1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h @@ -8,160 +8,16 @@ #pragma once -#if !defined(Q_MOC_RUN) -#include - -AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -#include -#include -#include - -#include #include -#include -#include -#include -#endif - -class QPushButton; - -namespace Ui -{ - class Scanner; -} - -namespace AzQtComponents -{ - class StyledBusyLabel; -} - namespace ScriptCanvasEditor { - //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog - class Scanner - : public AzQtComponents::StyledDialog - , private AZ::SystemTickBus::Handler - , private UpgradeNotifications::Bus::Handler - , private AZ::Debug::TraceMessageBus::Handler + namespace VersionExplorer { - Q_OBJECT - - public: - AZ_CLASS_ALLOCATOR(Scanner, AZ::SystemAllocator, 0); - - explicit Scanner(QWidget* parent = nullptr); - ~Scanner(); - - private: - - static constexpr int ColumnAsset = 0; - static constexpr int ColumnAction = 1; - static constexpr int ColumnBrowse = 2; - static constexpr int ColumnStatus = 3; - - void OnScan(); - void OnClose(); - - enum class ProcessState + class Scanner { - Inactive, - Backup, - Scan, - Upgrade, + public: + AZ_CLASS_ALLOCATOR(Scanner, AZ::SystemAllocator, 0); }; - ProcessState m_state = ProcessState::Inactive; - - void DoScan(); - void ScanComplete(const AZ::Data::Asset&); - - void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); - - void OnUpgradeAll(); - - // SystemTickBus::Handler - void OnSystemTick() override; - // - - // AZ::Debug::TranceMessageBus::Handler - bool OnException(const char* /*message*/) override; - bool OnPrintf(const char* /*window*/, const char* /*message*/) override; - bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - // - - bool CaptureLogFromTraceBus(const char* window, const char* message); - - enum class OperationResult - { - Success, - Failure, - }; - - void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); - - bool IsUpgrading() const; - - bool m_inProgress = false; - // scan fields - size_t m_currentAssetRowIndex = 0; - size_t m_inspectedAssets = 0; - size_t m_failedAssets = 0; - size_t m_discoveredAssets = 0; - - IUpgradeRequests::AssetList m_assetsToInspect; - IUpgradeRequests::AssetList::iterator m_inspectingAsset; - using UpgradeAssets = AZStd::vector>; - UpgradeAssets m_assetsToUpgrade; - UpgradeAssets::iterator m_inProgressAsset; - - AZ::Data::Asset m_currentAsset; - - AZStd::unique_ptr m_ui; - - AZStd::unique_ptr m_settingsCache; - - // upgrade fields - AZStd::recursive_mutex m_mutex; - bool m_upgradeComplete = false; - AZ::Data::Asset m_upgradeAsset; - int m_upgradeAssetIndex = 0; - OperationResult m_upgradeResult; - AZStd::string m_upgradeMessage; - AZStd::string m_tmpFileName; - - AZStd::unique_ptr m_keepEditorAlive; - - AZStd::deque m_logs; - - AZ::Entity* m_scriptCanvasEntity = nullptr; - - bool m_isUpgradingSingleGraph = false; - - void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); - - void FlushLogs(); - - void FinalizeUpgrade(); - void FinalizeScan(); - - void BackupComplete(); - AZStd::string BackupGraph(const AZ::Data::Asset&); - void UpgradeGraph(const AZ::Data::Asset&); - - void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; - - void OnSourceFileReleased(AZ::Data::Asset asset); - - void closeEvent(QCloseEvent* event) override; - - bool m_overwriteAll = false; - void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); - - void Log(const char* format, ...); - }; + } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp index 6c9acea25c..be4b619bfd 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp @@ -6,1018 +6,94 @@ * */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -namespace VersionExplorerCpp +namespace LoggerCpp { - class FileEventHandler - : public AZ::IO::FileIOEventBus::Handler - { - public: - int m_errorCode = 0; - AZStd::string m_fileName; - - FileEventHandler() - { - BusConnect(); - } - - ~FileEventHandler() - { - BusDisconnect(); - } - - void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override - { - m_errorCode = errorCode; - if (fileName) - { - m_fileName = fileName; - } - } - }; } namespace ScriptCanvasEditor { - EditorKeepAlive::EditorKeepAlive() - { - ISystem* system = nullptr; - CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); - - m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); - - if (m_edKeepEditorActive) - { - m_keepEditorActive = m_edKeepEditorActive->GetIVal(); - m_edKeepEditorActive->Set(1); - } - } - - EditorKeepAlive::~EditorKeepAlive() - { - if (m_edKeepEditorActive) - { - m_edKeepEditorActive->Set(m_keepEditorActive); - } - } - - VersionExplorerLog::VersionExplorerLog(QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent) - , m_ui(new Ui::VersionExplorerLog()) - { - m_ui->setupUi(this); - - m_ui->tableWidget->horizontalHeader()->setVisible(false); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); - m_ui->tableWidget->setColumnWidth(3, 22); - - m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); - m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); - - connect(m_ui->scanButton, &QPushButton::pressed, this, &VersionExplorerLog::OnScan); - connect(m_ui->closeButton, &QPushButton::pressed, this, &VersionExplorerLog::OnClose); - connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &VersionExplorerLog::OnUpgradeAll); - - m_ui->progressBar->setValue(0); - m_ui->progressBar->setVisible(false); - - m_keepEditorAlive = AZStd::make_unique(); - m_inspectingAsset = m_assetsToInspect.end(); - - } - - VersionExplorerLog::~VersionExplorerLog() - { - AZ::SystemTickBus::Handler::BusDisconnect(); - - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - - } - - void VersionExplorerLog::Log(const char* format, ...) - { - if (m_ui->verbose->isChecked()) - { - char sBuffer[2048]; - va_list ArgList; - va_start(ArgList, format); - azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); - sBuffer[sizeof(sBuffer) - 1] = '\0'; - va_end(ArgList); - - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); - } - } - - void VersionExplorerLog::OnClose() - { - reject(); - } - - bool VersionExplorerLog::IsUpgrading() const - { - return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; - } - - void VersionExplorerLog::OnSystemTick() - { - switch (m_state) - { - case ProcessState::Scan: - - if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) - { - m_inProgress = true; - AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; - m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); - m_currentAsset.BlockUntilLoadComplete(); - if (m_currentAsset.IsReady()) - { - // The asset is ready, grab its info - m_inProgress = true; - InspectAsset(m_currentAsset, assetToUpgrade); - } - else - { - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem - ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - ++m_currentAssetRowIndex; - - Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); - ++m_failedAssets; - ScanComplete(m_currentAsset); - } - } - break; - - case ProcessState::Upgrade: - { - AZStd::lock_guard lock(m_mutex); - if (m_upgradeComplete) - { - ++m_upgradeAssetIndex; - m_inProgress = false; - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - - if (m_scriptCanvasEntity) - { - m_scriptCanvasEntity->Deactivate(); - m_scriptCanvasEntity = nullptr; - } - - GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); - - if (!m_isUpgradingSingleGraph) - { - if (m_inProgressAsset != m_assetsToUpgrade.end()) - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - } - - if (m_inProgressAsset == m_assetsToUpgrade.end()) - { - FinalizeUpgrade(); - } - } - else - { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - m_inProgress = false; - m_state = ProcessState::Inactive; - m_settingsCache.reset(); - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - } - - m_isUpgradingSingleGraph = false; - - if (m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(false); - } - - m_upgradeComplete = false; - } - - if (!IsUpgrading() && m_state == ProcessState::Upgrade) - { - AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); - // Make the backup - if (errorMessage.empty()) - { - Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); - QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); - spinner->SetIsBusy(true); - } - } - - // Upgrade the graph - UpgradeGraph(*m_inProgressAsset); - } - else - { - Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); - GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); - } - - } - break; - } - default: - break; - } - - FlushLogs(); - - AZ::Data::AssetManager::Instance().DispatchEvents(); - AZ::SystemTickBus::ExecuteQueuedEvents(); - } - - // Backup - - void VersionExplorerLog::OnUpgradeAll() - { - m_state = ProcessState::Upgrade; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - AZ::Interface::Get()->SetIsUpgrading(true); - AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); - m_inProgressAsset = m_assetsToUpgrade.begin(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - AZ::SystemTickBus::Handler::BusConnect(); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - m_keepEditorAlive = AZStd::make_unique(); - } - - AZStd::string VersionExplorerLog::BackupGraph(const AZ::Data::Asset& asset) + namespace VersionExplorer { - if (!m_ui->makeBackupCheckbox->isChecked()) + void Log::Activate() { - // considered a success - return ""; + AZ::Debug::TraceMessageBus::Handler::BusConnect(); } - QDateTime theTime = QDateTime::currentDateTime(); - QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; - - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + void Log::AddEntry(const char* format, ...) { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + if (m_isVerbose) { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); - return "Failed to create backup folder"; + char sBuffer[2048]; + va_list ArgList; + va_start(ArgList, format); + azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); + sBuffer[sizeof(sBuffer) - 1] = '\0'; + va_end(ArgList); + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); } } - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); - if (sourceInfoFound) + bool Log::CaptureFromTraceBus(const char* window, const char* message) { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorerLog::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); - return "Failed to find source file"; - } - - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorerLog::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return "Failed to copy source file to backup location"; - } - - Log("VersionExplorerLog::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return ""; - } - - void VersionExplorerLog::UpgradeGraph(const AZ::Data::Asset& asset) - { - m_inProgress = true; - m_upgradeComplete = false; - Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); - m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); - m_scriptCanvasEntity = nullptr; - - UpgradeNotifications::Bus::Handler::BusConnect(); - - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "VersionExplorerLog::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) + if (m_isExclusiveReportingEnabled && window != ScriptCanvas::k_VersionExplorerWindow) { - return; + return true; } - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) + AZStd::string msg = message; + if (msg.ends_with("\n")) { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); + msg = msg.substr(0, msg.size() - 1); } - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - if (graphComponent) - { - m_scriptCanvasEntity = scriptCanvasEntity; - - graphComponent->UpgradeGraph - ( asset - , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_ui->verbose->isChecked()); - } + m_logs.push_back(msg); + return m_isExclusiveReportingEnabled; } - AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); - } - - void VersionExplorerLog::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - if (!fullPathFound) + void Log::Deactivate() { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); + AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); } - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - this->OnSourceFileReleased(asset); - }); - streamer->QueueRequest(flushRequest); - } - - void VersionExplorerLog::OnSourceFileReleased(AZ::Data::Asset asset) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - m_tmpFileName.clear(); - AZStd::string tmpFileName; - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) + const AZStd::vector& Log::GetEntries() const { - GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); - return; + return m_logs; } - bool tempSavedSucceeded = false; - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) + void Log::SetVersionExporerExclusivity(bool enabled) { - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); - } - - fileStream.Close(); + m_isExclusiveReportingEnabled = enabled; } - // attempt to remove temporary file no matter what - m_tmpFileName = tmpFileName; - if (!tempSavedSucceeded) + void Log::SetVerbose(bool verbosity) { - GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); - return; + m_isVerbose = verbosity; } - using SCCommandBus = AzToolsFramework::SourceControlCommandBus; - SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, - [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) + bool Log::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) { - constexpr const size_t k_maxAttemps = 10; - - if (!info.IsReadOnly()) - { - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - if (m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - int result = QMessageBox::No; - if (!m_overwriteAll) - { - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Failed to Save Upgraded File"), - QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); - - result = mb.exec(); - if (result == QMessageBox::YesToAll) - { - m_overwriteAll = true; - } - } - - if (result == QMessageBox::Yes || m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - } - } - }); - } - - void VersionExplorerLog::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target - , size_t remainingAttempts) - { - VersionExplorerCpp::FileEventHandler fileEventHandler; - - if (remainingAttempts == 0) - { - // all attempts failed, give up - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); - GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); + AZStd::string msg = AZStd::string::format("(Error): %s", message); + return CaptureFromTraceBus(window, msg.c_str()); } - else if (remainingAttempts == 2) - { - // before the final attempt, flush all caches - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); - streamer->SetRequestCompleteCallback(flushRequest - , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction( - [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - else - { - // the actual move attempt - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) - { - m_tmpFileName.clear(); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - AZ::SystemTickBus::QueueFunction([this, asset]() - { - GraphUpgradeComplete(asset, OperationResult::Success, ""); - }); - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - } - } - - void VersionExplorerLog::GraphUpgradeComplete - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - AZStd::lock_guard lock(m_mutex); - m_upgradeComplete = true; - m_upgradeResult = result; - m_upgradeMessage = message; - m_upgradeAsset = asset; - - if (!m_tmpFileName.empty()) - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); - - if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) - { - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); - } - } - - if (m_upgradeResult == OperationResult::Failure) - { - AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); - } - - m_tmpFileName.clear(); - } - - void VersionExplorerLog::GraphUpgradeCompleteUIUpdate - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - QString text = asset.GetHint().c_str(); - QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); - - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); - QString assetName = asset.GetHint().c_str(); - - if (label->text().compare(assetName) == 0) - { - m_ui->tableWidget->removeCellWidget(row, ColumnAction); - m_ui->tableWidget->removeCellWidget(row, ColumnStatus); - - QToolButton* doneButton = new QToolButton(this); - doneButton->setToolTip("Upgrade complete"); - if (result == OperationResult::Success) - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); - } - else - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); - doneButton->setToolTip(message.data()); - } - - m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); - } - } - } - } - - void VersionExplorerLog::FinalizeUpgrade() - { - Log("FinalizeUpgrade!"); - m_inProgress = false; - m_assetsToUpgrade.clear(); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(true); - m_keepEditorAlive.reset(); - m_ui->progressBar->setVisible(false); - - // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - if (assetsThatNeedManualInspection > 0) - { - m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); - } - else - { - m_ui->spinner->SetText("Upgrade complete."); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Interface::Get()->SetIsUpgrading(false); - m_settingsCache.reset(); - } - - // Scanning - - void VersionExplorerLog::OnScan() - { - m_assetsToUpgrade.clear(); - m_assetsToInspect.clear(); - m_ui->tableWidget->setRowCount(0); - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); - m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); - DoScan(); - } - - void VersionExplorerLog::DoScan() - { - m_state = ProcessState::Scan; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - AZ::SystemTickBus::Handler::BusConnect(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - - if (!m_assetsToInspect.empty()) + bool Log::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) { - m_discoveredAssets = m_assetsToInspect.size(); - m_failedAssets = 0; - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - m_ui->progressFrame->setVisible(true); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); - m_ui->progressBar->setValue(0); - - m_ui->spinner->SetIsBusy(true); - m_ui->spinner->SetBusyIconSize(32); - - m_ui->scanButton->setEnabled(false); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(false); - - m_inspectingAsset = m_assetsToInspect.begin(); - m_keepEditorAlive = AZStd::make_unique(); + AZStd::string msg = AZStd::string::format("(Warning): %s", message); + return CaptureFromTraceBus(window, msg.c_str()); } - } - - void VersionExplorerLog::BackupComplete() - { - m_currentAssetRowIndex = 0; - m_ui->progressBar->setValue(0); - DoScan(); - } - void VersionExplorerLog::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) - { - Log("InspectAsset: %s", asset.GetHint().c_str()); - AZ::Entity* scriptCanvasEntity = nullptr; - if (asset.GetType() == azrtti_typeid()) + bool Log::OnException(const char* message) { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) - { - Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); - return; - } - - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); + AZStd::string msg = AZStd::string::format("(Exception): %s", message); + return CaptureFromTraceBus("Script Canvas", msg.c_str()); } - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); - bool forceUpgrade = m_ui->forceUpgrade->isChecked(); - ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); - - - if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) + bool Log::OnPrintf(const char* window, const char* message) { - ScanComplete(asset); - Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); - return; + return CaptureFromTraceBus(window, message); } - - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - - if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) - { - m_assetsToUpgrade.push_back(asset); - - AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); - spinner->SetBusyIconSize(16); - - QPushButton* rowGoToButton = new QPushButton(this); - rowGoToButton->setText("Upgrade"); - rowGoToButton->setEnabled(false); - - connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { - - AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { - // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda - UpgradeSingle(rowGoToButton, spinner, assetInfo); - }); - - AZ::SystemTickBus::ExecuteQueuedEvents(); - - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); - } - - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); - - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - QByteArray assetNameUtf8 = asset.GetHint().c_str(); - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); - - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); - - QToolButton* browseButton = new QToolButton(this); - browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); - browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); - - QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); - connect(browseButton, &QPushButton::clicked, [absolutePath] { - AzQtComponents::ShowFileOnDesktop(absolutePath); - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); - ScanComplete(asset); - ++m_inspectedAssets; - ++m_currentAssetRowIndex; } - - void VersionExplorerLog::UpgradeSingle - ( QPushButton* rowGoToButton - , AzQtComponents::StyledBusyLabel* spinner - , AZ::Data::AssetInfo assetInfo) - { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - - if (asset) - { - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) - { - AZ::Interface::Get()->SetIsUpgrading(true); - m_isUpgradingSingleGraph = true; - m_logs.clear(); - m_ui->textEdit->clear(); - spinner->SetIsBusy(true); - rowGoToButton->setEnabled(false); - - m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() - , [asset](const UpgradeAssets::value_type& assetToUpgrade) - { - return assetToUpgrade.GetId() == asset.GetId(); - }); - - m_state = ProcessState::Upgrade; - AZ::SystemTickBus::Handler::BusConnect(); - } - } - } - - void VersionExplorerLog::ScanComplete(const AZ::Data::Asset& asset) - { - Log("ScanComplete: %s", asset.GetHint().c_str()); - m_inProgress = false; - m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - m_ui->scanButton->setEnabled(true); - - m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); - FlushLogs(); - - if (m_inspectingAsset == m_assetsToInspect.end()) - { - AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - } - } - - void VersionExplorerLog::FinalizeScan() - { - Log("FinalizeScan()"); - - m_ui->spinner->SetIsBusy(false); - m_ui->onlyShowOutdated->setEnabled(true); - - // Enable all the Upgrade buttons - for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) - { - QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); - if (button) - { - button->setEnabled(true); - } - } - - QString spinnerText = QStringLiteral("Scan Complete"); - if (m_assetsToUpgrade.empty()) - { - spinnerText.append(" - No graphs require upgrade!"); - } - else - { - spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" - , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); - } - - - m_ui->spinner->SetText(spinnerText); - m_ui->progressBar->setVisible(false); - - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - - m_keepEditorAlive.reset(); - m_settingsCache.reset(); - m_state = ProcessState::Inactive; - } - - void VersionExplorerLog::FlushLogs() - { - if (m_logs.empty()) - { - return; - } - - const QTextCursor oldCursor = m_ui->textEdit->textCursor(); - QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); - - m_ui->textEdit->moveCursor(QTextCursor::End); - QTextCursor textCursor = m_ui->textEdit->textCursor(); - - while (!m_logs.empty()) - { - auto line = "\n" + m_logs.front(); - - m_logs.pop_front(); - - textCursor.insertText(line.c_str()); - } - - scrollBar->setValue(scrollBar->maximum()); - m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); - - } - - bool VersionExplorerLog::CaptureLogFromTraceBus(const char* window, const char* message) - { - if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) - { - return true; - } - - AZStd::string msg = message; - if (msg.ends_with("\n")) - { - msg = msg.substr(0, msg.size() - 1); - } - - m_logs.push_back(msg); - return m_ui->updateReportingOnly->isChecked(); - } - - bool VersionExplorerLog::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Error): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool VersionExplorerLog::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Warning): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } - - bool VersionExplorerLog::OnException(const char* message) - { - AZStd::string msg = AZStd::string::format("(Exception): %s", message); - return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); - } - - bool VersionExplorerLog::OnPrintf(const char* window, const char* message) - { - return CaptureLogFromTraceBus(window, message); - } - - void VersionExplorerLog::closeEvent(QCloseEvent* event) - { - m_keepEditorAlive.reset(); - - AzQtComponents::StyledDialog::closeEvent(event); - } - -#include - } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h index 498b2f7745..1ba8e8c9b1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h @@ -8,160 +8,36 @@ #pragma once -#if !defined(Q_MOC_RUN) -#include - -AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -#include -#include -#include - -#include #include - -#include -#include #include -#endif - -class QPushButton; - -namespace Ui -{ - class VersionExplorerLog; -} - -namespace AzQtComponents -{ - class StyledBusyLabel; -} namespace ScriptCanvasEditor { - //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog - class VersionExplorerLog - : public AzQtComponents::StyledDialog - , private AZ::SystemTickBus::Handler - , private UpgradeNotifications::Bus::Handler - , private AZ::Debug::TraceMessageBus::Handler + namespace VersionExplorer { - Q_OBJECT - - public: - AZ_CLASS_ALLOCATOR(VersionExplorerLog, AZ::SystemAllocator, 0); - - explicit VersionExplorerLog(QWidget* parent = nullptr); - ~VersionExplorerLog(); - - private: - - static constexpr int ColumnAsset = 0; - static constexpr int ColumnAction = 1; - static constexpr int ColumnBrowse = 2; - static constexpr int ColumnStatus = 3; - - void OnScan(); - void OnClose(); - - enum class ProcessState + class Log + : private AZ::Debug::TraceMessageBus::Handler { - Inactive, - Backup, - Scan, - Upgrade, + public: + AZ_CLASS_ALLOCATOR(Log, AZ::SystemAllocator, 0); + + void Activate(); + void AddEntry(const char* format, ...); + void Deactivate(); + const AZStd::vector& GetEntries() const; + void SetVersionExporerExclusivity(bool enabled); + void SetVerbose(bool verbosity); + + private: + bool m_isExclusiveReportingEnabled = false; + bool m_isVerbose = false; + AZStd::vector m_logs; + + bool CaptureFromTraceBus(const char* window, const char* message); + bool OnException(const char* /*message*/) override; + bool OnPrintf(const char* /*window*/, const char* /*message*/) override; + bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; + bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; }; - ProcessState m_state = ProcessState::Inactive; - - void DoScan(); - void ScanComplete(const AZ::Data::Asset&); - - void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); - - void OnUpgradeAll(); - - // SystemTickBus::Handler - void OnSystemTick() override; - // - - // AZ::Debug::TranceMessageBus::Handler - bool OnException(const char* /*message*/) override; - bool OnPrintf(const char* /*window*/, const char* /*message*/) override; - bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - // - - bool CaptureLogFromTraceBus(const char* window, const char* message); - - enum class OperationResult - { - Success, - Failure, - }; - - void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); - - bool IsUpgrading() const; - - bool m_inProgress = false; - // scan fields - size_t m_currentAssetRowIndex = 0; - size_t m_inspectedAssets = 0; - size_t m_failedAssets = 0; - size_t m_discoveredAssets = 0; - - IUpgradeRequests::AssetList m_assetsToInspect; - IUpgradeRequests::AssetList::iterator m_inspectingAsset; - using UpgradeAssets = AZStd::vector>; - UpgradeAssets m_assetsToUpgrade; - UpgradeAssets::iterator m_inProgressAsset; - - AZ::Data::Asset m_currentAsset; - - AZStd::unique_ptr m_ui; - - AZStd::unique_ptr m_settingsCache; - - // upgrade fields - AZStd::recursive_mutex m_mutex; - bool m_upgradeComplete = false; - AZ::Data::Asset m_upgradeAsset; - int m_upgradeAssetIndex = 0; - OperationResult m_upgradeResult; - AZStd::string m_upgradeMessage; - AZStd::string m_tmpFileName; - - AZStd::unique_ptr m_keepEditorAlive; - - AZStd::deque m_logs; - - AZ::Entity* m_scriptCanvasEntity = nullptr; - - bool m_isUpgradingSingleGraph = false; - - void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); - - void FlushLogs(); - - void FinalizeUpgrade(); - void FinalizeScan(); - - void BackupComplete(); - AZStd::string BackupGraph(const AZ::Data::Asset&); - void UpgradeGraph(const AZ::Data::Asset&); - - void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; - - void OnSourceFileReleased(AZ::Data::Asset asset); - - void closeEvent(QCloseEvent* event) override; - - bool m_overwriteAll = false; - void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); - - void Log(const char* format, ...); - }; + } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h deleted file mode 100644 index 2b23c711dd..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerTraits.h +++ /dev/null @@ -1,22 +0,0 @@ -#include - -namespace ScriptCanvasEditor -{ - namespace VersionExplorer - { - class RequestsTraits : public AZ::EBusTraits - { - public: - static const AZ::EBusAddressPolicy HandlerPolicy = AZ::EBusAddressPolicy::Single; - }; - using RequestsBus = AZ::EBus; - - class NotificationsTraits : public AZ::EBusTraits - { - public: - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - using BusIdType = NotificationsTraits*; - }; - using NotificationsBus = AZ::EBus; - } -} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp index eb182ed291..bf407765e1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp @@ -28,996 +28,909 @@ #include #include #include -#include -#include +#include +#include #include #include #include -namespace VersionExplorerCpp +namespace ScriptCanvasEditor { - class FileEventHandler - : public AZ::IO::FileIOEventBus::Handler + namespace VersionExplorer { - public: - int m_errorCode = 0; - AZStd::string m_fileName; - - FileEventHandler() + EditorKeepAlive::EditorKeepAlive() { - BusConnect(); - } + ISystem* system = nullptr; + CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); - ~FileEventHandler() - { - BusDisconnect(); + m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); + + if (m_edKeepEditorActive) + { + m_keepEditorActive = m_edKeepEditorActive->GetIVal(); + m_edKeepEditorActive->Set(1); + } } - void OnError(const AZ::IO::SystemFile* /*file*/, const char* fileName, int errorCode) override + EditorKeepAlive::~EditorKeepAlive() { - m_errorCode = errorCode; - - if (fileName) + if (m_edKeepEditorActive) { - m_fileName = fileName; + m_edKeepEditorActive->Set(m_keepEditorActive); } } - }; -} -namespace ScriptCanvasEditor -{ - EditorKeepAlive::EditorKeepAlive() - { - ISystem* system = nullptr; - CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); + View::View(QWidget* parent) + : AzQtComponents::StyledDialog(parent) + , m_ui(new Ui::View()) + { + m_ui->setupUi(this); + m_ui->tableWidget->horizontalHeader()->setVisible(false); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); + m_ui->tableWidget->setColumnWidth(3, 22); + m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + connect(m_ui->scanButton, &QPushButton::pressed, this, &View::OnScanButtonPress); + connect(m_ui->closeButton, &QPushButton::pressed, this, &View::OnCloseButtonPress); + connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &View::OnUpgradeAllButtonPress); + m_ui->progressBar->setValue(0); + m_ui->progressBar->setVisible(false); - m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); + ViewRequestsBus::Handler::BusConnect(); + ModelNotificationsBus::Handler::BusConnect(); - if (m_edKeepEditorActive) - { - m_keepEditorActive = m_edKeepEditorActive->GetIVal(); - m_edKeepEditorActive->Set(1); + // move to model, maybe + m_keepEditorAlive = AZStd::make_unique(); } - } - EditorKeepAlive::~EditorKeepAlive() - { - if (m_edKeepEditorActive) - { - m_edKeepEditorActive->Set(m_keepEditorActive); + void View::Log(const char* /*format*/, ...) + { +// if (m_ui->verbose->isChecked()) +// { +// char sBuffer[2048]; +// va_list ArgList; +// va_start(ArgList, format); +// azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); +// sBuffer[sizeof(sBuffer) - 1] = '\0'; +// va_end(ArgList); +// +// AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); +// } + } + + void View::OnCloseButtonPress() + { + reject(); + } + + void View::OnSystemTick() + { +// switch (m_state) +// { +// case ProcessState::Scan: +// +// if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) +// { +// m_inProgress = true; +// AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; +// m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); +// Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); +// m_currentAsset.BlockUntilLoadComplete(); +// if (m_currentAsset.IsReady()) +// { +// // The asset is ready, grab its info +// m_inProgress = true; +// InspectAsset(m_currentAsset, assetToUpgrade); +// } +// else +// { +// m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); +// QTableWidgetItem* rowName = new QTableWidgetItem +// (tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); +// m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); +// ++m_currentAssetRowIndex; +// +// Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); +// ++m_failedAssets; +// ScanComplete(m_currentAsset); +// } +// } +// break; +// +// case ProcessState::Upgrade: +// { +// AZStd::lock_guard lock(m_mutex); +// if (m_upgradeComplete) +// { +// ++m_upgradeAssetIndex; +// m_inProgress = false; +// m_ui->progressBar->setVisible(true); +// m_ui->progressBar->setValue(m_upgradeAssetIndex); +// +// if (m_scriptCanvasEntity) +// { +// m_scriptCanvasEntity->Deactivate(); +// m_scriptCanvasEntity = nullptr; +// } +// +// GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); +// +// if (!m_isUpgradingSingleGraph) +// { +// if (m_inProgressAsset != m_assetsToUpgrade.end()) +// { +// m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); +// } +// +// if (m_inProgressAsset == m_assetsToUpgrade.end()) +// { +// FinalizeUpgrade(); +// } +// } +// else +// { +// m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); +// m_inProgress = false; +// m_state = ProcessState::Inactive; +// // m_settingsCache.reset(); +// AZ::SystemTickBus::Handler::BusDisconnect(); +// +// } +// +// m_isUpgradingSingleGraph = false; +// +// if (m_assetsToUpgrade.empty()) +// { +// m_ui->upgradeAllButton->setEnabled(false); +// } +// +// m_upgradeComplete = false; +// } +// +// if (!IsUpgrading() && m_state == ProcessState::Upgrade) +// { +// AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); +// // Make the backup +// if (errorMessage.empty()) +// { +// Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); +// QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); +// if (!items.isEmpty()) +// { +// for (auto* item : items) +// { +// int row = item->row(); +// AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); +// spinner->SetIsBusy(true); +// } +// } +// +// // Upgrade the graph +// UpgradeGraph(*m_inProgressAsset); +// } +// else +// { +// Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); +// GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); +// } +// +// } +// break; +// } +// default: +// break; +// } +// +// FlushLogs(); +// +// AZ::Data::AssetManager::Instance().DispatchEvents(); +// AZ::SystemTickBus::ExecuteQueuedEvents(); + } + + // Backup + + void View::OnUpgradeAllButtonPress() + { + m_state = ProcessState::Upgrade; + //m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + AZ::Interface::Get()->SetIsUpgrading(true); + AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); + m_inProgressAsset = m_assetsToUpgrade.begin(); + AZ::SystemTickBus::Handler::BusConnect(); + m_ui->progressBar->setVisible(true); + m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); + m_ui->progressBar->setValue(m_upgradeAssetIndex); + m_keepEditorAlive = AZStd::make_unique(); } - } - VersionExplorer::VersionExplorer(QWidget* parent /*= nullptr*/) - : AzQtComponents::StyledDialog(parent) - , m_ui(new Ui::VersionExplorer()) - { - m_ui->setupUi(this); + AZStd::string View::BackupGraph(const AZ::Data::Asset& asset) + { + if (!m_ui->makeBackupCheckbox->isChecked()) + { + // considered a success + return ""; + } - m_ui->tableWidget->horizontalHeader()->setVisible(false); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); - m_ui->tableWidget->setColumnWidth(3, 22); + QDateTime theTime = QDateTime::currentDateTime(); + QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); - m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); + char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); + backupPath = backupPathCStr; - connect(m_ui->scanButton, &QPushButton::pressed, this, &VersionExplorer::OnScan); - connect(m_ui->closeButton, &QPushButton::pressed, this, &VersionExplorer::OnClose); - connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &VersionExplorer::OnUpgradeAll); + if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + { + if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + { + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); + return "Failed to create backup folder"; + } + } - m_ui->progressBar->setValue(0); - m_ui->progressBar->setVisible(false); + AZStd::string devRoot = "@devroot@"; + AZStd::string devAssets = "@devassets@"; - m_keepEditorAlive = AZStd::make_unique(); - m_inspectingAsset = m_assetsToInspect.end(); + char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - } + char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - VersionExplorer::~VersionExplorer() - { - AZ::SystemTickBus::Handler::BusDisconnect(); + AZStd::string relativePath = devAssetsCStr; + AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + AZStd::string sourceFilePath; - } + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound{}; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); + if (sourceInfoFound) + { + AZStd::string assetPath; + AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - void VersionExplorer::Log(const char* format, ...) - { - if (m_ui->verbose->isChecked()) - { - char sBuffer[2048]; - va_list ArgList; - va_start(ArgList, format); - azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); - sBuffer[sizeof(sBuffer) - 1] = '\0'; - va_end(ArgList); - - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); - } - } + sourceFilePath = assetPath; + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "View::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); + return "Failed to find source file"; + } - void VersionExplorer::OnClose() - { - reject(); - } + devRoot = devRootCStr; + AzFramework::StringFunc::Path::Normalize(devRoot); - bool VersionExplorer::IsUpgrading() const - { - return m_inProgressAsset != m_assetsToUpgrade.end() && m_inProgress; - } + relativePath = sourceFilePath; + AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); + if (relativePath.starts_with("/")) + { + relativePath = relativePath.substr(1, relativePath.size() - 1); + } - void VersionExplorer::OnSystemTick() - { - switch (m_state) - { - case ProcessState::Scan: + AzFramework::StringFunc::Path::Normalize(relativePath); + AzFramework::StringFunc::Path::Normalize(backupPath); + + AZStd::string targetFilePath = backupPath; + targetFilePath += relativePath; - if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) + if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) { - m_inProgress = true; - AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; - m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); - m_currentAsset.BlockUntilLoadComplete(); - if (m_currentAsset.IsReady()) - { - // The asset is ready, grab its info - m_inProgress = true; - InspectAsset(m_currentAsset, assetToUpgrade); - } - else - { - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem - ( tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - ++m_currentAssetRowIndex; - - Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); - ++m_failedAssets; - ScanComplete(m_currentAsset); - } + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "View::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return "Failed to copy source file to backup location"; } - break; - case ProcessState::Upgrade: + Log("View::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + return ""; + } + + void View::UpgradeGraph(const AZ::Data::Asset& asset) { - AZStd::lock_guard lock(m_mutex); - if (m_upgradeComplete) + m_inProgress = true; + m_upgradeComplete = false; + Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); + m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); + m_scriptCanvasEntity = nullptr; + + UpgradeNotifications::Bus::Handler::BusConnect(); + + if (asset.GetType() == azrtti_typeid()) { - ++m_upgradeAssetIndex; - m_inProgress = false; - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setValue(m_upgradeAssetIndex); + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" + , azrtti_typeid().template ToString().c_str()); - if (m_scriptCanvasEntity) + if (!scriptCanvasAsset) { - m_scriptCanvasEntity->Deactivate(); - m_scriptCanvasEntity = nullptr; + return; } - GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); + AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity"); + if (!scriptCanvasEntity) + { + return; + } - if (!m_isUpgradingSingleGraph) + AZ::Entity* queryEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); + if (queryEntity) { - if (m_inProgressAsset != m_assetsToUpgrade.end()) + if (queryEntity->GetState() == AZ::Entity::State::Active) { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); + queryEntity->Deactivate(); } - if (m_inProgressAsset == m_assetsToUpgrade.end()) - { - FinalizeUpgrade(); - } + scriptCanvasEntity = queryEntity; } - else + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) { - m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); - m_inProgress = false; - m_state = ProcessState::Inactive; - m_settingsCache.reset(); - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); + scriptCanvasEntity->Init(); } - m_isUpgradingSingleGraph = false; - - if (m_assetsToUpgrade.empty()) + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) { - m_ui->upgradeAllButton->setEnabled(false); + scriptCanvasEntity->Activate(); } - m_upgradeComplete = false; - } + AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - if (!IsUpgrading() && m_state == ProcessState::Upgrade) - { - AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); - // Make the backup - if (errorMessage.empty()) + if (graphComponent) { - Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); - QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); - spinner->SetIsBusy(true); - } - } + m_scriptCanvasEntity = scriptCanvasEntity; - // Upgrade the graph - UpgradeGraph(*m_inProgressAsset); - } - else - { - Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); - GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); + graphComponent->UpgradeGraph + (asset + , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_ui->verbose->isChecked()); } - } - break; - } - default: - break; - } - - FlushLogs(); - - AZ::Data::AssetManager::Instance().DispatchEvents(); - AZ::SystemTickBus::ExecuteQueuedEvents(); - } - - // Backup - void VersionExplorer::OnUpgradeAll() - { - m_state = ProcessState::Upgrade; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - AZ::Interface::Get()->SetIsUpgrading(true); - AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); - m_inProgressAsset = m_assetsToUpgrade.begin(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - AZ::SystemTickBus::Handler::BusConnect(); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - m_ui->progressBar->setValue(m_upgradeAssetIndex); - m_keepEditorAlive = AZStd::make_unique(); - } - - AZStd::string VersionExplorer::BackupGraph(const AZ::Data::Asset& asset) - { - if (!m_ui->makeBackupCheckbox->isChecked()) - { - // considered a success - return ""; + AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); } - QDateTime theTime = QDateTime::currentDateTime(); - QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; - - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + void View::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + if (!fullPathFound) { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); - return "Failed to create backup folder"; + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); } - } - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); - if (sourceInfoFound) - { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); - return "Failed to find source file"; - } - - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return "Failed to copy source file to backup location"; + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + this->OnSourceFileReleased(asset); + }); + streamer->QueueRequest(flushRequest); } - Log("VersionExplorer::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return ""; - } - - void VersionExplorer::UpgradeGraph(const AZ::Data::Asset& asset) - { - m_inProgress = true; - m_upgradeComplete = false; - Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); - m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); - m_scriptCanvasEntity = nullptr; - - UpgradeNotifications::Bus::Handler::BusConnect(); - - if (asset.GetType() == azrtti_typeid()) + void View::OnSourceFileReleased(AZ::Data::Asset asset) { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - - if (!scriptCanvasAsset) + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + m_tmpFileName.clear(); + AZStd::string tmpFileName; + // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) { + GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); return; } - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "VersionExplorer::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) + bool tempSavedSucceeded = false; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); + if (fileStream.IsOpen()) { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) + if (asset.GetType() == azrtti_typeid()) { - queryEntity->Deactivate(); + ScriptCanvasEditor::ScriptCanvasAssetHandler handler; + tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); } - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); + fileStream.Close(); } - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) + // attempt to remove temporary file no matter what + m_tmpFileName = tmpFileName; + if (!tempSavedSucceeded) { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - if (graphComponent) - { - m_scriptCanvasEntity = scriptCanvasEntity; - - graphComponent->UpgradeGraph - ( asset - , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_ui->verbose->isChecked()); + GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); + return; } - } - - AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); - } - void VersionExplorer::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - if (!fullPathFound) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); - } - - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - this->OnSourceFileReleased(asset); - }); - streamer->QueueRequest(flushRequest); - } - - void VersionExplorer::OnSourceFileReleased(AZ::Data::Asset asset) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - m_tmpFileName.clear(); - AZStd::string tmpFileName; - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); - return; - } - - bool tempSavedSucceeded = false; - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - if (asset.GetType() == azrtti_typeid()) + using SCCommandBus = AzToolsFramework::SourceControlCommandBus; + SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, + [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); - } + constexpr const size_t k_maxAttemps = 10; - fileStream.Close(); - } - - // attempt to remove temporary file no matter what - m_tmpFileName = tmpFileName; - if (!tempSavedSucceeded) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); - return; - } - - using SCCommandBus = AzToolsFramework::SourceControlCommandBus; - SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, - [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - constexpr const size_t k_maxAttemps = 10; - - if (!info.IsReadOnly()) - { - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - if (m_overwriteAll) + if (!info.IsReadOnly()) { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); } else { - int result = QMessageBox::No; - if (!m_overwriteAll) + if (m_overwriteAll) { - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Failed to Save Upgraded File"), - QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); - - result = mb.exec(); - if (result == QMessageBox::YesToAll) + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } + else + { + int result = QMessageBox::No; + if (!m_overwriteAll) { - m_overwriteAll = true; + QMessageBox mb(QMessageBox::Warning, + QObject::tr("Failed to Save Upgraded File"), + QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), + QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); + + result = mb.exec(); + if (result == QMessageBox::YesToAll) + { + m_overwriteAll = true; + } } - } - if (result == QMessageBox::Yes || m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + if (result == QMessageBox::Yes || m_overwriteAll) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); + } } } - } - }); - } - - void VersionExplorer::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target - , size_t remainingAttempts) - { - VersionExplorerCpp::FileEventHandler fileEventHandler; - - if (remainingAttempts == 0) - { - // all attempts failed, give up - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); - GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); - } - else if (remainingAttempts == 2) - { - // before the final attempt, flush all caches - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); - streamer->SetRequestCompleteCallback(flushRequest - , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction( - [this, asset, remainingAttempts, source, target](){ PerformMove(asset, source, target, remainingAttempts - 1); }); }); - streamer->QueueRequest(flushRequest); } - else + + void View::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target + , size_t remainingAttempts) { - // the actual move attempt - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) + // ViewCpp::FileEventHandler fileEventHandler; + + if (remainingAttempts == 0) { - m_tmpFileName.clear(); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - AZ::SystemTickBus::QueueFunction([this, asset]() - { - GraphUpgradeComplete(asset, OperationResult::Success, ""); - }); + // all attempts failed, give up + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); + GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); } - else + else if (remainingAttempts == 2) { + // before the final attempt, flush all caches AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); + streamer->SetRequestCompleteCallback(flushRequest + , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) { // Continue saving. - AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); + AZ::SystemTickBus::QueueFunction( + [this, asset, remainingAttempts, source, target]() { PerformMove(asset, source, target, remainingAttempts - 1); }); }); streamer->QueueRequest(flushRequest); } - } - } - - void VersionExplorer::GraphUpgradeComplete - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - AZStd::lock_guard lock(m_mutex); - m_upgradeComplete = true; - m_upgradeResult = result; - m_upgradeMessage = message; - m_upgradeAsset = asset; - - if (!m_tmpFileName.empty()) - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); - - if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) + else { - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); + // the actual move attempt + auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); + if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) + { + m_tmpFileName.clear(); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + // Bump the slice asset up in the asset processor's queue. + AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, asset]() + { + GraphUpgradeComplete(asset, OperationResult::Success, ""); + }); + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } } } - if (m_upgradeResult == OperationResult::Failure) + void View::GraphUpgradeComplete + (const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) { - AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); - } + AZStd::lock_guard lock(m_mutex); + m_upgradeComplete = true; + m_upgradeResult = result; + m_upgradeMessage = message; + m_upgradeAsset = asset; - m_tmpFileName.clear(); - } + if (!m_tmpFileName.empty()) + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); - void VersionExplorer::GraphUpgradeCompleteUIUpdate - ( const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - QString text = asset.GetHint().c_str(); - QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); + if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) + { + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); + } + } - if (!items.isEmpty()) - { - for (auto* item : items) + if (m_upgradeResult == OperationResult::Failure) { - int row = item->row(); - QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); - QString assetName = asset.GetHint().c_str(); + AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); + } + + m_tmpFileName.clear(); + } + + void View::GraphUpgradeCompleteUIUpdate + (const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) + { + QString text = asset.GetHint().c_str(); + QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); - if (label->text().compare(assetName) == 0) + if (!items.isEmpty()) + { + for (auto* item : items) { - m_ui->tableWidget->removeCellWidget(row, ColumnAction); - m_ui->tableWidget->removeCellWidget(row, ColumnStatus); + int row = item->row(); + QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); + QString assetName = asset.GetHint().c_str(); - QToolButton* doneButton = new QToolButton(this); - doneButton->setToolTip("Upgrade complete"); - if (result == OperationResult::Success) - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); - } - else + if (label->text().compare(assetName) == 0) { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); - doneButton->setToolTip(message.data()); - } + m_ui->tableWidget->removeCellWidget(row, ColumnAction); + m_ui->tableWidget->removeCellWidget(row, ColumnStatus); - m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); + QToolButton* doneButton = new QToolButton(this); + doneButton->setToolTip("Upgrade complete"); + if (result == OperationResult::Success) + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); + } + else + { + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); + doneButton->setToolTip(message.data()); + } + + m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); + } } } } - } - void VersionExplorer::FinalizeUpgrade() - { - Log("FinalizeUpgrade!"); - m_inProgress = false; - m_assetsToUpgrade.clear(); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(true); - m_keepEditorAlive.reset(); - m_ui->progressBar->setVisible(false); - - // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - if (assetsThatNeedManualInspection > 0) - { - m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); - } - else + void View::FinalizeUpgrade() { - m_ui->spinner->SetText("Upgrade complete."); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); - AZ::Interface::Get()->SetIsUpgrading(false); - m_settingsCache.reset(); - } - - // Scanning - - void VersionExplorer::OnScan() - { - m_assetsToUpgrade.clear(); - m_assetsToInspect.clear(); - m_ui->tableWidget->setRowCount(0); - m_inspectedAssets = 0; - m_currentAssetRowIndex = 0; - IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); - m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); - DoScan(); - } - - void VersionExplorer::DoScan() - { - m_state = ProcessState::Scan; - m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + Log("FinalizeUpgrade!"); + m_inProgress = false; + m_assetsToUpgrade.clear(); + m_ui->upgradeAllButton->setEnabled(false); + m_ui->onlyShowOutdated->setEnabled(true); + m_keepEditorAlive.reset(); + m_ui->progressBar->setVisible(false); - AZ::SystemTickBus::Handler::BusConnect(); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); + // Manual correction + size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); + if (assetsThatNeedManualInspection > 0) + { + m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); + } + else + { + m_ui->spinner->SetText("Upgrade complete."); + } - if (!m_assetsToInspect.empty()) + AZ::SystemTickBus::Handler::BusDisconnect(); + AZ::Interface::Get()->SetIsUpgrading(false); + //m_settingsCache.reset(); + } + + // Scanning + + void View::OnScanButtonPress() + { + ViewNotificationsBus::Broadcast(&ViewNotificationsTraits::ScanRequested); + +// m_assetsToUpgrade.clear(); +// m_assetsToInspect.clear(); +// m_ui->tableWidget->setRowCount(0); +// m_inspectedAssets = 0; +// m_currentAssetRowIndex = 0; +// IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); +// m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); +// DoScan(); + } + + void View::DoScan() + { +// m_state = ProcessState::Scan; +// m_settingsCache = AZStd::make_unique(); +// ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; +// ScriptCanvas::Grammar::g_printAbstractCodeModel = false; +// ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; +// +// AZ::SystemTickBus::Handler::BusConnect(); +// +// if (!m_assetsToInspect.empty()) +// { +// m_discoveredAssets = m_assetsToInspect.size(); +// m_failedAssets = 0; +// m_inspectedAssets = 0; +// m_currentAssetRowIndex = 0; +// m_ui->progressFrame->setVisible(true); +// m_ui->progressBar->setVisible(true); +// m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); +// m_ui->progressBar->setValue(0); +// +// m_ui->spinner->SetIsBusy(true); +// m_ui->spinner->SetBusyIconSize(32); +// +// m_ui->scanButton->setEnabled(false); +// m_ui->upgradeAllButton->setEnabled(false); +// m_ui->onlyShowOutdated->setEnabled(false); +// +// m_inspectingAsset = m_assetsToInspect.begin(); +// m_keepEditorAlive = AZStd::make_unique(); +// } + } + + void View::BackupComplete() { - m_discoveredAssets = m_assetsToInspect.size(); - m_failedAssets = 0; - m_inspectedAssets = 0; m_currentAssetRowIndex = 0; - m_ui->progressFrame->setVisible(true); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); m_ui->progressBar->setValue(0); - - m_ui->spinner->SetIsBusy(true); - m_ui->spinner->SetBusyIconSize(32); - - m_ui->scanButton->setEnabled(false); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(false); - - m_inspectingAsset = m_assetsToInspect.begin(); - m_keepEditorAlive = AZStd::make_unique(); + DoScan(); } - } - - void VersionExplorer::BackupComplete() - { - m_currentAssetRowIndex = 0; - m_ui->progressBar->setValue(0); - DoScan(); - } - void VersionExplorer::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) - { - Log("InspectAsset: %s", asset.GetHint().c_str()); - AZ::Entity* scriptCanvasEntity = nullptr; - if (asset.GetType() == azrtti_typeid()) + void View::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) + Log("InspectAsset: %s", asset.GetHint().c_str()); + AZ::Entity* scriptCanvasEntity = nullptr; + if (asset.GetType() == azrtti_typeid()) { - Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); - return; - } + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + if (!scriptCanvasAsset) + { + Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); + return; + } - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); - } + scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); + } - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); - bool forceUpgrade = m_ui->forceUpgrade->isChecked(); - ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); + bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); + bool forceUpgrade = m_ui->forceUpgrade->isChecked(); + ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); - if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) - { - ScanComplete(asset); - Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); - return; - } + if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) + { + ScanComplete(asset); + Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); + return; + } - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); + m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); - if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) - { - m_assetsToUpgrade.push_back(asset); + if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) + { + m_assetsToUpgrade.push_back(asset); - AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); - spinner->SetBusyIconSize(16); + AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); + spinner->SetBusyIconSize(16); - QPushButton* rowGoToButton = new QPushButton(this); - rowGoToButton->setText("Upgrade"); - rowGoToButton->setEnabled(false); + QPushButton* rowGoToButton = new QPushButton(this); + rowGoToButton->setText("Upgrade"); + rowGoToButton->setEnabled(false); - connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { + connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { - AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { - // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda - UpgradeSingle(rowGoToButton, spinner, assetInfo); + AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { + // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda + UpgradeSingle(rowGoToButton, spinner, assetInfo); }); - AZ::SystemTickBus::ExecuteQueuedEvents(); + AZ::SystemTickBus::ExecuteQueuedEvents(); }); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); - } + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); + } - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); + char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; + AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); + AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); + AZ::StringFunc::Path::Normalize(path); - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - QByteArray assetNameUtf8 = asset.GetHint().c_str(); - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + QByteArray assetNameUtf8 = asset.GetHint().c_str(); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); + AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); - QToolButton* browseButton = new QToolButton(this); - browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); - browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); + QToolButton* browseButton = new QToolButton(this); + browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); + browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); - QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); - connect(browseButton, &QPushButton::clicked, [absolutePath] { - AzQtComponents::ShowFileOnDesktop(absolutePath); + QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); + connect(browseButton, &QPushButton::clicked, [absolutePath] { + AzQtComponents::ShowFileOnDesktop(absolutePath); }); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); - ScanComplete(asset); - ++m_inspectedAssets; - ++m_currentAssetRowIndex; - } - - void VersionExplorer::UpgradeSingle - ( QPushButton* rowGoToButton - , AzQtComponents::StyledBusyLabel* spinner - , AZ::Data::AssetInfo assetInfo) - { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - ( assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); + m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); + ScanComplete(asset); + ++m_inspectedAssets; + ++m_currentAssetRowIndex; + } - if (asset) + void View::UpgradeSingle + (QPushButton* rowGoToButton + , AzQtComponents::StyledBusyLabel* spinner + , AZ::Data::AssetInfo assetInfo) { - asset.BlockUntilLoadComplete(); + AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset + (assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - if (asset.IsReady()) + if (asset) { - AZ::Interface::Get()->SetIsUpgrading(true); - m_isUpgradingSingleGraph = true; - m_logs.clear(); - m_ui->textEdit->clear(); - spinner->SetIsBusy(true); - rowGoToButton->setEnabled(false); + asset.BlockUntilLoadComplete(); - m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() - , [asset](const UpgradeAssets::value_type& assetToUpgrade) + if (asset.IsReady()) { - return assetToUpgrade.GetId() == asset.GetId(); - }); + AZ::Interface::Get()->SetIsUpgrading(true); + m_isUpgradingSingleGraph = true; + m_logs.clear(); + m_ui->textEdit->clear(); + spinner->SetIsBusy(true); + rowGoToButton->setEnabled(false); + + m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() + , [asset](const UpgradeAssets::value_type& assetToUpgrade) + { + return assetToUpgrade.GetId() == asset.GetId(); + }); - m_state = ProcessState::Upgrade; - AZ::SystemTickBus::Handler::BusConnect(); - } + m_state = ProcessState::Upgrade; + AZ::SystemTickBus::Handler::BusConnect(); + } + } } - } - void VersionExplorer::ScanComplete(const AZ::Data::Asset& asset) - { - Log("ScanComplete: %s", asset.GetHint().c_str()); - m_inProgress = false; - m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - m_ui->scanButton->setEnabled(true); - - m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); - FlushLogs(); - - if (m_inspectingAsset == m_assetsToInspect.end()) + void View::ScanComplete(const AZ::Data::Asset& asset) { - AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); + Log("ScanComplete: %s", asset.GetHint().c_str()); + m_inProgress = false; + m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); + m_ui->scanButton->setEnabled(true); - if (!m_assetsToUpgrade.empty()) + m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); + FlushLogs(); + + if (m_inspectingAsset == m_assetsToInspect.end()) { - m_ui->upgradeAllButton->setEnabled(true); + AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); + + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } } } - } - void VersionExplorer::FinalizeScan() - { - Log("FinalizeScan()"); + void View::FinalizeScan() + { + Log("FinalizeScan()"); - m_ui->spinner->SetIsBusy(false); - m_ui->onlyShowOutdated->setEnabled(true); + m_ui->spinner->SetIsBusy(false); + m_ui->onlyShowOutdated->setEnabled(true); - // Enable all the Upgrade buttons - for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) - { - QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); - if (button) + // Enable all the Upgrade buttons + for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) { - button->setEnabled(true); + QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); + if (button) + { + button->setEnabled(true); + } } - } - QString spinnerText = QStringLiteral("Scan Complete"); - if (m_assetsToUpgrade.empty()) - { - spinnerText.append(" - No graphs require upgrade!"); - } - else - { - spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" - , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); - } + QString spinnerText = QStringLiteral("Scan Complete"); + if (m_assetsToUpgrade.empty()) + { + spinnerText.append(" - No graphs require upgrade!"); + } + else + { + spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" + , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); + } - m_ui->spinner->SetText(spinnerText); - m_ui->progressBar->setVisible(false); + m_ui->spinner->SetText(spinnerText); + m_ui->progressBar->setVisible(false); - if (!m_assetsToUpgrade.empty()) - { - m_ui->upgradeAllButton->setEnabled(true); - } + if (!m_assetsToUpgrade.empty()) + { + m_ui->upgradeAllButton->setEnabled(true); + } - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); + AZ::SystemTickBus::Handler::BusDisconnect(); - m_keepEditorAlive.reset(); - m_settingsCache.reset(); - m_state = ProcessState::Inactive; - } - - void VersionExplorer::FlushLogs() - { - if (m_logs.empty()) - { - return; + m_keepEditorAlive.reset(); + //m_settingsCache.reset(); + m_state = ProcessState::Inactive; } - const QTextCursor oldCursor = m_ui->textEdit->textCursor(); - QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); - - m_ui->textEdit->moveCursor(QTextCursor::End); - QTextCursor textCursor = m_ui->textEdit->textCursor(); - - while (!m_logs.empty()) + void View::FlushLogs() { - auto line = "\n" + m_logs.front(); - - m_logs.pop_front(); - - textCursor.insertText(line.c_str()); - } - - scrollBar->setValue(scrollBar->maximum()); - m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); + if (m_logs.empty()) + { + return; + } - } + const QTextCursor oldCursor = m_ui->textEdit->textCursor(); + QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); - bool VersionExplorer::CaptureLogFromTraceBus(const char* window, const char* message) - { - if (m_ui->updateReportingOnly->isChecked() && window != ScriptCanvas::k_VersionExplorerWindow) - { - return true; - } + m_ui->textEdit->moveCursor(QTextCursor::End); + QTextCursor textCursor = m_ui->textEdit->textCursor(); - AZStd::string msg = message; - if (msg.ends_with("\n")) - { - msg = msg.substr(0, msg.size() - 1); - } + while (!m_logs.empty()) + { + auto line = "\n" + m_logs.front(); - m_logs.push_back(msg); - return m_ui->updateReportingOnly->isChecked(); - } + m_logs.pop_front(); - bool VersionExplorer::OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Error): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } + textCursor.insertText(line.c_str()); + } - bool VersionExplorer::OnPreWarning(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) - { - AZStd::string msg = AZStd::string::format("(Warning): %s", message); - return CaptureLogFromTraceBus(window, msg.c_str()); - } + scrollBar->setValue(scrollBar->maximum()); + m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); - bool VersionExplorer::OnException(const char* message) - { - AZStd::string msg = AZStd::string::format("(Exception): %s", message); - return CaptureLogFromTraceBus("Script Canvas", msg.c_str()); - } + } - bool VersionExplorer::OnPrintf(const char* window, const char* message) - { - return CaptureLogFromTraceBus(window, message); - } - void VersionExplorer::closeEvent(QCloseEvent* event) - { - m_keepEditorAlive.reset(); + void View::closeEvent(QCloseEvent* event) + { + m_keepEditorAlive.reset(); - AzQtComponents::StyledDialog::closeEvent(event); + AzQtComponents::StyledDialog::closeEvent(event); + } } -#include +#include } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h index 7ce1920dbb..905074d17e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h @@ -15,7 +15,6 @@ AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") AZ_POP_DISABLE_WARNING #include #include -#include #include #include #include @@ -23,11 +22,14 @@ AZ_POP_DISABLE_WARNING #include #endif +#include +#include + class QPushButton; namespace Ui { - class VersionExplorer; + class View; } namespace AzQtComponents @@ -37,140 +39,132 @@ namespace AzQtComponents namespace ScriptCanvasEditor { - //! Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow - //! the upgrade tool to work even if the editor is not in the foreground - class EditorKeepAlive - { - public: - EditorKeepAlive(); - ~EditorKeepAlive(); - - private: - int m_keepEditorActive; - ICVar* m_edKeepEditorActive; - }; - - //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog - class VersionExplorer - : public AzQtComponents::StyledDialog - , private AZ::SystemTickBus::Handler - , private UpgradeNotifications::Bus::Handler - , private AZ::Debug::TraceMessageBus::Handler + namespace VersionExplorer { - Q_OBJECT - - public: - AZ_CLASS_ALLOCATOR(VersionExplorer, AZ::SystemAllocator, 0); - - explicit VersionExplorer(QWidget* parent = nullptr); - ~VersionExplorer(); - - private: - - static constexpr int ColumnAsset = 0; - static constexpr int ColumnAction = 1; - static constexpr int ColumnBrowse = 2; - static constexpr int ColumnStatus = 3; + //! Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow + //! the upgrade tool to work even if the editor is not in the foreground + class EditorKeepAlive + { + public: + EditorKeepAlive(); + ~EditorKeepAlive(); - void OnScan(); - void OnClose(); + private: + int m_keepEditorActive; + ICVar* m_edKeepEditorActive; + }; - enum class ProcessState + //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog + //! Handles display change notifications, handles state change notifications, sends control requests + class View + : public AzQtComponents::StyledDialog + , private AZ::SystemTickBus::Handler + , private UpgradeNotifications::Bus::Handler + , private ViewRequestsBus::Handler + , private ModelNotificationsBus::Handler { - Inactive, - Backup, - Scan, - Upgrade, - }; - ProcessState m_state = ProcessState::Inactive; + Q_OBJECT - void DoScan(); - void ScanComplete(const AZ::Data::Asset&); + public: + AZ_CLASS_ALLOCATOR(View, AZ::SystemAllocator, 0); - void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); + explicit View(QWidget* parent = nullptr); + + private: - void OnUpgradeAll(); + static constexpr int ColumnAsset = 0; + static constexpr int ColumnAction = 1; + static constexpr int ColumnBrowse = 2; + static constexpr int ColumnStatus = 3; - // SystemTickBus::Handler - void OnSystemTick() override; - // + void OnCloseButtonPress(); + void OnScanButtonPress(); + void OnUpgradeAllButtonPress(); - // AZ::Debug::TranceMessageBus::Handler - bool OnException(const char* /*message*/) override; - bool OnPrintf(const char* /*window*/, const char* /*message*/) override; - bool OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override; - // + enum class ProcessState + { + Inactive, + Backup, + Scan, + Upgrade, + }; + ProcessState m_state = ProcessState::Inactive; - bool CaptureLogFromTraceBus(const char* window, const char* message); + void DoScan(); + void ScanComplete(const AZ::Data::Asset&); - enum class OperationResult - { - Success, - Failure, - }; + void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); + + // SystemTickBus::Handler + void OnSystemTick() override; - void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); + enum class OperationResult + { + Success, + Failure, + }; - bool IsUpgrading() const; + void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); - bool m_inProgress = false; - // scan fields - size_t m_currentAssetRowIndex = 0; - size_t m_inspectedAssets = 0; - size_t m_failedAssets = 0; - size_t m_discoveredAssets = 0; + bool IsUpgrading() const { return false; } - IUpgradeRequests::AssetList m_assetsToInspect; - IUpgradeRequests::AssetList::iterator m_inspectingAsset; - using UpgradeAssets = AZStd::vector>; - UpgradeAssets m_assetsToUpgrade; - UpgradeAssets::iterator m_inProgressAsset; + bool m_inProgress = false; + // scan fields + size_t m_currentAssetRowIndex = 0; + size_t m_inspectedAssets = 0; + size_t m_failedAssets = 0; + size_t m_discoveredAssets = 0; - AZ::Data::Asset m_currentAsset; + IUpgradeRequests::AssetList m_assetsToInspect; + IUpgradeRequests::AssetList::iterator m_inspectingAsset; + using UpgradeAssets = AZStd::vector>; + UpgradeAssets m_assetsToUpgrade; + UpgradeAssets::iterator m_inProgressAsset; - AZStd::unique_ptr m_ui; + AZ::Data::Asset m_currentAsset; - AZStd::unique_ptr m_settingsCache; + AZStd::unique_ptr m_ui; - // upgrade fields - AZStd::recursive_mutex m_mutex; - bool m_upgradeComplete = false; - AZ::Data::Asset m_upgradeAsset; - int m_upgradeAssetIndex = 0; - OperationResult m_upgradeResult; - AZStd::string m_upgradeMessage; - AZStd::string m_tmpFileName; + + // upgrade fields + AZStd::recursive_mutex m_mutex; + bool m_upgradeComplete = false; + AZ::Data::Asset m_upgradeAsset; + int m_upgradeAssetIndex = 0; + OperationResult m_upgradeResult; + AZStd::string m_upgradeMessage; + AZStd::string m_tmpFileName; - AZStd::unique_ptr m_keepEditorAlive; + AZStd::unique_ptr m_keepEditorAlive; - AZStd::deque m_logs; + AZStd::deque m_logs; - AZ::Entity* m_scriptCanvasEntity = nullptr; + AZ::Entity* m_scriptCanvasEntity = nullptr; - bool m_isUpgradingSingleGraph = false; + bool m_isUpgradingSingleGraph = false; - void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); + void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); - void FlushLogs(); + void FlushLogs(); - void FinalizeUpgrade(); - void FinalizeScan(); + void FinalizeUpgrade(); + void FinalizeScan(); - void BackupComplete(); - AZStd::string BackupGraph(const AZ::Data::Asset&); - void UpgradeGraph(const AZ::Data::Asset&); + void BackupComplete(); + AZStd::string BackupGraph(const AZ::Data::Asset&); + void UpgradeGraph(const AZ::Data::Asset&); - void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; + void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); + void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; - void OnSourceFileReleased(AZ::Data::Asset asset); + void OnSourceFileReleased(AZ::Data::Asset asset); - void closeEvent(QCloseEvent* event) override; + void closeEvent(QCloseEvent* event) override; - bool m_overwriteAll = false; - void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); + bool m_overwriteAll = false; + void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); - void Log(const char* format, ...); - }; + void Log(const char* format, ...); + }; + } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui index 0cd67bcf22..f549c821d6 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui @@ -1,7 +1,7 @@ - VersionExplorer - + View + Qt::WindowModal diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h new file mode 100644 index 0000000000..7f36e8503d --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +namespace ScriptCanvasEditor +{ + namespace VersionExplorer + { + class ViewRequestsTraits : public AZ::EBusTraits + { + public: + // flush logs, or add log text + // set progress update + virtual void ClearProgress() {} + virtual void SetInProgress() {} + }; + using ViewRequestsBus = AZ::EBus; + } +} diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index dbffe99afd..eb914ae139 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -259,20 +259,24 @@ set(FILES Editor/View/Windows/ScriptCanvasContextMenus.cpp Editor/View/Windows/ScriptCanvasContextMenus.h Editor/View/Windows/ScriptCanvasEditorResources.qrc - Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h + Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp + Editor/View/Windows/Tools/UpgradeTool/FileSaver.h + Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp + Editor/View/Windows/Tools/UpgradeTool/Modifier.h + Editor/View/Windows/Tools/UpgradeTool/Model.cpp + Editor/View/Windows/Tools/UpgradeTool/Model.h + Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h + Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp + Editor/View/Windows/Tools/UpgradeTool/Scanner.h Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui - Editor/View/Windows/Tools/UpgradeTool/Scanner.h - Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp - Editor/View/Windows/Tools/UpgradeTool/Modifier.h - Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp - Editor/View/Windows/Tools/UpgradeTool/FileSaver.h - Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp - Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.h - Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp - Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.ui - Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h + Editor/View/Windows/Tools/UpgradeTool/View.cpp + Editor/View/Windows/Tools/UpgradeTool/View.h + Editor/View/Windows/Tools/UpgradeTool/View.ui + Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp + Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h + Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h Editor/Framework/ScriptCanvasGraphUtilities.inl Editor/Framework/ScriptCanvasGraphUtilities.h Editor/Framework/ScriptCanvasTraceUtilities.h From fd717048945744f7c1afcea6815336bbeba6ccda Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 10 Sep 2021 20:27:01 -0700 Subject: [PATCH 007/293] rename view files --> controller Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/{View.cpp => Controller.cpp} | 0 .../View/Windows/Tools/UpgradeTool/{View.h => Controller.h} | 0 Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/{View.cpp => Controller.cpp} (100%) rename Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/{View.h => Controller.h} (100%) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp similarity index 100% rename from Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.cpp rename to Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h similarity index 100% rename from Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.h rename to Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index eb914ae139..1ce2b0c502 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -270,8 +270,8 @@ set(FILES Editor/View/Windows/Tools/UpgradeTool/Scanner.h Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui - Editor/View/Windows/Tools/UpgradeTool/View.cpp - Editor/View/Windows/Tools/UpgradeTool/View.h + Editor/View/Windows/Tools/UpgradeTool/Controller.cpp + Editor/View/Windows/Tools/UpgradeTool/Controller.h Editor/View/Windows/Tools/UpgradeTool/View.ui Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp From cbaa2fcff554ca27fb07b9229b6ea06537166f3e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 10 Sep 2021 21:03:14 -0700 Subject: [PATCH 008/293] rename view --> controller Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../View/Windows/Tools/UpgradeTool/{View.ui => Controller.ui} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/{View.ui => Controller.ui} (100%) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui similarity index 100% rename from Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui rename to Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui From dbc1f3bb62ec246115f6f7f22c9f766da58d9897 Mon Sep 17 00:00:00 2001 From: Yuriy Toporovskyy Date: Mon, 13 Sep 2021 11:57:39 -0400 Subject: [PATCH 009/293] Don't const_cast, instead remove const qualifier from function Signed-off-by: Yuriy Toporovskyy --- .../SkinnedMesh/SkinnedMeshOutputStreamManagerInterface.h | 2 +- .../Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp | 7 +------ .../Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h | 3 +-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshOutputStreamManagerInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshOutputStreamManagerInterface.h index 3c3ddc7ddc..fea6d090f7 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshOutputStreamManagerInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshOutputStreamManagerInterface.h @@ -51,7 +51,7 @@ namespace AZ } //! Returns the buffer asset that is used for all skinned mesh outputs - virtual Data::Asset GetBufferAsset() const = 0; + virtual Data::Asset GetBufferAsset() = 0; //! Returns the buffer that is used for all skinned mesh outputs virtual Data::Instance GetBuffer() = 0; diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp index ffbe850160..f3744fe119 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp @@ -87,11 +87,6 @@ namespace AZ { } - void SkinnedMeshOutputStreamManager::EnsureInit() const - { - const_cast(this)->EnsureInit(); - } - void SkinnedMeshOutputStreamManager::EnsureInit() { if (!m_needsInit) @@ -156,7 +151,7 @@ namespace AZ } } - Data::Asset SkinnedMeshOutputStreamManager::GetBufferAsset() const + Data::Asset SkinnedMeshOutputStreamManager::GetBufferAsset() { EnsureInit(); return m_bufferAsset; diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h index 6009a62362..d0d00ead18 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.h @@ -39,14 +39,13 @@ namespace AZ AZStd::intrusive_ptr Allocate(size_t byteCount) override; void DeAllocate(RHI::VirtualAddress allocation) override; void DeAllocateNoSignal(RHI::VirtualAddress allocation) override; - Data::Asset GetBufferAsset() const override; + Data::Asset GetBufferAsset() override; Data::Instance GetBuffer() override; private: // SystemTickBus void OnSystemTick() override; - void EnsureInit() const; void EnsureInit(); void GarbageCollect(); void CalculateAlignment(); From 1badb5a31f7b73b7b83247f6ba90c48949c088a6 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 13 Sep 2021 15:30:31 -0700 Subject: [PATCH 010/293] scan refactor is in a working state Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../ScriptCanvas/Bus/EditorScriptCanvasBus.h | 3 +- .../Code/Editor/SystemComponent.cpp | 107 +---- .../Code/Editor/SystemComponent.h | 69 +-- .../Code/Editor/View/Windows/MainWindow.cpp | 10 +- .../Code/Editor/View/Windows/MainWindow.h | 2 +- .../Windows/Tools/UpgradeTool/Controller.cpp | 393 +++++++++--------- .../Windows/Tools/UpgradeTool/Controller.h | 45 +- .../Windows/Tools/UpgradeTool/Controller.ui | 4 +- .../View/Windows/Tools/UpgradeTool/Model.cpp | 44 ++ .../View/Windows/Tools/UpgradeTool/Model.h | 26 +- .../Windows/Tools/UpgradeTool/ModelTraits.h | 23 +- .../Windows/Tools/UpgradeTool/Scanner.cpp | 94 +++++ .../View/Windows/Tools/UpgradeTool/Scanner.h | 20 + .../Windows/Tools/UpgradeTool/ViewTraits.h | 10 +- 14 files changed, 477 insertions(+), 373 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index 4497968ffc..09869ba2eb 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -221,8 +221,7 @@ namespace ScriptCanvasEditor AZ_TYPE_INFO(IUpgradeRequests, "{D25318F2-4DDA-4E76-98CB-6D561BB6234D}"); using AssetList = AZStd::list; - virtual AssetList& GetAssetsToUpgrade() = 0; - + virtual void ClearGraphsThatNeedUpgrade() = 0; virtual void GraphNeedsManualUpgrade(const AZ::Data::AssetId&) = 0; virtual const AZStd::vector& GetGraphsThatNeedManualUpgrade() const = 0; diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp index 4b60fd357c..f901915fdb 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.cpp @@ -6,46 +6,35 @@ * */ - -#include -#include -#include #include +#include +#include +#include +#include #include - #include - +#include #include +#include #include - -#include - +#include +#include #include - -#include #include #include -#include - +#include +#include +#include +#include +#include #include +#include +#include #include #include #include #include -#include -#include - -#include - -#include -#include - #include -#include -#include - -#include -#include namespace ScriptCanvasEditor { @@ -54,6 +43,7 @@ namespace ScriptCanvasEditor SystemComponent::SystemComponent() { AzToolsFramework::AssetSeedManagerRequests::Bus::Handler::BusConnect(); + m_versionExplorer = AZStd::make_unique(); } SystemComponent::~SystemComponent() @@ -61,7 +51,6 @@ namespace ScriptCanvasEditor AzToolsFramework::UnregisterViewPane(LyViewPane::ScriptCanvas); AzToolsFramework::EditorContextMenuBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); AzToolsFramework::AssetSeedManagerRequests::Bus::Handler::BusDisconnect(); } @@ -141,17 +130,12 @@ namespace ScriptCanvasEditor { if (userSettings->m_showUpgradeDialog) { - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); } else { m_upgradeDisabled = true; } } - else - { - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } } void SystemComponent::NotifyRegisterViews() @@ -172,7 +156,6 @@ namespace ScriptCanvasEditor AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); ScriptCanvasExecutionBus::Handler::BusDisconnect(); SystemRequestBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); m_jobContext.reset(); m_jobManager.reset(); @@ -397,64 +380,6 @@ namespace ScriptCanvasEditor return reporter; } - void SystemComponent::OnCatalogLoaded(const char* /*catalogFile*/) - { - // Enumerate all ScriptCanvas assets - AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, - nullptr, - [this](const AZ::Data::AssetId, const AZ::Data::AssetInfo& assetInfo) { - - if (assetInfo.m_assetType == azrtti_typeid()) - { - AddAssetToUpgrade(assetInfo); - } - }, - nullptr - ); - } - - void SystemComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) - { - if (IsUpgrading()) - { - return; - } - - auto assetInfo = ScriptCanvasEditor::AssetHelpers::GetAssetInfo(assetId); - AddAssetToUpgrade(assetInfo); - } - - void SystemComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& /*assetInfo*/) - { - if (IsUpgrading()) - { - return; - } - - AZStd::erase_if(m_assetsToConvert, [assetId](const AZ::Data::AssetInfo& assetToConvert) - { - return assetToConvert.m_assetId == assetId; - } - ); - } - - void SystemComponent::AddAssetToUpgrade(const AZ::Data::AssetInfo& assetInfo) - { - auto query = AZStd::find_if(m_assetsToConvert.begin(), m_assetsToConvert.end(), [assetInfo](const AZ::Data::AssetInfo& assetToConvert) - { - return assetToConvert.m_assetId == assetInfo.m_assetId; - } - ); - - if (query == m_assetsToConvert.end()) - { - if (assetInfo.m_assetType == azrtti_typeid()) - { - m_assetsToConvert.push_back(assetInfo); - } - } - } - AzToolsFramework::AssetSeedManagerRequests::AssetTypePairs SystemComponent::GetAssetTypeMapping() { return { diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h index ba850401d6..37d5962271 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h @@ -9,23 +9,20 @@ #pragma once -#include -#include -#include - #include -#include +#include +#include #include - +#include #include +#include #include #include +#include #include - -#include - -#include -#include +#include +#include +#include namespace ScriptCanvasEditor { @@ -36,9 +33,7 @@ namespace ScriptCanvasEditor , private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler , private ScriptCanvasExecutionBus::Handler , private AZ::UserSettingsNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler , private AZ::Data::AssetBus::MultiHandler - , private AZ::Interface::Registrar , private AzToolsFramework::AssetSeedManagerRequests::Bus::Handler , private AzToolsFramework::EditorContextMenuBus::Handler { @@ -96,74 +91,30 @@ namespace ScriptCanvasEditor void OnUserSettingsActivated() override; //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// - // AzFramework::AssetCatalogEventBus::Handler... - void OnCatalogLoaded(const char* /*catalogFile*/) override; - void OnCatalogAssetAdded(const AZ::Data::AssetId& /*assetId*/) override; - void OnCatalogAssetRemoved(const AZ::Data::AssetId& /*assetId*/, const AZ::Data::AssetInfo& /*assetInfo*/) override; - //////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////// // AssetSeedManagerRequests::Bus::Handler... AzToolsFramework::AssetSeedManagerRequests::AssetTypePairs GetAssetTypeMapping() override; //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// - // IUpgradeRequests... - void ClearGraphsThatNeedUpgrade() - { - m_assetsThatNeedManualUpgrade.clear(); - } - - IUpgradeRequests::AssetList& GetAssetsToUpgrade() override - { - return m_assetsToConvert; - } - - void GraphNeedsManualUpgrade(const AZ::Data::AssetId& assetId) override - { - if (AZStd::find(m_assetsThatNeedManualUpgrade.begin(), m_assetsThatNeedManualUpgrade.end(), assetId) == m_assetsThatNeedManualUpgrade.end()) - { - m_assetsThatNeedManualUpgrade.push_back(assetId); - } - } - - const AZStd::vector& GetGraphsThatNeedManualUpgrade() const override - { - return m_assetsThatNeedManualUpgrade; - } - - bool IsUpgrading() override - { - return m_isUpgrading; - } - - void SetIsUpgrading(bool isUpgrading) override - { - m_isUpgrading = isUpgrading; - } - - //////////////////////////////////////////////////////////////////////// private: SystemComponent(const SystemComponent&) = delete; void FilterForScriptCanvasEnabledEntities(AzToolsFramework::EntityIdList& sourceList, AzToolsFramework::EntityIdList& targetList); void PopulateEditorCreatableTypes(); - void AddAssetToUpgrade(const AZ::Data::AssetInfo& assetInfo); - + AZStd::unique_ptr m_jobManager; AZStd::unique_ptr m_jobContext; + AZStd::unique_ptr m_versionExplorer; AZStd::unordered_set m_creatableTypes; AssetTracker m_assetTracker; - IUpgradeRequests::AssetList m_assetsToConvert; AZStd::vector m_assetsThatNeedManualUpgrade; bool m_isUpgrading = false; bool m_upgradeDisabled = false; - }; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 33a58c18a7..6c10726e13 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -134,7 +134,6 @@ #include #include #include -#include #include @@ -3436,9 +3435,14 @@ namespace ScriptCanvasEditor void MainWindow::RunUpgradeTool() { - auto versionExplorer = aznew VersionExplorer::View(this); + // \todo, restore this behavior, post modification step + + /* + auto versionExplorer = aznew VersionExplorer::Controller(this); versionExplorer->exec(); + + // Manual correction size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); @@ -3448,6 +3452,8 @@ namespace ScriptCanvasEditor UpgradeHelper* upgradeHelper = new UpgradeHelper(this); upgradeHelper->show(); } + */ + } void MainWindow::OnShowValidationErrors() diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 54557c3691..1eeb2dadfb 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -51,7 +51,7 @@ #include -#include +#include #if SCRIPTCANVAS_EDITOR #include diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index bf407765e1..4b2d3d37b9 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -28,12 +28,14 @@ #include #include #include -#include -#include +#include #include #include #include +#include +#include + namespace ScriptCanvasEditor { namespace VersionExplorer @@ -60,33 +62,32 @@ namespace ScriptCanvasEditor } } - View::View(QWidget* parent) + Controller::Controller(QWidget* parent) : AzQtComponents::StyledDialog(parent) - , m_ui(new Ui::View()) + , m_view(new Ui::Controller()) { - m_ui->setupUi(this); - m_ui->tableWidget->horizontalHeader()->setVisible(false); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); - m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); - m_ui->tableWidget->setColumnWidth(3, 22); - m_ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); - m_ui->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); - connect(m_ui->scanButton, &QPushButton::pressed, this, &View::OnScanButtonPress); - connect(m_ui->closeButton, &QPushButton::pressed, this, &View::OnCloseButtonPress); - connect(m_ui->upgradeAllButton, &QPushButton::pressed, this, &View::OnUpgradeAllButtonPress); - m_ui->progressBar->setValue(0); - m_ui->progressBar->setVisible(false); - - ViewRequestsBus::Handler::BusConnect(); + m_view->setupUi(this); + m_view->tableWidget->horizontalHeader()->setVisible(false); + m_view->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + m_view->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); + m_view->tableWidget->setColumnWidth(3, 22); + m_view->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); + connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnScanButtonPress); + connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnCloseButtonPress); + connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnUpgradeAllButtonPress); + m_view->progressBar->setValue(0); + m_view->progressBar->setVisible(false); + ModelNotificationsBus::Handler::BusConnect(); // move to model, maybe m_keepEditorAlive = AZStd::make_unique(); } - void View::Log(const char* /*format*/, ...) + void Controller::Log(const char* /*format*/, ...) { -// if (m_ui->verbose->isChecked()) +// if (m_view->verbose->isChecked()) // { // char sBuffer[2048]; // va_list ArgList; @@ -99,12 +100,12 @@ namespace ScriptCanvasEditor // } } - void View::OnCloseButtonPress() + void Controller::OnCloseButtonPress() { reject(); } - void View::OnSystemTick() + void Controller::OnSystemTick() { // switch (m_state) // { @@ -125,10 +126,10 @@ namespace ScriptCanvasEditor // } // else // { -// m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); +// m_view->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); // QTableWidgetItem* rowName = new QTableWidgetItem // (tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); -// m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); +// m_view->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); // ++m_currentAssetRowIndex; // // Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); @@ -145,8 +146,8 @@ namespace ScriptCanvasEditor // { // ++m_upgradeAssetIndex; // m_inProgress = false; -// m_ui->progressBar->setVisible(true); -// m_ui->progressBar->setValue(m_upgradeAssetIndex); +// m_view->progressBar->setVisible(true); +// m_view->progressBar->setValue(m_upgradeAssetIndex); // // if (m_scriptCanvasEntity) // { @@ -182,7 +183,7 @@ namespace ScriptCanvasEditor // // if (m_assetsToUpgrade.empty()) // { -// m_ui->upgradeAllButton->setEnabled(false); +// m_view->upgradeAllButton->setEnabled(false); // } // // m_upgradeComplete = false; @@ -195,13 +196,13 @@ namespace ScriptCanvasEditor // if (errorMessage.empty()) // { // Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); -// QList items = m_ui->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); +// QList items = m_view->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); // if (!items.isEmpty()) // { // for (auto* item : items) // { // int row = item->row(); -// AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnStatus)); +// AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnStatus)); // spinner->SetIsBusy(true); // } // } @@ -230,7 +231,7 @@ namespace ScriptCanvasEditor // Backup - void View::OnUpgradeAllButtonPress() + void Controller::OnUpgradeAllButtonPress() { m_state = ProcessState::Upgrade; //m_settingsCache = AZStd::make_unique(); @@ -241,15 +242,15 @@ namespace ScriptCanvasEditor AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); m_inProgressAsset = m_assetsToUpgrade.begin(); AZ::SystemTickBus::Handler::BusConnect(); - m_ui->progressBar->setVisible(true); - m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - m_ui->progressBar->setValue(m_upgradeAssetIndex); + m_view->progressBar->setVisible(true); + m_view->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); + m_view->progressBar->setValue(m_upgradeAssetIndex); m_keepEditorAlive = AZStd::make_unique(); } - AZStd::string View::BackupGraph(const AZ::Data::Asset& asset) + AZStd::string Controller::BackupGraph(const AZ::Data::Asset& asset) { - if (!m_ui->makeBackupCheckbox->isChecked()) + if (!m_view->makeBackupCheckbox->isChecked()) { // considered a success return ""; @@ -303,7 +304,7 @@ namespace ScriptCanvasEditor } else { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "View::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Controller::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); return "Failed to find source file"; } @@ -325,20 +326,20 @@ namespace ScriptCanvasEditor if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "View::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Controller::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); return "Failed to copy source file to backup location"; } - Log("View::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); + Log("Controller::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); return ""; } - void View::UpgradeGraph(const AZ::Data::Asset& asset) + void Controller::UpgradeGraph(const AZ::Data::Asset& asset) { m_inProgress = true; m_upgradeComplete = false; Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); - m_ui->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); + m_view->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); m_scriptCanvasEntity = nullptr; UpgradeNotifications::Bus::Handler::BusConnect(); @@ -355,7 +356,7 @@ namespace ScriptCanvasEditor } AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity"); + AZ_Assert(scriptCanvasEntity, "Controller::UpgradeGraph The Script Canvas asset must have a valid entity"); if (!scriptCanvasEntity) { return; @@ -393,15 +394,15 @@ namespace ScriptCanvasEditor graphComponent->UpgradeGraph (asset - , m_ui->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_ui->verbose->isChecked()); + , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_view->verbose->isChecked()); } } AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); } - void View::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) + void Controller::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) { AZStd::string relativePath, fullPath; AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); @@ -421,7 +422,7 @@ namespace ScriptCanvasEditor streamer->QueueRequest(flushRequest); } - void View::OnSourceFileReleased(AZ::Data::Asset asset) + void Controller::OnSourceFileReleased(AZ::Data::Asset asset) { AZStd::string relativePath, fullPath; AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); @@ -502,7 +503,7 @@ namespace ScriptCanvasEditor }); } - void View::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target + void Controller::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target , size_t remainingAttempts) { // ViewCpp::FileEventHandler fileEventHandler; @@ -559,7 +560,7 @@ namespace ScriptCanvasEditor } } - void View::GraphUpgradeComplete + void Controller::GraphUpgradeComplete (const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) { AZStd::lock_guard lock(m_mutex); @@ -587,24 +588,24 @@ namespace ScriptCanvasEditor m_tmpFileName.clear(); } - void View::GraphUpgradeCompleteUIUpdate + void Controller::GraphUpgradeCompleteUIUpdate (const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) { QString text = asset.GetHint().c_str(); - QList items = m_ui->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); + QList items = m_view->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); if (!items.isEmpty()) { for (auto* item : items) { int row = item->row(); - QTableWidgetItem* label = m_ui->tableWidget->item(row, ColumnAsset); + QTableWidgetItem* label = m_view->tableWidget->item(row, ColumnAsset); QString assetName = asset.GetHint().c_str(); if (label->text().compare(assetName) == 0) { - m_ui->tableWidget->removeCellWidget(row, ColumnAction); - m_ui->tableWidget->removeCellWidget(row, ColumnStatus); + m_view->tableWidget->removeCellWidget(row, ColumnAction); + m_view->tableWidget->removeCellWidget(row, ColumnStatus); QToolButton* doneButton = new QToolButton(this); doneButton->setToolTip("Upgrade complete"); @@ -618,31 +619,31 @@ namespace ScriptCanvasEditor doneButton->setToolTip(message.data()); } - m_ui->tableWidget->setCellWidget(row, ColumnStatus, doneButton); + m_view->tableWidget->setCellWidget(row, ColumnStatus, doneButton); } } } } - void View::FinalizeUpgrade() + void Controller::FinalizeUpgrade() { Log("FinalizeUpgrade!"); m_inProgress = false; m_assetsToUpgrade.clear(); - m_ui->upgradeAllButton->setEnabled(false); - m_ui->onlyShowOutdated->setEnabled(true); + m_view->upgradeAllButton->setEnabled(false); + m_view->onlyShowOutdated->setEnabled(true); m_keepEditorAlive.reset(); - m_ui->progressBar->setVisible(false); + m_view->progressBar->setVisible(false); // Manual correction size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); if (assetsThatNeedManualInspection > 0) { - m_ui->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); + m_view->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); } else { - m_ui->spinner->SetText("Upgrade complete."); + m_view->spinner->SetText("Upgrade complete."); } AZ::SystemTickBus::Handler::BusDisconnect(); @@ -650,126 +651,120 @@ namespace ScriptCanvasEditor //m_settingsCache.reset(); } - // Scanning - - void View::OnScanButtonPress() + void Controller::OnScanButtonPress() { - ViewNotificationsBus::Broadcast(&ViewNotificationsTraits::ScanRequested); - -// m_assetsToUpgrade.clear(); -// m_assetsToInspect.clear(); -// m_ui->tableWidget->setRowCount(0); -// m_inspectedAssets = 0; -// m_currentAssetRowIndex = 0; -// IUpgradeRequests* upgradeRequests = AZ::Interface::Get(); -// m_assetsToInspect = upgradeRequests->GetAssetsToUpgrade(); -// DoScan(); - } + auto isUpToDate = [this](AZ::Data::Asset asset) + { + Log("InspectAsset: %s", asset.GetHint().c_str()); + AZ::Entity* scriptCanvasEntity = nullptr; - void View::DoScan() - { -// m_state = ProcessState::Scan; -// m_settingsCache = AZStd::make_unique(); -// ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; -// ScriptCanvas::Grammar::g_printAbstractCodeModel = false; -// ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; -// -// AZ::SystemTickBus::Handler::BusConnect(); -// -// if (!m_assetsToInspect.empty()) -// { -// m_discoveredAssets = m_assetsToInspect.size(); -// m_failedAssets = 0; -// m_inspectedAssets = 0; -// m_currentAssetRowIndex = 0; -// m_ui->progressFrame->setVisible(true); -// m_ui->progressBar->setVisible(true); -// m_ui->progressBar->setRange(0, aznumeric_cast(m_assetsToInspect.size())); -// m_ui->progressBar->setValue(0); -// -// m_ui->spinner->SetIsBusy(true); -// m_ui->spinner->SetBusyIconSize(32); -// -// m_ui->scanButton->setEnabled(false); -// m_ui->upgradeAllButton->setEnabled(false); -// m_ui->onlyShowOutdated->setEnabled(false); -// -// m_inspectingAsset = m_assetsToInspect.begin(); -// m_keepEditorAlive = AZStd::make_unique(); -// } + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + if (!scriptCanvasAsset) + { + Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); + return true; + } + + scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); + } + + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + return !m_view->forceUpgrade->isChecked() && graphComponent->GetVersion().IsLatest(); + }; + + ScanConfiguration config; + config.reportFilteredGraphs = !m_view->onlyShowOutdated->isChecked(); + config.filter = isUpToDate; + + ModelRequestsBus::Broadcast(&ModelRequestsTraits::Scan, config); } - void View::BackupComplete() + void Controller::OnScanBegin(size_t assetCount) { m_currentAssetRowIndex = 0; - m_ui->progressBar->setValue(0); - DoScan(); + m_view->tableWidget->setRowCount(0); + m_view->progressBar->setVisible(true); + m_view->progressBar->setRange(0, aznumeric_cast(assetCount)); + m_view->progressBar->setValue(0); + m_view->scanButton->setEnabled(false); + m_view->upgradeAllButton->setEnabled(false); + m_view->onlyShowOutdated->setEnabled(false); } - void View::InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo) + void Controller::OnScanComplete(const ScanResult& result) { - Log("InspectAsset: %s", asset.GetHint().c_str()); - AZ::Entity* scriptCanvasEntity = nullptr; - if (asset.GetType() == azrtti_typeid()) + Log("Full Scan Complete."); + + m_view->onlyShowOutdated->setEnabled(true); + + // Enable all the Upgrade buttons + for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - if (!scriptCanvasAsset) + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) { - Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); - return; + button->setEnabled(true); } - - scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity"); } - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - bool onlyShowOutdatedGraphs = m_ui->onlyShowOutdated->isChecked(); - bool forceUpgrade = m_ui->forceUpgrade->isChecked(); - ScriptCanvas::VersionData graphVersion = graphComponent->GetVersion(); + QString spinnerText = QStringLiteral("Scan Complete"); + spinnerText.append(QString::asprintf(" - Discovered: %zu, Failed: %zu, Upgradeable: %zu, Up-to-date: %zu" + , result.m_catalogAssets.size() + , result.m_loadErrors.size() + , result.m_unfiltered.size() + , result.m_filteredAssets.size())); + m_view->spinner->SetText(spinnerText); + m_view->progressBar->setVisible(false); - if (!forceUpgrade && onlyShowOutdatedGraphs && graphVersion.IsLatest()) + if (!result.m_unfiltered.empty()) { - ScanComplete(asset); - Log("InspectAsset: %s, is at latest", asset.GetHint().c_str()); - return; + m_view->upgradeAllButton->setEnabled(true); } - m_ui->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(asset.GetHint().c_str())); - m_ui->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + m_keepEditorAlive.reset(); + } - if (forceUpgrade || !graphComponent->GetVersion().IsLatest()) - { - m_assetsToUpgrade.push_back(asset); + void Controller::OnScanFilteredGraph(const AZ::Data::AssetInfo& info) + { + OnScannedGraph(info, Filtered::Yes); + } - AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); - spinner->SetBusyIconSize(16); + void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, Filtered filtered) + { + m_view->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); + m_view->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + if (filtered == Filtered::No) + { QPushButton* rowGoToButton = new QPushButton(this); rowGoToButton->setText("Upgrade"); rowGoToButton->setEnabled(false); + AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); + spinner->SetBusyIconSize(16); +// +// connect(rowGoToButton, &QPushButton::clicked, [this, rowGoToButton, assetInfo] { +// +// // request upgrade of a single graph +// // AZ::SystemTickBus::QueueFunction([this, rowGoToButton, assetInfo]() { +// // // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda +// // UpgradeSingle(rowGoToButton, spinner, assetInfo); +// // }); +// // +// // AZ::SystemTickBus::ExecuteQueuedEvents(); +// +// }); - connect(rowGoToButton, &QPushButton::clicked, [this, spinner, rowGoToButton, assetInfo] { - - AZ::SystemTickBus::QueueFunction([this, rowGoToButton, spinner, assetInfo]() { - // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda - UpgradeSingle(rowGoToButton, spinner, assetInfo); - }); - - AZ::SystemTickBus::ExecuteQueuedEvents(); - - }); - - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); + m_view->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); + m_view->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); } char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.m_relativePath.c_str()); AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); AZ::StringFunc::Path::Normalize(path); @@ -777,10 +772,17 @@ namespace ScriptCanvasEditor bool result = false; AZ::Data::AssetInfo info; AZStd::string watchFolder; - QByteArray assetNameUtf8 = asset.GetHint().c_str(); - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetNameUtf8, info, watchFolder); - - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), result, "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); + QByteArray assetNameUtf8 = assetInfo.m_relativePath.c_str(); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult + ( result + , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath + , assetNameUtf8 + , info + , watchFolder); + AZ_Error + ( ScriptCanvas::k_VersionExplorerWindow.data() + , result + , "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); QToolButton* browseButton = new QToolButton(this); browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); @@ -791,14 +793,40 @@ namespace ScriptCanvasEditor AzQtComponents::ShowFileOnDesktop(absolutePath); }); - m_ui->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); - ScanComplete(asset); - ++m_inspectedAssets; + m_view->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); + OnScannedGraphResult(assetInfo); + } + + void Controller::OnScannedGraphResult(const AZ::Data::AssetInfo& info) + { + m_view->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); ++m_currentAssetRowIndex; + Log("ScanComplete: %s", info.m_relativePath.c_str()); + FlushLogs(); + } + + void Controller::OnScanLoadFailure(const AZ::Data::AssetInfo& info) + { + m_view->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + QTableWidgetItem* rowName = new QTableWidgetItem + (tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str())); + m_view->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + OnScannedGraphResult(info); + } + + void Controller::OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) + { + OnScannedGraph(info, Filtered::No); } - void View::UpgradeSingle - (QPushButton* rowGoToButton + void Controller::BackupComplete() + { + m_currentAssetRowIndex = 0; + m_view->progressBar->setValue(0); + } + + void Controller::UpgradeSingle + ( QPushButton* rowGoToButton , AzQtComponents::StyledBusyLabel* spinner , AZ::Data::AssetInfo assetInfo) { @@ -814,7 +842,7 @@ namespace ScriptCanvasEditor AZ::Interface::Get()->SetIsUpgrading(true); m_isUpgradingSingleGraph = true; m_logs.clear(); - m_ui->textEdit->clear(); + m_view->textEdit->clear(); spinner->SetIsBusy(true); rowGoToButton->setEnabled(false); @@ -830,38 +858,37 @@ namespace ScriptCanvasEditor } } - void View::ScanComplete(const AZ::Data::Asset& asset) + void Controller::ScanComplete(const AZ::Data::Asset& asset) { Log("ScanComplete: %s", asset.GetHint().c_str()); m_inProgress = false; - m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - m_ui->scanButton->setEnabled(true); + m_view->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); + m_view->scanButton->setEnabled(true); m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); - FlushLogs(); - + if (m_inspectingAsset == m_assetsToInspect.end()) { AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); if (!m_assetsToUpgrade.empty()) { - m_ui->upgradeAllButton->setEnabled(true); + m_view->upgradeAllButton->setEnabled(true); } } } - void View::FinalizeScan() + void Controller::FinalizeScan() { Log("FinalizeScan()"); - m_ui->spinner->SetIsBusy(false); - m_ui->onlyShowOutdated->setEnabled(true); + m_view->spinner->SetIsBusy(false); + m_view->onlyShowOutdated->setEnabled(true); // Enable all the Upgrade buttons - for (int row = 0; row < m_ui->tableWidget->rowCount(); ++row) + for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) { - QPushButton* button = qobject_cast(m_ui->tableWidget->cellWidget(row, ColumnAction)); + QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction)); if (button) { button->setEnabled(true); @@ -880,12 +907,12 @@ namespace ScriptCanvasEditor } - m_ui->spinner->SetText(spinnerText); - m_ui->progressBar->setVisible(false); + m_view->spinner->SetText(spinnerText); + m_view->progressBar->setVisible(false); if (!m_assetsToUpgrade.empty()) { - m_ui->upgradeAllButton->setEnabled(true); + m_view->upgradeAllButton->setEnabled(true); } AZ::SystemTickBus::Handler::BusDisconnect(); @@ -895,18 +922,18 @@ namespace ScriptCanvasEditor m_state = ProcessState::Inactive; } - void View::FlushLogs() + void Controller::FlushLogs() { if (m_logs.empty()) { return; } - const QTextCursor oldCursor = m_ui->textEdit->textCursor(); - QScrollBar* scrollBar = m_ui->textEdit->verticalScrollBar(); + const QTextCursor oldCursor = m_view->textEdit->textCursor(); + QScrollBar* scrollBar = m_view->textEdit->verticalScrollBar(); - m_ui->textEdit->moveCursor(QTextCursor::End); - QTextCursor textCursor = m_ui->textEdit->textCursor(); + m_view->textEdit->moveCursor(QTextCursor::End); + QTextCursor textCursor = m_view->textEdit->textCursor(); while (!m_logs.empty()) { @@ -918,19 +945,15 @@ namespace ScriptCanvasEditor } scrollBar->setValue(scrollBar->maximum()); - m_ui->textEdit->moveCursor(QTextCursor::StartOfLine); + m_view->textEdit->moveCursor(QTextCursor::StartOfLine); } - - void View::closeEvent(QCloseEvent* event) + void Controller::closeEvent(QCloseEvent* event) { m_keepEditorAlive.reset(); AzQtComponents::StyledDialog::closeEvent(event); } } - -#include - } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 905074d17e..85459b4d46 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -9,27 +9,26 @@ #pragma once #if !defined(Q_MOC_RUN) -#include -AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING #include #include +#include #include +#include +#include #include #include #include #include +AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING #endif -#include -#include - class QPushButton; namespace Ui { - class View; + class Controller; } namespace AzQtComponents @@ -56,29 +55,41 @@ namespace ScriptCanvasEditor //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog //! Handles display change notifications, handles state change notifications, sends control requests - class View + class Controller : public AzQtComponents::StyledDialog , private AZ::SystemTickBus::Handler , private UpgradeNotifications::Bus::Handler - , private ViewRequestsBus::Handler , private ModelNotificationsBus::Handler { Q_OBJECT public: - AZ_CLASS_ALLOCATOR(View, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(Controller, AZ::SystemAllocator, 0); - explicit View(QWidget* parent = nullptr); + explicit Controller(QWidget* parent = nullptr); private: - static constexpr int ColumnAsset = 0; static constexpr int ColumnAction = 1; static constexpr int ColumnBrowse = 2; static constexpr int ColumnStatus = 3; void OnCloseButtonPress(); + void OnScanBegin(size_t assetCount) override; void OnScanButtonPress(); + void OnScanComplete(const ScanResult& result) override; + void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) override; + void OnScanLoadFailure(const AZ::Data::AssetInfo& info) override; + void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) override; + enum Filtered + { + No, + Yes + }; + void OnScannedGraph(const AZ::Data::AssetInfo& info, Filtered filtered); + void OnScannedGraphResult(const AZ::Data::AssetInfo& info); + + void OnUpgradeAllButtonPress(); enum class ProcessState @@ -90,11 +101,8 @@ namespace ScriptCanvasEditor }; ProcessState m_state = ProcessState::Inactive; - void DoScan(); void ScanComplete(const AZ::Data::Asset&); - void InspectAsset(AZ::Data::Asset& asset, AZ::Data::AssetInfo& assetInfo); - // SystemTickBus::Handler void OnSystemTick() override; @@ -123,9 +131,8 @@ namespace ScriptCanvasEditor AZ::Data::Asset m_currentAsset; - AZStd::unique_ptr m_ui; - - + AZStd::unique_ptr m_view; + // upgrade fields AZStd::recursive_mutex m_mutex; bool m_upgradeComplete = false; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui index f549c821d6..fdeb701f33 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui @@ -1,7 +1,7 @@ - View - + Controller + Qt::WindowModal diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index 710d6863f5..8d5aa62674 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -6,7 +6,10 @@ * */ +#include #include +#include +#include namespace ModifierCpp { @@ -17,9 +20,50 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + Model::Model() + { + ModelRequestsBus::Handler::BusConnect(); + } + + void Model::CacheSettings() + { + m_settingsCache = AZStd::make_unique(); + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + ScriptCanvas::Grammar::g_printAbstractCodeModel = false; + ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; + } + const AZStd::vector* Model::GetLogs() { return &m_log.GetEntries(); } + + bool Model::IsWorking() const + { + return m_state != State::Idle; + } + + void Model::OnScanComplete() + { + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanComplete, m_scanner->GetResult()); + m_state = State::Idle; + } + + void Model::Scan(const ScanConfiguration& config) + { + if (IsWorking()) + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Explorer is already working"); + return; + } + + m_state = State::Scanning; + m_scanner = AZStd::make_unique(config, [this](){ OnScanComplete(); }); + } + + void Model::RestoreSettings() + { + m_settingsCache.reset(); + } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h index 44da70e85c..407074fa94 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h @@ -7,9 +7,13 @@ */ #pragma once -#include + +#include #include +#include +#include #include +#include namespace ScriptCanvasEditor { @@ -22,12 +26,30 @@ namespace ScriptCanvasEditor public: AZ_CLASS_ALLOCATOR(Model, AZ::SystemAllocator, 0); + Model(); + const AZStd::vector* GetLogs(); + void Scan(const ScanConfiguration& config) override; private: - Log m_log; + enum class State + { + Idle, + Scanning, + Modifying, + }; + State m_state = State::Idle; + Log m_log; + + AZStd::unique_ptr m_modifier; + AZStd::unique_ptr m_scanner; AZStd::unique_ptr m_settingsCache; + + void CacheSettings(); + bool IsWorking() const; + void OnScanComplete(); + void RestoreSettings(); }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index e66cdac13e..11a956c555 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -8,23 +8,44 @@ #pragma once #include +#include namespace ScriptCanvasEditor { namespace VersionExplorer { + struct ScanConfiguration + { + AZStd::function)> filter; + bool reportFilteredGraphs = false; + }; + class ModelRequestsTraits : public AZ::EBusTraits { public: - virtual const AZStd::vector* GetLogs(); + virtual const AZStd::vector* GetLogs() = 0; + virtual void Scan(const ScanConfiguration& filter) = 0; }; using ModelRequestsBus = AZ::EBus; + struct ScanResult + { + AZStd::vector m_catalogAssets; + AZStd::vector m_unfiltered; + AZStd::vector m_filteredAssets; + AZStd::vector m_loadErrors; + }; + class ModelNotificationsTraits : public AZ::EBusTraits { public: + virtual void OnScanBegin(size_t assetCount) = 0; + virtual void OnScanComplete(const ScanResult& result) = 0; + virtual void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) = 0; + virtual void OnScanLoadFailure(const AZ::Data::AssetInfo& info) = 0; + virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0; }; using ModelNotificationsBus = AZ::EBus; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index f74c27004b..09574883b6 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace ScannerCpp { @@ -17,6 +18,99 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + Scanner::Scanner(const ScanConfiguration& config, AZStd::function onComplete) + : m_config(config) + , m_onComplete(onComplete) + { + AZ::Data::AssetCatalogRequestBus::Broadcast + ( &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets + , nullptr + , [this](const AZ::Data::AssetId, const AZ::Data::AssetInfo& assetInfo) + { + if (assetInfo.m_assetType == azrtti_typeid()) + { + m_result.m_catalogAssets.push_back(assetInfo); + } + } + , nullptr); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanBegin, m_result.m_catalogAssets.size()); + AZ::SystemTickBus::Handler::BusConnect(); + } + + void Scanner::FilterAsset(AZ::Data::Asset asset) + { + if (m_config.filter && m_config.filter(asset)) + { + m_result.m_filteredAssets.push_back(GetCurrentAsset()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanFilteredGraph, GetCurrentAsset()); + } + else + { + m_result.m_unfiltered.push_back(GetCurrentAsset()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, GetCurrentAsset()); + } + } + + const AZ::Data::AssetInfo& Scanner::GetCurrentAsset() const + { + return m_result.m_catalogAssets[m_catalogAssetIndex]; + } + + const ScanResult& Scanner::GetResult() const + { + return m_result; + } + + AZ::Data::Asset Scanner::LoadAsset() + { + AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset + ( GetCurrentAsset().m_assetId + , azrtti_typeid() + , AZ::Data::AssetLoadBehavior::PreLoad); + + // Log("Scan: Loading: %s ", m_catalogAssets[m_catalogAssetIndex].GetHint().c_str()); + asset.BlockUntilLoadComplete(); + + if (asset.IsReady()) + { + return asset; + } + else + { + return {}; + } + } + + void Scanner::OnSystemTick() + { + if (m_catalogAssetIndex == m_result.m_catalogAssets.size()) + { + AZ::SystemTickBus::Handler::BusConnect(); + if (m_onComplete) + { + m_onComplete(); + } + } + else + { + if (auto asset = LoadAsset()) + { + FilterAsset(asset); + } + else + { + m_result.m_loadErrors.push_back(GetCurrentAsset()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanLoadFailure, GetCurrentAsset()); + } + + ++m_catalogAssetIndex; + } + } + + ScanResult&& Scanner::TakeResult() + { + return AZStd::move(m_result); + } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h index 19642a07f1..8b4dd69c82 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h @@ -9,15 +9,35 @@ #pragma once #include +#include +#include namespace ScriptCanvasEditor { namespace VersionExplorer { class Scanner + : private AZ::SystemTickBus::Handler { public: AZ_CLASS_ALLOCATOR(Scanner, AZ::SystemAllocator, 0); + + Scanner(const ScanConfiguration& config, AZStd::function onComplete); + + const ScanResult& GetResult() const; + + ScanResult&& TakeResult(); + + private: + size_t m_catalogAssetIndex = 0; + AZStd::function m_onComplete; + ScanConfiguration m_config; + ScanResult m_result; + + void FilterAsset(AZ::Data::Asset); + const AZ::Data::AssetInfo& GetCurrentAsset() const; + AZ::Data::Asset LoadAsset(); + void OnSystemTick() override; }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h index 7f36e8503d..cf49072230 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h @@ -13,14 +13,6 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { - class ViewRequestsTraits : public AZ::EBusTraits - { - public: - // flush logs, or add log text - // set progress update - virtual void ClearProgress() {} - virtual void SetInProgress() {} - }; - using ViewRequestsBus = AZ::EBus; + } } From cb12d318217e2616dc97d3e66f62af6221b75ac8 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 13 Sep 2021 18:01:49 -0700 Subject: [PATCH 011/293] Modifier step WIP Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/Controller.cpp | 790 ++---------------- .../Windows/Tools/UpgradeTool/Controller.h | 119 +-- .../Windows/Tools/UpgradeTool/LogTraits.h | 32 + .../View/Windows/Tools/UpgradeTool/Model.cpp | 77 +- .../View/Windows/Tools/UpgradeTool/Model.h | 22 +- .../Windows/Tools/UpgradeTool/ModelTraits.h | 18 +- .../Windows/Tools/UpgradeTool/Modifier.cpp | 13 + .../View/Windows/Tools/UpgradeTool/Modifier.h | 16 + .../Windows/Tools/UpgradeTool/Scanner.cpp | 16 +- .../Tools/UpgradeTool/VersionExplorerLog.cpp | 32 +- .../Tools/UpgradeTool/VersionExplorerLog.h | 13 +- .../Windows/Tools/UpgradeTool/ViewTraits.h | 18 - .../Code/scriptcanvasgem_editor_files.cmake | 14 +- 13 files changed, 317 insertions(+), 863 deletions(-) create mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h delete mode 100644 Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 4b2d3d37b9..44d6f2e738 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -40,28 +41,6 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { - EditorKeepAlive::EditorKeepAlive() - { - ISystem* system = nullptr; - CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); - - m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); - - if (m_edKeepEditorActive) - { - m_keepEditorActive = m_edKeepEditorActive->GetIVal(); - m_edKeepEditorActive->Set(1); - } - } - - EditorKeepAlive::~EditorKeepAlive() - { - if (m_edKeepEditorActive) - { - m_edKeepEditorActive->Set(m_keepEditorActive); - } - } - Controller::Controller(QWidget* parent) : AzQtComponents::StyledDialog(parent) , m_view(new Ui::Controller()) @@ -80,582 +59,43 @@ namespace ScriptCanvasEditor m_view->progressBar->setVisible(false); ModelNotificationsBus::Handler::BusConnect(); - - // move to model, maybe - m_keepEditorAlive = AZStd::make_unique(); - } - - void Controller::Log(const char* /*format*/, ...) - { -// if (m_view->verbose->isChecked()) -// { -// char sBuffer[2048]; -// va_list ArgList; -// va_start(ArgList, format); -// azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); -// sBuffer[sizeof(sBuffer) - 1] = '\0'; -// va_end(ArgList); -// -// AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); -// } - } - - void Controller::OnCloseButtonPress() - { - reject(); - } - - void Controller::OnSystemTick() - { -// switch (m_state) -// { -// case ProcessState::Scan: -// -// if (!m_inProgress && m_inspectingAsset != m_assetsToInspect.end()) -// { -// m_inProgress = true; -// AZ::Data::AssetInfo& assetToUpgrade = *m_inspectingAsset; -// m_currentAsset = AZ::Data::AssetManager::Instance().GetAsset(assetToUpgrade.m_assetId, assetToUpgrade.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); -// Log("SystemTick::ProcessState::Scan: %s pre-blocking load hint", m_currentAsset.GetHint().c_str()); -// m_currentAsset.BlockUntilLoadComplete(); -// if (m_currentAsset.IsReady()) -// { -// // The asset is ready, grab its info -// m_inProgress = true; -// InspectAsset(m_currentAsset, assetToUpgrade); -// } -// else -// { -// m_view->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); -// QTableWidgetItem* rowName = new QTableWidgetItem -// (tr(AZStd::string::format("Error: %s", assetToUpgrade.m_relativePath.c_str()).c_str())); -// m_view->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); -// ++m_currentAssetRowIndex; -// -// Log("SystemTick::ProcessState::Scan: %s post-blocking load, problem loading asset", assetToUpgrade.m_relativePath.c_str()); -// ++m_failedAssets; -// ScanComplete(m_currentAsset); -// } -// } -// break; -// -// case ProcessState::Upgrade: -// { -// AZStd::lock_guard lock(m_mutex); -// if (m_upgradeComplete) -// { -// ++m_upgradeAssetIndex; -// m_inProgress = false; -// m_view->progressBar->setVisible(true); -// m_view->progressBar->setValue(m_upgradeAssetIndex); -// -// if (m_scriptCanvasEntity) -// { -// m_scriptCanvasEntity->Deactivate(); -// m_scriptCanvasEntity = nullptr; -// } -// -// GraphUpgradeCompleteUIUpdate(m_upgradeAsset, m_upgradeResult, m_upgradeMessage); -// -// if (!m_isUpgradingSingleGraph) -// { -// if (m_inProgressAsset != m_assetsToUpgrade.end()) -// { -// m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); -// } -// -// if (m_inProgressAsset == m_assetsToUpgrade.end()) -// { -// FinalizeUpgrade(); -// } -// } -// else -// { -// m_inProgressAsset = m_assetsToUpgrade.erase(m_inProgressAsset); -// m_inProgress = false; -// m_state = ProcessState::Inactive; -// // m_settingsCache.reset(); -// AZ::SystemTickBus::Handler::BusDisconnect(); -// -// } -// -// m_isUpgradingSingleGraph = false; -// -// if (m_assetsToUpgrade.empty()) -// { -// m_view->upgradeAllButton->setEnabled(false); -// } -// -// m_upgradeComplete = false; -// } -// -// if (!IsUpgrading() && m_state == ProcessState::Upgrade) -// { -// AZStd::string errorMessage = BackupGraph(*m_inProgressAsset); -// // Make the backup -// if (errorMessage.empty()) -// { -// Log("SystemTick::ProcessState::Upgrade: Backup Success %s ", m_inProgressAsset->GetHint().c_str()); -// QList items = m_view->tableWidget->findItems(m_inProgressAsset->GetHint().c_str(), Qt::MatchFlag::MatchExactly); -// if (!items.isEmpty()) -// { -// for (auto* item : items) -// { -// int row = item->row(); -// AzQtComponents::StyledBusyLabel* spinner = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnStatus)); -// spinner->SetIsBusy(true); -// } -// } -// -// // Upgrade the graph -// UpgradeGraph(*m_inProgressAsset); -// } -// else -// { -// Log("SystemTick::ProcessState::Upgrade: Backup Failed %s ", m_inProgressAsset->GetHint().c_str()); -// GraphUpgradeComplete(*m_inProgressAsset, OperationResult::Failure, errorMessage); -// } -// -// } -// break; -// } -// default: -// break; -// } -// -// FlushLogs(); -// -// AZ::Data::AssetManager::Instance().DispatchEvents(); -// AZ::SystemTickBus::ExecuteQueuedEvents(); - } - - // Backup - - void Controller::OnUpgradeAllButtonPress() - { - m_state = ProcessState::Upgrade; - //m_settingsCache = AZStd::make_unique(); - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - ScriptCanvas::Grammar::g_printAbstractCodeModel = false; - ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; - AZ::Interface::Get()->SetIsUpgrading(true); - AZ::Interface::Get()->ClearGraphsThatNeedUpgrade(); - m_inProgressAsset = m_assetsToUpgrade.begin(); - AZ::SystemTickBus::Handler::BusConnect(); - m_view->progressBar->setVisible(true); - m_view->progressBar->setRange(0, aznumeric_cast(m_assetsToUpgrade.size())); - m_view->progressBar->setValue(m_upgradeAssetIndex); - m_keepEditorAlive = AZStd::make_unique(); - } - - AZStd::string Controller::BackupGraph(const AZ::Data::Asset& asset) - { - if (!m_view->makeBackupCheckbox->isChecked()) - { - // considered a success - return ""; - } - - QDateTime theTime = QDateTime::currentDateTime(); - QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; - - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) - { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); - return "Failed to create backup folder"; - } - } - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - - AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo; - bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); - if (sourceInfoFound) - { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Controller::BackupGraph: Failed to find file: %s", asset.GetHint().c_str()); - return "Failed to find source file"; - } - - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Controller::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return "Failed to copy source file to backup location"; - } - - Log("Controller::BackupGraph: Backed up: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); - return ""; } - void Controller::UpgradeGraph(const AZ::Data::Asset& asset) + void Controller::AddLogEntries() { - m_inProgress = true; - m_upgradeComplete = false; - Log("UpgradeGraph %s ", m_inProgressAsset->GetHint().c_str()); - m_view->spinner->SetText(QObject::tr("Upgrading: %1").arg(asset.GetHint().c_str())); - m_scriptCanvasEntity = nullptr; - - UpgradeNotifications::Bus::Handler::BusConnect(); - - if (asset.GetType() == azrtti_typeid()) + const AZStd::vector* logs = nullptr; + LogBus::BroadcastResult(logs, &LogTraits::GetEntries); + if (!logs || logs->empty()) { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "Controller::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) - { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - - if (graphComponent) - { - m_scriptCanvasEntity = scriptCanvasEntity; - - graphComponent->UpgradeGraph - (asset - , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_view->verbose->isChecked()); - } - } - - AZ_Assert(m_scriptCanvasEntity, "The ScriptCanvas asset should have an entity"); - } - - void Controller::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool /*skipped*/ /*= false*/) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - if (!fullPathFound) - { - AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Full source path not found for %s", relativePath.c_str()); - } - - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - this->OnSourceFileReleased(asset); - }); - streamer->QueueRequest(flushRequest); - } - - void Controller::OnSourceFileReleased(AZ::Data::Asset asset) - { - AZStd::string relativePath, fullPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); - bool fullPathFound = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); - m_tmpFileName.clear(); - AZStd::string tmpFileName; - // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. - // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. - if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Failure to create temporary file name"); return; } - bool tempSavedSucceeded = false; - AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); - if (fileStream.IsOpen()) - { - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasEditor::ScriptCanvasAssetHandler handler; - tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); - } - - fileStream.Close(); - } - - // attempt to remove temporary file no matter what - m_tmpFileName = tmpFileName; - if (!tempSavedSucceeded) - { - GraphUpgradeComplete(asset, OperationResult::Failure, "Save asset data to temporary file failed"); - return; - } - - using SCCommandBus = AzToolsFramework::SourceControlCommandBus; - SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, fullPath.c_str(), true, - [this, asset, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) - { - constexpr const size_t k_maxAttemps = 10; - - if (!info.IsReadOnly()) - { - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - if (m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - else - { - int result = QMessageBox::No; - if (!m_overwriteAll) - { - QMessageBox mb(QMessageBox::Warning, - QObject::tr("Failed to Save Upgraded File"), - QObject::tr("The upgraded file could not be saved because the file is read only.\nDo you want to make it writeable and overwrite it?"), - QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No, this); - - result = mb.exec(); - if (result == QMessageBox::YesToAll) - { - m_overwriteAll = true; - } - } - - if (result == QMessageBox::Yes || m_overwriteAll) - { - AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); - PerformMove(asset, tmpFileName, fullPath, k_maxAttemps); - } - } - } - }); - } - - void Controller::PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target - , size_t remainingAttempts) - { - // ViewCpp::FileEventHandler fileEventHandler; - - if (remainingAttempts == 0) - { - // all attempts failed, give up - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s. giving up", target.c_str()); - GraphUpgradeComplete(asset, OperationResult::Failure, "Failed to move updated file from backup to source destination"); - } - else if (remainingAttempts == 2) - { - // before the final attempt, flush all caches - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); - streamer->SetRequestCompleteCallback(flushRequest - , [this, asset, remainingAttempts, source, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction( - [this, asset, remainingAttempts, source, target]() { PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - else - { - // the actual move attempt - auto moveResult = AZ::IO::SmartMove(source.c_str(), target.c_str()); - if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) - { - m_tmpFileName.clear(); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - // Bump the slice asset up in the asset processor's queue. - AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); - AZ::SystemTickBus::QueueFunction([this, asset]() - { - GraphUpgradeComplete(asset, OperationResult::Success, ""); - }); - } - else - { - AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to source destination failed: %s, trying again", target.c_str()); - auto streamer = AZ::Interface::Get(); - AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); - streamer->SetRequestCompleteCallback(flushRequest, [this, asset, source, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) - { - // Continue saving. - AZ::SystemTickBus::QueueFunction([this, asset, source, target, remainingAttempts]() { PerformMove(asset, source, target, remainingAttempts - 1); }); - }); - streamer->QueueRequest(flushRequest); - } - } - } - - void Controller::GraphUpgradeComplete - (const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - AZStd::lock_guard lock(m_mutex); - m_upgradeComplete = true; - m_upgradeResult = result; - m_upgradeMessage = message; - m_upgradeAsset = asset; - - if (!m_tmpFileName.empty()) - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - AZ_Assert(fileIO, "GraphUpgradeComplete: No FileIO instance"); + const QTextCursor oldCursor = m_view->textEdit->textCursor(); + QScrollBar* scrollBar = m_view->textEdit->verticalScrollBar(); - if (fileIO->Exists(m_tmpFileName.c_str()) && !fileIO->Remove(m_tmpFileName.c_str())) - { - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "Failed to remove temporary file: %s", m_tmpFileName.c_str()); - } - } + m_view->textEdit->moveCursor(QTextCursor::End); + QTextCursor textCursor = m_view->textEdit->textCursor(); - if (m_upgradeResult == OperationResult::Failure) + for (auto& entry : *logs) { - AZ::Interface::Get()->GraphNeedsManualUpgrade(asset.GetId()); + auto line = "\n" + entry; + textCursor.insertText(line.c_str()); } - m_tmpFileName.clear(); - } - - void Controller::GraphUpgradeCompleteUIUpdate - (const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message) - { - QString text = asset.GetHint().c_str(); - QList items = m_view->tableWidget->findItems(text, Qt::MatchFlag::MatchExactly); - - if (!items.isEmpty()) - { - for (auto* item : items) - { - int row = item->row(); - QTableWidgetItem* label = m_view->tableWidget->item(row, ColumnAsset); - QString assetName = asset.GetHint().c_str(); - - if (label->text().compare(assetName) == 0) - { - m_view->tableWidget->removeCellWidget(row, ColumnAction); - m_view->tableWidget->removeCellWidget(row, ColumnStatus); - - QToolButton* doneButton = new QToolButton(this); - doneButton->setToolTip("Upgrade complete"); - if (result == OperationResult::Success) - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); - } - else - { - doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); - doneButton->setToolTip(message.data()); - } - - m_view->tableWidget->setCellWidget(row, ColumnStatus, doneButton); - } - } - } + scrollBar->setValue(scrollBar->maximum()); + m_view->textEdit->moveCursor(QTextCursor::StartOfLine); + LogBus::Broadcast(&LogTraits::Clear); } - void Controller::FinalizeUpgrade() + void Controller::OnCloseButtonPress() { - Log("FinalizeUpgrade!"); - m_inProgress = false; - m_assetsToUpgrade.clear(); - m_view->upgradeAllButton->setEnabled(false); - m_view->onlyShowOutdated->setEnabled(true); - m_keepEditorAlive.reset(); - m_view->progressBar->setVisible(false); - - // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - if (assetsThatNeedManualInspection > 0) - { - m_view->spinner->SetText("Some graphs will require manual corrections, you will be prompted to review them upon closing this dialog"); - } - else - { - m_view->spinner->SetText("Upgrade complete."); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); - AZ::Interface::Get()->SetIsUpgrading(false); - //m_settingsCache.reset(); + reject(); } void Controller::OnScanButtonPress() { auto isUpToDate = [this](AZ::Data::Asset asset) { - Log("InspectAsset: %s", asset.GetHint().c_str()); AZ::Entity* scriptCanvasEntity = nullptr; if (asset.GetType() == azrtti_typeid()) @@ -663,7 +103,11 @@ namespace ScriptCanvasEditor ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); if (!scriptCanvasAsset) { - Log("InspectAsset: %s, AsestData failed to return ScriptCanvasAsset", asset.GetHint().c_str()); + AZ_Warning + ( ScriptCanvas::k_VersionExplorerWindow.data() + , false + , "InspectAsset: %s, AsestData failed to return ScriptCanvasAsset" + , asset.GetHint().c_str()); return true; } @@ -697,8 +141,6 @@ namespace ScriptCanvasEditor void Controller::OnScanComplete(const ScanResult& result) { - Log("Full Scan Complete."); - m_view->onlyShowOutdated->setEnabled(true); // Enable all the Upgrade buttons @@ -724,8 +166,6 @@ namespace ScriptCanvasEditor { m_view->upgradeAllButton->setEnabled(true); } - - m_keepEditorAlive.reset(); } void Controller::OnScanFilteredGraph(const AZ::Data::AssetInfo& info) @@ -746,7 +186,7 @@ namespace ScriptCanvasEditor rowGoToButton->setEnabled(false); AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); spinner->SetBusyIconSize(16); -// +// \\ todo restore this // connect(rowGoToButton, &QPushButton::clicked, [this, rowGoToButton, assetInfo] { // // // request upgrade of a single graph @@ -797,19 +237,18 @@ namespace ScriptCanvasEditor OnScannedGraphResult(assetInfo); } - void Controller::OnScannedGraphResult(const AZ::Data::AssetInfo& info) + void Controller::OnScannedGraphResult([[maybe_unused]] const AZ::Data::AssetInfo& info) { m_view->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); ++m_currentAssetRowIndex; - Log("ScanComplete: %s", info.m_relativePath.c_str()); - FlushLogs(); + AddLogEntries(); } void Controller::OnScanLoadFailure(const AZ::Data::AssetInfo& info) { m_view->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); QTableWidgetItem* rowName = new QTableWidgetItem - (tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str())); + ( tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str())); m_view->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); OnScannedGraphResult(info); } @@ -819,141 +258,92 @@ namespace ScriptCanvasEditor OnScannedGraph(info, Filtered::No); } - void Controller::BackupComplete() - { - m_currentAssetRowIndex = 0; - m_view->progressBar->setValue(0); - } - - void Controller::UpgradeSingle - ( QPushButton* rowGoToButton - , AzQtComponents::StyledBusyLabel* spinner - , AZ::Data::AssetInfo assetInfo) + void Controller::OnUpgradeAllButtonPress() { - AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - (assetInfo.m_assetId, assetInfo.m_assetType, AZ::Data::AssetLoadBehavior::PreLoad); - - if (asset) + auto simpleUpdate = [this](AZ::Data::Asset asset) { - asset.BlockUntilLoadComplete(); - - if (asset.IsReady()) + if (asset.GetType() == azrtti_typeid()) { - AZ::Interface::Get()->SetIsUpgrading(true); - m_isUpgradingSingleGraph = true; - m_logs.clear(); - m_view->textEdit->clear(); - spinner->SetIsBusy(true); - rowGoToButton->setEnabled(false); - - m_inProgressAsset = AZStd::find_if(m_assetsToUpgrade.begin(), m_assetsToUpgrade.end() - , [asset](const UpgradeAssets::value_type& assetToUpgrade) + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" + , azrtti_typeid().template ToString().c_str()); + if (!scriptCanvasAsset) { - return assetToUpgrade.GetId() == asset.GetId(); - }); - - m_state = ProcessState::Upgrade; - AZ::SystemTickBus::Handler::BusConnect(); - } - } - } + return; + } - void Controller::ScanComplete(const AZ::Data::Asset& asset) - { - Log("ScanComplete: %s", asset.GetHint().c_str()); - m_inProgress = false; - m_view->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - m_view->scanButton->setEnabled(true); + AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity"); + if (!scriptCanvasEntity) + { + return; + } - m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); - - if (m_inspectingAsset == m_assetsToInspect.end()) - { - AZ::SystemTickBus::QueueFunction([this]() { FinalizeScan(); }); + AZ::Entity* queryEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); + if (queryEntity) + { + if (queryEntity->GetState() == AZ::Entity::State::Active) + { + queryEntity->Deactivate(); + } - if (!m_assetsToUpgrade.empty()) - { - m_view->upgradeAllButton->setEnabled(true); - } - } - } + scriptCanvasEntity = queryEntity; + } - void Controller::FinalizeScan() - { - Log("FinalizeScan()"); + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) + { + scriptCanvasEntity->Init(); + } - m_view->spinner->SetIsBusy(false); - m_view->onlyShowOutdated->setEnabled(true); + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) + { + scriptCanvasEntity->Activate(); + } - // Enable all the Upgrade buttons - for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) - { - QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction)); - if (button) - { - button->setEnabled(true); + AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + if (graphComponent) + { + graphComponent->UpgradeGraph + ( asset + , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_view->verbose->isChecked()); + } } - } - - QString spinnerText = QStringLiteral("Scan Complete"); - if (m_assetsToUpgrade.empty()) - { - spinnerText.append(" - No graphs require upgrade!"); - } - else - { - spinnerText.append(QString::asprintf(" - Discovered: %zu, Inspected: %zu, Failed: %zu, Upgradeable: %zu" - , m_discoveredAssets, m_inspectedAssets, m_failedAssets, m_assetsToUpgrade.size())); - } - - - m_view->spinner->SetText(spinnerText); - m_view->progressBar->setVisible(false); - - if (!m_assetsToUpgrade.empty()) - { - m_view->upgradeAllButton->setEnabled(true); - } - - AZ::SystemTickBus::Handler::BusDisconnect(); + }; - m_keepEditorAlive.reset(); - //m_settingsCache.reset(); - m_state = ProcessState::Inactive; + ModifyConfiguration config; + config.modification = simpleUpdate; + config.backupGraphBeforeModification = m_view->makeBackupCheckbox->isChecked(); + ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config); } - void Controller::FlushLogs() + void Controller::OnUpgradeAllBegin() { - if (m_logs.empty()) - { - return; - } - - const QTextCursor oldCursor = m_view->textEdit->textCursor(); - QScrollBar* scrollBar = m_view->textEdit->verticalScrollBar(); - - m_view->textEdit->moveCursor(QTextCursor::End); - QTextCursor textCursor = m_view->textEdit->textCursor(); - - while (!m_logs.empty()) - { - auto line = "\n" + m_logs.front(); + m_currentAssetRowIndex = 0; + m_view->tableWidget->setRowCount(0); + m_view->progressBar->setVisible(true); + m_view->progressBar->setValue(0); + m_view->scanButton->setEnabled(false); + m_view->upgradeAllButton->setEnabled(false); + m_view->onlyShowOutdated->setEnabled(false); + } - m_logs.pop_front(); + void Controller::OnUpgradeAllComplete() + { - textCursor.insertText(line.c_str()); - } + } - scrollBar->setValue(scrollBar->maximum()); - m_view->textEdit->moveCursor(QTextCursor::StartOfLine); + void Controller::OnUpgradeAllDependencySortBegin() + { } - void Controller::closeEvent(QCloseEvent* event) + void Controller::OnUpgradeAllDependencySortEnd(const AZStd::vector& sortedAssets) { - m_keepEditorAlive.reset(); - - AzQtComponents::StyledDialog::closeEvent(event); + m_view->progressBar->setRange(0, aznumeric_cast(sortedAssets.size())); } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 85459b4d46..f7a0315730 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -10,12 +10,9 @@ #if !defined(Q_MOC_RUN) #include -#include #include #include #include -#include -#include #include #include #include @@ -40,24 +37,10 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { - //! Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow - //! the upgrade tool to work even if the editor is not in the foreground - class EditorKeepAlive - { - public: - EditorKeepAlive(); - ~EditorKeepAlive(); - - private: - int m_keepEditorActive; - ICVar* m_edKeepEditorActive; - }; - //! A tool that collects and upgrades all Script Canvas graphs in the asset catalog //! Handles display change notifications, handles state change notifications, sends control requests class Controller : public AzQtComponents::StyledDialog - , private AZ::SystemTickBus::Handler , private UpgradeNotifications::Bus::Handler , private ModelNotificationsBus::Handler { @@ -74,104 +57,28 @@ namespace ScriptCanvasEditor static constexpr int ColumnBrowse = 2; static constexpr int ColumnStatus = 3; + AZStd::unique_ptr m_view; + size_t m_currentAssetRowIndex = 0; + + void AddLogEntries(); + void OnCloseButtonPress(); - void OnScanBegin(size_t assetCount) override; void OnScanButtonPress(); + void OnUpgradeAllButtonPress(); + + void OnScanBegin(size_t assetCount) override; void OnScanComplete(const ScanResult& result) override; void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) override; void OnScanLoadFailure(const AZ::Data::AssetInfo& info) override; void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) override; - enum Filtered - { - No, - Yes - }; + enum class Filtered { No, Yes }; void OnScannedGraph(const AZ::Data::AssetInfo& info, Filtered filtered); void OnScannedGraphResult(const AZ::Data::AssetInfo& info); - - - void OnUpgradeAllButtonPress(); - - enum class ProcessState - { - Inactive, - Backup, - Scan, - Upgrade, - }; - ProcessState m_state = ProcessState::Inactive; - - void ScanComplete(const AZ::Data::Asset&); - - // SystemTickBus::Handler - void OnSystemTick() override; - - enum class OperationResult - { - Success, - Failure, - }; - - void GraphUpgradeComplete(const AZ::Data::Asset, OperationResult result, AZStd::string_view message); - - bool IsUpgrading() const { return false; } - - bool m_inProgress = false; - // scan fields - size_t m_currentAssetRowIndex = 0; - size_t m_inspectedAssets = 0; - size_t m_failedAssets = 0; - size_t m_discoveredAssets = 0; - - IUpgradeRequests::AssetList m_assetsToInspect; - IUpgradeRequests::AssetList::iterator m_inspectingAsset; - using UpgradeAssets = AZStd::vector>; - UpgradeAssets m_assetsToUpgrade; - UpgradeAssets::iterator m_inProgressAsset; - - AZ::Data::Asset m_currentAsset; - - AZStd::unique_ptr m_view; - // upgrade fields - AZStd::recursive_mutex m_mutex; - bool m_upgradeComplete = false; - AZ::Data::Asset m_upgradeAsset; - int m_upgradeAssetIndex = 0; - OperationResult m_upgradeResult; - AZStd::string m_upgradeMessage; - AZStd::string m_tmpFileName; - - AZStd::unique_ptr m_keepEditorAlive; - - AZStd::deque m_logs; - - AZ::Entity* m_scriptCanvasEntity = nullptr; - - bool m_isUpgradingSingleGraph = false; - - void UpgradeSingle(QPushButton* item, AzQtComponents::StyledBusyLabel* spinner, AZ::Data::AssetInfo assetInfo); - - void FlushLogs(); - - void FinalizeUpgrade(); - void FinalizeScan(); - - void BackupComplete(); - AZStd::string BackupGraph(const AZ::Data::Asset&); - void UpgradeGraph(const AZ::Data::Asset&); - - void GraphUpgradeCompleteUIUpdate(const AZ::Data::Asset asset, OperationResult result, AZStd::string_view message); - void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) override; - - void OnSourceFileReleased(AZ::Data::Asset asset); - - void closeEvent(QCloseEvent* event) override; - - bool m_overwriteAll = false; - void PerformMove(AZ::Data::Asset asset, AZStd::string source, AZStd::string target, size_t remainingAttempts); - - void Log(const char* format, ...); + void OnUpgradeAllBegin() override; + void OnUpgradeAllComplete() override; + void OnUpgradeAllDependencySortBegin() override; + void OnUpgradeAllDependencySortEnd(const AZStd::vector& sortedAssets) override; }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h new file mode 100644 index 0000000000..c75133f09e --- /dev/null +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +#define VE_LOG(...) LogBus::Broadcast(&LogTraits::Entry, __VA_ARGS__); + +namespace ScriptCanvasEditor +{ + namespace VersionExplorer + { + class LogTraits + : public AZ::EBusTraits + { + public: + virtual void Activate() = 0; + virtual void Clear() = 0; + virtual void Deactivate() = 0; + virtual void Entry(const char* format, ...) = 0; + virtual const AZStd::vector* GetEntries() const = 0; + virtual void SetVersionExporerExclusivity(bool enabled) = 0; + virtual void SetVerbose(bool verbosity) = 0; + }; + using LogBus = AZ::EBus; + } +} diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index 8d5aa62674..ad9d39cb98 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -7,8 +7,11 @@ */ #include -#include +#include #include +#include +#include +#include #include namespace ModifierCpp @@ -20,6 +23,31 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + EditorKeepAlive::EditorKeepAlive() + { + ISystem* system = nullptr; + CrySystemRequestBus::BroadcastResult(system, &CrySystemRequestBus::Events::GetCrySystem); + + if (system) + { + m_edKeepEditorActive = system->GetIConsole()->GetCVar("ed_KeepEditorActive"); + + if (m_edKeepEditorActive) + { + m_keepEditorActive = m_edKeepEditorActive->GetIVal(); + m_edKeepEditorActive->Set(1); + } + } + } + + EditorKeepAlive::~EditorKeepAlive() + { + if (m_edKeepEditorActive) + { + m_edKeepEditorActive->Set(m_keepEditorActive); + } + } + Model::Model() { ModelRequestsBus::Handler::BusConnect(); @@ -33,20 +61,58 @@ namespace ScriptCanvasEditor ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; } - const AZStd::vector* Model::GetLogs() + void Model::Idle() { - return &m_log.GetEntries(); + m_state = State::Idle; + m_keepEditorAlive.reset(); } - + + bool Model::IsReadyToModify() const + { + if (IsWorking()) + { + return false; + } + + if (!m_scanner) + { + return false; + } + + return !m_scanner->GetResult().m_unfiltered.empty(); + } + bool Model::IsWorking() const { return m_state != State::Idle; } + void Model::Modify(const ModifyConfiguration& modification) + { + if (!IsReadyToModify()) + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Explorer is not ready to modify graphs."); + return; + } + + m_state = State::Modifying; + m_keepEditorAlive = AZStd::make_unique(); + auto results = m_scanner->TakeResult(); + m_modifier = AZStd::make_unique(modification, AZStd::move(results.m_unfiltered), [this](){ OnModificationComplete(); }); + } + + void Model::OnModificationComplete() + { + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanComplete, m_scanner->GetResult()); + m_modifier.reset(); + m_scanner.reset(); + Idle(); + } + void Model::OnScanComplete() { ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanComplete, m_scanner->GetResult()); - m_state = State::Idle; + Idle(); } void Model::Scan(const ScanConfiguration& config) @@ -58,6 +124,7 @@ namespace ScriptCanvasEditor } m_state = State::Scanning; + m_keepEditorAlive = AZStd::make_unique(); m_scanner = AZStd::make_unique(config, [this](){ OnScanComplete(); }); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h index 407074fa94..72ab210e37 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h @@ -15,10 +15,25 @@ #include #include +struct ICVar; + namespace ScriptCanvasEditor { namespace VersionExplorer { + //!Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow + //! the upgrade tool to work even if the editor is not in the foreground + class EditorKeepAlive + { + public: + EditorKeepAlive(); + ~EditorKeepAlive(); + + private: + int m_keepEditorActive; + ICVar* m_edKeepEditorActive; + }; + //! Handles model change requests, state queries; sends state change notifications class Model : public ModelRequestsBus::Handler @@ -28,7 +43,8 @@ namespace ScriptCanvasEditor Model(); - const AZStd::vector* GetLogs(); + void Modify(const ModifyConfiguration& modification) override; + void Scan(const ScanConfiguration& config) override; private: @@ -45,9 +61,13 @@ namespace ScriptCanvasEditor AZStd::unique_ptr m_modifier; AZStd::unique_ptr m_scanner; AZStd::unique_ptr m_settingsCache; + AZStd::unique_ptr m_keepEditorAlive; void CacheSettings(); + void Idle(); + bool IsReadyToModify() const; bool IsWorking() const; + void OnModificationComplete(); void OnScanComplete(); void RestoreSettings(); }; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index 11a956c555..d48c15949a 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -14,6 +14,12 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + struct ModifyConfiguration + { + AZStd::function)> modification; + bool backupGraphBeforeModification = false; + }; + struct ScanConfiguration { AZStd::function)> filter; @@ -24,11 +30,16 @@ namespace ScriptCanvasEditor : public AZ::EBusTraits { public: - virtual const AZStd::vector* GetLogs() = 0; + virtual void Modify(const ModifyConfiguration& modification) = 0; virtual void Scan(const ScanConfiguration& filter) = 0; }; using ModelRequestsBus = AZ::EBus; + struct ModificationResult + { + + }; + struct ScanResult { AZStd::vector m_catalogAssets; @@ -46,6 +57,11 @@ namespace ScriptCanvasEditor virtual void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) = 0; virtual void OnScanLoadFailure(const AZ::Data::AssetInfo& info) = 0; virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0; + + virtual void OnUpgradeAllBegin() = 0; + virtual void OnUpgradeAllComplete() = 0; + virtual void OnUpgradeAllDependencySortBegin() = 0; + virtual void OnUpgradeAllDependencySortEnd(const AZStd::vector& sortedAssets) = 0; }; using ModelNotificationsBus = AZ::EBus; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index a0067e1a5f..d782ebd572 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -17,6 +17,19 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + Modifier::Modifier + ( const ModifyConfiguration& modification + , AZStd::vector&& assets + , AZStd::function onComplete) + { + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeAllBegin); + AZ::SystemTickBus::Handler::BusConnect(); + } + + void Modifier::OnSystemTick() + { + + } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index e5a40ff096..d391f51bf7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -9,15 +9,31 @@ #pragma once #include +#include +#include namespace ScriptCanvasEditor { namespace VersionExplorer { class Modifier + : private AZ::SystemTickBus::Handler { public: AZ_CLASS_ALLOCATOR(Modifier, AZ::SystemAllocator, 0); + + Modifier + ( const ModifyConfiguration& modification + , AZStd::vector&& assets + , AZStd::function onComplete); + + private: + size_t m_assetIndex = 0; + AZStd::function m_onComplete; + ModifyConfiguration m_config; + ModifyConfiguration m_result; + + void OnSystemTick() override; }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index 09574883b6..26765a9f97 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -8,11 +8,7 @@ #include #include - -namespace ScannerCpp -{ - -} +#include namespace ScriptCanvasEditor { @@ -42,11 +38,13 @@ namespace ScriptCanvasEditor { if (m_config.filter && m_config.filter(asset)) { + VE_LOG("Scanner: Excluded: %s ", GetCurrentAsset().m_relativePath.c_str()); m_result.m_filteredAssets.push_back(GetCurrentAsset()); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanFilteredGraph, GetCurrentAsset()); } else { + VE_LOG("Scanner: Included: %s ", GetCurrentAsset().m_relativePath.c_str()); m_result.m_unfiltered.push_back(GetCurrentAsset()); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, GetCurrentAsset()); } @@ -69,7 +67,6 @@ namespace ScriptCanvasEditor , azrtti_typeid() , AZ::Data::AssetLoadBehavior::PreLoad); - // Log("Scan: Loading: %s ", m_catalogAssets[m_catalogAssetIndex].GetHint().c_str()); asset.BlockUntilLoadComplete(); if (asset.IsReady()) @@ -86,7 +83,9 @@ namespace ScriptCanvasEditor { if (m_catalogAssetIndex == m_result.m_catalogAssets.size()) { - AZ::SystemTickBus::Handler::BusConnect(); + VE_LOG("Scanner: Complete."); + AZ::SystemTickBus::Handler::BusDisconnect(); + if (m_onComplete) { m_onComplete(); @@ -96,14 +95,17 @@ namespace ScriptCanvasEditor { if (auto asset = LoadAsset()) { + VE_LOG("Scanner: Loaded: %s ", GetCurrentAsset().m_relativePath.c_str()); FilterAsset(asset); } else { + VE_LOG("Scanner: Failed to load: %s ", GetCurrentAsset().m_relativePath.c_str()); m_result.m_loadErrors.push_back(GetCurrentAsset()); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanLoadFailure, GetCurrentAsset()); } + VE_LOG("Scanner: scan of %s complete", GetCurrentAsset().m_relativePath.c_str()); ++m_catalogAssetIndex; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp index be4b619bfd..6f856b9d4c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp @@ -20,20 +20,12 @@ namespace ScriptCanvasEditor void Log::Activate() { AZ::Debug::TraceMessageBus::Handler::BusConnect(); + LogBus::Handler::BusConnect(); } - void Log::AddEntry(const char* format, ...) + void Log::Clear() { - if (m_isVerbose) - { - char sBuffer[2048]; - va_list ArgList; - va_start(ArgList, format); - azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); - sBuffer[sizeof(sBuffer) - 1] = '\0'; - va_end(ArgList); - AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); - } + m_logs.clear(); } bool Log::CaptureFromTraceBus(const char* window, const char* message) @@ -58,9 +50,23 @@ namespace ScriptCanvasEditor AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); } - const AZStd::vector& Log::GetEntries() const + void Log::Entry(const char* format, ...) + { + if (m_isVerbose) + { + char sBuffer[2048]; + va_list ArgList; + va_start(ArgList, format); + azvsnprintf(sBuffer, sizeof(sBuffer), format, ArgList); + sBuffer[sizeof(sBuffer) - 1] = '\0'; + va_end(ArgList); + AZ_TracePrintf(ScriptCanvas::k_VersionExplorerWindow.data(), "%s\n", sBuffer); + } + } + + const AZStd::vector* Log::GetEntries() const { - return m_logs; + return &m_logs; } void Log::SetVersionExporerExclusivity(bool enabled) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h index 1ba8e8c9b1..7399b085da 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h @@ -10,6 +10,7 @@ #include #include +#include namespace ScriptCanvasEditor { @@ -17,16 +18,18 @@ namespace ScriptCanvasEditor { class Log : private AZ::Debug::TraceMessageBus::Handler + , private LogBus::Handler { public: AZ_CLASS_ALLOCATOR(Log, AZ::SystemAllocator, 0); - void Activate(); - void AddEntry(const char* format, ...); + void Activate() override; + void Clear() override; void Deactivate(); - const AZStd::vector& GetEntries() const; - void SetVersionExporerExclusivity(bool enabled); - void SetVerbose(bool verbosity); + void Entry(const char* format, ...) override; + const AZStd::vector* GetEntries() const override; + void SetVersionExporerExclusivity(bool enabled) override; + void SetVerbose(bool verbosity) override; private: bool m_isExclusiveReportingEnabled = false; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h deleted file mode 100644 index cf49072230..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h +++ /dev/null @@ -1,18 +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 - * - */ -#pragma once - -#include - -namespace ScriptCanvasEditor -{ - namespace VersionExplorer - { - - } -} diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 1ce2b0c502..b12c608fe5 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -259,24 +259,24 @@ set(FILES Editor/View/Windows/ScriptCanvasContextMenus.cpp Editor/View/Windows/ScriptCanvasContextMenus.h Editor/View/Windows/ScriptCanvasEditorResources.qrc + Editor/View/Windows/Tools/UpgradeTool/Controller.cpp + Editor/View/Windows/Tools/UpgradeTool/Controller.h + Editor/View/Windows/Tools/UpgradeTool/Controller.ui Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp Editor/View/Windows/Tools/UpgradeTool/FileSaver.h - Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp - Editor/View/Windows/Tools/UpgradeTool/Modifier.h + Editor/View/Windows/Tools/UpgradeTool/LogTraits.h Editor/View/Windows/Tools/UpgradeTool/Model.cpp Editor/View/Windows/Tools/UpgradeTool/Model.h + Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp + Editor/View/Windows/Tools/UpgradeTool/Modifier.h Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp Editor/View/Windows/Tools/UpgradeTool/Scanner.h Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp + Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui - Editor/View/Windows/Tools/UpgradeTool/Controller.cpp - Editor/View/Windows/Tools/UpgradeTool/Controller.h - Editor/View/Windows/Tools/UpgradeTool/View.ui - Editor/View/Windows/Tools/UpgradeTool/ViewTraits.h Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h - Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.h Editor/Framework/ScriptCanvasGraphUtilities.inl Editor/Framework/ScriptCanvasGraphUtilities.h Editor/Framework/ScriptCanvasTraceUtilities.h From f55737af11081c6f6cc588b61df696774dfb9d23 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 14 Sep 2021 08:41:11 -0700 Subject: [PATCH 012/293] dependency sort WIP Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/Controller.cpp | 1 + .../Windows/Tools/UpgradeTool/ModelTraits.h | 2 + .../Windows/Tools/UpgradeTool/Modifier.cpp | 87 ++++++++++++++++++- .../View/Windows/Tools/UpgradeTool/Modifier.h | 19 +++- 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 44d6f2e738..09f0428901 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -94,6 +94,7 @@ namespace ScriptCanvasEditor void Controller::OnScanButtonPress() { + // \todo move to another file auto isUpToDate = [this](AZ::Data::Asset asset) { AZ::Entity* scriptCanvasEntity = nullptr; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index d48c15949a..d01d311ebc 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -18,6 +18,8 @@ namespace ScriptCanvasEditor { AZStd::function)> modification; bool backupGraphBeforeModification = false; + // disabling this can be acceptable, but be careful + bool successfulDependencyUpgradeRequired = true; }; struct ScanConfiguration diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index d782ebd572..9841a9f60e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -7,6 +7,8 @@ */ #include +#include +#include namespace ModifierCpp { @@ -21,15 +23,98 @@ namespace ScriptCanvasEditor ( const ModifyConfiguration& modification , AZStd::vector&& assets , AZStd::function onComplete) + : m_config(modification) + , m_assets(assets) + , m_onComplete(onComplete) { - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeAllBegin); AZ::SystemTickBus::Handler::BusConnect(); } + + const AZ::Data::AssetInfo& Modifier::GetCurrentAsset() const + { + return m_state == State::GatheringDependencies + ? m_assets[m_assetIndex] + : m_assets[m_dependencyOrderedIndicies[m_assetIndex]]; + } + + void Modifier::GatherDependencies() + { + AZ::SerializeContext* serializeContext{}; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + AZ_Assert(serializeContext, "SerializeContext is required to enumerate dependent assets in the ScriptCanvas file"); + + /* + + // AZStd::unordered_multimap jobDependenciesByKey; + auto assetFilter = [this, &jobDependenciesByKey] + ( void* instancePointer + , const AZ::SerializeContext::ClassData* classData + , [[maybe_unused]] const AZ::SerializeContext::ClassElement* classElement) + { + auto azTypeId = classData->m_azRtti->GetTypeId(); + if (azTypeId == azrtti_typeid>()) + { + const auto* subgraphAsset = reinterpret_cast*>(instancePointer); + if (subgraphAsset->GetId().IsValid()) + { + // AssetBuilderSDK::SourceFileDependency dependency; + // dependency.m_sourceFileDependencyUUID = subgraphAsset->GetId().m_guid; + // jobDependenciesByKey.insert({ s_scriptCanvasProcessJobKey, dependency }); + // this->m_processEditorAssetDependencies.push_back + // ({ subgraphAsset->GetId(), azTypeId, AZ::Data::AssetLoadBehavior::PreLoad }); + } + } + // always continue, make note of the script canvas dependencies + return true; + }; + + AZ_Verify(serializeContext->EnumerateInstanceConst + ( sourceGraph->GetGraphData() + , azrtti_typeid() + , assetFilter + , {} + , AZ::SerializeContext::ENUM_ACCESS_FOR_READ + , nullptr + , nullptr), "Failed to gather dependencies from graph data"); + + // Flush asset database events to ensure no asset references are held by closures queued on Ebuses. + AZ::Data::AssetManager::Instance().DispatchEvents(); + */ + } + + AZ::Data::Asset Modifier::LoadAsset() + { + AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset + (GetCurrentAsset().m_assetId + , azrtti_typeid() + , AZ::Data::AssetLoadBehavior::PreLoad); + + asset.BlockUntilLoadComplete(); + + if (asset.IsReady()) + { + return asset; + } + else + { + return {}; + } + } + void Modifier::OnSystemTick() { + switch (m_state) + { + case State::GatheringDependencies: + TickGatherDependencies(); + break; + case State::ModifyingGraphs: + TickUpdateGraph(); + break; + } } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index d391f51bf7..b862de82f0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -28,12 +28,29 @@ namespace ScriptCanvasEditor , AZStd::function onComplete); private: + enum class State + { + GatheringDependencies, + ModifyingGraphs + }; + + State m_state = State::GatheringDependencies; size_t m_assetIndex = 0; AZStd::function m_onComplete; + AZStd::vector m_assets; + AZStd::vector m_dependencyOrderedIndicies; + AZStd::unordered_map> m_dependencies; + AZStd::vector m_failures; ModifyConfiguration m_config; - ModifyConfiguration m_result; + ModificationResult m_result; + void GatherDependencies(); + const AZ::Data::AssetInfo& GetCurrentAsset() const; + AZ::Data::Asset LoadAsset(); + void SortGraphsByDependencies(); void OnSystemTick() override; + void TickGatherDependencies(); + void TickUpdateGraph(); }; } } From 0e2f75492c4ac67fdd475c62729912fb5365d50e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 14 Sep 2021 14:05:15 -0700 Subject: [PATCH 013/293] dependency sort finished, but not tested Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/Controller.cpp | 4 +- .../Windows/Tools/UpgradeTool/Controller.h | 4 +- .../Windows/Tools/UpgradeTool/LogTraits.h | 1 + .../Windows/Tools/UpgradeTool/ModelTraits.h | 4 +- .../Windows/Tools/UpgradeTool/Modifier.cpp | 159 ++++++++++++++++-- .../View/Windows/Tools/UpgradeTool/Modifier.h | 21 ++- 6 files changed, 174 insertions(+), 19 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 09f0428901..8eae0e1bd0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -342,7 +342,9 @@ namespace ScriptCanvasEditor } - void Controller::OnUpgradeAllDependencySortEnd(const AZStd::vector& sortedAssets) + void Controller::OnUpgradeAllDependencySortEnd + ( const AZStd::vector& sortedAssets + , [[maybe_unused]] const AZStd::vector& sortedOrder) { m_view->progressBar->setRange(0, aznumeric_cast(sortedAssets.size())); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index f7a0315730..e2f00fe6f3 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -78,7 +78,9 @@ namespace ScriptCanvasEditor void OnUpgradeAllBegin() override; void OnUpgradeAllComplete() override; void OnUpgradeAllDependencySortBegin() override; - void OnUpgradeAllDependencySortEnd(const AZStd::vector& sortedAssets) override; + void OnUpgradeAllDependencySortEnd + ( const AZStd::vector& sortedAssets + , const AZStd::vector& sortedOrder) override; }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h index c75133f09e..47cebe7324 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/LogTraits.h @@ -8,6 +8,7 @@ #pragma once #include +#include #define VE_LOG(...) LogBus::Broadcast(&LogTraits::Entry, __VA_ARGS__); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index d01d311ebc..09ad2b01c1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -63,7 +63,9 @@ namespace ScriptCanvasEditor virtual void OnUpgradeAllBegin() = 0; virtual void OnUpgradeAllComplete() = 0; virtual void OnUpgradeAllDependencySortBegin() = 0; - virtual void OnUpgradeAllDependencySortEnd(const AZStd::vector& sortedAssets) = 0; + virtual void OnUpgradeAllDependencySortEnd + ( const AZStd::vector& assets + , const AZStd::vector& sortedOrder) = 0; }; using ModelNotificationsBus = AZ::EBus; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 9841a9f60e..1723b0f8ff 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -6,9 +6,11 @@ * */ +#include #include #include #include +#include namespace ModifierCpp { @@ -23,7 +25,8 @@ namespace ScriptCanvasEditor ( const ModifyConfiguration& modification , AZStd::vector&& assets , AZStd::function onComplete) - : m_config(modification) + : m_state(State::GatheringDependencies) + , m_config(modification) , m_assets(assets) , m_onComplete(onComplete) { @@ -31,12 +34,22 @@ namespace ScriptCanvasEditor AZ::SystemTickBus::Handler::BusConnect(); } - const AZ::Data::AssetInfo& Modifier::GetCurrentAsset() const { return m_state == State::GatheringDependencies ? m_assets[m_assetIndex] - : m_assets[m_dependencyOrderedIndicies[m_assetIndex]]; + : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]]; + } + + AZStd::unordered_set& Modifier::GetOrCreateDependencyIndexSet() + { + auto iter = m_dependencies.find(m_assetIndex); + if (iter == m_dependencies.end()) + { + iter = m_dependencies.insert_or_assign(m_assetIndex, AZStd::unordered_set()).first; + } + + return iter->second; } void Modifier::GatherDependencies() @@ -45,10 +58,19 @@ namespace ScriptCanvasEditor AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); AZ_Assert(serializeContext, "SerializeContext is required to enumerate dependent assets in the ScriptCanvas file"); - /* + auto asset = LoadAsset(); + if (!asset + || !asset.GetAs() + || !asset.GetAs()->GetScriptCanvasGraph() + || !asset.GetAs()->GetScriptCanvasGraph()->GetGraphData()) + { + VE_LOG("Modifier: Failed to load asset %s for modification, even though it scanned properly"); + return; + } - // AZStd::unordered_multimap jobDependenciesByKey; - auto assetFilter = [this, &jobDependenciesByKey] + auto graphData = asset.GetAs()->GetScriptCanvasGraph()->GetGraphData(); + + auto dependencyGrabber = [this] ( void* instancePointer , const AZ::SerializeContext::ClassData* classData , [[maybe_unused]] const AZ::SerializeContext::ClassElement* classElement) @@ -59,11 +81,15 @@ namespace ScriptCanvasEditor const auto* subgraphAsset = reinterpret_cast*>(instancePointer); if (subgraphAsset->GetId().IsValid()) { - // AssetBuilderSDK::SourceFileDependency dependency; - // dependency.m_sourceFileDependencyUUID = subgraphAsset->GetId().m_guid; - // jobDependenciesByKey.insert({ s_scriptCanvasProcessJobKey, dependency }); - // this->m_processEditorAssetDependencies.push_back - // ({ subgraphAsset->GetId(), azTypeId, AZ::Data::AssetLoadBehavior::PreLoad }); + if (auto iter = m_assetInfoIndexById.find(subgraphAsset->GetId().m_guid); iter != m_assetInfoIndexById.end()) + { + GetOrCreateDependencyIndexSet().insert(iter->second); + } + else + { + VE_LOG("Modifier: Dependency found that was not picked up by the scanner: %s" + , subgraphAsset->GetId().ToString().c_str()); + } } } // always continue, make note of the script canvas dependencies @@ -71,9 +97,9 @@ namespace ScriptCanvasEditor }; AZ_Verify(serializeContext->EnumerateInstanceConst - ( sourceGraph->GetGraphData() + ( graphData , azrtti_typeid() - , assetFilter + , dependencyGrabber , {} , AZ::SerializeContext::ENUM_ACCESS_FOR_READ , nullptr @@ -81,13 +107,12 @@ namespace ScriptCanvasEditor // Flush asset database events to ensure no asset references are held by closures queued on Ebuses. AZ::Data::AssetManager::Instance().DispatchEvents(); - */ } AZ::Data::Asset Modifier::LoadAsset() { AZ::Data::Asset asset = AZ::Data::AssetManager::Instance().GetAsset - (GetCurrentAsset().m_assetId + ( GetCurrentAsset().m_assetId , azrtti_typeid() , AZ::Data::AssetLoadBehavior::PreLoad); @@ -116,5 +141,109 @@ namespace ScriptCanvasEditor break; } } + + const AZStd::unordered_set* Modifier::Sorter::GetDependencies(size_t index) const + { + auto iter = modifier->m_dependencies.find(index); + return iter != modifier->m_dependencies.end() ? &iter->second : nullptr; + } + + void Modifier::Sorter::Sort() + { + for (size_t index = 0; index != modifier->m_assets.size(); ++index) + { + Visit(index); + } + /* + L ← Empty list that will contain the sorted nodes + (m_dependencyOrderedAssetIndicies) + + while exists nodes without a permanent mark do + select an unmarked node n + visit(n) + */ + } + + void Modifier::Sorter::Visit(size_t index) + { + if (markedPermanent.contains(index)) + { + return; + } + + if (markedTemporary.contains(index)) + { + AZ_Error + ( ScriptCanvas::k_VersionExplorerWindow.data() + , false + , "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s" + , modifier->GetCurrentAsset().m_relativePath.c_str()); + return; + } + + markedTemporary.insert(index); + + if (auto dependencies = GetDependencies(index)) + { + for (auto& dependency : *dependencies) + { + Visit(dependency); + } + } + + markedTemporary.erase(index); + markedPermanent.insert(index); + modifier->m_dependencyOrderedAssetIndicies.push_back(index); + } + + void Modifier::SortGraphsByDependencies() + { + m_dependencyOrderedAssetIndicies.reserve(m_assets.size()); + Sorter sorter; + sorter.modifier = this; + sorter.Sort(); + } + + void Modifier::TickGatherDependencies() + { + if (m_assetIndex == 0) + { + if (m_config.successfulDependencyUpgradeRequired) + { + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeAllDependencySortBegin); + m_assetInfoIndexById.reserve(m_assets.size()); + + for (size_t index = 0; index != m_assets.size(); ++index) + { + m_assetInfoIndexById.insert({ m_assets[index].m_assetId.m_guid, index }); + } + } + else + { + m_dependencyOrderedAssetIndicies.reserve(m_assets.size()); + + for (size_t index = 0; index != m_assets.size(); ++index) + { + m_dependencyOrderedAssetIndicies.push_back(index); + } + } + } + + if (m_assetIndex == m_assets.size()) + { + SortGraphsByDependencies(); + ModelNotificationsBus::Broadcast + ( &ModelNotificationsTraits::OnUpgradeAllDependencySortEnd + , m_assets + , m_dependencyOrderedAssetIndicies); + m_assetIndex = 0; + m_state = State::ModifyingGraphs; + } + else + { + GatherDependencies(); + ++m_assetIndex; + } + } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index b862de82f0..e0b1f1a289 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -28,6 +28,20 @@ namespace ScriptCanvasEditor , AZStd::function onComplete); private: + friend class Sorter; + + struct Sorter + { + Modifier* modifier; + AZStd::unordered_set markedPermanent; + AZStd::unordered_set markedTemporary; + void Sort(); + + private: + void Visit(size_t index); + const AZStd::unordered_set* GetDependencies(size_t index) const; + }; + enum class State { GatheringDependencies, @@ -37,15 +51,20 @@ namespace ScriptCanvasEditor State m_state = State::GatheringDependencies; size_t m_assetIndex = 0; AZStd::function m_onComplete; + // asset infos in scanned order AZStd::vector m_assets; - AZStd::vector m_dependencyOrderedIndicies; + // dependency sorted order indices into the asset vector + AZStd::vector m_dependencyOrderedAssetIndicies; + // dependency indices by asset info index (only exist if graphs have them) AZStd::unordered_map> m_dependencies; + AZStd::unordered_map m_assetInfoIndexById; AZStd::vector m_failures; ModifyConfiguration m_config; ModificationResult m_result; void GatherDependencies(); const AZ::Data::AssetInfo& GetCurrentAsset() const; + AZStd::unordered_set& GetOrCreateDependencyIndexSet(); AZ::Data::Asset LoadAsset(); void SortGraphsByDependencies(); void OnSystemTick() override; From 0dfcc1ea42708d12c4d68103908f83ae3fad523d Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 15 Sep 2021 12:25:06 -0700 Subject: [PATCH 014/293] dependency sort finished, UI updated Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Windows/MainWindow.cpp | 25 +-- .../Windows/Tools/UpgradeTool/Controller.cpp | 186 +++++++++++++++--- .../Windows/Tools/UpgradeTool/Controller.h | 28 ++- .../Windows/Tools/UpgradeTool/ModelTraits.h | 24 ++- .../Windows/Tools/UpgradeTool/Modifier.cpp | 122 +++++++----- 5 files changed, 281 insertions(+), 104 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index 6c10726e13..ee539aa5fa 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -3435,25 +3435,20 @@ namespace ScriptCanvasEditor void MainWindow::RunUpgradeTool() { - // \todo, restore this behavior, post modification step - - /* auto versionExplorer = aznew VersionExplorer::Controller(this); versionExplorer->exec(); - - + // update and fix this // Manual correction - size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); - - // If there are graphs that need manual correction, show the helper - if (assetsThatNeedManualInspection > 0) - { - UpgradeHelper* upgradeHelper = new UpgradeHelper(this); - upgradeHelper->show(); - } - */ - +// size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); +// // If there are graphs that need manual correction, show the helper +// if (assetsThatNeedManualInspection > 0) +// { +// UpgradeHelper* upgradeHelper = new UpgradeHelper(this); +// upgradeHelper->show(); +// } + + delete versionExplorer; } void MainWindow::OnShowValidationErrors() diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 8eae0e1bd0..c8353b1d25 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -54,7 +54,7 @@ namespace ScriptCanvasEditor m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnScanButtonPress); connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnCloseButtonPress); - connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnUpgradeAllButtonPress); + connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnUpgradeButtonPress); m_view->progressBar->setValue(0); m_view->progressBar->setVisible(false); @@ -130,7 +130,7 @@ namespace ScriptCanvasEditor void Controller::OnScanBegin(size_t assetCount) { - m_currentAssetRowIndex = 0; + m_handledAssetCount = 0; m_view->tableWidget->setRowCount(0); m_view->progressBar->setVisible(true); m_view->progressBar->setRange(0, aznumeric_cast(assetCount)); @@ -138,6 +138,10 @@ namespace ScriptCanvasEditor m_view->scanButton->setEnabled(false); m_view->upgradeAllButton->setEnabled(false); m_view->onlyShowOutdated->setEnabled(false); + + QString spinnerText = QStringLiteral("Scan in progress - gathering graphs that can be updated"); + m_view->spinner->SetText(spinnerText); + SetSpinnerIsBusy(true); } void Controller::OnScanComplete(const ScanResult& result) @@ -161,6 +165,7 @@ namespace ScriptCanvasEditor , result.m_filteredAssets.size())); m_view->spinner->SetText(spinnerText); + SetSpinnerIsBusy(false); m_view->progressBar->setVisible(false); if (!result.m_unfiltered.empty()) @@ -176,17 +181,17 @@ namespace ScriptCanvasEditor void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, Filtered filtered) { - m_view->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + m_view->tableWidget->insertRow(m_handledAssetCount); QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); - m_view->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + m_view->tableWidget->setItem(m_handledAssetCount, static_cast(ColumnAsset), rowName); + SetRowSucceeded(m_handledAssetCount); if (filtered == Filtered::No) { QPushButton* rowGoToButton = new QPushButton(this); rowGoToButton->setText("Upgrade"); rowGoToButton->setEnabled(false); - AzQtComponents::StyledBusyLabel* spinner = new AzQtComponents::StyledBusyLabel(this); - spinner->SetBusyIconSize(16); + SetRowBusy(m_handledAssetCount); // \\ todo restore this // connect(rowGoToButton, &QPushButton::clicked, [this, rowGoToButton, assetInfo] { // @@ -200,8 +205,7 @@ namespace ScriptCanvasEditor // // }); - m_view->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnAction), rowGoToButton); - m_view->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnStatus), spinner); + m_view->tableWidget->setCellWidget(m_handledAssetCount, static_cast(ColumnAction), rowGoToButton); } char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; @@ -234,23 +238,24 @@ namespace ScriptCanvasEditor AzQtComponents::ShowFileOnDesktop(absolutePath); }); - m_view->tableWidget->setCellWidget(static_cast(m_currentAssetRowIndex), static_cast(ColumnBrowse), browseButton); + m_view->tableWidget->setCellWidget(m_handledAssetCount, static_cast(ColumnBrowse), browseButton); OnScannedGraphResult(assetInfo); } void Controller::OnScannedGraphResult([[maybe_unused]] const AZ::Data::AssetInfo& info) { - m_view->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); - ++m_currentAssetRowIndex; + m_view->progressBar->setValue(aznumeric_cast(m_handledAssetCount)); + ++m_handledAssetCount; AddLogEntries(); } void Controller::OnScanLoadFailure(const AZ::Data::AssetInfo& info) { - m_view->tableWidget->insertRow(static_cast(m_currentAssetRowIndex)); + m_view->tableWidget->insertRow(m_handledAssetCount); QTableWidgetItem* rowName = new QTableWidgetItem ( tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str())); - m_view->tableWidget->setItem(static_cast(m_currentAssetRowIndex), static_cast(ColumnAsset), rowName); + m_view->tableWidget->setItem(m_handledAssetCount, static_cast(ColumnAsset), rowName); + SetRowFailed(m_handledAssetCount, "Load failed"); OnScannedGraphResult(info); } @@ -259,7 +264,7 @@ namespace ScriptCanvasEditor OnScannedGraph(info, Filtered::No); } - void Controller::OnUpgradeAllButtonPress() + void Controller::OnUpgradeButtonPress() { auto simpleUpdate = [this](AZ::Data::Asset asset) { @@ -321,32 +326,167 @@ namespace ScriptCanvasEditor ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config); } - void Controller::OnUpgradeAllBegin() + void Controller::OnUpgradeBegin + ( const ModifyConfiguration& config + , [[maybe_unused]] const AZStd::vector& assets) { - m_currentAssetRowIndex = 0; - m_view->tableWidget->setRowCount(0); + for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) + { + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) + { + button->setEnabled(false); + SetRowBusy(row); + } + } + + QString spinnerText = QStringLiteral("Upgrade in progress - "); + if (config.modifySingleAsset) + { + spinnerText.append(" single graph"); + } + else + { + spinnerText.append(" all scanned graphs"); + } + + m_view->spinner->SetText(spinnerText); + SetSpinnerIsBusy(true); + } + + void Controller::SetSpinnerIsBusy(bool isBusy) + { + m_view->spinner->SetIsBusy(isBusy); + m_view->spinner->SetBusyIconSize(16); + } + + void Controller::OnUpgradeComplete() + { + SetSpinnerIsBusy(false); + } + + void Controller::OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) + { + QList items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + + if (result == Result::Success) + { + SetRowSucceeded(row); + } + else + { + SetRowFailed(row, ""); + } + } + } + m_view->progressBar->setVisible(true); + ++m_handledAssetCount; + m_view->progressBar->setValue(m_handledAssetCount); + } + + void Controller::OnUpgradeDependencySortBegin + ( [[maybe_unused]] const ModifyConfiguration& config + , const AZStd::vector& assets) + { + m_handledAssetCount = 0; + m_view->progressBar->setVisible(true); + m_view->progressBar->setRange(0, aznumeric_caster(assets.size())); m_view->progressBar->setValue(0); m_view->scanButton->setEnabled(false); m_view->upgradeAllButton->setEnabled(false); m_view->onlyShowOutdated->setEnabled(false); + + for (int row = 0; row != m_view->tableWidget->rowCount(); ++row) + { + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) + { + button->setEnabled(false); + SetRowBusy(row); + } + } + + QString spinnerText = QStringLiteral("Upgrade in progress - gathering dependencies for the scanned graphs"); + m_view->spinner->SetText(spinnerText); + SetSpinnerIsBusy(true); + } + + void Controller::OnUpgradeDependencySortEnd + ( [[maybe_unused]] const ModifyConfiguration& config + , const AZStd::vector& assets + , [[maybe_unused]] const AZStd::vector& sortedOrder) + { + m_handledAssetCount = 0; + m_view->progressBar->setRange(0, aznumeric_caster(assets.size())); + m_view->progressBar->setValue(0); + m_view->progressBar->setVisible(true); + + for (int row = 0; row != m_view->tableWidget->rowCount(); ++row) + { + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) + { + button->setEnabled(false); + SetRowPending(row); + } + } + + QString spinnerText = QStringLiteral("Upgrade in progress - gathering dependencies is complete"); + m_view->spinner->SetText(spinnerText); + SetSpinnerIsBusy(false); } - void Controller::OnUpgradeAllComplete() + void Controller::SetRowBusy(int index) { + if (index >= m_view->tableWidget->rowCount()) + { + return; + } + AzQtComponents::StyledBusyLabel* busy = new AzQtComponents::StyledBusyLabel(this); + busy->SetBusyIconSize(16); + m_view->tableWidget->setCellWidget(index, ColumnStatus, busy); } - void Controller::OnUpgradeAllDependencySortBegin() + void Controller::SetRowFailed(int index, AZStd::string_view message) { + if (index >= m_view->tableWidget->rowCount()) + { + return; + } + QToolButton* doneButton = new QToolButton(this); + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/titlebar-close.svg")); + doneButton->setToolTip(message.data()); + m_view->tableWidget->setCellWidget(index, ColumnStatus, doneButton); } - void Controller::OnUpgradeAllDependencySortEnd - ( const AZStd::vector& sortedAssets - , [[maybe_unused]] const AZStd::vector& sortedOrder) + void Controller::SetRowPending(int index) + { + m_view->tableWidget->removeCellWidget(index, ColumnStatus); + } + + void Controller::SetRowsBusy() + { + for (int i = 0; i != m_view->tableWidget->rowCount(); ++i) + { + SetRowBusy(i); + } + } + + void Controller::SetRowSucceeded(int index) { - m_view->progressBar->setRange(0, aznumeric_cast(sortedAssets.size())); + if (index >= m_view->tableWidget->rowCount()) + { + return; + } + + QToolButton* doneButton = new QToolButton(this); + doneButton->setIcon(QIcon(":/stylesheet/img/UI20/checkmark-menu.svg")); + m_view->tableWidget->setCellWidget(index, ColumnStatus, doneButton); } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index e2f00fe6f3..f99aaf5466 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -58,13 +58,13 @@ namespace ScriptCanvasEditor static constexpr int ColumnStatus = 3; AZStd::unique_ptr m_view; - size_t m_currentAssetRowIndex = 0; + int m_handledAssetCount = 0; void AddLogEntries(); void OnCloseButtonPress(); void OnScanButtonPress(); - void OnUpgradeAllButtonPress(); + void OnUpgradeButtonPress(); void OnScanBegin(size_t assetCount) override; void OnScanComplete(const ScanResult& result) override; @@ -74,13 +74,25 @@ namespace ScriptCanvasEditor enum class Filtered { No, Yes }; void OnScannedGraph(const AZ::Data::AssetInfo& info, Filtered filtered); void OnScannedGraphResult(const AZ::Data::AssetInfo& info); - - void OnUpgradeAllBegin() override; - void OnUpgradeAllComplete() override; - void OnUpgradeAllDependencySortBegin() override; - void OnUpgradeAllDependencySortEnd - ( const AZStd::vector& sortedAssets + + // for single operation UI updates, just check the assets size, or note it on the request + void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) override; + void OnUpgradeComplete() override; + void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) override; + void OnUpgradeDependencySortBegin + ( const ModifyConfiguration& config + , const AZStd::vector& assets) override; + void OnUpgradeDependencySortEnd + ( const ModifyConfiguration& config + , const AZStd::vector& assets , const AZStd::vector& sortedOrder) override; + + void SetSpinnerIsBusy(bool isBusy); + void SetRowBusy(int index); + void SetRowFailed(int index, AZStd::string_view message); + void SetRowPending(int index); + void SetRowsBusy(); + void SetRowSucceeded(int index); }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index 09ad2b01c1..86e1b47b18 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -17,8 +17,8 @@ namespace ScriptCanvasEditor struct ModifyConfiguration { AZStd::function)> modification; + bool modifySingleAsset = false; bool backupGraphBeforeModification = false; - // disabling this can be acceptable, but be careful bool successfulDependencyUpgradeRequired = true; }; @@ -50,6 +50,12 @@ namespace ScriptCanvasEditor AZStd::vector m_loadErrors; }; + enum Result + { + Failure, + Success + }; + class ModelNotificationsTraits : public AZ::EBusTraits { @@ -60,11 +66,17 @@ namespace ScriptCanvasEditor virtual void OnScanLoadFailure(const AZ::Data::AssetInfo& info) = 0; virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0; - virtual void OnUpgradeAllBegin() = 0; - virtual void OnUpgradeAllComplete() = 0; - virtual void OnUpgradeAllDependencySortBegin() = 0; - virtual void OnUpgradeAllDependencySortEnd - ( const AZStd::vector& assets + virtual void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) = 0; + virtual void OnUpgradeComplete() = 0; + // virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config) = 0; + // virtual void OnUpgradeModification(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, Result result) = 0; + virtual void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) = 0; + virtual void OnUpgradeDependencySortBegin + ( const ModifyConfiguration& config + , const AZStd::vector& assets) = 0; + virtual void OnUpgradeDependencySortEnd + ( const ModifyConfiguration& config + , const AZStd::vector& assets , const AZStd::vector& sortedOrder) = 0; }; using ModelNotificationsBus = AZ::EBus; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 1723b0f8ff..5656d6cf6d 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -30,7 +30,7 @@ namespace ScriptCanvasEditor , m_assets(assets) , m_onComplete(onComplete) { - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeAllBegin); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeBegin, modification, m_assets); AZ::SystemTickBus::Handler::BusConnect(); } @@ -58,52 +58,64 @@ namespace ScriptCanvasEditor AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); AZ_Assert(serializeContext, "SerializeContext is required to enumerate dependent assets in the ScriptCanvas file"); + bool anyFailures = false; auto asset = LoadAsset(); - if (!asset - || !asset.GetAs() - || !asset.GetAs()->GetScriptCanvasGraph() - || !asset.GetAs()->GetScriptCanvasGraph()->GetGraphData()) - { - VE_LOG("Modifier: Failed to load asset %s for modification, even though it scanned properly"); - return; - } - auto graphData = asset.GetAs()->GetScriptCanvasGraph()->GetGraphData(); - - auto dependencyGrabber = [this] - ( void* instancePointer - , const AZ::SerializeContext::ClassData* classData - , [[maybe_unused]] const AZ::SerializeContext::ClassElement* classElement) + if (asset + && asset.GetAs() + && asset.GetAs()->GetScriptCanvasGraph() + && asset.GetAs()->GetScriptCanvasGraph()->GetGraphData()) { - auto azTypeId = classData->m_azRtti->GetTypeId(); - if (azTypeId == azrtti_typeid>()) + auto graphData = asset.GetAs()->GetScriptCanvasGraph()->GetGraphData(); + + auto dependencyGrabber = [this] + ( void* instancePointer + , const AZ::SerializeContext::ClassData* classData + , [[maybe_unused]] const AZ::SerializeContext::ClassElement* classElement) { - const auto* subgraphAsset = reinterpret_cast*>(instancePointer); - if (subgraphAsset->GetId().IsValid()) + if (auto azTypeId = classData->m_azRtti->GetTypeId(); + azTypeId == azrtti_typeid>()) { - if (auto iter = m_assetInfoIndexById.find(subgraphAsset->GetId().m_guid); iter != m_assetInfoIndexById.end()) - { - GetOrCreateDependencyIndexSet().insert(iter->second); - } - else + const auto* subgraphAsset = + reinterpret_cast*>(instancePointer); + if (subgraphAsset->GetId().IsValid()) { - VE_LOG("Modifier: Dependency found that was not picked up by the scanner: %s" - , subgraphAsset->GetId().ToString().c_str()); + if (auto iter = m_assetInfoIndexById.find(subgraphAsset->GetId().m_guid); iter != m_assetInfoIndexById.end()) + { + // insert the index of the dependency into the set that belongs to this asset + GetOrCreateDependencyIndexSet().insert(iter->second); + } } } + // always continue, make note of the script canvas dependencies + return true; + }; + + if (!serializeContext->EnumerateInstanceConst + ( graphData + , azrtti_typeid() + , dependencyGrabber + , {} + , AZ::SerializeContext::ENUM_ACCESS_FOR_READ + , nullptr + , nullptr)) + { + anyFailures = true; + VE_LOG("Modifier: ERROR - Failed to gather dependencies from graph data: %s" + , GetCurrentAsset().m_relativePath.c_str()) } - // always continue, make note of the script canvas dependencies - return true; - }; - - AZ_Verify(serializeContext->EnumerateInstanceConst - ( graphData - , azrtti_typeid() - , dependencyGrabber - , {} - , AZ::SerializeContext::ENUM_ACCESS_FOR_READ - , nullptr - , nullptr), "Failed to gather dependencies from graph data"); + } + else + { + anyFailures = true; + VE_LOG("Modifier: ERROR - Failed to load asset %s for modification, even though it scanned properly" + , GetCurrentAsset().m_relativePath.c_str()); + } + + ModelNotificationsBus::Broadcast + ( &ModelNotificationsTraits::OnUpgradeDependenciesGathered + , GetCurrentAsset() + , anyFailures ? Result::Failure : Result::Success); // Flush asset database events to ensure no asset references are held by closures queued on Ebuses. AZ::Data::AssetManager::Instance().DispatchEvents(); @@ -154,14 +166,6 @@ namespace ScriptCanvasEditor { Visit(index); } - /* - L ← Empty list that will contain the sorted nodes - (m_dependencyOrderedAssetIndicies) - - while exists nodes without a permanent mark do - select an unmarked node n - visit(n) - */ } void Modifier::Sorter::Visit(size_t index) @@ -210,7 +214,7 @@ namespace ScriptCanvasEditor { if (m_config.successfulDependencyUpgradeRequired) { - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeAllDependencySortBegin); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeDependencySortBegin, m_config, m_assets); m_assetInfoIndexById.reserve(m_assets.size()); for (size_t index = 0; index != m_assets.size(); ++index) @@ -226,16 +230,24 @@ namespace ScriptCanvasEditor { m_dependencyOrderedAssetIndicies.push_back(index); } + + // go straight into ModifyinGraphs + m_assetIndex = m_assets.size(); } } if (m_assetIndex == m_assets.size()) { - SortGraphsByDependencies(); - ModelNotificationsBus::Broadcast - ( &ModelNotificationsTraits::OnUpgradeAllDependencySortEnd - , m_assets - , m_dependencyOrderedAssetIndicies); + if (m_config.successfulDependencyUpgradeRequired) + { + SortGraphsByDependencies(); + ModelNotificationsBus::Broadcast + ( &ModelNotificationsTraits::OnUpgradeDependencySortEnd + , m_config + , m_assets + , m_dependencyOrderedAssetIndicies); + } + m_assetIndex = 0; m_state = State::ModifyingGraphs; } @@ -245,5 +257,11 @@ namespace ScriptCanvasEditor ++m_assetIndex; } } + + void Modifier::TickUpdateGraph() + { + + } + } } From 296fca722e36aab372ee8f43d545c9ef027d5023 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 15 Sep 2021 15:42:54 -0700 Subject: [PATCH 015/293] file save finished, not tested Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Components/GraphUpgrade.cpp | 2 +- .../ScriptCanvas/Bus/EditorScriptCanvasBus.h | 5 +- .../Widgets/NodePalette/NodePaletteModel.cpp | 4 +- .../Widgets/NodePalette/NodePaletteModel.h | 2 +- .../ScriptCanvasNodePaletteDockWidget.cpp | 4 +- .../ScriptCanvasNodePaletteDockWidget.h | 2 +- .../Code/Editor/View/Windows/MainWindow.h | 6 +- .../Windows/Tools/UpgradeTool/Controller.cpp | 221 ++++++++++++------ .../Windows/Tools/UpgradeTool/Controller.h | 14 +- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 184 +++++++++++++++ .../Windows/Tools/UpgradeTool/FileSaver.h | 25 ++ .../View/Windows/Tools/UpgradeTool/Model.cpp | 2 +- .../View/Windows/Tools/UpgradeTool/Model.h | 3 +- .../Windows/Tools/UpgradeTool/ModelTraits.h | 27 ++- .../Windows/Tools/UpgradeTool/Modifier.cpp | 185 ++++++++++++--- .../View/Windows/Tools/UpgradeTool/Modifier.h | 27 ++- .../View/Windows/Tools/UpgradeTool/Scanner.h | 1 - 17 files changed, 581 insertions(+), 133 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp index e87c82e186..2754cc9777 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp @@ -686,7 +686,7 @@ namespace ScriptCanvasEditor void EditorGraphUpgradeMachine::OnComplete(IState::ExitStatus exitStatus) { - UpgradeNotifications::Bus::Broadcast(&UpgradeNotifications::OnGraphUpgradeComplete, m_asset, exitStatus == IState::ExitStatus::Skipped); + UpgradeNotificationsBus::Broadcast(&UpgradeNotifications::OnGraphUpgradeComplete, m_asset, exitStatus == IState::ExitStatus::Skipped); m_asset = {}; } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index 09869ba2eb..7c47c77b3e 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -236,8 +236,6 @@ namespace ScriptCanvasEditor static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - using Bus = AZ::EBus; - virtual void OnUpgradeStart() {} virtual void OnUpgradeComplete() {} virtual void OnUpgradeCancelled() {} @@ -245,6 +243,5 @@ namespace ScriptCanvasEditor virtual void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) { (void)skipped; } }; - - + using UpgradeNotificationsBus = AZ::EBus; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp index 390dbaf0fb..4602fe5a87 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp @@ -829,12 +829,12 @@ namespace ScriptCanvasEditor NodePaletteModel::NodePaletteModel() : m_paletteId(AZ::Entity::MakeId()) { - UpgradeNotifications::Bus::Handler::BusConnect(); + UpgradeNotificationsBus::Handler::BusConnect(); } NodePaletteModel::~NodePaletteModel() { - UpgradeNotifications::Bus::Handler::BusDisconnect(); + UpgradeNotificationsBus::Handler::BusDisconnect(); DisconnectLambdas(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h index b27bfd97f1..f92ab5142e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h @@ -61,7 +61,7 @@ namespace ScriptCanvasEditor class NodePaletteModel : public GraphCanvas::CategorizerInterface - , UpgradeNotifications::Bus::Handler + , UpgradeNotificationsBus::Handler { public: typedef AZStd::unordered_map< ScriptCanvas::NodeTypeIdentifier, NodePaletteModelInformation* > NodePaletteRegistry; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp index 96b0ac353f..b60b4f2924 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp @@ -148,7 +148,7 @@ namespace ScriptCanvasEditor , m_assetModel(assetModel) , m_categorizer(nodePaletteModel) { - UpgradeNotifications::Bus::Handler::BusConnect(); + UpgradeNotificationsBus::Handler::BusConnect(); if (m_assetModel) { @@ -166,7 +166,7 @@ namespace ScriptCanvasEditor AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); AZ::Data::AssetBus::MultiHandler::BusDisconnect(); - UpgradeNotifications::Bus::Handler::BusDisconnect(); + UpgradeNotificationsBus::Handler::BusDisconnect(); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h index 7b2e9293bd..16beb5b79e 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h @@ -57,7 +57,7 @@ namespace ScriptCanvasEditor : public GraphCanvas::NodePaletteTreeItem , AzFramework::AssetCatalogEventBus::Handler , AZ::Data::AssetBus::MultiHandler - , UpgradeNotifications::Bus::Handler + , UpgradeNotificationsBus::Handler , AZ::SystemTickBus::Handler { public: diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index 1eeb2dadfb..afc413a425 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -98,19 +98,19 @@ namespace ScriptCanvasEditor class ScriptCanvasAssetBrowserModel : public AzToolsFramework::AssetBrowser::AssetBrowserFilterModel - , private UpgradeNotifications::Bus::Handler + , private UpgradeNotificationsBus::Handler { public: explicit ScriptCanvasAssetBrowserModel(QObject* parent = nullptr) : AzToolsFramework::AssetBrowser::AssetBrowserFilterModel(parent) { - UpgradeNotifications::Bus::Handler::BusConnect(); + UpgradeNotificationsBus::Handler::BusConnect(); } ~ScriptCanvasAssetBrowserModel() override { - UpgradeNotifications::Bus::Handler::BusDisconnect(); + UpgradeNotificationsBus::Handler::BusDisconnect(); } void OnUpgradeStart() override diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index c8353b1d25..f3ea605451 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -52,9 +52,9 @@ namespace ScriptCanvasEditor m_view->tableWidget->setColumnWidth(3, 22); m_view->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); - connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnScanButtonPress); - connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnCloseButtonPress); - connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnUpgradeButtonPress); + connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnButtonPressScan); + connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnButtonPressClose); + connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnButtonPressUpgrade); m_view->progressBar->setValue(0); m_view->progressBar->setVisible(false); @@ -87,12 +87,12 @@ namespace ScriptCanvasEditor LogBus::Broadcast(&LogTraits::Clear); } - void Controller::OnCloseButtonPress() + void Controller::OnButtonPressClose() { reject(); } - void Controller::OnScanButtonPress() + void Controller::OnButtonPressScan() { // \todo move to another file auto isUpToDate = [this](AZ::Data::Asset asset) @@ -128,6 +128,148 @@ namespace ScriptCanvasEditor ModelRequestsBus::Broadcast(&ModelRequestsTraits::Scan, config); } + void Controller::OnButtonPressUpgrade() + { + auto simpleUpdate = [this](AZ::Data::Asset asset) + { + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); + AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" + , azrtti_typeid().template ToString().c_str()); + if (!scriptCanvasAsset) + { + return; + } + + AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); + AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity"); + if (!scriptCanvasEntity) + { + return; + } + + AZ::Entity* queryEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); + if (queryEntity) + { + if (queryEntity->GetState() == AZ::Entity::State::Active) + { + queryEntity->Deactivate(); + } + + scriptCanvasEntity = queryEntity; + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) + { + scriptCanvasEntity->Init(); + } + + if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) + { + scriptCanvasEntity->Activate(); + } + + AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); + auto graphComponent = scriptCanvasEntity->FindComponent(); + AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); + if (graphComponent) + { + graphComponent->UpgradeGraph + ( asset + , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate + , m_view->verbose->isChecked()); + } + } + }; + + auto onReadyOnlyFile = [this]()->bool + { + int result = QMessageBox::No; + QMessageBox mb + ( QMessageBox::Warning + , QObject::tr("Failed to Save Upgraded File") + , QObject::tr("The upgraded file could not be saved because the file is read only.\n" + "Do you want to make it writeable and overwrite it?") + , QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No + , this); + result = mb.exec(); + return result == QMessageBox::YesToAll; + }; + + ModifyConfiguration config; + config.modification = simpleUpdate; + config.onReadOnlyFile = onReadyOnlyFile; + config.backupGraphBeforeModification = m_view->makeBackupCheckbox->isChecked(); + ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config); + } + + void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) + { + QList items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + SetRowBusy(row); + } + } + } + + void Controller::OnUpgradeModificationEnd + ( [[maybe_unused]] const ModifyConfiguration& config + , const AZ::Data::AssetInfo& info + , ModificationResult result) + { + if (result.errorMessage.empty()) + { + VE_LOG("Successfully modified %s", result.assetInfo.m_relativePath.c_str()); + } + else + { + VE_LOG("Failed to modify %s: %s", result.assetInfo.m_relativePath.c_str(), result.errorMessage.data()); + } + + QList items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); + if (!items.isEmpty()) + { + for (auto* item : items) + { + int row = item->row(); + + if (result.errorMessage.empty()) + { + SetRowSucceeded(row); + } + else + { + SetRowFailed(row, ""); + } + } + } + + m_view->progressBar->setVisible(true); + ++m_handledAssetCount; + m_view->progressBar->setValue(m_handledAssetCount); + } + + void Controller::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool skipped) + { + ModificationResult result; + result.asset = asset; + AZ::Data::AssetCatalogRequestBus::BroadcastResult + ( result.assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, asset.GetId()); + + if (skipped) + { + result.errorMessage = "Failed in editor upgrade state machine - check logs"; + } + + ModificationNotificationsBus::Broadcast(&ModificationNotificationsTraits::ModificationComplete, result); + } + void Controller::OnScanBegin(size_t assetCount) { m_handledAssetCount = 0; @@ -264,68 +406,6 @@ namespace ScriptCanvasEditor OnScannedGraph(info, Filtered::No); } - void Controller::OnUpgradeButtonPress() - { - auto simpleUpdate = [this](AZ::Data::Asset asset) - { - if (asset.GetType() == azrtti_typeid()) - { - ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs(); - AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s" - , azrtti_typeid().template ToString().c_str()); - if (!scriptCanvasAsset) - { - return; - } - - AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity(); - AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity"); - if (!scriptCanvasEntity) - { - return; - } - - AZ::Entity* queryEntity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId()); - if (queryEntity) - { - if (queryEntity->GetState() == AZ::Entity::State::Active) - { - queryEntity->Deactivate(); - } - - scriptCanvasEntity = queryEntity; - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed) - { - scriptCanvasEntity->Init(); - } - - if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init) - { - scriptCanvasEntity->Activate(); - } - - AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active"); - auto graphComponent = scriptCanvasEntity->FindComponent(); - AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component"); - if (graphComponent) - { - graphComponent->UpgradeGraph - ( asset - , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate - , m_view->verbose->isChecked()); - } - } - }; - - ModifyConfiguration config; - config.modification = simpleUpdate; - config.backupGraphBeforeModification = m_view->makeBackupCheckbox->isChecked(); - ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config); - } - void Controller::OnUpgradeBegin ( const ModifyConfiguration& config , [[maybe_unused]] const AZStd::vector& assets) @@ -359,8 +439,13 @@ namespace ScriptCanvasEditor m_view->spinner->SetBusyIconSize(16); } - void Controller::OnUpgradeComplete() + void Controller::OnUpgradeComplete(const ModificationResults& result) { + QString spinnerText = QStringLiteral("Upgrade Complete - "); + spinnerText.append(QString::asprintf(" - Upgraded: %zu, Failed: %zu" + , result.m_successes.size() + , result.m_failures.size())); + m_view->spinner->SetText(spinnerText); SetSpinnerIsBusy(false); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index f99aaf5466..1b8b109759 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -41,7 +41,7 @@ namespace ScriptCanvasEditor //! Handles display change notifications, handles state change notifications, sends control requests class Controller : public AzQtComponents::StyledDialog - , private UpgradeNotifications::Bus::Handler + , private UpgradeNotificationsBus::Handler , private ModelNotificationsBus::Handler { Q_OBJECT @@ -62,10 +62,12 @@ namespace ScriptCanvasEditor void AddLogEntries(); - void OnCloseButtonPress(); - void OnScanButtonPress(); - void OnUpgradeButtonPress(); + void OnButtonPressClose(); + void OnButtonPressScan(); + void OnButtonPressUpgrade(); + void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped) override; + void OnScanBegin(size_t assetCount) override; void OnScanComplete(const ScanResult& result) override; void OnScanFilteredGraph(const AZ::Data::AssetInfo& info) override; @@ -77,7 +79,7 @@ namespace ScriptCanvasEditor // for single operation UI updates, just check the assets size, or note it on the request void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) override; - void OnUpgradeComplete() override; + void OnUpgradeComplete(const ModificationResults& results) override; void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) override; void OnUpgradeDependencySortBegin ( const ModifyConfiguration& config @@ -86,6 +88,8 @@ namespace ScriptCanvasEditor ( const ModifyConfiguration& config , const AZStd::vector& assets , const AZStd::vector& sortedOrder) override; + void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) override; + void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) override; void SetSpinnerIsBusy(bool isBusy); void SetRowBusy(int index); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index 7a7c4fe5a3..f067feeca4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -6,8 +6,15 @@ * */ +#include +#include #include +#include +#include +#include +#include #include +#include namespace FileSaverCpp { @@ -44,6 +51,183 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + FileSaver::FileSaver + ( AZStd::function onReadOnlyFile + , AZStd::function onComplete) + : m_onReadOnlyFile(onReadOnlyFile) + , m_onComplete(onComplete) + {} + void FileSaver::PerformMove + ( AZStd::string tmpFileName + , AZStd::string target + , size_t remainingAttempts) + { + FileSaverCpp::FileEventHandler fileEventHandler; + + if (remainingAttempts == 0) + { + AZ::SystemTickBus::QueueFunction([this, tmpFileName]() + { + FileSaveResult result; + result.fileSaveError = "Failed to move updated file from temporary location to tmpFileName destination"; + result.tempFileRemovalError = RemoveTempFile(tmpFileName); + m_onComplete(result); + }); + } + else if (remainingAttempts == 2) + { + auto streamer = AZ::Interface::Get(); + // before the last attempt, flush all the caches + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCaches(); + streamer->SetRequestCompleteCallback(flushRequest + , [this, remainingAttempts, tmpFileName, target]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // One last try + AZ::SystemTickBus::QueueFunction( + [this, remainingAttempts, tmpFileName, target]() { PerformMove(tmpFileName, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + else + { + // the actual move attempt + auto moveResult = AZ::IO::SmartMove(tmpFileName.c_str(), target.c_str()); + if (moveResult.GetResultCode() == AZ::IO::ResultCode::Success) + { + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + // Bump the slice asset up in the asset processor's queue. + AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str()); + AZ::SystemTickBus::QueueFunction([this, tmpFileName]() + { + FileSaveResult result; + result.tempFileRemovalError = RemoveTempFile(tmpFileName); + m_onComplete(result); + }); + } + else + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str()); + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str()); + streamer->SetRequestCompleteCallback(flushRequest, [this, tmpFileName, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + // Continue saving. + AZ::SystemTickBus::QueueFunction([this, tmpFileName, target, remainingAttempts]() { PerformMove(tmpFileName, target, remainingAttempts - 1); }); + }); + streamer->QueueRequest(flushRequest); + } + } + } + + void FileSaver::OnSourceFileReleased(AZ::Data::Asset asset) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath); + AZStd::string tmpFileName; + // here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file. + // This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP. + if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName)) + { + FileSaveResult result; + result.fileSaveError = "Failure to create temporary file name"; + m_onComplete(result); + return; + } + + bool tempSavedSucceeded = false; + AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); + if (fileStream.IsOpen()) + { + if (asset.GetType() == azrtti_typeid()) + { + ScriptCanvasEditor::ScriptCanvasAssetHandler handler; + tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream); + } + + fileStream.Close(); + } + + if (!tempSavedSucceeded) + { + FileSaveResult result; + result.fileSaveError = "Save asset data to temporary file failed"; + m_onComplete(result); + return; + } + + AzToolsFramework::SourceControlCommandBus::Broadcast + ( &AzToolsFramework::SourceControlCommandBus::Events::RequestEdit + , fullPath.c_str() + , true + , [this, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info) + { + constexpr const size_t k_maxAttemps = 10; + + if (!info.IsReadOnly()) + { + PerformMove(tmpFileName, fullPath, k_maxAttemps); + } + else if (m_onReadOnlyFile && m_onReadOnlyFile()) + { + AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true); + PerformMove(tmpFileName, fullPath, k_maxAttemps); + } + else + { + FileSaveResult result; + result.fileSaveError = "Source file was and remained read-only"; + result.tempFileRemovalError = RemoveTempFile(tmpFileName); + m_onComplete(result); + } + }); + } + + AZStd::string FileSaver::RemoveTempFile(AZStd::string_view tempFile) + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + if (!fileIO) + { + return "GraphUpgradeComplete: No FileIO instance"; + } + + if (fileIO->Exists(tempFile.data()) && !fileIO->Remove(tempFile.data())) + { + return AZStd::string::format("Failed to remove temporary file: %s", tempFile.data()); + } + + return ""; + } + + void FileSaver::Save(AZ::Data::Asset asset) + { + AZStd::string relativePath, fullPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId()); + bool fullPathFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult + (fullPathFound + , &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath + , relativePath, fullPath); + + if (!fullPathFound) + { + FileSaveResult result; + result.fileSaveError = "Full source path not found"; + m_onComplete(result); + } + else + { + auto streamer = AZ::Interface::Get(); + AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath); + streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request) + { + this->OnSourceFileReleased(asset); + }); + streamer->QueueRequest(flushRequest); + } + } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h index e1ab92acbc..dd333927ed 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.h @@ -14,10 +14,35 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + struct FileSaveResult + { + AZStd::string fileSaveError; + AZStd::string tempFileRemovalError; + }; + class FileSaver { public: AZ_CLASS_ALLOCATOR(FileSaver, AZ::SystemAllocator, 0); + + FileSaver + ( AZStd::function onReadOnlyFile + , AZStd::function onComplete); + + void Save(AZ::Data::Asset asset); + + private: + AZStd::function m_onComplete; + AZStd::function m_onReadOnlyFile; + + void OnSourceFileReleased(AZ::Data::Asset asset); + + void PerformMove + ( AZStd::string source + , AZStd::string target + , size_t remainingAttempts); + + AZStd::string RemoveTempFile(AZStd::string_view tempFile); }; } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index ad9d39cb98..b88d147d6d 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -103,7 +103,7 @@ namespace ScriptCanvasEditor void Model::OnModificationComplete() { - ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanComplete, m_scanner->GetResult()); + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeComplete, m_modifier->GetResult()); m_modifier.reset(); m_scanner.reset(); Idle(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h index 72ab210e37..637c77648a 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h @@ -57,7 +57,8 @@ namespace ScriptCanvasEditor State m_state = State::Idle; Log m_log; - + + // these two are managed by the same class because the modifer will only operate on the results of the scanner AZStd::unique_ptr m_modifier; AZStd::unique_ptr m_scanner; AZStd::unique_ptr m_settingsCache; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index 86e1b47b18..6eedba647f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -17,11 +17,27 @@ namespace ScriptCanvasEditor struct ModifyConfiguration { AZStd::function)> modification; + AZStd::function onReadOnlyFile; bool modifySingleAsset = false; bool backupGraphBeforeModification = false; bool successfulDependencyUpgradeRequired = true; }; + struct ModificationResult + { + AZ::Data::Asset asset; + AZ::Data::AssetInfo assetInfo; + AZStd::string errorMessage; + }; + + class ModificationNotificationsTraits + : public AZ::EBusTraits + { + public: + virtual void ModificationComplete(const ModificationResult& result) = 0; + }; + using ModificationNotificationsBus = AZ::EBus; + struct ScanConfiguration { AZStd::function)> filter; @@ -37,9 +53,10 @@ namespace ScriptCanvasEditor }; using ModelRequestsBus = AZ::EBus; - struct ModificationResult + struct ModificationResults { - + AZStd::vector m_successes; + AZStd::vector m_failures; }; struct ScanResult @@ -67,9 +84,7 @@ namespace ScriptCanvasEditor virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0; virtual void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) = 0; - virtual void OnUpgradeComplete() = 0; - // virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config) = 0; - // virtual void OnUpgradeModification(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, Result result) = 0; + virtual void OnUpgradeComplete(const ModificationResults& results) = 0; virtual void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) = 0; virtual void OnUpgradeDependencySortBegin ( const ModifyConfiguration& config @@ -78,6 +93,8 @@ namespace ScriptCanvasEditor ( const ModifyConfiguration& config , const AZStd::vector& assets , const AZStd::vector& sortedOrder) = 0; + virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) = 0; + virtual void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) = 0; }; using ModelNotificationsBus = AZ::EBus; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 5656d6cf6d..4096508b8b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -30,6 +30,7 @@ namespace ScriptCanvasEditor , m_assets(assets) , m_onComplete(onComplete) { + AZ_Assert(m_config.modification, "No modification function provided"); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeBegin, modification, m_assets); AZ::SystemTickBus::Handler::BusConnect(); } @@ -52,6 +53,11 @@ namespace ScriptCanvasEditor return iter->second; } + const ModificationResults& Modifier::GetResult() const + { + return m_results; + } + void Modifier::GatherDependencies() { AZ::SerializeContext* serializeContext{}; @@ -140,64 +146,105 @@ namespace ScriptCanvasEditor } } - void Modifier::OnSystemTick() + void Modifier::ModificationComplete(const ModificationResult& result) { - switch (m_state) + m_result = result; + + if (result.errorMessage.empty()) { - case State::GatheringDependencies: - TickGatherDependencies(); - break; + SaveModifiedGraph(result); + } + else + { + ReportModificationError(result.errorMessage); + } + } - case State::ModifyingGraphs: - TickUpdateGraph(); - break; + void Modifier::ModifyCurrentAsset() + { + m_result = {}; + m_result.assetInfo = GetCurrentAsset(); + + ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeModificationBegin, m_config, GetCurrentAsset()); + + if (auto asset = LoadAsset()) + { + ModificationNotificationsBus::Handler::BusConnect(); + m_modifyState = ModifyState::InProgress; + m_config.modification(asset); + } + else + { + ReportModificationError("Failed to load during modification"); } } - const AZStd::unordered_set* Modifier::Sorter::GetDependencies(size_t index) const + void Modifier::ModifyNextAsset() { - auto iter = modifier->m_dependencies.find(index); - return iter != modifier->m_dependencies.end() ? &iter->second : nullptr; + ModelNotificationsBus::Broadcast + ( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, GetCurrentAsset(), m_result); + m_modifyState = ModifyState::Idle; + ++m_assetIndex; + m_result = {}; } - void Modifier::Sorter::Sort() + void Modifier::ReportModificationError(AZStd::string_view report) { - for (size_t index = 0; index != modifier->m_assets.size(); ++index) - { - Visit(index); - } + m_result.asset = {}; + m_result.errorMessage = report; + m_results.m_failures.push_back(m_result); + ModifyNextAsset(); } - void Modifier::Sorter::Visit(size_t index) + void Modifier::ReportModificationSuccess() { - if (markedPermanent.contains(index)) + m_results.m_successes.push_back(m_result.assetInfo); + ModifyNextAsset(); + } + + void Modifier::OnFileSaveComplete(const FileSaveResult& result) + { + if (!result.tempFileRemovalError.empty()) { - return; + VE_LOG + ( "Temporary file not removed for %s: %s" + , m_result.assetInfo.m_relativePath.c_str() + , result.tempFileRemovalError.c_str()); } - if (markedTemporary.contains(index)) + m_fileSaver.reset(); + + if (result.fileSaveError.empty()) { - AZ_Error - ( ScriptCanvas::k_VersionExplorerWindow.data() - , false - , "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s" - , modifier->GetCurrentAsset().m_relativePath.c_str()); - return; + ReportModificationSuccess(); } + else + { + ReportModificationError(result.fileSaveError); + } + } - markedTemporary.insert(index); - - if (auto dependencies = GetDependencies(index)) + void Modifier::OnSystemTick() + { + switch (m_state) { - for (auto& dependency : *dependencies) - { - Visit(dependency); - } + case State::GatheringDependencies: + TickGatherDependencies(); + break; + + case State::ModifyingGraphs: + TickUpdateGraph(); + break; } + } - markedTemporary.erase(index); - markedPermanent.insert(index); - modifier->m_dependencyOrderedAssetIndicies.push_back(index); + void Modifier::SaveModifiedGraph(const ModificationResult& result) + { + m_modifyState = ModifyState::Saving; + m_fileSaver = AZStd::make_unique + ( m_config.onReadOnlyFile + , [this](const FileSaveResult& result) { OnFileSaveComplete(result); }); + m_fileSaver->Save(result.asset); } void Modifier::SortGraphsByDependencies() @@ -208,6 +255,11 @@ namespace ScriptCanvasEditor sorter.Sort(); } + ModificationResults&& Modifier::TakeResult() + { + return AZStd::move(m_results); + } + void Modifier::TickGatherDependencies() { if (m_assetIndex == 0) @@ -260,8 +312,69 @@ namespace ScriptCanvasEditor void Modifier::TickUpdateGraph() { + if (m_assetIndex == m_assets.size()) + { + VE_LOG("Modifier: Complete."); + AZ::SystemTickBus::Handler::BusDisconnect(); + + if (m_onComplete) + { + m_onComplete(); + } + } + else + { + if (m_modifyState == ModifyState::Idle) + { + ModifyCurrentAsset(); + } + } + } + + const AZStd::unordered_set* Modifier::Sorter::GetDependencies(size_t index) const + { + auto iter = modifier->m_dependencies.find(index); + return iter != modifier->m_dependencies.end() ? &iter->second : nullptr; + } + void Modifier::Sorter::Sort() + { + for (size_t index = 0; index != modifier->m_assets.size(); ++index) + { + Visit(index); + } } + void Modifier::Sorter::Visit(size_t index) + { + if (markedPermanent.contains(index)) + { + return; + } + + if (markedTemporary.contains(index)) + { + AZ_Error + (ScriptCanvas::k_VersionExplorerWindow.data() + , false + , "Modifier: Dependency sort has failed during, circular dependency detected for Asset: %s" + , modifier->GetCurrentAsset().m_relativePath.c_str()); + return; + } + + markedTemporary.insert(index); + + if (auto dependencies = GetDependencies(index)) + { + for (auto& dependency : *dependencies) + { + Visit(dependency); + } + } + + markedTemporary.erase(index); + markedPermanent.insert(index); + modifier->m_dependencyOrderedAssetIndicies.push_back(index); + } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index e0b1f1a289..f318627cbe 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -8,9 +8,10 @@ #pragma once -#include -#include #include +#include +#include +#include namespace ScriptCanvasEditor { @@ -18,6 +19,7 @@ namespace ScriptCanvasEditor { class Modifier : private AZ::SystemTickBus::Handler + , private ModificationNotificationsBus::Handler { public: AZ_CLASS_ALLOCATOR(Modifier, AZ::SystemAllocator, 0); @@ -27,6 +29,9 @@ namespace ScriptCanvasEditor , AZStd::vector&& assets , AZStd::function onComplete); + const ModificationResults& GetResult() const; + ModificationResults&& TakeResult(); + private: friend class Sorter; @@ -48,7 +53,16 @@ namespace ScriptCanvasEditor ModifyingGraphs }; + enum class ModifyState + { + Idle, + InProgress, + Saving, + }; + + // the two states reside in this class because the modification is only complete if the new source file saves out State m_state = State::GatheringDependencies; + ModifyState m_modifyState = ModifyState::Idle; size_t m_assetIndex = 0; AZStd::function m_onComplete; // asset infos in scanned order @@ -61,12 +75,21 @@ namespace ScriptCanvasEditor AZStd::vector m_failures; ModifyConfiguration m_config; ModificationResult m_result; + ModificationResults m_results; + AZStd::unique_ptr m_fileSaver; void GatherDependencies(); const AZ::Data::AssetInfo& GetCurrentAsset() const; AZStd::unordered_set& GetOrCreateDependencyIndexSet(); AZ::Data::Asset LoadAsset(); + void ModifyCurrentAsset(); + void ModifyNextAsset(); + void ModificationComplete(const ModificationResult& result) override; + void ReportModificationError(AZStd::string_view report); + void ReportModificationSuccess(); + void SaveModifiedGraph(const ModificationResult& result); void SortGraphsByDependencies(); + void OnFileSaveComplete(const FileSaveResult& result); void OnSystemTick() override; void TickGatherDependencies(); void TickUpdateGraph(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h index 8b4dd69c82..fb030845c7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.h @@ -25,7 +25,6 @@ namespace ScriptCanvasEditor Scanner(const ScanConfiguration& config, AZStd::function onComplete); const ScanResult& GetResult() const; - ScanResult&& TakeResult(); private: From 9196e98ee6e2057f3543525fad2a33e7d81cfb30 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 15 Sep 2021 17:03:16 -0700 Subject: [PATCH 016/293] update reporting and logging and make bug fixes Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Components/GraphUpgrade.cpp | 4 +- .../ScriptCanvas/Bus/EditorScriptCanvasBus.h | 14 ---- .../ScriptCanvas/Components/GraphUpgrade.h | 5 ++ .../Code/Editor/View/Windows/MainWindow.cpp | 18 ++--- .../Windows/Tools/UpgradeTool/Controller.cpp | 15 ++-- .../Windows/Tools/UpgradeTool/Controller.h | 11 +-- .../View/Windows/Tools/UpgradeTool/Model.cpp | 9 +++ .../View/Windows/Tools/UpgradeTool/Model.h | 4 + .../Windows/Tools/UpgradeTool/ModelTraits.h | 59 ++++++++------- .../Windows/Tools/UpgradeTool/Modifier.cpp | 9 ++- .../View/Windows/Tools/UpgradeTool/Modifier.h | 4 +- .../Windows/Tools/UpgradeTool/Scanner.cpp | 2 +- .../Tools/UpgradeTool/UpgradeHelper.cpp | 74 ++++++++++--------- 13 files changed, 122 insertions(+), 106 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp index 2754cc9777..0e5f11fa40 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/GraphUpgrade.cpp @@ -519,7 +519,7 @@ namespace ScriptCanvasEditor if (validationResults.HasErrors()) { - AZ::Interface::Get()->GraphNeedsManualUpgrade(sm->m_asset.GetId()); + sm->MarkError("Failed to Parse"); for (auto& err : validationResults.GetEvents()) { @@ -735,7 +735,7 @@ namespace ScriptCanvasEditor { AZ::SystemTickBus::Handler::BusDisconnect(); - OnComplete(exitStatus); + OnComplete(m_error.empty() ? exitStatus : IState::ExitStatus::Skipped); } } diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index 7c47c77b3e..02edce4974 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -215,20 +215,6 @@ namespace ScriptCanvasEditor using EditorLoggingComponentNotificationBus = AZ::EBus; - class IUpgradeRequests - { - public: - AZ_TYPE_INFO(IUpgradeRequests, "{D25318F2-4DDA-4E76-98CB-6D561BB6234D}"); - - using AssetList = AZStd::list; - - virtual void ClearGraphsThatNeedUpgrade() = 0; - virtual void GraphNeedsManualUpgrade(const AZ::Data::AssetId&) = 0; - virtual const AZStd::vector& GetGraphsThatNeedManualUpgrade() const = 0; - virtual bool IsUpgrading() = 0; - virtual void SetIsUpgrading(bool isUpgrading) = 0; - }; - class UpgradeNotifications : public AZ::EBusTraits { diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h index 89ee0f3b55..f67bc11244 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Components/GraphUpgrade.h @@ -133,18 +133,23 @@ namespace ScriptCanvasEditor bool GetVerbose() const; + const AZStd::string GetError() const { return m_error; } + void SetVerbose(bool isVerbose); const AZStd::string& GetDebugPrefix() const; void SetDebugPrefix(AZStd::string_view); + void MarkError(AZStd::string_view error) { m_error = error; } + AZStd::shared_ptr m_currentState = nullptr; AZStd::vector> m_states; private: bool m_isVerbose = true; AZStd::string m_debugPrefix; + AZStd::string m_error; }; //! This state machine will collect and share a variety of data from the EditorGraph diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index ee539aa5fa..4da806f2e8 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -3435,18 +3435,18 @@ namespace ScriptCanvasEditor void MainWindow::RunUpgradeTool() { + using namespace VersionExplorer; auto versionExplorer = aznew VersionExplorer::Controller(this); versionExplorer->exec(); - // update and fix this - // Manual correction -// size_t assetsThatNeedManualInspection = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade().size(); -// // If there are graphs that need manual correction, show the helper -// if (assetsThatNeedManualInspection > 0) -// { -// UpgradeHelper* upgradeHelper = new UpgradeHelper(this); -// upgradeHelper->show(); -// } + const ModificationResults* result = nullptr; + ModelRequestsBus::BroadcastResult(result, &ModelRequestsTraits::GetResults); + if (result && !result->m_failures.empty()) + { + // If there are graphs that need manual correction, show the helper + UpgradeHelper* upgradeHelper = new UpgradeHelper(this); + upgradeHelper->show(); + } delete versionExplorer; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index f3ea605451..9d7224373f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -58,6 +58,7 @@ namespace ScriptCanvasEditor m_view->progressBar->setValue(0); m_view->progressBar->setVisible(false); + UpgradeNotificationsBus::Handler::BusConnect(); ModelNotificationsBus::Handler::BusConnect(); } @@ -78,8 +79,8 @@ namespace ScriptCanvasEditor for (auto& entry : *logs) { - auto line = "\n" + entry; - textCursor.insertText(line.c_str()); + textCursor.insertText("\n"); + textCursor.insertText(entry.c_str()); } scrollBar->setValue(scrollBar->maximum()); @@ -253,6 +254,7 @@ namespace ScriptCanvasEditor m_view->progressBar->setVisible(true); ++m_handledAssetCount; m_view->progressBar->setValue(m_handledAssetCount); + AddLogEntries(); } void Controller::OnGraphUpgradeComplete(AZ::Data::Asset& asset, bool skipped) @@ -408,7 +410,7 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeBegin ( const ModifyConfiguration& config - , [[maybe_unused]] const AZStd::vector& assets) + , [[maybe_unused]] const WorkingAssets& assets) { for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) { @@ -447,6 +449,7 @@ namespace ScriptCanvasEditor , result.m_failures.size())); m_view->spinner->SetText(spinnerText); SetSpinnerIsBusy(false); + AddLogEntries(); } void Controller::OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) @@ -472,11 +475,12 @@ namespace ScriptCanvasEditor m_view->progressBar->setVisible(true); ++m_handledAssetCount; m_view->progressBar->setValue(m_handledAssetCount); + AddLogEntries(); } void Controller::OnUpgradeDependencySortBegin ( [[maybe_unused]] const ModifyConfiguration& config - , const AZStd::vector& assets) + , const WorkingAssets& assets) { m_handledAssetCount = 0; m_view->progressBar->setVisible(true); @@ -502,7 +506,7 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeDependencySortEnd ( [[maybe_unused]] const ModifyConfiguration& config - , const AZStd::vector& assets + , const WorkingAssets& assets , [[maybe_unused]] const AZStd::vector& sortedOrder) { m_handledAssetCount = 0; @@ -522,6 +526,7 @@ namespace ScriptCanvasEditor QString spinnerText = QStringLiteral("Upgrade in progress - gathering dependencies is complete"); m_view->spinner->SetText(spinnerText); SetSpinnerIsBusy(false); + AddLogEntries(); } void Controller::SetRowBusy(int index) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 1b8b109759..0fb3ce1bf4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -50,7 +50,7 @@ namespace ScriptCanvasEditor AZ_CLASS_ALLOCATOR(Controller, AZ::SystemAllocator, 0); explicit Controller(QWidget* parent = nullptr); - + private: static constexpr int ColumnAsset = 0; static constexpr int ColumnAction = 1; @@ -61,7 +61,6 @@ namespace ScriptCanvasEditor int m_handledAssetCount = 0; void AddLogEntries(); - void OnButtonPressClose(); void OnButtonPressScan(); void OnButtonPressUpgrade(); @@ -78,15 +77,13 @@ namespace ScriptCanvasEditor void OnScannedGraphResult(const AZ::Data::AssetInfo& info); // for single operation UI updates, just check the assets size, or note it on the request - void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) override; + void OnUpgradeBegin(const ModifyConfiguration& config, const WorkingAssets& assets) override; void OnUpgradeComplete(const ModificationResults& results) override; void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) override; - void OnUpgradeDependencySortBegin - ( const ModifyConfiguration& config - , const AZStd::vector& assets) override; + void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const WorkingAssets& assets) override; void OnUpgradeDependencySortEnd ( const ModifyConfiguration& config - , const AZStd::vector& assets + , const WorkingAssets& assets , const AZStd::vector& sortedOrder) override; void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) override; void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) override; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index b88d147d6d..ed17293ab7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -61,10 +61,16 @@ namespace ScriptCanvasEditor ScriptCanvas::Grammar::g_saveRawTranslationOuputToFile = false; } + const ModificationResults* Model::GetResults() + { + return !IsWorking() ? &m_modResults : nullptr; + } + void Model::Idle() { m_state = State::Idle; m_keepEditorAlive.reset(); + m_log.Deactivate(); } bool Model::IsReadyToModify() const @@ -95,7 +101,9 @@ namespace ScriptCanvasEditor return; } + m_modResults = {}; m_state = State::Modifying; + m_log.Activate(); m_keepEditorAlive = AZStd::make_unique(); auto results = m_scanner->TakeResult(); m_modifier = AZStd::make_unique(modification, AZStd::move(results.m_unfiltered), [this](){ OnModificationComplete(); }); @@ -124,6 +132,7 @@ namespace ScriptCanvasEditor } m_state = State::Scanning; + m_log.Activate(); m_keepEditorAlive = AZStd::make_unique(); m_scanner = AZStd::make_unique(config, [this](){ OnScanComplete(); }); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h index 637c77648a..e11f8857e7 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h @@ -43,6 +43,8 @@ namespace ScriptCanvasEditor Model(); + const ModificationResults* GetResults() override; + void Modify(const ModifyConfiguration& modification) override; void Scan(const ScanConfiguration& config) override; @@ -64,6 +66,8 @@ namespace ScriptCanvasEditor AZStd::unique_ptr m_settingsCache; AZStd::unique_ptr m_keepEditorAlive; + ModificationResults m_modResults; + void CacheSettings(); void Idle(); bool IsReadyToModify() const; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index 6eedba647f..026748c344 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -14,6 +14,14 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { + struct WorkingAsset + { + AZ::Data::Asset asset; + AZ::Data::AssetInfo info; + }; + + using WorkingAssets = AZStd::vector; + struct ModifyConfiguration { AZStd::function)> modification; @@ -30,13 +38,11 @@ namespace ScriptCanvasEditor AZStd::string errorMessage; }; - class ModificationNotificationsTraits - : public AZ::EBusTraits + struct ModificationResults { - public: - virtual void ModificationComplete(const ModificationResult& result) = 0; + AZStd::vector m_successes; + AZStd::vector m_failures; }; - using ModificationNotificationsBus = AZ::EBus; struct ScanConfiguration { @@ -44,25 +50,10 @@ namespace ScriptCanvasEditor bool reportFilteredGraphs = false; }; - class ModelRequestsTraits - : public AZ::EBusTraits - { - public: - virtual void Modify(const ModifyConfiguration& modification) = 0; - virtual void Scan(const ScanConfiguration& filter) = 0; - }; - using ModelRequestsBus = AZ::EBus; - - struct ModificationResults - { - AZStd::vector m_successes; - AZStd::vector m_failures; - }; - struct ScanResult { AZStd::vector m_catalogAssets; - AZStd::vector m_unfiltered; + WorkingAssets m_unfiltered; AZStd::vector m_filteredAssets; AZStd::vector m_loadErrors; }; @@ -73,6 +64,24 @@ namespace ScriptCanvasEditor Success }; + class ModificationNotificationsTraits + : public AZ::EBusTraits + { + public: + virtual void ModificationComplete(const ModificationResult& result) = 0; + }; + using ModificationNotificationsBus = AZ::EBus; + + class ModelRequestsTraits + : public AZ::EBusTraits + { + public: + virtual const ModificationResults* GetResults() = 0; + virtual void Modify(const ModifyConfiguration& modification) = 0; + virtual void Scan(const ScanConfiguration& filter) = 0; + }; + using ModelRequestsBus = AZ::EBus; + class ModelNotificationsTraits : public AZ::EBusTraits { @@ -83,15 +92,13 @@ namespace ScriptCanvasEditor virtual void OnScanLoadFailure(const AZ::Data::AssetInfo& info) = 0; virtual void OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info) = 0; - virtual void OnUpgradeBegin(const ModifyConfiguration& config, const AZStd::vector& assets) = 0; + virtual void OnUpgradeBegin(const ModifyConfiguration& config, const WorkingAssets& assets) = 0; virtual void OnUpgradeComplete(const ModificationResults& results) = 0; virtual void OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) = 0; - virtual void OnUpgradeDependencySortBegin - ( const ModifyConfiguration& config - , const AZStd::vector& assets) = 0; + virtual void OnUpgradeDependencySortBegin(const ModifyConfiguration& config, const WorkingAssets& assets) = 0; virtual void OnUpgradeDependencySortEnd ( const ModifyConfiguration& config - , const AZStd::vector& assets + , const WorkingAssets& assets , const AZStd::vector& sortedOrder) = 0; virtual void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) = 0; virtual void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) = 0; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 4096508b8b..1bd33bbe49 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -23,7 +23,7 @@ namespace ScriptCanvasEditor { Modifier::Modifier ( const ModifyConfiguration& modification - , AZStd::vector&& assets + , WorkingAssets&& assets , AZStd::function onComplete) : m_state(State::GatheringDependencies) , m_config(modification) @@ -38,8 +38,8 @@ namespace ScriptCanvasEditor const AZ::Data::AssetInfo& Modifier::GetCurrentAsset() const { return m_state == State::GatheringDependencies - ? m_assets[m_assetIndex] - : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]]; + ? m_assets[m_assetIndex].info + : m_assets[m_dependencyOrderedAssetIndicies[m_assetIndex]].info; } AZStd::unordered_set& Modifier::GetOrCreateDependencyIndexSet() @@ -183,6 +183,7 @@ namespace ScriptCanvasEditor { ModelNotificationsBus::Broadcast ( &ModelNotificationsTraits::OnUpgradeModificationEnd, m_config, GetCurrentAsset(), m_result); + ModificationNotificationsBus::Handler::BusDisconnect(); m_modifyState = ModifyState::Idle; ++m_assetIndex; m_result = {}; @@ -271,7 +272,7 @@ namespace ScriptCanvasEditor for (size_t index = 0; index != m_assets.size(); ++index) { - m_assetInfoIndexById.insert({ m_assets[index].m_assetId.m_guid, index }); + m_assetInfoIndexById.insert({ m_assets[index].info.m_assetId.m_guid, index }); } } else diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index f318627cbe..2a8a12e3cf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -26,7 +26,7 @@ namespace ScriptCanvasEditor Modifier ( const ModifyConfiguration& modification - , AZStd::vector&& assets + , WorkingAssets&& assets , AZStd::function onComplete); const ModificationResults& GetResult() const; @@ -66,7 +66,7 @@ namespace ScriptCanvasEditor size_t m_assetIndex = 0; AZStd::function m_onComplete; // asset infos in scanned order - AZStd::vector m_assets; + WorkingAssets m_assets; // dependency sorted order indices into the asset vector AZStd::vector m_dependencyOrderedAssetIndicies; // dependency indices by asset info index (only exist if graphs have them) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp index 26765a9f97..bc69f6e634 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Scanner.cpp @@ -45,7 +45,7 @@ namespace ScriptCanvasEditor else { VE_LOG("Scanner: Included: %s ", GetCurrentAsset().m_relativePath.c_str()); - m_result.m_unfiltered.push_back(GetCurrentAsset()); + m_result.m_unfiltered.push_back({ asset, GetCurrentAsset() }); ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnScanUnFilteredGraph, GetCurrentAsset()); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp index 9670bb2f1f..14bc1c4dc8 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.cpp @@ -6,37 +6,32 @@ * */ +#include +#include #include #include -#include #include -#include #include -#include "UpgradeHelper.h" - #include #include #include #include - #include #include - +#include +#include #include #include #include - -#include - +#include #include +#include +#include #include #include - #include #include -#include -#include namespace ScriptCanvasEditor { @@ -52,40 +47,47 @@ namespace ScriptCanvasEditor m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); int rows = 0; - auto& graphsToUpgrade = AZ::Interface::Get()->GetGraphsThatNeedManualUpgrade(); - for (auto& assetId : graphsToUpgrade) + const VersionExplorer::ModificationResults* result = nullptr; + VersionExplorer::ModelRequestsBus::BroadcastResult(result, &VersionExplorer::ModelRequestsTraits::GetResults); + + if (result && !result->m_failures.empty()) { - auto assetInfo = ScriptCanvasEditor::AssetHelpers::GetAssetInfo(assetId); - m_ui->tableWidget->insertRow(rows); + for (auto& failedUpdate : result->m_failures) + { + auto& assetInfo = failedUpdate.assetInfo; + auto assetId = assetInfo.m_assetId; - connect(m_ui->closeButton, &QPushButton::pressed, this, &QDialog::accept); - connect(m_ui->tableWidget, &QTableWidget::itemDoubleClicked, this, [this, rows, assetId](QTableWidgetItem* item) - { - if (item && item->data(Qt::UserRole).toInt() == rows) + m_ui->tableWidget->insertRow(rows); + + connect(m_ui->closeButton, &QPushButton::pressed, this, &QDialog::accept); + connect(m_ui->tableWidget, &QTableWidget::itemDoubleClicked, this, [this, rows, assetId](QTableWidgetItem* item) { - OpenGraph(assetId); + if (item && item->data(Qt::UserRole).toInt() == rows) + { + OpenGraph(assetId); + } } - } - ); + ); + + auto openGraph = [this, assetId] { + OpenGraph(assetId); + }; - auto openGraph = [this, assetId] { - OpenGraph(assetId); - }; + QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); + rowName->setData(Qt::UserRole, rows); + m_ui->tableWidget->setItem(rows, 0, rowName); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); - rowName->setData(Qt::UserRole, rows); - m_ui->tableWidget->setItem(rows, 0, rowName); + QToolButton* rowGoToButton = new QToolButton(this); + rowGoToButton->setIcon(QIcon(":/stylesheet/img/UI20/open-in-internal-app.svg")); + rowGoToButton->setToolTip("Open Graph"); - QToolButton* rowGoToButton = new QToolButton(this); - rowGoToButton->setIcon(QIcon(":/stylesheet/img/UI20/open-in-internal-app.svg")); - rowGoToButton->setToolTip("Open Graph"); - - connect(rowGoToButton, &QToolButton::clicked, openGraph); + connect(rowGoToButton, &QToolButton::clicked, openGraph); - m_ui->tableWidget->setCellWidget(rows, 1, rowGoToButton); + m_ui->tableWidget->setCellWidget(rows, 1, rowGoToButton); - ++rows; + ++rows; + } } } From 6cd770a9448cfd00274efb3647e70395fc4d40bb Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sun, 19 Sep 2021 12:57:57 -0400 Subject: [PATCH 017/293] Fixed in-editor "Scripting" category components reference links to o3de.org docs Signed-off-by: Pinfel --- .../AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp | 2 +- .../Code/Editor/Components/EditorScriptCanvasComponent.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp index cc350c8107..376cd67e32 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ScriptEditorComponent.cpp @@ -1024,7 +1024,7 @@ namespace AzToolsFramework ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/LuaScript.svg") ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo::Uuid()) ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Script.png") - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/lua-script/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/lua-script/") ->DataElement("AssetRef", &ScriptEditorComponent::m_scriptAsset, "Script", "Which script to use") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &ScriptEditorComponent::ScriptHasChanged) ->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg") diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 2708f95f92..043e034062 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -170,7 +170,7 @@ namespace ScriptCanvasEditor ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0)) ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Level", 0x9aeacc13)) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/script-canvas/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/script-canvas/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_scriptCanvasAssetHolder, "Script Canvas Asset", "Script Canvas asset associated with this component") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorScriptCanvasComponent::m_variableOverrides, "Properties", "Script Canvas Graph Properties") From 890dbbf2e9180983110ac02a8832737e781fefc9 Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sun, 19 Sep 2021 13:01:40 -0400 Subject: [PATCH 018/293] Fixed in-editor "AI" category components reference links to o3de.org docs Signed-off-by: Pinfel --- .../Code/Source/Ai/EditorNavigationAreaComponent.cpp | 2 +- .../Code/Source/Ai/EditorNavigationSeedComponent.cpp | 2 +- Gems/LmbrCentral/Code/Source/Ai/NavigationComponent.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationAreaComponent.cpp b/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationAreaComponent.cpp index 4a290443d0..f723918cf3 100644 --- a/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationAreaComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationAreaComponent.cpp @@ -51,7 +51,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/NavigationArea.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/NavigationArea.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/nav-area/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/ai/nav-area/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::CheckBox, &EditorNavigationAreaComponent::m_exclusion, "Exclusion", "Does this area add or subtract from the Navigation Mesh") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorNavigationAreaComponent::OnNavigationAreaChanged) diff --git a/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationSeedComponent.cpp b/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationSeedComponent.cpp index 975eb17da1..47999dbd4b 100644 --- a/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationSeedComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Ai/EditorNavigationSeedComponent.cpp @@ -36,7 +36,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/NavigationSeed.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/NavigationSeed.svg") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/nav-seed/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/ai/nav-seed/") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorNavigationSeedComponent::m_agentType, "Agent Type", "Describes the type of the Entity for navigation purposes.") ->Attribute(AZ::Edit::Attributes::StringList, &PopulateAgentTypeList) ->Attribute("ChangeNotify", &EditorNavigationSeedComponent::OnAgentTypeChanged); diff --git a/Gems/LmbrCentral/Code/Source/Ai/NavigationComponent.cpp b/Gems/LmbrCentral/Code/Source/Ai/NavigationComponent.cpp index 9897895dcd..500d5c17da 100644 --- a/Gems/LmbrCentral/Code/Source/Ai/NavigationComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Ai/NavigationComponent.cpp @@ -125,7 +125,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Navigation.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/navigation/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/ai/navigation/") ->DataElement(AZ::Edit::UIHandlers::Default, &NavigationComponent::m_agentSpeed, "Agent Speed", "The speed of the agent while navigating ") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &NavigationComponent::m_agentType, "Agent Type", From 1fc8ef44c7da3c54b50fc2071a96f75176a68386 Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sun, 19 Sep 2021 13:07:50 -0400 Subject: [PATCH 019/293] Fixed in-editor "Animation" category components reference links to o3de.org docs Signed-off-by: Pinfel --- .../Code/Source/Animation/EditorAttachmentComponent.cpp | 2 +- .../Integration/Editor/Components/EditorActorComponent.cpp | 2 +- .../Integration/Editor/Components/EditorAnimGraphComponent.cpp | 2 +- .../Editor/Components/EditorSimpleMotionComponent.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp index 878eb51efb..c494b08b22 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Animation/EditorAttachmentComponent.cpp @@ -70,7 +70,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute( AZ::Edit::Attributes::HelpPageURL, - "https://o3de.org/docs/user-guide/components/reference/attachment/") + "https://o3de.org/docs/user-guide/components/reference/animation/attachment/") ->DataElement(0, &EditorAttachmentComponent::m_targetId, "Target entity", "Attach to this entity.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetIdChanged) ->DataElement( diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index ed4edda891..293f9a1015 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -106,7 +106,7 @@ namespace EMotionFX ->Attribute(AZ::Edit::Attributes::ViewportIcon, ":/EMotionFX/Viewport/ActorComponent.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/actor/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/animation/actor/") ->DataElement(0, &EditorActorComponent::m_actorAsset, "Actor asset", "Assigned actor asset") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorActorComponent::OnAssetSelected) diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp index 8721acbf3d..3e5de8237c 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorAnimGraphComponent.cpp @@ -64,7 +64,7 @@ namespace EMotionFX ->Attribute(AZ::Edit::Attributes::ViewportIcon, ":/EMotionFX/Viewport/AnimGraphComponent.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/animgraph/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/animation/animgraph/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorAnimGraphComponent::m_motionSetAsset, "Motion set asset", "EMotion FX motion set asset to be loaded for this actor.") ->Attribute("EditButton", "") diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorSimpleMotionComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorSimpleMotionComponent.cpp index 8446050254..783399c956 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorSimpleMotionComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorSimpleMotionComponent.cpp @@ -46,12 +46,12 @@ namespace EMotionFX ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, azrtti_typeid()) ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Mannequin.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/animation/simple-motion/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &EditorSimpleMotionComponent::m_previewInEditor, "Preview In Editor", "Plays motion in Editor") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorSimpleMotionComponent::OnEditorPropertyChanged) ->DataElement(0, &EditorSimpleMotionComponent::m_configuration, "Configuration", "Settings for this Simple Motion") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorSimpleMotionComponent::OnEditorPropertyChanged) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/simple-motion/") ; } } From 00b5b7ba2d0cfa357ee7386562c4ab28dbefee81 Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sun, 19 Sep 2021 13:15:05 -0400 Subject: [PATCH 020/293] Fixed in-editor "Atom" category components reference links to o3de.org docs Signed-off-by: Pinfel --- .../Code/Source/CoreLights/EditorAreaLightComponent.cpp | 2 +- .../Code/Source/CoreLights/EditorDirectionalLightComponent.cpp | 2 +- .../EditorDiffuseProbeGridComponent.cpp | 1 + .../CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp | 2 +- .../Source/ImageBasedLights/EditorImageBasedLightComponent.cpp | 2 +- .../Code/Source/Material/EditorMaterialComponent.cpp | 2 +- .../CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp | 2 +- .../EditorOcclusionCullingPlaneComponent.cpp | 1 + .../Code/Source/PostProcess/Bloom/EditorBloomComponent.cpp | 2 +- .../PostProcess/DepthOfField/EditorDepthOfFieldComponent.cpp | 2 +- .../PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp | 2 +- .../Code/Source/PostProcess/EditorPostFxLayerComponent.cpp | 2 +- .../ExposureControl/EditorExposureControlComponent.cpp | 2 +- .../EditorGradientWeightModifierComponent.cpp | 2 +- .../LookModification/EditorLookModificationComponent.cpp | 2 +- .../EditorRadiusWeightModifierComponent.cpp | 2 +- .../ShapeWeightModifier/EditorShapeWeightModifierComponent.cpp | 2 +- .../Code/Source/PostProcess/Ssao/EditorSsaoComponent.cpp | 2 +- .../Source/ReflectionProbe/EditorReflectionProbeComponent.cpp | 1 + .../Code/Source/ScreenSpace/EditorDeferredFogComponent.cpp | 2 +- .../Code/Source/Scripting/EditorEntityReferenceComponent.cpp | 2 +- .../Code/Source/SkyBox/EditorHDRiSkyboxComponent.cpp | 2 +- .../Code/Source/SkyBox/EditorPhysicalSkyComponent.cpp | 2 +- 23 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 659c394cba..954ec4cad8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -49,7 +49,7 @@ namespace AZ ->Attribute(Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/AreaLight.svg") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/area-light/") + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/light/") ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp index ef9c73c0b4..2854244f6b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp @@ -44,7 +44,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO][ATOM-1998] create icons. ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [GFX TODO][ATOM-1998] create page + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/directional-light/") // [GFX TODO][ATOM-1998] create page ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp index 013a8ee1b4..8383ac0f17 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp @@ -53,6 +53,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/diffuse-probe-grid/") ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo::Uuid()) ->ClassElement(AZ::Edit::ClassElements::Group, "Probe Spacing") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp index 76f198852e..253f3ddd90 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp @@ -34,7 +34,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/grid/") ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/EditorImageBasedLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/EditorImageBasedLightComponent.cpp index 0547da6240..31eb0d51b1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/EditorImageBasedLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ImageBasedLights/EditorImageBasedLightComponent.cpp @@ -34,7 +34,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/global-skylight-ibl/") ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index c243522257..899dce4feb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -89,7 +89,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/material/") ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo::Uuid()) ->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorMaterialComponent::m_message, "Message", "") ->Attribute(AZ_CRC("PlaceholderText", 0xa23ec278), "Component cannot be edited with multiple entities selected") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp index 3324bdfa8d..c89546264a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.cpp @@ -48,7 +48,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Mesh.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/mesh/") ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo::Uuid()) ->DataElement(AZ::Edit::UIHandlers::Button, &EditorMeshComponent::m_addMaterialComponentFlag, "Add Material Component", "Add Material Component") ->Attribute(AZ::Edit::Attributes::NameLabelOverride, "") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp index 3908aafe89..85eb4a209a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp @@ -37,6 +37,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/occlusion-culling-plane/") ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Bloom/EditorBloomComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Bloom/EditorBloomComponent.cpp index 22c8e2dceb..9018b0860b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Bloom/EditorBloomComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Bloom/EditorBloomComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO ATOM-2672][PostFX] need to create icons for PostProcessing. ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [TODO ATOM-2672][PostFX] need create page for PostProcessing. + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/bloom/") // [TODO ATOM-2672][PostFX] need create page for PostProcessing. ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DepthOfField/EditorDepthOfFieldComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DepthOfField/EditorDepthOfFieldComponent.cpp index b3f77b1b8f..4b9ed8f6af 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DepthOfField/EditorDepthOfFieldComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DepthOfField/EditorDepthOfFieldComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO ATOM-2672][PostFX] need to create icons for PostProcessing.y ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [GFX TODO][ATOM-2672][PostFX] need create page for PostProcessing. + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/depth-of-field/") // [GFX TODO][ATOM-2672][PostFX] need create page for PostProcessing. ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index d06bc981fe..246fbbff5d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -33,7 +33,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO][ATOM-2672][PostFX] need to create icons for PostProcessing. ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector({ AZ_CRC("Level", 0x9aeacc13), AZ_CRC("Game", 0x232b318c) })) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [GFX TODO][ATOM-2672][PostFX] need to create page for PostProcessing. + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/display-mapper/") // [GFX TODO][ATOM-2672][PostFX] need to create page for PostProcessing. ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/EditorPostFxLayerComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/EditorPostFxLayerComponent.cpp index 344c5f8edd..b61cce839e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/EditorPostFxLayerComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/EditorPostFxLayerComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/postfx-layer/") ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ExposureControl/EditorExposureControlComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ExposureControl/EditorExposureControlComponent.cpp index 5bf3e0ec9c..d8bf13dd81 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ExposureControl/EditorExposureControlComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ExposureControl/EditorExposureControlComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO ATOM-2672][PostFX] need to create icons for PostProcessing. ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [TODO ATOM-2672][PostFX] need create page for PostProcessing. + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/exposure-control/") // [TODO ATOM-2672][PostFX] need create page for PostProcessing. ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/EditorGradientWeightModifierComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/EditorGradientWeightModifierComponent.cpp index 86b5ad554a..2f143491f5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/EditorGradientWeightModifierComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/GradientWeightModifier/EditorGradientWeightModifierComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "") + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/postfx-gradient-weight-modifier/") ; editContext->Class("GradientWeightModifierComponentController", "") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/EditorLookModificationComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/EditorLookModificationComponent.cpp index 310762863a..b23ae9805b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/EditorLookModificationComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/LookModification/EditorLookModificationComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO ATOM-2672][PostFX] need to create icons for PostProcessing. ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [TODO ATOM-2672][PostFX] need to create page for PostProcessing. + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/look-modification/") // [TODO ATOM-2672][PostFX] need to create page for PostProcessing. ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp index 219ab6acb9..d4d86d6496 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "") + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/radius-weight-modifier/") ; editContext->Class("RadiusWeightModifierComponentController", "") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/EditorShapeWeightModifierComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/EditorShapeWeightModifierComponent.cpp index 46de0f0c68..842e1a6995 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/EditorShapeWeightModifierComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/ShapeWeightModifier/EditorShapeWeightModifierComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "") + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/postfx-shape-weight-modifier/") ; editContext->Class("ShapeWeightModifierComponentController", "") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Ssao/EditorSsaoComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Ssao/EditorSsaoComponent.cpp index b018ac7a54..43f311a77e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Ssao/EditorSsaoComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/Ssao/EditorSsaoComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO ATOM-2672][PostFX] need to create icons for PostProcessing. ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [GFX TODO][ATOM-2672][PostFX] need create page for PostProcessing. + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/ssao/") // [GFX TODO][ATOM-2672][PostFX] need create page for PostProcessing. ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index 4f4f21ab0f..deb26f869d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -51,6 +51,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/reflection-probe/") ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo::Uuid()) ->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap Bake") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ScreenSpace/EditorDeferredFogComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ScreenSpace/EditorDeferredFogComponent.cpp index 208747abaa..139c24a959 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ScreenSpace/EditorDeferredFogComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ScreenSpace/EditorDeferredFogComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") // [GFX TODO ATOM-2672][PostFX] need to create icons for PostProcessing. ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "https://") // [TODO][ATOM-13427] Create Wiki for Deferred Fog + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/deferred-fog/") // [TODO][ATOM-13427] Create Wiki for Deferred Fog ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Scripting/EditorEntityReferenceComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Scripting/EditorEntityReferenceComponent.cpp index 65491a9833..e297b7cc12 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Scripting/EditorEntityReferenceComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Scripting/EditorEntityReferenceComponent.cpp @@ -31,7 +31,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->Attribute(Edit::Attributes::HelpPageURL, "") + ->Attribute(Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/entity-reference/") ; editContext->Class("EntityReferenceComponentController", "") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorHDRiSkyboxComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorHDRiSkyboxComponent.cpp index a0ffb4e509..1cf14cca71 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorHDRiSkyboxComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorHDRiSkyboxComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/hdri-skybox/") ; editContext->Class( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorPhysicalSkyComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorPhysicalSkyComponent.cpp index 28cb4121cf..81b182ccaa 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorPhysicalSkyComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/EditorPhysicalSkyComponent.cpp @@ -32,7 +32,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/atom/physical-sky/") ; editContext->Class( From 83616242c7ce2650e1feb6cad88009d9948a9d56 Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sun, 19 Sep 2021 13:15:55 -0400 Subject: [PATCH 021/293] Fixed in-editor "Camera" category components reference links to o3de.org docs Signed-off-by: Pinfel --- Gems/Camera/Code/Source/EditorCameraComponent.cpp | 2 +- Gems/CameraFramework/Code/Source/CameraRigComponent.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Camera/Code/Source/EditorCameraComponent.cpp b/Gems/Camera/Code/Source/EditorCameraComponent.cpp index 4ebec334ec..0a922b4c4c 100644 --- a/Gems/Camera/Code/Source/EditorCameraComponent.cpp +++ b/Gems/Camera/Code/Source/EditorCameraComponent.cpp @@ -95,7 +95,7 @@ namespace Camera ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/Camera.svg") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/camera/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/camera/camera/") ->UIElement(AZ::Edit::UIHandlers::Button,"", "Sets the view to this camera") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCameraComponent::OnPossessCameraButtonClicked) ->Attribute(AZ::Edit::Attributes::ButtonText, &EditorCameraComponent::GetCameraViewButtonText) diff --git a/Gems/CameraFramework/Code/Source/CameraRigComponent.cpp b/Gems/CameraFramework/Code/Source/CameraRigComponent.cpp index e8df095ed0..12c1e5861b 100644 --- a/Gems/CameraFramework/Code/Source/CameraRigComponent.cpp +++ b/Gems/CameraFramework/Code/Source/CameraRigComponent.cpp @@ -126,7 +126,7 @@ namespace Camera ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/CameraRig.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/CameraRig.png") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/camera-rig/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/camera/camera-rig/") ->DataElement(0, &CameraRigComponent::m_targetAcquirers, "Target acquirers", "A list of behaviors that define how a camera will select a target. They are executed in order until one succeeds") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) From 9b29ea7ae24ac1b58ad6f3bdfcbe8e49c774ca75 Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sun, 19 Sep 2021 13:16:26 -0400 Subject: [PATCH 022/293] Fixed in-editor "Editor" category components reference links to o3de.org docs Signed-off-by: Pinfel --- Gems/LmbrCentral/Code/Source/Editor/EditorCommentComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/LmbrCentral/Code/Source/Editor/EditorCommentComponent.cpp b/Gems/LmbrCentral/Code/Source/Editor/EditorCommentComponent.cpp index 97f8dc60a2..6c929bd3c4 100644 --- a/Gems/LmbrCentral/Code/Source/Editor/EditorCommentComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Editor/EditorCommentComponent.cpp @@ -33,7 +33,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Comment.svg") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector({ AZ_CRC("Level", 0x9aeacc13), AZ_CRC("Game", 0x232b318c), AZ_CRC("Layer", 0xe4db211a) })) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/comment/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/editor/comment/") ->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorCommentComponent::m_comment,"", "Comment") ->Attribute(AZ_CRC("PlaceholderText", 0xa23ec278), "Add comment text here"); } From c2a3351676dd24bbbe8b907480adfab408f3fe72 Mon Sep 17 00:00:00 2001 From: Pinfel Date: Sun, 19 Sep 2021 13:19:17 -0400 Subject: [PATCH 023/293] Fixed in-editor "Gameplay" category components reference links to o3de.org docs Signed-off-by: Pinfel --- Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp | 2 +- Gems/LmbrCentral/Code/Source/Scripting/SimpleStateComponent.cpp | 2 +- .../Code/Source/InputConfigurationComponent.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp b/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp index fa98601a11..90fc0db437 100644 --- a/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Scripting/EditorTagComponent.cpp @@ -38,7 +38,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Tag.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Tag.svg") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/tag/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/gameplay/tag/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorTagComponent::m_tags, "Tags", "The tags that will be on this entity by default") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorTagComponent::OnTagChanged); } diff --git a/Gems/LmbrCentral/Code/Source/Scripting/SimpleStateComponent.cpp b/Gems/LmbrCentral/Code/Source/Scripting/SimpleStateComponent.cpp index e278f18e8b..29c97cdde1 100644 --- a/Gems/LmbrCentral/Code/Source/Scripting/SimpleStateComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Scripting/SimpleStateComponent.cpp @@ -204,7 +204,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/SimpleState.svg") ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/SimpleState.svg") - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/simple-state/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/gameplay/simple-state/") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SimpleStateComponent::m_initialStateName, "Initial state", "The initial active state") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ_CRC("RefreshAttributesAndValues", 0xcbc2147c)) ->Attribute(AZ::Edit::Attributes::StringList, &SimpleStateComponent::GetStateNames) diff --git a/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp b/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp index 42fa05473c..b2a1251662 100644 --- a/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp +++ b/Gems/StartingPointInput/Code/Source/InputConfigurationComponent.cpp @@ -55,7 +55,7 @@ namespace StartingPointInput ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/InputConfig.svg") ->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo::Uuid()) ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game")) - ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/input/") + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/gameplay/input/") ->DataElement(AZ::Edit::UIHandlers::Default, &InputConfigurationComponent::m_inputEventBindingsAsset, "Input to event bindings", "Asset containing input to event binding information.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) From e125462eaaaadbd9c0762784100b52bfef8935c2 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 24 Sep 2021 11:56:42 -0700 Subject: [PATCH 024/293] Set logging preference before running tools Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Editor/View/Windows/Tools/UpgradeTool/Controller.cpp | 8 ++++++++ .../Editor/View/Windows/Tools/UpgradeTool/Controller.h | 1 + .../Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp | 3 +++ 3 files changed, 12 insertions(+) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 9d7224373f..4e4e842cb8 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -126,6 +126,7 @@ namespace ScriptCanvasEditor config.reportFilteredGraphs = !m_view->onlyShowOutdated->isChecked(); config.filter = isUpToDate; + SetLoggingPreferences(); ModelRequestsBus::Broadcast(&ModelRequestsTraits::Scan, config); } @@ -199,6 +200,7 @@ namespace ScriptCanvasEditor return result == QMessageBox::YesToAll; }; + SetLoggingPreferences(); ModifyConfiguration config; config.modification = simpleUpdate; config.onReadOnlyFile = onReadyOnlyFile; @@ -435,6 +437,12 @@ namespace ScriptCanvasEditor SetSpinnerIsBusy(true); } + void Controller::SetLoggingPreferences() + { + LogBus::Broadcast(&LogTraits::SetVerbose, m_view->verbose->isChecked()); + LogBus::Broadcast(&LogTraits::SetVersionExporerExclusivity, m_view->updateReportingOnly->isChecked()); + } + void Controller::SetSpinnerIsBusy(bool isBusy) { m_view->spinner->SetIsBusy(isBusy); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 0fb3ce1bf4..fd297832bb 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -88,6 +88,7 @@ namespace ScriptCanvasEditor void OnUpgradeModificationBegin(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) override; void OnUpgradeModificationEnd(const ModifyConfiguration& config, const AZ::Data::AssetInfo& info, ModificationResult result) override; + void SetLoggingPreferences(); void SetSpinnerIsBusy(bool isBusy); void SetRowBusy(int index); void SetRowFailed(int index, AZStd::string_view message); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 1bd33bbe49..3c62670ef0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -237,6 +237,9 @@ namespace ScriptCanvasEditor TickUpdateGraph(); break; } + + AZ::Data::AssetManager::Instance().DispatchEvents(); + AZ::SystemTickBus::ExecuteQueuedEvents(); } void Modifier::SaveModifiedGraph(const ModificationResult& result) From 619948231a9f67f7b687a89bdce80fc4154f9dbb Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 30 Sep 2021 14:26:27 -0700 Subject: [PATCH 025/293] fix compile error from bad automatic merge Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvas/Code/Editor/SystemComponent.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h index 0b085a7e8d..6f85b3c5a6 100644 --- a/Gems/ScriptCanvas/Code/Editor/SystemComponent.h +++ b/Gems/ScriptCanvas/Code/Editor/SystemComponent.h @@ -97,8 +97,7 @@ namespace ScriptCanvasEditor //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// - void ClearGraphsThatNeedUpgrade() - + private: SystemComponent(const SystemComponent&) = delete; From 2185505302e7a80dbb0c441a44d7df487711b98e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 30 Sep 2021 14:59:11 -0700 Subject: [PATCH 026/293] Repair upgrade notification after bad automatic merge Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h | 1 - .../Editor/View/Widgets/NodePalette/NodePaletteModel.h | 4 ---- .../View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp | 9 --------- .../View/Widgets/ScriptCanvasNodePaletteDockWidget.h | 1 - Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h | 5 ----- 5 files changed, 20 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h index 02edce4974..7e7b600081 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h @@ -223,7 +223,6 @@ namespace ScriptCanvasEditor static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; virtual void OnUpgradeStart() {} - virtual void OnUpgradeComplete() {} virtual void OnUpgradeCancelled() {} virtual void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped = false) { (void)skipped; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h index f92ab5142e..28d627af01 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.h @@ -104,10 +104,6 @@ namespace ScriptCanvasEditor { DisconnectLambdas(); } - void OnUpgradeComplete() override - { - ConnectLambdas(); - } // Asset Node Support void OnRowsInserted(const QModelIndex& parentIndex, int first, int last); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp index b60b4f2924..9e51c1896f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp @@ -386,15 +386,6 @@ namespace ScriptCanvasEditor AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } - void ScriptCanvasRootPaletteTreeItem::OnUpgradeComplete() - { - ConnectLambdas(); - - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - - TraverseTree(); - } - void ScriptCanvasRootPaletteTreeItem::OnUpgradeCancelled() { if (!AzFramework::AssetCatalogEventBus::Handler::BusIsConnected()) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h index 16beb5b79e..45645ceb33 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h @@ -92,7 +92,6 @@ namespace ScriptCanvasEditor // UpgradeNotifications::Bus void OnUpgradeStart() override; - void OnUpgradeComplete() override; void OnUpgradeCancelled() override; //// diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index f8703cc5c5..244d9dcd72 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -117,11 +117,6 @@ namespace ScriptCanvasEditor { AzToolsFramework::AssetBrowser::AssetBrowserComponentNotificationBus::Handler::BusDisconnect(); } - - void OnUpgradeComplete() override - { - AzToolsFramework::AssetBrowser::AssetBrowserComponentNotificationBus::Handler::BusConnect(); - } }; class OnSaveToast From 779edb7fe5fd54ab67c1acb2439522a5c13eded4 Mon Sep 17 00:00:00 2001 From: kritin Date: Thu, 30 Sep 2021 16:43:15 -0700 Subject: [PATCH 027/293] Sample Editor test for QA Automation project Signed-off-by: kritin --- .../EditorScripts/Sample_Editor_Tests.py | 143 ++++++++++++++++++ .../editor/TestSuite_Main_Optimized.py | 3 + 2 files changed, 146 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py new file mode 100644 index 0000000000..746c0a936d --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py @@ -0,0 +1,143 @@ +""" +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 + +Test Case: Creating tests for basic editor feature like creating a level, adding new entities, modifying the entities etc. +""" + + +class Tests: + create_level = ("Level created and loaded successfully", "Failed to create the level") + open_level = ("Level loaded successfully", "Failed to load the level") + create_entity = ("Parent entity created successfully", "Failed to create a parent entity") + set_entity_name = ("Entity name set successfully", "Failed to set entity name") + delete_entity = ("Parent entity deleted successfully", "Failed to delete parent entity") + game_mode_enter = ("Game Mode entered successfully", "Failed to enter the game mode") + game_mode_exit = ("Game mode exited successfully", "Failed to exit game mode") + create_child_entity = ("Child entity created successfully", "Failed to create a child entity") + delete_child_entity = ("Child entity deleted successfully", "Failed to delete child entity") + add_mesh_component = ("Mesh component added successfully", "Failed to add mesh component") + found_component_typeId = ("Found component typeId", "Unable to find component TypeId") + remove_mesh_component = ("Mesh component removed successfully", "Failed to remove mesh component") + + +def sample_editor_tests(): + """ + Performing basic test in editor + 01. create_level if it does not exist else 02. open exiting level + + 03. create parent entity and set name + 04. create child entity + 05. delete child entity + 06. add mesh component + 07. remove mesh component + 08. enter game mode + 09. exit game_mode + 10. delete parent entity + 11. save level + + """ + import os + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + import editor_python_test_tools.hydra_editor_utils as hydra + + import azlmbr.math as math + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.object + + def search_entity(entity_to_search, entity_name): + """ + + :param entity_to_search: entity to be searched + :param entity_name: name of the entity used in the set command + :return: True if entity id exists in the entity_list + False if entity id does not exist in the entity_list + """ + entity_list = [] + entity_search_filter = entity.SearchFilter() + entity_search_filter.names = entity_name + entity_list = entity.SearchBus(bus.Broadcast, 'SearchEntities', entity_search_filter) + if entity_list: + if entity_to_search in entity_list: + return True + return False + return False + + # 01. create_level + + test_level = 'Simple' + general.open_level_no_prompt(test_level) + Report.result(Tests.create_level, general.get_current_level_name() == test_level) + + # 02. load existing level - skipping this since this could alter existing level that other test depends on + + # 03. create_entity and set name + # Delete any exiting entity and Create a new Entity at the root level + search_filter = azlmbr.entity.SearchFilter() + all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) + editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) + parent_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", entity.EntityId()) + Report.result(Tests.create_entity, parent_entity.IsValid()) + + # Setting a new name + parent_entity_name = "Parent_1" + editor.EditorEntityAPIBus(bus.Event, 'SetName', parent_entity, parent_entity_name) + Report.result(Tests.set_entity_name, + editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', parent_entity) == parent_entity_name) + + # 04. Creating child Entity and setting name to above created parent entity + child_1_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', parent_entity) + Report.result(Tests.create_child_entity, child_1_entity.IsValid()) + child_entity_name = "Child_1" + editor.EditorEntityAPIBus(bus.Event, 'SetName', child_1_entity, child_entity_name) + Report.result(Tests.set_entity_name, + editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', child_1_entity) == child_entity_name) + + # 05. delete_Child_entity + editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', child_1_entity) + Report.result(Tests.delete_entity, search_entity(child_1_entity, "Child_1") == False) + + # 06. add mesh component to parent entity + type_id_list = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Mesh"], + entity.EntityType().Game) + if type_id_list is not None: + component_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', parent_entity, + type_id_list) + Report.result(Tests.add_mesh_component, component_outcome.IsSuccess()) + else: + Report.result(Tests.found_component_typeId, type_id_list is not None) + + # 09. remove mesh component + outcome_get_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', parent_entity, + type_id_list[0]) + if outcome_get_component.IsSuccess(): + component_entity_pair = outcome_get_component.GetValue() + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component_entity_pair]) + component_exists = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', parent_entity, + type_id_list[0]) + mesh_test = True + if component_exists: + mesh_test = False + Report.result(Tests.remove_mesh_component, mesh_test) + else: + Report.result(Tests.found_component_typeId, outcome_get_component.IsSuccess()) + + # 10. delete parent entity + editor.ToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'DeleteEntityById', parent_entity) + Report.result(Tests.delete_entity, search_entity(parent_entity, "Parent_1") == False) + + # Close editor without saving + editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt') + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + + Report.start_test(sample_editor_tests) diff --git a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py index 9c0b99daff..9aef8a8b2c 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py @@ -73,3 +73,6 @@ class TestAutomationAutoTestMode(EditorTestSuite): @pytest.mark.skip(reason="Times out due to dialogs failing to dismiss: LYN-4208") class test_Menus_FileMenuOptions_Work(EditorSharedTest): from .EditorScripts import Menus_FileMenuOptions as test_module + + class test_Sample_Editor_Tests(EditorSharedTest): + from .EditorScripts import Sample_Editor_Tests as test_module \ No newline at end of file From 1245c2361d769bd777255400660caff958a151af Mon Sep 17 00:00:00 2001 From: Mike Cronin <58789750+micronAMZN@users.noreply.github.com> Date: Fri, 1 Oct 2021 16:06:11 -0700 Subject: [PATCH 028/293] Updated documentation_url field. This doc is being moved per: https://github.com/o3de/o3de.org/pull/993 Signed-off-by: Mike Cronin <58789750+micronAMZN@users.noreply.github.com> --- Gems/LmbrCentral/gem.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/LmbrCentral/gem.json b/Gems/LmbrCentral/gem.json index 36de4c4ed3..9fca421538 100644 --- a/Gems/LmbrCentral/gem.json +++ b/Gems/LmbrCentral/gem.json @@ -15,6 +15,6 @@ ], "icon_path": "preview.png", "requirements": "", - "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/core/lmbr-central/", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/o3de-core/", "dependencies": [] } From 73891c71b777ed1e8e1402ffdbc7463bff6670a8 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Sun, 3 Oct 2021 22:49:13 -0700 Subject: [PATCH 029/293] Fix EditorServer connection by ensuring that SendReadyForEntityUpdates is only called after a handshake is finished and the editor has accepted the editorserver's connection. Also allow engine-centric projects to use editor-server by passing in the project-path when launching the editor-server. Also allow devs to set sv_defaultPlayerSpawnAsset from inside the editor and it'll be used by the editor-server Signed-off-by: Gene Walters --- .../Editor/MultiplayerEditorConnection.cpp | 1 - .../MultiplayerEditorSystemComponent.cpp | 8 ++++++- .../Source/MultiplayerSystemComponent.cpp | 22 ++++++++++++++----- .../Code/Source/MultiplayerSystemComponent.h | 2 ++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index 3ca1af8b66..24858e6412 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -146,7 +146,6 @@ namespace Multiplayer { // Connect the Editor to the editor server for Multiplayer simulation AZ::Interface::Get()->Connect(remoteAddress.c_str(), remotePort); - AZ::Interface::Get()->SendReadyForEntityUpdates(true); } } } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 377fb1eb56..d13c6538db 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -142,8 +142,14 @@ namespace Multiplayer } // Start the configured server if it's available + AZStd::string projectPath(AZ::Utils::GetProjectPath().c_str()); + AZStd::replace(projectPath.begin(), projectPath.end(), AZ::IO::WindowsPathSeparator, AZ::IO::PosixPathSeparator); AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; - processLaunchInfo.m_commandlineParameters = AZStd::string::format("\"%s\" --editorsv_isDedicated true", serverPath.c_str()); + processLaunchInfo.m_commandlineParameters = AZStd::string::format( + R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s")", + serverPath.c_str(), + projectPath.c_str(), + static_cast(sv_defaultPlayerSpawnAsset).c_str()); processLaunchInfo.m_showWindow = true; processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index e66eb8d3a3..9b04cd98d4 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -489,11 +489,23 @@ namespace Multiplayer { m_didHandshake = true; - AZ::CVarFixedString commandString = "sv_map " + packet.GetMap(); - AZ::Interface::Get()->PerformCommand(commandString.c_str()); + // If this is an Editor then we're now accepting the connection to the EditorServer. + // In normal game clients SendReadyForEntityUpdates will be enabled once the appropriate level's root spawnable is loaded, + // but since we're in Editor, we're already in the level. + AZ::ApplicationTypeQuery applicationType; + AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::QueryApplicationType, applicationType); + if (applicationType.IsEditor()) + { + SendReadyForEntityUpdates(true); + } + else + { + AZ::CVarFixedString commandString = "sv_map " + packet.GetMap(); + AZ::Interface::Get()->PerformCommand(commandString.c_str()); - AZ::CVarFixedString loadLevelString = "LoadLevel " + packet.GetMap(); - AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); + AZ::CVarFixedString loadLevelString = "LoadLevel " + packet.GetMap(); + AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); + } return true; } @@ -981,7 +993,7 @@ namespace Multiplayer INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity(), Multiplayer::AutoActivate::DoNotActivate); NetworkEntityHandle controlledEntity; - if (entityList.size() > 0) + if (!entityList.empty()) { controlledEntity = entityList[0]; } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index c467ed9ad9..ba014f814a 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -37,6 +37,8 @@ namespace AzNetworking namespace Multiplayer { + AZ_CVAR_EXTERNED(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset); + //! Multiplayer system component wraps the bridging logic between the game and transport layer. class MultiplayerSystemComponent final : public AZ::Component From e306321b6150ad51234c12a0b24a752850cce41f Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Mon, 4 Oct 2021 10:56:16 -0500 Subject: [PATCH 030/293] Removing xfail from optimized Landscape Canvas suite and disabling non-optimized suites Signed-off-by: jckand-amzn --- .../PythonTests/largeworlds/CMakeLists.txt | 26 ------------------- .../TestSuite_Main_Optimized.py | 1 - 2 files changed, 27 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt index f1299ddc2d..59ccdffdca 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt @@ -55,32 +55,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ ## LandscapeCanvas ## - ly_add_pytest( - NAME AutomatedTesting::LandscapeCanvasTests_Main - TEST_SERIAL - TEST_SUITE main - PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/TestSuite_Main.py - RUNTIME_DEPENDENCIES - AZ::AssetProcessor - Legacy::Editor - AutomatedTesting.Assets - COMPONENT - LargeWorlds - ) - - ly_add_pytest( - NAME AutomatedTesting::LandscapeCanvasTests_Periodic - TEST_SERIAL - TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/TestSuite_Periodic.py - RUNTIME_DEPENDENCIES - AZ::AssetProcessor - Legacy::Editor - AutomatedTesting.Assets - COMPONENT - LargeWorlds - ) - ly_add_pytest( NAME AutomatedTesting::LandscapeCanvasTests_Main_Optimized TEST_SERIAL diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py index 9cc572ad69..0461ff2647 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py @@ -12,7 +12,6 @@ import ly_test_tools.environment.file_system as file_system from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite -@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") @pytest.mark.SUITE_periodic @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) From a52faa7340f7ed85e6de370db21462fe0f33e74d Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:03:55 -0700 Subject: [PATCH 031/293] Fixed qthread error coming from file i/o thread Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/Modifier.cpp | 41 ++++++++++++++----- .../View/Windows/Tools/UpgradeTool/Modifier.h | 5 +++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp index 3c62670ef0..f3da1ba309 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.cpp @@ -203,6 +203,24 @@ namespace ScriptCanvasEditor ModifyNextAsset(); } + void Modifier::ReportSaveResult() + { + AZStd::lock_guard lock(m_mutex); + m_fileSaver.reset(); + + if (m_fileSaveResult.fileSaveError.empty()) + { + ReportModificationSuccess(); + } + else + { + ReportModificationError(m_fileSaveResult.fileSaveError); + } + + m_fileSaveResult = {}; + m_modifyState = ModifyState::Idle; + } + void Modifier::OnFileSaveComplete(const FileSaveResult& result) { if (!result.tempFileRemovalError.empty()) @@ -213,16 +231,10 @@ namespace ScriptCanvasEditor , result.tempFileRemovalError.c_str()); } + AZStd::lock_guard lock(m_mutex); + m_modifyState = ModifyState::ReportResult; m_fileSaver.reset(); - - if (result.fileSaveError.empty()) - { - ReportModificationSuccess(); - } - else - { - ReportModificationError(result.fileSaveError); - } + m_fileSaveResult = result; } void Modifier::OnSystemTick() @@ -328,9 +340,18 @@ namespace ScriptCanvasEditor } else { - if (m_modifyState == ModifyState::Idle) + AZStd::lock_guard lock(m_mutex); + + switch (m_modifyState) { + case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::Idle: ModifyCurrentAsset(); + break; + case ScriptCanvasEditor::VersionExplorer::Modifier::ModifyState::ReportResult: + ReportSaveResult(); + break; + default: + break; } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h index 2a8a12e3cf..981a1eb746 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Modifier.h @@ -58,8 +58,11 @@ namespace ScriptCanvasEditor Idle, InProgress, Saving, + ReportResult }; + AZStd::recursive_mutex m_mutex; + // the two states reside in this class because the modification is only complete if the new source file saves out State m_state = State::GatheringDependencies; ModifyState m_modifyState = ModifyState::Idle; @@ -77,6 +80,7 @@ namespace ScriptCanvasEditor ModificationResult m_result; ModificationResults m_results; AZStd::unique_ptr m_fileSaver; + FileSaveResult m_fileSaveResult; void GatherDependencies(); const AZ::Data::AssetInfo& GetCurrentAsset() const; @@ -87,6 +91,7 @@ namespace ScriptCanvasEditor void ModificationComplete(const ModificationResult& result) override; void ReportModificationError(AZStd::string_view report); void ReportModificationSuccess(); + void ReportSaveResult(); void SaveModifiedGraph(const ModificationResult& result); void SortGraphsByDependencies(); void OnFileSaveComplete(const FileSaveResult& result); From 118834efdedb4ebe5290c2de1826ef2e562a5741 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 4 Oct 2021 15:08:13 -0700 Subject: [PATCH 032/293] Added ability to list gem repos using CLI and integrated support into Project Manager Signed-off-by: nggieber --- .../Source/GemRepo/GemRepoInfo.h | 2 +- .../Source/GemRepo/GemRepoItemDelegate.cpp | 3 +- .../Source/GemRepo/GemRepoScreen.cpp | 21 ++ .../Source/ProjectManagerDefs.h | 2 + .../ProjectManager/Source/PythonBindings.cpp | 60 +++++- .../ProjectManager/Source/PythonBindings.h | 2 +- scripts/o3de/o3de/manifest.py | 190 +++++++----------- scripts/o3de/o3de/validation.py | 1 - 8 files changed, 152 insertions(+), 129 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h index 14c76bd0c2..61220cefe7 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h @@ -30,7 +30,7 @@ namespace O3DE::ProjectManager bool operator<(const GemRepoInfo& gemRepoInfo) const; QString m_path = ""; - QString m_name = "Unknown Gem Repo Name"; + QString m_name = "Unknown Repo Name"; QString m_creator = "Unknown Creator"; bool m_isEnabled = false; //! Is the repo currently enabled for this engine? QString m_summary = "No summary provided."; diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp index 88ccee2636..58b10a1d1a 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -95,7 +96,7 @@ namespace O3DE::ProjectManager painter->drawText(repoCreatorRect, Qt::TextSingleLine, repoCreator); // Repo update - QString repoUpdatedDate = GemRepoModel::GetLastUpdated(modelIndex).toString("dd/MM/yyyy hh:mmap"); + QString repoUpdatedDate = GemRepoModel::GetLastUpdated(modelIndex).toString(RepoTimeFormat); repoUpdatedDate = standardFontMetrics.elidedText(repoUpdatedDate, Qt::TextElideMode::ElideRight, s_updatedMaxWidth); QRect repoUpdatedDateRect = GetTextRect(standardFont, repoUpdatedDate, s_fontSize); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 9c432884e6..a233010225 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -104,9 +105,29 @@ namespace O3DE::ProjectManager { // Add all available repos to the model const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue(); + QDateTime oldestRepoUpdate; + if (!allGemRepoInfos.isEmpty()) + { + oldestRepoUpdate = allGemRepoInfos[0].m_lastUpdated; + } for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos) { m_gemRepoModel->AddGemRepo(gemRepoInfo); + + // Find least recently updated repo + if (gemRepoInfo.m_lastUpdated < oldestRepoUpdate) + { + oldestRepoUpdate = gemRepoInfo.m_lastUpdated; + } + } + + if (!allGemRepoInfos.isEmpty()) + { + m_lastAllUpdateLabel->setText(tr("Last Updated: %1").arg(oldestRepoUpdate.toString(RepoTimeFormat))); + } + else + { + m_lastAllUpdateLabel->setText(tr("Last Updated: Never")); } } else diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h index 264515652f..e8e290ad02 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h +++ b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h @@ -26,4 +26,6 @@ namespace O3DE::ProjectManager static const QString ProjectCMakeCommand = "cmake"; static const QString ProjectCMakeBuildTargetEditor = "Editor"; + static const QString RepoTimeFormat = "dd/MM/yyyy hh:mmap"; + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index b9369b5bb0..96c54d8af2 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -929,13 +929,55 @@ namespace O3DE::ProjectManager return AZ::Failure("Adding Gem Repo not implemented yet in o3de scripts."); } - GemRepoInfo PythonBindings::GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath) + GemRepoInfo PythonBindings::GetGemRepoInfo(pybind11::handle repoUri) { - /* Placeholder Logic */ - (void)path; - (void)pyEnginePath; + GemRepoInfo gemRepoInfo; + gemRepoInfo.m_repoLink = Py_To_String(repoUri); - return GemRepoInfo(); + auto data = m_manifest.attr("get_repo_json_data")(repoUri); + if (pybind11::isinstance(data)) + { + try + { + // required + gemRepoInfo.m_repoLink = Py_To_String(data["repo_uri"]); + gemRepoInfo.m_name = Py_To_String(data["repo_name"]); + gemRepoInfo.m_creator = Py_To_String(data["origin"]); + + // optional + gemRepoInfo.m_summary = Py_To_String_Optional(data, "summary", "No summary provided."); + gemRepoInfo.m_additionalInfo = Py_To_String_Optional(data, "additional_info", ""); + + auto repoPath = m_manifest.attr("get_repo_path")(repoUri); + gemRepoInfo.m_path = gemRepoInfo.m_directoryLink = Py_To_String(repoPath); + + QString lastUpdated = Py_To_String_Optional(data, "last_updated", ""); + gemRepoInfo.m_lastUpdated = QDateTime::fromString(lastUpdated, RepoTimeFormat); + + if (data.contains("enabled")) + { + gemRepoInfo.m_isEnabled = data["enabled"].cast(); + } + else + { + gemRepoInfo.m_isEnabled = false; + } + + if (data.contains("gem_paths")) + { + for (auto gemPath : data["gem_paths"]) + { + gemRepoInfo.m_includedGemPaths.push_back(Py_To_String(gemPath)); + } + } + } + catch ([[maybe_unused]] const std::exception& e) + { + AZ_Warning("PythonBindings", false, "Failed to get GemRepoInfo for repo %s", Py_To_String(repoUri)); + } + } + + return gemRepoInfo; } //#define MOCK_GEM_REPO_INFO true @@ -948,14 +990,10 @@ namespace O3DE::ProjectManager auto result = ExecuteWithLockErrorHandling( [&] { - /* Placeholder Logic, o3de scripts need method added - * - for (auto path : m_manifest.attr("get_gem_repos")()) + for (auto repoUri : m_manifest.attr("get_repos")()) { - gemRepos.push_back(GemRepoInfoFromPath(path, pybind11::none())); + gemRepos.push_back(GetGemRepoInfo(repoUri)); } - * - */ }); if (!result.IsSuccess()) { diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 42f04ed6e6..195915a18f 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -66,7 +66,7 @@ namespace O3DE::ProjectManager AZ::Outcome ExecuteWithLockErrorHandling(AZStd::function executionCallback); bool ExecuteWithLock(AZStd::function executionCallback); GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); - GemRepoInfo GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath); + GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri); ProjectInfo ProjectInfoFromPath(pybind11::handle path); ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); bool RegisterThisEngine(); diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 7e504d29cd..ccb5cda761 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -13,8 +13,10 @@ import json import logging import os import pathlib +import shutil +import hashlib -from o3de import validation +from o3de import validation, utils logger = logging.getLogger() logging.basicConfig() @@ -135,12 +137,12 @@ def get_o3de_manifest() -> pathlib.Path: json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) json_data.update({'default_third_party_folder': default_third_party_folder.as_posix()}) + json_data.update({'engines': []}) json_data.update({'projects': []}) json_data.update({'external_subdirectories': []}) json_data.update({'templates': []}) json_data.update({'restricted': []}) json_data.update({'repos': []}) - json_data.update({'engines': []}) default_restricted_folder_json = default_restricted_folder / 'restricted.json' if not default_restricted_folder_json.is_file(): @@ -195,23 +197,25 @@ def load_o3de_manifest(manifest_path: pathlib.Path = None) -> dict: return json_data -def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> bool: +def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> None: """ - Save the json dictionary to the supplied manifest file or ~/.o3de/o3de_manifest.json if manifest_path is None + Save the json dictionary to the supplied manifest file or ~/.o3de/o3de_manifest.json if None - :param json_data: dictionary to save in json format at the file path - :param manifest_path: optional path to manifest file to save - """ + :param json_data: dictionary to save in json format at the file path + :param manifest_path: optional path to manifest file to save + """ if not manifest_path: manifest_path = get_o3de_manifest() + backup_name = utils.backup_file(manifest_path) with manifest_path.open('w') as s: try: s.write(json.dumps(json_data, indent=4) + '\n') - return True - except OSError as e: + except Exception as e: logger.error(f'Manifest json failed to save: {str(e)}') - return False - + os.unlink(manifest_path) + os.rename(backup_name, manifest_path) + finally: + os.unlink(backup_name) def get_gems_from_subdirectories(external_subdirs: list) -> list: @@ -236,6 +240,12 @@ def get_gems_from_subdirectories(external_subdirs: list) -> list: # Data query methods +def get_this_engine() -> dict: + json_data = load_o3de_manifest() + engine_data = find_engine_data(json_data) + return engine_data + + def get_engines() -> list: json_data = load_o3de_manifest() engine_list = json_data['engines'] if 'engines' in json_data else [] @@ -421,40 +431,48 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa return list(filter(filter_project_and_gem_templates_out, get_all_templates())) - -def get_engine_json_data(engine_name: str = None, - engine_path: str or pathlib.Path = None) -> dict or None: - if not engine_name and not engine_path: - logger.error('Must specify either a Engine name or Engine Path.') +def get_json_data(object_typename: str = None, + object_path: str or pathlib.Path = None, + object_validator = callable) -> dict or None: + if not object_typename or not object_validator: + logger.error(f'Missing object info.') + + if not object_path: + logger.error(f'{object_typename} Path {object_path} has not been registered.') return None - if engine_name and not engine_path: - engine_path = get_registered(engine_name=engine_name) - - if not engine_path: - logger.error(f'Engine Path {engine_path} has not been registered.') + object_path = pathlib.Path(object_path).resolve() + object_json = object_path / f'{object_typename}.json' + if not object_json.is_file(): + logger.error(f'{object_typename} json {object_json} is not present.') return None - - engine_path = pathlib.Path(engine_path).resolve() - engine_json = engine_path / 'engine.json' - if not engine_json.is_file(): - logger.error(f'Engine json {engine_json} is not present.') - return None - if not validation.valid_o3de_engine_json(engine_json): - logger.error(f'Engine json {engine_json} is not valid.') + if not object_validator(object_json): + logger.error(f'{object_typename} json {object_json} is not valid.') return None - with engine_json.open('r') as f: + with object_json.open('r') as f: try: - engine_json_data = json.load(f) + object_json_data = json.load(f) except json.JSONDecodeError as e: - logger.warn(f'{engine_json} failed to load: {str(e)}') + logger.warn(f'{object_json} failed to load: {str(e)}') else: - return engine_json_data + return object_json_data return None +def get_engine_json_data(engine_name: str = None, + engine_path: str or pathlib.Path = None) -> dict or None: + if not engine_name and not engine_path: + logger.error('Must specify either a Engine name or Engine Path.') + return None + + if engine_name and not engine_path: + engine_path = get_registered(engine_name=engine_name) + + return get_json_data('engine', engine_path, validation.valid_o3de_engine_json) + + def get_project_json_data(project_name: str = None, project_path: str or pathlib.Path = None) -> dict or None: if not project_name and not project_path: @@ -464,28 +482,7 @@ def get_project_json_data(project_name: str = None, if project_name and not project_path: project_path = get_registered(project_name=project_name) - if not project_path: - logger.error(f'Project Path {project_path} has not been registered.') - return None - - project_path = pathlib.Path(project_path).resolve() - project_json = project_path / 'project.json' - if not project_json.is_file(): - logger.error(f'Project json {project_json} is not present.') - return None - if not validation.valid_o3de_project_json(project_json): - logger.error(f'Project json {project_json} is not valid.') - return None - - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{project_json} failed to load: {str(e)}') - else: - return project_json_data - - return None + return get_json_data('project', project_path, validation.valid_o3de_project_json) def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None, @@ -497,28 +494,7 @@ def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None if gem_name and not gem_path: gem_path = get_registered(gem_name=gem_name, project_path=project_path) - if not gem_path: - logger.error(f'Gem Path {gem_path} has not been registered.') - return None - - gem_path = pathlib.Path(gem_path).resolve() - gem_json = gem_path / 'gem.json' - if not gem_json.is_file(): - logger.error(f'Gem json {gem_json} is not present.') - return None - if not validation.valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') - return None - - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{gem_json} failed to load: {str(e)}') - else: - return gem_json_data - - return None + return get_json_data('gem', gem_path, validation.valid_o3de_gem_json) def get_template_json_data(template_name: str = None, template_path: str or pathlib.Path = None, @@ -530,28 +506,7 @@ def get_template_json_data(template_name: str = None, template_path: str or path if template_name and not template_path: template_path = get_registered(template_name=template_name, project_path=project_path) - if not template_path: - logger.error(f'Template Path {template_path} has not been registered.') - return None - - template_path = pathlib.Path(template_path).resolve() - template_json = template_path / 'template.json' - if not template_json.is_file(): - logger.error(f'Template json {template_json} is not present.') - return None - if not validation.valid_o3de_template_json(template_json): - logger.error(f'Template json {template_json} is not valid.') - return None - - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{template_json} failed to load: {str(e)}') - else: - return template_json_data - - return None + return get_json_data('template', template_path, validation.valid_o3de_template_json) def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None, @@ -563,29 +518,38 @@ def get_restricted_json_data(restricted_name: str = None, restricted_path: str o if restricted_name and not restricted_path: restricted_path = get_registered(restricted_name=restricted_name, project_path=project_path) - if not restricted_path: - logger.error(f'Restricted Path {restricted_path} has not been registered.') + return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json) + +def get_repo_json_data(repo_uri: str = None) -> dict or None: + if not repo_uri: + logger.error('Must specify a Repo Uri.') return None - restricted_path = pathlib.Path(restricted_path).resolve() - restricted_json = restricted_path / 'restricted.json' - if not restricted_json.is_file(): - logger.error(f'Restricted json {restricted_json} is not present.') + repo_json = get_repo_path(repo_uri=repo_uri) + + if not repo_json.is_file(): + logger.error(f'Repo json {repo_json} is not present.') return None - if not validation.valid_o3de_restricted_json(restricted_json): - logger.error(f'Restricted json {restricted_json} is not valid.') + if not validation.valid_o3de_repo_json(repo_json): + logger.error(f'Repo json {repo_json} is not valid.') return None - with restricted_json.open('r') as f: + with repo_json.open('r') as f: try: - restricted_json_data = json.load(f) + repo_json_data = json.load(f) except json.JSONDecodeError as e: - logger.warn(f'{restricted_json} failed to load: {str(e)}') + logger.warn(f'{repo_json} failed to load: {str(e)}') else: - return restricted_json_data + return repo_json_data return None +def get_repo_path(repo_uri: str = None, cache_folder: str = None) -> pathlib.Path: + if not cache_folder: + cache_folder = get_o3de_cache_folder() + + repo_sha256 = hashlib.sha256(repo_uri.encode()) + return cache_folder / str(repo_sha256.hexdigest() + '.json') def get_registered(engine_name: str = None, project_name: str = None, @@ -721,9 +685,7 @@ def get_registered(engine_name: str = None, elif isinstance(repo_name, str): cache_folder = get_o3de_cache_folder() for repo_uri in json_data['repos']: - repo_uri = pathlib.Path(repo_uri).resolve() - repo_sha256 = hashlib.sha256(repo_uri.encode()) - cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + cache_file = get_repo_path(repo_uri=repo_uri, cache_folder=cache_folder) if cache_file.is_file(): repo = pathlib.Path(cache_file).resolve() with repo.open('r') as f: diff --git a/scripts/o3de/o3de/validation.py b/scripts/o3de/o3de/validation.py index 8fcc0d7e7d..5c683f0667 100644 --- a/scripts/o3de/o3de/validation.py +++ b/scripts/o3de/o3de/validation.py @@ -27,7 +27,6 @@ def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool: test = json_data['origin'] except (json.JSONDecodeError, KeyError) as e: return False - return True From b7e3a63faea416a22ba8f3a7d13dc22728bfd64a Mon Sep 17 00:00:00 2001 From: kritin Date: Mon, 4 Oct 2021 23:18:31 -0700 Subject: [PATCH 033/293] responded to code reviews Signed-off-by: kritin --- ...flows_ExistingLevel_EntityComponentCRUD.py | 159 ++++++++++++++++++ .../editor/TestSuite_Main_Optimized.py | 3 +- 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py new file mode 100644 index 0000000000..451b3a6714 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py @@ -0,0 +1,159 @@ +""" +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: + load_level = ( + "Level loaded successfully", + "Failed to load the level" + ) + create_entity = ( + "Parent entity created successfully", + "Failed to create a parent entity" + ) + set_entity_name = ( + "Entity name set successfully", + "Failed to set entity name" + ) + delete_entity = ( + "Parent Entity deleted successfully", + "Failed to delete parent entity" + ) + create_child_entity = ( + "Child entity created successfully", + "Failed to create a child entity" + ) + delete_child_entity = ( + "Child entity deleted successfully", + "Failed to delete child entity" + ) + add_mesh_component = ( + "Mesh component added successfully", + "Failed to add mesh component" + ) + found_component_typeId = ( + "Found component typeId", + "Unable to find component TypeId" + ) + remove_mesh_component = ( + "Mesh component removed successfully", + "Failed to remove mesh component" + ) + + +def BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD(): + """ + Performing basic test in editor + 01. Load exiting level + 02. create parent entity and set name + 03. create child entity and set a name + 04. delete child entity + 05. add mesh component to parent entity + 06. remove mesh component + 07. delete parent entity + Close editor without saving + """ + import os + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + import editor_python_test_tools.hydra_editor_utils as hydra + + import azlmbr.math as math + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.object + + def search_entity(entity_to_search, entity_name): + """ + + :param entity_to_search: entity to be searched + :param entity_name: name of the entity used in the set command + :return: True if entity id exists in the entity_list + False if entity id does not exist in the entity_list + """ + entity_list = [] + entity_search_filter = entity.SearchFilter() + entity_search_filter.names = entity_name + entity_list = entity.SearchBus(bus.Broadcast, 'SearchEntities', entity_search_filter) + if entity_list: + if entity_to_search in entity_list: + return True + return False + return False + + # 01. load an existing level + + test_level = 'Simple' + general.open_level_no_prompt(test_level) + Report.result(Tests.load_level, general.get_current_level_name() == test_level) + + # 02. create parent entity and set name + # Delete any exiting entity and Create a new Entity at the root level + search_filter = azlmbr.entity.SearchFilter() + all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) + editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) + parent_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", entity.EntityId()) + Report.result(Tests.create_entity, parent_entity.IsValid()) + + # Setting a new name + parent_entity_name = "Parent_1" + editor.EditorEntityAPIBus(bus.Event, 'SetName', parent_entity, parent_entity_name) + Report.result(Tests.set_entity_name, + editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', parent_entity) == parent_entity_name) + + # 03. Create child Entity to above created parent entity and set a name + child_1_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', parent_entity) + Report.result(Tests.create_child_entity, child_1_entity.IsValid()) + child_entity_name = "Child_1" + editor.EditorEntityAPIBus(bus.Event, 'SetName', child_1_entity, child_entity_name) + Report.result(Tests.set_entity_name, + editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', child_1_entity) == child_entity_name) + + # 04. delete_Child_entity + editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', child_1_entity) + Report.result(Tests.delete_child_entity, search_entity(child_1_entity, "Child_1") == False) + + # 05. add mesh component to parent entity + type_id_list = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Mesh"], + entity.EntityType().Game) + if type_id_list is not None: + component_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', parent_entity, + type_id_list) + Report.result(Tests.add_mesh_component, component_outcome.IsSuccess()) + else: + Report.result(Tests.found_component_typeId, type_id_list is not None) + + # 06. remove mesh component + outcome_get_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', parent_entity, + type_id_list[0]) + if outcome_get_component.IsSuccess(): + component_entity_pair = outcome_get_component.GetValue() + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component_entity_pair]) + component_exists = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', parent_entity, + type_id_list[0]) + mesh_test = True + if component_exists: + mesh_test = False + Report.result(Tests.remove_mesh_component, mesh_test) + else: + Report.result(Tests.found_component_typeId, outcome_get_component.IsSuccess()) + + # 7. delete parent entity + editor.ToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'DeleteEntityById', parent_entity) + Report.result(Tests.delete_entity, search_entity(parent_entity, "Parent_1") == False) + + # Close editor without saving + editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt') + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + + Report.start_test(BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD) diff --git a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py index 9aef8a8b2c..755f75216b 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py @@ -73,6 +73,7 @@ class TestAutomationAutoTestMode(EditorTestSuite): @pytest.mark.skip(reason="Times out due to dialogs failing to dismiss: LYN-4208") class test_Menus_FileMenuOptions_Work(EditorSharedTest): from .EditorScripts import Menus_FileMenuOptions as test_module + class test_Sample_Editor_Tests(EditorSharedTest): - from .EditorScripts import Sample_Editor_Tests as test_module \ No newline at end of file + from .EditorScripts import BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD as test_module From a870c6ad80a77a03a4869f79595c448f99b9091b Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 5 Oct 2021 09:52:52 -0700 Subject: [PATCH 034/293] Fix explorer bugs and restore upgrade single option Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../ScriptCanvasBuilderWorkerUtility.cpp | 2 + .../Windows/Tools/UpgradeTool/Controller.cpp | 36 ++++++++------- .../Windows/Tools/UpgradeTool/Controller.h | 2 + .../View/Windows/Tools/UpgradeTool/Model.cpp | 24 +++++++++- .../Windows/Tools/UpgradeTool/ModelTraits.h | 2 +- .../Libraries/Core/ReceiveScriptEvent.cpp | 27 +++++------ .../Libraries/Core/ReceiveScriptEvent.h | 3 +- .../Libraries/Core/ScriptEventBase.cpp | 7 +-- .../ScriptCanvas/Translation/GraphToLua.cpp | 11 +++-- .../ScriptCanvas/Translation/GraphToX.cpp | 45 ++++++++++--------- .../ScriptCanvas/Translation/GraphToX.h | 5 ++- .../Translation/TranslationResult.cpp | 9 ++++ .../Translation/TranslationResult.h | 8 ++-- 13 files changed, 113 insertions(+), 68 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp index 0853789b19..665a481a17 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp @@ -113,6 +113,7 @@ namespace ScriptCanvasBuilder if (!isSuccessOutcome.IsSuccess()) { + // sanity check return AZ::Failure(isSuccessOutcome.TakeError()); } auto& translation = translationResult.m_translations.find(ScriptCanvas::Translation::TargetFlags::Lua)->second; @@ -481,6 +482,7 @@ namespace ScriptCanvasBuilder buildEntity->Activate(); } + AZ_Assert(buildEntity->GetState() == AZ::Entity::State::Active, "build entity not active"); return sourceGraph; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 4e4e842cb8..207f70aec1 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -131,6 +131,11 @@ namespace ScriptCanvasEditor } void Controller::OnButtonPressUpgrade() + { + OnButtonPressUpgradeImplementation({}); + } + + void Controller::OnButtonPressUpgradeImplementation(const AZ::Data::AssetInfo& assetInfo) { auto simpleUpdate = [this](AZ::Data::Asset asset) { @@ -202,12 +207,18 @@ namespace ScriptCanvasEditor SetLoggingPreferences(); ModifyConfiguration config; + config.modifySingleAsset = assetInfo; config.modification = simpleUpdate; config.onReadOnlyFile = onReadyOnlyFile; config.backupGraphBeforeModification = m_view->makeBackupCheckbox->isChecked(); ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config); } + void Controller::OnButtonPressUpgradeSingle(const AZ::Data::AssetInfo& assetInfo) + { + OnButtonPressUpgradeImplementation(assetInfo); + } + void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) { QList items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); @@ -325,7 +336,7 @@ namespace ScriptCanvasEditor OnScannedGraph(info, Filtered::Yes); } - void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, Filtered filtered) + void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] Filtered filtered) { m_view->tableWidget->insertRow(m_handledAssetCount); QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); @@ -338,19 +349,14 @@ namespace ScriptCanvasEditor rowGoToButton->setText("Upgrade"); rowGoToButton->setEnabled(false); SetRowBusy(m_handledAssetCount); -// \\ todo restore this -// connect(rowGoToButton, &QPushButton::clicked, [this, rowGoToButton, assetInfo] { -// -// // request upgrade of a single graph -// // AZ::SystemTickBus::QueueFunction([this, rowGoToButton, assetInfo]() { -// // // Queue the process state change because we can't connect to the SystemTick bus in a Qt lambda -// // UpgradeSingle(rowGoToButton, spinner, assetInfo); -// // }); -// // -// // AZ::SystemTickBus::ExecuteQueuedEvents(); -// -// }); - + connect + ( rowGoToButton + , &QPushButton::pressed + , this + , [this, assetInfo]() + { + this->OnButtonPressUpgradeSingle(assetInfo); + }); m_view->tableWidget->setCellWidget(m_handledAssetCount, static_cast(ColumnAction), rowGoToButton); } @@ -424,7 +430,7 @@ namespace ScriptCanvasEditor } QString spinnerText = QStringLiteral("Upgrade in progress - "); - if (config.modifySingleAsset) + if (config.modifySingleAsset.m_assetId.IsValid()) { spinnerText.append(" single graph"); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index fd297832bb..23f35840be 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -64,6 +64,8 @@ namespace ScriptCanvasEditor void OnButtonPressClose(); void OnButtonPressScan(); void OnButtonPressUpgrade(); + void OnButtonPressUpgradeImplementation(const AZ::Data::AssetInfo& assetInfo); + void OnButtonPressUpgradeSingle(const AZ::Data::AssetInfo& assetInfo); void OnGraphUpgradeComplete(AZ::Data::Asset&, bool skipped) override; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index ed17293ab7..98edef54bf 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -101,11 +101,33 @@ namespace ScriptCanvasEditor return; } + auto results = m_scanner->TakeResult(); + if (modification.modifySingleAsset.m_assetId.IsValid()) + { + auto iter = AZStd::find_if + ( results.m_unfiltered.begin() + , results.m_unfiltered.end() + , [&modification](const auto& candidate) + { + return candidate.info.m_assetId == modification.modifySingleAsset.m_assetId; + }); + + if (iter == results.m_unfiltered.end()) + { + AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Requested upgrade graph not found in scanned list."); + return; + } + + WorkingAsset singleEntry = *iter; + results.m_unfiltered.clear(); + results.m_unfiltered.push_back(singleEntry); + } + m_modResults = {}; m_state = State::Modifying; m_log.Activate(); m_keepEditorAlive = AZStd::make_unique(); - auto results = m_scanner->TakeResult(); + m_modifier = AZStd::make_unique(modification, AZStd::move(results.m_unfiltered), [this](){ OnModificationComplete(); }); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h index 026748c344..01eb200542 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/ModelTraits.h @@ -26,7 +26,7 @@ namespace ScriptCanvasEditor { AZStd::function)> modification; AZStd::function onReadOnlyFile; - bool modifySingleAsset = false; + AZ::Data::AssetInfo modifySingleAsset; bool backupGraphBeforeModification = false; bool successfulDependencyUpgradeRequired = true; }; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.cpp index 5a2eb80187..c548176af5 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.cpp @@ -67,7 +67,7 @@ namespace ScriptCanvas void ReceiveScriptEvent::PopulateAsset(AZ::Data::Asset asset, SlotIdMapping& populationMapping) { - if (CreateHandler(asset)) + if (InitializeDefinition(asset)) { if (!CreateEbus()) { @@ -140,7 +140,6 @@ namespace ScriptCanvas } } - void ReceiveScriptEvent::InitializeEvent(AZ::Data::Asset asset, int eventIndex, SlotIdMapping& populationMapping) { if (!m_handler) @@ -353,6 +352,13 @@ namespace ScriptCanvas AZStd::optional ReceiveScriptEvent::GetEventIndex(AZStd::string eventName) const { + if (!m_handler) + { + const_cast(this)->InitializeDefinition(m_asset); + const_cast(this)->CreateEbus(); + } + + AZ_Error("ScriptCanvas", m_handler != nullptr, "GetEventIndex called and handler was not created"); return m_handler ? AZStd::optional(m_handler->GetFunctionIndex(eventName.c_str())) : AZStd::nullopt; } @@ -490,15 +496,10 @@ namespace ScriptCanvas return m_definition.IsAddressRequired() || (slot && slot->GetDataType().IsValid()); } - bool ReceiveScriptEvent::CreateHandler(AZ::Data::Asset asset) + bool ReceiveScriptEvent::InitializeDefinition(AZ::Data::Asset asset) { AZStd::lock_guard lock(m_mutex); - if (m_handler) - { - return true; - } - if (!asset) { return false; @@ -518,12 +519,11 @@ namespace ScriptCanvas } return true; - } void ReceiveScriptEvent::OnScriptEventReady(const AZ::Data::Asset& asset) { - if (CreateHandler(asset)) + if (InitializeDefinition(asset)) { CompleteInitialize(asset); } @@ -531,7 +531,7 @@ namespace ScriptCanvas bool ReceiveScriptEvent::CreateEbus() { - if (!m_ebus) + if (!m_ebus || !m_handler) { AZ::BehaviorContext* behaviorContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationBus::Events::GetBehaviorContext); @@ -547,13 +547,11 @@ namespace ScriptCanvas AZ_Assert(m_ebus, "Behavior Context EBus does not exist: %s", m_definition.GetName().c_str()); AZ_Assert(m_ebus->m_createHandler, "The ebus %s has no create handler!", m_definition.GetName().c_str()); AZ_Assert(m_ebus->m_destroyHandler, "The ebus %s has no destroy handler!", m_definition.GetName().c_str()); - AZ_Verify(m_ebus->m_createHandler->InvokeResult(m_handler, &m_definition), "Behavior Context EBus handler creation failed %s", m_definition.GetName().c_str()); - AZ_Assert(m_handler, "Ebus create handler failed %s", m_definition.GetName().c_str()); } - return true; + return m_ebus != nullptr && m_handler != nullptr; } bool ReceiveScriptEvent::IsOutOfDate(const VersionData& graphVersion) const @@ -597,7 +595,6 @@ namespace ScriptCanvas } } - AZStd::string ReceiveScriptEvent::GetUpdateString() const { if (m_ebus) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.h index 0f8d673629..a41d0ba3f9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ReceiveScriptEvent.h @@ -101,7 +101,7 @@ namespace ScriptCanvas Internal::ScriptEventEntry ConfigureEbusEntry(const ScriptEvents::Method& methodDefinition, const AZ::BehaviorEBusHandler::BusForwarderEvent& event, SlotIdMapping& populationMapping); - bool CreateHandler(AZ::Data::Asset asset); + bool InitializeDefinition(AZ::Data::Asset asset); void CompleteInitialize(AZ::Data::Asset asset); void PopulateAsset(AZ::Data::Asset asset, SlotIdMapping& populationMapping); bool m_eventInitComplete = false; @@ -120,7 +120,6 @@ namespace ScriptCanvas bool m_autoConnectToGraphOwner = true; bool m_connected; - }; } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ScriptEventBase.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ScriptEventBase.cpp index 3b01a8fa7c..e4cbfc94f7 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ScriptEventBase.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/ScriptEventBase.cpp @@ -122,11 +122,8 @@ namespace ScriptCanvas void ScriptEventBase::OnActivate() { - if (!m_asset || m_asset.GetStatus() == AZ::Data::AssetData::AssetStatus::NotLoaded) - { - m_asset = AZ::Data::AssetManager::Instance().GetAsset(m_scriptEventAssetId, AZ::Data::AssetLoadBehavior::PreLoad); - m_asset.BlockUntilLoadComplete(); - } + m_asset = AZ::Data::AssetManager::Instance().GetAsset(m_scriptEventAssetId, AZ::Data::AssetLoadBehavior::PreLoad); + m_asset.BlockUntilLoadComplete(); } void ScriptEventBase::OnAssetReady(AZ::Data::Asset asset) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp index 9a1ef73126..ee7eb704bb 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp @@ -246,8 +246,7 @@ namespace ScriptCanvas } else { - ErrorList errors = { AZStd::string("provide translation failure details") }; - return AZ::Failure(errors); + return AZ::Failure(translation.MoveErrors()); } } @@ -874,7 +873,13 @@ namespace ScriptCanvas AZStd::optional eventIndex = ebusHandling->m_node->GetEventIndex(nameAndEventThread.first); if (!eventIndex) { - AddError(nullptr, aznew Internal::ParseError(ebusHandling->m_node->GetEntityId(), AZStd::string::format("EBus handler did not return a valid index for event %s", nameAndEventThread.first.c_str()))); + AddError(nullptr, + aznew Internal::ParseError( + ebusHandling->m_node->GetEntityId() + , AZStd::string::format + ( "EBus Handler %s did not return a valid index for event %s" + , ebusHandling->m_ebusName.c_str() + , nameAndEventThread.first.c_str()))); return; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.cpp index 09315ec4b0..d21fb354b1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.cpp @@ -107,27 +107,9 @@ namespace ScriptCanvas m_translationDuration = AZStd::chrono::microseconds(AZStd::chrono::system_clock::now() - m_translationStartTime).count(); } - AZStd::string GraphToX::ResolveScope(const AZStd::vector& namespaces) - { - AZStd::string resolution; - - if (!namespaces.empty()) - { - resolution = Grammar::ToIdentifier(namespaces[0]); - - for (size_t index = 1; index < namespaces.size(); ++index) - { - resolution += m_configuration.m_lexicalScopeDelimiter; - resolution += Grammar::ToIdentifier(namespaces[index]); - } - } - - return resolution; - } - - void GraphToX::SingleLineComment(Writer& writer) + AZStd::vector&& GraphToX::MoveErrors() { - writer.Write(m_configuration.m_singleLineComment); + return AZStd::move(m_errors); } void GraphToX::OpenBlockComment(Writer& writer) @@ -160,6 +142,29 @@ namespace ScriptCanvas writer.Indent(); } + AZStd::string GraphToX::ResolveScope(const AZStd::vector& namespaces) + { + AZStd::string resolution; + + if (!namespaces.empty()) + { + resolution = Grammar::ToIdentifier(namespaces[0]); + + for (size_t index = 1; index < namespaces.size(); ++index) + { + resolution += m_configuration.m_lexicalScopeDelimiter; + resolution += Grammar::ToIdentifier(namespaces[index]); + } + } + + return resolution; + } + + void GraphToX::SingleLineComment(Writer& writer) + { + writer.Write(m_configuration.m_singleLineComment); + } + void GraphToX::WriteCopyright(Writer& writer) { OpenBlockComment(writer); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.h index 062a58efe1..c4e189679a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToX.h @@ -51,12 +51,13 @@ namespace ScriptCanvas AZStd::string_view GetGraphName() const; AZStd::string_view GetFullPath() const; AZStd::sys_time_t GetTranslationDuration() const; - AZStd::string ResolveScope(const AZStd::vector& namespaces); - void SingleLineComment(Writer& writer); + AZStd::vector&& MoveErrors(); void OpenBlockComment(Writer& writer); void OpenFunctionBlock(Writer& writer); void OpenNamespace(Writer& writer, AZStd::string_view ns); void OpenScope(Writer& writer); + AZStd::string ResolveScope(const AZStd::vector& namespaces); + void SingleLineComment(Writer& writer); void WriteCopyright(Writer& writer); void WriteDoNotModify(Writer& writer); void WriteLastWritten(Writer& writer); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.cpp index dd8b42730d..c39cac13a3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.cpp @@ -72,6 +72,15 @@ namespace ScriptCanvas resultString += entry->GetDescription(); } + for (const auto& errors : m_errors) + { + for (auto& entry : errors.second) + { + resultString += "* "; + resultString += entry->GetDescription(); + } + } + return resultString; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.h index 0cde56d5dd..bd616fbfbb 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationResult.h @@ -12,10 +12,11 @@ #include #include #include -#include #include -#include +#include +#include #include +#include namespace AZ { @@ -85,7 +86,7 @@ namespace ScriptCanvas AZStd::sys_time_t m_duration; }; - using ErrorList = AZStd::vector; + using ErrorList = AZStd::vector; using Errors = AZStd::unordered_map; using Translations = AZStd::unordered_map; @@ -102,7 +103,6 @@ namespace ScriptCanvas const AZStd::sys_time_t m_translationDuration; Result(AZStd::string invalidSourceInfo); - Result(Result&& source); Result(Grammar::AbstractCodeModelConstPtr model); Result(Grammar::AbstractCodeModelConstPtr model, Translations&& translations, Errors&& errors); From bb8971a3addd11eb803cebb1287f9741c2ece612 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:48:27 -0700 Subject: [PATCH 035/293] LYN-5288 | Clicking on a Prefab in the viewport should select the entire Prefab and not an individual Entity (#4462) * Setup work for the ContainerEntity SystemComponent and Interface. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce Container Entity Notification Bus Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce a proxy model to control open/closed state of entity containers. Register prefab containers as entity containers. Profit. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add open state to OnContainerEntityStatusChanged notification + improvements to comments. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix to notification trigger to include new arguments. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix issue where the Level container would not be expanded correctly. The Level container is now no longer a container entity (since we don't need to be able to close it). Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Revert the addition of an extra proxy layer (which was causing issues) and just move the container logic to the existing filter. Fix bug in the dataChanged signal. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix column count in dataChanged signal to correctly update all column and fix visual glitches. Limit container registration to the prefab WIP flag so that the changes can be submitted with an opt-in mechanism. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add doubleclick behavior on Outliner items - enters focus mode when double clicking on prefab containers. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * override sourceModel() to store pointer to avoid dynamic casting at every filterAcceptsRow call. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor comment fixes and nits Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Move container selection logic to a helper function in the ContainerEntityInterface to simplify reusing it in the near future. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Support lazy initialization for tests (since we do not load a level, the lazy initialization in OnEntityStreamLoadSuccess does not trigger) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Application/ToolsApplication.cpp | 2 + .../AzToolsFrameworkModule.cpp | 2 + .../ContainerEntityInterface.h | 61 +++++++++ .../ContainerEntityNotificationBus.h | 41 ++++++ .../ContainerEntitySystemComponent.cpp | 120 ++++++++++++++++++ .../ContainerEntitySystemComponent.h | 54 ++++++++ .../Prefab/PrefabFocusHandler.cpp | 72 ++++++++++- .../Prefab/PrefabFocusHandler.h | 17 ++- .../EditorEntityUiHandlerBase.cpp | 46 +++++-- .../EditorEntityUiHandlerBase.h | 3 + .../UI/Outliner/EntityOutlinerListModel.cpp | 25 +++- .../UI/Outliner/EntityOutlinerListModel.hxx | 5 + .../EntityOutlinerSortFilterProxyModel.cpp | 22 ++++ .../EntityOutlinerSortFilterProxyModel.hxx | 12 +- .../UI/Outliner/EntityOutlinerWidget.cpp | 9 +- .../UI/Outliner/EntityOutlinerWidget.hxx | 2 + .../UI/Prefab/PrefabIntegrationManager.cpp | 32 ++++- .../UI/Prefab/PrefabIntegrationManager.h | 3 + .../UI/Prefab/PrefabUiHandler.cpp | 15 +++ .../UI/Prefab/PrefabUiHandler.h | 3 +- .../ViewportSelection/EditorHelpers.cpp | 11 +- .../aztoolsframework_files.cmake | 4 + 22 files changed, 531 insertions(+), 30 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index 717e0c6f8a..c54735fe91 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,7 @@ namespace AzToolsFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp index b68d086892..05d67d9d71 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ namespace AzToolsFramework Components::EditorSelectionAccentSystemComponent::CreateDescriptor(), EditorEntityContextComponent::CreateDescriptor(), EditorEntityFixupComponent::CreateDescriptor(), + ContainerEntitySystemComponent::CreateDescriptor(), FocusModeSystemComponent::CreateDescriptor(), SliceMetadataEntityContextComponent::CreateDescriptor(), SliceRequestComponent::CreateDescriptor(), diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h new file mode 100644 index 0000000000..45da3a9d8f --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework +{ + //! Outcome object that returns an error message in case of failure to allow caller to handle internal errors. + using ContainerEntityOperationResult = AZ::Outcome; + + //! ContainerEntityInterface + //! An entity registered as Container is just like a regular entity when open. If its state is changed + //! to closed, all descendants of the entity will be treated as part of the entity itself. Selecting any + //! descendant will result in the container being selected, and descendants will be hidden until the + //! container is opened. + class ContainerEntityInterface + { + public: + AZ_RTTI(ContainerEntityInterface, "{0A877C3A-726C-4FD2-BAFE-A2B9F1DE78E4}"); + + //! Registers the entity as a container. The container will be closed by default. + //! @param entityId The entityId that will be registered as a container. + virtual ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) = 0; + + //! Unregisters the entity as a container. + //! The system will retain the closed state in case the entity is registered again later, but + //! if queried the entity will no longer behave as a container. + //! @param entityId The entityId that will be unregistered as a container. + virtual ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) = 0; + + //! Returns whether the entity id provided is registered as a container. + virtual bool IsContainer(AZ::EntityId entityId) const = 0; + + //! Sets the open state of the container entity provided. + //! @param entityId The entityId whose open state will be set. + //! @param open True if the container should be opened, false if it should be closed. + //! @return An error message if the operation was invalid, success otherwise. + virtual ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) = 0; + + //! If the entity id provided is registered as a container, it returns whether it's open. + //! @note the default value for non-containers is true, so this function can be called without + //! verifying whether the entityId is registered as a container beforehand, since the container's + //! open behavior is exactly the same as the one of a regular entity. + //! @return False if the entityId is registered as a container, and its state is closed. True otherwise. + virtual bool IsContainerOpen(AZ::EntityId entityId) const = 0; + + //! Detects if one of the ancestors of entityId is a closed container entity. + //! @return The highest closed entity container id if any, or entityId otherwise. + virtual AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const = 0; + + }; + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h new file mode 100644 index 0000000000..95608feefb --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include + +namespace AzToolsFramework +{ + //! Used to notify changes of state for Container Entities. + class ContainerEntityNotifications + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = AzFramework::EntityContextId; + ////////////////////////////////////////////////////////////////////////// + + //! Triggered when a container entity status changes. + //! @param entityId The entity whose status has changed. + //! @param open The open state the container was changed to. + virtual void OnContainerEntityStatusChanged([[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] bool open) {} + + protected: + ~ContainerEntityNotifications() = default; + }; + + using ContainerEntityNotificationBus = AZ::EBus; + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp new file mode 100644 index 0000000000..0ea2eeb5f6 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +namespace AzToolsFramework +{ + void ContainerEntitySystemComponent::Activate() + { + AZ::Interface::Register(this); + } + + void ContainerEntitySystemComponent::Deactivate() + { + AZ::Interface::Unregister(this); + } + + void ContainerEntitySystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) + { + } + + void ContainerEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("ContainerEntityService")); + } + + ContainerEntityOperationResult ContainerEntitySystemComponent::RegisterEntityAsContainer(AZ::EntityId entityId) + { + if (IsContainer(entityId)) + { + return AZ::Failure(AZStd::string( + "ContainerEntitySystemComponent error - trying to register entity as container twice.")); + } + + m_containers.insert(entityId); + + return AZ::Success(); + } + + ContainerEntityOperationResult ContainerEntitySystemComponent::UnregisterEntityAsContainer(AZ::EntityId entityId) + { + if (!IsContainer(entityId)) + { + return AZ::Failure(AZStd::string( + "ContainerEntitySystemComponent error - trying to unregister entity that is not a container.")); + } + + m_containers.erase(entityId); + + return AZ::Success(); + } + + bool ContainerEntitySystemComponent::IsContainer(AZ::EntityId entityId) const + { + return m_containers.contains(entityId); + } + + ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpenState(AZ::EntityId entityId, bool open) + { + if (!IsContainer(entityId)) + { + return AZ::Failure(AZStd::string( + "ContainerEntitySystemComponent error - cannot set open state of entity that was not registered as container.")); + } + + if(open) + { + m_openContainers.insert(entityId); + } + else + { + m_openContainers.erase(entityId); + } + + ContainerEntityNotificationBus::Broadcast(&ContainerEntityNotificationBus::Events::OnContainerEntityStatusChanged, entityId, open); + + return AZ::Success(); + } + + bool ContainerEntitySystemComponent::IsContainerOpen(AZ::EntityId entityId) const + { + // If the entity is not a container, it should behave as open. + if(!m_containers.contains(entityId)) + { + return true; + } + + // If the entity is a container, return its state. + return m_openContainers.contains(entityId); + } + + AZ::EntityId ContainerEntitySystemComponent::FindHighestSelectableEntity(AZ::EntityId entityId) const + { + AZ::EntityId highestSelectableEntityId = entityId; + + // Go up the hierarchy until you hit the root + while (entityId.IsValid()) + { + if (!IsContainerOpen(entityId)) + { + // If one of the ancestors is a container and it's closed, keep track of its id. + // We only return of the higher closed container in the hierarchy. + highestSelectableEntityId = entityId; + } + + AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId); + } + + return highestSelectableEntityId; + } + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h new file mode 100644 index 0000000000..18c0fb70c6 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include + +namespace AzToolsFramework +{ + //! System Component to track Container Entity registration and open state. + //! An entity registered as Container is just like a regular entity when open. If its state is changed + //! to closed, all descendants of the entity will be treated as part of the entity itself. Selecting any + //! descendant will result in the container being selected, and descendants will be hidden until the + //! container is opened. + class ContainerEntitySystemComponent final + : public AZ::Component + , private ContainerEntityInterface + { + public: + AZ_COMPONENT(ContainerEntitySystemComponent, "{74349759-B36B-44A6-B89F-F45D7111DD11}"); + + ContainerEntitySystemComponent() = default; + virtual ~ContainerEntitySystemComponent() = default; + + // AZ::Component overrides ... + void Activate() override; + void Deactivate() override; + + static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + + // ContainerEntityInterface overrides ... + ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) override; + ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) override; + bool IsContainer(AZ::EntityId entityId) const override; + ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) override; + bool IsContainerOpen(AZ::EntityId entityId) const override; + AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const override; + + private: + AZStd::unordered_set m_containers; //!< All entities in this set are containers. + AZStd::unordered_set m_openContainers; //!< All entities in this set are open containers. + }; + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 4e58bbdf05..9ffc18af5a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -35,6 +36,30 @@ namespace AzToolsFramework::Prefab EditorEntityContextNotificationBus::Handler::BusDisconnect(); } + void PrefabFocusHandler::Initialize() + { + m_containerEntityInterface = AZ::Interface::Get(); + AZ_Assert( + m_containerEntityInterface, + "Prefab - PrefabFocusHandler - " + "Container Entity Interface could not be found. " + "Check that it is being correctly initialized."); + + m_focusModeInterface = AZ::Interface::Get(); + AZ_Assert( + m_focusModeInterface, + "Prefab - PrefabFocusHandler - " + "Focus Mode Interface could not be found. " + "Check that it is being correctly initialized."); + + m_instanceEntityMapperInterface = AZ::Interface::Get(); + AZ_Assert( + m_instanceEntityMapperInterface, + "Prefab - PrefabFocusHandler - " + "Instance Entity Mapper Interface could not be found. " + "Check that it is being correctly initialized."); + } + PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId) { InstanceOptionalReference focusedInstance; @@ -44,7 +69,7 @@ namespace AzToolsFramework::Prefab PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = AZ::Interface::Get(); - if(!prefabEditorEntityOwnershipInterface) + if (!prefabEditorEntityOwnershipInterface) { return AZ::Failure(AZStd::string("Could not focus on root prefab instance - internal error " "(PrefabEditorEntityOwnershipInterface unavailable).")); @@ -79,8 +104,16 @@ namespace AzToolsFramework::Prefab return AZ::Failure(AZStd::string("Prefab Focus Handler: invalid instance to focus on.")); } + if (!m_isInitialized) + { + Initialize(); + } + if (!m_focusedInstance.has_value() || &m_focusedInstance->get() != &focusedInstance->get()) { + // Close all container entities in the old path + CloseInstanceContainers(m_instanceFocusVector); + m_focusedInstance = focusedInstance; m_focusedTemplateId = focusedInstance->get().GetTemplateId(); @@ -103,12 +136,14 @@ namespace AzToolsFramework::Prefab } // Focus on the descendants of the container entity - if (FocusModeInterface* focusModeInterface = AZ::Interface::Get()) - { - focusModeInterface->SetFocusRoot(containerEntityId); - } + m_focusModeInterface->SetFocusRoot(containerEntityId); + // Refresh path variables RefreshInstanceFocusList(); + + // Open all container entities in the new path + OpenInstanceContainers(m_instanceFocusVector); + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); } @@ -156,6 +191,11 @@ namespace AzToolsFramework::Prefab void PrefabFocusHandler::OnEntityStreamLoadSuccess() { + if (!m_isInitialized) + { + Initialize(); + } + // Focus on the root prefab (AZ::EntityId() will default to it) FocusOnOwningPrefab(AZ::EntityId()); } @@ -184,4 +224,26 @@ namespace AzToolsFramework::Prefab } } + void PrefabFocusHandler::OpenInstanceContainers(const AZStd::vector& instances) const + { + for (const InstanceOptionalReference& instance : instances) + { + if (instance.has_value()) + { + m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), true); + } + } + } + + void PrefabFocusHandler::CloseInstanceContainers(const AZStd::vector& instances) const + { + for (const InstanceOptionalReference& instance : instances) + { + if (instance.has_value()) + { + m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), false); + } + } + } + } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 2ccec36882..2f631f772d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -15,6 +15,12 @@ #include #include +namespace AzToolsFramework +{ + class ContainerEntityInterface; + class FocusModeInterface; +} + namespace AzToolsFramework::Prefab { class InstanceEntityMapperInterface; @@ -30,6 +36,8 @@ namespace AzToolsFramework::Prefab PrefabFocusHandler(); ~PrefabFocusHandler(); + void Initialize(); + // PrefabFocusInterface overrides ... PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override; @@ -46,12 +54,19 @@ namespace AzToolsFramework::Prefab PrefabFocusOperationResult FocusOnPrefabInstance(InstanceOptionalReference focusedInstance); void RefreshInstanceFocusList(); + void OpenInstanceContainers(const AZStd::vector& instances) const; + void CloseInstanceContainers(const AZStd::vector& instances) const; + InstanceOptionalReference m_focusedInstance; TemplateId m_focusedTemplateId; AZStd::vector m_instanceFocusVector; AZ::IO::Path m_instanceFocusPath; - InstanceEntityMapperInterface* m_instanceEntityMapperInterface; + ContainerEntityInterface* m_containerEntityInterface = nullptr; + FocusModeInterface* m_focusModeInterface = nullptr; + InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr; + + bool m_isInitialized = false; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp index a0da20ebf0..3cdcade1b0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp @@ -37,51 +37,71 @@ namespace AzToolsFramework return m_handlerId; } - QString EditorEntityUiHandlerBase::GenerateItemInfoString(AZ::EntityId /*entityId*/) const + QString EditorEntityUiHandlerBase::GenerateItemInfoString([[maybe_unused]] AZ::EntityId entityId) const { return QString(); } - QString EditorEntityUiHandlerBase::GenerateItemTooltip(AZ::EntityId /*entityId*/) const + QString EditorEntityUiHandlerBase::GenerateItemTooltip([[maybe_unused]] AZ::EntityId entityId) const { return QString(); } - QIcon EditorEntityUiHandlerBase::GenerateItemIcon(AZ::EntityId /*entityId*/) const + QIcon EditorEntityUiHandlerBase::GenerateItemIcon([[maybe_unused]] AZ::EntityId entityId) const { return QIcon(); } - bool EditorEntityUiHandlerBase::CanToggleLockVisibility(AZ::EntityId /*entityId*/) const + bool EditorEntityUiHandlerBase::CanToggleLockVisibility([[maybe_unused]] AZ::EntityId entityId) const { return true; } - bool EditorEntityUiHandlerBase::CanRename(AZ::EntityId /*entityId*/) const + bool EditorEntityUiHandlerBase::CanRename([[maybe_unused]] AZ::EntityId entityId) const { return true; } - void EditorEntityUiHandlerBase::PaintItemBackground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const + void EditorEntityUiHandlerBase::PaintItemBackground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index) const { } - void EditorEntityUiHandlerBase::PaintDescendantBackground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/, - const QModelIndex& /*descendantIndex*/) const + void EditorEntityUiHandlerBase::PaintDescendantBackground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index, + [[maybe_unused]] const QModelIndex& descendantIndex) const { } - void EditorEntityUiHandlerBase::PaintDescendantBranchBackground(QPainter* /*painter*/, const QTreeView* /*view*/, const QRect& /*rect*/, - const QModelIndex& /*index*/, const QModelIndex& /*descendantIndex*/) const + void EditorEntityUiHandlerBase::PaintDescendantBranchBackground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QTreeView* view, + [[maybe_unused]] const QRect& rect, + [[maybe_unused]] const QModelIndex& index, + [[maybe_unused]] const QModelIndex& descendantIndex) const { } - void EditorEntityUiHandlerBase::PaintItemForeground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const + void EditorEntityUiHandlerBase::PaintItemForeground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index) const { } - void EditorEntityUiHandlerBase::PaintDescendantForeground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/, - const QModelIndex& /*descendantIndex*/) const + void EditorEntityUiHandlerBase::PaintDescendantForeground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index, + [[maybe_unused]] const QModelIndex& descendantIndex) const + { + } + + void EditorEntityUiHandlerBase::OnDoubleClick([[maybe_unused]] AZ::EntityId entityId) const { } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h index c37b099272..9554ad01fc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h @@ -61,6 +61,9 @@ namespace AzToolsFramework virtual void PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QModelIndex& descendantIndex) const; + //! Triggered when the entity is double clicked in the Outliner. + virtual void OnDoubleClick(AZ::EntityId entityId) const; + private: EditorEntityUiHandlerId m_handlerId = 0; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp index 2872c1bce3..234696ff2a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp @@ -88,6 +88,7 @@ namespace AzToolsFramework EntityOutlinerListModel::~EntityOutlinerListModel() { + ContainerEntityNotificationBus::Handler::BusDisconnect(); EditorEntityInfoNotificationBus::Handler::BusDisconnect(); EditorEntityContextNotificationBus::Handler::BusDisconnect(); ToolsApplicationEvents::Bus::Handler::BusDisconnect(); @@ -105,6 +106,12 @@ namespace AzToolsFramework EntityCompositionNotificationBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); + + ContainerEntityNotificationBus::Handler::BusConnect(editorEntityContextId); + m_editorEntityUiInterface = AZ::Interface::Get(); AZ_Assert(m_editorEntityUiInterface != nullptr, "EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize."); @@ -1333,12 +1340,26 @@ namespace AzToolsFramework emit EnableSelectionUpdates(true); } - void EntityOutlinerListModel::OnEntityRuntimeActivationChanged(AZ::EntityId entityId, bool activeOnStart) + void EntityOutlinerListModel::OnEntityRuntimeActivationChanged(AZ::EntityId entityId, [[maybe_unused]] bool activeOnStart) { - AZ_UNUSED(activeOnStart); QueueEntityUpdate(entityId); } + void EntityOutlinerListModel::OnContainerEntityStatusChanged(AZ::EntityId entityId, [[maybe_unused]] bool open) + { + QModelIndex changedIndex = GetIndexFromEntity(entityId); + + // Trigger a refresh of all direct children so that they can be shown or hidden appropriately. + int numChildren = rowCount(changedIndex); + if (numChildren > 0) + { + emit dataChanged(index(0, 0, changedIndex), index(numChildren - 1, ColumnCount - 1, changedIndex)); + } + + // Always expand containers + QueueEntityToExpand(entityId, true); + } + void EntityOutlinerListModel::OnEntityInfoUpdatedRemoveChildBegin([[maybe_unused]] AZ::EntityId parentId, [[maybe_unused]] AZ::EntityId childId) { //add/remove operations trigger selection change signals which assert and break undo/redo operations in progress in inspector etc. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx index 4b13aa6d27..7b946c6304 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -54,6 +55,7 @@ namespace AzToolsFramework , private EntityCompositionNotificationBus::Handler , private EditorEntityRuntimeActivationChangeNotificationBus::Handler , private AZ::EntitySystemBus::Handler + , private ContainerEntityNotificationBus::Handler { Q_OBJECT; @@ -216,6 +218,9 @@ namespace AzToolsFramework // EditorEntityRuntimeActivationChangeNotificationBus::Handler void OnEntityRuntimeActivationChanged(AZ::EntityId entityId, bool activeOnStart) override; + // ContainerEntityNotificationBus overrides ... + void OnContainerEntityStatusChanged(AZ::EntityId entityId, bool open) override; + // Drag/Drop of components from Component Palette. bool dropMimeDataComponentPalette(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp index 841a01f5e5..600ca284f4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include "EntityOutlinerListModel.hxx" namespace AzToolsFramework @@ -19,6 +21,10 @@ namespace AzToolsFramework EntityOutlinerSortFilterProxyModel::EntityOutlinerSortFilterProxyModel(QObject* pParent) : QSortFilterProxyModel(pParent) { + m_containerEntityInterface = AZ::Interface::Get(); + AZ_Assert( + m_containerEntityInterface != nullptr, + "EntityOutlinerContainerProxyModel requires a ContainerEntityInterface instance on construction."); } void EntityOutlinerSortFilterProxyModel::UpdateFilter() @@ -26,8 +32,24 @@ namespace AzToolsFramework invalidateFilter(); } + void EntityOutlinerSortFilterProxyModel::setSourceModel(QAbstractItemModel* sourceModel) + { + QSortFilterProxyModel::setSourceModel(sourceModel); + + m_listModel = qobject_cast(sourceModel); + AZ_Assert(m_listModel != nullptr, "EntityOutlinerContainerProxyModel requires an EntityOutlinerListModel as its source ."); + } + bool EntityOutlinerSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { + // Retrieve the entityId of the parent entity + AZ::EntityId parentEntityId = m_listModel->GetEntityFromIndex(sourceParent); + + if(!m_containerEntityInterface->IsContainerOpen(parentEntityId)) + { + return false; + } + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); QVariant visibilityData = sourceModel()->data(index, EntityOutlinerListModel::VisibilityRole); return visibilityData.isValid() ? visibilityData.toBool() : true; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx index b7e1a3f869..c6e1410688 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx @@ -19,11 +19,12 @@ namespace AzToolsFramework { + class ContainerEntityInterface; + class EntityOutlinerListModel; - /*! - * Enables the Outliner to filter entries based on search string. - * Enables the Outliner to do custom sorting on entries. - */ + //! Enables the Outliner to filter entries based on search string. + //! Enables the Outliner to do custom sorting on entries. + //! Enforces the correct rendering for container entities. class EntityOutlinerSortFilterProxyModel : public QSortFilterProxyModel { @@ -37,12 +38,15 @@ namespace AzToolsFramework void UpdateFilter(); // Qt overrides + void setSourceModel(QAbstractItemModel* sourceModel) override; bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; bool lessThan(const QModelIndex& left, const QModelIndex& right) const override; void sort(int column, Qt::SortOrder order) override; private: QString m_filterName; + EntityOutlinerListModel* m_listModel = nullptr; + ContainerEntityInterface* m_containerEntityInterface = nullptr; }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 689e5b5dc4..8f90d2c0d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -198,6 +198,7 @@ namespace AzToolsFramework m_proxyModel = aznew EntityOutlinerSortFilterProxyModel(this); m_proxyModel->setSourceModel(m_listModel); + m_gui->m_objectTree->setModel(m_proxyModel); // Link up signals for informing the model of tree changes using the proxy as an intermediary @@ -905,8 +906,12 @@ namespace AzToolsFramework } } - void EntityOutlinerWidget::OnTreeItemDoubleClicked(const QModelIndex& /*index*/) + void EntityOutlinerWidget::OnTreeItemDoubleClicked(const QModelIndex& index) { + if (AZ::EntityId entityId = GetEntityIdFromIndex(index); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId)) + { + entityUiHandler->OnDoubleClick(entityId); + } } void EntityOutlinerWidget::OnTreeItemExpanded(const QModelIndex& index) @@ -1142,7 +1147,7 @@ namespace AzToolsFramework { QTimer::singleShot(1, this, [this]() { m_gui->m_objectTree->setUpdatesEnabled(true); - m_gui->m_objectTree->expand(m_proxyModel->index(0,0)); + m_gui->m_objectTree->expandToDepth(0); }); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx index 78aced3587..78927359f2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx @@ -41,6 +41,7 @@ namespace AzToolsFramework { class EditorEntityUiInterface; class EntityOutlinerListModel; + class EntityOutlinerContainerProxyModel; class EntityOutlinerSortFilterProxyModel; namespace EntityOutliner @@ -117,6 +118,7 @@ namespace AzToolsFramework Ui::EntityOutlinerWidgetUI* m_gui; EntityOutlinerListModel* m_listModel; + EntityOutlinerContainerProxyModel* m_containerModel; EntityOutlinerSortFilterProxyModel* m_proxyModel; AZ::u64 m_selectionContextId; AZStd::vector m_selectedEntityIds; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 34152f8287..62842e18d5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ namespace AzToolsFramework { namespace Prefab { - + ContainerEntityInterface* PrefabIntegrationManager::s_containerEntityInterface = nullptr; EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr; PrefabFocusInterface* PrefabIntegrationManager::s_prefabFocusInterface = nullptr; PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr; @@ -89,6 +90,13 @@ namespace AzToolsFramework PrefabIntegrationManager::PrefabIntegrationManager() { + s_containerEntityInterface = AZ::Interface::Get(); + if (s_containerEntityInterface == nullptr) + { + AZ_Assert(false, "Prefab - could not get ContainerEntityInterface on PrefabIntegrationManager construction."); + return; + } + s_editorEntityUiInterface = AZ::Interface::Get(); if (s_editorEntityUiInterface == nullptr) { @@ -1057,6 +1065,7 @@ namespace AzToolsFramework void PrefabIntegrationManager::OnPrefabComponentActivate(AZ::EntityId entityId) { + // Register entity to appropriate UI Handler for UI overrides if (s_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId)) { s_editorEntityUiInterface->RegisterEntity(entityId, m_levelRootUiHandler.GetHandlerId()); @@ -1064,11 +1073,32 @@ namespace AzToolsFramework else { s_editorEntityUiInterface->RegisterEntity(entityId, m_prefabUiHandler.GetHandlerId()); + + bool prefabWipFeaturesEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + + if (prefabWipFeaturesEnabled) + { + // Register entity as a container + s_containerEntityInterface->RegisterEntityAsContainer(entityId); + } } } void PrefabIntegrationManager::OnPrefabComponentDeactivate(AZ::EntityId entityId) { + bool prefabWipFeaturesEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + + if (prefabWipFeaturesEnabled && !s_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId)) + { + // Unregister entity as a container + s_containerEntityInterface->UnregisterEntityAsContainer(entityId); + } + + // Unregister entity from UI Handler s_editorEntityUiInterface->UnregisterEntity(entityId); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 6f66b1f514..44e30b2013 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -26,6 +26,8 @@ namespace AzToolsFramework { + class ContainerEntityInterface; + namespace Prefab { class PrefabFocusInterface; @@ -134,6 +136,7 @@ namespace AzToolsFramework static const AZStd::string s_prefabFileExtension; + static ContainerEntityInterface* s_containerEntityInterface; static EditorEntityUiInterface* s_editorEntityUiInterface; static PrefabFocusInterface* s_prefabFocusInterface; static PrefabLoaderInterface* s_prefabLoaderInterface; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp index c802850c4b..7d1f3485aa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include #include @@ -317,4 +319,17 @@ namespace AzToolsFramework return Internal_GetLastVisibleChild(model, lastChild); } + + void PrefabUiHandler::OnDoubleClick(AZ::EntityId entityId) const + { + bool prefabWipFeaturesEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + + if (prefabWipFeaturesEnabled) + { + // Focus on this prefab + m_prefabFocusInterface->FocusOnOwningPrefab(entityId); + } + } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h index 547c100eb1..bb7168f409 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h @@ -29,13 +29,14 @@ namespace AzToolsFramework PrefabUiHandler(); ~PrefabUiHandler() override = default; - // EditorEntityUiHandler... + // EditorEntityUiHandler overrides ... QString GenerateItemInfoString(AZ::EntityId entityId) const override; QString GenerateItemTooltip(AZ::EntityId entityId) const override; QIcon GenerateItemIcon(AZ::EntityId entityId) const override; void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void PaintDescendantBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QModelIndex& descendantIndex) const override; + void OnDoubleClick(AZ::EntityId entityId) const override; private: Prefab::PrefabFocusInterface* m_prefabFocusInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index 57e6c9ff7a..3ce350287f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -13,8 +13,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -191,6 +192,14 @@ namespace AzToolsFramework return AZ::EntityId(); } + // Container Entity support - if the entity that is being selected is part of a closed container, + // change the selection to the container instead. + ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get(); + if (containerEntityInterface) + { + return containerEntityInterface->FindHighestSelectableEntity(entityIdUnderCursor); + } + return entityIdUnderCursor; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index f09d4f9b72..0866b225c1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -114,6 +114,10 @@ set(FILES Component/EditorLevelComponentAPIBus.h Component/EditorLevelComponentAPIComponent.cpp Component/EditorLevelComponentAPIComponent.h + ContainerEntity/ContainerEntityInterface.h + ContainerEntity/ContainerEntityNotificationBus.h + ContainerEntity/ContainerEntitySystemComponent.cpp + ContainerEntity/ContainerEntitySystemComponent.h Editor/EditorContextMenuBus.h Editor/EditorSettingsAPIBus.h Entity/EditorEntityStartStatus.h From 643bd84739048fd18785dbfb881d01ba23655e90 Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:21:21 -0500 Subject: [PATCH 036/293] Create helper function for getting threads per (#4480) * Create helper function for getting threads per group from a compute shader Added GetComputeShaderNumThreads() functions to RPIUtils. By default the function returns 1, 1, 1 in case of errors. Updated existing code that was looking for 'numthreads' attribute data with the new GetComputeShaderNumThreads() API. Signed-off-by: garrieta --- .../DiffuseProbeGridBlendDistancePass.cpp | 23 +----- .../DiffuseProbeGridBlendIrradiancePass.cpp | 23 +----- .../DiffuseProbeGridBorderUpdatePass.cpp | 23 +----- .../DiffuseProbeGridClassificationPass.cpp | 23 +----- .../DiffuseProbeGridRelocationPass.cpp | 23 +----- .../MorphTargets/MorphTargetDispatchItem.cpp | 11 +-- .../SkinnedMesh/SkinnedMeshDispatchItem.cpp | 14 ++-- .../Code/Include/Atom/RPI.Public/RPIUtils.h | 18 +++++ .../Source/RPI.Public/Pass/ComputePass.cpp | 27 ++----- .../RPI/Code/Source/RPI.Public/RPIUtils.cpp | 74 +++++++++++++++++++ 10 files changed, 122 insertions(+), 137 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp index 69a4ecdee5..cf1897054a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp @@ -54,27 +54,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeGridBlendDistancePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeGridBlendDistancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp index 83ef312bf4..f4733c833a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp @@ -54,27 +54,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp index b251526cb4..6c72f904b9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp @@ -67,27 +67,10 @@ namespace AZ srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(shader->GetAsset(), dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeGridBorderUpdatePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeGridBorderUpdatePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp index 2690f90a7d..61540c3332 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp @@ -58,27 +58,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeClassificationPass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeClassificationPass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp index 67fb95a833..a1b236ed4d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp @@ -58,27 +58,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeRelocationPass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeRelocationPass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp index 19f379b17d..fcf1402ae6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -79,15 +80,11 @@ namespace AZ m_dispatchItem.m_pipelineState = m_morphTargetShader->AcquirePipelineState(pipelineStateDescriptor); // Get the threads-per-group values from the compute shader [numthreads(x,y,z)] - const auto& numThreads = m_morphTargetShader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, AZ::Name{ "numthreads" }); auto& arguments = m_dispatchItem.m_arguments.m_direct; - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_morphTargetShader->GetAsset(), arguments); + if (!outcome.IsSuccess()) { - const auto& args = *numThreads; - // Check that the arguments are valid integers, and fall back to 1,1,1 if there is an error - arguments.m_threadsPerGroupX = static_cast(args[0].type() == azrtti_typeid() ? AZStd::any_cast(args[0]) : 1); - arguments.m_threadsPerGroupY = static_cast(args[1].type() == azrtti_typeid() ? AZStd::any_cast(args[1]) : 1); - arguments.m_threadsPerGroupZ = static_cast(args[2].type() == azrtti_typeid() ? AZStd::any_cast(args[2]) : 1); + AZ_Error("MorphTargetDispatchItem", false, outcome.GetError().c_str()); } arguments.m_totalNumberOfThreadsX = m_morphTargetMetaData.m_vertexCount; diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp index bfc533763e..5ec26cebde 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -199,17 +200,14 @@ namespace AZ m_instanceSrg->Compile(); m_dispatchItem.m_uniqueShaderResourceGroup = m_instanceSrg->GetRHIShaderResourceGroup(); m_dispatchItem.m_pipelineState = m_skinningShader->AcquirePipelineState(pipelineStateDescriptor); - - const auto& numThreads = m_skinningShader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, AZ::Name{ "numthreads" }); + auto& arguments = m_dispatchItem.m_arguments.m_direct; - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_skinningShader->GetAsset(), arguments); + if (!outcome.IsSuccess()) { - const auto& args = *numThreads; - arguments.m_threadsPerGroupX = static_cast(args[0].type() == azrtti_typeid() ? AZStd::any_cast(args[0]) : 1); - arguments.m_threadsPerGroupY = static_cast(args[1].type() == azrtti_typeid() ? AZStd::any_cast(args[1]) : 1); - arguments.m_threadsPerGroupZ = static_cast(args[2].type() == azrtti_typeid() ? AZStd::any_cast(args[2]) : 1); + AZ_Error("SkinnedMeshInputBuffers", false, outcome.GetError().c_str()); } - + arguments.m_totalNumberOfThreadsX = xThreads; arguments.m_totalNumberOfThreadsY = yThreads; arguments.m_totalNumberOfThreadsZ = 1; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h index a2972ff0fd..3e92542429 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -40,6 +41,23 @@ namespace AZ //! Loads a streaming image asset for the given file path Data::Instance LoadStreamingTexture(AZStd::string_view path); + + //! Looks for a three arguments attribute named @attributeName in the given shader asset. + //! Assigns the value to each non-null output variables. + //! @param shaderAsset + //! @param attributeName + //! @param numThreadsX Can be NULL. If not NULL it takes the value of the 1st argument of the attribute. Becomes 1 on error. + //! @param numThreadsY Can be NULL. If not NULL it takes the value of the 2nd argument of the attribute. Becomes 1 on error. + //! @param numThreadsZ Can be NULL. If not NULL it takes the value of the 3rd argument of the attribute. Becomes 1 on error. + //! @returns An Outcome instance with error message in case of error. + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, const AZ::Name& attributeName, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ); + + //! Same as above, but assumes the name of the attribute to be 'numthreads'. + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ); + + //! Same as above. Provided as a convenience when all arguments of the 'numthreads' attributes should be assigned to RHI::DispatchDirect::m_threadsPerGroup* variables. + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, RHI::DispatchDirect& dispatchDirect); + } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp index 2505409c62..8bcf9b1b85 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp @@ -107,30 +107,13 @@ namespace AZ dispatchArgs.m_totalNumberOfThreadsY = passData->m_totalNumberOfThreadsY; dispatchArgs.m_totalNumberOfThreadsZ = passData->m_totalNumberOfThreadsZ; - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[ComputePass '%s']: Shader '%s' contains invalid numthreads arguments.", - GetPathName().GetCStr(), - passData->m_shaderReference.m_filePath.data()); - return; - } - - dispatchArgs.m_threadsPerGroupX = aznumeric_cast(AZStd::any_cast(args[0])); - dispatchArgs.m_threadsPerGroupY = aznumeric_cast(AZStd::any_cast(args[1])); - dispatchArgs.m_threadsPerGroupZ = aznumeric_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[ComputePass '%s']: Shader '%.*s' contains invalid numthreads arguments:\n%s", + GetPathName().GetCStr(), passData->m_shaderReference.m_filePath.size(), passData->m_shaderReference.m_filePath.data(), outcome.GetError().c_str()); } + m_dispatchItem.m_arguments = dispatchArgs; m_isFullscreenPass = passData->m_makeFullscreenPass; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp index 9173b47fad..e70885daa1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp @@ -143,5 +143,79 @@ namespace AZ return RPI::StreamingImage::FindOrCreate(streamingImageAsset); } + + //! A helper function for GetComputeShaderNumThreads(), to consolidate error messages, etc. + static bool GetAttributeArgumentByIndex(const Data::Asset& shaderAsset, const AZ::Name& attributeName, const RHI::ShaderStageAttributeArguments& args, const size_t argIndex, uint16_t* value, AZStd::string& errorMsg) + { + if (value) + { + const auto numArguments = args.size(); + if (numArguments > argIndex) + { + if (args[argIndex].type() == azrtti_typeid()) + { + *value = aznumeric_caster(AZStd::any_cast(args[argIndex])); + } + else + { + errorMsg = AZStd::string::format("Was expecting argument '%zu' in attribute '%s' to be of type 'int' from shader asset '%s'", argIndex, attributeName.GetCStr(), shaderAsset.GetHint().c_str()); + return false; + } + } + else + { + errorMsg = AZStd::string::format("Was expecting at least '%zu' arguments in attribute '%s' from shader asset '%s'", argIndex + 1, attributeName.GetCStr(), shaderAsset.GetHint().c_str()); + return false; + } + } + return true; + } + + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, const AZ::Name& attributeName, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ) + { + // Set default 1, 1, 1 now. In case of errors later this is what the caller will get. + if (numThreadsX) + { + *numThreadsX = 1; + } + if (numThreadsY) + { + *numThreadsY = 1; + } + if (numThreadsZ) + { + *numThreadsZ = 1; + } + const auto numThreads = shaderAsset->GetAttribute(RHI::ShaderStage::Compute, attributeName); + if (!numThreads) + { + return AZ::Failure(AZStd::string::format("Couldn't find attribute '%s' in shader asset '%s'", attributeName.GetCStr(), shaderAsset.GetHint().c_str())); + } + const RHI::ShaderStageAttributeArguments& args = *numThreads; + AZStd::string errorMsg; + if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 0, numThreadsX, errorMsg)) + { + return AZ::Failure(errorMsg); + } + if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 1, numThreadsY, errorMsg)) + { + return AZ::Failure(errorMsg); + } + if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 2, numThreadsZ, errorMsg)) + { + return AZ::Failure(errorMsg); + } + return AZ::Success(); + } + + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ) + { + return GetComputeShaderNumThreads(shaderAsset, Name{ "numthreads" }, numThreadsX, numThreadsY, numThreadsZ); + } + + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, RHI::DispatchDirect& dispatchDirect) + { + return GetComputeShaderNumThreads(shaderAsset, &dispatchDirect.m_threadsPerGroupX, &dispatchDirect.m_threadsPerGroupY, &dispatchDirect.m_threadsPerGroupZ); + } } } From f648cb1fd88ceeacada17e827d944bf124a195d0 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 5 Oct 2021 15:12:53 -0500 Subject: [PATCH 037/293] Update the FileIO Aliases (#4186) * Update the FileIOAlias naming to make the cache, project root and engine root paths more clear The alias of `@root@`, `@assets@`, and `@projectplatformcache@` has been collapsed to `@projectproductassets@` The alias of `@devroot@` and `@engroot@` has been collapsed to `@engroot@` The alias of `@devassets@` and `@projectroot@` has been collapsed to `@projectroot@` Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated use of devassets and devroot properties in python Those properties now use projectroot and engroot Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updating the alias @engroot@ alias path comment in each platform specific LocalFileIO_*.cpp file Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed hardcoded size of 9 for the product asset alias. The ResolvePath function now just appends the @projectproductassets@ alias with the input path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove duplicate @projectproductassets@ check in ProcessFileTreeRequest Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix for typos in Hydra python test Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated LocalFileIO::Copy call on Windows to use the Unicode aware CopyFileW API Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AWSMetreicsGemAllocatorFixture to properly suppress asset cache write errors for Test file creation. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed unneeded call to set the @projectproductasstes@ alias at the bottom of the AssetSeedManagerTest SetUp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added a deprecated alias map to the FileIO System When a deprecated alias is accessed, the FileIO System logs an AZ_Error and indicates the alias that should be used Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated python test scripts to use the projectroot binding Retrieving the AutomatedTesting project path based on "/AutomatedTesting" has been removed. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated references to devroot and devgame within the codebase The GetAbsoluteDevGameFolderPath functions has been replaced with direct call to AZ::Utils::GetProjectPath The GetAbsoluteDevRootFolderPath functions has been replaced with direct calls to AZ::Utils::GetEnginePath Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated /AutomatedTesting references to projectroot Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced references that assumes the project path is /AutomatedTesting with in the AutomatedTesting python test Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Correct casing in emfxworkspace file Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed newly added AppendPathParts function Removed the Path constructors which accepts a PathIterable instance The PathIterable isn't safe to return to a user of the Path class as it might be referencing temporary paths supplied via PathView arguments Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed unused parameter warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Undid change to the LexicallyProximate function to set the path result to the base path. It needs to return the *this path if the pathResult is empty Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Moved the LocalFileIO ConvertToAbsolutePath implementations to AZ::Utils Fixed the ConvertToAbsolutePath implementation for Unix platforms to use a buffer that is size PATH_MAX(4096 on all our supported Unix platforms). Because the buffer before was AZ::IO::MaxPathLength which as a size of 1024, this was resulting in the Unix `realpath` function smashing the stack when it converts a path to an absolute path that is longer than 1024 characters Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the EditorCore.Tests to attach the AZ Environment to the EditorCore shared library that is statically loaded on launch. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed for DeprecatedAlaisesKeyVisitor Visit function causing the non string_view overloads being hidden causing a hidden base class function warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed the AWSMetricsGemMock to use a temporary for writing test assets Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the LocalFileIO::ResolvePath function to use HasRootPath to determine if a path starts with a root path such as "D:", "D:/" or "/" IsAbsolute was not the corect check as the path of "D:" is a relative path. To be absolute according to the Windows the path must have a root directory. i.e "D:/" or "D:\" Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed absolute path comment from LocalFile_UnixLike.cpp and LocalFile_Android.cpp FindFiles implementations Updated the ConvertToAlias to supply an AZ::IO::FixedMaxPath Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced usage of the @projectproductassets@ alias with @engroot@ when referring to the LmbrCentral source folder in the CopyDependencyBuilderTest and the SeedBuilderTests Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the ScriptCanvas Upgrade Tool to output backed up files to the Project User Path instead of the engine root Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed whitespacing issues in Application.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove unnecessary creation of a FixedMaxPath in the UpgradeTool.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Modified testSeedFolder variable in the SeedBuilderTests to use the @engroot@ alias instead of @projectproductassets@/.. alias when referring to the LmbrCentral Gem source path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated references to the Project Asset Cache in the PythonTests. Those tests no longer use the logic `azlmbr.paths.projectroot / "Cache" / "pc"` to retrieve a path to the cache root but instead the `azlmbr.paths.projectproductassets` constant Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed the FileIO Deprecated Alias test on Windows Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removing @projectsourceassets@ alias, as it is only used once. Updated the PhysX EditorSystemComponent.cpp to query the ProjectPath form the SettingsRegistry. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced @projectproductassets@ alias with @products@ Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Rollback changes to the PhysX EditorSystemComponent.cpp The changes to use the ProjectPath from the SettingsRegistry has been implemented in PR #4497 Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Assets/Engine/exclude.filetag | 32 --- .../Atom/atom_utils/material_editor_utils.py | 2 +- ...ydra_AtomEditorComponents_AddedToEntity.py | 2 +- ...dra_AtomEditorComponents_LightComponent.py | 2 +- .../hydra_AtomMaterialEditor_BasicTests.py | 16 +- ...GPUTest_AtomFeatureIntegrationBenchmark.py | 2 +- .../tests/hydra_GPUTest_BasicLevelSetup.py | 2 +- .../tests/hydra_GPUTest_LightComponent.py | 2 +- .../EditorCommandLine_test.py | 1 - .../EditorCommandLine_test_case.py | 6 - .../ComponentUpdateListProperty_test_case.py | 2 +- .../LevelComponentCommands.cfg | 2 +- .../ViewportTitleDlgCommands.cfg | 2 +- ...ynamicSliceInstanceSpawner_Embedded_E2E.py | 2 +- ...ynamicSliceInstanceSpawner_External_E2E.py | 2 +- .../EditorScripts/LayerBlender_E2E_Editor.py | 2 +- .../editor_dynveg_test_helper.py | 6 +- .../cowboy.emfxworkspace | 2 +- .../ws.emfxworkspace | 2 +- Code/Editor/Controls/FolderTreeCtrl.cpp | 13 +- Code/Editor/Core/Tests/test_Main.cpp | 2 + Code/Editor/Core/Tests/test_PathUtil.cpp | 37 ++-- Code/Editor/CryEdit.cpp | 2 +- Code/Editor/CryEditDoc.cpp | 4 +- Code/Editor/Dialogs/PythonScriptsDialog.cpp | 2 +- Code/Editor/EditorFileMonitor.cpp | 36 +--- .../SandboxIntegration.cpp | 2 +- .../AssetImporterWindow.cpp | 79 +++---- .../SceneSerializationHandler.cpp | 25 +-- .../ProjectSettingsToolWindow.cpp | 1 - .../ProjectSettingsToolWindow.h | 1 - .../Plugins/ProjectSettingsTool/Utils.cpp | 34 ++- .../Plugins/ProjectSettingsTool/Utils.h | 2 +- Code/Editor/Settings.cpp | 5 +- .../TrackView/SequenceBatchRenderDialog.cpp | 26 +-- Code/Editor/Util/PathUtil.cpp | 200 +++--------------- Code/Editor/Util/PathUtil.h | 90 -------- Code/Framework/AzCore/AzCore/IO/FileIO.h | 15 +- Code/Framework/AzCore/AzCore/IO/IStreamer.h | 32 +-- Code/Framework/AzCore/AzCore/IO/Path/Path.h | 52 +++-- Code/Framework/AzCore/AzCore/IO/Path/Path.inl | 83 +++++--- .../AzCore/AzCore/IO/Path/PathIterable.inl | 2 +- .../Settings/SettingsRegistryMergeUtils.cpp | 6 +- .../AzCore/UnitTest/Mocks/MockFileIOBase.h | 1 + Code/Framework/AzCore/AzCore/Utils/Utils.cpp | 14 ++ Code/Framework/AzCore/AzCore/Utils/Utils.h | 1 + .../Android/AzCore/Utils/Utils_Android.cpp | 33 ++- .../UnixLike/AzCore/Utils/Utils_UnixLike.cpp | 31 ++- .../WinAPI/AzCore/Utils/Utils_WinAPI.cpp | 17 +- .../AzCore/Tests/FileIOBaseTestTypes.h | 4 + .../AzCore/Tests/IO/Path/PathTests.cpp | 2 +- .../AzFramework/Application/Application.cpp | 89 ++++++-- .../AzFramework/Archive/Archive.cpp | 6 +- .../AzFramework/Archive/ArchiveFileIO.cpp | 10 + .../AzFramework/Archive/ArchiveFileIO.h | 1 + .../AzFramework/Archive/ArchiveFindData.cpp | 18 +- .../AzFramework/Archive/MissingFileReport.cpp | 2 +- .../AzFramework/Asset/AssetCatalog.cpp | 2 +- .../AzFramework/AzFramework/Gem/GemInfo.cpp | 2 +- .../AzFramework/IO/LocalFileIO.cpp | 119 ++++++++--- .../AzFramework/AzFramework/IO/LocalFileIO.h | 6 +- .../AzFramework/IO/RemoteFileIO.cpp | 30 ++- .../AzFramework/AzFramework/IO/RemoteFileIO.h | 2 + .../AzFramework/IO/LocalFileIO_Android.cpp | 62 ++---- .../AzFramework/IO/LocalFileIO_UnixLike.cpp | 50 ++--- .../AzFramework/IO/LocalFileIO_WinAPI.cpp | 33 +-- .../AzFramework/IO/LocalFileIO_Windows.cpp | 32 ++- .../AzFramework/Tests/Application.cpp | 2 +- .../AzFramework/Tests/ArchiveTests.cpp | 62 +++--- Code/Framework/AzFramework/Tests/FileIO.cpp | 45 ++++ .../AzFramework/Tests/FileTagTests.cpp | 18 +- .../AzFramework/Tests/GenAppDescriptors.cpp | 110 ++++------ .../Application/GameApplication.cpp | 4 +- .../Utilities/EncryptionCommon.cpp | 2 +- .../API/EditorAssetSystemAPI.h | 8 - .../Asset/AssetSystemComponent.cpp | 20 -- .../Asset/AssetSystemComponent.h | 2 - .../AssetEditor/AssetEditorWidget.cpp | 2 +- .../AzToolsFramework/Debug/TraceContext.h | 2 +- .../AzToolsFramework/Logger/TraceLogger.cpp | 2 +- .../Slice/SliceRequestComponent.cpp | 9 +- .../Slice/SliceTransaction.cpp | 6 +- .../ToolsComponents/EditorLayerComponent.cpp | 4 +- .../UI/Prefab/PrefabIntegrationManager.cpp | 2 +- .../AzToolsFramework/Tests/ArchiveTests.cpp | 4 +- .../Tests/AssetSeedManager.cpp | 34 ++- .../AzToolsFramework/Tests/AssetSystemMocks.h | 2 - .../AzToolsFramework/Tests/EntityTestbed.h | 4 +- .../PlatformAddressedAssetCatalogTests.cpp | 8 +- .../SliceStabilityTestFramework.h | 2 - Code/Legacy/CryCommon/CryPath.h | 6 +- Code/Legacy/CrySystem/ConsoleBatchFile.cpp | 6 +- Code/Legacy/CrySystem/DebugCallStack.cpp | 2 +- .../CrySystem/LevelSystem/LevelSystem.cpp | 2 +- Code/Legacy/CrySystem/SystemCFG.cpp | 10 +- Code/Legacy/CrySystem/SystemInit.cpp | 9 +- .../Android/InitializeCerts_Android.cpp | 2 +- .../AssetBuilder/AssetBuilderComponent.cpp | 17 +- .../native/AssetManager/AssetCatalog.cpp | 46 ++-- .../native/AssetManager/AssetCatalog.h | 4 - .../AssetManager/assetProcessorManager.cpp | 9 +- .../AssetManager/assetProcessorManager.h | 2 - .../native/FileServer/fileServer.cpp | 16 +- .../AssetCatalog/AssetCatalogUnitTests.cpp | 4 +- .../unittests/RCcontrollerUnitTests.cpp | 26 +-- .../native/unittests/UnitTestRunner.h | 3 +- .../utilities/GUIApplicationManager.cpp | 9 +- .../CrashHandler/Tools/ToolsCrashHandler.cpp | 2 +- .../tests/ApplicationTests.cpp | 2 +- .../SceneCore/Export/MtlMaterialExporter.cpp | 13 +- .../SerializeContextTools/SliceConverter.cpp | 8 +- .../Configuration/AWSCoreConfiguration.cpp | 2 +- .../Source/Editor/UI/AWSCoreEditorMenu.cpp | 2 +- .../AWSCoreConfigurationTest.cpp | 6 +- .../Tests/Editor/UI/AWSCoreEditorMenuTest.cpp | 2 +- .../Code/Source/IdentityProvider.cpp | 2 +- .../AWSMetrics/Code/Tests/AWSMetricsGemMock.h | 40 ++-- .../Source/AssetValidationSystemComponent.cpp | 8 +- .../BuilderSettings/BuilderSettingManager.cpp | 2 +- .../Editor/ShaderVariantAssetBuilder.cpp | 50 ++--- Gems/Atom/RHI/Code/Tests/UtilsTests.cpp | 2 +- .../Include/Atom/RPI.Edit/Common/AssetUtils.h | 10 +- .../RPI/Code/Tests/Common/AssetSystemStub.cpp | 10 - .../RPI/Code/Tests/Common/AssetSystemStub.h | 2 - .../RPI/Code/Tests/Common/RPITestFixture.cpp | 6 +- .../Application/AtomToolsApplication.cpp | 6 +- .../CreateMaterialDialog.cpp | 2 +- .../MaterialEditorBrowserInteractions.cpp | 4 +- .../ViewportSettingsInspector.cpp | 2 +- .../Scripts/GenerateAllMaterialScreenshots.py | 6 +- .../GenerateShaderVariantListForMaterials.py | 2 +- .../AtomFont/Code/Source/AtomFont.cpp | 2 +- .../EditorDiffuseProbeGridComponent.cpp | 4 +- .../EditorMaterialComponentInspector.cpp | 2 +- .../EditorReflectionProbeComponent.cpp | 2 +- .../Builder/AudioControlBuilderWorker.cpp | 10 +- .../Source/Builder/WwiseBuilderWorker.cpp | 8 +- .../Tests/AudioEngineWwiseBuilderTest.cpp | 16 +- .../Code/Tests/AudioEngineWwiseTest.cpp | 20 +- .../Code/Source/Engine/ATLComponents.cpp | 2 +- .../Components/BlastSystemComponent.cpp | 4 +- .../Code/Source/DataSource/FileDataSource.cpp | 14 +- .../EMotionFX/Source/EMotionFXManager.cpp | 14 +- .../EMStudioSDK/Source/FileManager.cpp | 22 +- .../EMStudioSDK/Source/MainWindow.cpp | 28 +-- .../EMStudioSDK/Source/Workspace.cpp | 2 +- .../Integration/Assets/AnimGraphAsset.cpp | 14 +- .../Integration/Assets/MotionSetAsset.cpp | 20 +- .../Integration/System/SystemComponent.cpp | 6 +- ...MotionSetWhenSameMotionInTwoMotionSets.cpp | 6 +- .../Code/Tests/CommandRemoveMotionTests.cpp | 2 +- .../Code/Tests/EMotionFXBuilderTests.cpp | 16 +- .../Tests/Editor/MotionSetLoadEscalation.cpp | 2 +- .../Tests/Game/SamplePerformanceTests.cpp | 18 +- .../Code/Tests/Integration/CanAddActor.cpp | 2 +- .../Tests/Integration/PoseComparisonTests.cpp | 24 +-- .../AnimGraph/PreviewMotionFixture.cpp | 6 +- .../ProvidesUI/Menus/FileMenu/CanReset.cpp | 2 +- .../ProvidesUI/Motions/CanAddMotions.cpp | 2 +- .../Motions/MotionPlaybacksTests.cpp | 2 +- .../Code/Tests/UI/CanAutoSaveFile.cpp | 2 +- .../Code/Tests/UI/CanUseFileMenu.cpp | 2 +- .../Assets/release_notes.md | 2 +- .../Code/Source/PythonReflectionComponent.cpp | 12 +- .../Code/Source/PythonSystemComponent.cpp | 4 +- .../Code/Tests/PythonBindingLibTests.cpp | 8 +- .../Tests/PythonReflectionComponentTests.cpp | 13 +- .../Code/Tests/PythonTestingUtility.h | 1 - .../GameStateLevelLoading.inl | 2 +- .../GameStateSamples/GameStateLevelPaused.inl | 2 +- .../GameStateLevelRunning.inl | 2 +- .../GameStateLocalUserLobby.inl | 4 +- .../GameStateSamples/GameStateMainMenu.inl | 2 +- .../GameStateSamples/GameStateOptionsMenu.inl | 2 +- .../GameStatePrimaryUserSelection.inl | 2 +- .../GraphCanvas/Styling/StyleManager.cpp | 12 +- .../Android/InAppPurchasesAndroid.cpp | 10 +- .../EmfxWorkspaceBuilderWorker.cpp | 8 +- .../LevelBuilder/LevelBuilderWorker.cpp | 2 +- .../MaterialBuilderComponent.cpp | 48 ++--- .../Bundling/BundlingSystemComponent.cpp | 4 +- Gems/LmbrCentral/Code/Source/LmbrCentral.cpp | 2 +- .../Builders/CopyDependencyBuilderTest.cpp | 14 +- .../Code/Tests/Builders/LevelBuilderTest.cpp | 6 +- .../Code/Tests/Builders/LuaBuilderTests.cpp | 4 +- .../Tests/Builders/MaterialBuilderTests.cpp | 17 +- .../Code/Tests/Builders/SeedBuilderTests.cpp | 10 +- .../Tests/BundlingSystemComponentTests.cpp | 46 ++-- .../productdependencies.emfxworkspace | 2 +- .../Code/Tests/Materials/test_mat17.mtl | 2 +- Gems/LyShine/Code/Editor/EditorMenu.cpp | 10 +- Gems/LyShine/Code/Editor/UiSliceManager.cpp | 6 +- Gems/LyShine/Code/Source/UiCanvasManager.cpp | 12 +- Gems/LyShine/Code/Tests/LyShineEditorTest.cpp | 8 +- .../Code/Source/LyShineMessagePopup.cpp | 8 +- .../AnimationEditorFiles/Cowboy.emfxworkspace | 2 +- .../Source/QtForPythonSystemComponent.cpp | 3 - .../Tests/SceneBuilder/SceneBuilderTests.cpp | 15 +- .../ScriptCanvas/Assets/ScriptCanvasAsset.h | 2 +- .../CommonSettingsConfigurations.cpp | 19 +- .../Code/Editor/View/Windows/MainWindow.cpp | 133 ++++++------ .../Code/Editor/View/Windows/MainWindow.h | 2 +- .../Windows/Tools/UpgradeTool/UpgradeTool.cpp | 60 ++---- .../Windows/Tools/UpgradeTool/UpgradeTool.h | 3 +- .../Tools/UpgradeTool/VersionExplorer.cpp | 71 ++----- .../ScriptCanvas/Asset/ExecutionLogAsset.cpp | 2 +- .../Include/ScriptCanvas/Asset/RuntimeAsset.h | 4 +- .../Code/Source/EditorWhiteBoxComponent.cpp | 17 +- Registry/fileio.setreg | 26 +++ 209 files changed, 1367 insertions(+), 1680 deletions(-) create mode 100644 Registry/fileio.setreg diff --git a/Assets/Engine/exclude.filetag b/Assets/Engine/exclude.filetag index 52534a87d8..3528454ec4 100644 --- a/Assets/Engine/exclude.filetag +++ b/Assets/Engine/exclude.filetag @@ -125,17 +125,6 @@ - - - - - - - - - - - @@ -207,27 +196,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py index ef0a592df0..b21c74de19 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py @@ -211,7 +211,7 @@ class Timeout: return time.time() > self.die_after -screenshotsFolder = os.path.join(azlmbr.paths.devroot, "AtomTest", "Cache" "pc", "Screenshots") +screenshotsFolder = os.path.join(azlmbr.paths.products, "Screenshots") class ScreenshotHelper: diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py index 602e7564b3..bbc8463152 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py @@ -17,7 +17,7 @@ import azlmbr.legacy.general as general import azlmbr.editor as editor import azlmbr.render as render -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import TestHelper diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py index 751f425916..7ecdc6859b 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py @@ -14,7 +14,7 @@ import azlmbr.math as math import azlmbr.paths import azlmbr.legacy.general as general -sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from Atom.atom_utils.atom_constants import LIGHT_TYPES diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py index 88a1ef4c7b..9f8f6c44b2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py @@ -16,7 +16,7 @@ import time import azlmbr.math as math import azlmbr.paths -sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import Atom.atom_utils.material_editor_utils as material_editor @@ -27,10 +27,10 @@ TEST_MATERIAL_1 = "001_DefaultWhite.material" TEST_MATERIAL_2 = "002_BaseColorLerp.material" TEST_MATERIAL_3 = "003_MetalMatte.material" TEST_DATA_PATH = os.path.join( - azlmbr.paths.devroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases" + azlmbr.paths.engroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases" ) MATERIAL_TYPE_PATH = os.path.join( - azlmbr.paths.devroot, "Gems", "Atom", "Feature", "Common", "Assets", + azlmbr.paths.engroot, "Gems", "Atom", "Feature", "Common", "Assets", "Materials", "Types", "StandardPBR.materialtype", ) CACHE_FILE_EXTENSION = ".azmaterial" @@ -61,7 +61,7 @@ def run(): print(f"Material opened: {material_editor.is_open(document_id)}") # Verify if the test material exists initially - target_path = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL) + target_path = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL) print(f"Test asset doesn't exist initially: {not os.path.exists(target_path)}") # 2) Test Case: Creating a New Material Using Existing One @@ -109,10 +109,10 @@ def run(): # Assign new color to the material file and save the document as copy expected_color_1 = math.Color(0.5, 0.5, 0.5, 1.0) material_editor.set_property(document_id, property_name, expected_color_1) - target_path_1 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_1) + target_path_1 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_1) cache_file_name_1 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_1', '.material') cache_file_1 = f"{cache_file_name_1[0]}{CACHE_FILE_EXTENSION}" - target_path_1_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_1) + target_path_1_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_1) material_editor.save_document_as_copy(document_id, target_path_1) material_editor.wait_for_condition(lambda: os.path.exists(target_path_1_cache), 4.0) @@ -120,10 +120,10 @@ def run(): # Assign new color to the material file save the document as child expected_color_2 = math.Color(0.75, 0.75, 0.75, 1.0) material_editor.set_property(document_id, property_name, expected_color_2) - target_path_2 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_2) + target_path_2 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_2) cache_file_name_2 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_2', '.material') cache_file_2 = f"{cache_file_name_2[0]}{CACHE_FILE_EXTENSION}" - target_path_2_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_2) + target_path_2_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_2) material_editor.save_document_as_child(document_id, target_path_2) material_editor.wait_for_condition(lambda: os.path.exists(target_path_2_cache), 4.0) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py index 4f7edeba75..92199bf196 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py @@ -10,7 +10,7 @@ import sys import azlmbr.legacy.general as general -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.editor_test_helper import EditorTestHelper diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py index 62a122a723..ac28e67fa1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py @@ -17,7 +17,7 @@ import azlmbr.math as math import azlmbr.paths import azlmbr.editor as editor -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.editor_test_helper import EditorTestHelper diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py index 4a3ae8c85d..1c3e6226c1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py @@ -14,7 +14,7 @@ import azlmbr.math as math import azlmbr.paths import azlmbr.legacy.general as general -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py index 1d3ca11618..fcce6eab37 100755 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py @@ -42,7 +42,6 @@ class TestEditorAutomation(object): "editor command line arg bar", "editor command line arg baz", "editor engroot set", - "editor devroot set", "path resolved worked" ] diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py index bd8791fad6..c6ae65612f 100755 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py @@ -20,12 +20,6 @@ if (engroot is not None and len(engroot) is not 0): print ('engroot is {}'.format(engroot)) print ('editor engroot set') -# make sure the @devroot@ exists as a azlmbr.paths property -devroot = azlmbr.paths.devroot -if (devroot is not None and len(devroot) != 0): - print ('devroot is {}'.format(devroot)) - print ('editor devroot set') - # resolving a basic path path = azlmbr.paths.resolve_path('@engroot@/engineassets/texturemsg/defaultsolids.mtl') if (len(path) != 0 and path.find('@engroot@') == -1): diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py index 5b7f2f42c1..c5ca4de603 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py @@ -16,7 +16,7 @@ import azlmbr.entity as entity import azlmbr.math as math import azlmbr.paths -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) +sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests')) from automatedtesting_shared.editor_test_helper import EditorTestHelper diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg index 3adc32d20a..ccc605cec9 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg @@ -1,2 +1,2 @@ # this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test -pyRunFile @devroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done \ No newline at end of file +pyRunFile @engroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg index 6230dfe0fa..3cbd84c1b5 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg @@ -1,2 +1,2 @@ # this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test -pyRunFile @devroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py \ No newline at end of file +pyRunFile @engroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py index e51be58ec6..84c661873c 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py @@ -109,7 +109,7 @@ def DynamicSliceInstanceSpawner_Embedded_E2E(): # 6) Save and export to engine general.save_level() general.export_to_engine() - pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak") + pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") Report.result(Tests.saved_and_exported, os.path.exists(pak_path)) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py index 7a0abdd969..de2554034f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py @@ -131,7 +131,7 @@ def DynamicSliceInstanceSpawner_External_E2E(): # 6) Save and export to engine general.save_level() general.export_to_engine() - pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak") + pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") Report.result(Tests.saved_and_exported, os.path.exists(pak_path)) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py index f56c0b836e..bf6501f469 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py @@ -155,7 +155,7 @@ def LayerBlender_E2E_Editor(): # 6) Save and export to engine general.save_level() general.export_to_engine() - pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak") + pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") Report.result(Tests.saved_and_exported, os.path.exists(pak_path)) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py index 65ebf8e59e..957536fffb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py @@ -17,7 +17,7 @@ import azlmbr.vegetation as vegetation import azlmbr.areasystem as areasystem import azlmbr.paths -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) +sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests')) import editor_python_test_tools.hydra_editor_utils as hydra @@ -25,7 +25,7 @@ def create_surface_entity(name, center_point, box_size_x, box_size_y, box_size_z # Create a "flat surface" entity to use as a plantable vegetation surface surface_entity = hydra.Entity(name) surface_entity.create_entity( - center_point, + center_point, ["Box Shape", "Shape Surface Tag Emitter"] ) if surface_entity.id.IsValid(): @@ -56,7 +56,7 @@ def create_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_ # Create a vegetation area entity to use as our test vegetation spawner spawner_entity = hydra.Entity(name) spawner_entity.create_entity( - center_point, + center_point, ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"] ) if spawner_entity.id.IsValid(): diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace b/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace index 188fee9f05..05140f340b 100644 --- a/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace +++ b/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n" +startScript="ImportActor -filename \"@products@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n" diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace index e429d74a57..870b9a8579 100644 --- a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace +++ b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/rin_physics.animgraph\"\n" +startScript="ImportActor -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_physics.animgraph\"\n" diff --git a/Code/Editor/Controls/FolderTreeCtrl.cpp b/Code/Editor/Controls/FolderTreeCtrl.cpp index b1cbb9414e..4088ab976f 100644 --- a/Code/Editor/Controls/FolderTreeCtrl.cpp +++ b/Code/Editor/Controls/FolderTreeCtrl.cpp @@ -278,17 +278,16 @@ void CFolderTreeCtrl::LoadTreeRec(const QString& currentFolder) void CFolderTreeCtrl::AddItem(const QString& path) { - QString folder; - QString fileNameWithoutExtension; - QString ext; - - Path::Split(path, folder, fileNameWithoutExtension, ext); + AZ::IO::FixedMaxPath folder{ AZ::IO::PathView(path.toUtf8().constData()) }; + AZ::IO::FixedMaxPath fileNameWithoutExtension = folder.Extension(); + folder = folder.ParentPath(); auto regex = QRegExp(m_fileNameSpec, Qt::CaseInsensitive, QRegExp::Wildcard); if (regex.exactMatch(path)) { - CTreeItem* folderTreeItem = CreateFolderItems(folder); - folderTreeItem->AddChild(fileNameWithoutExtension, path, eTreeImage_File); + CTreeItem* folderTreeItem = CreateFolderItems(QString::fromUtf8(folder.c_str(), static_cast(folder.Native().size()))); + folderTreeItem->AddChild(QString::fromUtf8(fileNameWithoutExtension.c_str(), + static_cast(fileNameWithoutExtension.Native().size())), path, eTreeImage_File); } } diff --git a/Code/Editor/Core/Tests/test_Main.cpp b/Code/Editor/Core/Tests/test_Main.cpp index 3d3e286f18..16b0aa92cf 100644 --- a/Code/Editor/Core/Tests/test_Main.cpp +++ b/Code/Editor/Core/Tests/test_Main.cpp @@ -33,6 +33,7 @@ public: protected: void SetupEnvironment() override { + AttachEditorCoreAZEnvironment(AZ::Environment::GetInstance()); m_allocatorScope.ActivateAllocators(); m_cryPak = new NiceMock(); @@ -49,6 +50,7 @@ protected: { delete m_cryPak; m_allocatorScope.DeactivateAllocators(); + DetachEditorCoreAZEnvironment(); } private: diff --git a/Code/Editor/Core/Tests/test_PathUtil.cpp b/Code/Editor/Core/Tests/test_PathUtil.cpp index 83e50a5947..cade19eb81 100644 --- a/Code/Editor/Core/Tests/test_PathUtil.cpp +++ b/Code/Editor/Core/Tests/test_PathUtil.cpp @@ -5,22 +5,29 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include "EditorDefs.h" -#include -#include "Util/PathUtil.h" -#include - -TEST(PathUtil, GamePathToFullPath_DoesNotBufferOverflow) +#include +#include +namespace UnitTest { - // There are no test assertions in this test because the purpose is just to verify that the test runs without crashing - QString pngExtension(".png"); + class PathUtil + : public ScopedAllocatorSetupFixture + { + }; + + TEST_F(PathUtil, GamePathToFullPath_DoesNotBufferOverflow) + { + // There are no test assertions in this test because the purpose is just to verify that the test runs without crashing + QString pngExtension(".png"); - // Create a string of lenth AZ_MAX_PATH_LEN that ends in .png - QString longStringMaxPath(AZ_MAX_PATH_LEN, 'x'); - longStringMaxPath.replace(longStringMaxPath.length() - pngExtension.length(), longStringMaxPath.length(), pngExtension); - Path::GamePathToFullPath(longStringMaxPath); + // Create a string of length AZ_MAX_PATH_LEN that ends in .png + QString longStringMaxPath(AZ_MAX_PATH_LEN, 'x'); + longStringMaxPath.replace(longStringMaxPath.length() - pngExtension.length(), longStringMaxPath.length(), pngExtension); + AZ_TEST_START_TRACE_SUPPRESSION; + Path::GamePathToFullPath(longStringMaxPath); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; - QString longStringMaxPathPlusOne(AZ_MAX_PATH_LEN + 1, 'x'); - longStringMaxPathPlusOne.replace(longStringMaxPathPlusOne.length() - pngExtension.length(), longStringMaxPathPlusOne.length(), pngExtension); - Path::GamePathToFullPath(longStringMaxPathPlusOne); + QString longStringMaxPathPlusOne(AZ_MAX_PATH_LEN + 1, 'x'); + longStringMaxPathPlusOne.replace(longStringMaxPathPlusOne.length() - pngExtension.length(), longStringMaxPathPlusOne.length(), pngExtension); + Path::GamePathToFullPath(longStringMaxPathPlusOne); + } } diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index b5eb4229df..4aa3d22114 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -2642,7 +2642,7 @@ void CCryEditApp::OnFileResaveSlices() sliceAssetInfos.reserve(5000); AZ::Data::AssetCatalogRequests::AssetEnumerationCB sliceCountCb = [&sliceAssetInfos]([[maybe_unused]] const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info) { - // Only add slices and nothing that has been temporarily added to the catalog with a macro in it (ie @devroot@) + // Only add slices and nothing that has been temporarily added to the catalog with a macro in it (ie @engroot@) if (info.m_assetType == azrtti_typeid() && info.m_relativePath[0] != '@') { sliceAssetInfos.push_back(info); diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp index 07d946c609..75bd0ad270 100644 --- a/Code/Editor/CryEditDoc.cpp +++ b/Code/Editor/CryEditDoc.cpp @@ -1108,7 +1108,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename) if (QFileInfo(filename).isRelative()) { // Resolving the path through resolvepath would normalize and lowcase it, and in this case, we don't want that. - fullPathName = Path::ToUnixPath(QDir(QString::fromUtf8(gEnv->pFileIO->GetAlias("@devassets@"))).absoluteFilePath(fullPathName)); + fullPathName = Path::ToUnixPath(QDir(QString::fromUtf8(gEnv->pFileIO->GetAlias("@projectroot@"))).absoluteFilePath(fullPathName)); } if (!CFileUtil::OverwriteFile(fullPathName)) @@ -2159,7 +2159,7 @@ bool CCryEditDoc::LoadXmlArchiveArray(TDocMultiArchive& arrXmlAr, const QString& xmlAr.bLoading = true; // bound to the level folder, as if it were the assets folder. - // this mounts (whateverlevelname.ly) as @assets@/Levels/whateverlevelname/ and thus it works... + // this mounts (whateverlevelname.ly) as @products@/Levels/whateverlevelname/ and thus it works... bool openLevelPakFileSuccess = pIPak->OpenPack(levelPath.toUtf8().data(), absoluteLevelPath.toUtf8().data()); if (!openLevelPakFileSuccess) { diff --git a/Code/Editor/Dialogs/PythonScriptsDialog.cpp b/Code/Editor/Dialogs/PythonScriptsDialog.cpp index e95fb90c0a..35047947ac 100644 --- a/Code/Editor/Dialogs/PythonScriptsDialog.cpp +++ b/Code/Editor/Dialogs/PythonScriptsDialog.cpp @@ -91,7 +91,7 @@ CPythonScriptsDialog::CPythonScriptsDialog(QWidget* parent) { AZ::IO::Path newSourcePath = jsonSourcePathPointer; // Resolve any file aliases first - Do not use ResolvePath() as that assumes - // any relative path is underneath the @assets@ alias + // any relative path is underneath the @products@ alias if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { AZ::IO::FixedMaxPath replacedAliasPath; diff --git a/Code/Editor/EditorFileMonitor.cpp b/Code/Editor/EditorFileMonitor.cpp index 7feb9d32a8..311c42befa 100644 --- a/Code/Editor/EditorFileMonitor.cpp +++ b/Code/Editor/EditorFileMonitor.cpp @@ -14,6 +14,8 @@ // Editor #include "CryEdit.h" +#include + ////////////////////////////////////////////////////////////////////////// CEditorFileMonitor::CEditorFileMonitor() { @@ -177,26 +179,14 @@ void CEditorFileMonitor::OnFileMonitorChange(const SFileChangeInfo& rChange) // Make file relative to PrimaryCD folder. QString filename = rChange.filename; - // Remove game directory if present in path. - const QString rootPath = - QDir::fromNativeSeparators(QString::fromLatin1(Path::GetEditingRootFolder().c_str())); - if (filename.startsWith(rootPath, Qt::CaseInsensitive)) - { - filename = filename.right(filename.length() - rootPath.length()); - } - - // Make sure there is no leading slash - if (!filename.isEmpty() && (filename[0] == '\\' || filename[0] == '/')) - { - filename = filename.mid(1); - } + // Make path relative to the the project directory + AZ::IO::Path projectPath{ AZ::Utils::GetProjectPath() }; + AZ::IO::FixedMaxPath projectRelativeFilePath = AZ::IO::PathView(filename.toUtf8().constData()).LexicallyProximate( + projectPath); - if (!filename.isEmpty()) + if (!projectRelativeFilePath.empty()) { - //remove game name. Make it relative to the game folder - const QString filenameRelGame = RemoveGameName(filename); - const int extIndex = filename.lastIndexOf('.'); - const QString ext = filename.right(filename.length() - 1 - extIndex); + AZ::IO::PathView ext = projectRelativeFilePath.Extension(); // Check for File Monitor callback std::vector::iterator iter; @@ -207,15 +197,11 @@ void CEditorFileMonitor::OnFileMonitorChange(const SFileChangeInfo& rChange) // We compare against length of callback string, so we get directory matches as well as full filenames if (sCallback.pListener) { - if (sCallback.extension == "*" || ext.compare(sCallback.extension, Qt::CaseInsensitive) == 0) + if (sCallback.extension == "*" || AZ::IO::PathView(sCallback.extension.toUtf8().constData()) == ext) { - if (filenameRelGame.compare(sCallback.item, Qt::CaseInsensitive) == 0) - { - sCallback.pListener->OnFileChange(qPrintable(filenameRelGame), IFileChangeListener::EChangeType(rChange.changeType)); - } - else if (filename.compare(sCallback.item, Qt::CaseInsensitive) == 0) + if (AZ::IO::PathView(sCallback.item.toUtf8().constData()) == projectRelativeFilePath) { - sCallback.pListener->OnFileChange(qPrintable(filename), IFileChangeListener::EChangeType(rChange.changeType)); + sCallback.pListener->OnFileChange(qPrintable(projectRelativeFilePath.c_str()), IFileChangeListener::EChangeType(rChange.changeType)); } } } diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index b9e4878879..41e950a058 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -1895,7 +1895,7 @@ void SandboxIntegrationManager::MakeSliceFromEntities(const AzToolsFramework::En AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(entitiesAndDescendants, &AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, entities); - const AZStd::string slicesAssetsPath = "@devassets@/Slices"; + const AZStd::string slicesAssetsPath = "@projectroot@/Slices"; if (!gEnv->pFileIO->Exists(slicesAssetsPath.c_str())) { diff --git a/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp b/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp index 98bf228391..0ff9467f33 100644 --- a/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp +++ b/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp @@ -30,6 +30,7 @@ class CXTPDockingPaneLayout; // Needed for settings.h #include #include #include +#include #include #include #include @@ -47,41 +48,6 @@ class CXTPDockingPaneLayout; // Needed for settings.h const char* AssetImporterWindow::s_documentationWebAddress = "http://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer.html"; const AZ::Uuid AssetImporterWindow::s_browseTag = AZ::Uuid::CreateString("{C240D2E1-BFD2-4FFA-BB5B-CC0FA389A5D3}"); -void MakeUserFriendlySourceAssetPath(QString& out, const QString& sourcePath) -{ - char devAssetsRoot[AZ_MAX_PATH_LEN] = { 0 }; - if (!gEnv->pFileIO->ResolvePath("@devroot@", devAssetsRoot, AZ_MAX_PATH_LEN)) - { - out = sourcePath; - return; - } - - AZStd::replace(devAssetsRoot, devAssetsRoot + AZ_MAX_PATH_LEN- 1, AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR); - - // Find if the sourcePathArray is a sub directory of the devAssets folder - // Keep reference to sourcePathArray long enough to use in PathView - QByteArray sourcePathArray = sourcePath.toUtf8(); - AZ::IO::PathView sourcePathRootView(sourcePathArray.data()); - AZ::IO::PathView devAssetsRootView(devAssetsRoot); - auto [sourcePathIter, devAssetsIter] = AZStd::mismatch(sourcePathRootView.begin(), sourcePathRootView.end(), - devAssetsRootView.begin(), devAssetsRootView.end()); - // If the devAssets path iterator is not equal to the end, then there was a mismistch while comparing it - // against the source path indicating that the source path is not a sub-directory - if (devAssetsIter != devAssetsRootView.end()) - { - out = sourcePath; - return; - } - - int offset = aznumeric_cast(strlen(devAssetsRoot)); - if (sourcePath.at(offset) == AZ_CORRECT_FILESYSTEM_SEPARATOR) - { - ++offset; - } - out = sourcePath.right(sourcePath.length() - offset); - -} - AssetImporterWindow::AssetImporterWindow() : AssetImporterWindow(nullptr) { @@ -102,7 +68,7 @@ AssetImporterWindow::AssetImporterWindow(QWidget* parent) AssetImporterWindow::~AssetImporterWindow() { - AZ_Assert(m_processingOverlayIndex == AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, + AZ_Assert(m_processingOverlayIndex == AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, "Processing overlay (and potentially background thread) still active at destruction."); AZ_Assert(!m_processingOverlay, "Processing overlay (and potentially background thread) still active at destruction."); } @@ -133,7 +99,7 @@ void AssetImporterWindow::OpenFile(const AZStd::string& filePath) QMessageBox::warning(this, "In progress", "Unable to close one or more windows at this time."); return; } - + OpenFileInternal(filePath); } @@ -146,7 +112,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev) if (m_processingOverlay) { - AZ_Assert(m_processingOverlayIndex != AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, + AZ_Assert(m_processingOverlayIndex != AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, "Processing overlay present, but not the index in the overlay for it."); if (m_processingOverlay->HasProcessingCompleted()) { @@ -157,7 +123,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev) } else { - QMessageBox::critical(this, "Processing In Progress", "Unable to close the result window at this time.", + QMessageBox::critical(this, "Processing In Progress", "Unable to close the result window at this time.", QMessageBox::Ok, QMessageBox::Ok); ev->ignore(); return; @@ -165,7 +131,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev) } else { - QMessageBox::critical(this, "Processing In Progress", "Please wait until processing has completed to try again.", + QMessageBox::critical(this, "Processing In Progress", "Please wait until processing has completed to try again.", QMessageBox::Ok, QMessageBox::Ok); ev->ignore(); return; @@ -199,7 +165,9 @@ void AssetImporterWindow::Init() // Load the style sheets AzQtComponents::StylesheetPreprocessor styleSheetProcessor(nullptr); - AZStd::string mainWindowQSSPath = Path::GetEditingRootFolder() + "\\Editor\\Styles\\AssetImporterWindow.qss"; + auto mainWindowQSSPath = AZ::IO::Path(AZ::Utils::GetEnginePath()) / "Assets"; + mainWindowQSSPath /= "Editor/Styles/AssetImporterWindow.qss"; + mainWindowQSSPath.MakePreferred(); QFile mainWindowStyleSheetFile(mainWindowQSSPath.c_str()); if (mainWindowStyleSheetFile.open(QFile::ReadOnly)) { @@ -212,7 +180,7 @@ void AssetImporterWindow::Init() { ui->m_actionInspect->setVisible(false); } - + ResetMenuAccess(WindowState::InitialNothingLoaded); // Setup the overlay system, and set the root to be the root display. The root display has the browse, @@ -220,7 +188,7 @@ void AssetImporterWindow::Init() m_overlay.reset(aznew AZ::SceneAPI::UI::OverlayWidget(this)); m_rootDisplay.reset(aznew ImporterRootDisplay(m_serializeContext)); connect(m_rootDisplay.data(), &ImporterRootDisplay::UpdateClicked, this, &AssetImporterWindow::UpdateClicked); - + connect(m_overlay.data(), &AZ::SceneAPI::UI::OverlayWidget::LayerAdded, this, &AssetImporterWindow::OverlayLayerAdded); connect(m_overlay.data(), &AZ::SceneAPI::UI::OverlayWidget::LayerRemoved, this, &AssetImporterWindow::OverlayLayerRemoved); @@ -242,7 +210,7 @@ void AssetImporterWindow::Init() AZStd::string joinedExtensions; AzFramework::StringFunc::Join(joinedExtensions, extensions.begin(), extensions.end(), " or "); - AZStd::string firstLineText = + AZStd::string firstLineText = AZStd::string::format( "%s files are available for use after placing them in any folder within your game project. " "These files will automatically be processed and may be accessed via the Asset Browser. Learn more...", @@ -250,13 +218,13 @@ void AssetImporterWindow::Init() ui->m_initialPromptFirstLine->setText(firstLineText.c_str()); - AZStd::string secondLineText = + AZStd::string secondLineText = AZStd::string::format("To adjust the %s settings, right-click the file in the Asset Browser and select \"Edit Settings\" from the context menu.", joinedExtensions.c_str()); ui->m_initialPromptSecondLine->setText(secondLineText.c_str()); } else { - AZStd::string firstLineText = + AZStd::string firstLineText = AZStd::string::format( "Files are available for use after placing them in any folder within your game project. " "These files will automatically be processed and may be accessed via the Asset Browser. Learn more...", s_documentationWebAddress); @@ -282,12 +250,12 @@ void AssetImporterWindow::OpenFileInternal(const AZStd::string& filePath) auto asyncLoadHandler = AZStd::make_shared( s_browseTag, [this, filePath]() - { - m_assetImporterDocument->LoadScene(filePath); + { + m_assetImporterDocument->LoadScene(filePath); }, [this]() { - HandleAssetLoadingCompleted(); + HandleAssetLoadingCompleted(); }, this); m_processingOverlay.reset(new ProcessingOverlayWidget(m_overlay.data(), ProcessingOverlayWidget::Layout::Loading, s_browseTag)); @@ -304,7 +272,7 @@ bool AssetImporterWindow::IsAllowedToChangeSourceFile() return true; } - QMessageBox messageBox(QMessageBox::Icon::NoIcon, "Unsaved changes", + QMessageBox messageBox(QMessageBox::Icon::NoIcon, "Unsaved changes", "You have unsaved changes. Do you want to discard those changes?", QMessageBox::StandardButton::Discard | QMessageBox::StandardButton::Cancel, this); messageBox.exec(); @@ -406,7 +374,7 @@ void AssetImporterWindow::OnSceneResetRequested() else { m_assetImporterDocument->ClearScene(); - AZ_TracePrintf(ErrorWindow, "Manifest reset returned in '%s'", + AZ_TracePrintf(ErrorWindow, "Manifest reset returned in '%s'", result.GetResult() == ProcessingResult::Failure ? "Failure" : "Ignored"); } }, @@ -456,7 +424,7 @@ void AssetImporterWindow::OnInspect() // make sure the inspector doesn't outlive the AssetImporterWindow, since we own the data it will be inspecting. auto* theInspectWidget = aznew AZ::SceneAPI::UI::SceneGraphInspectWidget(*m_assetImporterDocument->GetScene()); QObject::connect(this, &QObject::destroyed, theInspectWidget, [theInspectWidget]() { theInspectWidget->window()->close(); } ); - + m_overlay->PushLayer(label, theInspectWidget, "Scene Inspector", buttons); } @@ -483,7 +451,7 @@ void AssetImporterWindow::OverlayLayerRemoved() else { ResetMenuAccess(WindowState::InitialNothingLoaded); - + ui->m_initialBrowseContainer->show(); m_rootDisplay->hide(); } @@ -533,8 +501,9 @@ void AssetImporterWindow::HandleAssetLoadingCompleted() m_fullSourcePath = m_assetImporterDocument->GetScene()->GetSourceFilename(); SetTitle(m_fullSourcePath.c_str()); - QString userFriendlyFileName; - MakeUserFriendlySourceAssetPath(userFriendlyFileName, m_fullSourcePath.c_str()); + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + AZ::IO::FixedMaxPath relativeSourcePath = AZ::IO::PathView(m_fullSourcePath).LexicallyProximate(projectPath); + auto userFriendlyFileName = QString::fromUtf8(relativeSourcePath.c_str(), static_cast(relativeSourcePath.Native().size())); m_rootDisplay->SetSceneDisplay(userFriendlyFileName, m_assetImporterDocument->GetScene()); // Once we've browsed to something successfully, we need to hide the initial browse button layer and diff --git a/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp b/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp index b1d07af41c..5ee54667b9 100644 --- a/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp +++ b/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp @@ -7,9 +7,11 @@ */ #include +#include #include #include #include +#include #include #include #include @@ -50,22 +52,15 @@ namespace AZ return nullptr; } - AZStd::string cleanPath = filePath; - if (AzFramework::StringFunc::Path::IsRelative(filePath.c_str())) + AZ::IO::Path enginePath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - const char* absolutePath = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(absolutePath, - &AzToolsFramework::AssetSystemRequestBus::Events::GetAbsoluteDevRootFolderPath); - AZ_Assert(absolutePath, "Unable to retrieve the dev folder path"); - AzFramework::StringFunc::Path::Join(absolutePath, cleanPath.c_str(), cleanPath); - } - else - { - // Normalizing is not needed if the path is relative as Join(...) will also normalize. - AzFramework::StringFunc::Path::Normalize(cleanPath); + settingsRegistry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } - auto sceneIt = m_scenes.find(cleanPath); + AZ::IO::Path cleanPath = (enginePath / filePath).LexicallyNormal(); + + auto sceneIt = m_scenes.find(cleanPath.Native()); if (sceneIt != m_scenes.end()) { AZStd::shared_ptr scene = sceneIt->second.lock(); @@ -98,14 +93,14 @@ namespace AZ } AZStd::shared_ptr scene = - AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath, sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid()); + AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath.Native(), sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid()); if (!scene) { AZ_TracePrintf(Utilities::ErrorWindow, "Failed to load the requested scene."); return nullptr; } - m_scenes.emplace(AZStd::move(cleanPath), scene); + m_scenes.emplace(AZStd::move(cleanPath.Native()), scene); return scene; } diff --git a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp index 6b454474be..a53ce966c4 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp +++ b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp @@ -46,7 +46,6 @@ namespace ProjectSettingsTool , LastPathBus::Handler() , m_ui(new Ui::ProjectSettingsToolWidget()) , m_reconfigureProcess() - , m_devRoot(GetDevRoot()) , m_projectRoot(GetProjectRoot()) , m_projectName(GetProjectName()) , m_plistsInitVector( diff --git a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h index 1c9aa4b1bf..daa5bea27c 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h +++ b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h @@ -147,7 +147,6 @@ namespace ProjectSettingsTool // The process used to reconfigure settings QProcess m_reconfigureProcess; - AZStd::string m_devRoot; AZStd::string m_projectRoot; AZStd::string m_projectName; diff --git a/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp b/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp index 0e171adf04..d5b94469cc 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp +++ b/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp @@ -27,37 +27,31 @@ namespace } template - StringType GetAbsoluteDevRoot() + StringType GetAbsoluteEngineRoot() { - const char* devRoot = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - devRoot, - &AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevRootFolderPath); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); - if (!devRoot) + if (engineRoot.empty()) { return ""; } - StringType devRootString(devRoot); - ToUnixPath(devRootString); - return devRootString; + StringType engineRootString(engineRoot.c_str()); + ToUnixPath(engineRootString); + return engineRootString; } template StringType GetAbsoluteProjectRoot() { - const char* projectRoot = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - projectRoot, - &AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevGameFolderPath); + AZ::IO::FixedMaxPath projectRoot = AZ::Utils::GetProjectPath(); - if (!projectRoot) + if (projectRoot.empty()) { return ""; } - StringType projectRootString(projectRoot); + StringType projectRootString(projectRoot.c_str()); ToUnixPath(projectRootString); return projectRootString; } @@ -87,9 +81,9 @@ namespace ProjectSettingsTool return reinterpret_cast(func); } - AZStd::string GetDevRoot() + AZStd::string GetEngineRoot() { - return GetAbsoluteDevRoot(); + return GetAbsoluteEngineRoot(); } AZStd::string GetProjectRoot() { @@ -104,7 +98,7 @@ namespace ProjectSettingsTool QString SelectXmlFromFileDialog(const QString& currentFile) { // The selected file must be relative to this path - QString defaultPath = GetAbsoluteDevRoot(); + QString defaultPath = GetAbsoluteEngineRoot(); QString startPath; // Choose the starting path for file dialog @@ -139,7 +133,7 @@ namespace ProjectSettingsTool QString SelectImageFromFileDialog(const QString& currentFile) { - QString defaultPath = QStringLiteral("%1Code%2/Resources/").arg(GetAbsoluteDevRoot(), ::GetProjectName()); + QString defaultPath = QStringLiteral("%1Code%2/Resources/").arg(GetAbsoluteEngineRoot(), ::GetProjectName()); QString startPath; @@ -188,7 +182,7 @@ namespace ProjectSettingsTool // Android if (group <= ImageGroup::AndroidPortrait) { - root = GetDevRoot() + "/Code/Tools/Android/ProjectBuilder/app_"; + root = GetEngineRoot() + "/Code/Tools/Android/ProjectBuilder/app_"; } //Ios else diff --git a/Code/Editor/Plugins/ProjectSettingsTool/Utils.h b/Code/Editor/Plugins/ProjectSettingsTool/Utils.h index 4226d534a6..050fb3b85b 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/Utils.h +++ b/Code/Editor/Plugins/ProjectSettingsTool/Utils.h @@ -17,7 +17,7 @@ namespace ProjectSettingsTool { void* ConvertFunctorToVoid(AZStd::pair(*func)(const QString&)); - AZStd::string GetDevRoot(); + AZStd::string GetEngineRoot(); AZStd::string GetProjectRoot(); AZStd::string GetProjectName(); diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index 05a6960695..47743d1c42 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -935,8 +935,9 @@ void SEditorSettings::LoadDefaultGamePaths() searchPaths[EDITOR_PATH_MATERIALS].push_back((Path::GetEditingGameDataFolder() + "/Materials").c_str()); } - AZStd::string iconsPath; - AZ::StringFunc::Path::Join(Path::GetEditingRootFolder().c_str(), "Editor/UI/Icons", iconsPath); + auto iconsPath = AZ::IO::Path(AZ::Utils::GetEnginePath()) / "Assets"; + iconsPath /= "Editor/UI/Icons"; + iconsPath.MakePreferred(); searchPaths[EDITOR_PATH_UI_ICONS].push_back(iconsPath.c_str()); } diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp index b510315995..d7901e338a 100644 --- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -269,7 +269,7 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange() // Enable/disable the 'remove'/'update' button properly. bool bNoSelection = !m_ui->m_renderList->selectionModel()->hasSelection(); m_ui->BATCH_RENDER_REMOVE_SEQ->setEnabled(bNoSelection ? false : true); - + CheckForEnableUpdateButton(); if (bNoSelection) @@ -360,7 +360,7 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange() cvarsText += item.cvars[static_cast(i)]; cvarsText += "\r\n"; } - m_ui->m_cvarsEdit->setPlainText(cvarsText); + m_ui->m_cvarsEdit->setPlainText(cvarsText); } void CSequenceBatchRenderDialog::CheckForEnableUpdateButton() @@ -494,7 +494,7 @@ void CSequenceBatchRenderDialog::OnSavePreset() } void CSequenceBatchRenderDialog::stashActiveViewportResolution() -{ +{ // stash active resolution in global vars activeViewportWidth = resolutions[0][0]; activeViewportHeight = resolutions[0][1]; @@ -502,7 +502,7 @@ void CSequenceBatchRenderDialog::stashActiveViewportResolution() if (activeViewport) { activeViewport->GetDimensions(&activeViewportWidth, &activeViewportHeight); - } + } } void CSequenceBatchRenderDialog::OnGo() @@ -640,7 +640,7 @@ void CSequenceBatchRenderDialog::OnResolutionSelected() int defaultH; const QString currentCustomResText = m_ui->m_resolutionCombo->currentText(); GetResolutionFromCustomResText(currentCustomResText.toStdString().c_str(), defaultW, defaultH); - + CCustomResolutionDlg resDlg(defaultW, defaultH, this); if (resDlg.exec() == QDialog::Accepted) { @@ -752,7 +752,7 @@ bool CSequenceBatchRenderDialog::LoadOutputOptions(const QString& pathname) { const QString customResText = resolutionNode->getContent(); m_ui->m_resolutionCombo->setItemText(curSel, customResText); - + GetResolutionFromCustomResText(customResText.toStdString().c_str(), m_customResW, m_customResH); } m_ui->m_resolutionCombo->setCurrentIndex(curSel); @@ -907,12 +907,12 @@ void CSequenceBatchRenderDialog::CaptureItemStart() folder += "/"; folder += itemText; - // If this is a relative path, prepend the @assets@ folder to match where the Renderer is going + // If this is a relative path, prepend the @products@ folder to match where the Renderer is going // to dump the frame buffer image captures. if (AzFramework::StringFunc::Path::IsRelative(folder.toUtf8().data())) { AZStd::string absolutePath; - AZStd::string assetsRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + AZStd::string assetsRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::Path::Join(assetsRoot.c_str(), folder.toUtf8().data(), absolutePath); folder = absolutePath.c_str(); } @@ -962,7 +962,7 @@ void CSequenceBatchRenderDialog::CaptureItemStart() m_renderContext.cvarDisplayInfoBU = cvarDebugInfo->GetIVal(); if (renderItem.disableDebugInfo && cvarDebugInfo->GetIVal()) { - const int DISPLAY_INFO_OFF = 0; + const int DISPLAY_INFO_OFF = 0; cvarDebugInfo->Set(DISPLAY_INFO_OFF); } } @@ -1100,13 +1100,13 @@ void CSequenceBatchRenderDialog::OnUpdateEnd(IAnimSequence* sequence) sequence->SetActiveDirector(m_renderContext.pActiveDirectorBU); const auto imageFormat = m_ui->m_imageFormatCombo->currentText(); - + SRenderItem renderItem = m_renderItems[m_renderContext.currentItemIndex]; if (m_bFFMPEGCommandAvailable && renderItem.bCreateVideo) { // Create a video using the ffmpeg plug-in from captured images. m_renderContext.processingFFMPEG = true; - + AZStd::string outputFolder = m_renderContext.captureOptions.folder; auto future = QtConcurrent::run( [renderItem, outputFolder, imageFormat] @@ -1238,7 +1238,7 @@ void CSequenceBatchRenderDialog::OnKickIdleTimout() } void CSequenceBatchRenderDialog::OnKickIdle() -{ +{ if (m_renderContext.captureState == CaptureState::WarmingUpAfterResChange) { OnUpdateWarmingUpAfterResChange(); @@ -1254,7 +1254,7 @@ void CSequenceBatchRenderDialog::OnKickIdle() else if (m_renderContext.captureState == CaptureState::Capturing) { OnUpdateCapturing(); - } + } else if (m_renderContext.captureState == CaptureState::End) { OnUpdateEnd(m_renderContext.endingSequence); diff --git a/Code/Editor/Util/PathUtil.cpp b/Code/Editor/Util/PathUtil.cpp index c9e6823824..ca3481ddae 100644 --- a/Code/Editor/Util/PathUtil.cpp +++ b/Code/Editor/Util/PathUtil.cpp @@ -11,9 +11,9 @@ #include "PathUtil.h" -#include // for AZ_MAX_PATH_LEN +#include +#include #include // for ebus events -#include #include #include #include @@ -179,7 +179,7 @@ namespace Path EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); return QString(engineRoot); } - + ////////////////////////////////////////////////////////////////////////// QString& ReplaceFilename(const QString& strFilepath, const QString& strFilename, QString& strOutputFilename, bool bCallCaselessPath) { @@ -216,30 +216,21 @@ namespace Path ////////////////////////////////////////////////////////////////////////// QString GetResolvedUserSandboxFolder() { - char resolvedPath[AZ_MAX_PATH_LEN] = { 0 }; - gEnv->pFileIO->ResolvePath(GetUserSandboxFolder().toUtf8().data(), resolvedPath, AZ_MAX_PATH_LEN); - return QString::fromLatin1(resolvedPath); + AZ::IO::FixedMaxPath userSandboxFolderPath; + gEnv->pFileIO->ResolvePath(userSandboxFolderPath, GetUserSandboxFolder().toUtf8().constData()); + return QString::fromUtf8(userSandboxFolderPath.c_str(), static_cast(userSandboxFolderPath.Native().size())); } // internal function, you should use GetEditingGameDataFolder instead. AZStd::string GetGameAssetsFolder() { - const char* resultValue = nullptr; - EBUS_EVENT_RESULT(resultValue, AzToolsFramework::AssetSystemRequestBus, GetAbsoluteDevGameFolderPath); - if (!resultValue) - { - if ((gEnv) && (gEnv->pFileIO)) - { - resultValue = gEnv->pFileIO->GetAlias("@devassets@"); - } - } - - if (!resultValue) + AZ::IO::Path projectPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - resultValue = "."; + settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } - return resultValue; + return projectPath.Native(); } /// Get the data folder @@ -258,26 +249,6 @@ namespace Path return str; } - //! Get the root folder (in source control or other writable assets) where you should save root data. - AZStd::string GetEditingRootFolder() - { - const char* resultValue = nullptr; - EBUS_EVENT_RESULT(resultValue, AzToolsFramework::AssetSystemRequestBus, GetAbsoluteDevRootFolderPath); - - if (!resultValue) - { - if ((gEnv) && (gEnv->pFileIO)) - { - resultValue = gEnv->pFileIO->GetAlias("@devassets@"); - } - } - if (!resultValue) - { - resultValue = "."; - } - return resultValue; - } - AZStd::string MakeModPathFromGamePath(const char* relGamePath) { @@ -335,165 +306,60 @@ namespace Path return ""; } - bool relPathfound = false; + bool relPathFound = false; AZStd::string relativePath; AZStd::string fullAssetPath(fullPath.toUtf8().data()); - EBUS_EVENT_RESULT(relPathfound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullAssetPath, relativePath); + EBUS_EVENT_RESULT(relPathFound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullAssetPath, relativePath); - if (relPathfound) + if (relPathFound) { // do not normalize this path, it will already be an appropriate asset ID. return CaselessPaths(relativePath.c_str()); } - char rootpath[_MAX_PATH] = { 0 }; - azstrcpy(rootpath, _MAX_PATH, Path::GetEditingRootFolder().c_str()); - - if (bRelativeToGameFolder) - { - azstrcpy(rootpath, _MAX_PATH, Path::GetEditingGameDataFolder().c_str()); - } - - QString rootPathNormalized(rootpath); - QString srcPathNormalized(fullPath); - -#if defined(AZ_PLATFORM_WINDOWS) - // avoid confusing PathRelativePathTo - rootPathNormalized.replace('/', '\\'); - srcPathNormalized.replace('/', '\\'); -#endif + AZ::IO::FixedMaxPath rootPath = bRelativeToGameFolder ? AZ::Utils::GetProjectPath() : AZ::Utils::GetEnginePath(); + AZ::IO::FixedMaxPath resolvedFullPath; + AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedFullPath, fullPath.toUtf8().constData()); // Create relative path - char resolvedSrcPath[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(srcPathNormalized.toUtf8().data(), resolvedSrcPath, AZ_MAX_PATH_LEN); - QByteArray path = QDir(rootPathNormalized).relativeFilePath(resolvedSrcPath).toUtf8(); - if (path.isEmpty()) - { - return fullPath; - } - // The following code is required because the windows PathRelativePathTo function will always return "./SomePath" instead of just "SomePath" - // Only remove single dot (.) and slash parts of a path, never the double dot (..) - const char* pBuffer = path.data(); - bool bHasDot = false; - while (*pBuffer && pBuffer != path.end()) - { - switch (*pBuffer) - { - case '.': - if (bHasDot) - { - // Found a double dot, rewind and stop removing - pBuffer--; - break; - } - // Fall through intended - case '/': - case '\\': - bHasDot = (*pBuffer == '.'); - pBuffer++; - continue; - } - break; - } - - QString relPath = pBuffer; - return CaselessPaths(relPath); + return CaselessPaths(resolvedFullPath.LexicallyProximate(rootPath).MakePreferred().c_str()); } QString GamePathToFullPath(const QString& path) { using namespace AzToolsFramework; - AZ_Warning("GamePathToFullPath", path.size() <= AZ_MAX_PATH_LEN, "Path exceeds maximum path length of %d", AZ_MAX_PATH_LEN); - if ((gEnv) && (gEnv->pFileIO) && gEnv->pCryPak && path.size() <= AZ_MAX_PATH_LEN) + AZ_Warning("GamePathToFullPath", path.size() <= AZ::IO::MaxPathLength, "Path exceeds maximum path length of %zu", AZ::IO::MaxPathLength); + if (path.size() <= AZ::IO::MaxPathLength) { // first, adjust the file name for mods: - bool fullPathfound = false; - AZStd::string assetFullPath; - AZStd::string adjustedFilePath = path.toUtf8().data(); - AssetSystemRequestBus::BroadcastResult(fullPathfound, &AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, adjustedFilePath, assetFullPath); - if (fullPathfound) + bool fullPathFound = false; + AZ::IO::Path assetFullPath; + AZ::IO::Path adjustedFilePath = path.toUtf8().constData(); + AssetSystemRequestBus::BroadcastResult(fullPathFound, &AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, + adjustedFilePath.Native(), assetFullPath.Native()); + if (fullPathFound) { - //if the bus message succeeds than normalize and lowercase the path - AzFramework::StringFunc::Path::Normalize(assetFullPath); - return assetFullPath.c_str(); + //if the bus message succeeds than normalize + return assetFullPath.LexicallyNormal().c_str(); } - // if the bus message didn't succeed, 'guess' the source assets: + // if the bus message didn't succeed, check if he path exist as a resolved path else { // Not all systems have been converted to use local paths. Some editor files save XML files directly, and a full or correctly aliased path is already passed in. // If the path passed in exists already, then return the resolved filepath if (AZ::IO::FileIOBase::GetDirectInstance()->Exists(adjustedFilePath.c_str())) { - char resolvedPath[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 }; - AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(adjustedFilePath.c_str(), resolvedPath, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength); - return QString::fromUtf8(resolvedPath); + AZ::IO::FixedMaxPath resolvedPath; + AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedPath, adjustedFilePath); + return QString::fromUtf8(resolvedPath.c_str(), static_cast(resolvedPath.Native().size())); } - // if we get here it means that the Asset Processor does not know about this file. most of the time we should never get here - // the rest of this code just does a bunch of heuristic guesses in case of missing files or if the user has hand-edited - // the asset cache by moving files in via some other means or external process. - if (adjustedFilePath[0] != '@') - { - const char* prefix = (adjustedFilePath[0] == '/' || adjustedFilePath[0] == '\\') ? "@devassets@" : "@devassets@/"; - adjustedFilePath = prefix + adjustedFilePath; - } - - char szAdjustedFile[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 }; - gEnv->pFileIO->ResolvePath(adjustedFilePath.c_str(), szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile)); - - if ((azstrnicmp(szAdjustedFile, "@devassets@", 11) == 0) && ((szAdjustedFile[11] == '/') || (szAdjustedFile[11] == '\\'))) - { - if (!gEnv->pCryPak->IsFileExist(szAdjustedFile)) - { - AZStd::string newName(szAdjustedFile); - AzFramework::StringFunc::Replace(newName, "@devassets@", "@devroot@/engine", false); - - if (gEnv->pCryPak->IsFileExist(newName.c_str())) - { - azstrcpy(szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile), newName.c_str()); - } - else - { - // getting tricky here, try @devroot@ alone, in case its 'editor' - AzFramework::StringFunc::Replace(newName, "@devassets@", "@devroot@", false); - if (gEnv->pCryPak->IsFileExist(szAdjustedFile)) - { - azstrcpy(szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile), newName.c_str()); - } - // give up, best guess is just @devassets@ - } - } - } - - // we should very rarely actually get to this point in the code. - - // szAdjustedFile may contain an alias at this point. (@assets@/blah.whatever) - // there is a case in which the loose asset exists only within a pak file for some reason - // this is not recommended but it is possible.in that case, we want to return the original szAdjustedFile - // without touching it or resolving it so that crypak can open it successfully. - char adjustedPath[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 }; - if (gEnv->pFileIO->ResolvePath(szAdjustedFile, adjustedPath, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength)) // resolve to full path - { - if ((gEnv->pCryPak->IsFileExist(adjustedPath)) || (!gEnv->pCryPak->IsFileExist(szAdjustedFile))) - { - // note that if we get here, then EITHER - // the file exists as a loose asset in the actual adjusted path - // OR the file does not exist in the original passed-in aliased name (like '@assets@/whatever') - // in which case we may as well just resolve the path to a full path and return it. - assetFullPath = adjustedPath; - AzFramework::StringFunc::Path::Normalize(assetFullPath); - azstrcpy(szAdjustedFile, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength, assetFullPath.c_str()); - } - // if the above case succeeded then it means that the file does NOT exist loose - // but DOES exist in a pak, in which case we leave szAdjustedFile with the alias on the front of it, meaning - // fopens via crypak will actually succeed. - } - return szAdjustedFile; + return path; } } else { - return ""; + return QString{}; } } diff --git a/Code/Editor/Util/PathUtil.h b/Code/Editor/Util/PathUtil.h index 2c49031155..163d74e358 100644 --- a/Code/Editor/Util/PathUtil.h +++ b/Code/Editor/Util/PathUtil.h @@ -44,9 +44,6 @@ namespace Path //! always returns a full path EDITOR_CORE_API AZStd::string GetEditingGameDataFolder(); - //! Get the root folder (in source control or other writable assets) where you should save root data. - EDITOR_CORE_API AZStd::string GetEditingRootFolder(); - //! Set the current mod NAME for editing purposes. After doing this the above functions will take this into account //! name only, please! EDITOR_CORE_API void SetModName(const char* input); @@ -69,93 +66,6 @@ namespace Path return strPath; } - //! Split full file name to path and filename - //! @param filepath [IN] Full file name inclusing path. - //! @param path [OUT] Extracted file path. - //! @param file [OUT] Extracted file (with extension). - inline void Split(const QString& filepath, QString& path, QString& file) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.toUtf8().data(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext)); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); - path = path_buffer; - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), 0, 0, fname, ext); -#else - _splitpath(filepath.toUtf8().data(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); - path = path_buffer; - _makepath(path_buffer, 0, 0, fname, ext); -#endif - file = path_buffer; - } - inline void Split(const AZStd::string& filepath, AZStd::string& path, AZStd::string& file) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.c_str(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), 0, 0, 0, 0); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); - path = path_buffer; - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), 0, 0, fname, ext); -#else - _splitpath(filepath.c_str(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); - path = path_buffer; - _makepath(path_buffer, 0, 0, fname, ext); -#endif - file = path_buffer; - } - - //! Split full file name to path and filename - //! @param filepath [IN] Full file name inclusing path. - //! @param path [OUT] Extracted file path. - //! @param filename [OUT] Extracted file (without extension). - //! @param ext [OUT] Extracted files extension. - inline void Split(const QString& filepath, QString& path, QString& filename, QString& fext) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.toUtf8().data(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext)); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); -#else - _splitpath(filepath.toUtf8().data(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); -#endif - path = path_buffer; - filename = fname; - fext = ext; - } - inline void Split(const AZStd::string& filepath, AZStd::string& path, AZStd::string& filename, AZStd::string& fext) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.c_str(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext)); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); -#else - _splitpath(filepath.c_str(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); -#endif - path = path_buffer; - filename = fname; - fext = ext; - } - //! Split path into segments //! @param filepath [IN] path inline QStringList SplitIntoSegments(const QString& path) diff --git a/Code/Framework/AzCore/AzCore/IO/FileIO.h b/Code/Framework/AzCore/AzCore/IO/FileIO.h index 6406025417..25dd422a47 100644 --- a/Code/Framework/AzCore/AzCore/IO/FileIO.h +++ b/Code/Framework/AzCore/AzCore/IO/FileIO.h @@ -148,7 +148,7 @@ namespace AZ virtual AZ::u64 ModificationTime(HandleType fileHandle) = 0; virtual AZ::u64 ModificationTime(const char* filePath) = 0; - /// Get the size of the file. Returns Success if we report size. + /// Get the size of the file. Returns Success if we report size. virtual Result Size(const char* filePath, AZ::u64& size) = 0; virtual Result Size(HandleType fileHandle, AZ::u64& size) = 0; @@ -198,7 +198,7 @@ namespace AZ /// note: the callback will contain the full concatenated path (filePath + slash + fileName) /// not just the individual file name found. /// note: if the file path of the found file corresponds to a registered ALIAS, the longest matching alias will be returned - /// so expect return values like @assets@/textures/mytexture.dds instead of a full path. This is so that fileIO works over remote connections. + /// so expect return values like @products@/textures/mytexture.dds instead of a full path. This is so that fileIO works over remote connections. /// note: if rootPath is specified the implementation has the option of substituting it for the current directory /// as would be the case on a file server. typedef AZStd::function FindFilesCallbackType; @@ -206,13 +206,18 @@ namespace AZ // Alias system - /// SetAlias - Adds an alias to the path resolution system, e.g. @user@, @root@, etc. + /// SetAlias - Adds an alias to the path resolution system, e.g. @user@, @products@, etc. virtual void SetAlias(const char* alias, const char* path) = 0; /// ClearAlias - Removes an alias from the path resolution system virtual void ClearAlias(const char* alias) = 0; /// GetAlias - Returns the destination path for a given alias, or nullptr if the alias does not exist virtual const char* GetAlias(const char* alias) const = 0; + /// SetDeprecateAlias - Adds a deprecated alias with path resolution which points to a new alias + /// When the DeprecatedAlias is used an Error is logged and the alias is resolved to the path + /// specified by the new alais + virtual void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) = 0; + /// Shorten the given path if it contains an alias. it will always pick the longest alias match. /// note that it re-uses the buffer, since the data can only get smaller and we don't want to internally allocate memory if we /// can avoid it. @@ -230,8 +235,8 @@ namespace AZ //! ResolvePath - Replaces any aliases in path with their values and stores the result in resolvedPath, //! also ensures that the path is absolute - //! NOTE: If the path does not start with an alias then the resolved value of the @assets@ is used - //! which has the effect of making the path relative to the @assets@/ folder + //! NOTE: If the path does not start with an alias then the resolved value of the @products@ is used + //! which has the effect of making the path relative to the @products@/ folder //! returns true if path was resolved, false otherwise //! note that all of the above file-finding and opening functions automatically resolve the path before operating //! so you should not need to call this except in very exceptional circumstances where you absolutely need to diff --git a/Code/Framework/AzCore/AzCore/IO/IStreamer.h b/Code/Framework/AzCore/AzCore/IO/IStreamer.h index d959fa716c..438384e687 100644 --- a/Code/Framework/AzCore/AzCore/IO/IStreamer.h +++ b/Code/Framework/AzCore/AzCore/IO/IStreamer.h @@ -42,8 +42,8 @@ namespace AZ::IO // These functions can't be called after a request has been queued. // - //! Creates a request to read a file. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! Creates a request to read a file. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param outputBuffer The buffer that will hold the loaded data. This must be able to at least hold "size" number of bytes. //! @param outputBufferSize The size of the buffer that will hold the loaded data. This must be equal or larger than "size" number of bytes. //! @param readSize The number of bytes to read from the file at the relative path. @@ -62,9 +62,9 @@ namespace AZ::IO IStreamerTypes::Priority priority = IStreamerTypes::s_priorityMedium, size_t offset = 0) = 0; - //! Sets a request to the read command. + //! Sets a request to the read command. //! @param request The request that will store the read command. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param outputBuffer The buffer that will hold the loaded data. This must be able to at least hold "size" number of bytes. //! @param outputBufferSize The size of the buffer that will hold the loaded data. This must be equal or larger than "size" number of bytes. //! @param readSize The number of bytes to read from the file at the relative path. @@ -84,8 +84,8 @@ namespace AZ::IO IStreamerTypes::Priority priority = IStreamerTypes::s_priorityMedium, size_t offset = 0) = 0; - //! Creates a request to the read command. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! Creates a request to the read command. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param allocator The allocator used to reserve and release memory for the read request. Memory allocated this way will //! be automatically freed when there are no more references to the FileRequestPtr. To avoid this, use GetReadRequestResult //! to claim the pointer and use the provided allocator to release the memory at a later point. @@ -106,9 +106,9 @@ namespace AZ::IO IStreamerTypes::Priority priority = IStreamerTypes::s_priorityMedium, size_t offset = 0) = 0; - //! Sets a request to the read command. + //! Sets a request to the read command. //! @param request The request that will store the read command. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param allocator The allocator used to reserve and release memory for the read request. Memory allocated this way will //! be automatically freed when there are no more references to the FileRequestPtr. To avoid this, use GetReadRequestResult //! to claim the pointer and use the provided allocator to release the memory at a later point. @@ -138,7 +138,7 @@ namespace AZ::IO //! @result A smart pointer to the newly created request with the cancel command. virtual FileRequestPtr Cancel(FileRequestPtr target) = 0; - //! Sets a request to the cancel command. + //! Sets a request to the cancel command. //! When this request completes it's not guaranteed to have canceled the target request. Not all requests can be canceled and requests //! that already processing may complete. It's recommended to let the target request handle the completion of the request as normal //! and handle cancellation by checking the status on the target request is set to IStreamerTypes::RequestStatus::Canceled. @@ -177,7 +177,7 @@ namespace AZ::IO //! DestroyDedicatedCache is called. Typical use of a dedicated cache is for files that have their own compression //! and are periodically visited to read a section, e.g. streaming video play or streaming audio banks. This //! request will fail if there are no nodes in Streamer's stack that deal with dedicated caches. - //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @products@. //! @return A smart pointer to the newly created request with the command to create a dedicated cache. virtual FileRequestPtr CreateDedicatedCache(AZStd::string_view relativePath) = 0; @@ -186,25 +186,25 @@ namespace AZ::IO //! and are periodically visited to read a section, e.g. streaming video play or streaming audio banks. This //! request will fail if there are no nodes in Streamer's stack that deal with dedicated caches. //! @param request The request that will store the command to create a dedicated cache. - //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @products@. //! @return A reference to the provided request. virtual FileRequestPtr& CreateDedicatedCache(FileRequestPtr& request, AZStd::string_view relativePath) = 0; //! Destroy a dedicated cache created by CreateDedicatedCache. See CreateDedicatedCache for more details. - //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @products@. //! @return A smart pointer to the newly created request with the command to destroy a dedicated cache. virtual FileRequestPtr DestroyDedicatedCache(AZStd::string_view relativePath) = 0; //! Destroy a dedicated cache created by CreateDedicatedCache. See CreateDedicatedCache for more details. //! @param request The request that will store the command to destroy a dedicated cache. - //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @products@. //! @return A reference to the provided request. virtual FileRequestPtr& DestroyDedicatedCache(FileRequestPtr& request, AZStd::string_view relativePath) = 0; //! Clears a file from all caches in use by Streamer. //! Flushing the cache will cause the streaming stack to pause processing until it's idle before issuing the flush and resuming //! processing. This can result in a noticeable interruption. - //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @products@. //! @return A smart pointer to the newly created request with the command to flush a file from all caches. virtual FileRequestPtr FlushCache(AZStd::string_view relativePath) = 0; @@ -212,7 +212,7 @@ namespace AZ::IO //! Flushing the cache will cause the streaming stack to pause processing until it's idle before issuing the flush and resuming //! processing. This can result in a noticeable interruption. //! @param request The request that will store the command to flush a file from all caches. - //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @products@. //! @return A reference to the provided request. virtual FileRequestPtr& FlushCache(FileRequestPtr& request, AZStd::string_view relativePath) = 0; @@ -334,7 +334,7 @@ namespace AZ::IO // //! Collect statistics from all the components that make up Streamer. - //! This is thread safe in the sense that it won't crash. + //! This is thread safe in the sense that it won't crash. //! Data is collected lockless from involved threads and might be slightly //! out of date in some cases. //! @param statistics The container where statistics will be added to. diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.h b/Code/Framework/AzCore/AzCore/IO/Path/Path.h index 24f26daa51..3b5c224957 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.h +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.h @@ -98,6 +98,11 @@ namespace AZ::IO //! made from the internal string constexpr AZStd::fixed_string FixedMaxPathString() const noexcept; + // as_posix + //! Replicates the behavior of the Python pathlib as_posix method + //! by replacing the Windows Path Separator with the Posix Path Seperator + constexpr AZStd::fixed_string FixedMaxPathStringAsPosix() const noexcept; + // decomposition //! Given a windows path of "C:\O3DE\foo\bar\name.txt" and a posix path of //! "/O3DE/foo/bar/name.txt" @@ -178,7 +183,7 @@ namespace AZ::IO //! Normalizes a path in a purely lexical manner. //! # Path separators are converted to their preferred path separator //! # Path parts of "." are collapsed to nothing empty - //! # Paths parts of ".." are removed if there is a preceding directory + //! # Paths parts of ".." are removed if there is a preceding directory //! The preceding directory is also removed //! # Runs of Two or more path separators are collapsed into one path separator //! unless the path begins with two path separators @@ -238,7 +243,7 @@ namespace AZ::IO // iterators //! Returns an iterator to the beginning of the path that can be used to traverse the path - //! according to the following + //! according to the following //! 1. Root name - (0 or 1) //! 2. Root directory - (0 or 1) //! 3. Filename - (0 or more) @@ -253,24 +258,23 @@ namespace AZ::IO template friend class BasicPath; friend struct AZStd::hash; + struct PathIterable; - template - static constexpr void MakeRelativeTo(PathResultType& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base); + static constexpr void MakeRelativeTo(PathIterable& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base) noexcept; - struct PathIterable; //! Returns a structure that provides a view of the path parts which can be used for iteration //! Only the path parts that correspond to creating an normalized path is returned //! This function is useful for returning a "view" into a normalized path without the need //! to allocate memory for the heap static constexpr PathIterable GetNormalPathParts(const AZ::IO::PathView& path) noexcept; - // joins the input path to the Path Iterable structure using similiar logic to Path::Append - // If the input path is absolute it will replace the current PathIterable otherwise - // the input path will be appended to the Path Iterable structure - // For example a PathIterable with parts = ['C:', '/', 'foo'] - // If the path input = 'bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar'] - // If the path input = 'C:/bar', then the new PathIterable parts = [C:', '/', 'bar'] - // If the path input = 'C:bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar' ] - // If the path input = 'D:bar', then the new PathIterable parts = [D:, 'bar' ] + //! joins the input path to the Path Iterable structure using similiar logic to Path::Append + //! If the input path is absolute it will replace the current PathIterable otherwise + //! the input path will be appended to the Path Iterable structure + //! For example a PathIterable with parts = ['C:', '/', 'foo'] + //! If the path input = 'bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar'] + //! If the path input = 'C:/bar', then the new PathIterable parts = [C:', '/', 'bar'] + //! If the path input = 'C:bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar' ] + //! If the path input = 'D:bar', then the new PathIterable parts = [D:, 'bar' ] static constexpr void AppendNormalPathParts(PathIterable& pathIterableResult, const AZ::IO::PathView& path) noexcept; constexpr int ComparePathView(const PathView& other) const; @@ -325,32 +329,32 @@ namespace AZ::IO constexpr BasicPath(BasicPath&& other) = default; // Conversion constructor for other types of BasicPath instantiations - constexpr BasicPath(const PathView& other); + constexpr BasicPath(const PathView& other) noexcept; // String constructors //! Constructs a Path by copying the pathString to its internal string //! The preferred separator is to the OS default path separator constexpr BasicPath(const string_type& pathString) noexcept; //! Constructs a Path by copying the pathString to its internal string - //! The preferred separator it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(const string_type& pathString, const char preferredSeparator) noexcept; //! Constructs a Path by moving the pathString to its internal string //! The preferred separator is to the OS default path separator constexpr BasicPath(string_type&& pathString) noexcept; //! Constructs a Path by copying the pathString to its internal string - //! The preferred separator it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(string_type&& pathString, const char preferredSeparator) noexcept; //! Constructs a Path by constructing it's internal out of a string_view //! The preferred separator is to the OS default path separator constexpr BasicPath(AZStd::string_view src) noexcept; //! Constructs a Path by constructing it's internal out of a string_view - //! The preferred separators it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(AZStd::string_view src, const char preferredSeparator) noexcept; //! Constructs a Path by constructing it's internal out of a value_type* //! The preferred separator is to the OS default path separator constexpr BasicPath(const value_type* pathString) noexcept; //! Constructs a Path by constructing it's internal out of a value_type* - //! The preferred separator it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(const value_type* pathString, const char preferredSeparator) noexcept; //! Constructs a empty Path with the preferred separator set to the parameter explicit constexpr BasicPath(const char preferredSeparator) noexcept; @@ -371,7 +375,7 @@ namespace AZ::IO constexpr BasicPath& operator=(BasicPath&& other) = default; // conversion assignment operator - constexpr BasicPath& operator=(const PathView& pathView); + constexpr BasicPath& operator=(const PathView& pathView) noexcept; constexpr BasicPath& operator=(const string_type& str) noexcept; constexpr BasicPath& operator=(string_type&& str) noexcept; constexpr BasicPath& operator=(AZStd::string_view str) noexcept; @@ -477,6 +481,12 @@ namespace AZ::IO //! made from the internal string constexpr AZStd::fixed_string FixedMaxPathString() const; + // as_posix + //! Replicates the behavior of the Python pathlib as_posix method + //! by replacing the Windows Path Separator with the Posix Path Seperator + AZStd::string StringAsPosix() const; + constexpr AZStd::fixed_string FixedMaxPathStringAsPosix() const noexcept; + // compare //! Performs a compare of each of the path parts for equivalence //! Each part of the path is compare using string comparison @@ -574,7 +584,7 @@ namespace AZ::IO //! Normalizes a path in a purely lexical manner. //! # Path separators are converted to their preferred path separator //! # Path parts of "." are collapsed to nothing empty - //! # Paths parts of ".." are removed if there is a preceding directory + //! # Paths parts of ".." are removed if there is a preceding directory //! The preceding directory is also removed //! # Runs of Two or more path separators are collapsed into one path separator //! unless the path begins with two path separators @@ -616,7 +626,7 @@ namespace AZ::IO // iterators //! Returns an iterator to the beginning of the path that can be used to traverse the path - //! according to the following + //! according to the following //! 1. Root name - (0 or 1) //! 2. Root directory - (0 or 1) //! 3. Filename - (0 or more) diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl index 0147ad3356..1d654c1502 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl @@ -240,6 +240,14 @@ namespace AZ::IO return AZStd::fixed_string(m_path.begin(), m_path.end()); } + // as_posix + constexpr AZStd::fixed_string PathView::FixedMaxPathStringAsPosix() const noexcept + { + AZStd::fixed_string resultPath(m_path.begin(), m_path.end()); + AZStd::replace(resultPath.begin(), resultPath.end(), AZ::IO::WindowsPathSeparator, AZ::IO::PosixPathSeparator); + return resultPath; + } + // decomposition constexpr auto PathView::RootName() const -> PathView { @@ -473,8 +481,7 @@ namespace AZ::IO return lhs.Compare(rhs) >= 0; } - template - constexpr void PathView::MakeRelativeTo(PathResultType& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base) + constexpr void PathView::MakeRelativeTo(PathIterable& pathIterable, const AZ::IO::PathView& path, const AZ::IO::PathView& base) noexcept { const bool exactCaseCompare = path.m_preferred_separator == PosixPathSeparator || base.m_preferred_separator == PosixPathSeparator; @@ -492,13 +499,11 @@ namespace AZ::IO if (int res = Internal::ComparePathSegment(*pathParser, *pathParserBase, exactCaseCompare); res != 0) { - pathResult.m_path = AZStd::string_view{}; return; } } else if (CheckIterMismatchAtBase()) { - pathResult.m_path = AZStd::string_view{}; return; } @@ -512,7 +517,6 @@ namespace AZ::IO } if (CheckIterMismatchAtBase()) { - pathResult.m_path = AZStd::string_view{}; return; } } @@ -530,7 +534,7 @@ namespace AZ::IO // If there is no mismatch, return ".". if (!pathParser && !pathParserBase) { - pathResult.m_path = AZStd::string_view{ "." }; + pathIterable.emplace_back(".", parser::PathPartKind::PK_Dot); return; } @@ -539,27 +543,25 @@ namespace AZ::IO int elemCount = parser::DetermineLexicalElementCount(pathParserBase); if (elemCount < 0) { - pathResult.m_path = AZStd::string_view{}; return; } // if elemCount == 0 and (pathParser == end() || pathParser->empty()), returns path("."); otherwise if (elemCount == 0 && (pathParser.AtEnd() || *pathParser == "")) { - pathResult.m_path = AZStd::string_view{ "." }; + pathIterable.emplace_back(".", parser::PathPartKind::PK_Dot); return; } // return a path constructed with 'n' dot-dot elements, followed by the // elements of '*this' after the mismatch. - pathResult = PathResultType(path.m_preferred_separator); while (elemCount--) { - pathResult /= ".."; + pathIterable.emplace_back("..", parser::PathPartKind::PK_DotDot); } for (; pathParser; ++pathParser) { - pathResult /= *pathParser; + pathIterable.emplace_back(*pathParser, parser::ClassifyPathPart(pathParser)); } } @@ -673,7 +675,7 @@ namespace AZ::IO // Basic Path implementation template - constexpr BasicPath::BasicPath(const PathView& other) + constexpr BasicPath::BasicPath(const PathView& other) noexcept : m_path(other.m_path) , m_preferred_separator(other.m_preferred_separator) {} @@ -726,6 +728,7 @@ namespace AZ::IO : m_path(first, last) , m_preferred_separator(preferredSeparator) {} + template constexpr BasicPath::operator PathView() const noexcept { @@ -733,7 +736,7 @@ namespace AZ::IO } template - constexpr auto BasicPath::operator=(const PathView& other) -> BasicPath& + constexpr auto BasicPath::operator=(const PathView& other) noexcept -> BasicPath& { m_path = other.m_path; m_preferred_separator = other.m_preferred_separator; @@ -974,13 +977,13 @@ namespace AZ::IO template constexpr auto BasicPath::MakePreferred() -> BasicPath& { - if (m_preferred_separator != '/') + if (m_preferred_separator != PosixPathSeparator) { - AZStd::replace(m_path.begin(), m_path.end(), '/', m_preferred_separator); + AZStd::replace(m_path.begin(), m_path.end(), PosixPathSeparator, m_preferred_separator); } else { - AZStd::replace(m_path.begin(), m_path.end(), '\\', m_preferred_separator); + AZStd::replace(m_path.begin(), m_path.end(), WindowsPathSeparator, m_preferred_separator); } return *this; } @@ -1033,6 +1036,24 @@ namespace AZ::IO return AZStd::fixed_string(m_path.begin(), m_path.end()); } + // as_posix + // Returns a copy of the path with the path separators converted to PosixPathSeparator + template + AZStd::string BasicPath::StringAsPosix() const + { + AZStd::string resultPath(m_path.begin(), m_path.end()); + AZStd::replace(resultPath.begin(), resultPath.end(), WindowsPathSeparator, PosixPathSeparator); + return resultPath; + } + + template + constexpr AZStd::fixed_string BasicPath::FixedMaxPathStringAsPosix() const noexcept + { + AZStd::fixed_string resultPath(m_path.begin(), m_path.end()); + AZStd::replace(resultPath.begin(), resultPath.end(), WindowsPathSeparator, PosixPathSeparator); + return resultPath; + } + template constexpr void BasicPath::swap(BasicPath& rhs) noexcept { @@ -1234,6 +1255,7 @@ namespace AZ::IO { pathResult /= pathPartView; } + return pathResult; } @@ -1241,7 +1263,13 @@ namespace AZ::IO constexpr auto BasicPath::LexicallyRelative(const PathView& base) const -> BasicPath { BasicPath pathResult(m_preferred_separator); - static_cast(*this).MakeRelativeTo(pathResult, *this, base); + PathView::PathIterable pathIterable; + PathView::MakeRelativeTo(pathIterable, *this, base); + for ([[maybe_unused]] auto [pathPartView, pathPartKind] : pathIterable) + { + pathResult /= pathPartView; + } + return pathResult; } @@ -1355,7 +1383,7 @@ namespace AZ::IO return !basePathParts.empty() || !thisPathParts.IsAbsolute(); } - constexpr FixedMaxPath PathView::LexicallyNormal() const + constexpr auto PathView::LexicallyNormal() const -> FixedMaxPath { FixedMaxPath pathResult(m_preferred_separator); PathIterable pathIterable = GetNormalPathParts(*this); @@ -1367,21 +1395,28 @@ namespace AZ::IO return pathResult; } - constexpr FixedMaxPath PathView::LexicallyRelative(const PathView& base) const + constexpr auto PathView::LexicallyRelative(const PathView& base) const -> FixedMaxPath { FixedMaxPath pathResult(m_preferred_separator); - MakeRelativeTo(pathResult, *this, base); + PathIterable pathIterable; + MakeRelativeTo(pathIterable, *this, base); + for ([[maybe_unused]] auto [pathPartView, pathPartKind] : pathIterable) + { + pathResult /= pathPartView; + } + return pathResult; } - constexpr FixedMaxPath PathView::LexicallyProximate(const PathView& base) const + constexpr auto PathView::LexicallyProximate(const PathView& base) const -> FixedMaxPath { - FixedMaxPath result = LexicallyRelative(base); - if (result.empty()) + FixedMaxPath pathResult = LexicallyRelative(base); + if (pathResult.empty()) { return FixedMaxPath(*this); } - return result; + + return pathResult; } } diff --git a/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl b/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl index a1faa29b31..e700ab0196 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl @@ -49,8 +49,8 @@ namespace AZ::IO constexpr void clear() noexcept; - friend constexpr auto PathView::GetNormalPathParts(const AZ::IO::PathView&) noexcept -> PathIterable; friend constexpr auto PathView::AppendNormalPathParts(PathIterable& pathIterable, const AZ::IO::PathView&) noexcept -> void; + friend constexpr auto PathView::MakeRelativeTo(PathIterable& pathIterable, const AZ::IO::PathView&, const AZ::IO::PathView&) noexcept -> void; PartKindArray m_parts{}; size_t m_size{}; }; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index e1bd717e7b..36f66312d8 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -546,7 +546,7 @@ namespace AZ::SettingsRegistryMergeUtils AZ::IO::FixedMaxPath path = AZ::Utils::GetExecutableDirectory(); registry.Set(FilePathKey_BinaryFolder, path.LexicallyNormal().Native()); - // Engine root folder - corresponds to the @engroot@ and @devroot@ aliases + // Engine root folder - corresponds to the @engroot@ and @engroot@ aliases AZ::IO::FixedMaxPath engineRoot = FindEngineRoot(registry); registry.Set(FilePathKey_EngineRootFolder, engineRoot.LexicallyNormal().Native()); @@ -570,7 +570,7 @@ namespace AZ::SettingsRegistryMergeUtils assetPlatform = AZ::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); } - // Project path - corresponds to the @devassets@ alias + // Project path - corresponds to the @projectroot@ alias // NOTE: Here we append to engineRoot, but if projectPathValue is absolute then engineRoot is discarded. path = engineRoot / projectPathValue; @@ -662,7 +662,7 @@ namespace AZ::SettingsRegistryMergeUtils } else { - // Cache: root - same as the @root@ alias, this is the starting path for cache files. + // Cache: root - same as the @products@ alias, this is the starting path for cache files. path = normalizedProjectPath / "Cache"; registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native()); path /= assetPlatform; diff --git a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h index c9b7d44e1f..d7d0789c1a 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h @@ -52,6 +52,7 @@ namespace AZ MOCK_METHOD2(SetAlias, void(const char* alias, const char* path)); MOCK_METHOD1(ClearAlias, void(const char* alias)); MOCK_CONST_METHOD1(GetAlias, const char*(const char* alias)); + MOCK_METHOD2(SetDeprecatedAlias, void(AZStd::string_view, AZStd::string_view)); MOCK_CONST_METHOD2(ConvertToAlias, AZStd::optional(char* inOutBuffer, AZ::u64 bufferLength)); MOCK_CONST_METHOD2(ConvertToAlias, bool(AZ::IO::FixedMaxPath& aliasPath, const AZ::IO::PathView& path)); MOCK_CONST_METHOD3(ResolvePath, bool(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize)); diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp index c4dd24be35..2031d14d08 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp @@ -51,6 +51,20 @@ namespace AZ::Utils return executableDirectory; } + AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + { + AZ::IO::FixedMaxPathString absolutePath; + AZ::IO::FixedMaxPathString srcPath{ path }; + if (ConvertToAbsolutePath(srcPath.c_str(), absolutePath.data(), absolutePath.capacity())) + { + // Fix the size value of the fixed string by calculating the c-string length using char traits + absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); + return srcPath; + } + + return AZStd::nullopt; + } + AZ::IO::FixedMaxPathString GetEngineManifestPath() { AZ::IO::FixedMaxPath o3deManifestPath = GetO3deManifestDirectory(); diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.h b/Code/Framework/AzCore/AzCore/Utils/Utils.h index d8d4290f7f..c147e38bfb 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.h +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.h @@ -104,6 +104,7 @@ namespace AZ // Attempts the supplied path to an absolute path. //! Returns nullopt if path cannot be converted to an absolute path AZStd::optional ConvertToAbsolutePath(AZStd::string_view path); + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 absolutePathMaxSize); //! Save a string to a file. Otherwise returns a failure with error message. AZ::Outcome WriteFile(AZStd::string_view content, AZStd::string_view filePath); diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp index 1333006c4c..9a3f825bfc 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp +++ b/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp @@ -60,23 +60,34 @@ namespace AZ return writeStorage ? AZStd::make_optional(writeStorage) : AZStd::nullopt; } - AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) { - AZ::IO::FixedMaxPathString absolutePath; - AZ::IO::FixedMaxPathString srcPath{ path }; - if (AZ::Android::Utils::IsApkPath(srcPath.c_str())) + if (AZ::Android::Utils::IsApkPath(path)) { - return srcPath; + azstrcpy(absolutePath, maxLength, path); + return true; } - if(char* result = realpath(srcPath.c_str(), absolutePath.data()); result) +#ifdef PATH_MAX + static constexpr size_t UnixMaxPathLength = PATH_MAX; +#else + // Fallback to 4096 if the PATH_MAX macro isn't defined on the Unix System + static constexpr size_t UnixMaxPathLength = 4096; +#endif + if (!AZ::IO::PathView(path).IsAbsolute()) { - // Fix the size value of the fixed string by calculating the c-string length using char traits - absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); - return absolutePath; + // note that realpath fails if the path does not exist and actually changes the return value + // to be the actual place that FAILED, which we don't want. + // if we fail, we'd prefer to fall through and at least use the original path. + char absolutePathBuffer[UnixMaxPathLength]; + if (const char* result = realpath(path, absolutePathBuffer); result != nullptr) + { + azstrcpy(absolutePath, maxLength, absolutePathBuffer); + return true; + } } - - return AZStd::nullopt; + azstrcpy(absolutePath, maxLength, path); + return AZ::IO::PathView(absolutePath).IsAbsolute(); } } } diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp index 2e31936057..7327c8f152 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp @@ -47,23 +47,32 @@ namespace AZ AZ::IO::FixedMaxPath path{pass->pw_dir}; return path.Native(); } - + return {}; } - AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) { - AZ::IO::FixedMaxPathString absolutePath; - AZ::IO::FixedMaxPathString srcPath{ path }; - - if (char* result = realpath(srcPath.c_str(), absolutePath.data()); result) +#ifdef PATH_MAX + static constexpr size_t UnixMaxPathLength = PATH_MAX; +#else + // Fallback to 4096 if the PATH_MAX macro isn't defined on the Unix System + static constexpr size_t UnixMaxPathLength = 4096; +#endif + if (!AZ::IO::PathView(path).IsAbsolute()) { - // Fix the size value of the fixed string by calculating the c-string length using char traits - absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); - return absolutePath; + // note that realpath fails if the path does not exist and actually changes the return value + // to be the actual place that FAILED, which we don't want. + // if we fail, we'd prefer to fall through and at least use the original path. + char absolutePathBuffer[UnixMaxPathLength]; + if (const char* result = realpath(path, absolutePathBuffer); result != nullptr) + { + azstrcpy(absolutePath, maxLength, absolutePathBuffer); + return true; + } } - - return AZStd::nullopt; + azstrcpy(absolutePath, maxLength, path); + return AZ::IO::PathView(absolutePath).IsAbsolute(); } } // namespace Utils } // namespace AZ diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp index bcba24b768..24786e2bc9 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp @@ -67,19 +67,12 @@ namespace AZ return AZStd::nullopt; } - AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) { - AZ::IO::FixedMaxPathString absolutePath; - AZ::IO::FixedMaxPathString srcPath{ path }; - char* result = _fullpath(absolutePath.data(), srcPath.c_str(), absolutePath.capacity()); - // Force update of the fixed_string size() value - absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); - if (result) - { - return absolutePath; - } - - return AZStd::nullopt; + char* result = _fullpath(absolutePath, path, maxLength); + return result != nullptr; } + + } } diff --git a/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h b/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h index 26b3df55bb..5897b3aaee 100644 --- a/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h +++ b/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h @@ -426,6 +426,10 @@ public: return nullptr; } + void SetDeprecatedAlias(AZStd::string_view, AZStd::string_view) override + { + } + void ClearAlias(const char* ) override { } AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64) const override diff --git a/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp b/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp index 34076a10f6..cf239a0821 100644 --- a/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp +++ b/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp @@ -698,7 +698,7 @@ AZ_POP_DISABLE_WARNING using PathViewLexicallyProximateFixture = PathLexicallyFixture; - TEST_P(PathViewLexicallyProximateFixture, LexicallyProximate_ReturnsRelativePathIfNotEmptyOrTestPathIfNot) + TEST_P(PathViewLexicallyProximateFixture, LexicallyProximate_ReturnsRelativePathIfNotEmptyOrTestPath) { const auto& testParams = GetParam(); AZ::IO::PathView testPath(testParams.m_testPathString, testParams.m_preferredSeparator); diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index e72e2de472..1f99a594fa 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -77,11 +77,15 @@ namespace AzFramework { + namespace ApplicationInternal { static constexpr const char s_prefabSystemKey[] = "/Amazon/Preferences/EnablePrefabSystem"; static constexpr const char s_prefabWipSystemKey[] = "/Amazon/Preferences/EnablePrefabSystemWipFeatures"; static constexpr const char s_legacySlicesAssertKey[] = "/Amazon/Preferences/ShouldAssertForLegacySlicesUsage"; + static constexpr const char* DeprecatedFileIOAliasesRoot = "/O3DE/AzCore/FileIO/DeprecatedAliases"; + static constexpr const char* DeprecatedFileIOAliasesOldAliasKey = "OldAlias"; + static constexpr const char* DeprecatedFileIOAliasesNewAliasKey = "NewAlias"; } Application::Application() @@ -563,6 +567,68 @@ namespace AzFramework } } + struct DeprecatedAliasesKeyVisitor + : AZ::SettingsRegistryInterface::Visitor + { + using VisitResponse = AZ::SettingsRegistryInterface::VisitResponse; + using VisitAction = AZ::SettingsRegistryInterface::VisitAction; + using Type = AZ::SettingsRegistryInterface::Type; + + using AZ::SettingsRegistryInterface::Visitor::Visit; + + VisitResponse Traverse(AZStd::string_view path, AZStd::string_view, + VisitAction action, Type type) override + { + if (action == AZ::SettingsRegistryInterface::VisitAction::Begin) + { + if (type == AZ::SettingsRegistryInterface::Type::Array) + { + m_parentArrayPath = path; + } + + // Strip off last path segment from json path and check if is a child element of the array + if (AZ::StringFunc::TokenizeLast(path, '/'); + m_parentArrayPath == path) + { + m_aliases.emplace_back(); + } + } + else if (action == AZ::SettingsRegistryInterface::VisitAction::End) + { + if (type == AZ::SettingsRegistryInterface::Type::Array) + { + m_parentArrayPath = AZStd::string{}; + } + } + + return AZ::SettingsRegistryInterface::VisitResponse::Continue; + } + + void Visit(AZStd::string_view, AZStd::string_view valueName, Type, AZStd::string_view value) override + { + if (!m_aliases.empty()) + { + if (valueName == ApplicationInternal::DeprecatedFileIOAliasesOldAliasKey) + { + m_aliases.back().m_oldAlias = value; + } + else if (valueName == ApplicationInternal::DeprecatedFileIOAliasesNewAliasKey) + { + m_aliases.back().m_newAlias = value; + } + } + } + + struct AliasPair + { + AZStd::string m_oldAlias; + AZStd::string m_newAlias; + }; + AZStd::vector m_aliases; + + private: + AZStd::string m_parentArrayPath; + }; static void CreateUserCache(const AZ::IO::FixedMaxPath& cacheUserPath, AZ::IO::FileIOBase& fileIoBase) { @@ -610,9 +676,8 @@ namespace AzFramework void Application::SetFileIOAliases() { - if (m_archiveFileIO) + if (auto fileIoBase = m_archiveFileIO.get(); fileIoBase) { - auto fileIoBase = m_archiveFileIO.get(); // Set up the default file aliases based on the settings registry fileIoBase->SetAlias("@engroot@", GetEngineRoot()); fileIoBase->SetAlias("@projectroot@", GetEngineRoot()); @@ -620,29 +685,20 @@ namespace AzFramework { AZ::IO::FixedMaxPath pathAliases; - if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) - { - fileIoBase->SetAlias("@projectcache@", pathAliases.c_str()); - } pathAliases.clear(); if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) { - fileIoBase->SetAlias("@assets@", pathAliases.c_str()); - fileIoBase->SetAlias("@projectplatformcache@", pathAliases.c_str()); - fileIoBase->SetAlias("@root@", pathAliases.c_str()); // Deprecated Use @projectplatformcache@ + fileIoBase->SetAlias("@products@", pathAliases.c_str()); } pathAliases.clear(); if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) { fileIoBase->SetAlias("@engroot@", pathAliases.c_str()); - fileIoBase->SetAlias("@devroot@", pathAliases.c_str()); // Deprecated - Use @engroot@ } pathAliases.clear(); if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) { - fileIoBase->SetAlias("@devassets@", pathAliases.c_str()); // Deprecated - Use @projectsourceassets@ fileIoBase->SetAlias("@projectroot@", pathAliases.c_str()); - fileIoBase->SetAlias("@projectsourceassets@", (pathAliases / "Assets").c_str()); } } @@ -663,6 +719,15 @@ namespace AzFramework } fileIoBase->SetAlias("@log@", projectLogPath.c_str()); fileIoBase->CreatePath(projectLogPath.c_str()); + + DeprecatedAliasesKeyVisitor visitor; + if (m_settingsRegistry->Visit(visitor, ApplicationInternal::DeprecatedFileIOAliasesRoot)) + { + for (const auto& [oldAlias, newAlias] : visitor.m_aliases) + { + fileIoBase->SetDeprecatedAlias(oldAlias, newAlias); + } + } } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp index 8064ba6669..e5a42aabbc 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp @@ -1121,7 +1121,7 @@ namespace AZ::IO if (AZ::IO::FixedMaxPath pathBindRoot; !AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(pathBindRoot, szBindRoot)) { - AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(pathBindRoot, "@assets@"); + AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(pathBindRoot, "@products@"); desc.m_pathBindRoot = pathBindRoot.LexicallyNormal().String(); } else @@ -1807,9 +1807,9 @@ namespace AZ::IO if (m_eRecordFileOpenList != IArchive::RFOM_Disabled) { // we only want to record ASSET access - // assets are identified as files that are relative to the resolved @assets@ alias path + // assets are identified as files that are relative to the resolved @products@ alias path auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); - const char* aliasValue = fileIoBase->GetAlias("@assets@"); + const char* aliasValue = fileIoBase->GetAlias("@products@"); if (AZ::IO::FixedMaxPath resolvedFilePath; fileIoBase->ResolvePath(resolvedFilePath, szFilename) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp index 85ce0b6f9a..9e6e1034ea 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp @@ -546,6 +546,16 @@ namespace AZ::IO realUnderlyingFileIO->GetAlias(alias); } + void ArchiveFileIO::SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + FileIOBase* realUnderlyingFileIO = FileIOBase::GetDirectInstance(); + if (!realUnderlyingFileIO) + { + return; + } + realUnderlyingFileIO->SetDeprecatedAlias(oldAlias, newAlias); + } + AZStd::optional ArchiveFileIO::ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const { if ((!inOutBuffer) || (bufferLength == 0)) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h index 21cef18a7a..7fd4e15e3a 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h @@ -63,6 +63,7 @@ namespace AZ::IO IO::Result FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback) override; void SetAlias(const char* alias, const char* path) override; void ClearAlias(const char* alias) override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp index d7a92efbf6..7b483dc5de 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp @@ -186,8 +186,8 @@ namespace AZ::IO { // filter out the stuff which does not match. - // the problem here is that szDir might be something like "@assets@/levels/*" - // but our archive might be mounted at the root, or at some other folder at like "@assets@" or "@assets@/levels/mylevel" + // the problem here is that szDir might be something like "@products@/levels/*" + // but our archive might be mounted at the root, or at some other folder at like "@products@" or "@products@/levels/mylevel" // so there's really no way to filter out opening the pack and looking at the files inside. // however, the bind root is not part of the inner zip entry name either // and the ZipDir::FindFile actually expects just the chopped off piece. @@ -202,22 +202,22 @@ namespace AZ::IO // Example: - // "@assets@\\levels\\*" <--- szDir - // "@assets@\\" <--- mount point + // "@products@\\levels\\*" <--- szDir + // "@products@\\" <--- mount point // ~~~~~~~~~~~ Common part // "levels\\*" <---- remainder that is not in common // "" <--- mount point remainder. In this case, we should scan the contents of the pak for the remainder // Example: - // "@assets@\\levels\\*" <--- szDir - // "@assets@\\levels\\mylevel\\" <--- mount point (its level.pak) + // "@products@\\levels\\*" <--- szDir + // "@products@\\levels\\mylevel\\" <--- mount point (its level.pak) // ~~~~~~~~~~~~~~~~~~ common part // "*" <---- remainder that is not in common // "mylevel\\" <--- mount point remainder. // example: - // "@assets@\\levels\\otherlevel\\*" <--- szDir - // "@assets@\\levels\\mylevel\\" <--- mount point (its level.pak) + // "@products@\\levels\\otherlevel\\*" <--- szDir + // "@products@\\levels\\mylevel\\" <--- mount point (its level.pak) // "otherlevel\\*" <---- remainder // "mylevel\\" <--- mount point remainder. @@ -249,7 +249,7 @@ namespace AZ::IO // which means we may search inside the pack. ScanInZip(it->pZip.get(), sourcePathRemainder.Native()); } - + } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp b/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp index 0a6116d313..4c6ed0363e 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp @@ -94,7 +94,7 @@ namespace AZ::IO::Internal } AZStd::smatch matches; - const AZStd::regex lodRegex("@assets@\\\\(.*)_lod[0-9]+(\\.cgfm?)"); + const AZStd::regex lodRegex("@products@\\\\(.*)_lod[0-9]+(\\.cgfm?)"); if (!AZStd::regex_match(szPath, matches, lodRegex) || matches.size() != 3) { // The current file is not a valid LOD file diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp index 9b1946701c..e6b8211c28 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp @@ -725,7 +725,7 @@ namespace AzFramework if (!info.m_relativePath.empty()) { - const char* devAssetRoot = fileIO->GetAlias("@devassets@"); + const char* devAssetRoot = fileIO->GetAlias("@projectroot@"); if (devAssetRoot) { AZ::Data::AssetStreamInfo streamInfo; diff --git a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp index a7c6b18061..cc31df3dbc 100644 --- a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp +++ b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp @@ -61,7 +61,7 @@ namespace AzFramework AZ::IO::Path& gemAbsPath = gemInfo.m_absoluteSourcePaths.emplace_back(value); // Resolve any file aliases first - Do not use ResolvePath() as that assumes - // any relative path is underneath the @assets@ alias + // any relative path is underneath the @products@ alias if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { AZ::IO::FixedMaxPath replacedAliasPath; diff --git a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp index 49e16dcb90..c1b9c941bc 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include namespace AZ @@ -292,7 +294,7 @@ namespace AZ void LocalFileIO::CheckInvalidWrite([[maybe_unused]] const char* path) { #if defined(AZ_ENABLE_TRACING) - const char* assetAliasPath = GetAlias("@assets@"); + const char* assetAliasPath = GetAlias("@products@"); if (path && assetAliasPath) { const AZ::IO::PathView pathView(path); @@ -478,17 +480,15 @@ namespace AZ return false; } - if (IsAbsolutePath(path)) + if (AZ::IO::PathView(path).HasRootPath()) { size_t pathLen = strlen(path); if (pathLen + 1 < resolvedPathSize) { azstrncpy(resolvedPath, resolvedPathSize, path, pathLen + 1); - //see if the absolute path uses @assets@ or @root@, if it does lowercase the relative part - [[maybe_unused]] bool lowercasePath = LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@assets@")) - || LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@root@")) - || LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@projectplatformcache@")); + //see if the absolute path matches the resolved value of @products@, if it does lowercase the relative part + LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@products@")); ToUnixSlashes(resolvedPath, resolvedPathSize); return true; @@ -499,34 +499,39 @@ namespace AZ } } - char rootedPathBuffer[AZ_MAX_PATH_LEN] = {0}; + constexpr AZStd::string_view productAssetAlias = "@products@"; + // Add plus one for the path separator: / + constexpr size_t MaxPathSizeWithProductAssetAlias = AZ::IO::MaxPathLength + productAssetAlias.size() + 1; + using RootedPathString = AZStd::fixed_string; + RootedPathString rootedPathBuffer; const char* rootedPath = path; - // if the path does not begin with an alias, then it is assumed to begin with @assets@ + // if the path does not begin with an alias, then it is assumed to begin with @products@ if (path[0] != '@') { - if (GetAlias("@assets@")) + if (GetAlias("@products@")) { - const int rootLength = 9;// strlen("@assets@/") - azstrncpy(rootedPathBuffer, AZ_MAX_PATH_LEN, "@assets@/", rootLength); - size_t pathLen = strlen(path); - size_t rootedPathBufferlength = rootLength + pathLen + 1;// +1 for null terminator - if (rootedPathBufferlength > resolvedPathSize) + + if (const size_t requiredSize = productAssetAlias.size() + strlen(path) + 1; + requiredSize > rootedPathBuffer.capacity()) { - AZ_Assert(rootedPathBufferlength < resolvedPathSize, "Constructed path length is wrong:%s", rootedPathBuffer);//path constructed is wrong - size_t remainingSize = resolvedPathSize - rootLength - 1;// - 1 for null terminator - azstrncpy(rootedPathBuffer + rootLength, AZ_MAX_PATH_LEN, path, remainingSize); - rootedPathBuffer[resolvedPathSize - 1] = '\0'; + AZ_Error("FileIO", false, "Prepending the %.*s alias to the input path results in a path longer than the" + " AZ::IO::MaxPathLength + the alias size of %zu. The size of the potential failed path is %zu", + AZ_STRING_ARG(productAssetAlias), rootedPathBuffer.capacity(), requiredSize) } else { - azstrncpy(rootedPathBuffer + rootLength, AZ_MAX_PATH_LEN - rootLength, path, pathLen + 1); + rootedPathBuffer = RootedPathString::format("%.*s/%s", AZ_STRING_ARG(productAssetAlias), path); } } else { - ConvertToAbsolutePath(path, rootedPathBuffer, AZ_MAX_PATH_LEN); + if (ConvertToAbsolutePath(path, rootedPathBuffer.data(), rootedPathBuffer.capacity())) + { + // Recalculate the internal string length + rootedPathBuffer.resize_no_construct(AZStd::char_traits::length(rootedPathBuffer.data())); + } } - rootedPath = rootedPathBuffer; + rootedPath = rootedPathBuffer.c_str(); } if (ResolveAliases(rootedPath, resolvedPath, resolvedPathSize)) @@ -561,11 +566,57 @@ namespace AZ const char* LocalFileIO::GetAlias(const char* key) const { - const auto it = m_aliases.find(key); - if (it != m_aliases.end()) + if (const auto it = m_aliases.find(key); it != m_aliases.end()) { return it->second.c_str(); } + else if (const auto deprecatedIt = m_deprecatedAliases.find(key); + deprecatedIt != m_deprecatedAliases.end()) + { + AZ_Error("FileIO", false, R"(Alias "%s" is deprecated. Please use alias "%s" instead)", + key, deprecatedIt->second.c_str()); + AZStd::string_view aliasValue = deprecatedIt->second; + // Contains the list of aliases resolved so far + // If max_size is hit, than an error is logged and nullptr is returned + using VisitedAliasSet = AZStd::fixed_unordered_set; + VisitedAliasSet visitedAliasSet; + while (aliasValue.starts_with("@")) + { + if (visitedAliasSet.contains(aliasValue)) + { + AZ_Error("FileIO", false, "Cycle found with for alias %.*s when trying to resolve deprecated alias %s", + AZ_STRING_ARG(aliasValue), key); + return nullptr; + } + + if(visitedAliasSet.size() == visitedAliasSet.max_size()) + { + AZ_Error("FileIO", false, "Unable to resolve path to deprecated alias %s within %zu steps", + key, visitedAliasSet.max_size()); + return nullptr; + } + + // Add the current alias value to the visited set + visitedAliasSet.emplace(aliasValue); + + // Check if the alias value corresponds to another alias + if (auto resolvedIter = m_aliases.find(aliasValue); resolvedIter != m_aliases.end()) + { + aliasValue = resolvedIter->second; + } + else if (resolvedIter = m_deprecatedAliases.find(aliasValue); + resolvedIter != m_deprecatedAliases.end()) + { + aliasValue = resolvedIter->second; + } + else + { + return nullptr; + } + } + + return aliasValue.data(); + } return nullptr; } @@ -574,6 +625,11 @@ namespace AZ m_aliases.erase(key); } + void LocalFileIO::SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + m_deprecatedAliases[oldAlias] = newAlias; + } + AZStd::optional LocalFileIO::ConvertToAliasBuffer(char* outBuffer, AZ::u64 outBufferLength, AZStd::string_view inBuffer) const { size_t longestMatch = 0; @@ -675,7 +731,9 @@ namespace AZ : string_view_pair{}; size_t requiredResolvedPathSize = pathView.size() - aliasKey.size() + aliasValue.size() + 1; - AZ_Assert(path != resolvedPath && resolvedPathSize >= requiredResolvedPathSize, "Resolved path is incorrect"); + AZ_Assert(path != resolvedPath, "ResolveAliases does not support inplace update of the path"); + AZ_Assert(resolvedPathSize >= requiredResolvedPathSize, "Resolved path size %llu not large enough. It needs to be %zu", + resolvedPathSize, requiredResolvedPathSize); // we assert above, but we also need to properly handle the case when the resolvedPath buffer size // is too small to copy the source into. if (path == resolvedPath || (resolvedPathSize < requiredResolvedPathSize)) @@ -699,13 +757,9 @@ namespace AZ resolvedPath[resolvedPathLen] = '\0'; // If the path started with one of the "asset cache" path aliases, lowercase the path - const char* assetAliasPath = GetAlias("@assets@"); - const char* rootAliasPath = GetAlias("@root@"); - const char* projectPlatformCacheAliasPath = GetAlias("@projectplatformcache@"); + const char* projectPlatformCacheAliasPath = GetAlias("@products@"); - const bool lowercasePath = (assetAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, assetAliasPath)) || - (rootAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, rootAliasPath)) || - (projectPlatformCacheAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, projectPlatformCacheAliasPath)); + const bool lowercasePath = projectPlatformCacheAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, projectPlatformCacheAliasPath); if (lowercasePath) { @@ -822,5 +876,10 @@ namespace AZ return pathStr + "/"; } + + bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const + { + return AZ::Utils::ConvertToAbsolutePath(path, absolutePath, maxLength); + } } // namespace IO } // namespace AZ diff --git a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h index a9db55b320..a5ee1519a2 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h @@ -61,6 +61,8 @@ namespace AZ void SetAlias(const char* alias, const char* path) override; void ClearAlias(const char* alias) override; const char* GetAlias(const char* alias) const override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; + AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; @@ -71,7 +73,7 @@ namespace AZ bool GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const override; bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const; - + private: SystemFile* GetFilePointerFromHandle(HandleType fileHandle); @@ -79,7 +81,6 @@ namespace AZ AZStd::optional ConvertToAliasBuffer(char* outBuffer, AZ::u64 outBufferLength, AZStd::string_view inBuffer) const; bool ResolveAliases(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const; - bool IsAbsolutePath(const char* path) const; bool LowerIfBeginsWith(char* inOutBuffer, AZ::u64 bufferLen, const char* alias) const; @@ -91,6 +92,7 @@ namespace AZ AZStd::atomic m_nextHandle; AZStd::unordered_map m_openFiles; AZStd::unordered_map m_aliases; + AZStd::unordered_map m_deprecatedAliases; void CheckInvalidWrite(const char* path); }; diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp index 041e5baf4a..9e05cd5cb9 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp @@ -49,14 +49,14 @@ namespace AZ s_IOLog.append(m_name); s_IOLog.append("\r\n"); } - + void Append(const char* line) { s_IOLog.append(AZStd::string::format("%u ", m_fileOperation)); s_IOLog.append(line); s_IOLog.append("\r\n"); } - + ~LogCall() { s_IOLog.append(AZStd::string::format("%u End ", m_fileOperation)); @@ -251,7 +251,7 @@ namespace AZ REMOTEFILE_LOG_APPEND(AZStd::string::format("NetworkFileIO::Size(filePath=%s) size request failed. return Error", filePath).c_str()); return ResultCode::Error; } - + size = response.m_size; REMOTEFILE_LOG_APPEND(AZStd::string::format("NetworkFileIO::Size(filePath=%s) size=%u. return Success", filePath, size).c_str()); return ResultCode::Success; @@ -793,6 +793,12 @@ namespace AZ REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::ClearAlias(alias=%s)", alias?alias:"nullptr").c_str()); } + void NetworkFileIO::SetDeprecatedAlias([[maybe_unused]] AZStd::string_view oldAlias, [[maybe_unused]] AZStd::string_view newAlias) + { + REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::SetDeprecatedAlias(oldAlias=%.*s, newAlias=%.*s)", + AZ_STRING_ARG(oldAlias), AZ_STRING_ARG(newAlias)).c_str()); + } + AZStd::optional NetworkFileIO::ConvertToAlias(char* inOutBuffer, [[maybe_unused]] AZ::u64 bufferLength) const { REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::ConvertToAlias(inOutBuffer=%s, bufferLength=%u)", inOutBuffer?inOutBuffer:"nullptr", bufferLength).c_str()); @@ -927,7 +933,7 @@ namespace AZ { m_cacheLookaheadPos = filePosition - CacheStartFilePosition(); } - + void RemoteFileCache::SyncCheck() { #ifdef REMOTEFILEIO_SYNC_CHECK @@ -955,7 +961,7 @@ namespace AZ AZ_TracePrintf(RemoteFileCacheChannel, "RemoteFileCache::SyncCheck(m_fileHandle=%u) tell request failed.", m_fileHandle); REMOTEFILE_LOG_APPEND(AZStd::string::format("RemoteFileCache::SyncCheck(m_fileHandle=%u) tell request failed.", m_fileHandle).c_str()); } - + if (responce.m_offset != m_filePosition) { AZ_TracePrintf(RemoteFileCacheChannel, "RemoteFileCache::SyncCheck(m_fileHandle=%u) failed!!! m_filePosition=%u tell=%u", m_fileHandle, m_filePosition, responce.m_offset); @@ -1028,7 +1034,7 @@ namespace AZ { REMOTEFILE_LOG_CALL(AZStd::string::format("RemoteFileIO()::Close(fileHandle=%u)", fileHandle).c_str()); Result returnValue = NetworkFileIO::Close(fileHandle); - + if (returnValue == ResultCode::Success) { AZStd::lock_guard lock(m_remoteFileCacheGuard); @@ -1160,7 +1166,7 @@ namespace AZ REMOTEFILE_LOG_CALL(AZStd::string::format("RemoteFileIO()::Read(fileHandle=%u, buffer=OUT, size=%u, failOnFewerThanSizeBytesRead=%s, bytesRead=OUT)", fileHandle, size, failOnFewerThanSizeBytesRead ? "True" : "False").c_str()); AZStd::lock_guard lock(m_remoteFileCacheGuard); RemoteFileCache& cache = GetCache(fileHandle); - + AZ::u64 remainingBytesToRead = size; AZ::u64 bytesReadFromCache = 0; AZ::u64 remainingBytesInCache = cache.RemainingBytes(); @@ -1263,7 +1269,7 @@ namespace AZ RemoteFileCache& cache = GetCache(fileHandle); if (cache.m_cacheLookaheadBuffer.size() && cache.RemainingBytes()) { - // find out where we are + // find out where we are AZ::u64 seekPosition = cache.CacheFilePosition(); // note, seeks are predicted, and do not ask for a response. @@ -1361,6 +1367,14 @@ namespace AZ } } + void RemoteFileIO::SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + if (m_excludedFileIO) + { + m_excludedFileIO->SetDeprecatedAlias(oldAlias, newAlias); + } + } + AZStd::optional RemoteFileIO::ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const { return m_excludedFileIO ? m_excludedFileIO->ConvertToAlias(inOutBuffer, bufferLength) : strlen(inOutBuffer); diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h index d91e59bebc..77e91e1978 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h @@ -102,6 +102,7 @@ namespace AZ Result FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback) override; void SetAlias(const char* alias, const char* path) override; void ClearAlias(const char* alias) override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; @@ -194,6 +195,7 @@ namespace AZ void SetAlias(const char* alias, const char* path) override; const char* GetAlias(const char* alias) const override; void ClearAlias(const char* alias) override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp index b454755cd4..bd5ba39d76 100644 --- a/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -42,10 +41,10 @@ namespace AZ { Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) { - char resolvedSourcePath[AZ_MAX_PATH_LEN]; - char resolvedDestPath[AZ_MAX_PATH_LEN]; - ResolvePath(sourceFilePath, resolvedSourcePath, AZ_MAX_PATH_LEN); - ResolvePath(destinationFilePath, resolvedDestPath, AZ_MAX_PATH_LEN); + char resolvedSourcePath[AZ::IO::MaxPathLength]; + char resolvedDestPath[AZ::IO::MaxPathLength]; + ResolvePath(sourceFilePath, resolvedSourcePath, AZ::IO::MaxPathLength); + ResolvePath(destinationFilePath, resolvedDestPath, AZ::IO::MaxPathLength); if (AZ::Android::Utils::IsApkPath(sourceFilePath) || AZ::Android::Utils::IsApkPath(destinationFilePath)) { @@ -77,18 +76,17 @@ namespace AZ { ANDROID_IO_PROFILE_SECTION_ARGS("FindFiles:%s", filePath); - char resolvedPath[AZ_MAX_PATH_LEN]; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength]; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); AZStd::string pathWithoutSlash = RemoveTrailingSlash(resolvedPath); bool isInAPK = AZ::Android::Utils::IsApkPath(pathWithoutSlash.c_str()); + AZ::IO::FixedMaxPath tempBuffer; if (isInAPK) { AZ::IO::FixedMaxPath strippedPath = AZ::Android::Utils::StripApkPrefix(pathWithoutSlash.c_str()); - char tempBuffer[AZ_MAX_PATH_LEN] = {0}; - AZ::Android::APKFileHandler::ParseDirectory(strippedPath.c_str(), [&](const char* name) { AZStd::string_view filenameView = name; @@ -98,10 +96,9 @@ namespace AZ AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath); foundFilePath += name; // if aliased, de-alias! - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str()); - ConvertToAlias(tempBuffer, AZ_MAX_PATH_LEN); + ConvertToAlias(tempBuffer, AZ::IO::PathView{ foundFilePath }); - if (!callback(tempBuffer)) + if (!callback(tempBuffer.c_str())) { return false; } @@ -115,10 +112,6 @@ namespace AZ if (dir != nullptr) { - // because the absolute path might actually be SHORTER than the alias ("c:/r/dev" -> "@devroot@"), we need to - // use a static buffer here. - char tempBuffer[AZ_MAX_PATH_LEN]; - // clear the errno state so we can distinguish between errors and end of stream errno = 0; struct dirent* entry = readdir(dir); @@ -133,10 +126,9 @@ namespace AZ AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath); foundFilePath += entry->d_name; // if aliased, de-alias! - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str()); - ConvertToAlias(tempBuffer, AZ_MAX_PATH_LEN); + ConvertToAlias(tempBuffer, AZ::IO::PathView{ foundFilePath }); - if (!callback(tempBuffer)) + if (!callback(tempBuffer.c_str())) { break; } @@ -163,8 +155,8 @@ namespace AZ Result LocalFileIO::CreatePath(const char* filePath) { - char resolvedPath[AZ_MAX_PATH_LEN]; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength]; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); if (AZ::Android::Utils::IsApkPath(resolvedPath)) { @@ -201,33 +193,5 @@ namespace AZ mkdir(pathBuffer.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); return IsDirectory(resolvedPath) ? ResultCode::Success : ResultCode::Error; } - - bool LocalFileIO::IsAbsolutePath(const char* path) const - { - return path && path[0] == '/'; - } - - bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const - { - if (AZ::Android::Utils::IsApkPath(path)) - { - azstrncpy(absolutePath, maxLength, path, maxLength); - return true; - } - AZ_Assert(maxLength >= AZ_MAX_PATH_LEN, "Path length is larger than AZ_MAX_PATH_LEN"); - if (!IsAbsolutePath(path)) - { - // note that realpath fails if the path does not exist and actually changes the return value - // to be the actual place that FAILED, which we don't want. - // if we fail, we'd prefer to fall through and at least use the original path. - const char* result = realpath(path, absolutePath); - if (result) - { - return true; - } - } - azstrcpy(absolutePath, maxLength, path); - return IsAbsolutePath(absolutePath); - } } // namespace IO }//namespace AZ diff --git a/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp b/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp index 844464681a..cbcf4a3f56 100644 --- a/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp +++ b/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include namespace AZ @@ -19,11 +19,11 @@ namespace AZ { Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) { - char resolvedSourceFilePath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(sourceFilePath, resolvedSourceFilePath, AZ_MAX_PATH_LEN); + char resolvedSourceFilePath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(sourceFilePath, resolvedSourceFilePath, AZ::IO::MaxPathLength); - char resolvedDestinationFilePath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(destinationFilePath, resolvedDestinationFilePath, AZ_MAX_PATH_LEN); + char resolvedDestinationFilePath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(destinationFilePath, resolvedDestinationFilePath, AZ::IO::MaxPathLength); // Use standard C++ method of file copy. { @@ -45,17 +45,15 @@ namespace AZ Result LocalFileIO::FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback) { - char resolvedPath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); AZStd::string withoutSlash = RemoveTrailingSlash(resolvedPath); DIR* dir = opendir(withoutSlash.c_str()); if (dir != nullptr) { - // because the absolute path might actually be SHORTER than the alias ("c:/r/dev" -> "@devroot@"), we need to - // use a static buffer here. - char tempBuffer[AZ_MAX_PATH_LEN]; + AZ::IO::FixedMaxPath tempBuffer; errno = 0; struct dirent* entry = readdir(dir); @@ -70,10 +68,9 @@ namespace AZ AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath); foundFilePath += entry->d_name; // if aliased, dealias! - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str()); - ConvertToAlias(tempBuffer, AZ_MAX_PATH_LEN); + ConvertToAlias(tempBuffer, AZ::IO::PathView{ foundFilePath }); - if (!callback(tempBuffer)) + if (!callback(tempBuffer.c_str())) { break; } @@ -92,8 +89,8 @@ namespace AZ Result LocalFileIO::CreatePath(const char* filePath) { - char resolvedPath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); // create all paths up to that directory. // its not an error if the path exists. @@ -125,28 +122,5 @@ namespace AZ mkdir(buf.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); return IsDirectory(resolvedPath) ? ResultCode::Success : ResultCode::Error; } - - bool LocalFileIO::IsAbsolutePath(const char* path) const - { - return path && path[0] == '/'; - } - - bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const - { - AZ_Assert(maxLength >= AZ_MAX_PATH_LEN, "Path length is larger than AZ_MAX_PATH_LEN"); - if (!IsAbsolutePath(path)) - { - // note that realpath fails if the path does not exist and actually changes the return value - // to be the actual place that FAILED, which we don't want. - // if we fail, we'd prefer to fall through and at least use the original path. - const char* result = realpath(path, absolutePath); - if (result) - { - return true; - } - } - azstrcpy(absolutePath, maxLength, path); - return IsAbsolutePath(absolutePath); - } } // namespace IO } // namespace AZ diff --git a/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp b/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp index 64787d4951..7ff8a96c09 100644 --- a/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp +++ b/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp @@ -47,7 +47,7 @@ namespace AZ if (hFind != INVALID_HANDLE_VALUE) { - // because the absolute path might actually be SHORTER than the alias ("c:/r/dev" -> "@devroot@"), we need to + // because the absolute path might actually be SHORTER than the alias ("D:/o3de" -> "@engroot@"), we need to // use a static buffer here. char tempBuffer[AZ_MAX_PATH_LEN]; do @@ -133,36 +133,5 @@ namespace AZ return SystemFile::CreateDir(buf.c_str()) ? ResultCode::Success : ResultCode::Error; } - - bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const - { - char* result = _fullpath(absolutePath, path, maxLength); - size_t len = ::strlen(absolutePath); - if (len > 0) - { - // strip trailing slash - if (absolutePath[len - 1] == '/' || absolutePath[len - 1] == '\\') - { - absolutePath[len - 1] = 0; - } - - // For some reason, at least on windows, _fullpath returns a lowercase drive letter even though other systems like Qt, use upper case. - if (len > 2) - { - if (absolutePath[1] == ':') - { - absolutePath[0] = (char)toupper(absolutePath[0]); - } - } - } - return result != nullptr; - } - - bool LocalFileIO::IsAbsolutePath(const char* path) const - { - char drive[16] = { 0 }; - _splitpath_s(path, drive, 16, nullptr, 0, nullptr, 0, nullptr, 0); - return strlen(drive) > 0; - } } // namespace IO }//namespace AZ diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp index b8f62a2b77..173ec61263 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp @@ -7,26 +7,24 @@ */ #include #include +#include +#include #include -namespace AZ +namespace AZ::IO { - namespace IO + Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) { + AZ::IO::FixedMaxPath resolvedSourcePath; + ResolvePath(resolvedSourcePath, sourceFilePath); + AZ::IO::FixedMaxPath resolvedDestPath; + ResolvePath(resolvedDestPath, destinationFilePath); - Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) - { - char resolvedSourcePath[AZ_MAX_PATH_LEN]; - ResolvePath(sourceFilePath, resolvedSourcePath, AZ_MAX_PATH_LEN); - char resolvedDestPath[AZ_MAX_PATH_LEN]; - ResolvePath(destinationFilePath, resolvedDestPath, AZ_MAX_PATH_LEN); + AZStd::fixed_wstring resolvedSourcePathW; + AZStd::fixed_wstring resolvedDestPathW; + AZStd::to_wstring(resolvedSourcePathW, resolvedSourcePath.Native()); + AZStd::to_wstring(resolvedDestPathW, resolvedDestPath.Native()); - if (::CopyFileA(resolvedSourcePath, resolvedDestPath, false) == 0) - { - return ResultCode::Error; - } - - return ResultCode::Success; - } - } // namespace IO -}//namespace AZ + return ::CopyFileW(resolvedSourcePathW.c_str(), resolvedDestPathW.c_str(), false) != 0 ? ResultCode::Success : ResultCode::Error; + } +}//namespace AZ::IO diff --git a/Code/Framework/AzFramework/Tests/Application.cpp b/Code/Framework/AzFramework/Tests/Application.cpp index 313b5e3b56..9ad072cba5 100644 --- a/Code/Framework/AzFramework/Tests/Application.cpp +++ b/Code/Framework/AzFramework/Tests/Application.cpp @@ -26,7 +26,7 @@ protected: } if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { - fileIoBase->SetAlias("@assets@", m_tempDirectory.GetDirectory()); + fileIoBase->SetAlias("@products@", m_tempDirectory.GetDirectory()); } } diff --git a/Code/Framework/AzFramework/Tests/ArchiveTests.cpp b/Code/Framework/AzFramework/Tests/ArchiveTests.cpp index 8e88ccfc39..37babb49a8 100644 --- a/Code/Framework/AzFramework/Tests/ArchiveTests.cpp +++ b/Code/Framework/AzFramework/Tests/ArchiveTests.cpp @@ -50,7 +50,7 @@ namespace UnitTest m_application->Start({}); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); } @@ -262,7 +262,7 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(testArchivePath_withSubfolders.c_str())); - EXPECT_TRUE(archive->OpenPack("@assets@", testArchivePath_withSubfolders.c_str())); + EXPECT_TRUE(archive->OpenPack("@products@", testArchivePath_withSubfolders.c_str())); EXPECT_TRUE(archive->IsFileExist(fileInArchiveFile)); } @@ -353,7 +353,7 @@ namespace UnitTest // and be able to IMMEDIATELY // * read the file in the subfolder // * enumerate the folders (including that subfolder) even though they are 'virtual', not real folders on physical media - // * all of the above even though the mount point for the archive is @assets@ wheras the physical pack lives in @usercache@ + // * all of the above even though the mount point for the archive is @products@ wheras the physical pack lives in @usercache@ // finally, we're going to repeat the above test but with files mounted with subfolders // so for example, the pack will contain levelinfo.xml at the root of it // but it will be mounted at a subfolder (levels/mylevel). @@ -388,7 +388,7 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(testArchivePath_withSubfolders)); - EXPECT_TRUE(archive->OpenPack("@assets@", testArchivePath_withSubfolders)); + EXPECT_TRUE(archive->OpenPack("@products@", testArchivePath_withSubfolders)); // ---- BARRAGE OF TESTS EXPECT_TRUE(archive->IsFileExist("levels\\mylevel\\levelinfo.xml")); EXPECT_TRUE(archive->IsFileExist("levels//mylevel//levelinfo.xml")); @@ -484,7 +484,7 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(testArchivePath_withMountPoint)); - EXPECT_TRUE(archive->OpenPack("@assets@\\uniquename\\mylevel2", testArchivePath_withMountPoint)); + EXPECT_TRUE(archive->OpenPack("@products@\\uniquename\\mylevel2", testArchivePath_withMountPoint)); // ---- BARRAGE OF TESTS EXPECT_TRUE(archive->IsFileExist("uniquename\\mylevel2\\levelinfo.xml")); @@ -543,7 +543,7 @@ namespace UnitTest archive->ClosePack(testArchivePath_withMountPoint); // --- test to make sure that when you iterate only the first component is found, so bury it deep and ask for the root - EXPECT_TRUE(archive->OpenPack("@assets@\\uniquename\\mylevel2\\mylevel3\\mylevel4", testArchivePath_withMountPoint)); + EXPECT_TRUE(archive->OpenPack("@products@\\uniquename\\mylevel2\\mylevel3\\mylevel4", testArchivePath_withMountPoint)); found_mylevel_folder = false; handle = archive->FindFirst("uniquename\\*"); @@ -574,9 +574,9 @@ namespace UnitTest found_mylevel_folder = false; // now make sure no red herrings appear - // for example, if a file is mounted at "@assets@\\uniquename\\mylevel2\\mylevel3\\mylevel4" - // and the file "@assets@\\somethingelse" is requested it should not be found - // in addition if the file "@assets@\\uniquename\\mylevel3" is requested it should not be found + // for example, if a file is mounted at "@products@\\uniquename\\mylevel2\\mylevel3\\mylevel4" + // and the file "@products@\\somethingelse" is requested it should not be found + // in addition if the file "@products@\\uniquename\\mylevel3" is requested it should not be found handle = archive->FindFirst("somethingelse\\*"); EXPECT_FALSE(static_cast(handle)); @@ -610,7 +610,7 @@ namespace UnitTest cpfio.Remove(genericArchiveFileName); // create the asset alias directory - cpfio.CreatePath("@assets@"); + cpfio.CreatePath("@products@"); // create generic file @@ -635,11 +635,11 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(genericArchiveFileName)); - EXPECT_TRUE(archive->OpenPack("@assets@", genericArchiveFileName)); + EXPECT_TRUE(archive->OpenPack("@products@", genericArchiveFileName)); // ---- BARRAGE OF TESTS EXPECT_TRUE(cpfio.Exists("testfile.xml")); - EXPECT_TRUE(cpfio.Exists("@assets@/testfile.xml")); // this should be hte same file + EXPECT_TRUE(cpfio.Exists("@products@/testfile.xml")); // this should be hte same file EXPECT_TRUE(!cpfio.Exists("@log@/testfile.xml")); EXPECT_TRUE(!cpfio.Exists("@usercache@/testfile.xml")); EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml")); @@ -685,9 +685,9 @@ namespace UnitTest EXPECT_EQ(ResultCode::Success, cpfio.Close(normalFileHandle)); EXPECT_TRUE(!cpfio.IsDirectory("testfile.xml")); - EXPECT_TRUE(cpfio.IsDirectory("@assets@")); + EXPECT_TRUE(cpfio.IsDirectory("@products@")); EXPECT_TRUE(cpfio.IsReadOnly("testfile.xml")); - EXPECT_TRUE(cpfio.IsReadOnly("@assets@/testfile.xml")); + EXPECT_TRUE(cpfio.IsReadOnly("@products@/testfile.xml")); EXPECT_TRUE(!cpfio.IsReadOnly("@log@/unittesttemp/realfileforunittest.xml")); @@ -714,10 +714,10 @@ namespace UnitTest // find files test. AZ::IO::FixedMaxPath resolvedTestFilePath; - EXPECT_TRUE(cpfio.ResolvePath(resolvedTestFilePath, AZ::IO::PathView("@assets@/testfile.xml"))); + EXPECT_TRUE(cpfio.ResolvePath(resolvedTestFilePath, AZ::IO::PathView("@products@/testfile.xml"))); bool foundIt = false; // note that this file exists only in the archive. - cpfio.FindFiles("@assets@", "*.xml", [&foundIt, &cpfio, &resolvedTestFilePath](const char* foundName) + cpfio.FindFiles("@products@", "*.xml", [&foundIt, &cpfio, &resolvedTestFilePath](const char* foundName) { AZ::IO::FixedMaxPath resolvedFoundPath; EXPECT_TRUE(cpfio.ResolvePath(resolvedFoundPath, AZ::IO::PathView(foundName))); @@ -734,10 +734,10 @@ namespace UnitTest // The following test is disabled because it will trigger an AZ_ERROR which will affect the outcome of this entire test - // EXPECT_NE(ResultCode::Success, cpfio.Remove("@assets@/testfile.xml")); // may not delete archive files + // EXPECT_NE(ResultCode::Success, cpfio.Remove("@products@/testfile.xml")); // may not delete archive files // make sure it works with and without alias: - EXPECT_TRUE(cpfio.Exists("@assets@/testfile.xml")); + EXPECT_TRUE(cpfio.Exists("@products@/testfile.xml")); EXPECT_TRUE(cpfio.Exists("testfile.xml")); EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml")); @@ -788,22 +788,22 @@ namespace UnitTest EXPECT_TRUE(archive->ClosePack(realNameBuf)); // change its actual location: - EXPECT_TRUE(archive->OpenPack("@assets@", realNameBuf)); - EXPECT_TRUE(archive->IsFileExist("@assets@/foundit.dat")); + EXPECT_TRUE(archive->OpenPack("@products@", realNameBuf)); + EXPECT_TRUE(archive->IsFileExist("@products@/foundit.dat")); EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous location! - EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); - EXPECT_FALSE(archive->IsFileExist("@assets@/notfoundit.dat")); + EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); + EXPECT_FALSE(archive->IsFileExist("@products@/notfoundit.dat")); EXPECT_TRUE(archive->ClosePack(realNameBuf)); // try sub-folders - EXPECT_TRUE(archive->OpenPack("@assets@/mystuff", realNameBuf)); - EXPECT_TRUE(archive->IsFileExist("@assets@/mystuff/foundit.dat")); - EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat")); // do not find it in the previous locations! + EXPECT_TRUE(archive->OpenPack("@products@/mystuff", realNameBuf)); + EXPECT_TRUE(archive->IsFileExist("@products@/mystuff/foundit.dat")); + EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat")); // do not find it in the previous locations! EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous locations! - EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); - EXPECT_FALSE(archive->IsFileExist("@assets@/mystuff/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); - EXPECT_FALSE(archive->IsFileExist("@assets@/notfoundit.dat")); // non-existent file - EXPECT_FALSE(archive->IsFileExist("@assets@/mystuff/notfoundit.dat")); // non-existent file + EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); + EXPECT_FALSE(archive->IsFileExist("@products@/mystuff/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); + EXPECT_FALSE(archive->IsFileExist("@products@/notfoundit.dat")); // non-existent file + EXPECT_FALSE(archive->IsFileExist("@products@/mystuff/notfoundit.dat")); // non-existent file EXPECT_TRUE(archive->ClosePack(realNameBuf)); } @@ -861,7 +861,7 @@ namespace UnitTest AZ::IO::FileIOBase* ioBase = AZ::IO::FileIOBase::GetInstance(); ASSERT_NE(nullptr, ioBase); - const char* assetsPath = ioBase->GetAlias("@assets@"); + const char* assetsPath = ioBase->GetAlias("@products@"); ASSERT_NE(nullptr, assetsPath); auto stringToAdd = AZ::IO::Path(assetsPath) / "textures" / "test.dds"; @@ -872,7 +872,7 @@ namespace UnitTest // it normalizes the string, so the slashes flip and everything is lowercased. AZ::IO::FixedMaxPath resolvedAddedPath; AZ::IO::FixedMaxPath resolvedResourcePath; - EXPECT_TRUE(ioBase->ReplaceAlias(resolvedAddedPath, "@assets@/textures/test.dds")); + EXPECT_TRUE(ioBase->ReplaceAlias(resolvedAddedPath, "@products@/textures/test.dds")); EXPECT_TRUE(ioBase->ReplaceAlias(resolvedResourcePath, reslist->GetFirst())); EXPECT_EQ(resolvedAddedPath, resolvedResourcePath); reslist->Clear(); diff --git a/Code/Framework/AzFramework/Tests/FileIO.cpp b/Code/Framework/AzFramework/Tests/FileIO.cpp index dbee109978..ca7c46b66c 100644 --- a/Code/Framework/AzFramework/Tests/FileIO.cpp +++ b/Code/Framework/AzFramework/Tests/FileIO.cpp @@ -802,6 +802,51 @@ namespace UnitTest AZ_TEST_STOP_TRACE_SUPPRESSION(1); } + TEST_F(AliasTest, GetAlias_LogsError_WhenAccessingDeprecatedAlias_Succeeds) + { + AZ::IO::LocalFileIO local; + + AZ::IO::FixedMaxPathString aliasFolder; + EXPECT_TRUE(local.ConvertToAbsolutePath("/temp", aliasFolder.data(), aliasFolder.capacity())); + aliasFolder.resize_no_construct(AZStd::char_traits::length(aliasFolder.data())); + + local.SetAlias("@test@", aliasFolder.c_str()); + local.SetDeprecatedAlias("@deprecated@", "@test@"); + local.SetDeprecatedAlias("@deprecatednonexistent@", "@nonexistent@"); + local.SetDeprecatedAlias("@deprecatedsecond@", "@deprecated@"); + local.SetDeprecatedAlias("@deprecatednonaliaspath@", aliasFolder); + + AZ_TEST_START_TRACE_SUPPRESSION; + const char* testAlias = local.GetAlias("@test@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(0); + + // Validate that accessing Deprecated Alias results in AZ_Error + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecated@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecatednonexistent@"); + EXPECT_EQ(nullptr, testAlias); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecatedsecond@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecatednonaliaspath@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + class SmartMoveTests : public FolderFixture { diff --git a/Code/Framework/AzFramework/Tests/FileTagTests.cpp b/Code/Framework/AzFramework/Tests/FileTagTests.cpp index 134e7aad6d..2b09a5638c 100644 --- a/Code/Framework/AzFramework/Tests/FileTagTests.cpp +++ b/Code/Framework/AzFramework/Tests/FileTagTests.cpp @@ -27,7 +27,7 @@ namespace UnitTest const char DummyFile[] = "dummy.txt"; const char AnotherDummyFile[] = "Foo/Dummy.txt"; - + const char DummyPattern[] = R"(^(.+)_([a-z]+)\..+$)"; const char MatchingPatternFile[] = "Foo/dummy_abc.txt"; const char NonMatchingPatternFile[] = "Foo/dummy_a8c.txt"; @@ -75,7 +75,7 @@ namespace UnitTest : public AllocatorsFixture { public: - + void SetUp() override { AllocatorsFixture::SetUp(); @@ -89,7 +89,7 @@ namespace UnitTest const char* testAssetRoot = m_tempDirectory.GetDirectory(); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -98,7 +98,7 @@ namespace UnitTest AZ::IO::FileIOBase::SetInstance(nullptr); AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO.get()); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", testAssetRoot); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", testAssetRoot); m_data->m_excludeFileQueryManager = AZStd::make_unique(FileTagType::Exclude); m_data->m_includeFileQueryManager = AZStd::make_unique(FileTagType::Include); @@ -114,7 +114,7 @@ namespace UnitTest AZStd::vector includedWildcardTags = { DummyFileTags[DummyFileTagIndex::GIdx] }; EXPECT_TRUE(m_data->m_fileTagManager.AddFilePatternTags(DummyWildcard, FilePatternType::Wildcard, FileTagType::Include, includedWildcardTags).IsSuccess()); - + AzFramework::StringFunc::Path::Join(testAssetRoot, AZStd::string::format("%s.%s", ExcludeFile, FileTagAsset::Extension()).c_str(), m_data->m_excludeFile); AzFramework::StringFunc::Path::Join(testAssetRoot, AZStd::string::format("%s.%s", IncludeFile, FileTagAsset::Extension()).c_str(), m_data->m_includeFile); @@ -184,7 +184,7 @@ namespace UnitTest TEST_F(FileTagTest, FileTags_QueryByAbsoluteFilePath_Valid) { AZStd::string absoluteDummyFilePath = DummyFile; - EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@assets@", absoluteDummyFilePath.c_str(), absoluteDummyFilePath)); + EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@products@", absoluteDummyFilePath.c_str(), absoluteDummyFilePath)); AZStd::set tags = m_data->m_excludeFileQueryManager->GetTags(absoluteDummyFilePath); @@ -196,7 +196,7 @@ namespace UnitTest ASSERT_EQ(tags.size(), 0); AZStd::string absoluteAnotherDummyFilePath = AnotherDummyFile; - EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@assets@", absoluteAnotherDummyFilePath.c_str(), absoluteAnotherDummyFilePath)); + EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@products@", absoluteAnotherDummyFilePath.c_str(), absoluteAnotherDummyFilePath)); tags = m_data->m_includeFileQueryManager->GetTags(absoluteAnotherDummyFilePath); ASSERT_EQ(tags.size(), 2); @@ -213,7 +213,7 @@ namespace UnitTest // Set the customized alias AZStd::string customizedAliasFilePath; - const char* assetsAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + const char* assetsAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::AssetDatabasePath::Join(assetsAlias, "foo", customizedAliasFilePath); AZ::IO::FileIOBase::GetInstance()->SetAlias("@customizedalias@", customizedAliasFilePath.c_str()); @@ -305,7 +305,7 @@ namespace UnitTest m_data->m_excludeFileQueryManager->ClearData(); EXPECT_TRUE(m_data->m_excludeFileQueryManager->Load(m_data->m_excludeFile)); - + AZStd::set outputTags = m_data->m_excludeFileQueryManager->GetTags(MatchingWildcardFile); EXPECT_EQ(outputTags.size(), 2); diff --git a/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp b/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp index 169834249f..665c06b571 100644 --- a/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp +++ b/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp @@ -6,81 +6,19 @@ * */ +#include #include #include #include -#include -#include +#include +#include namespace UnitTest { - using namespace AZ; - - class FileIOBaseRAII - { - public: - FileIOBaseRAII(AZ::IO::FileIOBase& fileIO) - : m_prevFileIO(AZ::IO::FileIOBase::GetInstance()) - { - AZ::IO::FileIOBase::SetInstance(&fileIO); - } - - ~FileIOBaseRAII() - { - AZ::IO::FileIOBase::SetInstance(m_prevFileIO); - } - private: - AZ::IO::FileIOBase* m_prevFileIO; - }; - class GenAppDescriptors : public AllocatorsTestFixture { public: - - void run() - { - struct Config - { - const char* platformName; - const char* configName; - const char* libSuffix; - }; - - ComponentApplication app; - - SerializeContext serializeContext; - AZ::ComponentApplication::Descriptor::Reflect(&serializeContext, &app); - AZ::Entity::Reflect(&serializeContext); - DynamicModuleDescriptor::Reflect(&serializeContext); - - AZ::Entity dummySystemEntity(AZ::SystemEntityId, "SystemEntity"); - - const Config config = {"Platform", "Config", "libSuffix"}; - - AZ::ComponentApplication::Descriptor descriptor; - - if (config.libSuffix && config.libSuffix[0]) - { - FakePopulateModules(descriptor, config.libSuffix); - } - - const AZStd::string filename = AZStd::string::format("LYConfig_%s%s.xml", config.platformName, config.configName); - - IO::FileIOStream stream(filename.c_str(), IO::OpenMode::ModeWrite); - ObjectStream* objStream = ObjectStream::Create(&stream, serializeContext, ObjectStream::ST_XML); - bool descWriteOk = objStream->WriteClass(&descriptor); - (void)descWriteOk; - AZ_Warning("ComponentApplication", descWriteOk, "Failed to write memory descriptor to application descriptor file %s!", filename.c_str()); - bool entityWriteOk = objStream->WriteClass(&dummySystemEntity); - (void)entityWriteOk; - AZ_Warning("ComponentApplication", entityWriteOk, "Failed to write system entity to application descriptor file %s!", filename.c_str()); - bool flushOk = objStream->Finalize(); - (void)flushOk; - AZ_Warning("ComponentApplication", flushOk, "Failed finalizing application descriptor file %s!", filename.c_str()); - - } - void FakePopulateModules(AZ::ComponentApplication::Descriptor& desc, const char* libSuffix) { static const char* modules[] = @@ -100,10 +38,44 @@ namespace UnitTest } }; - TEST_F(GenAppDescriptors, Test) + TEST_F(GenAppDescriptors, WriteDescriptor_ToXML_Succeeds) { - AZ::IO::LocalFileIO fileIO; - FileIOBaseRAII restoreFileIOScope(fileIO); - run(); + struct Config + { + const char* platformName; + const char* configName; + const char* libSuffix; + }; + + AzFramework::Application app; + + AZ::SerializeContext serializeContext; + AZ::ComponentApplication::Descriptor::Reflect(&serializeContext, &app); + AZ::Entity::Reflect(&serializeContext); + AZ::DynamicModuleDescriptor::Reflect(&serializeContext); + + AZ::Entity dummySystemEntity(AZ::SystemEntityId, "SystemEntity"); + + const Config config = {"Platform", "Config", "libSuffix"}; + + AZ::ComponentApplication::Descriptor descriptor; + + if (config.libSuffix && config.libSuffix[0]) + { + FakePopulateModules(descriptor, config.libSuffix); + } + + AZ::Test::ScopedAutoTempDirectory tempDirectory; + const auto filename = AZ::IO::Path(tempDirectory.GetDirectory()) / + AZStd::string::format("LYConfig_%s%s.xml", config.platformName, config.configName); + + AZ::IO::FileIOStream stream(filename.c_str(), AZ::IO::OpenMode::ModeWrite); + auto objStream = AZ::ObjectStream::Create(&stream, serializeContext, AZ::ObjectStream::ST_XML); + const bool descWriteOk = objStream->WriteClass(&descriptor); + EXPECT_TRUE(descWriteOk) << "Failed to write memory descriptor to application descriptor file " << filename.c_str() << "!"; + const bool entityWriteOk = objStream->WriteClass(&dummySystemEntity); + EXPECT_TRUE(entityWriteOk) << "Failed to write system entity to application descriptor file " << filename.c_str() << "!"; + const bool flushOk = objStream->Finalize(); + EXPECT_TRUE(flushOk) << "Failed finalizing application descriptor file " << filename.c_str() << "!"; } } diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index 424132b624..462de43262 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -38,12 +38,12 @@ namespace AzGameFramework { // fall back to checking Project Cache Root. enginePakPath /= "engine.pak"; - enginePakOpened = m_archive->OpenPack("@projectproductassets@", enginePakPath.Native()); + enginePakOpened = m_archive->OpenPack("@products@", enginePakPath.Native()); } if (!enginePakOpened) { enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak"; - m_archive->OpenPack("@projectproductassets@", enginePakPath.Native()); + m_archive->OpenPack("@products@", enginePakPath.Native()); } } diff --git a/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp b/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp index 3fdfa042a5..9f496c3e0c 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp @@ -107,7 +107,7 @@ namespace AzNetworking if (AZ::IO::FileIOBase::GetInstance() != nullptr) { char buffer[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@assets@/", buffer, sizeof(buffer)); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@products@/", buffer, sizeof(buffer)); assetDir = AZStd::string(buffer); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h index eab2d5e1a0..c18ddc2f67 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h @@ -47,14 +47,6 @@ namespace AzToolsFramework //! Retrieve the absolute path for the Asset Database Location virtual bool GetAbsoluteAssetDatabaseLocation(AZStd::string& /*result*/) { return false; } - - //! Retrieve the absolute folder path to the current game's source assets (the ones that go into source control) - //! This may include the current mod path, if a mod is being edited by the editor - virtual const char* GetAbsoluteDevGameFolderPath() = 0; - - //! Retrieve the absolute folder path to the current developer root ('dev'), which contains source artifacts - //! and is generally checked into source control. - virtual const char* GetAbsoluteDevRootFolderPath() = 0; /// Convert a full source path like "c:\\dev\\gamename\\blah\\test.tga" into a relative product path. /// asset paths never mention their alias and are relative to the asset cache root diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp index cc3153ed8e..86b32d4379 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp @@ -354,26 +354,6 @@ namespace AzToolsFramework } } - const char* AssetSystemComponent::GetAbsoluteDevGameFolderPath() - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileIO) - { - return fileIO->GetAlias("@devassets@"); - } - return ""; - } - - const char* AssetSystemComponent::GetAbsoluteDevRootFolderPath() - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileIO) - { - return fileIO->GetAlias("@devroot@"); - } - return ""; - } - void AssetSystemComponent::OnSystemTick() { AssetSystemBus::ExecuteQueuedEvents(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h index 4774b96be4..fcd697393c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h @@ -56,8 +56,6 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::AssetSystemRequestBus::Handler overrides bool GetAbsoluteAssetDatabaseLocation(AZStd::string& result) override; - const char* GetAbsoluteDevGameFolderPath() override; - const char* GetAbsoluteDevRootFolderPath() override; bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& outputPath) override; bool GenerateRelativeSourcePath( const AZStd::string& sourcePath, AZStd::string& outputPath, AZStd::string& watchFolder) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp index e09dd183f8..8856989911 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp @@ -137,7 +137,7 @@ namespace AzToolsFramework AssetEditorWidgetUserSettings::AssetEditorWidgetUserSettings() { char assetRoot[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", assetRoot, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", assetRoot, AZ_MAX_PATH_LEN); m_lastSavePath = assetRoot; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h index 988963eaca..3ba826804d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h @@ -39,7 +39,7 @@ namespace AzToolsFramework // the TraceContextLogFormatter. // // Usage example: - // const char* gameFolder = m_context.pRC->GetSystemEnvironment()->pFileIO->GetAlias("@devassets@"); + // const char* gameFolder = m_context.pRC->GetSystemEnvironment()->pFileIO->GetAlias("@projectroot@"); // AZ_TraceContext("Game folder", gameFolder); // // for (int i=0; iSetAlias("@log@", logDirectory.c_str()); - fileIO->CreatePath("@root@"); + fileIO->CreatePath("@products@"); fileIO->CreatePath("@user@"); fileIO->CreatePath("@log@"); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp index 36f647e4c2..99d0768cf6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -78,13 +79,9 @@ namespace AzToolsFramework AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(entitiesAndDescendants, &AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, AzToolsFramework::EntityIdList{ entityId }); - // Retrieve the game folder so we can use that as a root with the passed in relative path - const char* gameFolder = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(gameFolder, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); - // Join our relative path with the game folder to get a full path to the desired asset - AZStd::string assetFullPath; - AzFramework::StringFunc::Path::Join(gameFolder, assetPath, assetFullPath); + AZ::IO::FixedMaxPath assetFullPath = AZ::Utils::GetProjectPath(); + assetFullPath /= assetPath; // Call SliceUtilities::MakeNewSlice with all user input prompts disabled bool success = AzToolsFramework::SliceUtilities::MakeNewSlice(entitiesAndDescendants, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp index d8b5fe0a15..9d2c58a717 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp @@ -718,7 +718,7 @@ namespace AzToolsFramework if (!fullPathFound) { - assetFullPath = AZStd::string::format("@devassets@/%s", sliceAssetPath.c_str()); + assetFullPath = AZStd::string::format("@projectroot@/%s", sliceAssetPath.c_str()); } return Commit(assetFullPath.c_str(), preSaveCallback, postSaveCallback, sliceCommitFlags); @@ -1020,13 +1020,13 @@ namespace AzToolsFramework AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "File IO is not initialized."); - AZStd::string devAssetPath = fileIO->GetAlias("@devassets@"); + AZStd::string devAssetPath = fileIO->GetAlias("@projectroot@"); AZStd::string userPath = fileIO->GetAlias("@user@"); AZStd::string tempPath = fullPath; EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, devAssetPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, userPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, tempPath); - AzFramework::StringFunc::Replace(tempPath, "@devassets@", devAssetPath.c_str()); + AzFramework::StringFunc::Replace(tempPath, "@projectroot@", devAssetPath.c_str()); AzFramework::StringFunc::Replace(tempPath, devAssetPath.c_str(), userPath.c_str()); tempPath.append(".slicetemp"); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp index f58f273f11..01b1213473 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp @@ -378,11 +378,11 @@ namespace AzToolsFramework // If this layer is being loaded, it won't have a level save dependency yet, so clear that flag. m_mustSaveLevelWhenLayerSaves = false; QString fullPathName = levelPakFile; - if (fullPathName.contains("@devassets@")) + if (fullPathName.contains("@projectroot@")) { AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); // Resolving the path through resolvepath would normalize and lowcase it, and in this case, we don't want that. - fullPathName.replace("@devassets@", fileIO->GetAlias("@devassets@")); + fullPathName.replace("@projectroot@", fileIO->GetAlias("@projectroot@")); } QFileInfo fileNameInfo(fullPathName); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 62842e18d5..07dcd2ab20 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -315,7 +315,7 @@ namespace AzToolsFramework // temporarily null after QFileDialogs close, which we need in order to // be able to parent our message dialogs properly QWidget* activeWindow = QApplication::activeWindow(); - const AZStd::string prefabFilesPath = "@devassets@/Prefabs"; + const AZStd::string prefabFilesPath = "@projectroot@/Prefabs"; // Remove Level entity if it's part of the list diff --git a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp index 66520c804c..395e4c9049 100644 --- a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp @@ -131,13 +131,13 @@ namespace UnitTest m_app.reset(aznew ToolsTestApplication("ArchiveComponentTest")); m_app->Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { - fileIoBase->SetAlias("@assets@", m_tempDir.GetDirectory()); + fileIoBase->SetAlias("@products@", m_tempDir.GetDirectory()); } } diff --git a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp index 24488f3ed3..827737f561 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp +++ b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp @@ -37,10 +37,10 @@ namespace // anonymous bool Search(const AzToolsFramework::AssetFileInfoList& assetList, const AZ::Data::AssetId& assetId) { - return AZStd::find_if(assetList.m_fileInfoList.begin(), assetList.m_fileInfoList.end(), - [&](AzToolsFramework::AssetFileInfo fileInfo) - { - return fileInfo.m_assetId == assetId; + return AZStd::find_if(assetList.m_fileInfoList.begin(), assetList.m_fileInfoList.end(), + [&](AzToolsFramework::AssetFileInfo fileInfo) + { + return fileInfo.m_assetId == assetId; }); } } @@ -74,11 +74,11 @@ namespace UnitTest m_application->Start(AzFramework::Application::Descriptor()); - // By default @assets@ is setup to include the platform at the end. But this test is going to + // By default @products@ is setup to include the platform at the end. But this test is going to // loop over platforms and it will be included as part of the relative path of the file. // So the asset folder for these tests have to point to the cache project root folder, which // doesn't include the platform. - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheProjectRootFolder.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", cacheProjectRootFolder.c_str()); for (int idx = 0; idx < s_totalAssets; idx++) { @@ -158,17 +158,17 @@ namespace UnitTest m_assetRegistry->RegisterAssetDependency(assets[5], AZ::Data::ProductDependency(assets[6], 0)); m_assetRegistry->RegisterAssetDependency(assets[6], AZ::Data::ProductDependency(assets[7], 0)); - // asset8 -> asset6 + // asset8 -> asset6 m_assetRegistry->RegisterAssetDependency(assets[8], AZ::Data::ProductDependency(assets[6], 0)); - // asset10 -> asset11 + // asset10 -> asset11 m_assetRegistry->RegisterAssetDependency(assets[10], AZ::Data::ProductDependency(assets[11], 0)); - // asset11 -> asset10 + // asset11 -> asset10 m_assetRegistry->RegisterAssetDependency(assets[11], AZ::Data::ProductDependency(assets[10], 0)); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -203,10 +203,6 @@ namespace UnitTest const AZStd::string engroot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engroot.c_str()); - - AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); - assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); } void TearDown() override @@ -219,7 +215,7 @@ namespace UnitTest delete m_application; } - AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override + AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override { auto foundIter = m_assetRegistry->m_assetIdToInfo.find(id); if (foundIter != m_assetRegistry->m_assetIdToInfo.end()) @@ -540,7 +536,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList, assets[7])); EXPECT_TRUE(Search(assetList, assets[8])); - // Removing the android flag from the asset should still produce the same result + // Removing the android flag from the asset should still produce the same result m_assetSeedManager->RemoveSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID); assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC); @@ -564,7 +560,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList, assets[3])); EXPECT_TRUE(Search(assetList, assets[4])); - // Adding the android flag again to the asset + // Adding the android flag again to the asset m_assetSeedManager->AddSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID); assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::ANDROID_ID); @@ -624,7 +620,7 @@ namespace UnitTest EXPECT_EQ(assetList1.m_fileInfoList[0].m_assetId, assetList2.m_fileInfoList[0].m_assetId); EXPECT_GE(assetList2.m_fileInfoList[0].m_modificationTime, assetList1.m_fileInfoList[0].m_modificationTime); // file mod time should change - + // file hash should not change for (int idx = 0; idx < 5; idx++) { @@ -680,7 +676,7 @@ namespace UnitTest m_assetSeedManager->AddSeedAsset(assets[validFileIndex], AzFramework::PlatformFlags::Platform_PC, m_assetsPath[invalidFileIndex]); const AzFramework::AssetSeedList& oldSeedList = m_assetSeedManager->GetAssetSeedList(); - + for (const auto& seedInfo : oldSeedList) { if (seedInfo.m_assetId == assets[validFileIndex]) diff --git a/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h b/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h index 2678c2f57c..ba3e38ba8f 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h +++ b/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h @@ -18,8 +18,6 @@ namespace UnitTests { public: MOCK_METHOD1(GetAbsoluteAssetDatabaseLocation, bool(AZStd::string&)); - MOCK_METHOD0(GetAbsoluteDevGameFolderPath, const char* ()); - MOCK_METHOD0(GetAbsoluteDevRootFolderPath, const char* ()); MOCK_METHOD2(GetRelativeProductPathFromFullSourceOrProductPath, bool(const AZStd::string& fullPath, AZStd::string& relativeProductPath)); MOCK_METHOD3(GenerateRelativeSourcePath, bool(const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder)); diff --git a/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h b/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h index 2128b3676a..1bf51045c0 100644 --- a/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h +++ b/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h @@ -181,8 +181,8 @@ namespace UnitTest const char* dir = m_componentApplication->GetExecutableFolder(); - m_localFileIO.SetAlias("@assets@", dir); - m_localFileIO.SetAlias("@devassets@", dir); + m_localFileIO.SetAlias("@products@", dir); + m_localFileIO.SetAlias("@projectroot@", dir); } void Destroy() diff --git a/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp b/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp index 67d40be376..9c226cbb1b 100644 --- a/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp @@ -22,7 +22,7 @@ #include #include -namespace +namespace { static const int s_totalAssets = 12; } @@ -53,15 +53,15 @@ namespace UnitTest m_application->Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - // By default @assets@ is setup to include the platform at the end. But this test is going to + // By default @products@ is setup to include the platform at the end. But this test is going to // loop over all platforms and it will be included as part of the relative path of the file. // So the asset folder for these tests have to point to the cache project root folder, which // doesn't include the platform. - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheProjectRootFolder.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", cacheProjectRootFolder.c_str()); for (int platformNum = AzFramework::PlatformId::PC; platformNum < AzFramework::PlatformId::NumPlatformIds; ++platformNum) { diff --git a/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h b/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h index 93e86374db..01b40fbb16 100644 --- a/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h +++ b/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h @@ -142,8 +142,6 @@ namespace UnitTest /* * AssetSystemRequestBus */ - const char* GetAbsoluteDevGameFolderPath() override { return ""; } - const char* GetAbsoluteDevRootFolderPath() override { return ""; } bool GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) override { return false; } bool GenerateRelativeSourcePath( [[maybe_unused]] const AZStd::string& sourcePath, [[maybe_unused]] AZStd::string& relativePath, diff --git a/Code/Legacy/CryCommon/CryPath.h b/Code/Legacy/CryCommon/CryPath.h index 197c9b2d56..51b379ac51 100644 --- a/Code/Legacy/CryCommon/CryPath.h +++ b/Code/Legacy/CryCommon/CryPath.h @@ -520,14 +520,14 @@ namespace PathUtil unsigned int index = 0; if (relativePath.length() && relativePath[index] == '@') // already aliased { - if (AZ::StringFunc::Equal(relativePath.c_str(), "@assets@/", false, 9)) + if (AZ::StringFunc::Equal(relativePath.c_str(), "@products@/", false, 9)) { return relativePath.substr(9); // assets is assumed. } return relativePath; } - const char* rootValue = gEnv->pFileIO->GetAlias("@root@"); + const char* rootValue = gEnv->pFileIO->GetAlias("@products@"); if (rootValue) { stack_string rootPath(ToUnixPath(rootValue)); @@ -538,7 +538,7 @@ namespace PathUtil ) { stack_string chopped_string = relativePath.substr(rootPath.size()); - stack_string rooted = stack_string("@root@") + chopped_string; + stack_string rooted = stack_string("@products@") + chopped_string; return rooted; } } diff --git a/Code/Legacy/CrySystem/ConsoleBatchFile.cpp b/Code/Legacy/CrySystem/ConsoleBatchFile.cpp index bdc8d6de7d..5b96b943a7 100644 --- a/Code/Legacy/CrySystem/ConsoleBatchFile.cpp +++ b/Code/Legacy/CrySystem/ConsoleBatchFile.cpp @@ -59,10 +59,10 @@ bool CConsoleBatchFile::ExecuteConfigFile(const char* sFilename) AZStd::string filename; - if (sFilename[0] != '@') // console config files are actually by default in @root@ instead of @assets@ + if (sFilename[0] != '@') // console config files are actually by default in @products@ instead of @products@ { // However, if we've passed in a relative or absolute path that matches an existing file name, - // don't change it. Only change it to "@root@/filename" and strip off any relative paths + // don't change it. Only change it to "@products@/filename" and strip off any relative paths // if the given pattern *didn't* match a file. if (AZ::IO::FileIOBase::GetDirectInstance()->Exists(sFilename)) { @@ -70,7 +70,7 @@ bool CConsoleBatchFile::ExecuteConfigFile(const char* sFilename) } else { - filename = PathUtil::Make("@root@", PathUtil::GetFile(sFilename)); + filename = PathUtil::Make("@products@", PathUtil::GetFile(sFilename)); } } else diff --git a/Code/Legacy/CrySystem/DebugCallStack.cpp b/Code/Legacy/CrySystem/DebugCallStack.cpp index bea6c8c035..8018e46d69 100644 --- a/Code/Legacy/CrySystem/DebugCallStack.cpp +++ b/Code/Legacy/CrySystem/DebugCallStack.cpp @@ -372,7 +372,7 @@ void DebugCallStack::LogExceptionInfo(EXCEPTION_POINTERS* pex) const char* logAlias = gEnv->pFileIO->GetAlias("@log@"); if (!logAlias) { - logAlias = gEnv->pFileIO->GetAlias("@root@"); + logAlias = gEnv->pFileIO->GetAlias("@products@"); } if (logAlias) { diff --git a/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp b/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp index 2e61760d8c..49af5080ec 100644 --- a/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp +++ b/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp @@ -306,7 +306,7 @@ void CLevelSystem::ScanFolder(const char* subfolder, bool modFolder) } AZStd::string levelContainerPakPath; - AZ::StringFunc::Path::Join("@assets@", m_levelsFolder.c_str(), levelContainerPakPath); + AZ::StringFunc::Path::Join("@products@", m_levelsFolder.c_str(), levelContainerPakPath); if (subfolder && subfolder[0]) { AZ::StringFunc::Path::Join(levelContainerPakPath.c_str(), subfolder, levelContainerPakPath); diff --git a/Code/Legacy/CrySystem/SystemCFG.cpp b/Code/Legacy/CrySystem/SystemCFG.cpp index c97345a518..7a643f2069 100644 --- a/Code/Legacy/CrySystem/SystemCFG.cpp +++ b/Code/Legacy/CrySystem/SystemCFG.cpp @@ -292,10 +292,10 @@ static bool ParseSystemConfig(const AZStd::string& strSysConfigFilePath, ILoadCo // to either root or assets/config. this is done so that code can just request a simple file name and get its data if ( !(file.Open(filename.c_str(), "rb")) && - !(file.Open((AZStd::string("@root@/") + filename).c_str(), "rb")) && - !(file.Open((AZStd::string("@assets@/") + filename).c_str(), "rb")) && - !(file.Open((AZStd::string("@assets@/config/") + filename).c_str(), "rb")) && - !(file.Open((AZStd::string("@assets@/config/spec/") + filename).c_str(), "rb")) + !(file.Open((AZStd::string("@products@/") + filename).c_str(), "rb")) && + !(file.Open((AZStd::string("@products@/") + filename).c_str(), "rb")) && + !(file.Open((AZStd::string("@products@/config/") + filename).c_str(), "rb")) && + !(file.Open((AZStd::string("@products@/config/spec/") + filename).c_str(), "rb")) ) { if (warnIfMissing) @@ -414,7 +414,7 @@ static bool ParseSystemConfig(const AZStd::string& strSysConfigFilePath, ILoadCo // replace '\\\\' with '\\' and '\\\"' with '\"' AZ::StringFunc::Replace(strValue, "\\\\", "\\"); AZ::StringFunc::Replace(strValue, "\\\"", "\""); - + pSink->OnLoadConfigurationEntry(strKey.c_str(), strValue.c_str(), strGroup.c_str()); } } diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 3187095094..6de10f3855 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -796,7 +796,7 @@ void CSystem::OpenBasicPaks() bBasicPaksLoaded = true; // open pak files - constexpr AZStd::string_view paksFolder = "@assets@/*.pak"; // (@assets@ assumed) + constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed) m_env.pCryPak->OpenPacks(paksFolder); InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( paksFolder.c_str() )"); @@ -805,7 +805,7 @@ void CSystem::OpenBasicPaks() // Open engine packs ////////////////////////////////////////////////////////////////////////// - const char* const assetsDir = "@assets@"; + const char* const assetsDir = "@products@"; // After game paks to have same search order as with files on disk m_env.pCryPak->OpenPack(assetsDir, "engine.pak"); @@ -874,7 +874,7 @@ void CSystem::OpenLanguageAudioPak([[maybe_unused]] const char* sLanguage) if (!AZ::StringFunc::Equal(sLocalizationFolder, "Languages", false)) { - sLocalizationFolder = "@assets@"; + sLocalizationFolder = "@products@"; } // load localized pak with crc32 filenames on consoles to save memory. @@ -1260,9 +1260,6 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init Create console"); - // Need to load the engine.pak that includes the config files needed during initialization - m_env.pCryPak->OpenPack("@assets@", "engine.pak"); - InitFileSystem_LoadEngineFolders(startupParams); #if !defined(RELEASE) || defined(RELEASE_LOGGING) diff --git a/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp b/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp index e0a6725ed4..24366498a5 100644 --- a/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp +++ b/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp @@ -27,7 +27,7 @@ namespace AWSNativeSDKInit void CopyCaCertBundle() { AZStd::vector contents; - AZStd::string certificatePath = "@assets@/certificates/aws/cacert.pem"; + AZStd::string certificatePath = "@products@/certificates/aws/cacert.pem"; AZStd::string publicStoragePath = AZ::Android::Utils::GetAppPublicStoragePath(); publicStoragePath.append("/certificates/aws/cacert.pem"); diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp index 42a43ef84e..78244ab02c 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp @@ -683,31 +683,26 @@ void AssetBuilderComponent::ProcessJob(const AssetBuilderSDK::ProcessJobFunction AZ_Assert(settingsRegistry != nullptr, "SettingsRegistry must be ready for use in the AssetBuilder."); // The root path is the cache plus the platform name. - AZ::IO::FixedMaxPath newRoot(m_gameCache); + AZ::IO::FixedMaxPath newProjectCache(m_gameCache); // Check if the platform identifier is a valid "asset platform" // If so, use it, other wise use the OS default platform as a fail safe // This is to make sure the "debug platform" isn't added as a path segment - // the Cache Root folder + // the Cache ProjectCache folder if (AzFramework::PlatformHelper::GetPlatformIdFromName(request.m_platformInfo.m_identifier) != AzFramework::PlatformId::Invalid) { - newRoot /= request.m_platformInfo.m_identifier; + newProjectCache /= request.m_platformInfo.m_identifier; } else { - newRoot /= AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); + newProjectCache /= AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); } - // The asset path is root and the lower case game name. - AZ::IO::FixedMaxPath newAssets = newRoot; - // Now set the paths and run the job. { // Save out the prior paths. - ScopedAliasSetter assetAliasScope(*ioBase, "@assets@", newAssets.c_str()); - ScopedAliasSetter rootAliasScope(*ioBase, "@root@", newRoot.c_str()); - ScopedAliasSetter projectplatformCacheAliasScope(*ioBase, "@projectplatformcache@", newRoot.c_str()); + ScopedAliasSetter projectPlatformCacheAliasScope(*ioBase, "@products@", newProjectCache.c_str()); ScopedSettingsRegistrySetter cacheRootFolderScope(*settingsRegistry, - AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder, newRoot.Native()); + AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder, newProjectCache.Native()); // Invoke the Process Job function job(request, outResponse); diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp index 6eee3d6f2b..d7cdd30be8 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp @@ -27,7 +27,7 @@ namespace AssetProcessor , m_registryBuiltOnce(false) , m_registriesMutex(QMutex::Recursive) { - + for (const AssetBuilderSDK::PlatformInfo& info : m_platformConfig->GetEnabledPlatforms()) { m_platforms.push_back(QString::fromUtf8(info.m_identifier.c_str())); @@ -38,17 +38,9 @@ namespace AssetProcessor // save 30mb for this. Really large projects do get this big (and bigger) // if you don't do this, things get fragmented very fast. - m_saveBuffer.reserve(1024 * 1024 * 30); - - m_absoluteDevFolderPath[0] = 0; - m_absoluteDevGameFolderPath[0] = 0; - - AZStd::string engineRoot; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - azstrcpy(m_absoluteDevFolderPath, AZ_MAX_PATH_LEN, engineRoot.c_str()); + m_saveBuffer.reserve(1024 * 1024 * 30); - AZStd::string gameFolderPath{AssetUtilities::ComputeProjectPath().toUtf8().constData()}; - azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, gameFolderPath.c_str()); + AssetUtilities::ComputeProjectPath(); AssetUtilities::ComputeProjectCacheRoot(m_cacheRootDir); @@ -359,7 +351,7 @@ namespace AssetProcessor [[maybe_unused]] bool makeDirResult = AZ::IO::SystemFile::CreateDir(absPath.toUtf8().constData()); AZ_Warning(AssetProcessor::ConsoleChannel, makeDirResult, "Failed create folder %s", platformCacheDir.toUtf8().constData()); } - + // if we succeeded in doing this, then use "rename" to move the file over the previous copy. bool moved = AssetUtilities::MoveFileWithTimeout(tempRegistryFile, actualRegistryFile, 3); allCatalogsSaved = allCatalogsSaved && moved; @@ -382,7 +374,7 @@ namespace AssetProcessor } } } - + { // scoped to minimize the duration of this mutex lock QMutexLocker locker(&m_savingRegistryMutex); @@ -605,7 +597,7 @@ namespace AssetProcessor AZStd::string nameForMap(relativeFilePath.toUtf8().constData()); AZStd::to_lower(nameForMap.begin(), nameForMap.end()); - + m_sourceNameToSourceUUIDMap.insert({ nameForMap, sourceUuid }); } @@ -627,16 +619,6 @@ namespace AssetProcessor ////////////////////////////////////////////////////////////////////////// - const char* AssetCatalog::GetAbsoluteDevGameFolderPath() - { - return m_absoluteDevGameFolderPath; - } - - const char* AssetCatalog::GetAbsoluteDevRootFolderPath() - { - return m_absoluteDevFolderPath; - } - bool AssetCatalog::GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullSourceOrProductPath, AZStd::string& relativeProductPath) { ProcessGetRelativeProductPathFromFullSourceOrProductPathRequest(fullSourceOrProductPath, relativeProductPath); @@ -976,7 +958,7 @@ namespace AssetProcessor // regardless of which way we come into this function we must always use ConvertToRelativePath // to convert from whatever the input format is to a database path (which may include output prefix) - QString databaseName; + QString databaseName; QString scanFolder; if (!AzFramework::StringFunc::Path::IsRelative(sourcePath)) { @@ -1163,7 +1145,7 @@ namespace AssetProcessor AZStd::string AssetCatalog::GetAssetPathById(const AZ::Data::AssetId& id) { return GetAssetInfoById(id).m_relativePath; - + } AZ::Data::AssetId AssetCatalog::GetAssetIdByPath(const char* path, const AZ::Data::AssetType& typeToRegister, bool autoRegisterIfNotFound) @@ -1175,7 +1157,7 @@ namespace AssetProcessor AZStd::string relProductPath; GetRelativeProductPathFromFullSourceOrProductPath(path, relProductPath); QString tempPlatformName = GetDefaultAssetPlatform(); - + AZ::Data::AssetId assetId; { QMutexLocker locker(&m_registriesMutex); @@ -1344,7 +1326,7 @@ namespace AssetProcessor //remove aliases if present normalisedAssetPath = AssetUtilities::NormalizeAndRemoveAlias(normalisedAssetPath); - if (!normalisedAssetPath.isEmpty()) // this happens if it comes in as just for example "@assets@/" + if (!normalisedAssetPath.isEmpty()) // this happens if it comes in as just for example "@products@/" { AZStd::lock_guard lock(m_databaseMutex); @@ -1439,7 +1421,7 @@ namespace AssetProcessor relativePath = entry.m_sourceName; watchFolder = scanEntry.m_scanFolder; - + return true; } @@ -1489,7 +1471,7 @@ namespace AssetProcessor { return foundIter->second; } - + // we did not find it - try the backup mapping! AssetId legacyMapping = registryToUse.GetAssetIdByLegacyAssetId(assetId); if (legacyMapping.IsValid()) @@ -1533,7 +1515,7 @@ namespace AssetProcessor return !assetInfo.m_relativePath.empty(); } - + // Asset isn't in the DB or in the APM queue, we don't know what this asset ID is return false; } @@ -1588,7 +1570,7 @@ namespace AssetProcessor AZStd::string sourceFileFullPath; AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), sourceFileFullPath); assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceFileFullPath.c_str()); - + assetInfo.m_assetType = AZ::Uuid::CreateNull(); // most source files don't have a type! // Go through the list of source assets and see if this asset's file path matches any of the filters diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h index 84e96bcf3e..e876e259fb 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h @@ -88,8 +88,6 @@ namespace AssetProcessor ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::AssetSystem::AssetSystemRequestBus::Handler overrides - const char* GetAbsoluteDevGameFolderPath() override; - const char* GetAbsoluteDevRootFolderPath() override; bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& relativeProductPath) override; //! Given a partial or full source file path, respond with its relative path and the watch folder it is relative to. @@ -215,8 +213,6 @@ namespace AssetProcessor AZStd::vector m_saveBuffer; // so that we don't realloc all the time - char m_absoluteDevFolderPath[AZ_MAX_PATH_LEN]; - char m_absoluteDevGameFolderPath[AZ_MAX_PATH_LEN]; QDir m_cacheRootDir; }; } diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp index 3a7bc6ef3e..4cd4489a4c 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp @@ -56,15 +56,8 @@ namespace AssetProcessor // cache this up front. Note that it can fail here, and will retry later. InitializeCacheRoot(); - m_absoluteDevFolderPath[0] = 0; - m_absoluteDevGameFolderPath[0] = 0; - QDir assetRoot; - if (AssetUtilities::ComputeAssetRoot(assetRoot)) - { - azstrcpy(m_absoluteDevFolderPath, AZ_MAX_PATH_LEN, assetRoot.absolutePath().toUtf8().constData()); - azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, AssetUtilities::ComputeProjectPath().toUtf8().constData()); - } + AssetUtilities::ComputeAssetRoot(assetRoot); using namespace AZStd::placeholders; diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h index 376af5d773..891e091f91 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h @@ -440,8 +440,6 @@ namespace AssetProcessor AZStd::mutex m_sourceUUIDToSourceInfoMapMutex; QString m_normalizedCacheRootPath; - char m_absoluteDevFolderPath[AZ_MAX_PATH_LEN]; - char m_absoluteDevGameFolderPath[AZ_MAX_PATH_LEN]; QDir m_cacheRootDir; bool m_isCurrentlyScanning = false; bool m_quitRequested = false; diff --git a/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp b/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp index 30d8e5fada..c35f3a4b0f 100644 --- a/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp +++ b/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp @@ -95,7 +95,7 @@ void FileServer::ConnectionAdded(unsigned int connId, Connection* connection) Q_UNUSED(connection); // Connection has not completed negotiation yet, register to be notified - // when we know what platform is connected and map the @assets@ alias then + // when we know what platform is connected and map the @products@ alias then connect(connection, &Connection::AssetPlatformChanged, this, [this, connection]() { auto fileIO = m_fileIOs[connection->ConnectionId()]; @@ -114,8 +114,7 @@ void FileServer::ConnectionAdded(unsigned int connId, Connection* connection) projectCacheRoot = QDir(projectCacheRoot.absoluteFilePath(assetPlatform)); } const char* projectCachePath = projectCacheRoot.absolutePath().toUtf8().data(); - fileIO->SetAlias("@assets@", projectCachePath); - fileIO->SetAlias("@root@", projectCachePath); + fileIO->SetAlias("@products@", projectCachePath); if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { @@ -955,10 +954,10 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig FileTreeResponse::FolderList folders; AZStd::vector untestedFolders; - if (fileIO->IsDirectory("@assets@")) + if (fileIO->IsDirectory("@products@")) { - folders.push_back("@assets@"); - untestedFolders.push_back("@assets@"); + folders.push_back("@products@"); + untestedFolders.push_back("@products@"); } if (fileIO->IsDirectory("@usercache@")) { @@ -975,11 +974,6 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig folders.push_back("@log@"); untestedFolders.push_back("@log@"); } - if (fileIO->IsDirectory("@root@")) - { - folders.push_back("@root@"); - untestedFolders.push_back("@root@"); - } AZ::IO::Result res = ResultCode::Success; diff --git a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp index 5d2d0e77d3..2a1c4e4755 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp @@ -766,7 +766,7 @@ namespace AssetProcessor TEST_F(AssetCatalogTest_GetFullSourcePath, AliasedCachePath_ReturnsAbsolutePathToSource) { //feed it a path with alias and asset id - QString fileToCheck = "@assets@/subfolder3/randomfileoutput.random1"; + QString fileToCheck = "@products@/subfolder3/randomfileoutput.random1"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } @@ -787,7 +787,7 @@ namespace AssetProcessor TEST_F(AssetCatalogTest_GetFullSourcePath, InvalidSourcePathContainingCacheAlias_ReturnsAbsolutePathToSource) { //feed it a path with alias and input name - QString fileToCheck = "@assets@/somerandomfile.random"; + QString fileToCheck = "@products@/somerandomfile.random"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } diff --git a/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp index 5b15a6a552..a8bc714698 100644 --- a/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp @@ -47,7 +47,7 @@ void RCcontrollerUnitTests::Reset() m_rcController.m_RCJobListModel.m_jobs.clear(); m_rcController.m_RCJobListModel.m_jobsInFlight.clear(); m_rcController.m_RCJobListModel.m_jobsInQueueLookup.clear(); - + m_rcController.m_pendingCriticalJobsPerPlatform.clear(); m_rcController.m_jobsCountPerPlatform.clear(); @@ -56,7 +56,7 @@ void RCcontrollerUnitTests::Reset() m_rcController.m_RCQueueSortModel.AttachToModel(&m_rcController.m_RCJobListModel); m_rcController.m_RCQueueSortModel.m_currentJobRunKeyToJobEntries.clear(); m_rcController.m_RCQueueSortModel.m_currentlyConnectedPlatforms.clear(); -} +} void RCcontrollerUnitTests::StartTest() { @@ -183,11 +183,11 @@ void RCcontrollerUnitTests::RunRCControllerTests() QStringList tempJobNames; // Note that while this is an OS-SPECIFIC path, this test does not actually invoke the file system - // or file operators, so is purely doing in-memory testing. So the path does not actually matter and the + // or file operators, so is purely doing in-memory testing. So the path does not actually matter and the // test should function on other operating systems too. // test - exact match - tempJobNames << "c:/somerandomfolder/dev/blah/test.dds"; + tempJobNames << "c:/somerandomfolder/dev/blah/test.dds"; tempJobNames << "c:/somerandomfolder/dev/blah/test.cre"; // must not match // test - NO MATCH @@ -218,7 +218,7 @@ void RCcontrollerUnitTests::RunRCControllerTests() QList createdJobs; - + for (QString name : tempJobNames) { @@ -270,7 +270,7 @@ void RCcontrollerUnitTests::RunRCControllerTests() // EXACT MATCH TEST (with prefixes and such) NetworkRequestID requestID(1, 1234); - m_rcController.OnRequestCompileGroup(requestID, "pc", "@assets@/blah/test.dds", AZ::Data::AssetId()); + m_rcController.OnRequestCompileGroup(requestID, "pc", "@products@/blah/test.dds", AZ::Data::AssetId()); QCoreApplication::processEvents(QEventLoop::AllEvents); // this should have matched exactly one item, and when we finish that item, it should terminate: @@ -626,9 +626,9 @@ void RCcontrollerUnitTests::RunRCControllerTests() jobdetailsB.m_jobEntry.m_watchFolderPath = scanFolderInfo.ScanPath(); jobdetailsB.m_jobEntry.m_jobKey = "TestJobB"; jobdetailsB.m_jobEntry.m_builderGuid = builderUuid; - + jobdetailsB.m_critical = true; //make jobB critical so that it will be analyzed first even though we want JobA to run first - + AssetBuilderSDK::SourceFileDependency sourceFileBDependency; sourceFileBDependency.m_sourceFileDependencyPath = "fileB.txt"; @@ -694,10 +694,10 @@ void RCcontrollerUnitTests::RunRCControllerTests() m_rcController.DispatchJobs(); UNIT_TEST_EXPECT_TRUE(UnitTestUtils::BlockUntil(allJobsCompleted, 5000)); - UNIT_TEST_EXPECT_TRUE(jobFinishedB); + UNIT_TEST_EXPECT_TRUE(jobFinishedB); - // Now test the use case where we have a cyclic dependency, - // although the order in which these job will start is not defined but we can ensure that + // Now test the use case where we have a cyclic dependency, + // although the order in which these job will start is not defined but we can ensure that // all the job finishes and RCController goes Idle allJobsCompleted = false; Reset(); @@ -728,8 +728,8 @@ void RCcontrollerUnitTests::RunRCControllerTests() jobdetailsD.m_jobEntry.m_builderGuid = builderUuid; AssetBuilderSDK::SourceFileDependency sourceFileDDependency; sourceFileDDependency.m_sourceFileDependencyPath = "fileD.txt"; - - //creating cyclic job order dependencies i.e JobC and JobD have order job dependency on each other + + //creating cyclic job order dependencies i.e JobC and JobD have order job dependency on each other AssetBuilderSDK::JobDependency jobDependencyC("TestJobC", "pc", AssetBuilderSDK::JobDependencyType::Order, sourceFileCDependency); AssetBuilderSDK::JobDependency jobDependencyD("TestJobD", "pc", AssetBuilderSDK::JobDependencyType::Order, sourceFileDDependency); jobdetailsC.m_jobDependencyList.push_back({ jobDependencyD }); diff --git a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h index f77c706421..c281b3050a 100644 --- a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h +++ b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h @@ -262,11 +262,10 @@ namespace UnitTestUtils AZ::IO::FileIOBase::SetInstance(m_localFileIO); - m_localFileIO->SetAlias("@assets@", (newDir + QString("/ALIAS/assets")).toUtf8().constData()); + m_localFileIO->SetAlias("@products@", (newDir + QString("/ALIAS/assets")).toUtf8().constData()); m_localFileIO->SetAlias("@log@", (newDir + QString("/ALIAS/logs")).toUtf8().constData()); m_localFileIO->SetAlias("@usercache@", (newDir + QString("/ALIAS/cache")).toUtf8().constData()); m_localFileIO->SetAlias("@user@", (newDir + QString("/ALIAS/user")).toUtf8().constData()); - m_localFileIO->SetAlias("@root@", (newDir + QString("/ALIAS/root")).toUtf8().constData()); } ~ScopedDir() diff --git a/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp b/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp index 6f974a0ff6..40d3bd3caa 100644 --- a/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp @@ -104,17 +104,17 @@ ApplicationManager::BeforeRunStatus GUIApplicationManager::BeforeRun() // The build process may leave behind some temporaries, try to delete them RemoveTemporaries(); - QDir devRoot; - AssetUtilities::ComputeAssetRoot(devRoot); + QDir projectAssetRoot; + AssetUtilities::ComputeAssetRoot(projectAssetRoot); #if defined(EXTERNAL_CRASH_REPORTING) - CrashHandler::ToolsCrashHandler::InitCrashHandler("AssetProcessor", devRoot.absolutePath().toStdString()); + CrashHandler::ToolsCrashHandler::InitCrashHandler("AssetProcessor", projectAssetRoot.absolutePath().toStdString()); #endif AssetProcessor::MessageInfoBus::Handler::BusConnect(); // we have to monitor both the cache folder and the database file and restart AP if either of them gets deleted // It is important to note that we are monitoring the parent folder and not the actual cache folder itself since // we want to handle the use case on Mac OS if the user moves the cache folder to the trash. - m_qtFileWatcher.addPath(devRoot.absolutePath()); + m_qtFileWatcher.addPath(projectAssetRoot.absolutePath()); QDir projectCacheRoot; AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); @@ -615,7 +615,6 @@ void GUIApplicationManager::DirectoryChanged([[maybe_unused]] QString path) void GUIApplicationManager::FileChanged(QString path) { - QDir devRoot = ApplicationManager::GetSystemRoot(); QDir projectCacheRoot; AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); QString assetDbPath = projectCacheRoot.filePath("assetdb.sqlite"); diff --git a/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp b/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp index 527feac6b4..2cf7705e96 100644 --- a/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp +++ b/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp @@ -56,7 +56,7 @@ namespace CrashHandler if (fileIO) { // If our devroot alias is available, use that - const char* devAlias = fileIO->GetAlias("@devroot@"); + const char* devAlias = fileIO->GetAlias("@engroot@"); if (devAlias) { return devAlias; diff --git a/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp b/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp index 91ca77fa7b..c7d85428b4 100644 --- a/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp +++ b/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp @@ -87,7 +87,7 @@ namespace PythonBindingsExample TEST_F(PythonBindingsExampleTest, Application_ImportAzLmbrPaths_Works) { ApplicationParameters params; - params.m_pythonStatement = "import azlmbr.paths; print (azlmbr.paths.engroot); print (azlmbr.paths.devroot)"; + params.m_pythonStatement = "import azlmbr.paths; print (azlmbr.paths.engroot)"; EXPECT_TRUE(s_application->RunWithParameters(params)); } diff --git a/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp b/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp index aaa76e5977..aa88dee90f 100644 --- a/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp @@ -14,8 +14,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -170,11 +172,14 @@ namespace AZ { using AzToolsFramework::AssetSystemRequestBus; - const char* path = nullptr; - AssetSystemRequestBus::BroadcastResult(path, &AssetSystemRequestBus::Events::GetAbsoluteDevGameFolderPath); - if (path) + AZ::IO::Path projectPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - return path; + settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); + } + if (!projectPath.empty()) + { + return projectPath.Native(); } else { diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index c815af3b7a..6cfe072f80 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -38,7 +38,7 @@ // SliceConverter reads in a slice file (saved in an ObjectStream format), instantiates it, creates a prefab out of the data, // and saves the prefab in a JSON format. This can be used for one-time migrations of slices or slice-based levels to prefabs. -// +// // If the slice contains legacy data, it will print out warnings / errors about the data that couldn't be serialized. // The prefab will be generated without that data. @@ -56,7 +56,7 @@ namespace AZ AZ_Error("SerializeContextTools", false, "Command line not available."); return false; } - + JsonSerializerSettings convertSettings; convertSettings.m_keepDefaults = commandLine->HasSwitch("keepdefaults"); convertSettings.m_registrationContext = application.GetJsonRegistrationContext(); @@ -82,7 +82,7 @@ namespace AZ // Load the asset catalog so that we can find any nested assets successfully. We also need to tick the tick bus // so that the OnCatalogLoaded event gets processed now, instead of during application shutdown. AZ::Data::AssetCatalogRequestBus::Broadcast( - &AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); + &AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml"); application.Tick(); AZStd::string logggingScratchBuffer; @@ -870,7 +870,7 @@ namespace AZ // Wait for the disconnect to finish. bool disconnected = false; - AzFramework::AssetSystemRequestBus::BroadcastResult(disconnected, + AzFramework::AssetSystemRequestBus::BroadcastResult(disconnected, &AzFramework::AssetSystem::AssetSystemRequests::WaitUntilAssetProcessorDisconnected, AZStd::chrono::seconds(30)); AZ_Error("Convert-Slice", disconnected, "Asset Processor failed to disconnect successfully."); diff --git a/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp b/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp index 4653975a52..d51539a471 100644 --- a/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp +++ b/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp @@ -64,7 +64,7 @@ namespace AWSCore void AWSCoreConfiguration::InitSourceProjectFolderPath() { - auto sourceProjectFolder = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + auto sourceProjectFolder = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); if (!sourceProjectFolder) { AZ_Error(AWSCoreConfigurationName, false, ProjectSourceFolderNotFoundErrorMessage); diff --git a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp index a2c89a5af3..0b485609ad 100644 --- a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp +++ b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp @@ -197,7 +197,7 @@ namespace AWSCore subMenu->addAction(AddExternalLinkAction( AWSMetricsAdvancedTopicsActionText, AWSMetricsAdvancedTopicsUrl, ":/Notifications/link.svg")); - AZStd::string priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@"); + AZStd::string priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@engroot@"); AZStd::string configFilePath = priorAlias + "\\Gems\\AWSMetrics\\Code\\" + AZ::SettingsRegistryInterface::RegistryFolder; AzFramework::StringFunc::Path::Normalize(configFilePath); diff --git a/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp b/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp index 6bde2c2fbf..e54a55f728 100644 --- a/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp +++ b/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp @@ -60,7 +60,7 @@ public: m_normalizedSourceProjectFolder.c_str(), AZ::SettingsRegistryInterface::RegistryFolder); AzFramework::StringFunc::Path::Normalize(m_normalizedSetRegFolderPath); - m_localFileIO->SetAlias("@devassets@", m_normalizedSourceProjectFolder.c_str()); + m_localFileIO->SetAlias("@projectroot@", m_normalizedSourceProjectFolder.c_str()); CreateTestSetRegFile(TEST_VALID_RESOURCE_MAPPING_SETREG); } @@ -122,7 +122,7 @@ private: TEST_F(AWSCoreConfigurationTest, InitConfig_NoSourceProjectFolderFound_ReturnEmptyConfigFilePath) { m_settingsRegistry->MergeSettingsFile(m_normalizedSetRegFilePath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}); - m_localFileIO->ClearAlias("@devassets@"); + m_localFileIO->ClearAlias("@projectroot@"); AZ_TEST_START_TRACE_SUPPRESSION; m_awsCoreConfiguration->InitConfig(); @@ -154,7 +154,7 @@ TEST_F(AWSCoreConfigurationTest, InitConfig_LoadValidSettingsRegistry_ReturnNonE TEST_F(AWSCoreConfigurationTest, ReloadConfiguration_NoSourceProjectFolderFound_ReturnEmptyConfigFilePath) { m_settingsRegistry->MergeSettingsFile(m_normalizedSetRegFilePath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}); - m_localFileIO->ClearAlias("@devassets@"); + m_localFileIO->ClearAlias("@projectroot@"); m_awsCoreConfiguration->ReloadConfiguration(); auto actualConfigFilePath = m_awsCoreConfiguration->GetResourceMappingConfigFilePath(); diff --git a/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp b/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp index 40ed5b53b5..e9453a4a0a 100644 --- a/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp +++ b/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp @@ -32,7 +32,7 @@ class AWSCoreEditorMenuTest { AWSCoreEditorUIFixture::SetUp(); AWSCoreFixture::SetUp(); - m_localFileIO->SetAlias("@devroot@", "dummy engine root"); + m_localFileIO->SetAlias("@engroot@", "dummy engine root"); } void TearDown() override diff --git a/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp b/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp index 7e4ec05aba..bc8ff9a42e 100644 --- a/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp +++ b/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp @@ -22,7 +22,7 @@ namespace AWSMetrics AZStd::string IdentityProvider::GetEngineVersion() { - static constexpr const char* EngineConfigFilePath = "@root@/engine.json"; + static constexpr const char* EngineConfigFilePath = "@products@/engine.json"; static constexpr const char* EngineVersionJsonKey = "O3DEVersion"; AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetDirectInstance(); diff --git a/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h b/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h index 6b7c809601..b77f39c93c 100644 --- a/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h +++ b/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include namespace AWSMetrics { @@ -34,15 +34,22 @@ namespace AWSMetrics // Set up the file IO and alias m_localFileIO = aznew AZ::IO::LocalFileIO(); m_priorFileIO = AZ::IO::FileIOBase::GetInstance(); - // we need to set it to nullptr first because otherwise the + // we need to set it to nullptr first because otherwise the // underneath code assumes that we might be leaking the previous instance AZ::IO::FileIOBase::SetInstance(nullptr); AZ::IO::FileIOBase::SetInstance(m_localFileIO); - const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); - m_localFileIO->SetAlias("@devroot@", engineRoot.c_str()); - m_localFileIO->SetAlias("@root@", engineRoot.c_str()); - m_localFileIO->SetAlias("@user@", GetTestFolderPath().c_str()); + const AZ::IO::Path engineRoot = AZ::Test::GetEngineRootPath(); + const auto productAssetPath = GetTestFolderPath() / "Cache"; + const auto userPath = GetTestFolderPath() / "user"; + m_localFileIO->CreatePath(productAssetPath.c_str()); + m_localFileIO->CreatePath(userPath.c_str()); + m_localFileIO->SetAlias("@engroot@", engineRoot.c_str()); + m_localFileIO->SetAlias("@products@", productAssetPath.c_str()); + m_localFileIO->SetAlias("@user@", userPath.c_str()); + // Copy engine.json to the cache + EXPECT_TRUE(m_localFileIO->Copy((engineRoot / "engine.json").c_str(), "engine.json")); + m_serializeContext = AZStd::make_unique(); m_registrationContext = AZStd::make_unique(); @@ -69,6 +76,13 @@ namespace AWSMetrics m_serializeContext.reset(); m_registrationContext.reset(); + const auto productAssetPath = GetTestFolderPath() / "Cache"; + const auto userPath = GetTestFolderPath() / "user"; + // Clear the product asset cache alias to prevent cache write errors + m_localFileIO->ClearAlias("@products@"); + m_localFileIO->DestroyPath(userPath.c_str()); + m_localFileIO->DestroyPath(productAssetPath.c_str()); + AZ::IO::FileIOBase::SetInstance(nullptr); delete m_localFileIO; AZ::IO::FileIOBase::SetInstance(m_priorFileIO); @@ -97,22 +111,22 @@ namespace AWSMetrics bool CreateFile(const AZStd::string& filePath, const AZStd::string& content) { AZ::IO::HandleType fileHandle; + // Suppress errors about writing to product asset cache + AZ_TEST_START_TRACE_SUPPRESSION; if (!m_localFileIO->Open(filePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText, fileHandle)) { return false; } m_localFileIO->Write(fileHandle, content.c_str(), content.size()); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; m_localFileIO->Close(fileHandle); return true; } AZStd::string GetDefaultTestFilePath() { - AZStd::string testFilePath = GetTestFolderPath(); - AzFramework::StringFunc::Path::Join(testFilePath.c_str(), "Test.json", testFilePath); - - return testFilePath; + return (GetTestFolderPath() / "Test.json").Native(); } bool RemoveFile(const AZStd::string& filePath) @@ -133,14 +147,16 @@ namespace AWSMetrics AZ::IO::FileIOBase* m_priorFileIO = nullptr; AZ::IO::FileIOBase* m_localFileIO = nullptr; + AZ::Test::ScopedAutoTempDirectory m_testDirectory; AZStd::unique_ptr m_serializeContext; AZStd::unique_ptr m_registrationContext; AZStd::unique_ptr m_settingsRegistry; private: - AZStd::string GetTestFolderPath() + AZ::IO::Path GetTestFolderPath() { - return AZ_TRAIT_TEST_ROOT_FOLDER; + AZ::IO::Path testPathString{ m_testDirectory.GetDirectory() }; + return testPathString; } }; } diff --git a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp index b4bf68bac1..56f28856af 100644 --- a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp +++ b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp @@ -142,14 +142,14 @@ namespace AssetValidation system.GetIConsole()->AddCommand("addseedlist", ConsoleCommandAddSeedList); system.GetIConsole()->AddCommand("removeseedlist", ConsoleCommandRemoveSeedList); system.GetIConsole()->AddCommand("printexcluded", ConsoleCommandTogglePrintExcluded); - } + } bool AssetValidationSystemComponent::IsKnownAsset(const char* assetPath) { AZStd::string lowerAsset{ assetPath }; AZStd::replace(lowerAsset.begin(), lowerAsset.end(), AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR); - const AZStd::vector prefixes = { "./", "@assets@/" }; + const AZStd::vector prefixes = { "./", "@products@/" }; for (const AZStd::string& prefix : prefixes) { if (lowerAsset.starts_with(prefix)) @@ -392,7 +392,7 @@ namespace AssetValidation AssetValidationRequestBus::Broadcast(&AssetValidationRequestBus::Events::AddSeedList, seedfilepath); } - bool AssetValidationSystemComponent::AddSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) + bool AssetValidationSystemComponent::AddSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) { for (const AzFramework::SeedInfo& thisSeed : seedList) { @@ -401,7 +401,7 @@ namespace AssetValidation return true; } - bool AssetValidationSystemComponent::RemoveSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) + bool AssetValidationSystemComponent::RemoveSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) { AssetValidationRequests::AssetSourceList removeList; for (const AzFramework::SeedInfo& thisSeed : seedList) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp index 3493099d4c..924c01b916 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp @@ -244,7 +244,7 @@ namespace ImageProcessingAtom } AZ::IO::FixedMaxPath projectConfigFolder; - if (auto sourceGameRoot = fileIoBase->ResolvePath("@devassets@"); sourceGameRoot.has_value()) + if (auto sourceGameRoot = fileIoBase->ResolvePath("@projectroot@"); sourceGameRoot.has_value()) { projectConfigFolder = *sourceGameRoot; projectConfigFolder /= s_projectConfigRelativeFolder; diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 7c5be89508..27ae90dcdc 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -139,16 +139,16 @@ namespace AZ //! Validates if a given .shadervariantlist file is located at the correct path for a given .shader full path. //! There are two valid paths: //! 1- Lower Precedence: The same folder where the .shader file is located. - //! 2- Higher Precedence: //ShaderVariants/. + //! 2- Higher Precedence: /ShaderVariants/. //! The "Higher Precedence" path gives the option to game projects to override what variants to generate. If this //! file exists then the "Lower Precedence" path is disregarded. //! A .shader full path is located under an AP scan folder. - //! Example: "/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader" - //! - In this example the Scan Folder is "/Gems/Atom/Feature/Common/Assets", while the subfolder is "Materials/Types". + //! Example: "/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader" + //! - In this example the Scan Folder is "/Gems/Atom/Feature/Common/Assets", while the subfolder is "Materials/Types". //! The "Higher Precedence" expected valid location for the .shadervariantlist would be: - //! - //ShaderVariants/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. + //! - //ShaderVariants/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. //! The "Lower Precedence" valid location would be: - //! - /Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. + //! - /Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. //! @shouldExitEarlyFromProcessJob [out] Set to true if ProcessJob should do no work but return successfully. //! Set to false if ProcessJob should do work and create assets. //! When @shaderVariantListFileFullPath is provided by a Gem/Feature instead of the Game Project @@ -169,17 +169,13 @@ namespace AZ AZStd::string shaderVariantListFileRelativePath = shaderProductFileRelativePath; AzFramework::StringFunc::Path::ReplaceExtension(shaderVariantListFileRelativePath, RPI::ShaderVariantListSourceData::Extension); - const char * gameProjectPath = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(gameProjectPath, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); + AZ::IO::FixedMaxPath gameProjectPath = AZ::Utils::GetProjectPath(); - AZStd::string expectedHigherPrecedenceFileFullPath; - AzFramework::StringFunc::Path::Join(gameProjectPath, RPI::ShaderVariantTreeAsset::CommonSubFolder, expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */); - AzFramework::StringFunc::Path::Join(expectedHigherPrecedenceFileFullPath.c_str(), shaderProductFileRelativePath.c_str(), expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */); - AzFramework::StringFunc::Path::ReplaceExtension(expectedHigherPrecedenceFileFullPath, AZ::RPI::ShaderVariantListSourceData::Extension); - AzFramework::StringFunc::Path::Normalize(expectedHigherPrecedenceFileFullPath); + auto expectedHigherPrecedenceFileFullPath = (gameProjectPath + / RPI::ShaderVariantTreeAsset::CommonSubFolder / shaderProductFileRelativePath).LexicallyNormal(); + expectedHigherPrecedenceFileFullPath.ReplaceExtension(AZ::RPI::ShaderVariantListSourceData::Extension); - AZStd::string normalizedShaderVariantListFileFullPath = shaderVariantListFileFullPath; - AzFramework::StringFunc::Path::Normalize(normalizedShaderVariantListFileFullPath); + auto normalizedShaderVariantListFileFullPath = AZ::IO::FixedMaxPath(shaderVariantListFileFullPath).LexicallyNormal(); if (expectedHigherPrecedenceFileFullPath == normalizedShaderVariantListFileFullPath) { @@ -203,23 +199,15 @@ namespace AZ } // Check the "Lower Precedence" case, .shader path == .shadervariantlist path. - AZStd::string normalizedShaderFileFullPath = shaderFileFullPath; - AzFramework::StringFunc::Path::Normalize(normalizedShaderFileFullPath); - - AZStd::string normalizedShaderFileFullPathWithoutExtension = normalizedShaderFileFullPath; - AzFramework::StringFunc::Path::StripExtension(normalizedShaderFileFullPathWithoutExtension); - - AZStd::string normalizedShaderVariantListFileFullPathWithoutExtension = normalizedShaderVariantListFileFullPath; - AzFramework::StringFunc::Path::StripExtension(normalizedShaderVariantListFileFullPathWithoutExtension); - -#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - //In certain circumstances, the capitalization of the drive letter may not match - const bool caseSensitive = false; -#else - //On the other platforms there's no drive letter, so it should be a non-issue. - const bool caseSensitive = true; -#endif - if (!StringFunc::Equal(normalizedShaderFileFullPathWithoutExtension.c_str(), normalizedShaderVariantListFileFullPathWithoutExtension.c_str(), caseSensitive)) + AZ::IO::Path normalizedShaderFileFullPath = AZ::IO::Path(shaderFileFullPath).LexicallyNormal(); + + auto normalizedShaderFileFullPathWithoutExtension = normalizedShaderFileFullPath; + normalizedShaderFileFullPathWithoutExtension.ReplaceExtension(""); + + auto normalizedShaderVariantListFileFullPathWithoutExtension = normalizedShaderVariantListFileFullPath; + normalizedShaderVariantListFileFullPathWithoutExtension.ReplaceExtension(""); + + if (normalizedShaderFileFullPathWithoutExtension != normalizedShaderVariantListFileFullPathWithoutExtension) { AZ_Error(ShaderVariantAssetBuilderName, false, "For shader file at path [%s], the shader variant list [%s] is expected to be located at [%s.%s] or [%s]" , normalizedShaderFileFullPath.c_str(), normalizedShaderVariantListFileFullPath.c_str(), diff --git a/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp b/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp index 8495e9b119..27336c8280 100644 --- a/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp +++ b/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp @@ -28,7 +28,7 @@ namespace UnitTest m_application.reset(); } - static constexpr const char TestDataFolder[] = "@devroot@/Gems/Atom/RHI/Code/Tests/UtilsTestsData/"; + static constexpr const char TestDataFolder[] = "@engroot@/Gems/Atom/RHI/Code/Tests/UtilsTestsData/"; AZStd::unique_ptr m_application; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h index 341824a84d..bd11965ffa 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h @@ -44,14 +44,14 @@ namespace AZ AZStd::string GetSourcePathByAssetId(const AZ::Data::AssetId& assetId); //! Tries to resolve a relative file reference, given the path of a referencing file. - //! @param originatingSourceFilePath Path to the parent file that references referencedSourceFilePath. May be absolute or relative to asset-root. + //! @param originatingSourceFilePath Path to the parent file that references referencedSourceFilePath. May be absolute or relative to asset-root. //! @param referencedSourceFilePath Path that the parent file references. May be relative to the parent file location or relative to asset-root. //! @return A full path for referencedSourceFilePath, if a full path was found. If a full path could not be constructed, returns referencedSourceFilePath unmodified. AZStd::string ResolvePathReference(const AZStd::string& originatingSourceFilePath, const AZStd::string& referencedSourceFilePath); - //! Returns the list of paths where a source asset file could possibly appear. + //! Returns the list of paths where a source asset file could possibly appear. //! This is intended for use by AssetBuilders when reporting dependencies, to support relative paths between source files. - //! When a source data file references another file using a relative path, the path might be relative to the originating + //! When a source data file references another file using a relative path, the path might be relative to the originating //! file or it might be a standard source asset path (i.e. relative to the logical asset-root). This function will help reporting //! dependencies on all possible locations where that file may appear at some point in the future. //! For example a file MyGem/Assets/Foo/a.json might reference another file as "Bar/b.json". In this case, calling @@ -94,9 +94,9 @@ namespace AZ template Outcome> LoadAsset(const AZ::Data::AssetId& assetId, [[maybe_unused]] const char* sourcePathForDebug) { - if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@")) + if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@")) { - // The absence of "@assets@" is not necessarily the reason LoadAsset() can't be used in CreateJobs(), but it + // The absence of "@products@" is not necessarily the reason LoadAsset() can't be used in CreateJobs(), but it // is a symptom of calling LoadAsset() from CreateJobs() which is not supported. AZ_Assert(false, "It appears AssetUtils::LoadAsset() is being called in CreateJobs(). It can only be used in ProcessJob()."); return AZ::Failure(); diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp index 63a1524929..a5511edea1 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp @@ -53,16 +53,6 @@ namespace UnitTest return false; } - const char* AssetSystemStub::GetAbsoluteDevGameFolderPath() - { - return nullptr; - } - - const char* AssetSystemStub::GetAbsoluteDevRootFolderPath() - { - return nullptr; - } - bool AssetSystemStub::GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) { return false; diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h index a73570e3c9..2dd810b1e6 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h @@ -56,8 +56,6 @@ namespace UnitTest AZStd::unordered_map m_sourceInfoMap; bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override; - const char* GetAbsoluteDevGameFolderPath() override; - const char* GetAbsoluteDevRootFolderPath() override; bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& relativeProductPath) override; bool GenerateRelativeSourcePath( const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder) override; diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp index aaa574a14a..5343c295d8 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp @@ -67,7 +67,7 @@ namespace UnitTest AZ::IO::Path assetPath = AZStd::string_view{ AZ::Utils::GetProjectPath() }; assetPath /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetPath.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetPath.c_str()); m_jsonRegistrationContext = AZStd::make_unique(); m_jsonSystemComponent = AZStd::make_unique(); @@ -90,7 +90,7 @@ namespace UnitTest JobManagerThreadDesc threadDesc; #if AZ_TRAIT_SET_JOB_PROCESSOR_ID threadDesc.m_cpuId = 0; // Don't set processors IDs on windows -#endif +#endif uint32_t numWorkerThreads = AZStd::thread::hardware_concurrency(); @@ -99,7 +99,7 @@ namespace UnitTest desc.m_workerThreads.push_back(threadDesc); #if AZ_TRAIT_SET_JOB_PROCESSOR_ID threadDesc.m_cpuId++; -#endif +#endif } m_jobManager = AZStd::make_unique(desc); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index 13b9a2ba27..3fae2ee7a3 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -173,7 +173,7 @@ namespace AtomToolsFramework AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); - AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); + AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml"); if (!AZ::RPI::RPISystemInterface::Get()->IsInitialized()) { @@ -289,7 +289,7 @@ namespace AtomToolsFramework ExitMainLoop(); } } - + void AtomToolsApplication::SaveSettings() { if (m_activatedLocalUserSettings) @@ -378,7 +378,7 @@ namespace AtomToolsFramework ExitMainLoop(); } } - + bool AtomToolsApplication::LaunchLocalServer() { // Determine if this is the first launch of the tool by attempting to connect to a running server diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp index f27a08b08d..fd20716570 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp @@ -24,7 +24,7 @@ namespace MaterialEditor { CreateMaterialDialog::CreateMaterialDialog(QWidget* parent) - : CreateMaterialDialog(QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials", parent) + : CreateMaterialDialog(QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials", parent) { } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp index e6ffd2842f..d73737a2dc 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp @@ -106,7 +106,7 @@ namespace MaterialEditor menu->addAction("Create Material...", [entry]() { const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + + QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." + AZ::RPI::MaterialSourceData::Extension).absoluteFilePath(); @@ -182,7 +182,7 @@ namespace MaterialEditor menu->addAction("Create Child Material...", [entry]() { const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + + QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." + AZ::RPI::MaterialSourceData::Extension).absoluteFilePath(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp index a00d3eec05..5721dfcc72 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp @@ -346,7 +346,7 @@ namespace MaterialEditor AZStd::string ViewportSettingsInspector::GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const { - AZStd::string savePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + AZStd::string savePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR; savePath += "Materials"; savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR; diff --git a/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py b/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py index 6708553e20..041e1a80c5 100755 --- a/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py +++ b/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py @@ -16,10 +16,10 @@ import sys import os.path import filecmp -g_devroot = azlmbr.paths.devroot -sys.path.append(os.path.join(g_devroot, 'Tests', 'Atom', 'Automated')) +g_engroot = azlmbr.paths.engroot +sys.path.append(os.path.join(g_engroot, 'Tests', 'Atom', 'Automated')) -g_materialTestFolder = os.path.join(g_devroot,'Gems','Atom','TestData','TestData','Materials','StandardPbrTestCases') +g_materialTestFolder = os.path.join(g_engroot,'Gems','Atom','TestData','TestData','Materials','StandardPbrTestCases') # Change this to True to replace the expected screenshot images g_replaceExpectedScreenshots = False diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py b/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py index 7bd65568ed..c31047d347 100755 --- a/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py +++ b/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py @@ -135,7 +135,7 @@ def main(): # clean previously generated shader variant list file so they don't clash. pre, ext = os.path.splitext(shaderAssetInfo.relativePath) - projectShaderVariantListFilePath = os.path.join(azlmbr.paths.devassets, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist') + projectShaderVariantListFilePath = os.path.join(azlmbr.paths.projectroot, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist') pre, ext = os.path.splitext(filename) defaultShaderVariantListFilePath = f'{pre}.shadervariantlist' diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp index 5711e3ff6e..cdb941546d 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp @@ -46,7 +46,7 @@ static void DumfontTexture(IConsoleCmdArgs* cmdArgs) if (fontName && *fontName && *fontName != '0') { - AZStd::string fontFilePath("@devroot@/"); + AZStd::string fontFilePath("@engroot@/"); fontFilePath += fontName; fontFilePath += ".bmp"; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp index 7f676e4c10..4363ac1a62 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp @@ -389,7 +389,7 @@ namespace AZ // create the full paths char projectPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN); AZStd::string irradianceTextureFullPath; AzFramework::StringFunc::Path::Join(projectPath, irradianceTextureRelativePath.c_str(), irradianceTextureFullPath, true, true); @@ -481,7 +481,7 @@ namespace AZ AZStd::string fullPath; char projectPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN); if (!relativePath.empty()) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 095c670e15..665adcd568 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -529,7 +529,7 @@ namespace AZ bool MaterialPropertyInspector::SaveMaterial() const { const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + + QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." + AZ::RPI::MaterialSourceData::Extension).absoluteFilePath(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index d7fcd124d0..f325a20ac1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -321,7 +321,7 @@ namespace AZ } char projectPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN); // retrieve the source cubemap path from the configuration // we need to make sure to use the same source cubemap for each bake diff --git a/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp b/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp index a31885cc69..2fe5d749cf 100644 --- a/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp @@ -105,7 +105,7 @@ namespace AudioControlBuilder Audio::ATLXmlTags::ATLPreloadRequestTag, "preload request")); } - // For each preload request in the control file, determine which config group is used for this platform and register each + // For each preload request in the control file, determine which config group is used for this platform and register each // bank listed in that preload request as a dependency. while (preloadRequestNode) { @@ -163,7 +163,7 @@ namespace AudioControlBuilder const AZ::rapidxml::xml_node* configGroupNode = configGroupMap[configGroupName]; if (!configGroupNode) { - // The config group this platform uses isn't defined in the control file. This might be intentional, so just + // The config group this platform uses isn't defined in the control file. This might be intentional, so just // generate a warning and keep going to the next preload node. AZ_TracePrintf("Audio Control Builder", "%s node for config group %s is not defined, so no banks are referenced.", Audio::ATLXmlTags::ATLConfigGroupTag, configGroupName.c_str()); @@ -188,7 +188,7 @@ namespace AudioControlBuilder } // Prepend the bank name with the relative path to the wwise sounds folder to get relative path to the bank from - // the @assets@ alias and push that into the list of banks referenced. + // the @products@ alias and push that into the list of banks referenced. AZStd::string soundsPrefix = Audio::Wwise::DefaultBanksPath; banksReferenced.emplace_back(soundsPrefix + bankNameAttribute->value()); @@ -496,7 +496,7 @@ namespace AudioControlBuilder pathDependencies.emplace(relativeBankPath, AssetBuilderSDK::ProductPathDependencyType::ProductFile); } - // For each bank figure out what events are included in the bank, then run through every event referenced in the file and + // For each bank figure out what events are included in the bank, then run through every event referenced in the file and // make sure it is in the list gathered from the banks. const auto triggersNode = node->first_node(Audio::ATLXmlTags::TriggersNodeTag); if (!triggersNode) @@ -520,7 +520,7 @@ namespace AudioControlBuilder AZStd::set wwiseEventsInReferencedBanks; - // Load all bankdeps files for all banks referenced and aggregate the list of events in those files. + // Load all bankdeps files for all banks referenced and aggregate the list of events in those files. for (const AZStd::string& relativeBankPath : banksReferenced) { // Create the full path to the bankdeps file from the bank file. diff --git a/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp b/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp index 3a1916edc3..22fa4cab7d 100644 --- a/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp @@ -52,7 +52,7 @@ namespace WwiseBuilder { fileNames.push_back(dependenciesArray[dependencyIndex].GetString()); } - + // The dependency array is empty, which likely means it was modified by hand. However, every bank is dependent // on init.bnk (other than itself), so just force add it as a dependency here. and emit a warning. if (fileNames.size() == 0) @@ -93,7 +93,7 @@ namespace WwiseBuilder void WwiseBuilderWorker::Initialize() { - AZ::IO::Path configFile("@devassets@"); + AZ::IO::Path configFile("@projectroot@"); configFile /= Audio::Wwise::DefaultBanksPath; configFile /= Audio::Wwise::ConfigFile; @@ -180,7 +180,7 @@ namespace WwiseBuilder { AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Starting Job.\n"); AZ::IO::PathView fullPath(request.m_fullPath); - + if (m_isShuttingDown) { AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown was requested.\n", request.m_fullPath.c_str()); @@ -204,7 +204,7 @@ namespace WwiseBuilder AZ::Outcome gatherProductDependenciesResponse = GatherProductDependencies(request.m_fullPath, request.m_sourceFile, dependencyPaths); if (!gatherProductDependenciesResponse.IsSuccess()) { - AZ_Error(WwiseBuilderWindowName, false, "Dependency gathering for %s failed. %s", + AZ_Error(WwiseBuilderWindowName, false, "Dependency gathering for %s failed. %s", request.m_fullPath.c_str(), gatherProductDependenciesResponse.GetError().c_str()); } else diff --git a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp index 2387588f31..e65dbcce9f 100644 --- a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp +++ b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp @@ -28,7 +28,7 @@ protected: { m_app.Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -39,7 +39,7 @@ protected: assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); } void TearDown() override @@ -158,7 +158,7 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_InitBank_NoMetadata_NoDependencies) TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoMetadata_NoDependencies) { - // Should generate a warning after trying to find metadata for the given bank, when the bank is not the init bank. + // Should generate a warning after trying to find metadata for the given bank, when the bank is not the init bank. // Warning should be about not being able to generate full dependency information without the metadata file. TestSuccessCaseNoDependencies("test_doesNotExist.bnk", true); } @@ -180,15 +180,15 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_MultipleDependencies) TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_DependencyArrayNonexistent_NoDependencies) { - // Should generate a warning when trying to get dependency info from metadata file, but the dependency field does - // not an empty array. Warning should be describing that a dependency on the init bank was added by default, but + // Should generate a warning when trying to get dependency info from metadata file, but the dependency field does + // not an empty array. Warning should be describing that a dependency on the init bank was added by default, but // the full dependency list could not be generated. TestSuccessCaseNoDependencies("test_bank7.bnk", true); } TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoElementsInDependencyArray_NoDependencies) { - // Should generate a warning when trying to get dependency info from metadata file, but the dependency field is + // Should generate a warning when trying to get dependency info from metadata file, but the dependency field is // an empty array. Warning should be describing that a dependency on the init bank was added by default, but the // full dependency list could not be generated. TestSuccessCaseNoDependencies("test_bank8.bnk", true); @@ -196,8 +196,8 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoElementsInDependencyArray_N TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_MissingInitBankDependency_MultipleDependencies) { - // Should generate a warning when trying to get dependency info from metadata file, but the dependency info in the - // metadata doesn't include the init bank. Warning should be describing that a dependency on the init bank was + // Should generate a warning when trying to get dependency info from metadata file, but the dependency info in the + // metadata doesn't include the init bank. Warning should be describing that a dependency on the init bank was // added by default. AZStd::vector expectedPaths = { "Sounds/wwise/init.bnk", diff --git a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp index 3724069045..4ee816b048 100644 --- a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp +++ b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp @@ -231,7 +231,7 @@ namespace UnitTest m_app.Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -253,10 +253,10 @@ namespace UnitTest AZ_TEST_ASSERT(serializeContext != nullptr); Audio::Wwise::ConfigurationSettings::Reflect(serializeContext); - // Set the @assets@ alias to the path where *this* cpp file lives. + // Set the @products@ alias to the path where *this* cpp file lives. AZStd::string rootFolder(AZ::Test::GetCurrentExecutablePath()); AZ::StringFunc::Path::Join(rootFolder.c_str(), "Test.Assets/Gems/AudioEngineWwise", rootFolder); - m_fileIO->SetAlias("@assets@", rootFolder.c_str()); + m_fileIO->SetAlias("@products@", rootFolder.c_str()); // So we don't have to compute it in each test... AZStd::string defaultBanksPath(Audio::Wwise::DefaultBanksPath); @@ -303,26 +303,12 @@ namespace UnitTest m_mapEntry.m_bankSubPath = "soundbanks"; config.m_platformMappings.push_back(m_mapEntry); - // Unfortunately we are writing to the config file that is simulated to be in the @assets@ subfolder - // This will cause an issue during save. Since 'm_configFilePath' is an absolute path, we need to - // reset the @assets@ alias to a meaningful assets path that does not contain any root of the m_configFilePath - // in order to write to the config file and proceed - //AZStd::string rootFolder(AZ::Test::GetCurrentExecutablePath()); - //AZ::IO::Path tempAssetPath(rootFolder); - //tempAssetPath /= "Cache"; - - //AZStd::string previousAlias = m_fileIO->GetAlias("@assets@"); - //m_fileIO->SetAlias("@assets@", tempAssetPath.c_str()); - config.Save(m_configFilePath); - //m_fileIO->SetAlias("@assets@", previousAlias.c_str()); m_wwiseImpl.SetBankPaths(); - //m_fileIO->SetAlias("@assets@", tempAssetPath.c_str()); m_fileIO->Remove(m_configFilePath.c_str()); - //m_fileIO->SetAlias("@assets@", previousAlias.c_str()); EXPECT_STREQ(m_wwiseImpl.m_soundbankFolder.c_str(), "sounds/wwise/soundbanks/"); } diff --git a/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp b/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp index 996a2a80b6..aa93a2bc12 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp @@ -977,7 +977,7 @@ namespace Audio , m_rPreloadRequests(rPreloadRequests) , m_nTriggerImplIDCounter(AUDIO_TRIGGER_IMPL_ID_NUM_RESERVED) , m_rFileCacheMgr(rFileCacheMgr) - , m_rootPath("@assets@") + , m_rootPath("@products@") #if !defined(AUDIO_RELEASE) , m_pDebugNameStore(nullptr) #endif // !AUDIO_RELEASE diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index 0c697f12b6..21ec1a4603 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -292,7 +292,7 @@ namespace Blast void BlastSystemComponent::SaveConfiguration() { - auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); if (!assetRoot) { @@ -309,7 +309,7 @@ namespace Blast void BlastSystemComponent::CheckoutConfiguration() { - const auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + const auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); AZStd::string fullPath; AzFramework::StringFunc::Path::Join(assetRoot, DefaultConfigurationPath, fullPath); diff --git a/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp b/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp index 21b0b28c47..85c9c696a2 100644 --- a/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp +++ b/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp @@ -16,7 +16,7 @@ namespace CertificateManager { static bool ReadFileIntoString(const char* filename, AZStd::vector& outBuffer) { - AZStd::string certificatePath = "@assets@/certificates/"; + AZStd::string certificatePath = "@products@/certificates/"; certificatePath.append(filename); AZ::IO::FileIOBase* fileBase = AZ::IO::FileIOBase::GetInstance(); @@ -58,7 +58,7 @@ namespace CertificateManager return true; } - FileDataSource::FileDataSource() + FileDataSource::FileDataSource() : m_privateKeyPEM(nullptr) , m_certificatePEM(nullptr) , m_certificateAuthorityCertPEM(nullptr) @@ -73,13 +73,13 @@ namespace CertificateManager azfree(m_privateKeyPEM); azfree(m_certificatePEM); azfree(m_certificateAuthorityCertPEM); - } + } void FileDataSource::ConfigureDataSource(const char* keyPath, const char* certPath, const char* caPath) { ConfigurePrivateKey(keyPath); ConfigureCertificate(certPath); - ConfigureCertificateAuthority(caPath); + ConfigureCertificateAuthority(caPath); } void FileDataSource::ConfigurePrivateKey(const char* path) @@ -107,7 +107,7 @@ namespace CertificateManager if (path != nullptr) { LoadGenericFile(path,m_certificatePEM); - } + } } void FileDataSource::ConfigureCertificateAuthority(const char* path) @@ -133,7 +133,7 @@ namespace CertificateManager { return m_certificateAuthorityCertPEM; } - + bool FileDataSource::HasPublicKey() const { return m_certificatePEM != nullptr; @@ -143,7 +143,7 @@ namespace CertificateManager { return m_certificatePEM; } - + bool FileDataSource::HasPrivateKey() const { return m_privateKeyPEM != nullptr; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp index 300543c896..d5fa3867e0 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp @@ -50,7 +50,7 @@ namespace EMotionFX // Create EMotion FX allocators Allocators::Create(); - + // create the new object gEMFX = AZ::Environment::CreateVariable(kEMotionFXInstanceVarName); gEMFX.Set(EMotionFXManager::Create()); @@ -166,11 +166,11 @@ namespace EMotionFX delete m_debugDraw; m_debugDraw = nullptr; - + m_eventManager->Destroy(); m_eventManager = nullptr; - + // delete the thread datas for (uint32 i = 0; i < m_threadDatas.size(); ++i) { @@ -341,7 +341,7 @@ namespace EMotionFX void EMotionFXManager::InitAssetFolderPaths() { // Initialize the asset source folder path. - const char* assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + const char* assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); if (assetSourcePath) { m_assetSourceFolder = assetSourcePath; @@ -361,12 +361,12 @@ namespace EMotionFX } else { - AZ_Warning("EMotionFX", false, "Failed to set asset source path for alias '@devassets@'."); + AZ_Warning("EMotionFX", false, "Failed to set asset source path for alias '@projectroot@'."); } // Initialize the asset cache folder path. - const char* assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + const char* assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); if (assetCachePath) { m_assetCacheFolder = assetCachePath; @@ -386,7 +386,7 @@ namespace EMotionFX } else { - AZ_Warning("EMotionFX", false, "Failed to set asset cache path for alias '@assets@'."); + AZ_Warning("EMotionFX", false, "Failed to set asset cache path for alias '@products@'."); } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp index 129d005f80..2d65a228b7 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp @@ -72,13 +72,13 @@ namespace EMStudio { AZStd::string filename; - AZStd::string assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + AZStd::string assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::AssetDatabasePath::Normalize(assetCachePath); AZStd::string relativePath; EBUS_EVENT_RESULT(relativePath, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, assetId); AzFramework::StringFunc::AssetDatabasePath::Join(assetCachePath.c_str(), relativePath.c_str(), filename); - + return filename; } @@ -243,7 +243,7 @@ namespace EMStudio void FileManager::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, [[maybe_unused]] AZ::TypeId sourceTypeId) { AZStd::string filename; - AZStd::string assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + AZStd::string assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); AzFramework::StringFunc::AssetDatabasePath::Normalize(assetSourcePath); AzFramework::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), relativePath.c_str(), filename); @@ -373,7 +373,7 @@ namespace EMStudio const ProductAssetBrowserEntry* product = azrtti_cast(assetBrowserEntry); filename.clear(); - AZStd::string cachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + AZStd::string cachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath); AzFramework::StringFunc::AssetDatabasePath::Join(cachePath.c_str(), product->GetRelativePath().c_str(), filename); @@ -395,7 +395,7 @@ namespace EMStudio { return AZStd::string(); } - + return filenames[0]; } @@ -435,12 +435,12 @@ namespace EMStudio AZStd::string result; if (EMStudio::GetCommandManager()->ExecuteCommand(command, result)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Actor successfully saved"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Actor failed to save

%s", result.c_str()).c_str()); } } @@ -574,12 +574,12 @@ namespace EMStudio AZStd::string result; if (GetCommandManager()->ExecuteCommand(command, result) == false) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("MotionSet failed to save

%s", result.c_str()).c_str()); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "MotionSet successfully saved"); } } @@ -608,7 +608,7 @@ namespace EMStudio } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - + AZStd::string FileManager::LoadAnimGraphFileDialog([[maybe_unused]] QWidget* parent) { GetManager()->SetAvoidRendering(true); @@ -618,7 +618,7 @@ namespace EMStudio { return AZStd::string(); } - + return filenames[0]; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp index 06088790d9..002634ea90 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -378,7 +378,7 @@ namespace EMStudio // reset action m_resetAction = menu->addAction(tr("&Reset"), this, &MainWindow::OnReset, QKeySequence::New); m_resetAction->setObjectName("EMFX.MainWindow.ResetAction"); - + // save all m_saveAllAction = menu->addAction(tr("Save All..."), this, &MainWindow::OnSaveAll, QKeySequence::Save); m_saveAllAction->setObjectName("EMFX.MainWindow.SaveAllAction"); @@ -467,7 +467,7 @@ namespace EMStudio menu->addAction("Documentation", this, [] { QDesktopServices::openUrl(QUrl("https://o3de.org/docs/")); - }); + }); menu->addAction("Forums", this, [] { @@ -491,7 +491,7 @@ namespace EMStudio // load preferences PluginOptionsNotificationsBus::Router::BusRouterConnect(); - LoadPreferences(); + LoadPreferences(); m_autosaveTimer->setInterval(m_options.GetAutoSaveInterval() * 60 * 1000); // Create the dirty file manager and register the workspace callback. @@ -1072,7 +1072,7 @@ namespace EMStudio // get only the version number of EMotion FX AZStd::string emfxVersionString = EMotionFX::GetEMotionFX().GetVersionString(); AzFramework::StringFunc::Replace(emfxVersionString, "EMotion FX ", "", true /* case sensitive */); - + // set the window title // only set the EMotion FX version if the filename is empty AZStd::string windowTitle; @@ -1359,7 +1359,7 @@ namespace EMStudio void MainWindow::LoadCharacter(const AZ::Data::AssetId& actorAssetId, const AZ::Data::AssetId& animgraphId, const AZ::Data::AssetId& motionSetId) { m_characterFiles.clear(); - AZStd::string cachePath = gEnv->pFileIO->GetAlias("@assets@"); + AZStd::string cachePath = gEnv->pFileIO->GetAlias("@products@"); AZStd::string filename; AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath); @@ -1543,12 +1543,12 @@ namespace EMStudio AZStd::string result; if (EMStudio::GetCommandManager()->ExecuteCommand(command, result)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Workspace successfully saved"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Workspace failed to save

%s", result.c_str()).c_str()); } } @@ -1575,12 +1575,12 @@ namespace EMStudio AZStd::string result; if (EMStudio::GetCommandManager()->ExecuteCommand(command, result)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Workspace successfully saved"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Workspace failed to save

%s", result.c_str()).c_str()); } } @@ -1644,7 +1644,7 @@ namespace EMStudio Workspace* workspace = GetManager()->GetWorkspace(); workspace->SetDirtyFlag(true); - } + } void MainWindow::OnReset() { @@ -2312,7 +2312,7 @@ namespace EMStudio void MainWindow::Activate(const AZ::Data::AssetId& actorAssetId, const EMotionFX::AnimGraph* animGraph, const EMotionFX::MotionSet* motionSet) { - AZStd::string cachePath = gEnv->pFileIO->GetAlias("@assets@"); + AZStd::string cachePath = gEnv->pFileIO->GetAlias("@products@"); AZStd::string filename; AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath); @@ -2776,17 +2776,17 @@ namespace EMStudio AZStd::string result; if (GetCommandManager()->ExecuteCommandGroup(commandGroup, result, false)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Autosave completed"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Autosave failed

%s", result.c_str()).c_str()); } } - + void MainWindow::moveEvent(QMoveEvent* event) { MCORE_UNUSED(event); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp index 4cdf645b16..ea7c92b742 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp @@ -428,7 +428,7 @@ namespace EMStudio continue; } - AzFramework::StringFunc::Replace(commands[i], "@assets@/", assetCacheFolder.c_str(), true /* case sensitive */); + AzFramework::StringFunc::Replace(commands[i], "@products@/", assetCacheFolder.c_str(), true /* case sensitive */); // add the command to the command group commandGroup->AddCommandString(commands[i]); diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp index 3e459d31d6..3593f58ff2 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp @@ -6,6 +6,8 @@ * */ +#include + #include #include #include @@ -66,14 +68,10 @@ namespace EMotionFX // through this method. Once EMotionFX is integrated to the asset system this can go away. AZStd::string assetFilename; EBUS_EVENT_RESULT(assetFilename, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, asset.GetId()); - const char* devAssetsPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); - if (devAssetsPath) + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + if (!projectPath.empty()) { - AZStd::string assetSourcePath = devAssetsPath; - - AzFramework::StringFunc::AssetDatabasePath::Normalize(assetSourcePath); - AZStd::string filename; - AzFramework::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), assetFilename.c_str(), filename); + AZ::IO::FixedMaxPathString filename{ (projectPath / assetFilename).LexicallyNormal().FixedMaxPathStringAsPosix() }; assetData->m_emfxAnimGraph->SetFileName(filename.c_str()); } @@ -81,7 +79,7 @@ namespace EMotionFX { if (GetEMotionFX().GetIsInEditorMode()) { - AZ_Warning("EMotionFX", false, "Failed to retrieve asset source path with alias '@devassets@'. Cannot set absolute filename for '%s'", assetFilename.c_str()); + AZ_Warning("EMotionFX", false, "Failed to retrieve project root path . Cannot set absolute filename for '%s'", assetFilename.c_str()); } assetData->m_emfxAnimGraph->SetFileName(assetFilename.c_str()); } diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp index 5ca9a34e72..280cedd06a 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,7 @@ namespace EMotionFX const char* motionFile = entry->GetFilename(); AZ::Data::AssetId motionAssetId; EBUS_EVENT_RESULT(motionAssetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, motionFile, azrtti_typeid(), false); - + // if it failed to find it, it might be still compiling - try forcing an immediate compile: if (!motionAssetId.IsValid()) { @@ -149,14 +150,11 @@ namespace EMotionFX // through this method. Once EMotionFX is integrated to the asset system this can go away. AZStd::string assetFilename; EBUS_EVENT_RESULT(assetFilename, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, asset.GetId()); - const char* devAssetsPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); - if (devAssetsPath) - { - AZStd::string assetSourcePath = devAssetsPath; - AZ::StringFunc::AssetDatabasePath::Normalize(assetSourcePath); - AZStd::string filename; - AZ::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), assetFilename.c_str(), filename); + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + if (!projectPath.empty()) + { + AZ::IO::FixedMaxPathString filename{ (projectPath / assetFilename).LexicallyNormal().FixedMaxPathStringAsPosix() }; assetData->m_emfxMotionSet->SetFilename(filename.c_str()); } @@ -164,11 +162,11 @@ namespace EMotionFX { if (GetEMotionFX().GetIsInEditorMode()) { - AZ_Warning("EMotionFX", false, "Failed to retrieve asset source path with alias '@devassets@'. Cannot set absolute filename for '%s'", assetFilename.c_str()); + AZ_Warning("EMotionFX", false, "Failed to retrieve project root path . Cannot set absolute filename for '%s'", assetFilename.c_str()); } assetData->m_emfxMotionSet->SetFilename(assetFilename.c_str()); } - + // now load them in: const EMotionFX::MotionSet::MotionEntries& motionEntries = assetData->m_emfxMotionSet->GetMotionEntries(); // Get the motions in the motion set. Escalate them to the top of the build queue first so that they can be done in parallel. @@ -179,7 +177,7 @@ namespace EMotionFX const char* motionFilename = motionEntry->GetFilename(); AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, motionFilename); } - + // now that they're all escalated, the asset processor will be processing them across all threads, and we can request them one by one: for (const auto& item : motionEntries) { diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 0f87c488b9..08e99f97d0 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -487,9 +487,9 @@ namespace EMotionFX return; } - SetMediaRoot("@assets@"); - // \todo Right now we're pointing at the @devassets@ location (source) and working from there, because .actor and .motion (motion) aren't yet processed through - // the scene pipeline. Once they are, we'll need to update various segments of the Tool to always read from the @assets@ cache, but write to the @devassets@ data/metadata. + SetMediaRoot("@products@"); + // \todo Right now we're pointing at the @projectroot@ location (source) and working from there, because .actor and .motion (motion) aren't yet processed through + // the scene pipeline. Once they are, we'll need to update various segments of the Tool to always read from the @products@ cache, but write to the @projectroot@ data/metadata. EMotionFX::GetEMotionFX().InitAssetFolderPaths(); // Register EMotionFX event handler diff --git a/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp b/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp index 25cd840cda..44453ed70f 100644 --- a/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp +++ b/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp @@ -25,11 +25,11 @@ namespace EMotionFX ExecuteCommands({ R"str(CreateMotionSet -name MotionSet0)str", R"str(CreateMotionSet -name MotionSet1)str", - R"str(MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", - R"str(MotionSetAddMotion -motionSetID 1 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", + R"str(MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", + R"str(MotionSetAddMotion -motionSetID 1 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", R"str(MotionSetRemoveMotion -motionSetID 0 -motionIds rin_idle)str", R"str(RemoveMotionSet -motionSetID 0)str", - R"str(RemoveMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion)str", + R"str(RemoveMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion)str", }); EMStudio::MotionSetsWindowPlugin* motionSetsWindowPlugin = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MotionSetsWindowPlugin::CLASS_ID)); diff --git a/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp b/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp index ce0b586bfe..e4e58fa01d 100644 --- a/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp +++ b/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp @@ -33,7 +33,7 @@ namespace EMotionFX ASSERT_TRUE(motionSet) << "Motion set with id 0 does not exist"; motionSetsWindowPlugin->SetSelectedSet(motionSet); - const std::string filename = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"; + const std::string filename = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"; ExecuteCommands({ "ImportMotion -filename " + filename, "MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds " + filename + ";rin_idle", diff --git a/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp b/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp index 0155b38da2..7b9f23f094 100644 --- a/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp +++ b/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp @@ -55,7 +55,7 @@ namespace EMotionFX // By using this mock catalog, we can pretend to load the specific referenced assets without actually loading anything. UnitTest::MockLoadAssetCatalogAndHandler testAssetCatalog({ referencedAnimGraph, referencedMotionSet }); - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExample.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExample.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -68,7 +68,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_NoDependency_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExampleNoDependency.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExampleNoDependency.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -78,7 +78,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_InvalidFilePath_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -88,7 +88,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_EmptyFile_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyAnimGraphExample.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyAnimGraphExample.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -100,7 +100,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_HasReferenceNode_OutputProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; @@ -112,7 +112,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_NoDependency_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExampleNoDependency.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExampleNoDependency.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; @@ -122,7 +122,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_InvalidFilePath_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; @@ -132,7 +132,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_EmptyFile_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyMotionSetExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyMotionSetExample.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; diff --git a/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp b/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp index b1650ce0c6..905c4a825b 100644 --- a/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp +++ b/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp @@ -124,7 +124,7 @@ namespace EMotionFX { using testing::_; - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; MockAssetSystemRequests assetSystem; EXPECT_CALL(assetSystem, CompileAssetSync(_)) diff --git a/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp b/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp index ff7ead3800..36abf2b1d2 100644 --- a/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp +++ b/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp @@ -302,7 +302,7 @@ namespace EMotionFX GetEMotionFX().SetMediaRootFolder(assetFolder.c_str()); GetEMotionFX().InitAssetFolderPaths(); - const char* actorFilename = "@assets@\\animationsamples\\advanced_rinlocomotion\\actor\\rinactor.actor"; + const char* actorFilename = "@products@\\animationsamples\\advanced_rinlocomotion\\actor\\rinactor.actor"; Importer* importer = GetEMotionFX().GetImporter(); importer->SetLoggingEnabled(false); @@ -402,9 +402,9 @@ namespace EMotionFX // This path points to assets in the advance rin demo. // To test different assets, change the path here. - const char* actorFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; - const char* motionSetFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; - const char* animGraphFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; + const char* actorFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; + const char* motionSetFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; + const char* animGraphFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; Importer* importer = GetEMotionFX().GetImporter(); importer->SetLoggingEnabled(false); @@ -714,9 +714,9 @@ namespace EMotionFX // This path points to assets in the advance rin demo. // To test different assets, change the path here. - const char* actorFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; - const char* motionSetFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; - const char* animGraphFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; + const char* actorFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; + const char* motionSetFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; + const char* animGraphFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; Importer* importer = GetEMotionFX().GetImporter(); importer->SetLoggingEnabled(false); @@ -772,13 +772,13 @@ namespace EMotionFX TEST_F(PerformanceTestFixture, DISABLED_MotionSamplingPerformanceNonUniform) { // Make sure that the motion is set to use NonUniform sampling! Change this in the scene settings! Otherwise you get wrong results. - TestMotionSamplingPerformance("@assets@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_idle.motion"); + TestMotionSamplingPerformance("@products@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_idle.motion"); } TEST_F(PerformanceTestFixture, DISABLED_MotionSamplingPerformanceUniform) { // Make sure that the motion is set to use Uniform sampling! Change this in the scene settings! Otherwise you get wrong results. - TestMotionSamplingPerformance("@assets@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_walk_kick_01.motion"); + TestMotionSamplingPerformance("@products@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_walk_kick_01.motion"); } } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp index 9b18ca5862..31e1f75d29 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp @@ -33,7 +33,7 @@ namespace EMotionFX ASSERT_EQ(GetActorManager().GetNumActors(), 0); // Load an Actor - const char* actorCmd{ "ImportActor -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" }; + const char* actorCmd{ "ImportActor -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" }; { AZStd::string result; EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(actorCmd, result)) << result.c_str(); diff --git a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp index cccf744cfc..27692a90ff 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp @@ -297,16 +297,16 @@ namespace EMotionFX INSTANTIATE_TEST_CASE_P(Integ_TestPoses, INTEG_PoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ), PoseComparisonFixtureParams ( - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" ) ) ); @@ -314,10 +314,10 @@ namespace EMotionFX INSTANTIATE_TEST_CASE_P(Integ_TestPoseComparison, INTEG_TestPoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ) ) ); diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp index 287c34723f..16b223914e 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp @@ -30,12 +30,12 @@ namespace EMotionFX motionSetsWindowPlugin->SetSelectedSet(motionSet); ExecuteCommands({ - "ImportMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", - "MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle" + "ImportMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", + "MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle" }); char resolvedPath[AZ::IO::MaxPathLength]; - EXPECT_TRUE(AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", resolvedPath, AZ_ARRAY_SIZE(resolvedPath))); + EXPECT_TRUE(AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", resolvedPath, AZ_ARRAY_SIZE(resolvedPath))); m_motionFileName = resolvedPath; AzFramework::ApplicationRequests::Bus::Broadcast([](AzFramework::ApplicationRequests* requests, AZStd::string& path) { requests->NormalizePathKeepCase(path); }, m_motionFileName); m_motionName = "rin_idle"; diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp index 1f9a78a413..d53ddcc924 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp @@ -44,7 +44,7 @@ namespace EMotionFX RecordProperty("test_case_id", "C16302179"); - const AZStd::string motionAsset("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); + const AZStd::string motionAsset("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); const AZStd::string createAnimGraphCmd("CreateAnimGraph"); const AZStd::string motionSetName("TestMotionSet"); const AZStd::string createMotionSetCmd("CreateMotionSet -motionSetID 42 -name " + motionSetName); diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp index 82bfeba557..bb8368b17e 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp @@ -36,7 +36,7 @@ namespace EMotionFX RecordProperty("test_case_id", "C1559124"); const QString assetName = "rin_idle"; // Asset name to appear in table - const AZStd::string motionCmd = AZStd::string::format("ImportMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); + const AZStd::string motionCmd = AZStd::string::format("ImportMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); auto motionWindowPlugin = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MotionWindowPlugin::CLASS_ID)); ASSERT_TRUE(motionWindowPlugin) << "Could not find the Motion Window Plugin"; diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp index 6804d351cf..14d27ed60f 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp @@ -38,7 +38,7 @@ namespace EMotionFX EXPECT_EQ(table->rowCount(), 1) << "Expected the table to have no rows yet"; // Create actor and actor instance. - const char* actorFilename = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor"; + const char* actorFilename = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor"; AZStd::unique_ptr m_actor = EMotionFX::GetImporter().LoadActor(actorFilename); EXPECT_TRUE(m_actor.get() != nullptr) << "Actor not loaded."; EMotionFX::ActorInstance* m_actorInstance = ActorInstance::Create(m_actor.get()); diff --git a/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp b/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp index 4eb44a54ab..bdbc50fe9c 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp @@ -26,7 +26,7 @@ namespace EMotionFX EMStudio::GetMainWindow()->ApplicationModeChanged("AnimGraph"); // Load Rin anim graph. - const char* rinGraph = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph"; + const char* rinGraph = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph"; const AZStd::string rinGraphPath = ResolvePath(rinGraph); AZStd::string command = AZStd::string::format("LoadAnimGraph -filename \"%s\"", rinGraphPath.c_str()); AZStd::string result; diff --git a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp index b24971bfde..73a0f1c865 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp @@ -551,7 +551,7 @@ namespace EMotionFX QString GetTestMotionFileName() const { - AZStd::string resolvedAssetPath = this->ResolvePath("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); + AZStd::string resolvedAssetPath = this->ResolvePath("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); return QString::fromUtf8(resolvedAssetPath.data(), aznumeric_cast(resolvedAssetPath.size())); } diff --git a/Gems/EditorPythonBindings/Assets/release_notes.md b/Gems/EditorPythonBindings/Assets/release_notes.md index 4a4b5bc71f..59192e1fdc 100644 --- a/Gems/EditorPythonBindings/Assets/release_notes.md +++ b/Gems/EditorPythonBindings/Assets/release_notes.md @@ -59,7 +59,7 @@ The API: - ExecuteByString(string) – runs a string buffer in the Python VM; it returns no value - ExecuteByFilename(string) – loads a file off of the disk to execute in the Python VM; the call returns no value. The filename can contain an alias such as - ‘\@devroot\@’ to execute a project relative file inside the Editor + ‘\@projectroot\@’ to execute a project relative file inside the Editor #### New Console Commands diff --git a/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp index 4ca40a5bab..81476bdd7f 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp @@ -38,7 +38,7 @@ namespace EditorPythonBindings static constexpr const char* s_default = "default"; static constexpr const char* s_globals = "globals"; - // a structure for pybind11 to bind to hold constants, properties, and enums from the Behavior Context + // a structure for pybind11 to bind to hold constants, properties, and enums from the Behavior Context struct StaticPropertyHolder final { AZ_CLASS_ALLOCATOR(StaticPropertyHolder, AZ::SystemAllocator, 0); @@ -54,7 +54,7 @@ namespace EditorPythonBindings if (m_behaviorContext == nullptr) { return false; - } + } m_fullName = PyModule_GetName(scope.ptr()); @@ -199,12 +199,10 @@ namespace EditorPythonBindings } }); - RegisterAliasIfExists(pathsModule, "@devroot@", "devroot"); RegisterAliasIfExists(pathsModule, "@engroot@", "engroot"); - RegisterAliasIfExists(pathsModule, "@assets@", "assets"); - RegisterAliasIfExists(pathsModule, "@devassets@", "devassets"); + RegisterAliasIfExists(pathsModule, "@products@", "products"); + RegisterAliasIfExists(pathsModule, "@projectroot@", "projectroot"); RegisterAliasIfExists(pathsModule, "@log@", "log"); - RegisterAliasIfExists(pathsModule, "@root@", "root"); const char* executableFolder = nullptr; AZ::ComponentApplicationBus::BroadcastResult(executableFolder, &AZ::ComponentApplicationBus::Events::GetExecutableFolder); @@ -363,7 +361,7 @@ namespace EditorPythonBindings m_staticPropertyHolderMap.reset(); EditorPythonBindings::EditorPythonBindingsNotificationBus::Handler::BusDisconnect(); } - + void PythonReflectionComponent::OnImportModule(PyObject* module) { pybind11::module parentModule = pybind11::cast(module); diff --git a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp index cecbf15c5a..876ef19803 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp @@ -524,7 +524,7 @@ namespace EditorPythonBindings { AZ::IO::Path newSourcePath = jsonSourcePathPointer; // Resolve any file aliases first - Do not use ResolvePath() as that assumes - // any relative path is underneath the @assets@ alias + // any relative path is underneath the @products@ alias if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { AZ::IO::FixedMaxPath replacedAliasPath; @@ -803,7 +803,7 @@ namespace EditorPythonBindings return Result::Error_InvalidFilename; } - // support the alias version of a script such as @devroot@/Editor/Scripts/select_story_anim_objects.py + // support the alias version of a script such as @engroot@/Editor/Scripts/select_story_anim_objects.py AZStd::string theFilename(filename); { char resolvedPath[AZ_MAX_PATH_LEN] = { 0 }; diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp b/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp index 12d7d696d3..5aa4921287 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp +++ b/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp @@ -268,7 +268,7 @@ print ('entityId invalid is ' + str(entityId.id)) { Skip = 0, ImportModule, - TestCallHit, + TestCallHit, TestTypeDoCall1 }; @@ -302,7 +302,7 @@ print ('entityId invalid is ' + str(entityId.id)) pybind11::exec(R"( import sys, os import azlmbr.paths - sys.path.append(os.path.join(azlmbr.paths.devroot,'Gems','EditorPythonBindings','Code','Tests')) + sys.path.append(os.path.join(azlmbr.paths.engroot,'Gems','EditorPythonBindings','Code','Tests')) from test_package import import_test as itest print('ImportModule') itest.test_call() @@ -401,8 +401,8 @@ print ('entityId invalid is ' + str(entityId.id)) pybind11::exec(R"( import sys, os import azlmbr.paths - sys.path.append(os.path.join(azlmbr.paths.devroot,'Gems','EditorPythonBindings','Code','Tests')) - sys.path.append(os.path.join(azlmbr.paths.devroot,'Gems','EditorPythonBindings','Code','Tests','test_package')) + sys.path.append(os.path.join(azlmbr.paths.engroot,'Gems','EditorPythonBindings','Code','Tests')) + sys.path.append(os.path.join(azlmbr.paths.engroot,'Gems','EditorPythonBindings','Code','Tests','test_package')) from test_package import import_many import_many.test_many_entity_id() diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp b/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp index f68bef1c93..96619997bc 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp +++ b/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp @@ -161,7 +161,7 @@ namespace UnitTest ->Method("accept_vector_of_floats", &PythonReflectionContainerSimpleTypes::AcceptVectorOfFloats, nullptr, "") ->Method("return_vector_of_doubles", &PythonReflectionContainerSimpleTypes::ReturnVectorOfDoubles, nullptr, "") ->Method("accept_vector_of_doubles", &PythonReflectionContainerSimpleTypes::AcceptVectorOfDoubles, nullptr, "") - ->Property("vector_of_s8", + ->Property("vector_of_s8", [](PythonReflectionContainerSimpleTypes* self) { return self->m_s8ValueValues.ReturnValues(); }, [](PythonReflectionContainerSimpleTypes* self, const AZStd::vector& values) { return self->m_s8ValueValues.AcceptValues(values); }) ->Property("vector_of_u8", @@ -792,7 +792,7 @@ namespace UnitTest theAsset = reflectAny.access_any_ref() if( reflectAny.compare_asset_ids(theAsset,testObject.theAsset) ): print ('MutateAssetId') - + )"); } catch ([[maybe_unused]] const std::exception& e) @@ -1429,7 +1429,6 @@ namespace UnitTest { Skip = 0, EngrootIs, - DevrootIs, pathResolvedTo, }; @@ -1442,10 +1441,6 @@ namespace UnitTest { return static_cast(LogTypes::EngrootIs); } - else if (AzFramework::StringFunc::StartsWith(message, "devroot is ")) - { - return static_cast(LogTypes::DevrootIs); - } else if (AzFramework::StringFunc::StartsWith(message, "path resolved to ")) { return static_cast(LogTypes::pathResolvedTo); @@ -1470,9 +1465,6 @@ namespace UnitTest if (len(azlmbr.paths.engroot) != 0): print ('engroot is {}'.format(azlmbr.paths.engroot)) - if (len(azlmbr.paths.devroot) != 0): - print ('devroot is {}'.format(azlmbr.paths.devroot)) - path = azlmbr.paths.resolve_path('@engroot@/engineassets/texturemsg/defaultsolids.mtl') if (path.find('@engroot@') == -1): print ('path resolved to {}'.format(path)) @@ -1487,7 +1479,6 @@ namespace UnitTest e.Deactivate(); EXPECT_EQ(m_testSink.m_evaluationMap[(int)LogTypes::EngrootIs], 1); - EXPECT_EQ(m_testSink.m_evaluationMap[(int)LogTypes::DevrootIs], 1); EXPECT_EQ(m_testSink.m_evaluationMap[(int)LogTypes::pathResolvedTo], 1); } } diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h index a0109f8029..143863b4c8 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h +++ b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h @@ -81,7 +81,6 @@ namespace UnitTest } m_fileIOHelper = AZStd::make_unique(); - m_fileIOHelper->m_fileIO.SetAlias("@devroot@", m_engineRoot.c_str()); m_fileIOHelper->m_fileIO.SetAlias("@engroot@", m_engineRoot.c_str()); AzFramework::Application::Descriptor appDesc; diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl index 38747553a9..7dbe516aa5 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl @@ -27,7 +27,7 @@ namespace GameStateSamples IConsole* iConsole = iSystem ? iSystem->GetIConsole() : nullptr; if (iConsole) { - iConsole->GetCVar("level_load_screen_uicanvas_path")->Set("@assets@/ui/canvases/defaultlevelloadingscreen.uicanvas"); + iConsole->GetCVar("level_load_screen_uicanvas_path")->Set("@products@/ui/canvases/defaultlevelloadingscreen.uicanvas"); iConsole->GetCVar("level_load_screen_sequence_to_auto_play")->Set("DefaultLevelLoadingAnimatedSequence"); } } diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl index 63fea35224..4227e45fe9 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl @@ -182,7 +182,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateLevelPaused::GetPauseMenuCanvasAssetPath() { - return "@assets@/ui/canvases/defaultpausemenuscreen.uicanvas"; + return "@products@/ui/canvases/defaultpausemenuscreen.uicanvas"; } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl index f9ec19581c..a4af32feb8 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl @@ -206,6 +206,6 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateLevelRunning::GetPauseButtonCanvasAssetPath() { - return "@assets@/ui/canvases/defaultpausebuttonfortouchscreens.uicanvas"; + return "@products@/ui/canvases/defaultpausebuttonfortouchscreens.uicanvas"; } } diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl index dc658611b5..4a4fbac93a 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl @@ -223,7 +223,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateLocalUserLobby::GetSignedInUserOverlayCanvasAssetPath() { - return "@assets@/ui/canvases/defaultsignedinusersoverlay.uicanvas"; + return "@products@/ui/canvases/defaultsignedinusersoverlay.uicanvas"; } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -282,7 +282,7 @@ namespace GameStateSamples } // ...sort them by index and then go through to check whether they have been - // assigned a local user id. If so, auto-assign their local user id into the + // assigned a local user id. If so, auto-assign their local user id into the // first available local player slot (unless they've already been assigned). AZStd::sort(gamepadInputDevices.begin(), gamepadInputDevices.end(), [](const AzFramework::InputDevice* lhs, const AzFramework::InputDevice* rhs) diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl index 41ee034844..98147756f4 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl @@ -257,7 +257,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateMainMenu::GetMainMenuCanvasAssetPath() { - return "@assets@/ui/canvases/defaultmainmenuscreen.uicanvas"; + return "@products@/ui/canvases/defaultmainmenuscreen.uicanvas"; } diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl index 64269d223f..4389f5f0b7 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl @@ -215,7 +215,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateOptionsMenu::GetOptionsMenuCanvasAssetPath() { - return "@assets@/ui/canvases/defaultoptionsmenuscreen.uicanvas"; + return "@products@/ui/canvases/defaultoptionsmenuscreen.uicanvas"; } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl index bf50913ef9..42ad2290e1 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl @@ -168,6 +168,6 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStatePrimaryUserSelection::GetPrimaryUserSelectionCanvasAssetPath() { - return "@assets@/ui/canvases/defaultprimaryuserselectionscreen.uicanvas"; + return "@products@/ui/canvases/defaultprimaryuserselectionscreen.uicanvas"; } } diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp index 56f6e84332..0b4691ecf5 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp @@ -74,10 +74,10 @@ namespace m_paletteSwatches.push_back(QColor(0, 0, 0)); m_sourcePixmap = new QPixmap(16, 16); m_sourcePixmap->fill(Qt::transparent); - + QPainter painter(m_sourcePixmap); painter.setRenderHint(QPainter::RenderHint::Antialiasing); - + QPen pen; pen.setWidth(4); pen.setColor(QColor(0, 0, 0)); @@ -257,7 +257,7 @@ namespace GraphCanvas QBitmap mask = m_sourcePixmap->createMaskFromColor(m_paletteSwatches[i], Qt::MaskOutColor); painter.setClipRegion(QRegion(mask)); - QtDrawingUtils::FillArea(painter, drawRect, (*palettes[i%palettes.size()])); + QtDrawingUtils::FillArea(painter, drawRect, (*palettes[i%palettes.size()])); } return pixmap; @@ -317,7 +317,7 @@ namespace GraphCanvas void StyleManager::LoadStyleSheet() { - AZStd::string file = AZStd::string::format("@assets@/%s", m_assetPath.c_str()); + AZStd::string file = AZStd::string::format("@products@/%s", m_assetPath.c_str()); AZ::IO::FileIOBase* fileBase = AZ::IO::FileIOBase::GetInstance(); @@ -448,7 +448,7 @@ namespace GraphCanvas auto mapIter = m_dataPaletteMapping.find(dataType); if (mapIter == m_dataPaletteMapping.end()) - { + { return "ObjectDataColorPalette"; } else @@ -852,7 +852,7 @@ namespace GraphCanvas return icon; } - + void StyleManager::ClearStyles() { StyleManagerNotificationBus::Event(m_editorId, &StyleManagerNotifications::OnStylesUnloaded); diff --git a/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp b/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp index bd13e91dc6..d0d7160a73 100644 --- a/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp +++ b/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp @@ -58,7 +58,7 @@ namespace InAppPurchases } PurchasedProductDetailsAndroid* purchasedProductDetails = new PurchasedProductDetailsAndroid(); - + purchasedProductDetails->SetProductId(AZ::Android::JNI::ConvertJstringToString(static_cast(env->GetObjectField(jpurchasedProduct, fid[0])))); purchasedProductDetails->SetOrderId(AZ::Android::JNI::ConvertJstringToString(static_cast(env->GetObjectField(jpurchasedProduct, fid[1])))); purchasedProductDetails->SetPackageName(AZ::Android::JNI::ConvertJstringToString(static_cast(env->GetObjectField(jpurchasedProduct, fid[2])))); @@ -75,7 +75,7 @@ namespace InAppPurchases int numProducts = env->GetArrayLength(jproductDetails); InAppPurchasesInterface::GetInstance()->GetCache()->ClearCachedProductDetails(); - + const int NUM_FIELDS_PRODUCTS = 7; jfieldID fid[NUM_FIELDS_PRODUCTS]; jclass cls; @@ -224,7 +224,7 @@ namespace InAppPurchases AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; AZ::u64 fileSize = 0; - if (!fileReader->Open("@assets@/product_ids.json", AZ::IO::OpenMode::ModeRead, fileHandle)) + if (!fileReader->Open("@products@/product_ids.json", AZ::IO::OpenMode::ModeRead, fileHandle)) { AZ_TracePrintf("LumberyardInAppBilling", "Unable to open file product_ids.json\n"); return; @@ -319,10 +319,10 @@ namespace InAppPurchases env->DeleteLocalRef(billingClass); } - + void InAppPurchasesAndroid::RestorePurchasedProducts() const { - + } void InAppPurchasesAndroid::ConsumePurchase(const AZStd::string& purchaseToken) const diff --git a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp index 82c07f9f73..3dd7d5501e 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp @@ -63,13 +63,13 @@ namespace CopyDependencyBuilder charBuffer.back() = 0; /* File Contents of EMFX Workspace file looks like - startScript="ImportActor -filename \"@assets@/animationsamples/advanced_rinlocomotion/actor/rinactor.actor\"\nCreateActorInstance + startScript="ImportActor -filename \"@products@/animationsamples/advanced_rinlocomotion/actor/rinactor.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.020660 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000, - 0.00000000,0.00000000,0.99997193\n LoadMotionSet -filename \"@assets@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.motionset\" - \nLoadAnimGraph -filename \"@assets@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.animgraph\" + 0.00000000,0.00000000,0.99997193\n LoadMotionSet -filename \"@products@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.motionset\" + \nLoadAnimGraph -filename \"@products@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.animgraph\" \nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" */ - AZStd::regex pathRegex(R"(\s+-filename\s+\\\"(?:@assets@\/)?(\S+)\\\")"); + AZStd::regex pathRegex(R"(\s+-filename\s+\\\"(?:@products@\/)?(\S+)\\\")"); AZStd::smatch matches; AZStd::string::const_iterator searchStart = charBuffer.begin(); while (AZStd::regex_search(searchStart, matches, pathRegex)) diff --git a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp index 631bc41358..00e9eaf0fe 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp @@ -30,7 +30,7 @@ namespace LevelBuilder { const char s_materialExtension[] = ".mtl"; - const char s_audioControlFilesLevelPath[] = "@devassets@/libs/gameaudio/wwise/levels/%s"; + const char s_audioControlFilesLevelPath[] = "@projectroot@/libs/gameaudio/wwise/levels/%s"; const char s_audioControlFilter[] = "*.xml"; AZ::u64 readXmlDataLength(AZ::IO::GenericStream* stream, int& charSize) diff --git a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp index c06b21337b..48973b2779 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp @@ -28,7 +28,7 @@ namespace MaterialBuilder const char g_nodeNameTexture[] = "Texture"; const char g_nodeNameTextures[] = "Textures"; const char g_attributeFileName[] = "File"; - + const int g_numSourceImageFormats = 9; const char* g_sourceImageFormats[g_numSourceImageFormats] = { ".tif", ".tiff", ".bmp", ".gif", ".jpg", ".jpeg", ".tga", ".png", ".dds" }; bool IsSupportedImageExtension(const AZStd::string& extension) @@ -66,7 +66,7 @@ namespace MaterialBuilder return actualFileName; } - // Parses the material XML for all texture paths + // Parses the material XML for all texture paths AZ::Outcome GetTexturePathsFromMaterial(AZ::rapidxml::xml_node* materialNode, AZStd::vector& paths) { AZ::Outcome resultOutcome = AZ::Failure(AZStd::string("")); @@ -94,7 +94,7 @@ namespace MaterialBuilder // do an initial clean-up of the path taken from the file, similar to MaterialHelpers::SetTexturesFromXml AZStd::string texturePath = CleanLegacyPathingFromTexturePath(rawTexturePath); paths.emplace_back(AZStd::move(texturePath)); - } + } textureNode = textureNode->next_sibling(g_nodeNameTexture); } while (textureNode); @@ -112,7 +112,7 @@ namespace MaterialBuilder return AZ::Failure(AZStd::string("SubMaterials node exists but does not have any child Material nodes.")); } - do + do { // grab the texture paths from the submaterial, or error out if necessary AZ::Outcome subMaterialTexturePathsResult = GetTexturePathsFromMaterial(subMaterialNode, paths); @@ -142,7 +142,7 @@ namespace MaterialBuilder } // find a sequence of digits with a string starting from lastDigitIndex, and try to parse that sequence to and int - // and store it in outAnimIndex. + // and store it in outAnimIndex. bool ParseFilePathForCompleteNumber(const AZStd::string& filePath, int& lastDigitIndex, int& outAnimIndex) { int firstAnimIndexDigit = lastDigitIndex; @@ -162,7 +162,7 @@ namespace MaterialBuilder AZ::Outcome GetAllTexturesInTextureSequence(const AZStd::string& path, AZStd::vector& texturesInSequence) { // Taken from CShaderMan::mfReadTexSequence - // All comments next to variable declarations in this function are the original variable names in + // All comments next to variable declarations in this function are the original variable names in // CShaderMan::mfReadTexSequence, to help keep track of how these variables relate to the original function AZStd::string prefix; AZStd::string postfix; @@ -172,7 +172,7 @@ namespace MaterialBuilder AzFramework::StringFunc::Path::GetExtension(filePath.c_str(), extension); AzFramework::StringFunc::Path::StripExtension(filePath); - // unsure if it is actually possible to enter here or the original version with '$' as the indicator + // unsure if it is actually possible to enter here or the original version with '$' as the indicator // for texture sequences, but they check for both just in case, so this will match the behavior. char separator = '#'; // chSep int firstSeparatorIndex = static_cast(filePath.find(separator)); @@ -186,7 +186,7 @@ namespace MaterialBuilder separator = '$'; } - // we don't actually care about getting the speed of the animation, so just remove everything from the + // we don't actually care about getting the speed of the animation, so just remove everything from the // end of the string starting with the last open parenthesis size_t speedStartIndex = filePath.find_last_of('('); if (speedStartIndex != AZStd::string::npos) @@ -195,7 +195,7 @@ namespace MaterialBuilder AzFramework::StringFunc::Append(filePath, '\0'); } - // try to find where the digits start after the separator (there can be any number of separators + // try to find where the digits start after the separator (there can be any number of separators // between the texture name prefix and where the digit range starts) int firstAnimIndexDigit = -1; // m int numSeparators = 0; // j @@ -219,7 +219,7 @@ namespace MaterialBuilder { return AZ::Failure(AZStd::string("Failed to find separator '#' or '$' in texture path.")); } - + // store off everything before the separator prefix = AZStd::move(filePath.substr(0, firstSeparatorIndex)); @@ -242,7 +242,7 @@ namespace MaterialBuilder // reset to the start of the next index ++lastDigitIndex; - + // find the length of the end index, then parse that to an int if (!ParseFilePathForCompleteNumber(filePath, lastDigitIndex, endAnimIndex)) { @@ -262,8 +262,8 @@ namespace MaterialBuilder return AZ::Success(); } - - // Determine which product path to use based on the path stored in the texture, and make it relative to + + // Determine which product path to use based on the path stored in the texture, and make it relative to // the cache. bool ResolveMaterialTexturePath(const AZStd::string& path, AZStd::string& outPath) { @@ -272,7 +272,7 @@ namespace MaterialBuilder //if its a source image format try to load the dds AZStd::string extension; bool hasExtension = AzFramework::StringFunc::Path::GetExtension(path.c_str(), extension); - + // Replace all supported extensions with DDS if it has an extension. If the extension exists but is not supported, fail out. if (hasExtension && IsSupportedImageExtension(extension)) { @@ -286,17 +286,17 @@ namespace MaterialBuilder AZStd::to_lower(aliasedPath.begin(), aliasedPath.end()); AzFramework::StringFunc::Path::Normalize(aliasedPath); - + AZStd::string currentFolderSpecifier = AZStd::string::format(".%c", AZ_CORRECT_FILESYSTEM_SEPARATOR); if (AzFramework::StringFunc::StartsWith(aliasedPath, currentFolderSpecifier)) { AzFramework::StringFunc::Strip(aliasedPath, currentFolderSpecifier.c_str(), false, true); } - + AZStd::string resolvedPath; char fullPathBuffer[AZ_MAX_PATH_LEN] = {}; - // if there is an alias already at the front of the path, resolve it, and try to make it relative to the - // cache (@assets@). If it can't, then error out. + // if there is an alias already at the front of the path, resolve it, and try to make it relative to the + // cache (@products@). If it can't, then error out. // This case handles the possibility of aliases existing in texture paths in materials that is still supported // by the legacy loading code, however it is not currently used, so the else path is always taken. if (aliasedPath[0] == '@') @@ -308,7 +308,7 @@ namespace MaterialBuilder } resolvedPath = fullPathBuffer; AzFramework::StringFunc::Path::Normalize(resolvedPath); - if (!AzFramework::StringFunc::Replace(resolvedPath, AZ::IO::FileIOBase::GetDirectInstance()->GetAlias("@assets@"), "")) + if (!AzFramework::StringFunc::Replace(resolvedPath, AZ::IO::FileIOBase::GetDirectInstance()->GetAlias("@products@"), "")) { AZ_Warning(s_materialBuilder, false, "Failed to resolve aliased texture path %s to be relative to the asset cache. Please make sure this alias resolves to a path within the asset cache.", aliasedPath.c_str()); return false; @@ -318,7 +318,7 @@ namespace MaterialBuilder { resolvedPath = AZStd::move(aliasedPath); } - + // AP deferred path resolution requires UNIX separators and no leading separators, so clean up and convert here if (AzFramework::StringFunc::StartsWith(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING)) { @@ -357,7 +357,7 @@ namespace MaterialBuilder // (optimization) this builder does not emit source dependencies: builderDescriptor.m_flags |= AssetBuilderSDK::AssetBuilderDesc::BF_EmitsNoDependencies; - + m_materialBuilder.BusConnect(builderDescriptor.m_busId); EBUS_EVENT(AssetBuilderSDK::AssetBuilderBus, RegisterBuilderInformation, builderDescriptor); @@ -548,10 +548,10 @@ namespace MaterialBuilder } } - // for each texture in the file + // for each texture in the file for (const AZStd::string& texPath : texturePaths) { - // if the texture path starts with a '$' then it is a special runtime defined texture, so it it doesn't have + // if the texture path starts with a '$' then it is a special runtime defined texture, so it it doesn't have // an actual asset on disk to depend on. If the texture path doesn't have an extension, then it is a texture // that is determined at runtime (such as 'nearest_cubemap'), so also ignore those, as other things pull in // those dependencies. @@ -567,7 +567,7 @@ namespace MaterialBuilder AZ_Warning(s_materialBuilder, false, "Failed to resolve texture path %s to a product path when gathering dependencies for %s. Registering dependencies on this texture path will be skipped.", texPath.c_str(), path.c_str()); continue; } - + resolvedPaths.emplace_back(AZStd::move(resolvedPath)); } diff --git a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp index 20386e0628..c9fc656488 100644 --- a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp @@ -22,7 +22,7 @@ namespace LmbrCentral { - const char bundleRoot[] = "@assets@"; + const char bundleRoot[] = "@products@"; void BundlingSystemComponent::Activate() { @@ -178,7 +178,7 @@ namespace LmbrCentral // Not already opened, new entry m_openedBundles[bundleName] = AZStd::make_unique(); - AZStd::shared_ptr nextCatalog; // Not all bundles will have catalogs - some are legacy. + AZStd::shared_ptr nextCatalog; // Not all bundles will have catalogs - some are legacy. if (nextBundle == nullptr) { // Added to the end diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index 31cf68e9a0..a5884ccce9 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -484,7 +484,7 @@ namespace LmbrCentral } // load the catalog from disk (supported over VFS). - EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, LoadCatalog, AZStd::string::format("@assets@/%s", s_assetCatalogFilename).c_str()); + EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, LoadCatalog, AZStd::string::format("@products@/%s", s_assetCatalogFilename).c_str()); } void LmbrCentralSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) diff --git a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp index 65847a7fef..8b697f35f2 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp @@ -69,7 +69,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); SerializeContext* serializeContext; ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationRequests::GetSerializeContext); @@ -114,7 +114,7 @@ namespace UnitTest { AssetBuilderSDK::ProductPathDependencySet resolvedPaths; AZStd::vector productDependencies; - + AssetBuilderSDK::ProcessJobRequest request; request.m_fullPath = GetFullPath(fileName); request.m_sourceFile = fileName; @@ -211,8 +211,6 @@ namespace UnitTest ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::AssetSystem::AssetSystemRequestBus::Handler overrides - const char* GetAbsoluteDevGameFolderPath() override { return ""; } - const char* GetAbsoluteDevRootFolderPath() override { return ""; } bool GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) override { return true; } bool GenerateRelativeSourcePath( [[maybe_unused]] const AZStd::string& sourcePath, [[maybe_unused]] AZStd::string& relativePath, @@ -428,7 +426,7 @@ namespace UnitTest "Fonts/fontexample-bolditalic.font" }; - AZStd::string fileName = "Fonts/FontFamilyExample.fontfamily"; + AZStd::string fileName = "Fonts/FontFamilyExample.fontfamily"; FontBuilderWorker builderWorker; @@ -445,7 +443,7 @@ namespace UnitTest AZStd::string fileName = "Fonts/FontExample.font"; FontBuilderWorker builderWorker; - + TestSuccessCase(&builderWorker, fileName, "Fonts/FontExample.ttf"); } @@ -667,7 +665,7 @@ namespace UnitTest builderWorker.AddSchemaFileDirectory(GetFullPath("Xmls/Schema/WithoutVersionConstraints/OptionalAttribute")); AZStd::vector expectedProductDependencies; - + TestSuccessCase(&builderWorker, fileName, expectedPaths, expectedProductDependencies); } @@ -896,7 +894,7 @@ namespace UnitTest AssetBuilderSDK::CreateJobsResponse response; request.m_sourceFile = "Tests/Xmls/XmlExampleWithoutVersion.xml"; - request.m_watchFolder = "@root@/../Gems/LmbrCentral/Code/"; + request.m_watchFolder = "@engroot@/Gems/LmbrCentral/Code/"; XmlBuilderWorker builderWorker; builderWorker.AddSchemaFileDirectory(GetFullPath("Xmls/Schema/WithoutVersionConstraints/FullFeatured")); diff --git a/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp b/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp index 1fd17e25ce..e50fbbe56c 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp @@ -104,7 +104,7 @@ namespace UnitTest m_app.Start(m_descriptor); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); AZ::Debug::TraceMessageBus::Handler::BusConnect(); @@ -114,7 +114,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); auto* serializeContext = m_app.GetSerializeContext(); @@ -142,7 +142,7 @@ namespace UnitTest AZStd::string GetTestFileAliasedPath(AZStd::string_view fileName) { - constexpr char testFileFolder[] = "@devroot@/Gems/LmbrCentral/Code/Tests/Levels/"; + constexpr char testFileFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Levels/"; return AZStd::string::format("%s%.*s", testFileFolder, aznumeric_cast(fileName.size()), fileName.data()); } diff --git a/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp index 9e077c113c..a9b36d4624 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp @@ -36,7 +36,7 @@ namespace UnitTest m_app.Start(m_descriptor); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -45,7 +45,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); } void TearDown() override diff --git a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp index 225168ecaa..3786ef7565 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp @@ -35,7 +35,7 @@ namespace UnitTest m_app.reset(aznew AzToolsFramework::ToolsApplication); m_app->Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); AZ::Debug::TraceMessageBus::Handler::BusConnect(); @@ -45,8 +45,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); } void TearDown() override @@ -128,8 +127,8 @@ namespace UnitTest TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_NoChildren_ExpectFailure) { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when both a Textures node and a + // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling + // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when both a Textures node and a // SubMaterials node are not found. No other AZ_Errors should be generated. TestFailureCase("test_mat2.mtl", 1); } @@ -141,7 +140,7 @@ namespace UnitTest TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptySubMaterialNode_ExpectFailure) { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling + // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, // but has no children Material node. No other AZ_Errors should be generated. TestFailureCase("test_mat4.mtl", 1); @@ -154,9 +153,9 @@ namespace UnitTest TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyMaterialInSubMaterial_ExpectFailure) { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling + // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, - // but a child Material node has no child Textures node and no child SubMaterials node. No other AZ_Errors should + // but a child Material node has no child Textures node and no child SubMaterials node. No other AZ_Errors should // be generated. TestFailureCase("test_mat6.mtl", 1); } @@ -235,7 +234,7 @@ namespace UnitTest AZStd::vector expectedPaths = { "engineassets/textures/hex.dds", // resolved from "/engineassets/textures/hex.dds" "engineassets/textures/hex_ddn.dds", // resolved from "./engineassets/textures/hex_ddn.dds" - "engineassets/textures/hex_spec.dds" // resolved from "@assets@/engineassets/textures/hex_spec.dds" + "engineassets/textures/hex_spec.dds" // resolved from "@products@/engineassets/textures/hex_spec.dds" }; TestSuccessCase("test_mat17.mtl", expectedPaths); } diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp index 0d70e34701..f679a3502d 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp @@ -24,16 +24,16 @@ class SeedBuilderTests AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; registry->Set(projectPathKey, "AutomatedTesting"); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry); - + m_app.Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); const char* dir = m_app.GetExecutableFolder(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", dir); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", dir); AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); } @@ -49,7 +49,7 @@ TEST_F(SeedBuilderTests, SeedBuilder_SourceDependency_Valid) { DependencyBuilder::SeedBuilderWorker seedBuilderWorker; AssetBuilderSDK::CreateJobsRequest request; - constexpr char testSeedFolder[] = "@root@/../Gems/LmbrCentral/Code/Tests/Seed"; + constexpr char testSeedFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Seed"; char resolvedPath[AZ_MAX_PATH_LEN]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(testSeedFolder, resolvedPath, AZ_MAX_PATH_LEN); request.m_watchFolder = resolvedPath; @@ -78,7 +78,7 @@ TEST_F(SeedBuilderTests, SeedBuilder_EmptySourceDependency_Valid) { DependencyBuilder::SeedBuilderWorker seedBuilderWorker; AssetBuilderSDK::CreateJobsRequest request; - constexpr char testSeedFolder[] = "@root@/../Gems/LmbrCentral/Code/Tests/Seed"; + constexpr char testSeedFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Seed"; char resolvedPath[AZ_MAX_PATH_LEN]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(testSeedFolder, resolvedPath, AZ_MAX_PATH_LEN); request.m_watchFolder = resolvedPath; diff --git a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp index 08251eb716..7275909908 100644 --- a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp @@ -52,7 +52,7 @@ namespace UnitTest { return false; } - + AZ::Data::AssetInfo assetInfo; AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, testAssetId); return assetInfo.m_relativePath == assetPath; @@ -61,7 +61,7 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundles_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below const char testAssetPath[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; @@ -74,7 +74,7 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundlesCatalogChecks_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testAssetPath[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; @@ -94,34 +94,34 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleUnloadCheckCatalog_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testCSVAsset[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; const char testCSVAssetPak[] = "test/bundle/staticdata.pak"; - // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak + // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak const char testDDSAsset[] = "textures/test/ping.dds"; const char testDDSAssetPak[] = "test/bundle/ping.pak"; EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testDDSAsset)); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testCSVAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testCSVAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testDDSAsset)); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testDDSAsset)); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testCSVAssetPak)); @@ -134,7 +134,7 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleLoadAndBundleMode_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testCSVAsset[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; @@ -143,7 +143,7 @@ namespace UnitTest const char testMTLAssetPak[] = "test/TestMaterials.pak"; EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testMTLAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testMTLAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testMTLAssetPak)); EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testMTLAsset)); LmbrCentral::BundlingSystemRequestBus::Broadcast(&LmbrCentral::BundlingSystemRequestBus::Events::LoadBundles, "test/bundle", ".pak"); @@ -159,35 +159,35 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_OpenClosePackCount_Match) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testCSVAsset[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; const char testCSVAssetPak[] = "test/bundle/staticdata.pak"; - // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak + // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak const char testDDSAssetPak[] = "test/bundle/ping.pak"; size_t bundleCount{ 0 }; LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount,&LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 0); EXPECT_FALSE(TestAssetId(testCSVAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 1); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 0); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testCSVAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testCSVAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 1); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 1); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testCSVAssetPak)); @@ -208,7 +208,7 @@ namespace UnitTest LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 0); EXPECT_FALSE(TestAssetId(testDDSAsset_split)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(TestAssetId(testDDSAsset_split)); @@ -217,7 +217,7 @@ namespace UnitTest EXPECT_EQ(bundleCount, 0); EXPECT_FALSE(TestAssetId(testDDSAsset_split)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(TestAssetId(testDDSAsset_split)); @@ -240,7 +240,7 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testGamePropertiesAsset)); EXPECT_FALSE(TestAssetId(testUserRequestAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testGamePropertiesAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testGamePropertiesAssetPak)); EXPECT_TRUE(TestAssetId(testGamePropertiesAsset)); EXPECT_FALSE(TestAssetId(testUserRequestAsset)); AZ::Data::AssetId testAssetId; @@ -253,7 +253,7 @@ namespace UnitTest EXPECT_NE(assetInfo.m_sizeBytes, 0); AZ::u64 assetSize1 = assetInfo.m_sizeBytes; - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testUserRequestAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testUserRequestAssetPak)); EXPECT_TRUE(TestAssetId(testGamePropertiesAsset)); EXPECT_TRUE(TestAssetId(testUserRequestAsset)); @@ -271,13 +271,13 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testGamePropertiesAsset)); EXPECT_FALSE(TestAssetId(testUserRequestAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testUserRequestAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testUserRequestAssetPak)); AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, testAssetId); AZ::u64 assetSize3 = assetInfo.m_sizeBytes; EXPECT_EQ(assetSize3, assetSize2); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testGamePropertiesAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testGamePropertiesAssetPak)); AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, testAssetId); AZ::u64 assetSize4 = assetInfo.m_sizeBytes; EXPECT_EQ(assetSize4, assetSize1); diff --git a/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace b/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace index 6c7f7d3d87..0e92f9e83c 100644 --- a/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace +++ b/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/foo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00015891\nLoadMotionSet -filename \"@assets@/foo.motionset\"\nLoadAnimGraph -filename \"@assets@/foo.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" +startScript="ImportActor -filename \"@products@/foo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00015891\nLoadMotionSet -filename \"@products@/foo.motionset\"\nLoadAnimGraph -filename \"@products@/foo.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" diff --git a/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl b/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl index 099e006f4c..c3d0ddcf61 100644 --- a/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl +++ b/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl @@ -2,7 +2,7 @@ - + diff --git a/Gems/LyShine/Code/Editor/EditorMenu.cpp b/Gems/LyShine/Code/Editor/EditorMenu.cpp index 8a6c93de6b..0eeec9a06e 100644 --- a/Gems/LyShine/Code/Editor/EditorMenu.cpp +++ b/Gems/LyShine/Code/Editor/EditorMenu.cpp @@ -606,7 +606,7 @@ void EditorWindow::AddMenu_View() [this]([[maybe_unused]] bool checked) { // Clear guides - AZStd::string canvasUndoXml = CanvasHelpers::BeginUndoableCanvasChange(GetCanvas()); + AZStd::string canvasUndoXml = CanvasHelpers::BeginUndoableCanvasChange(GetCanvas()); EBUS_EVENT_ID(GetCanvas(), UiEditorCanvasBus, RemoveAllGuides); CanvasHelpers::EndUndoableCanvasChange(this, "clear guides", canvasUndoXml); }); @@ -724,7 +724,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) // Iterate through the subdirectories of the localization folder. Each // directory corresponds to a different language containing localization // translations for that language. - AZStd::string fullLocPath(AZStd::string(gEnv->pFileIO->GetAlias("@assets@")) + "/" + AZStd::string(m_startupLocFolderName.toUtf8().constData())); + AZStd::string fullLocPath(AZStd::string(gEnv->pFileIO->GetAlias("@products@")) + "/" + AZStd::string(m_startupLocFolderName.toUtf8().constData())); QDir locDir(fullLocPath.c_str()); locDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); locDir.setSorting(QDir::Name); @@ -733,7 +733,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) { QString directoryName(subDirectory.fileName().toLower()); - // The loc system expects XML assets stored in a language-specific + // The loc system expects XML assets stored in a language-specific // folder with an "_xml" suffix in the name. Truncate the displayed // name so the user just sees the language name (this isn't required // though). @@ -754,7 +754,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) { // First try to locate the directory by name, without the "_xml" // suffix (in case it actually exists by this name). - QString fullLocPath(QString(gEnv->pFileIO->GetAlias("@assets@")) + "/" + m_startupLocFolderName + "/" + directoryName); + QString fullLocPath(QString(gEnv->pFileIO->GetAlias("@products@")) + "/" + m_startupLocFolderName + "/" + directoryName); QDir locDir(fullLocPath); // Try the directory with the expected suffix @@ -780,7 +780,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) "This used to be set to CSystem::OnLocalizationFolderCVarChanged but is now missing. " "UI Editor language-switching features are no longer working."); } - + // Update the language setting; this will allow font families to // load language-specific font assets ICVar* languageCvar = gEnv->pConsole->GetCVar("g_language"); diff --git a/Gems/LyShine/Code/Editor/UiSliceManager.cpp b/Gems/LyShine/Code/Editor/UiSliceManager.cpp index 97e9a51e11..a8fdad5343 100644 --- a/Gems/LyShine/Code/Editor/UiSliceManager.cpp +++ b/Gems/LyShine/Code/Editor/UiSliceManager.cpp @@ -138,7 +138,7 @@ void UiSliceManager::MakeSliceFromEntities(AzToolsFramework::EntityIdList& entit // expand the list of entities to include all child entities AzToolsFramework::EntityIdSet entitiesAndDescendants = GatherEntitiesAndAllDescendents(entities); - const AZStd::string slicesAssetsPath = "@devassets@/UI/Slices"; + const AZStd::string slicesAssetsPath = "@projectroot@/UI/Slices"; if (!gEnv->pFileIO->Exists(slicesAssetsPath.c_str())) { @@ -991,13 +991,13 @@ AZStd::string UiSliceManager::MakeTemporaryFilePathForSave(const char* targetFil AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "File IO is not initialized."); - AZStd::string devAssetPath = fileIO->GetAlias("@devassets@"); + AZStd::string devAssetPath = fileIO->GetAlias("@projectroot@"); AZStd::string userPath = fileIO->GetAlias("@user@"); AZStd::string tempPath = targetFilename; EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, devAssetPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, userPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, tempPath); - AzFramework::StringFunc::Replace(tempPath, "@devassets@", devAssetPath.c_str()); + AzFramework::StringFunc::Replace(tempPath, "@projectroot@", devAssetPath.c_str()); AzFramework::StringFunc::Replace(tempPath, devAssetPath.c_str(), userPath.c_str()); tempPath.append(".slicetemp"); diff --git a/Gems/LyShine/Code/Source/UiCanvasManager.cpp b/Gems/LyShine/Code/Source/UiCanvasManager.cpp index a71c46d45e..f2397248b6 100644 --- a/Gems/LyShine/Code/Source/UiCanvasManager.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasManager.cpp @@ -67,7 +67,7 @@ namespace // Check if extension needs to be fixed up const AZStd::string canvasExtension("uicanvas"); - bool validExtension = AzFramework::StringFunc::Path::IsExtension(assetPath.c_str(), canvasExtension.c_str(), true); + bool validExtension = AzFramework::StringFunc::Path::IsExtension(assetPath.c_str(), canvasExtension.c_str(), true); if (!validExtension) { // Fix extension @@ -79,7 +79,7 @@ namespace // Normalize path EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePathKeepCase, assetPath); - // Check for any leading slashes as the specified path should be a relative path to the @assets@ alias. + // Check for any leading slashes as the specified path should be a relative path to the @products@ alias. // This eliminates inconsistencies between lower level file opens on different platforms int numCharsToErase = 0; for (; numCharsToErase < assetPath.length(); ++numCharsToErase) @@ -581,7 +581,7 @@ void UiCanvasManager::UpdateLoadedCanvases(float deltaTime) // Update all the canvases loaded in game. // It is unlikely this will call out to client code that could remove a canvas but we have no - // control over what custom components do so we increment the count that will defer all canvas deletion + // control over what custom components do so we increment the count that will defer all canvas deletion m_recursionGuardCount++; if (m_generateMousePositionInputEvent) { @@ -1087,7 +1087,7 @@ void UiCanvasManager::DebugDisplayCanvasData(int setting) const } const char* enabledString = isCanvasEnabled ? "Y" : "N"; totalEnabled += isCanvasEnabled ? 1 : 0; - + bool posEnabled = canvas->GetIsPositionalInputSupported(); const char* posEnabledString = posEnabled ? "Y" : "N"; totalPositionalInputs += posEnabled ? 1 : 0; @@ -1178,7 +1178,7 @@ void UiCanvasManager::DebugDisplayDrawCallData() const const AZ::Vector3 blue(0.3f,0.3f,1); const AZ::Vector3 green(0.3f,1,0.3f); const AZ::Vector3 yellow(0.7f,0.7f,0.2f); - + // local function to write a line of text (with a background rect) and increment Y offset AZStd::function WriteLine = [&](const char* buffer, const AZ::Vector3& color) { @@ -1191,7 +1191,7 @@ void UiCanvasManager::DebugDisplayDrawCallData() const draw2d->DrawText(buffer, AZ::Vector2(xOffset, yOffset), 16, textOpacity, &textOptions); yOffset += lineSpacing; }; - + char buffer[200]; sprintf_s(buffer, "NN: %20s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s", diff --git a/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp b/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp index ff4e054ac7..60074ac0a0 100644 --- a/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp +++ b/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp @@ -60,7 +60,7 @@ AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); using namespace AZ; using ::testing::NiceMock; -class LyShineSystemTestComponent +class LyShineSystemTestComponent : public LyShine::LyShineSystemComponent { friend class LyShineEditorTest; @@ -90,18 +90,18 @@ protected: m_app.Start(m_descriptor); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); AZ::SerializeContext* context = nullptr; ComponentApplicationBus::BroadcastResult(context, &ComponentApplicationBus::Events::GetSerializeContext); diff --git a/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp b/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp index 104118e4bf..40fed3448b 100644 --- a/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp +++ b/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp @@ -127,21 +127,21 @@ namespace MessagePopup switch (_buttons) { case EPopupButtons::EPopupButtons_NoButtons: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/defaultmessagepopup.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup.uicanvas"); break; case EPopupButtons::EPopupButtons_Confirm: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/defaultmessagepopup_confirm.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_confirm.uicanvas"); isNavigationSupported = true; break; case EPopupButtons::EPopupButtons_YesNo: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/defaultmessagepopup_yesno.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_yesno.uicanvas"); isNavigationSupported = true; break; } } else if (_kind == EPopupKind_Toaster) { - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/toaster.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/toaster.uicanvas"); } if (canvasEntityId.IsValid()) diff --git a/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace b/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace index 1727656092..8bc507082c 100644 --- a/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace +++ b/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@assets@/Characters/Cowboy/AnimationEditorFiles/Cowboy.motionset\"\nLoadAnimGraph -filename \"@assets@/Characters/Cowboy/AnimationEditorFiles/Cowboy.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" +startScript="ImportActor -filename \"@products@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@products@/Characters/Cowboy/AnimationEditorFiles/Cowboy.motionset\"\nLoadAnimGraph -filename \"@products@/Characters/Cowboy/AnimationEditorFiles/Cowboy.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" diff --git a/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp b/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp index a7bd193fd7..83a158dd18 100644 --- a/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp +++ b/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp @@ -202,9 +202,6 @@ namespace QtForPython QtBootstrapParameters QtForPythonSystemComponent::GetQtBootstrapParameters() const { QtBootstrapParameters params; - - char devroot[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devroot@", devroot, AZ_MAX_PATH_LEN); #if !defined(Q_OS_WIN) #error Unsupported OS platform for this QtForPython gem diff --git a/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp b/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp index a4da836aeb..5d0105f080 100644 --- a/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp +++ b/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp @@ -36,13 +36,12 @@ protected: m_app.Start(AZ::ComponentApplication::Descriptor()); AZ::Debug::TraceMessageBus::Handler::BusConnect(); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); m_workingDirectory = m_app.GetExecutableFolder(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", m_workingDirectory); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", m_workingDirectory); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", m_workingDirectory); } void TearDown() override @@ -78,7 +77,7 @@ protected: } void TestSuccessCase(const SceneAPI::Events::ExportProduct& exportProduct, - const AssetBuilderSDK::ProductPathDependency* expectedPathDependency = nullptr, + const AssetBuilderSDK::ProductPathDependency* expectedPathDependency = nullptr, const AZ::Uuid* expectedProductDependency = nullptr) { AssetBuilderSDK::ProductPathDependencySet expectedPathDependencies; @@ -86,13 +85,13 @@ protected: { expectedPathDependencies.emplace(*expectedPathDependency); } - + AZStd::vector expectedProductDependencies; if (expectedProductDependency) { expectedProductDependencies.push_back(*expectedProductDependency); } - + TestSuccessCase(exportProduct, expectedPathDependencies, expectedProductDependencies); } @@ -121,7 +120,7 @@ TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_PathDepen const char* absolutePathToFile = "/some/test/file.mtl"; #endif // AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS AssetBuilderSDK::ProductPathDependency expectedPathDependency(absolutePathToFile, AssetBuilderSDK::ProductPathDependencyType::SourceFile); - + SceneAPI::Events::ExportProduct product("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt); product.m_legacyPathDependencies.push_back(absolutePathToFile); TestSuccessCase(product, &expectedPathDependency); @@ -133,7 +132,7 @@ TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_PathDepen const char* relativeDependencyPathToFile = "some/test/file.mtl"; AssetBuilderSDK::ProductPathDependency expectedPathDependency(relativeDependencyPathToFile, AssetBuilderSDK::ProductPathDependencyType::ProductFile); - + SceneAPI::Events::ExportProduct product("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt); product.m_legacyPathDependencies.push_back(relativeDependencyPathToFile); diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h index fdc8cbc1d8..0fb0f567e8 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h @@ -41,7 +41,7 @@ namespace ScriptCanvasEditor azrtti_typeid(), "Script Canvas", "Script Canvas Graph Asset", - "@devassets@/scriptcanvas", + "@projectroot@/scriptcanvas", ".scriptcanvas", "Script Canvas", "Untitled-%i", diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp b/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp index 15cbd12d7e..a7c39fbf0f 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp @@ -9,27 +9,20 @@ #include "CommonSettingsConfigurations.h" #include +#include +#include #include namespace ScriptCanvasEditor { AZStd::string GetEditingGameDataFolder() { - const char* resultValue = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(resultValue, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); - if (!resultValue) + AZ::IO::Path projectPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - if (AZ::IO::FileIOBase::GetInstance()) - { - resultValue = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); - } + settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } - if (!resultValue) - { - resultValue = "."; - } - - return resultValue; + return projectPath.Native(); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index fbe03ffc0a..289643d59c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -224,7 +225,7 @@ namespace ScriptCanvasEditor } } } // anonymous namespace. - + void Workspace::Save() { auto workspace = AZ::UserSettings::CreateFind(AZ_CRC("ScriptCanvasEditorWindowState", 0x10c47d36), AZ::UserSettings::CT_LOCAL); @@ -423,7 +424,7 @@ namespace ScriptCanvasEditor , m_queueCloseRequest(false) , m_hasQueuedClose(false) , m_isInAutomation(false) - , m_allowAutoSave(true) + , m_allowAutoSave(true) , m_systemTickActions(0) , m_closeCurrentGraphAfterSave(false) , m_styleManager(ScriptCanvasEditor::AssetEditorId, "ScriptCanvas/StyleSheet/graphcanvas_style.json") @@ -432,7 +433,7 @@ namespace ScriptCanvasEditor GraphCanvas::AssetEditorAutomationRequestBus::Handler::BusConnect(ScriptCanvasEditor::AssetEditorId); AZStd::array unresolvedPath; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@assets@/translation/scriptcanvas_en_us.qm", unresolvedPath.data(), unresolvedPath.size()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@products@/translation/scriptcanvas_en_us.qm", unresolvedPath.data(), unresolvedPath.size()); QString translationFilePath(unresolvedPath.data()); if ( m_translator.load(QLocale::Language::English, translationFilePath) ) @@ -541,7 +542,7 @@ namespace ScriptCanvasEditor m_editorToolbar->AddCustomAction(m_createFunctionOutput); connect(m_createFunctionOutput, &QToolButton::clicked, this, &MainWindow::CreateFunctionOutput); - + { m_validateGraphToolButton = new QToolButton(); @@ -553,7 +554,7 @@ namespace ScriptCanvasEditor m_editorToolbar->AddCustomAction(m_validateGraphToolButton); connect(m_validateGraphToolButton, &QToolButton::clicked, this, &MainWindow::OnValidateCurrentGraph); - + m_layout->addWidget(m_editorToolbar); // Tab bar @@ -578,7 +579,7 @@ namespace ScriptCanvasEditor m_commandLine = new Widget::CommandLine(this); m_commandLine->setBaseSize(QSize(size().width(), m_commandLine->size().height())); - m_commandLine->setObjectName("CommandLine"); + m_commandLine->setObjectName("CommandLine"); m_layout->addWidget(m_commandLine); m_layout->addWidget(m_emptyCanvas); @@ -602,7 +603,7 @@ namespace ScriptCanvasEditor // in sync with the order we display under tools for consistency. { const bool isInContextMenu = false; - Widget::ScriptCanvasNodePaletteConfig nodePaletteConfig(m_nodePaletteModel, m_scriptEventsAssetModel, isInContextMenu); + Widget::ScriptCanvasNodePaletteConfig nodePaletteConfig(m_nodePaletteModel, m_scriptEventsAssetModel, isInContextMenu); m_nodePalette = aznew Widget::NodePaletteDockWidget(tr("Node Palette"), this, nodePaletteConfig); m_nodePalette->setObjectName("NodePalette"); @@ -734,21 +735,23 @@ namespace ScriptCanvasEditor message.append(QObject::tr("
%1 graph(s) that need manual corrections. You will be prompted to review them after you close this dialog.
").arg(assetsThatNeedManualInspection)); } - // Report - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string outputFileName = AZStd::string::format("@devroot@/ScriptCanvasUpgradeReport.html"); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZStd::string urlToReport = AZStd::string::format("For more information see the Upgrade Report.", resolvedBuffer); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + + AZ::IO::Path outputFileName; + settingsRegistry->Get(outputFileName.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectLogPath); + outputFileName /= "ScriptCanvasUpgradeReport.html"; + // Report + AZStd::string urlToReport = AZStd::string::format("For more information see the Upgrade Report.", outputFileName.c_str()); message.append(QObject::tr("
%1").arg(urlToReport.c_str())); // Backup if (upgradeTool->HasBackup()) { - AZStd::string outputFileName2 = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP"); - - AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName2.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); + AZ::IO::Path outputFileName2; + settingsRegistry->Get(outputFileName2.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); + outputFileName2 /= "ScriptCanvas_BACKUP"; - AZStd::string backupPath = AZStd::string::format("
Open the Backup Folder.", resolvedBuffer); + AZStd::string backupPath = AZStd::string::format("
Open the Backup Folder.", outputFileName.c_str()); message.append(QObject::tr("%1").arg(backupPath.c_str())); } @@ -882,14 +885,14 @@ namespace ScriptCanvasEditor connect(ui->action_ViewVariableManager, &QAction::triggered, this, &MainWindow::OnVariableManager); connect(m_variableDockWidget, &QDockWidget::visibilityChanged, this, &MainWindow::OnViewVisibilityChanged); - + connect(ui->action_ViewLogWindow, &QAction::triggered, this, &MainWindow::OnViewLogWindow); connect(m_loggingWindow, &QDockWidget::visibilityChanged, this, &MainWindow::OnViewVisibilityChanged); connect(ui->action_ViewDebugger, &QAction::triggered, this, &MainWindow::OnViewDebugger); connect(ui->action_ViewCommandLine, &QAction::triggered, this, &MainWindow::OnViewCommandLine); connect(ui->action_ViewLog, &QAction::triggered, this, &MainWindow::OnViewLog); - + connect(ui->action_GraphValidation, &QAction::triggered, this, &MainWindow::OnViewGraphValidation); connect(ui->action_Debugging, &QAction::triggered, this, &MainWindow::OnViewDebuggingWindow); @@ -897,7 +900,7 @@ namespace ScriptCanvasEditor connect(ui->action_NodeStatistics, &QAction::triggered, this, &MainWindow::OnViewStatisticsPanel); connect(ui->action_PresetsEditor, &QAction::triggered, this, &MainWindow::OnViewPresetsEditor); - connect(ui->action_ViewRestoreDefaultLayout, &QAction::triggered, this, &MainWindow::OnRestoreDefaultLayout); + connect(ui->action_ViewRestoreDefaultLayout, &QAction::triggered, this, &MainWindow::OnRestoreDefaultLayout); } void MainWindow::SignalActiveSceneChanged(AZ::Data::AssetId assetId) @@ -920,7 +923,7 @@ namespace ScriptCanvasEditor // The paste action refreshes based on the scene's mimetype RefreshPasteAction(); - + bool enabled = false; if (graphId.IsValid()) @@ -1016,7 +1019,7 @@ namespace ScriptCanvasEditor QString tabName = m_tabBar->tabText(tabCounter); UnsavedChangesOptions shouldSaveResults = ShowSaveDialog(tabName); - + if (shouldSaveResults == UnsavedChangesOptions::SAVE) { Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, AZ::Data::AssetId) @@ -1041,7 +1044,7 @@ namespace ScriptCanvasEditor { m_processedClosedAssetIds.clear(); event->ignore(); - + return; } else if (shouldSaveResults == UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING && @@ -1066,7 +1069,7 @@ namespace ScriptCanvasEditor } m_processedClosedAssetIds.clear(); - + event->accept(); } @@ -1232,7 +1235,7 @@ namespace ScriptCanvasEditor const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(memoryAssetId); if (fileState != Tracker::ScriptCanvasFileState::NEW) { - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); + AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); } } } @@ -1734,12 +1737,12 @@ namespace ScriptCanvasEditor { currentTarget.SetInvalid(); } - } + } } return retVal; } - + void MainWindow::OnFileNew() { MakeNewFile(); @@ -1756,7 +1759,7 @@ namespace ScriptCanvasEditor m_tabBar->InsertGraphTab(tabIndex, assetId); if (!IsTabOpen(assetId, outTabIndex)) - { + { AZ_Assert(false, AZStd::string::format("Unable to open new Script Canvas Asset with id %s in the Script Canvas Editor", AssetHelpers::AssetIdToString(assetId).c_str()).c_str()); return -1; } @@ -1854,7 +1857,7 @@ namespace ScriptCanvasEditor } PrepareAssetForSave(inMemoryAssetId); - + AZStd::string suggestedFilename; AZStd::string suggestedFileFilter; GetSuggestedFullFilenameToSaveAs(inMemoryAssetId, suggestedFilename, suggestedFileFilter); @@ -1881,7 +1884,7 @@ namespace ScriptCanvasEditor AZStd::string assetRoot; AZStd::array assetRootChar; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devroot@", assetRootChar.data(), assetRootChar.size()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@", assetRootChar.data(), assetRootChar.size()); assetRoot = assetRootChar.data(); /* if (!AZ::StringFunc::StartsWith(filePath, assetRoot)) @@ -1906,7 +1909,7 @@ namespace ScriptCanvasEditor if (isValidFileName) { - AZStd::string internalStringFile = selectedFile.toUtf8().data(); + AZStd::string internalStringFile = selectedFile.toUtf8().data(); if (!AssetHelpers::IsValidSourceFile(internalStringFile, GetActiveScriptCanvasId())) { @@ -1923,7 +1926,7 @@ namespace ScriptCanvasEditor return true; } - + return false; } @@ -1965,7 +1968,7 @@ namespace ScriptCanvasEditor saveTabIndex = m_tabBar->FindTab(previousFileAssetId); } } - + AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); // Update the tab's assetId to the file asset Id (necessary when saving a new asset) @@ -2047,7 +2050,7 @@ namespace ScriptCanvasEditor } m_closeCurrentGraphAfterSave = false; - + EnableAssetView(memoryAsset); UnblockCloseRequests(); @@ -2071,7 +2074,7 @@ namespace ScriptCanvasEditor AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); } }; - + AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Save, assetId, onSaveCallback); UpdateSaveState(); @@ -2109,7 +2112,7 @@ namespace ScriptCanvasEditor // Disable the current view if we are saving. if (memoryAsset) { - DisableAssetView(memoryAsset); + DisableAssetView(memoryAsset); } BlockCloseRequests(); @@ -2126,7 +2129,7 @@ namespace ScriptCanvasEditor AZStd::string assetRoot; { AZStd::array assetRootChar; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", assetRootChar.data(), assetRootChar.size()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", assetRootChar.data(), assetRootChar.size()); assetRoot = assetRootChar.data(); } @@ -2147,7 +2150,7 @@ namespace ScriptCanvasEditor AssetRegistryRequestBus::BroadcastResult(fileFilters, &AssetRegistryRequests::GetAssetHandlerFileFilters); QString filter; - + AZStd::set filterSet; auto aggregateFilters = fileFilters.values; for (auto aggregateFilters2 : fileFilters.values) @@ -2190,7 +2193,7 @@ namespace ScriptCanvasEditor dialog.setFileMode(QFileDialog::ExistingFiles); dialog.setNameFilters(nameFilters); - if (dialog.exec() == QDialog::Accepted) + if (dialog.exec() == QDialog::Accepted) { m_filesToOpen = dialog.selectedFiles(); @@ -2206,7 +2209,7 @@ namespace ScriptCanvasEditor ui->action_Paste->setShortcut(QKeySequence(QKeySequence::Paste)); ui->action_Delete->setShortcut(QKeySequence(QKeySequence::Delete)); - connect(ui->menuEdit, &QMenu::aboutToShow, this, &MainWindow::OnEditMenuShow); + connect(ui->menuEdit, &QMenu::aboutToShow, this, &MainWindow::OnEditMenuShow); // Edit Menu connect(ui->action_Undo, &QAction::triggered, this, &MainWindow::TriggerUndo); @@ -2215,8 +2218,8 @@ namespace ScriptCanvasEditor connect(ui->action_Copy, &QAction::triggered, this, &MainWindow::OnEditCopy); connect(ui->action_Paste, &QAction::triggered, this, &MainWindow::OnEditPaste); connect(ui->action_Duplicate, &QAction::triggered, this, &MainWindow::OnEditDuplicate); - connect(ui->action_Delete, &QAction::triggered, this, &MainWindow::OnEditDelete); - connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &MainWindow::RefreshPasteAction); + connect(ui->action_Delete, &QAction::triggered, this, &MainWindow::OnEditDelete); + connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &MainWindow::RefreshPasteAction); connect(ui->action_RemoveUnusedNodes, &QAction::triggered, this, &MainWindow::OnRemoveUnusedNodes); connect(ui->action_RemoveUnusedVariables, &QAction::triggered, this, &MainWindow::OnRemoveUnusedVariables); connect(ui->action_RemoveUnusedElements, &QAction::triggered, this, &MainWindow::OnRemoveUnusedElements); @@ -2246,7 +2249,7 @@ namespace ScriptCanvasEditor connect(ui->action_GotoEndOfChain, &QAction::triggered, this, &MainWindow::OnGotoEndOfChain); - connect(ui->action_GlobalPreferences, &QAction::triggered, [this]() + connect(ui->action_GlobalPreferences, &QAction::triggered, [this]() { ScriptCanvasEditor::SettingsDialog(ui->action_GlobalPreferences->text(), ScriptCanvas::ScriptCanvasId(), this).exec(); @@ -2372,7 +2375,7 @@ namespace ScriptCanvasEditor { AZ::EntityId graphCanvasGraphId = GetActiveGraphCanvasGraphId(); - GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::SelectAllRelative, GraphCanvas::ConnectionType::CT_Input); + GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::SelectAllRelative, GraphCanvas::ConnectionType::CT_Input); } void MainWindow::OnSelectOutputs() @@ -2635,8 +2638,8 @@ namespace ScriptCanvasEditor { ScriptCanvas::ScriptCanvasId scriptCanvasId; AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - return scriptCanvasId; - } + return scriptCanvasId; + } ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const { @@ -2849,7 +2852,7 @@ namespace ScriptCanvasEditor AssetTrackerRequests::AssetList assets; AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); - + for (auto asset : assets) { RemoveScriptCanvasAsset(asset->GetAsset().GetId()); @@ -2927,14 +2930,14 @@ namespace ScriptCanvasEditor } void MainWindow::SaveTab(int index) - { + { QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { auto assetId = tabdata.value(); SaveAssetImpl(assetId, nullptr); } - + } void MainWindow::CloseAllTabs() @@ -2955,7 +2958,7 @@ namespace ScriptCanvasEditor m_isClosingTabs = true; m_skipTabOnClose = assetId; CloseNextTab(); - } + } } void MainWindow::CopyPathToClipboard(int index) @@ -3051,7 +3054,7 @@ namespace ScriptCanvasEditor // The last tab has been removed. SetActiveAsset({}); } - + // Handling various close all events because the save is async need to deal with this in a bunch of different ways // Always want to trigger this, even if we don't have any active tabs to avoid doubling the clean-up // information @@ -3069,7 +3072,7 @@ namespace ScriptCanvasEditor for (const auto& slotId : outputDataSlotIds) { - + if (!IsInUndoRedo(graphCanvasGraphId) && !isPaste && CreateAzEventHandlerSlotMenuAction::FindBehaviorMethodWithAzEventReturn(graphCanvasGraphId, slotId)) { CreateAzEventHandlerSlotMenuAction eventHandlerAction(this); @@ -3195,7 +3198,7 @@ namespace ScriptCanvasEditor m_minimap->hide(); } */ - + resizeDocks( { m_nodePalette, m_propertyGrid }, { static_cast(size().width() * 0.15f), static_cast(size().width() * 0.2f) }, @@ -3204,7 +3207,7 @@ namespace ScriptCanvasEditor resizeDocks({ m_nodePalette, m_minimap }, { static_cast(size().height() * 0.70f), static_cast(size().height() * 0.30f) }, Qt::Vertical); - + resizeDocks({ m_propertyGrid, m_variableDockWidget }, { static_cast(size().height() * 0.70f), static_cast(size().height() * 0.30f) }, @@ -3229,7 +3232,7 @@ namespace ScriptCanvasEditor AZ::EntityId graphCanvasGraphId; EditorGraphRequestBus::EventResult(graphCanvasGraphId, scriptCanvasId, &EditorGraphRequests::GetGraphCanvasGraphId); - + bool hasCopiableSelection = false; bool hasSelection = false; @@ -3268,7 +3271,7 @@ namespace ScriptCanvasEditor ui->action_Duplicate->setEnabled(hasCopiableSelection); // Delete will work for anything that is selectable - ui->action_Delete->setEnabled(hasSelection); + ui->action_Delete->setEnabled(hasSelection); } void MainWindow::OnViewNodePalette() @@ -3470,7 +3473,7 @@ namespace ScriptCanvasEditor if (ui->action_Debugging->isChecked() != m_loggingWindow->isVisible()) { ui->action_Debugging->setChecked(m_loggingWindow->isVisible()); - } + } // Want these two elements to be mutually exclusive. if (m_statusWidget->isVisible() == m_validationDockWidget->isVisible()) @@ -3624,7 +3627,7 @@ namespace ScriptCanvasEditor if (m_isRestoringWorkspace) { m_isRestoringWorkspace = false; - + if (m_queuedFocusOverride.IsValid()) { SetActiveAsset(m_queuedFocusOverride); @@ -3701,7 +3704,7 @@ namespace ScriptCanvasEditor hasModifications = ( fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED); - + AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeAssetId); } @@ -4084,7 +4087,7 @@ namespace ScriptCanvasEditor if (action == nullptr) { GraphCanvas::GraphCanvasMimeEvent* mimeEvent = m_sceneContextMenu->GetNodePalette()->GetContextMenuEvent(); - + NodeIdPair finalNode = ProcessCreateNodeMimeEvent(mimeEvent, graphCanvasGraphId, AZ::Vector2(aznumeric_cast(scenePoint.x()), aznumeric_cast(scenePoint.y()))); GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::ClearSelection); @@ -4436,7 +4439,7 @@ namespace ScriptCanvasEditor targetLayer = (*selectedEntityIdIter); - selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); + selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); } else { @@ -4456,7 +4459,7 @@ namespace ScriptCanvasEditor AZ::TransformBus::Event(createdId, &AZ::TransformBus::Events::SetParent, targetLayer); } } - + for (const AZ::EntityId& entityId : selectedEntityIds) { AssignGraphToEntityImpl(entityId); @@ -4515,7 +4518,7 @@ namespace ScriptCanvasEditor { usableRequestBus = firstRequestBus; } - + if (usableRequestBus == nullptr) { AzToolsFramework::EntityCompositionRequestBus::Broadcast(&EntityCompositionRequests::AddComponentsToEntities, AzToolsFramework::EntityIdList{ entityId } @@ -4681,7 +4684,7 @@ namespace ScriptCanvasEditor } bool MainWindow::IsNodeNudgingEnabled() const - { + { if (m_userSettings) { return m_userSettings->m_allowNodeNudging; @@ -4720,7 +4723,7 @@ namespace ScriptCanvasEditor return 0.03f; } - float MainWindow::GetShakeDeadZonePercent() const + float MainWindow::GetShakeDeadZonePercent() const { if (m_userSettings) { @@ -4730,7 +4733,7 @@ namespace ScriptCanvasEditor return 0.01f; } - float MainWindow::GetShakeStraightnessPercent() const + float MainWindow::GetShakeStraightnessPercent() const { if (m_userSettings) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index ba5ff7f97f..30e84f3fa8 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -673,7 +673,7 @@ namespace ScriptCanvasEditor AZStd::array assetRootArray; if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(ScriptCanvas::AssetDescription::GetSuggestedSavePath(), assetRootArray.data(), assetRootArray.size())) { - AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @devassets@ path"); + AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); } AZStd::string assetPath; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp index 5e6858c993..f1832927c5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp @@ -13,7 +13,9 @@ #include #include +#include #include +#include #include #include @@ -169,10 +171,11 @@ namespace ScriptCanvasEditor QDateTime theTime = QDateTime::currentDateTime(); QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - m_backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(m_backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - m_backupPath = backupPathCStr; + auto settingsRegistry = AZ::SettingsRegistry::Get(); + m_backupPath.clear(); + settingsRegistry->Get(m_backupPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); + + m_backupPath = m_backupPath / "ScriptCanvas_BACKUP" / subFolder.toUtf8().data(); if (!AZ::IO::FileIOBase::GetInstance()->Exists(m_backupPath.c_str())) { @@ -489,56 +492,25 @@ namespace ScriptCanvasEditor void UpgradeTool::BackupAsset(const AZ::Data::AssetInfo& assetInfo) { - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; + AZ::IO::FixedMaxPath sourceFilePath; // Using this to get the watch folder AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo2; + AZ::Data::AssetInfo sourceFileAssetInfo; bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetInfo.m_relativePath.c_str(), assetInfo2, watchFolder); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, + &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + assetInfo.m_relativePath.c_str(), sourceFileAssetInfo, watchFolder); if (sourceInfoFound) { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; + sourceFilePath = AZ::IO::FixedMaxPath(AZStd::string_view(watchFolder)) / sourceFileAssetInfo.m_relativePath; } - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string targetFilePath; - AzFramework::StringFunc::Path::Join(m_backupPath.c_str(), relativePath.c_str(), targetFilePath); + const auto targetFilePath = m_backupPath / sourceFileAssetInfo.m_relativePath; if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Error) { - AZStd::string filename; - AzFramework::StringFunc::Path::GetFileName(sourceFilePath.c_str(), filename); - AZ_TracePrintf("Script Canvas", "Backup: %s -> %s\n", filename.c_str(), targetFilePath.c_str()); + AZ_TracePrintf("Script Canvas", "Backup: %s -> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); } else { @@ -583,7 +555,7 @@ namespace ScriptCanvasEditor void UpgradeTool::SaveLog() { - AZStd::string outputFileName = AZStd::string::format("@devroot@/ScriptCanvasUpgradeReport.html"); + AZStd::string outputFileName = AZStd::string::format("@log@/ScriptCanvasUpgradeReport.html"); char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h index be00198457..8a2034bf4f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h @@ -27,6 +27,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #endif class QPushButton; @@ -135,7 +136,7 @@ namespace ScriptCanvasEditor AZ::Entity* m_scriptCanvasEntity = nullptr; - AZStd::string m_backupPath; + AZ::IO::Path m_backupPath; void FinalizeUpgrade(); void DisconnectBuses(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp index eb182ed291..f400f84d51 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -301,51 +302,37 @@ namespace ScriptCanvasEditor return ""; } + auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + QDateTime theTime = QDateTime::currentDateTime(); QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; + AZ::IO::FixedMaxPath projectUserPath; + settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); + + AZ::IO::FixedMaxPath backupPath = projectUserPath / "ScriptCanvas_BACKUP" / subFolder.toUtf8().data(); - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + if (!fileIoBase->Exists(backupPath.c_str())) { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + if (fileIoBase->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) { AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); return "Failed to create backup folder"; } } - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - AZStd::string watchFolder; AZ::Data::AssetInfo assetInfo; + + AZ::IO::FixedMaxPath sourceFilePath; bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, + &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + asset.GetHint().c_str(), assetInfo, watchFolder); if (sourceInfoFound) { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; + sourceFilePath = AZ::IO::FixedMaxPath(AZStd::string_view(watchFolder)) / assetInfo.m_relativePath; } else { @@ -353,23 +340,9 @@ namespace ScriptCanvasEditor return "Failed to find source file"; } - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); + const AZ::IO::FixedMaxPath targetFilePath = backupPath / assetInfo.m_relativePath; - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) + if (fileIoBase->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) { AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); return "Failed to copy source file to backup location"; @@ -602,7 +575,7 @@ namespace ScriptCanvasEditor }); streamer->QueueRequest(flushRequest); } - } + } } void VersionExplorer::GraphUpgradeComplete @@ -816,7 +789,7 @@ namespace ScriptCanvasEditor } char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZStd::string path = AZStd::string::format("@engroot@/%s", asset.GetHint().c_str()); AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); AZ::StringFunc::Path::Normalize(path); @@ -873,7 +846,7 @@ namespace ScriptCanvasEditor m_state = ProcessState::Upgrade; AZ::SystemTickBus::Handler::BusConnect(); - } + } } } @@ -883,7 +856,7 @@ namespace ScriptCanvasEditor m_inProgress = false; m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); m_ui->scanButton->setEnabled(true); - + m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); FlushLogs(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp index 51cb034f35..e1fe71d4d9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp @@ -85,7 +85,7 @@ namespace ScriptCanvas const char* ExecutionLogAsset::GetDefaultDirectoryRoot() { - return AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@"); + return AZ::IO::FileIOBase::GetInstance()->GetAlias("@engroot@"); } ExecutionLogAsset::ExecutionLogAsset(const AZ::Data::AssetId& assetId, AZ::Data::AssetData::AssetStatus status) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h index 037985d980..24c83b20a1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h @@ -36,7 +36,7 @@ namespace ScriptCanvas azrtti_typeid(), "Script Canvas Runtime", "Script Canvas Runtime Graph", - "@devassets@/scriptcanvas", + "@projectroot@/scriptcanvas", ".scriptcanvas_compiled", "Script Canvas Runtime", "Untitled-%i", @@ -177,7 +177,7 @@ namespace ScriptCanvas azrtti_typeid(), "Script Canvas Function Interface", "Script Canvas Function Interface", - "@devassets@/scriptcanvas", + "@projectroot@/scriptcanvas", ".scriptcanvas_fn_compiled", "Script Canvas Function Interface", "Untitled-Function-%i", diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp index 849e2272a2..ee0052d5b9 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -129,7 +130,7 @@ namespace WhiteBox AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast( &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, - "@devroot@/Gems/WhiteBox/Editor/Scripts/default_shapes.py", scriptArgs); + "@engroot@/Gems/WhiteBox/Editor/Scripts/default_shapes.py", scriptArgs); EditorWhiteBoxComponentNotificationBus::Event( AZ::EntityComponentIdPair(GetEntityId(), GetId()), @@ -499,13 +500,13 @@ namespace WhiteBox static AZStd::string WhiteBoxPathAtProjectRoot(const AZStd::string_view name, const AZStd::string_view extension) { - const char* projectFolder = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - projectFolder, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); - - return AZStd::string::format( - "%s\\%.*s_whitebox.%.*s", projectFolder, aznumeric_cast(name.size()), name.data(), - aznumeric_cast(extension.size()), extension.data()); + AZ::IO::Path whiteBoxPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(whiteBoxPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); + } + whiteBoxPath /= AZ::IO::FixedMaxPathString::format("%.*s.%.*s", AZ_STRING_ARG(name), AZ_STRING_ARG(extension)); + return whiteBoxPath.Native(); } void EditorWhiteBoxComponent::ExportToFile() diff --git a/Registry/fileio.setreg b/Registry/fileio.setreg new file mode 100644 index 0000000000..d89e9f3f89 --- /dev/null +++ b/Registry/fileio.setreg @@ -0,0 +1,26 @@ +{ + "O3DE": { + "AzCore": { + "FileIO": { + "DeprecatedAliases": [ + { + "OldAlias": "@assets@", + "NewAlias": "@products@" + }, + { + "OldAlias": "@root@", + "NewAlias": "@products@" + }, + { + "OldAlias": "@devassets@", + "NewAlias": "@projectroot@" + }, + { + "OldAlias": "@devroot@", + "NewAlias": "@engroot@" + } + ] + } + } + } +} From 75b0b23fab66876d343edd33d38303ee208b9a33 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 5 Oct 2021 13:40:21 -0700 Subject: [PATCH 038/293] allow multiple single upgrade requests Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/Controller.cpp | 176 ++++++++++-------- .../Windows/Tools/UpgradeTool/Controller.h | 4 + .../View/Windows/Tools/UpgradeTool/Model.cpp | 26 ++- .../View/Windows/Tools/UpgradeTool/Model.h | 3 +- 4 files changed, 125 insertions(+), 84 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 207f70aec1..492759c341 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -88,6 +88,22 @@ namespace ScriptCanvasEditor LogBus::Broadcast(&LogTraits::Clear); } + void Controller::EnableAllUpgradeButtons() + { + for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) + { + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) + { + button->setEnabled(true); + } + } + } + + QList Controller::FindTableItems(const AZ::Data::AssetInfo& info) + { + return m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); + } + void Controller::OnButtonPressClose() { reject(); @@ -106,7 +122,7 @@ namespace ScriptCanvasEditor if (!scriptCanvasAsset) { AZ_Warning - ( ScriptCanvas::k_VersionExplorerWindow.data() + (ScriptCanvas::k_VersionExplorerWindow.data() , false , "InspectAsset: %s, AsestData failed to return ScriptCanvasAsset" , asset.GetHint().c_str()); @@ -184,7 +200,7 @@ namespace ScriptCanvasEditor if (graphComponent) { graphComponent->UpgradeGraph - ( asset + (asset , m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate , m_view->verbose->isChecked()); } @@ -195,7 +211,7 @@ namespace ScriptCanvasEditor { int result = QMessageBox::No; QMessageBox mb - ( QMessageBox::Warning + (QMessageBox::Warning , QObject::tr("Failed to Save Upgraded File") , QObject::tr("The upgraded file could not be saved because the file is read only.\n" "Do you want to make it writeable and overwrite it?") @@ -221,13 +237,14 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) { - QList items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); + QList items = FindTableItems(info); if (!items.isEmpty()) { for (auto* item : items) { int row = item->row(); SetRowBusy(row); + m_view->tableWidget->setCellWidget(row, ColumnAction, nullptr); } } } @@ -245,21 +262,23 @@ namespace ScriptCanvasEditor { VE_LOG("Failed to modify %s: %s", result.assetInfo.m_relativePath.c_str(), result.errorMessage.data()); } - - QList items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); - if (!items.isEmpty()) + + QList items = FindTableItems(info); + for (auto* item : items) { - for (auto* item : items) + int row = item->row(); + + if (result.errorMessage.empty()) { - int row = item->row(); + SetRowSucceeded(row); + } + else + { + SetRowFailed(row, ""); - if (result.errorMessage.empty()) + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) { - SetRowSucceeded(row); - } - else - { - SetRowFailed(row, ""); + button->setEnabled(false); } } } @@ -305,15 +324,6 @@ namespace ScriptCanvasEditor { m_view->onlyShowOutdated->setEnabled(true); - // Enable all the Upgrade buttons - for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) - { - if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) - { - button->setEnabled(true); - } - } - QString spinnerText = QStringLiteral("Scan Complete"); spinnerText.append(QString::asprintf(" - Discovered: %zu, Failed: %zu, Upgradeable: %zu, Up-to-date: %zu" , result.m_catalogAssets.size() @@ -324,6 +334,7 @@ namespace ScriptCanvasEditor m_view->spinner->SetText(spinnerText); SetSpinnerIsBusy(false); m_view->progressBar->setVisible(false); + EnableAllUpgradeButtons(); if (!result.m_unfiltered.empty()) { @@ -338,59 +349,67 @@ namespace ScriptCanvasEditor void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] Filtered filtered) { - m_view->tableWidget->insertRow(m_handledAssetCount); - QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); - m_view->tableWidget->setItem(m_handledAssetCount, static_cast(ColumnAsset), rowName); - SetRowSucceeded(m_handledAssetCount); + const int rowIndex = m_view->tableWidget->rowCount(); - if (filtered == Filtered::No) + if (filtered == Filtered::No || !m_view->onlyShowOutdated->isChecked()) { - QPushButton* rowGoToButton = new QPushButton(this); - rowGoToButton->setText("Upgrade"); - rowGoToButton->setEnabled(false); - SetRowBusy(m_handledAssetCount); - connect - ( rowGoToButton - , &QPushButton::pressed - , this - , [this, assetInfo]() + m_view->tableWidget->insertRow(rowIndex); + QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str())); + m_view->tableWidget->setItem(rowIndex, static_cast(ColumnAsset), rowName); + SetRowSucceeded(rowIndex); + + if (filtered == Filtered::No) + { + QPushButton* upgradeButton = new QPushButton(this); + upgradeButton->setText("Upgrade"); + upgradeButton->setEnabled(false); + SetRowBusy(rowIndex); + + connect + ( upgradeButton + , &QPushButton::pressed + , this + , [this, assetInfo]() { this->OnButtonPressUpgradeSingle(assetInfo); }); - m_view->tableWidget->setCellWidget(m_handledAssetCount, static_cast(ColumnAction), rowGoToButton); + + m_view->tableWidget->setCellWidget(rowIndex, static_cast(ColumnAction), upgradeButton); + } + + char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; + AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.m_relativePath.c_str()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); + AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); + AZ::StringFunc::Path::Normalize(path); + + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + QByteArray assetNameUtf8 = assetInfo.m_relativePath.c_str(); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult + ( result + , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath + , assetNameUtf8 + , info + , watchFolder); + AZ_Error + ( ScriptCanvas::k_VersionExplorerWindow.data() + , result + , "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); + + QToolButton* browseButton = new QToolButton(this); + browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); + browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); + + QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); + connect(browseButton, &QPushButton::clicked, [absolutePath] { + AzQtComponents::ShowFileOnDesktop(absolutePath); + }); + + m_view->tableWidget->setCellWidget(rowIndex, static_cast(ColumnBrowse), browseButton); } - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.m_relativePath.c_str()); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); - AZ::StringFunc::Path::Normalize(path); - - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - QByteArray assetNameUtf8 = assetInfo.m_relativePath.c_str(); - AzToolsFramework::AssetSystemRequestBus::BroadcastResult - ( result - , &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath - , assetNameUtf8 - , info - , watchFolder); - AZ_Error - ( ScriptCanvas::k_VersionExplorerWindow.data() - , result - , "Failed to locate asset info for '%s'.", assetNameUtf8.constData()); - - QToolButton* browseButton = new QToolButton(this); - browseButton->setToolTip(AzQtComponents::fileBrowserActionName()); - browseButton->setIcon(QIcon(":/stylesheet/img/UI20/browse-edit.svg")); - - QString absolutePath = QDir(watchFolder.c_str()).absoluteFilePath(info.m_relativePath.c_str()); - connect(browseButton, &QPushButton::clicked, [absolutePath] { - AzQtComponents::ShowFileOnDesktop(absolutePath); - }); - - m_view->tableWidget->setCellWidget(m_handledAssetCount, static_cast(ColumnBrowse), browseButton); OnScannedGraphResult(assetInfo); } @@ -403,11 +422,12 @@ namespace ScriptCanvasEditor void Controller::OnScanLoadFailure(const AZ::Data::AssetInfo& info) { - m_view->tableWidget->insertRow(m_handledAssetCount); + const int rowIndex = m_view->tableWidget->rowCount(); + m_view->tableWidget->insertRow(rowIndex); QTableWidgetItem* rowName = new QTableWidgetItem ( tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str())); - m_view->tableWidget->setItem(m_handledAssetCount, static_cast(ColumnAsset), rowName); - SetRowFailed(m_handledAssetCount, "Load failed"); + m_view->tableWidget->setItem(rowIndex, static_cast(ColumnAsset), rowName); + SetRowFailed(rowIndex, "Load failed"); OnScannedGraphResult(info); } @@ -425,8 +445,9 @@ namespace ScriptCanvasEditor if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) { button->setEnabled(false); - SetRowBusy(row); } + + SetRowBusy(row); } QString spinnerText = QStringLiteral("Upgrade in progress - "); @@ -464,6 +485,8 @@ namespace ScriptCanvasEditor m_view->spinner->SetText(spinnerText); SetSpinnerIsBusy(false); AddLogEntries(); + EnableAllUpgradeButtons(); + m_view->scanButton->setEnabled(true); } void Controller::OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) @@ -483,6 +506,11 @@ namespace ScriptCanvasEditor { SetRowFailed(row, ""); } + + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) + { + button->setEnabled(true); + } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 23f35840be..ac18ff6cf5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -22,6 +22,7 @@ AZ_POP_DISABLE_WARNING #endif class QPushButton; +class QTableWidgetItem; namespace Ui { @@ -61,6 +62,9 @@ namespace ScriptCanvasEditor int m_handledAssetCount = 0; void AddLogEntries(); + void EnableAllUpgradeButtons(); + QList FindTableItems(const AZ::Data::AssetInfo& assetInfo); + void OnButtonPressClose(); void OnButtonPressScan(); void OnButtonPressUpgrade(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp index 98edef54bf..d8d242adbb 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.cpp @@ -101,9 +101,9 @@ namespace ScriptCanvasEditor return; } - auto results = m_scanner->TakeResult(); if (modification.modifySingleAsset.m_assetId.IsValid()) { + const auto& results = m_scanner->GetResult(); auto iter = AZStd::find_if ( results.m_unfiltered.begin() , results.m_unfiltered.end() @@ -118,24 +118,32 @@ namespace ScriptCanvasEditor return; } - WorkingAsset singleEntry = *iter; - results.m_unfiltered.clear(); - results.m_unfiltered.push_back(singleEntry); + + m_state = State::ModifySingle; + m_modifier = AZStd::make_unique(modification, WorkingAssets{ *iter }, [this]() { OnModificationComplete(); }); + } + else + { + auto results = m_scanner->TakeResult(); + m_state = State::ModifyAll; + m_modifier = AZStd::make_unique(modification, AZStd::move(results.m_unfiltered), [this]() { OnModificationComplete(); }); } m_modResults = {}; - m_state = State::Modifying; m_log.Activate(); - m_keepEditorAlive = AZStd::make_unique(); - - m_modifier = AZStd::make_unique(modification, AZStd::move(results.m_unfiltered), [this](){ OnModificationComplete(); }); + m_keepEditorAlive = AZStd::make_unique(); } void Model::OnModificationComplete() { ModelNotificationsBus::Broadcast(&ModelNotificationsTraits::OnUpgradeComplete, m_modifier->GetResult()); m_modifier.reset(); - m_scanner.reset(); + + if (m_state == State::ModifyAll) + { + m_scanner.reset(); + } + Idle(); } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h index e11f8857e7..58ad9877be 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h @@ -54,7 +54,8 @@ namespace ScriptCanvasEditor { Idle, Scanning, - Modifying, + ModifyAll, + ModifySingle }; State m_state = State::Idle; From 09342694c92dd90386b24f3c2f78c0aa3ebdfd89 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Tue, 5 Oct 2021 13:49:27 -0700 Subject: [PATCH 039/293] Fix issues with adding a repo and make each object type optional in repo.json Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/register.py | 7 +++-- scripts/o3de/o3de/repo.py | 58 +++++++++++++++++++++++++++++------ scripts/o3de/o3de/utils.py | 8 +++-- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 7db09368ec..c3d201f23c 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -487,14 +487,14 @@ def register_repo(json_data: dict, if remove: logger.warn(f'Removing repo uri {repo_uri}.') return 0 - repo_sha256 = hashlib.sha256(url.encode()) cache_file = manifest.get_o3de_cache_folder() / str(repo_sha256.hexdigest() + '.json') - result = utils.download_file(url, cache_file) + result = utils.download_file(parsed_uri, cache_file) if result == 0: - json_data['repos'].insert(0, repo_uri.as_posix()) + json_data['repos'].insert(0, repo_uri) + repo_set = set() result = repo.process_add_o3de_repo(cache_file, repo_set) return result @@ -621,6 +621,7 @@ def register(engine_path: pathlib.Path = None, return 1 result = result or register_gem_path(json_data, gem_path, remove, external_subdir_engine_path, external_subdir_project_path) + if isinstance(external_subdir_path, pathlib.PurePath): if not external_subdir_path: logger.error(f'External Subdirectory path is None.') diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index 8492f391e5..39fe79bbc2 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -12,6 +12,7 @@ import pathlib import shutil import urllib.parse import urllib.request +import hashlib from o3de import manifest, utils, validation @@ -24,7 +25,6 @@ def process_add_o3de_repo(file_name: str or pathlib.Path, file_name = pathlib.Path(file_name).resolve() if not validation.valid_o3de_repo_json(file_name): return 1 - cache_folder = manifest.get_o3de_cache_folder() with file_name.open('r') as f: @@ -34,11 +34,30 @@ def process_add_o3de_repo(file_name: str or pathlib.Path, logger.error(f'{file_name} failed to load: {str(e)}') return 1 - for o3de_object_uris, manifest_json in [(repo_data['engines'], 'engine.json'), - (repo_data['projects'], 'project.json'), - (repo_data['gems'], 'gem.json'), - (repo_data['template'], 'template.json'), - (repo_data['restricted'], 'restricted.json')]: + # A repo may not contain all types of object. + manifest_download_list = [] + try: + manifest_download_list.append((repo_data['engines'], 'engine.json')) + except Exception: + pass + try: + manifest_download_list.append((repo_data['projects'], 'project.json')) + except Exception: + pass + try: + manifest_download_list.append((repo_data['gems'], 'gem.json')) + except Exception: + pass + try: + manifest_download_list.append((repo_data['templates'], 'template.json')) + except Exception: + pass + try: + manifest_download_list.append((repo_data['restricted'], 'restricted.json')) + except Exception: + pass + + for o3de_object_uris, manifest_json in manifest_download_list: for o3de_object_uri in o3de_object_uris: manifest_json_uri = f'{o3de_object_uri}/{manifest_json}' manifest_json_sha256 = hashlib.sha256(manifest_json_uri.encode()) @@ -49,7 +68,27 @@ def process_add_o3de_repo(file_name: str or pathlib.Path, if download_file_result != 0: return download_file_result - repo_set |= repo_data['repos'] + # Having a repo is also optional + repo_list = [] + try: + repo_list.add(repo_data['repos']) + except Exception: + pass + + for repo in repo_list: + if repo not in repo_set: + repo_set.add(repo) + for o3de_object_uri in o3de_object_uris: + parsed_uri = urllib.parse.urlparse(f'{repo}/repo.json') + manifest_json_sha256 = hashlib.sha256(parsed_uri.geturl().encode()) + cache_file = cache_folder / str(manifest_json_sha256.hexdigest() + '.json') + if cache_file.is_file(): + cache_file.unlink() + download_file_result = utils.download_file(parsed_uri, cache_file) + if download_file_result != 0: + return download_file_result + + return process_add_o3de_repo(parsed_uri.geturl(), repo_set) return 0 @@ -70,11 +109,10 @@ def refresh_repos() -> int: if repo_uri not in repo_set: repo_set.add(repo_uri) - repo_uri = f'{repo_uri}/repo.json' - repo_sha256 = hashlib.sha256(repo_uri.encode()) + parsed_uri = urllib.parse.urlparse(f'{repo_uri}/repo.json') + repo_sha256 = hashlib.sha256(parsed_uri.geturl().encode()) cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') if not cache_file.is_file(): - parsed_uri = urllib.parse.urlparse(repo_uri) download_file_result = utils.download_file(parsed_uri, cache_file) if download_file_result != 0: return download_file_result diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 18f80584cc..9f9c747390 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -13,6 +13,10 @@ import uuid import pathlib import shutil import urllib.request +import logging + +logger = logging.getLogger() +logging.basicConfig() def validate_identifier(identifier: str) -> bool: """ @@ -97,11 +101,11 @@ def download_file(parsed_uri, download_path: pathlib.Path) -> int: if download_path.is_file(): logger.warn(f'File already downloaded to {download_path}.') elif parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: - with urllib.request.urlopen(url) as s: + with urllib.request.urlopen(parsed_uri.geturl()) as s: with download_path.open('wb') as f: shutil.copyfileobj(s, f) else: - origin_file = pathlib.Path(url).resolve() + origin_file = pathlib.Path(parsed_uri.geturl()).resolve() if not origin_file.is_file(): return 1 shutil.copy(origin_file, download_path) From e5a7315de439efbc58b65d8ad544a1b32fbe52f3 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Tue, 5 Oct 2021 14:59:50 -0600 Subject: [PATCH 040/293] Auto-expand input mappings. (#4501) Signed-off-by: bosnichd --- .../AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp | 1 + .../AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp index 6837807f4e..a24860fd34 100644 --- a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp +++ b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp @@ -35,6 +35,7 @@ namespace AzFramework ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &InputMappingAnd::Config::GetNameLabelOverride) ->DataElement(AZ::Edit::UIHandlers::Default, &Config::m_sourceInputChannelNames, "Source Input Channel Names", "The source input channel names that will be mapped to the output input channel name.") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } } diff --git a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp index bc47065c05..7c983766c8 100644 --- a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp +++ b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp @@ -35,6 +35,7 @@ namespace AzFramework ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &InputMappingOr::Config::GetNameLabelOverride) ->DataElement(AZ::Edit::UIHandlers::Default, &Config::m_sourceInputChannelNames, "Source Input Channel Names", "The source input channel names that will be mapped to the output input channel name.") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } } From 64fa92c56dc36e156d437a55e756514cbdec6782 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Tue, 5 Oct 2021 14:41:20 -0700 Subject: [PATCH 041/293] Constrain exceptions to the type we are handling. Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/repo.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index 39fe79bbc2..52abfc3386 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -38,23 +38,23 @@ def process_add_o3de_repo(file_name: str or pathlib.Path, manifest_download_list = [] try: manifest_download_list.append((repo_data['engines'], 'engine.json')) - except Exception: + except KeyError: pass try: manifest_download_list.append((repo_data['projects'], 'project.json')) - except Exception: + except KeyError: pass try: manifest_download_list.append((repo_data['gems'], 'gem.json')) - except Exception: + except KeyError: pass try: manifest_download_list.append((repo_data['templates'], 'template.json')) - except Exception: + except KeyError: pass try: manifest_download_list.append((repo_data['restricted'], 'restricted.json')) - except Exception: + except KeyError: pass for o3de_object_uris, manifest_json in manifest_download_list: @@ -72,7 +72,7 @@ def process_add_o3de_repo(file_name: str or pathlib.Path, repo_list = [] try: repo_list.add(repo_data['repos']) - except Exception: + except KeyError: pass for repo in repo_list: From ac836da605fe23e0322f8d95875d66a8f13c76b4 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:43:19 -0700 Subject: [PATCH 042/293] disable upgrade all button until disparity from single upgrade is discovered Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Windows/Tools/UpgradeTool/Controller.cpp | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 492759c341..6fa0f1adfa 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -54,6 +54,7 @@ namespace ScriptCanvasEditor m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn); connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnButtonPressScan); connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnButtonPressClose); + m_view->upgradeAllButton->setVisible(false); connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnButtonPressUpgrade); m_view->progressBar->setValue(0); m_view->progressBar->setVisible(false); @@ -237,15 +238,11 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info) { - QList items = FindTableItems(info); - if (!items.isEmpty()) + for (auto* item : FindTableItems(info)) { - for (auto* item : items) - { - int row = item->row(); - SetRowBusy(row); - m_view->tableWidget->setCellWidget(row, ColumnAction, nullptr); - } + int row = item->row(); + SetRowBusy(row); + m_view->tableWidget->setCellWidget(row, ColumnAction, nullptr); } } @@ -263,8 +260,7 @@ namespace ScriptCanvasEditor VE_LOG("Failed to modify %s: %s", result.assetInfo.m_relativePath.c_str(), result.errorMessage.data()); } - QList items = FindTableItems(info); - for (auto* item : items) + for (auto* item : FindTableItems(info)) { int row = item->row(); @@ -440,23 +436,32 @@ namespace ScriptCanvasEditor ( const ModifyConfiguration& config , [[maybe_unused]] const WorkingAssets& assets) { - for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) - { - if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) - { - button->setEnabled(false); - } - - SetRowBusy(row); - } - QString spinnerText = QStringLiteral("Upgrade in progress - "); if (config.modifySingleAsset.m_assetId.IsValid()) { spinnerText.append(" single graph"); + + if (assets.size() == 1) + { + for (auto* item : FindTableItems(assets.front().info)) + { + int row = item->row(); + SetRowBusy(row); + } + } } else { + for (int row = 0; row < m_view->tableWidget->rowCount(); ++row) + { + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) + { + button->setEnabled(false); + } + + SetRowBusy(row); + } + spinnerText.append(" all scanned graphs"); } @@ -491,26 +496,22 @@ namespace ScriptCanvasEditor void Controller::OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result) { - QList items = m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly); - if (!items.isEmpty()) + for (auto* item : FindTableItems(info)) { - for (auto* item : items) - { - int row = item->row(); + int row = item->row(); - if (result == Result::Success) - { - SetRowSucceeded(row); - } - else - { - SetRowFailed(row, ""); - } + if (result == Result::Success) + { + SetRowSucceeded(row); + } + else + { + SetRowFailed(row, ""); + } - if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) - { - button->setEnabled(true); - } + if (QPushButton* button = qobject_cast(m_view->tableWidget->cellWidget(row, ColumnAction))) + { + button->setEnabled(true); } } From 84f28033a052553ebf69ca91d4efabff6d33f367 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:43:30 -0700 Subject: [PATCH 043/293] ATOM-16249 Adding draw srg caching to DynamicDrawContext since creating SRG can be expensive for some backend (#4491) * ATOM-16249 Adding draw srg caching to DynamicDrawContext since creating SRG can be expensive for some backend Signed-off-by: Qing Tao --- .../Atom/RHI/ShaderResourceGroupData.h | 4 +++ .../Source/RHI/ShaderResourceGroupData.cpp | 8 ++++++ .../DynamicDraw/DynamicDrawContext.h | 2 ++ .../RPI.Public/Shader/ShaderResourceGroup.h | 3 ++ .../DynamicDraw/DynamicDrawContext.cpp | 28 +++++++++++++++---- .../RPI.Public/Shader/ShaderResourceGroup.cpp | 5 ++++ 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h index 0ce43159f6..cbb0db53c8 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h @@ -166,6 +166,10 @@ namespace AZ AZStd::array_view> GetImageGroup() const; AZStd::array_view> GetBufferGroup() const; AZStd::array_view GetSamplerGroup() const; + + //! Reset image and buffer views setup for this ShaderResourceGroupData + //! So it won't hold references for any RHI resources + void ResetViews(); //! Returns the opaque constant data populated by calls to SetConstant and SetConstantData. //! diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp index da7697d8f2..18b292ac64 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp @@ -330,6 +330,14 @@ namespace AZ return m_samplers; } + void ShaderResourceGroupData::ResetViews() + { + m_imageViews.assign(m_imageViews.size(), nullptr); + m_bufferViews.assign(m_bufferViews.size(), nullptr); + m_imageViewsUnboundedArray.assign(m_imageViewsUnboundedArray.size(), nullptr); + m_bufferViewsUnboundedArray.assign(m_bufferViewsUnboundedArray.size(), nullptr); + } + AZStd::array_view ShaderResourceGroupData::GetConstantData() const { return m_constantsData.GetConstantData(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h index 93e595243e..c35d0750a5 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h @@ -268,6 +268,8 @@ namespace AZ AZStd::vector m_cachedStreamBufferViews; AZStd::vector m_cachedIndexBufferViews; AZStd::vector> m_cachedDrawSrg; + + uint32_t m_nextDrawSrgIdx = 0; // structure includes DrawItem and stream and index buffer index using BufferViewIndexType = uint32_t; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h index b2cea448c1..99f1f5f598 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h @@ -133,6 +133,9 @@ namespace AZ /// Returns an array of RPI buffers associated with the buffer shader input index. AZStd::array_view> GetBufferArray(RHI::ShaderInputNameIndex& inputIndex) const; AZStd::array_view> GetBufferArray(RHI::ShaderInputBufferIndex inputIndex) const; + + //! Reset image and buffer views so that it won't hold references for any RHI resources + void ResetViews(); ////////////////////////////////////////////////////////////////////////// // Methods for assignment / access of RHI Image types. diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp index 4da85823b3..3b3473a2da 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp @@ -518,7 +518,6 @@ namespace AZ if (drawSrg) { drawItem.m_uniqueShaderResourceGroup = drawSrg->GetRHIShaderResourceGroup(); - m_cachedDrawSrg.push_back(drawSrg); } // Set scissor per draw if scissor is enabled. @@ -608,7 +607,6 @@ namespace AZ if (drawSrg) { drawItem.m_uniqueShaderResourceGroup = drawSrg->GetRHIShaderResourceGroup(); - m_cachedDrawSrg.push_back(drawSrg); } // Set scissor per draw if scissor is enabled. @@ -635,7 +633,22 @@ namespace AZ { return nullptr; } - auto drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName()); + + Data::Instance drawSrg; + if (m_nextDrawSrgIdx == m_cachedDrawSrg.size()) + { + drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName()); + m_cachedDrawSrg.push_back(drawSrg); + } + else if (m_nextDrawSrgIdx < m_cachedDrawSrg.size()) + { + drawSrg = m_cachedDrawSrg[m_nextDrawSrgIdx]; + } + else + { + AZ_Assert(false, "Unexpected next draw srg index"); + } + m_nextDrawSrgIdx++; // Set fallback value for shader variant if draw srg contains constant for shader variant fallback if (m_hasShaderVariantKeyFallbackEntry) @@ -727,7 +740,7 @@ namespace AZ } for (auto& drawItemProperties : m_cachedDrawList) - { + { view->AddDrawItem(m_drawListTag, drawItemProperties); } } @@ -743,9 +756,14 @@ namespace AZ m_cachedDrawItems.clear(); m_cachedStreamBufferViews.clear(); m_cachedIndexBufferViews.clear(); - m_cachedDrawSrg.clear(); m_cachedDrawList.clear(); + m_nextDrawSrgIdx = 0; m_drawFinalized = false; + + for (auto srg:m_cachedDrawSrg) + { + srg->ResetViews(); + } } const RHI::PipelineState* DynamicDrawContext::GetCurrentPipelineState() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp index 499365a9a9..f95c6abfcd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp @@ -580,6 +580,11 @@ namespace AZ return {}; } + void ShaderResourceGroup::ResetViews() + { + m_data.ResetViews(); + } + const RHI::SamplerState& ShaderResourceGroup::GetSampler(RHI::ShaderInputNameIndex& inputIndex, uint32_t arrayIndex) const { inputIndex.ValidateOrFindSamplerIndex(GetLayout()); From f1fe2912e45ba6e493ba0fee3e6edd4876ccfc20 Mon Sep 17 00:00:00 2001 From: kritin Date: Tue, 5 Oct 2021 14:54:07 -0700 Subject: [PATCH 044/293] responded to code reviews Signed-off-by: kritin --- ...flows_ExistingLevel_EntityComponentCRUD.py | 82 +++------- .../EditorScripts/Sample_Editor_Tests.py | 143 ------------------ .../editor/TestSuite_Main_Optimized.py | 2 +- 3 files changed, 21 insertions(+), 206 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py index 451b3a6714..803b9e9a11 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py @@ -53,40 +53,19 @@ def BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD(): 03. create child entity and set a name 04. delete child entity 05. add mesh component to parent entity - 06. remove mesh component 07. delete parent entity Close editor without saving """ import os from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper - import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.editor_entity_utils import EditorEntity - import azlmbr.math as math - import azlmbr.asset as asset import azlmbr.bus as bus import azlmbr.editor as editor import azlmbr.entity as entity import azlmbr.legacy.general as general import azlmbr.object - def search_entity(entity_to_search, entity_name): - """ - - :param entity_to_search: entity to be searched - :param entity_name: name of the entity used in the set command - :return: True if entity id exists in the entity_list - False if entity id does not exist in the entity_list - """ - entity_list = [] - entity_search_filter = entity.SearchFilter() - entity_search_filter.names = entity_name - entity_list = entity.SearchBus(bus.Broadcast, 'SearchEntities', entity_search_filter) - if entity_list: - if entity_to_search in entity_list: - return True - return False - return False # 01. load an existing level @@ -94,60 +73,39 @@ def BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD(): general.open_level_no_prompt(test_level) Report.result(Tests.load_level, general.get_current_level_name() == test_level) + # 02. create parent entity and set name # Delete any exiting entity and Create a new Entity at the root level + search_filter = azlmbr.entity.SearchFilter() all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) - parent_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", entity.EntityId()) - Report.result(Tests.create_entity, parent_entity.IsValid()) + parent_entity = EditorEntity.create_editor_entity("Parent_1") + Report.result(Tests.create_entity, parent_entity.exists()) - # Setting a new name - parent_entity_name = "Parent_1" - editor.EditorEntityAPIBus(bus.Event, 'SetName', parent_entity, parent_entity_name) - Report.result(Tests.set_entity_name, - editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', parent_entity) == parent_entity_name) # 03. Create child Entity to above created parent entity and set a name - child_1_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', parent_entity) - Report.result(Tests.create_child_entity, child_1_entity.IsValid()) - child_entity_name = "Child_1" - editor.EditorEntityAPIBus(bus.Event, 'SetName', child_1_entity, child_entity_name) - Report.result(Tests.set_entity_name, - editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', child_1_entity) == child_entity_name) + + child_1_entity = EditorEntity.create_editor_entity("Child_1", parent_entity.id ) + Report.result(Tests.create_child_entity, child_1_entity.exists()) + # 04. delete_Child_entity - editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', child_1_entity) - Report.result(Tests.delete_child_entity, search_entity(child_1_entity, "Child_1") == False) + + child_1_entity.delete() + Report.result(Tests.delete_child_entity, not child_1_entity.exists()) + # 05. add mesh component to parent entity - type_id_list = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Mesh"], - entity.EntityType().Game) - if type_id_list is not None: - component_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', parent_entity, - type_id_list) - Report.result(Tests.add_mesh_component, component_outcome.IsSuccess()) - else: - Report.result(Tests.found_component_typeId, type_id_list is not None) - - # 06. remove mesh component - outcome_get_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', parent_entity, - type_id_list[0]) - if outcome_get_component.IsSuccess(): - component_entity_pair = outcome_get_component.GetValue() - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component_entity_pair]) - component_exists = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', parent_entity, - type_id_list[0]) - mesh_test = True - if component_exists: - mesh_test = False - Report.result(Tests.remove_mesh_component, mesh_test) - else: - Report.result(Tests.found_component_typeId, outcome_get_component.IsSuccess()) + + parent_entity.add_component("Mesh") + Report.result(Tests.add_mesh_component, parent_entity.has_component("Mesh")) + # 7. delete parent entity - editor.ToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'DeleteEntityById', parent_entity) - Report.result(Tests.delete_entity, search_entity(parent_entity, "Parent_1") == False) + + parent_entity.delete() + Report.result(Tests.delete_entity, not parent_entity.exists()) # Close editor without saving editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt') diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py deleted file mode 100644 index 746c0a936d..0000000000 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Sample_Editor_Tests.py +++ /dev/null @@ -1,143 +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 - -Test Case: Creating tests for basic editor feature like creating a level, adding new entities, modifying the entities etc. -""" - - -class Tests: - create_level = ("Level created and loaded successfully", "Failed to create the level") - open_level = ("Level loaded successfully", "Failed to load the level") - create_entity = ("Parent entity created successfully", "Failed to create a parent entity") - set_entity_name = ("Entity name set successfully", "Failed to set entity name") - delete_entity = ("Parent entity deleted successfully", "Failed to delete parent entity") - game_mode_enter = ("Game Mode entered successfully", "Failed to enter the game mode") - game_mode_exit = ("Game mode exited successfully", "Failed to exit game mode") - create_child_entity = ("Child entity created successfully", "Failed to create a child entity") - delete_child_entity = ("Child entity deleted successfully", "Failed to delete child entity") - add_mesh_component = ("Mesh component added successfully", "Failed to add mesh component") - found_component_typeId = ("Found component typeId", "Unable to find component TypeId") - remove_mesh_component = ("Mesh component removed successfully", "Failed to remove mesh component") - - -def sample_editor_tests(): - """ - Performing basic test in editor - 01. create_level if it does not exist else 02. open exiting level - - 03. create parent entity and set name - 04. create child entity - 05. delete child entity - 06. add mesh component - 07. remove mesh component - 08. enter game mode - 09. exit game_mode - 10. delete parent entity - 11. save level - - """ - import os - from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper - import editor_python_test_tools.hydra_editor_utils as hydra - - import azlmbr.math as math - import azlmbr.asset as asset - import azlmbr.bus as bus - import azlmbr.editor as editor - import azlmbr.entity as entity - import azlmbr.legacy.general as general - import azlmbr.object - - def search_entity(entity_to_search, entity_name): - """ - - :param entity_to_search: entity to be searched - :param entity_name: name of the entity used in the set command - :return: True if entity id exists in the entity_list - False if entity id does not exist in the entity_list - """ - entity_list = [] - entity_search_filter = entity.SearchFilter() - entity_search_filter.names = entity_name - entity_list = entity.SearchBus(bus.Broadcast, 'SearchEntities', entity_search_filter) - if entity_list: - if entity_to_search in entity_list: - return True - return False - return False - - # 01. create_level - - test_level = 'Simple' - general.open_level_no_prompt(test_level) - Report.result(Tests.create_level, general.get_current_level_name() == test_level) - - # 02. load existing level - skipping this since this could alter existing level that other test depends on - - # 03. create_entity and set name - # Delete any exiting entity and Create a new Entity at the root level - search_filter = azlmbr.entity.SearchFilter() - all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) - editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) - parent_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", entity.EntityId()) - Report.result(Tests.create_entity, parent_entity.IsValid()) - - # Setting a new name - parent_entity_name = "Parent_1" - editor.EditorEntityAPIBus(bus.Event, 'SetName', parent_entity, parent_entity_name) - Report.result(Tests.set_entity_name, - editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', parent_entity) == parent_entity_name) - - # 04. Creating child Entity and setting name to above created parent entity - child_1_entity = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', parent_entity) - Report.result(Tests.create_child_entity, child_1_entity.IsValid()) - child_entity_name = "Child_1" - editor.EditorEntityAPIBus(bus.Event, 'SetName', child_1_entity, child_entity_name) - Report.result(Tests.set_entity_name, - editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', child_1_entity) == child_entity_name) - - # 05. delete_Child_entity - editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', child_1_entity) - Report.result(Tests.delete_entity, search_entity(child_1_entity, "Child_1") == False) - - # 06. add mesh component to parent entity - type_id_list = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Mesh"], - entity.EntityType().Game) - if type_id_list is not None: - component_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', parent_entity, - type_id_list) - Report.result(Tests.add_mesh_component, component_outcome.IsSuccess()) - else: - Report.result(Tests.found_component_typeId, type_id_list is not None) - - # 09. remove mesh component - outcome_get_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', parent_entity, - type_id_list[0]) - if outcome_get_component.IsSuccess(): - component_entity_pair = outcome_get_component.GetValue() - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component_entity_pair]) - component_exists = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', parent_entity, - type_id_list[0]) - mesh_test = True - if component_exists: - mesh_test = False - Report.result(Tests.remove_mesh_component, mesh_test) - else: - Report.result(Tests.found_component_typeId, outcome_get_component.IsSuccess()) - - # 10. delete parent entity - editor.ToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'DeleteEntityById', parent_entity) - Report.result(Tests.delete_entity, search_entity(parent_entity, "Parent_1") == False) - - # Close editor without saving - editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt') - - -if __name__ == "__main__": - from editor_python_test_tools.utils import Report - - Report.start_test(sample_editor_tests) diff --git a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py index 755f75216b..afc52f962d 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py @@ -75,5 +75,5 @@ class TestAutomationAutoTestMode(EditorTestSuite): from .EditorScripts import Menus_FileMenuOptions as test_module - class test_Sample_Editor_Tests(EditorSharedTest): + class test_BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD(EditorSharedTest): from .EditorScripts import BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD as test_module From be166d68b8313397c8c79a36630f4f84bdc255d7 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Wed, 29 Sep 2021 16:16:29 -0500 Subject: [PATCH 045/293] Reduce the default worker thread priority for the Job system, Job system is now aimed at long running or idle tasks Add cvars to control the number of worker threads created by the TaskGraph and Job systems. The cvars are scales on the hw concurrency of the cpu. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- .../Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp | 9 +++++++-- Code/Framework/AzCore/AzCore/Jobs/JobManagerDesc.h | 2 +- Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp | 4 ++-- .../AzCore/AzCore/Task/TaskGraphSystemComponent.cpp | 8 ++++++-- .../AzCore/std/parallel/internal/thread_UnixLike.cpp | 4 ++++ 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp index 25dfc7a493..2cd740bf9e 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp @@ -18,6 +18,11 @@ #include #include +#include + +AZ_CVAR(uint32_t, cl_numeratorJobThreads, 1, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system multiplier on the number of hw threads the machine supports to create at initialization"); +AZ_CVAR(uint32_t, cl_denominatorJobThreads, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system divisor on the number of hw threads the machine supports to create at initialization"); + namespace AZ { //========================================================================= @@ -46,9 +51,9 @@ namespace AZ JobManagerThreadDesc threadDesc; int numberOfWorkerThreads = m_numberOfWorkerThreads; - if (numberOfWorkerThreads <= 0) + if (numberOfWorkerThreads <= 0) // spawn default number of threads { - numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), AZStd::thread::hardware_concurrency()); + numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), cl_numeratorJobThreads * AZStd::thread::hardware_concurrency() / cl_denominatorJobThreads); #if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS); #endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerDesc.h b/Code/Framework/AzCore/AzCore/Jobs/JobManagerDesc.h index 5594d7aa15..94f84f27b3 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerDesc.h +++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerDesc.h @@ -36,7 +36,7 @@ namespace AZ */ int m_stackSize; - JobManagerThreadDesc(int cpuId = -1, int priority = -100000, int stackSize = -1) + JobManagerThreadDesc(int cpuId = -1, int priority = 0, int stackSize = -1) : m_cpuId(cpuId) , m_priority(priority) , m_stackSize(stackSize) diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp index 7da04d7301..4097348798 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp @@ -308,11 +308,11 @@ namespace AZ void TaskExecutor::SetInstance(TaskExecutor* executor) { - if (!executor) + if (!executor) // allow unsetting the executor { s_executor.Reset(); } - else if (!s_executor) // ignore any calls to set after the first (this happens in unit tests that create new system entities) + else if (!s_executor) // ignore any extra executors after the first (this happens during unit tests) { s_executor = AZ::Environment::CreateVariable(s_executorName, executor); } diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp index eed461ecb4..198969dbce 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -14,6 +14,9 @@ // Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system. AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)"); +AZ_CVAR(uint32_t, cl_numeratorTaskGraphThreads, 3, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph multiplier on the number of hw threads the machine supports to create at initialization"); +AZ_CVAR(uint32_t, cl_denominatorTaskGraphThreads, 4, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph divisor on the number of hw threads the machine supports to create at initialization"); + static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService"); namespace AZ @@ -24,9 +27,10 @@ namespace AZ if (Interface::Get() == nullptr) { - Interface::Register(this); - m_taskExecutor = aznew TaskExecutor(); + uint32_t numThreads = cl_numeratorTaskGraphThreads * AZStd::thread::hardware_concurrency() / cl_denominatorTaskGraphThreads; + m_taskExecutor = aznew TaskExecutor(numThreads); TaskExecutor::SetInstance(m_taskExecutor); + Interface::Register(this); } } diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.cpp index 079f167408..b615f677f1 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.cpp @@ -59,6 +59,10 @@ namespace AZStd { priority = desc->m_priority; } + else + { + priority = SCHED_OTHER; + } if (desc->m_name) { name = desc->m_name; From 502513f08112fd41e752756de4c9f376231af960 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 5 Oct 2021 15:05:04 -0700 Subject: [PATCH 046/293] remove superflous comment Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp index 665a481a17..7d4cfec909 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp @@ -110,14 +110,12 @@ namespace ScriptCanvasBuilder const ScriptCanvas::Translation::Result translationResult = TranslateToLua(request); auto isSuccessOutcome = translationResult.IsSuccess(ScriptCanvas::Translation::TargetFlags::Lua); - if (!isSuccessOutcome.IsSuccess()) { - // sanity check return AZ::Failure(isSuccessOutcome.TakeError()); } - auto& translation = translationResult.m_translations.find(ScriptCanvas::Translation::TargetFlags::Lua)->second; + auto& translation = translationResult.m_translations.find(ScriptCanvas::Translation::TargetFlags::Lua)->second; AZ::Data::Asset asset; scriptAssetId.m_subId = AZ::ScriptAsset::CompiledAssetSubId; asset.Create(scriptAssetId); From 977d58e1a8f0a3b68a229191ef9c252814fc8538 Mon Sep 17 00:00:00 2001 From: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Tue, 5 Oct 2021 15:20:26 -0700 Subject: [PATCH 047/293] Update ZLIB min req osx ios and android to reasonable limits (#4473) This also updates the name of the zlib library to uppercase ZLIB which conforms to normal CMake standards . Signed-off-by: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> --- Code/Editor/CMakeLists.txt | 2 -- Code/Editor/Plugins/EditorCommon/CMakeLists.txt | 1 - Code/Framework/AzCore/CMakeLists.txt | 2 +- Code/Framework/AzFramework/CMakeLists.txt | 1 - Code/Framework/AzNetworking/CMakeLists.txt | 1 - Code/Legacy/CrySystem/CMakeLists.txt | 1 - cmake/3rdParty/BuiltInPackages.cmake | 11 ++++++++++- .../Platform/Android/BuiltInPackages_android.cmake | 2 +- .../Platform/Linux/BuiltInPackages_linux.cmake | 2 +- cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 2 +- .../Platform/Windows/BuiltInPackages_windows.cmake | 2 +- cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake | 2 +- 12 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index 5884795413..2ea0aa1a74 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Legacy::CryCommon - 3rdParty::zlib PUBLIC 3rdParty::Qt::Core 3rdParty::Qt::Gui @@ -105,7 +104,6 @@ ly_add_target( 3rdParty::Qt::Concurrent 3rdParty::tiff 3rdParty::squish-ccr - 3rdParty::zlib 3rdParty::AWSNativeSDK::STS Legacy::CryCommon Legacy::EditorCommon diff --git a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt index cd9f2e79c7..609482b581 100644 --- a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt +++ b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt @@ -39,7 +39,6 @@ ly_add_target( EDITOR_COMMON_IMPORTS BUILD_DEPENDENCIES PRIVATE - 3rdParty::zlib 3rdParty::Qt::Core 3rdParty::Qt::Widgets Legacy::CryCommon diff --git a/Code/Framework/AzCore/CMakeLists.txt b/Code/Framework/AzCore/CMakeLists.txt index 60c5f50594..96ed838ccc 100644 --- a/Code/Framework/AzCore/CMakeLists.txt +++ b/Code/Framework/AzCore/CMakeLists.txt @@ -39,7 +39,7 @@ ly_add_target( 3rdParty::Lua 3rdParty::RapidJSON 3rdParty::RapidXML - 3rdParty::zlib + 3rdParty::ZLIB 3rdParty::zstd 3rdParty::cityhash ${AZ_CORE_PIX_BUILD_DEPENDENCIES} diff --git a/Code/Framework/AzFramework/CMakeLists.txt b/Code/Framework/AzFramework/CMakeLists.txt index 59393d90a1..b22586162b 100644 --- a/Code/Framework/AzFramework/CMakeLists.txt +++ b/Code/Framework/AzFramework/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( AZ::AzCore PUBLIC AZ::GridMate - 3rdParty::zlib 3rdParty::zstd 3rdParty::lz4 ) diff --git a/Code/Framework/AzNetworking/CMakeLists.txt b/Code/Framework/AzNetworking/CMakeLists.txt index 7f9d856eb9..a0a3871201 100644 --- a/Code/Framework/AzNetworking/CMakeLists.txt +++ b/Code/Framework/AzNetworking/CMakeLists.txt @@ -25,7 +25,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE AZ::AzCore - 3rdParty::zlib 3rdParty::zstd 3rdParty::OpenSSL PUBLIC diff --git a/Code/Legacy/CrySystem/CMakeLists.txt b/Code/Legacy/CrySystem/CMakeLists.txt index 9e1cf92267..4c1f0d9b82 100644 --- a/Code/Legacy/CrySystem/CMakeLists.txt +++ b/Code/Legacy/CrySystem/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( 3rdParty::lz4 3rdParty::md5 3rdParty::tiff - 3rdParty::zlib 3rdParty::zstd Legacy::CryCommon Legacy::CrySystem.XMLBinary diff --git a/cmake/3rdParty/BuiltInPackages.cmake b/cmake/3rdParty/BuiltInPackages.cmake index c583774e3a..743e2e983e 100644 --- a/cmake/3rdParty/BuiltInPackages.cmake +++ b/cmake/3rdParty/BuiltInPackages.cmake @@ -18,4 +18,13 @@ set(LY_PAL_PACKAGE_FILE_NAME ${CMAKE_CURRENT_LIST_DIR}/${pal_dir}/BuiltInPackage include(${LY_PAL_PACKAGE_FILE_NAME}) # add the above file to the ALLFILES list, so that they show up in IDEs -set(ALLFILES ${ALLFILES} ${LY_PAL_PACKAGE_FILE_NAME}) \ No newline at end of file +set(ALLFILES ${ALLFILES} ${LY_PAL_PACKAGE_FILE_NAME}) + +# temporary compatibility: +# Some 3p libraries may still refer to zlib as "3rdParty::zlib" instead of +# the correct "3rdParty::ZLIB" (Case difference). Until those libraries are updated +# we alias the casing here. This also provides backward compatibility for Gems that use 3rdParty::zlib +# that are not part of the core O3DE repo. +ly_download_associated_package(ZLIB) +find_package(ZLIB) +add_library(3rdParty::zlib ALIAS 3rdParty::ZLIB) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index 5de2ad0253..4d17e4b20b 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -27,6 +27,6 @@ ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS Goo ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-android TARGETS libpng PACKAGE_HASH 51d3ec1559c5595196c11e11674cf5745989d3073bf33dabc6697e3eee77a1cc) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-android TARGETS zlib PACKAGE_HASH 85b730b97176772538cfcacd6b6aaf4655fc2d368d134d6dd55e02f28f183826) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-android TARGETS ZLIB PACKAGE_HASH 73c9e88892c237a3fc6eafc04268ccd9d479e6d55f9df2ed58b236c8f9cf2cae) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-android TARGETS lz4 PACKAGE_HASH f5b22642d218dbbb442cae61e469e5b241c4740acd258c3e8678e60dec61ea93) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index e634cb19c5..fb02a80088 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -42,7 +42,7 @@ ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-linux TARGETS SPIRVCross PACKAGE_HASH 7889ee5460a688e9b910c0168b31445c0079d363affa07b25d4c8aeb608a0b80) ly_associate_package(PACKAGE_NAME azslc-1.7.23-rev2-linux TARGETS azslc PACKAGE_HASH 1ba84d8321a566d35a1e9aa7400211ba8e6d1c11c08e4be3c93e6e74b8f7aef1) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-linux TARGETS zlib PACKAGE_HASH 16f3b9e11cda525efb62144f354c1cfc30a5def9eff020dbe49cb00ee7d8234f) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-linux TARGETS ZLIB PACKAGE_HASH 9be5ea85722fc27a8645a9c8a812669d107c68e6baa2ca0740872eaeb6a8b0fc) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-linux TARGETS squish-ccr PACKAGE_HASH 85fecafbddc6a41a27c5f59ed4a5dfb123a94cb4666782cf26e63c0a4724c530) ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev1-linux TARGETS astc-encoder PACKAGE_HASH 2ba97a06474d609945f0ab4419af1f6bbffdd294ca6b869f5fcebec75c573c0f) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-linux TARGETS ISPCTexComp PACKAGE_HASH 065fd12abe4247dde247330313763cf816c3375c221da030bdec35024947f259) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index fd46191015..e80956530a 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -40,7 +40,7 @@ ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-mac ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-mac TARGETS Qt PACKAGE_HASH 9d25918351898b308ded3e9e571fff6f26311b2071aeafd00dd5b249fdf53f7e) ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 1ad76cd038ccc1f288f83c5fe2859a0f35c5154e1fe7658e1230cc428d318a8b) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac TARGETS libsamplerate PACKAGE_HASH b912af40c0ac197af9c43d85004395ba92a6a859a24b7eacd920fed5854a97fe) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-mac TARGETS zlib PACKAGE_HASH 21714e8a6de4f2523ee92a7f52d51fbee29c5f37ced334e00dc3c029115b472e) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-mac TARGETS ZLIB PACKAGE_HASH b6fea9c79b8bf106d4703b67fecaa133f832ad28696c2ceef45fb5f20013c096) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-mac TARGETS squish-ccr PACKAGE_HASH 155bfbfa17c19a9cd2ef025de14c5db598f4290045d5b0d83ab58cb345089a77) ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev1-mac TARGETS astc-encoder PACKAGE_HASH 96f6ea8c3e45ec7fe525230c7c53ca665c8300d8e28456cc19bb3159ce6f8dcc) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-mac TARGETS ISPCTexComp PACKAGE_HASH 8a4e93277b8face6ea2fd57c6d017bdb55643ed3d6387110bc5f6b3b884dd169) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 333c952051..7e112c405e 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -47,7 +47,7 @@ ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows TARGETS civetweb PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-windows TARGETS OpenSSL PACKAGE_HASH 9af1c50343f89146b4053101a7aeb20513319a3fe2f007e356d7ce25f9241040) ly_associate_package(PACKAGE_NAME Crashpad-0.8.0-rev1-windows TARGETS Crashpad PACKAGE_HASH d162aa3070147bc0130a44caab02c5fe58606910252caf7f90472bd48d4e31e2) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-windows TARGETS zlib PACKAGE_HASH 9afab1d67641ed8bef2fb38fc53942da47f2ab339d9e77d3d20704a48af2da0b) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-windows TARGETS ZLIB PACKAGE_HASH 8847112429744eb11d92c44026fc5fc53caa4a06709382b5f13978f3c26c4cbd) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-windows TARGETS squish-ccr PACKAGE_HASH 5c3d9fa491e488ccaf802304ad23b932268a2b2846e383f088779962af2bfa84) ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev1-windows TARGETS astc-encoder PACKAGE_HASH 3addc6fc1a7eb0d6b7f3d530e962af967e6d92b3825ef485da243346357cf78e) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-windows TARGETS ISPCTexComp PACKAGE_HASH b6fa6ea28a2808a9a5524c72c37789c525925e435770f2d94eb2d387360fa2d0) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index 25df8101b4..c9de80c809 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -28,5 +28,5 @@ ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-ios TARGETS GoogleB ly_associate_package(PACKAGE_NAME libpng-1.6.37-ios TARGETS libpng PACKAGE_HASH 18a8217721083c4dc46514105be43ca764fa9c994a74aa0b57766ea6f8187e7b) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-ios TARGETS libsamplerate PACKAGE_HASH 7656b961697f490d4f9c35d2e61559f6fc38c32102e542a33c212cd618fc2119) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-ios TARGETS OpenSSL PACKAGE_HASH cd0dfce3086a7172777c63dadbaf0ac3695b676119ecb6d0614b5fb1da03462f) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-ios TARGETS zlib PACKAGE_HASH a59fc0f83a02c616b679799310e9d86fde84514c6d2acefa12c6def0ae4a880c) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-ios TARGETS ZLIB PACKAGE_HASH c7f10b4d0fe63192054d926f53b08e852cdf472bc2b18e2f7be5aecac1869f7f) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-ios TARGETS lz4 PACKAGE_HASH 588ea05739caa9231a9a17a1e8cf64c5b9a265e16528bc05420af7e2534e86c1) From be29712e57e424686914458a464a961315d7e432 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:35:04 -0700 Subject: [PATCH 048/293] Left aligned variable manager's header and data Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../VariablePanel/GraphVariablesTableView.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp index 91f85ae36a..5f76820975 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp @@ -37,6 +37,8 @@ #include #include +#pragma optimize("", off) + namespace ScriptCanvasEditor { @@ -411,10 +413,7 @@ namespace ScriptCanvasEditor case Qt::TextAlignmentRole: { - if (index.column() == ColumnIndex::Type) - { - return QVariant(Qt::AlignLeft | Qt::AlignVCenter); - } + return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } break; @@ -880,6 +879,11 @@ namespace ScriptCanvasEditor return tr(m_columnNames[section]); } + if (role == Qt::TextAlignmentRole) + { + return QVariant(Qt::AlignLeft | Qt::AlignVCenter); + } + return QAbstractItemModel::headerData(section, orientation, role); } @@ -1410,3 +1414,6 @@ namespace ScriptCanvasEditor #include } + + +#pragma optimize("", on) From 882e72dab34e0d1a206083791a174c1034cabe44 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:48:00 -0700 Subject: [PATCH 049/293] fix for late compilation errors on untyped input Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Grammar/AbstractCodeModel.cpp | 6 + .../Include/ScriptCanvas/Results/ErrorText.h | 1 + .../LY_SC_UnitTest_MultipleOut.scriptcanvas | 8465 +++++++---------- .../Tests/ScriptCanvas_RuntimeInterpreted.cpp | 4 +- 4 files changed, 3247 insertions(+), 5229 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 4509e7e907..7d76dbc27d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -4320,6 +4320,12 @@ namespace ScriptCanvas { AZ_Assert(execution->GetSymbol() != Symbol::FunctionDefinition, "Function definition input is not handled in AbstractCodeModel::ParseInputDatum"); + if (!input.GetDataType().IsValid()) + { + AddError(nullptr, aznew Internal::ParseError(execution->GetNodeId(), ParseErrors::InvalidDataTypeInInput)); + return; + } + auto nodes = execution->GetId().m_node->GetConnectedNodes(input); if (nodes.empty()) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h index da9a1ebc1f..a803ea862e 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h @@ -41,6 +41,7 @@ namespace ScriptCanvas constexpr const char* InactiveGraph = "This graph defines no functions, it is never activated, and will never execute. Add a Start node or connect an event handler or define functions."; constexpr const char* InfiniteLoopWritingToVariable = "infinite loop when writing to variable"; constexpr const char* InfiniteSelfActivationLoop = "infinite loop when activating the entity that owns this graph"; + constexpr const char* InvalidDataTypeInInput = "invalid data type in input slot"; constexpr const char* MetaDataNeedsTupleTypeIdForEventCall = "Meta data needs an AzTypeId for Tuple if an EBus call returns multiple types to ScriptCanvas"; constexpr const char* MetaDataRequiredForEventCall = "Meta data is required for ACM node that is an EBus call"; constexpr const char* MissingFalseExecutionSlotOnIf = "A 'False' Execution output slot is required in an If branch node"; diff --git a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_MultipleOut.scriptcanvas b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_MultipleOut.scriptcanvas index 1d316c4dc0..1770d0e6c2 100644 --- a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_MultipleOut.scriptcanvas +++ b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_MultipleOut.scriptcanvas @@ -1,5227 +1,3238 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "ScriptCanvasData", + "ClassData": { + "m_scriptCanvas": { + "Id": { + "id": 20005528169920 + }, + "Name": "LY_SC_UnitTest_MultipleOut", + "Components": { + "Component_[14476721853276197761]": { + "$type": "EditorGraphVariableManagerComponent", + "Id": 14476721853276197761, + "m_variableData": { + "m_nameVariableMap": [ + { + "Key": { + "m_id": "{0D12DC58-0CED-4E69-9234-7B03F80A0008}" + }, + "Value": { + "Datum": { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": false, + "label": "Boolean" + }, + "VariableId": { + "m_id": "{0D12DC58-0CED-4E69-9234-7B03F80A0008}" + }, + "VariableName": "Exec 1" + } + }, + { + "Key": { + "m_id": "{2ACB3F3A-6D87-4EBC-AD66-F8702F8F62DD}" + }, + "Value": { + "Datum": { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 3.0, + "label": "Three" + }, + "VariableId": { + "m_id": "{2ACB3F3A-6D87-4EBC-AD66-F8702F8F62DD}" + }, + "VariableName": "Three" + } + }, + { + "Key": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + }, + "Value": { + "Datum": { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Number" + }, + "VariableId": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + }, + "VariableName": "counter" + } + }, + { + "Key": { + "m_id": "{84E8E7E7-7A51-4DB2-8E03-ECEB4E448C2B}" + }, + "Value": { + "Datum": { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": false, + "label": "Boolean" + }, + "VariableId": { + "m_id": "{84E8E7E7-7A51-4DB2-8E03-ECEB4E448C2B}" + }, + "VariableName": "Exec 3" + } + }, + { + "Key": { + "m_id": "{DB5D6C5D-FD69-474C-BBBE-4984C5715FA8}" + }, + "Value": { + "Datum": { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": false, + "label": "Boolean" + }, + "VariableId": { + "m_id": "{DB5D6C5D-FD69-474C-BBBE-4984C5715FA8}" + }, + "VariableName": "Exec 2" + } + } + ] + } + }, + "Component_[16621147190561896838]": { + "$type": "{4D755CA9-AB92-462C-B24F-0B3376F19967} Graph", + "Id": 16621147190561896838, + "m_graphData": { + "m_nodes": [ + { + "Id": { + "id": 20044182875584 + }, + "Name": "SC-Node(Start)", + "Components": { + "Component_[10424525019465666117]": { + "$type": "Start", + "Id": 10424525019465666117, + "Slots": [ + { + "id": { + "m_id": "{25061884-0633-4061-B583-0796CDC9B215}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "toolTip": "Signaled when the entity that owns this graph is fully activated.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ] + } + } + }, + { + "Id": { + "id": 20014118104512 + }, + "Name": "SC-Node(OperatorAdd)", + "Components": { + "Component_[12328748346053958726]": { + "$type": "OperatorAdd", + "Id": 12328748346053958726, + "Slots": [ + { + "id": { + "m_id": "{AC7B582F-C1DE-4C3C-ACC9-D729BE959BF5}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{5E73CCFA-3E3B-44B5-9E9E-FD9250FCE078}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{B20F1E7F-B2BA-43E4-AD32-D58B8CFA5B57}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Number", + "toolTip": "An operand to use in performing the specified Operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + }, + { + "id": { + "m_id": "{265B8942-C187-4D83-A017-20BEE053B96D}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Number", + "toolTip": "An operand to use in performing the specified Operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{5B25184E-0BC4-44A8-9539-772AC75432B4}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Result", + "toolTip": "The result of the specified operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Number" + }, + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 1.0, + "label": "Number" + } + ] + } + } + }, + { + "Id": { + "id": 20022708039104 + }, + "Name": "SC-Node(OperatorAdd)", + "Components": { + "Component_[12328748346053958726]": { + "$type": "OperatorAdd", + "Id": 12328748346053958726, + "Slots": [ + { + "id": { + "m_id": "{AC7B582F-C1DE-4C3C-ACC9-D729BE959BF5}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{5E73CCFA-3E3B-44B5-9E9E-FD9250FCE078}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{B20F1E7F-B2BA-43E4-AD32-D58B8CFA5B57}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Number", + "toolTip": "An operand to use in performing the specified Operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + }, + { + "id": { + "m_id": "{265B8942-C187-4D83-A017-20BEE053B96D}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Number", + "toolTip": "An operand to use in performing the specified Operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{5B25184E-0BC4-44A8-9539-772AC75432B4}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Result", + "toolTip": "The result of the specified operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Number" + }, + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 1.0, + "label": "Number" + } + ] + } + } + }, + { + "Id": { + "id": 20061362744768 + }, + "Name": "SC-Node(OperatorAdd)", + "Components": { + "Component_[12328748346053958726]": { + "$type": "OperatorAdd", + "Id": 12328748346053958726, + "Slots": [ + { + "id": { + "m_id": "{AC7B582F-C1DE-4C3C-ACC9-D729BE959BF5}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{5E73CCFA-3E3B-44B5-9E9E-FD9250FCE078}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{B20F1E7F-B2BA-43E4-AD32-D58B8CFA5B57}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Number", + "toolTip": "An operand to use in performing the specified Operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + }, + { + "id": { + "m_id": "{265B8942-C187-4D83-A017-20BEE053B96D}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Number", + "toolTip": "An operand to use in performing the specified Operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{5B25184E-0BC4-44A8-9539-772AC75432B4}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + { + "$type": "MathOperatorContract", + "NativeTypes": [ + { + "m_type": 3 + }, + { + "m_type": 6 + }, + { + "m_type": 8 + }, + { + "m_type": 9 + }, + { + "m_type": 10 + }, + { + "m_type": 11 + }, + { + "m_type": 12 + }, + { + "m_type": 14 + }, + { + "m_type": 15 + } + ] + } + ], + "slotName": "Result", + "toolTip": "The result of the specified operation", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 1114760223 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 1114760223 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Number" + }, + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 1.0, + "label": "Number" + } + ] + } + } + }, + { + "Id": { + "id": 20009823137216 + }, + "Name": "SC-Node(EqualTo)", + "Components": { + "Component_[13545476611799837370]": { + "$type": "EqualTo", + "Id": 13545476611799837370, + "Slots": [ + { + "id": { + "m_id": "{3A36FFEC-1706-4E84-AF24-9CA117ED9A08}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Result", + "DisplayDataType": { + "m_type": 0 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{71837FF2-8438-4225-AA73-B017D5097FE7}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "Signal to perform the evaluation when desired.", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{85BEF751-FEBE-457B-B73A-F9334E248174}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "True", + "toolTip": "Signaled if the result of the operation is true.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{F17CFAD4-F1FB-4E17-B466-DDEAE1D0C4D7}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "False", + "toolTip": "Signaled if the result of the operation is false.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{F89D9F4D-8840-4420-BB13-A62BE5E0248C}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Value A", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 3545012108 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + }, + { + "id": { + "m_id": "{11C3CEF3-4EED-405E-88CB-B25B55C28D5D}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Value B", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 3545012108 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{2ACB3F3A-6D87-4EBC-AD66-F8702F8F62DD}" + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Value A" + }, + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Value B" + } + ] + } + } + }, + { + "Id": { + "id": 20065657712064 + }, + "Name": "SC-Node(EqualTo)", + "Components": { + "Component_[13545476611799837370]": { + "$type": "EqualTo", + "Id": 13545476611799837370, + "Slots": [ + { + "id": { + "m_id": "{3A36FFEC-1706-4E84-AF24-9CA117ED9A08}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Result", + "DisplayDataType": { + "m_type": 0 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{71837FF2-8438-4225-AA73-B017D5097FE7}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "Signal to perform the evaluation when desired.", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{85BEF751-FEBE-457B-B73A-F9334E248174}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "True", + "toolTip": "Signaled if the result of the operation is true.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{F17CFAD4-F1FB-4E17-B466-DDEAE1D0C4D7}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "False", + "toolTip": "Signaled if the result of the operation is false.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{F89D9F4D-8840-4420-BB13-A62BE5E0248C}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Value A", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 3545012108 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + }, + { + "id": { + "m_id": "{11C3CEF3-4EED-405E-88CB-B25B55C28D5D}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Value B", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 3545012108 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{2ACB3F3A-6D87-4EBC-AD66-F8702F8F62DD}" + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Value A" + }, + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Value B" + } + ] + } + } + }, + { + "Id": { + "id": 20069952679360 + }, + "Name": "SC-Node(EqualTo)", + "Components": { + "Component_[13545476611799837370]": { + "$type": "EqualTo", + "Id": 13545476611799837370, + "Slots": [ + { + "id": { + "m_id": "{3A36FFEC-1706-4E84-AF24-9CA117ED9A08}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Result", + "DisplayDataType": { + "m_type": 0 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{71837FF2-8438-4225-AA73-B017D5097FE7}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "Signal to perform the evaluation when desired.", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{85BEF751-FEBE-457B-B73A-F9334E248174}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "True", + "toolTip": "Signaled if the result of the operation is true.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{F17CFAD4-F1FB-4E17-B466-DDEAE1D0C4D7}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "False", + "toolTip": "Signaled if the result of the operation is false.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{F89D9F4D-8840-4420-BB13-A62BE5E0248C}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Value A", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 3545012108 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{69CFFC85-A02B-4538-8704-D5EB9D768BFA}" + } + }, + { + "id": { + "m_id": "{11C3CEF3-4EED-405E-88CB-B25B55C28D5D}" + }, + "DynamicTypeOverride": 3, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Value B", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DynamicGroup": { + "Value": 3545012108 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{2ACB3F3A-6D87-4EBC-AD66-F8702F8F62DD}" + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Value A" + }, + { + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Value B" + } + ] + } + } + }, + { + "Id": { + "id": 20048477842880 + }, + "Name": "SC Node(SetVariable)", + "Components": { + "Component_[14507547243373092664]": { + "$type": "SetVariableNode", + "Id": 14507547243373092664, + "Slots": [ + { + "id": { + "m_id": "{A23CADFC-70B4-45EB-8178-D9570EE659ED}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "When signaled sends the variable referenced by this node to a Data Output slot", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{69C4E25F-AD39-4CE9-9E19-87DC8C6B43AB}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "toolTip": "Signaled after the referenced variable has been pushed to the Data Output slot", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{87AF01EE-69E7-441F-BE3D-8DBD95475AF9}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Boolean", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{D0C36DFD-8ED8-4E64-8765-556123BAF3C1}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Boolean", + "DisplayDataType": { + "m_type": 0 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": true, + "label": "Boolean" + } + ], + "m_variableId": { + "m_id": "{DB5D6C5D-FD69-474C-BBBE-4984C5715FA8}" + }, + "m_variableDataInSlotId": { + "m_id": "{87AF01EE-69E7-441F-BE3D-8DBD95475AF9}" + }, + "m_variableDataOutSlotId": { + "m_id": "{D0C36DFD-8ED8-4E64-8765-556123BAF3C1}" + } + } + } + }, + { + "Id": { + "id": 20057067777472 + }, + "Name": "SC-Node(Print)", + "Components": { + "Component_[17364567436915815279]": { + "$type": "Print", + "Id": 17364567436915815279, + "Slots": [ + { + "id": { + "m_id": "{DE4E1FFE-8F36-4272-81AD-9973CC9DC197}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "Input signal", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{32561DF2-D512-49DD-8DCC-5FB951122DF5}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "m_format": "Hello", + "m_unresolvedString": [ + "Hello" + ] + } + } + }, + { + "Id": { + "id": 20052772810176 + }, + "Name": "SC Node(SetVariable)", + "Components": { + "Component_[18169977638437689378]": { + "$type": "SetVariableNode", + "Id": 18169977638437689378, + "Slots": [ + { + "id": { + "m_id": "{F65A6861-482D-4014-8532-31F31E9F64AC}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "When signaled sends the variable referenced by this node to a Data Output slot", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{D4DD8502-2960-4E11-81F5-3CCAC7FCFBCE}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "toolTip": "Signaled after the referenced variable has been pushed to the Data Output slot", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{0E4216CC-2501-4ED7-8B85-343813337526}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Boolean", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{B150FE31-45A9-4E45-929A-AE9799BA8E31}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Boolean", + "DisplayDataType": { + "m_type": 0 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": true, + "label": "Boolean" + } + ], + "m_variableId": { + "m_id": "{0D12DC58-0CED-4E69-9234-7B03F80A0008}" + }, + "m_variableDataInSlotId": { + "m_id": "{0E4216CC-2501-4ED7-8B85-343813337526}" + }, + "m_variableDataOutSlotId": { + "m_id": "{B150FE31-45A9-4E45-929A-AE9799BA8E31}" + } + } + } + }, + { + "Id": { + "id": 20018413071808 + }, + "Name": "SC Node(SetVariable)", + "Components": { + "Component_[2433126846967649500]": { + "$type": "SetVariableNode", + "Id": 2433126846967649500, + "Slots": [ + { + "id": { + "m_id": "{EA436CD0-DBC5-4DE6-B658-BA88DB2DD8FB}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "When signaled sends the variable referenced by this node to a Data Output slot", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{EF2E6C1F-3960-45D1-AC20-B49B92785FF9}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "toolTip": "Signaled after the referenced variable has been pushed to the Data Output slot", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{B2EB9354-2D69-4A25-990E-E321FDF0EDDA}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Boolean", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{FD662FEC-08F9-410B-BAA9-1AF2D8229766}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Boolean", + "DisplayDataType": { + "m_type": 0 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": true, + "label": "Boolean" + } + ], + "m_variableId": { + "m_id": "{84E8E7E7-7A51-4DB2-8E03-ECEB4E448C2B}" + }, + "m_variableDataInSlotId": { + "m_id": "{B2EB9354-2D69-4A25-990E-E321FDF0EDDA}" + }, + "m_variableDataOutSlotId": { + "m_id": "{FD662FEC-08F9-410B-BAA9-1AF2D8229766}" + } + } + } + }, + { + "Id": { + "id": 20027003006400 + }, + "Name": "SC-Node(Expect True)", + "Components": { + "Component_[4200368161720158321]": { + "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", + "Id": 4200368161720158321, + "Slots": [ + { + "isVisibile": false, + "id": { + "m_id": "{982114AA-80C2-479A-BB0E-040B8C119422}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "EntityID: 0", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{58E5597B-3073-45DD-86B7-E14097E3EC0B}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Candidate", + "toolTip": "a value that must be true", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{0D12DC58-0CED-4E69-9234-7B03F80A0008}" + } + }, + { + "id": { + "m_id": "{232AB412-02EB-4201-BA96-BEC573A758EF}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Report", + "toolTip": "additional notes for the test report", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{CAFD7A46-861D-4156-A15B-38E798044A36}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 1 + }, + "isNullPointer": false, + "$type": "EntityId", + "value": { + "id": 4276206253 + } + }, + { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": false, + "label": "Candidate" + }, + { + "scriptCanvasType": { + "m_type": 5 + }, + "isNullPointer": false, + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "value": "", + "label": "Report" + } + ], + "methodType": 2, + "methodName": "Expect True", + "className": "Unit Testing", + "resultSlotIDs": [ + {} + ], + "prettyClassName": "Unit Testing" + } + } + }, + { + "Id": { + "id": 20035592940992 + }, + "Name": "SC-Node(Expect True)", + "Components": { + "Component_[4200368161720158321]": { + "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", + "Id": 4200368161720158321, + "Slots": [ + { + "isVisibile": false, + "id": { + "m_id": "{982114AA-80C2-479A-BB0E-040B8C119422}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "EntityID: 0", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{58E5597B-3073-45DD-86B7-E14097E3EC0B}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Candidate", + "toolTip": "a value that must be true", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{0D12DC58-0CED-4E69-9234-7B03F80A0008}" + } + }, + { + "id": { + "m_id": "{232AB412-02EB-4201-BA96-BEC573A758EF}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Report", + "toolTip": "additional notes for the test report", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{CAFD7A46-861D-4156-A15B-38E798044A36}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 1 + }, + "isNullPointer": false, + "$type": "EntityId", + "value": { + "id": 4276206253 + } + }, + { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": false, + "label": "Candidate" + }, + { + "scriptCanvasType": { + "m_type": 5 + }, + "isNullPointer": false, + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "value": "", + "label": "Report" + } + ], + "methodType": 2, + "methodName": "Expect True", + "className": "Unit Testing", + "resultSlotIDs": [ + {} + ], + "prettyClassName": "Unit Testing" + } + } + }, + { + "Id": { + "id": 20039887908288 + }, + "Name": "SC-Node(Expect True)", + "Components": { + "Component_[4200368161720158321]": { + "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", + "Id": 4200368161720158321, + "Slots": [ + { + "isVisibile": false, + "id": { + "m_id": "{982114AA-80C2-479A-BB0E-040B8C119422}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "EntityID: 0", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{58E5597B-3073-45DD-86B7-E14097E3EC0B}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Candidate", + "toolTip": "a value that must be true", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{84E8E7E7-7A51-4DB2-8E03-ECEB4E448C2B}" + } + }, + { + "id": { + "m_id": "{232AB412-02EB-4201-BA96-BEC573A758EF}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Report", + "toolTip": "additional notes for the test report", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{CAFD7A46-861D-4156-A15B-38E798044A36}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 1 + }, + "isNullPointer": false, + "$type": "EntityId", + "value": { + "id": 4276206253 + } + }, + { + "scriptCanvasType": { + "m_type": 0 + }, + "isNullPointer": false, + "$type": "bool", + "value": false, + "label": "Candidate" + }, + { + "scriptCanvasType": { + "m_type": 5 + }, + "isNullPointer": false, + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "value": "", + "label": "Report" + } + ], + "methodType": 2, + "methodName": "Expect True", + "className": "Unit Testing", + "resultSlotIDs": [ + {} + ], + "prettyClassName": "Unit Testing" + } + } + }, + { + "Id": { + "id": 20031297973696 + }, + "Name": "SC-Node(Mark Complete)", + "Components": { + "Component_[4383017650724706609]": { + "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", + "Id": 4383017650724706609, + "Slots": [ + { + "isVisibile": false, + "id": { + "m_id": "{716C2DBF-F48F-48DC-A1B0-2A0D05ED2DC3}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "EntityID: 0", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{39BDE16A-0CBB-46D1-9C26-24F85A7183FC}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + }, + null + ], + "slotName": "Report", + "toolTip": "additional notes for the test report", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{496BD222-4D88-4AD0-992E-3873EB3E51F9}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{AD0780F8-7FB5-480D-B7C0-9CC8208223C4}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "Datums": [ + { + "scriptCanvasType": { + "m_type": 1 + }, + "isNullPointer": false, + "$type": "EntityId", + "value": { + "id": 4276206253 + } + }, + { + "scriptCanvasType": { + "m_type": 5 + }, + "isNullPointer": false, + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "value": "", + "label": "Report" + } + ], + "methodType": 2, + "methodName": "Mark Complete", + "className": "Unit Testing", + "resultSlotIDs": [ + {} + ], + "prettyClassName": "Unit Testing" + } + } + } + ], + "m_connections": [ + { + "Id": { + "id": 20074247646656 + }, + "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(Print: In)", + "Components": { + "Component_[9544956642945817670]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 9544956642945817670, + "sourceEndpoint": { + "nodeId": { + "id": 20044182875584 + }, + "slotId": { + "m_id": "{25061884-0633-4061-B583-0796CDC9B215}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20057067777472 + }, + "slotId": { + "m_id": "{DE4E1FFE-8F36-4272-81AD-9973CC9DC197}" + } + } + } + } + }, + { + "Id": { + "id": 20078542613952 + }, + "Name": "srcEndpoint=(Print: Out), destEndpoint=(Set Variable: In)", + "Components": { + "Component_[5846765668694970625]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 5846765668694970625, + "sourceEndpoint": { + "nodeId": { + "id": 20057067777472 + }, + "slotId": { + "m_id": "{32561DF2-D512-49DD-8DCC-5FB951122DF5}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20052772810176 + }, + "slotId": { + "m_id": "{F65A6861-482D-4014-8532-31F31E9F64AC}" + } + } + } + } + }, + { + "Id": { + "id": 20082837581248 + }, + "Name": "srcEndpoint=(Print: Out), destEndpoint=(Set Variable: In)", + "Components": { + "Component_[12462935459010319786]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 12462935459010319786, + "sourceEndpoint": { + "nodeId": { + "id": 20057067777472 + }, + "slotId": { + "m_id": "{32561DF2-D512-49DD-8DCC-5FB951122DF5}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20048477842880 + }, + "slotId": { + "m_id": "{A23CADFC-70B4-45EB-8178-D9570EE659ED}" + } + } + } + } + }, + { + "Id": { + "id": 20087132548544 + }, + "Name": "srcEndpoint=(Print: Out), destEndpoint=(Set Variable: In)", + "Components": { + "Component_[15367103920447716135]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 15367103920447716135, + "sourceEndpoint": { + "nodeId": { + "id": 20057067777472 + }, + "slotId": { + "m_id": "{32561DF2-D512-49DD-8DCC-5FB951122DF5}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20018413071808 + }, + "slotId": { + "m_id": "{EA436CD0-DBC5-4DE6-B658-BA88DB2DD8FB}" + } + } + } + } + }, + { + "Id": { + "id": 20091427515840 + }, + "Name": "srcEndpoint=(Add (+): Out), destEndpoint=(Equal To (==): In)", + "Components": { + "Component_[1770958354285950060]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 1770958354285950060, + "sourceEndpoint": { + "nodeId": { + "id": 20061362744768 + }, + "slotId": { + "m_id": "{5E73CCFA-3E3B-44B5-9E9E-FD9250FCE078}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20009823137216 + }, + "slotId": { + "m_id": "{71837FF2-8438-4225-AA73-B017D5097FE7}" + } + } + } + } + }, + { + "Id": { + "id": 20095722483136 + }, + "Name": "srcEndpoint=(Add (+): Out), destEndpoint=(Equal To (==): In)", + "Components": { + "Component_[15742434548170508999]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 15742434548170508999, + "sourceEndpoint": { + "nodeId": { + "id": 20014118104512 + }, + "slotId": { + "m_id": "{5E73CCFA-3E3B-44B5-9E9E-FD9250FCE078}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20065657712064 + }, + "slotId": { + "m_id": "{71837FF2-8438-4225-AA73-B017D5097FE7}" + } + } + } + } + }, + { + "Id": { + "id": 20100017450432 + }, + "Name": "srcEndpoint=(Add (+): Out), destEndpoint=(Equal To (==): In)", + "Components": { + "Component_[5888192785906240625]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 5888192785906240625, + "sourceEndpoint": { + "nodeId": { + "id": 20022708039104 + }, + "slotId": { + "m_id": "{5E73CCFA-3E3B-44B5-9E9E-FD9250FCE078}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20069952679360 + }, + "slotId": { + "m_id": "{71837FF2-8438-4225-AA73-B017D5097FE7}" + } + } + } + } + }, + { + "Id": { + "id": 20104312417728 + }, + "Name": "srcEndpoint=(Set Variable: Out), destEndpoint=(Add (+): In)", + "Components": { + "Component_[14484850856034595321]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 14484850856034595321, + "sourceEndpoint": { + "nodeId": { + "id": 20048477842880 + }, + "slotId": { + "m_id": "{69C4E25F-AD39-4CE9-9E19-87DC8C6B43AB}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20014118104512 + }, + "slotId": { + "m_id": "{AC7B582F-C1DE-4C3C-ACC9-D729BE959BF5}" + } + } + } + } + }, + { + "Id": { + "id": 20108607385024 + }, + "Name": "srcEndpoint=(Set Variable: Out), destEndpoint=(Add (+): In)", + "Components": { + "Component_[13948374526923268574]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 13948374526923268574, + "sourceEndpoint": { + "nodeId": { + "id": 20052772810176 + }, + "slotId": { + "m_id": "{D4DD8502-2960-4E11-81F5-3CCAC7FCFBCE}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20061362744768 + }, + "slotId": { + "m_id": "{AC7B582F-C1DE-4C3C-ACC9-D729BE959BF5}" + } + } + } + } + }, + { + "Id": { + "id": 20112902352320 + }, + "Name": "srcEndpoint=(Set Variable: Out), destEndpoint=(Add (+): In)", + "Components": { + "Component_[17650800042816564839]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 17650800042816564839, + "sourceEndpoint": { + "nodeId": { + "id": 20018413071808 + }, + "slotId": { + "m_id": "{EF2E6C1F-3960-45D1-AC20-B49B92785FF9}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20022708039104 + }, + "slotId": { + "m_id": "{AC7B582F-C1DE-4C3C-ACC9-D729BE959BF5}" + } + } + } + } + }, + { + "Id": { + "id": 20117197319616 + }, + "Name": "srcEndpoint=(Expect True: Out), destEndpoint=(Expect True: In)", + "Components": { + "Component_[9927163777207365219]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 9927163777207365219, + "sourceEndpoint": { + "nodeId": { + "id": 20035592940992 + }, + "slotId": { + "m_id": "{CAFD7A46-861D-4156-A15B-38E798044A36}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20039887908288 + }, + "slotId": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + } + } + } + } + }, + { + "Id": { + "id": 20121492286912 + }, + "Name": "srcEndpoint=(Expect True: Out), destEndpoint=(Expect True: In)", + "Components": { + "Component_[6569354793892923961]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 6569354793892923961, + "sourceEndpoint": { + "nodeId": { + "id": 20039887908288 + }, + "slotId": { + "m_id": "{CAFD7A46-861D-4156-A15B-38E798044A36}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20027003006400 + }, + "slotId": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + } + } + } + } + }, + { + "Id": { + "id": 20125787254208 + }, + "Name": "srcEndpoint=(Equal To (==): True), destEndpoint=(Expect True: In)", + "Components": { + "Component_[8734972779133126833]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 8734972779133126833, + "sourceEndpoint": { + "nodeId": { + "id": 20009823137216 + }, + "slotId": { + "m_id": "{85BEF751-FEBE-457B-B73A-F9334E248174}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20035592940992 + }, + "slotId": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + } + } + } + } + }, + { + "Id": { + "id": 20130082221504 + }, + "Name": "srcEndpoint=(Equal To (==): True), destEndpoint=(Expect True: In)", + "Components": { + "Component_[13233443675773627954]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 13233443675773627954, + "sourceEndpoint": { + "nodeId": { + "id": 20065657712064 + }, + "slotId": { + "m_id": "{85BEF751-FEBE-457B-B73A-F9334E248174}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20035592940992 + }, + "slotId": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + } + } + } + } + }, + { + "Id": { + "id": 20134377188800 + }, + "Name": "srcEndpoint=(Equal To (==): True), destEndpoint=(Expect True: In)", + "Components": { + "Component_[8564488729834246542]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 8564488729834246542, + "sourceEndpoint": { + "nodeId": { + "id": 20069952679360 + }, + "slotId": { + "m_id": "{85BEF751-FEBE-457B-B73A-F9334E248174}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20035592940992 + }, + "slotId": { + "m_id": "{9E9BE7E3-A17F-4603-8F71-59130F2D0E7E}" + } + } + } + } + }, + { + "Id": { + "id": 20138672156096 + }, + "Name": "srcEndpoint=(Expect True: Out), destEndpoint=(Mark Complete: In)", + "Components": { + "Component_[17252410557193957278]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 17252410557193957278, + "sourceEndpoint": { + "nodeId": { + "id": 20027003006400 + }, + "slotId": { + "m_id": "{CAFD7A46-861D-4156-A15B-38E798044A36}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 20031297973696 + }, + "slotId": { + "m_id": "{496BD222-4D88-4AD0-992E-3873EB3E51F9}" + } + } + } + } + } + ] + }, + "m_assetType": "{3E2AC8CD-713F-453E-967F-29517F331784}", + "versionData": { + "_grammarVersion": 1, + "_runtimeVersion": 1, + "_fileVersion": 1 + }, + "m_variableCounter": 3, + "GraphCanvasData": [ + { + "Key": { + "id": 20005528169920 + }, + "Value": { + "ComponentData": { + "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { + "$type": "SceneComponentSaveData", + "ViewParams": { + "Scale": 0.7164653965189688, + "AnchorX": -554.109130859375, + "AnchorY": -334.977783203125 + } + } + } + } + }, + { + "Key": { + "id": 20009823137216 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MathNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 1520.0, + 80.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{4B494FF9-7CD7-496F-9778-8E01DAAE393B}" + } + } + } + }, + { + "Key": { + "id": 20014118104512 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MathNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 880.0, + 280.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{DF978315-8A60-40C7-8889-A1C2EF190012}" + } + } + } + }, + { + "Key": { + "id": 20018413071808 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "SetVariableNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 560.0, + 420.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".setVariable" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{C1E23F0C-0829-4CBC-9176-29CF13B83640}" + } + } + } + }, + { + "Key": { + "id": 20022708039104 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MathNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 920.0, + 540.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{16FFB986-E605-47C3-8BAC-C5449F871465}" + } + } + } + }, + { + "Key": { + "id": 20027003006400 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MethodNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 2600.0, + 280.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".method" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{F5ACF848-9D4E-45DA-AA58-42DE9695AAB0}" + } + } + } + }, + { + "Key": { + "id": 20031297973696 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MethodNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 2900.0, + 280.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".method" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{456E2F70-A915-450F-B570-57C61FD8713C}" + } + } + } + }, + { + "Key": { + "id": 20035592940992 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MethodNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 1980.0, + 280.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".method" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{ED35AAD0-F976-4FA9-B6C7-08ED30452D33}" + } + } + } + }, + { + "Key": { + "id": 20039887908288 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MethodNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 2280.0, + 280.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".method" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{D2CF914D-DFC1-40B6-884F-85EBD5DF95B6}" + } + } + } + }, + { + "Key": { + "id": 20044182875584 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "TimeNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 0.0, + 260.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{8133F38D-4D68-4244-8999-BE5E019A24E0}" + } + } + } + }, + { + "Key": { + "id": 20048477842880 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "SetVariableNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 560.0, + 260.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".setVariable" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{377A822F-6220-45A6-91CB-A3E5F8E9ACFB}" + } + } + } + }, + { + "Key": { + "id": 20052772810176 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "SetVariableNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 560.0, + 60.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".setVariable" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{EF322638-4ADC-43B3-9398-105F49D40D96}" + } + } + } + }, + { + "Key": { + "id": 20057067777472 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "StringNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 200.0, + 260.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{6A6126C8-7C7E-48C1-A8A5-D26B9EA59578}" + } + } + } + }, + { + "Key": { + "id": 20061362744768 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MathNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 880.0, + 60.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{01CF2659-C0C0-4D6B-9C48-B47989D98148}" + } + } + } + }, + { + "Key": { + "id": 20065657712064 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MathNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 1500.0, + 300.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{F8D64912-B290-443F-90A1-891A893D9F3D}" + } + } + } + }, + { + "Key": { + "id": 20069952679360 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "MathNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 1540.0, + 560.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{A380E8D9-CEA5-44CF-A9DC-69A3C0115256}" + } + } + } + } + ], + "StatisticsHelper": { + "InstanceCounter": [ + { + "Key": 1244476766431948410, + "Value": 3 + }, + { + "Key": 2150378447039925262, + "Value": 1 + }, + { + "Key": 3117476785392655547, + "Value": 3 + }, + { + "Key": 4199610336680704683, + "Value": 1 + }, + { + "Key": 8132426562032687196, + "Value": 1 + }, + { + "Key": 10204019744198319120, + "Value": 1 + }, + { + "Key": 10684225535275896474, + "Value": 1 + }, + { + "Key": 12033332465728181077, + "Value": 3 + }, + { + "Key": 12096037962474910421, + "Value": 1 + } + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp index 00705bfbaa..9d75d3ed9d 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp @@ -779,7 +779,7 @@ TEST_F(ScriptCanvasTestFixture, InterpretedPrintConnectedInput) TEST_F(ScriptCanvasTestFixture, InterpretedPrintFormatEmptyValue) { - RunUnitTestGraph("LY_SC_UnitTest_PrintFormatEmptyValue", ExecutionMode::Interpreted); + ExpectParseError("LY_SC_UnitTest_PrintFormatEmptyValue"); } TEST_F(ScriptCanvasTestFixture, InterpretedProperties) @@ -819,7 +819,7 @@ TEST_F(ScriptCanvasTestFixture, InterpretedStringFormat) TEST_F(ScriptCanvasTestFixture, InterpretedStringFormatEmptyValue) { - RunUnitTestGraph("LY_SC_UnitTest_StringFormatEmptyValue", ExecutionMode::Interpreted); + ExpectParseError("LY_SC_UnitTest_StringFormatEmptyValue"); } TEST_F(ScriptCanvasTestFixture, InterpretedStringFormatWithRepeatedValueName) From 5969c94d22b007812c5a29c2efbbf087c69d9b0a Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 5 Oct 2021 17:46:55 -0700 Subject: [PATCH 050/293] Renamed controller.ui --> view.ui, minor tweaks in response to PR Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Editor/View/Windows/Tools/UpgradeTool/Controller.cpp | 6 +++--- .../Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h | 5 +++-- .../Code/Editor/View/Windows/Tools/UpgradeTool/Model.h | 2 +- .../View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp | 5 ----- .../Windows/Tools/UpgradeTool/{Controller.ui => View.ui} | 4 ++-- Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake | 2 +- 6 files changed, 10 insertions(+), 14 deletions(-) rename Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/{Controller.ui => View.ui} (99%) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 6fa0f1adfa..138532be0f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -34,8 +34,8 @@ #include #include -#include -#include +#include +// #include namespace ScriptCanvasEditor { @@ -43,7 +43,7 @@ namespace ScriptCanvasEditor { Controller::Controller(QWidget* parent) : AzQtComponents::StyledDialog(parent) - , m_view(new Ui::Controller()) + , m_view(new Ui::View()) { m_view->setupUi(this); m_view->tableWidget->horizontalHeader()->setVisible(false); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index ac18ff6cf5..298f755d56 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -11,6 +11,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #include #include #include @@ -26,7 +27,7 @@ class QTableWidgetItem; namespace Ui { - class Controller; + class View; } namespace AzQtComponents @@ -58,7 +59,7 @@ namespace ScriptCanvasEditor static constexpr int ColumnBrowse = 2; static constexpr int ColumnStatus = 3; - AZStd::unique_ptr m_view; + AZStd::unique_ptr m_view; int m_handledAssetCount = 0; void AddLogEntries(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h index 58ad9877be..ab0f710870 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Model.h @@ -21,7 +21,7 @@ namespace ScriptCanvasEditor { namespace VersionExplorer { - //!Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow + //! Scoped utility to set and restore the "ed_KeepEditorActive" CVar in order to allow //! the upgrade tool to work even if the editor is not in the foreground class EditorKeepAlive { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp index 6f856b9d4c..c1faedc3a3 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp @@ -8,11 +8,6 @@ #include -namespace LoggerCpp -{ - -} - namespace ScriptCanvasEditor { namespace VersionExplorer diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui similarity index 99% rename from Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui rename to Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui index fdeb701f33..f549c821d6 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.ui +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/View.ui @@ -1,7 +1,7 @@ - Controller - + View + Qt::WindowModal diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index b12c608fe5..609f7cd454 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -261,7 +261,6 @@ set(FILES Editor/View/Windows/ScriptCanvasEditorResources.qrc Editor/View/Windows/Tools/UpgradeTool/Controller.cpp Editor/View/Windows/Tools/UpgradeTool/Controller.h - Editor/View/Windows/Tools/UpgradeTool/Controller.ui Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp Editor/View/Windows/Tools/UpgradeTool/FileSaver.h Editor/View/Windows/Tools/UpgradeTool/LogTraits.h @@ -277,6 +276,7 @@ set(FILES Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.cpp Editor/View/Windows/Tools/UpgradeTool/VersionExplorerLog.h + Editor/View/Windows/Tools/UpgradeTool/View.ui Editor/Framework/ScriptCanvasGraphUtilities.inl Editor/Framework/ScriptCanvasGraphUtilities.h Editor/Framework/ScriptCanvasTraceUtilities.h From b8bf5486a46b8d79797eb840b6c9c4d33f41d444 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Tue, 5 Oct 2021 19:50:54 -0700 Subject: [PATCH 051/293] Removed the ScatterDistanceOutput texture from the EnvironmentCubeMapForwardMSAAPass. Removed unused Srgs from the ReflectionCompositePass. Signed-off-by: dmcdiar --- .../Passes/EnvironmentCubeMapForwardMSAA.pass | 40 ------------------- .../Reflections/ReflectionComposite.azsl | 3 -- 2 files changed, 43 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass index cd52ce946b..877ae489c0 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass @@ -147,22 +147,6 @@ }, "LoadAction": "Clear" } - }, - { - "Name": "ScatterDistanceOutput", - "SlotType": "Output", - "ScopeAttachmentUsage": "RenderTarget", - "LoadStoreAction": { - "ClearValue": { - "Value": [ - 0.0, - 0.0, - 0.0, - 0.0 - ] - }, - "LoadAction": "Clear" - } } ], "ImageAttachments": [ @@ -257,23 +241,6 @@ "AssetRef": { "FilePath": "Textures/BRDFTexture.attimage" } - }, - { - "Name": "ScatterDistanceImage", - "SizeSource": { - "Source": { - "Pass": "Parent", - "Attachment": "Output" - } - }, - "MultisampleSource": { - "Pass": "This", - "Attachment": "DepthStencilInputOutput" - }, - "ImageDescriptor": { - "Format": "R11G11B10_FLOAT", - "SharedQueueMask": "Graphics" - } } ], "Connections": [ @@ -318,13 +285,6 @@ "Pass": "This", "Attachment": "BRDFTexture" } - }, - { - "LocalSlot": "ScatterDistanceOutput", - "AttachmentRef": { - "Pass": "This", - "Attachment": "ScatterDistanceImage" - } } ] } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionComposite.azsl index 806337499c..207da9e857 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionComposite.azsl @@ -15,7 +15,6 @@ // box-filtered from the MSAA sub-pixels of the reflection texture. #include -#include #include #include @@ -26,8 +25,6 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2DMS m_reflection; } -#include - // Vertex Shader VSOutput MainVS(VSInput input) { From 02b6b1dbf4d9889b55d4c11e049aa5b1804c9897 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Tue, 5 Oct 2021 20:05:06 -0700 Subject: [PATCH 052/293] First in set of PRs for adding parallel GPU test runs to Atom tests. (#4276) * add remaining hydra code for test to run using new parallel test classes and interfaces * fix return value of Secondary Grid Spacing property test for Grid Entity * Add `or error_tracer.has_asserts` call for better error catching * make `Tests.viewport_set` test check a `Report.critical_result()` check instead of `Report.result()` check * add updates from PR feedback: makes constants for re-used component name strings, move test verifications into the Report() call instead of setting first then calling Report(), use builtin math.isclose function over custom function * remove after_level_load() and split it into several function calls, add screenshot check, cleanup the GPU script and fix the rendering not displaying by setting global_extra_cmdline_args = [] * fixes the viewport Test check and splits up the helper functions into multiple functions * add comment for global_extra_cmdline_args update in test and rename the zip file to f'screenshots_{formatted_timestamp}.zip' Signed-off-by: jromnoa Co-authored-by: smurly --- .../Gem/PythonTests/Atom/CMakeLists.txt | 14 + .../Atom/TestSuite_Main_GPU_Optimized.py | 43 +++ .../Atom/atom_utils/atom_component_helper.py | 50 ++- .../tests/hydra_AtomGPU_BasicLevelSetup.py | 292 ++++++++++++++++++ .../editor_entity_utils.py | 16 + .../editor_python_test_tools/utils.py | 55 +++- 6 files changed, 453 insertions(+), 17 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt index 02aaa42597..0d6fe4c8fa 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt @@ -65,4 +65,18 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT COMPONENT Atom ) + ly_add_pytest( + NAME AutomatedTesting::Atom_TestSuite_Main_GPU_Optimized + TEST_SUITE main + TEST_REQUIRES gpu + TEST_SERIAL + TIMEOUT 1200 + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU_Optimized.py + RUNTIME_DEPENDENCIES + AssetProcessor + AutomatedTesting.Assets + Editor + COMPONENT + Atom + ) endif() diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py new file mode 100644 index 0000000000..ef572d6e5c --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py @@ -0,0 +1,43 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" +import os + +import pytest + +import ly_test_tools.environment.file_system as file_system +from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite +from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots +from .atom_utils.atom_component_helper import create_screenshots_archive, golden_images_directory + +DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' + + +@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +class TestAutomation(EditorTestSuite): + # Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests. + global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"] + + class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest): + use_null_renderer = False # Default is True + screenshot_name = "AtomBasicLevelSetup.ppm" + test_screenshots = [] # Gets set by setup() + screenshot_directory = "" # Gets set by setup() + + # Clear existing test screenshots before starting test. + def setup(self, workspace): + screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) + test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)] + file_system.delete(test_screenshots, True, True) + + from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module + + golden_images = [os.path.join(golden_images_directory(), screenshot_name)] + for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images): + compare_screenshots(test_screenshot, golden_screenshot) + create_screenshots_archive(screenshot_directory) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 58b72ef01a..821e0acfdb 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -3,13 +3,54 @@ Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright SPDX-License-Identifier: Apache-2.0 OR MIT -File to assist with common hydra component functions used across various Atom tests. """ +import datetime import os +import zipfile -from editor_python_test_tools.editor_test_helper import EditorTestHelper -helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") +def create_screenshots_archive(screenshot_path): + """ + Creates a new zip file archive at archive_path containing all files listed within archive_path. + :param screenshot_path: location containing the files to archive, the zip archive file will also be saved here. + :return: None, but creates a new zip file archive inside path containing all of the files inside archive_path. + """ + files_to_archive = [] + + # Search for .png and .ppm files to add to the zip archive file. + for (folder_name, sub_folders, file_names) in os.walk(screenshot_path): + for file_name in file_names: + if file_name.endswith(".png") or file_name.endswith(".ppm"): + file_path = os.path.join(folder_name, file_name) + files_to_archive.append(file_path) + + # Setup variables for naming the zip archive file. + timestamp = datetime.datetime.now().timestamp() + formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S") + screenshots_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip') + + # Write all of the valid .png and .ppm files to the archive file. + with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive: + for file_path in files_to_archive: + file_name = os.path.basename(file_path) + zip_archive.write(file_path, file_name) + + +def golden_images_directory(): + """ + Uses this file location to return the valid location for golden image files. + :return: The path to the golden_images directory, but raises an IOError if the golden_images directory is missing. + """ + current_file_directory = os.path.join(os.path.dirname(__file__)) + golden_images_dir = os.path.join(current_file_directory, '..', 'golden_images') + + if not os.path.exists(golden_images_dir): + raise IOError( + f'golden_images" directory was not found at path "{golden_images_dir}"' + f'Please add a "golden_images" directory inside: "{current_file_directory}"' + ) + + return golden_images_dir def create_basic_atom_level(level_name): @@ -31,6 +72,9 @@ def create_basic_atom_level(level_name): import azlmbr.object import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.editor_test_helper import EditorTestHelper + + helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") # Create a new level. new_level_name = level_name diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py new file mode 100644 index 0000000000..92c555127a --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py @@ -0,0 +1,292 @@ +""" +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 : + camera_component_added = ("Camera component was added", "Camera component wasn't added") + camera_fov_set = ("Camera component FOV property set", "Camera component FOV property wasn't set") + directional_light_component_added = ("Directional Light component added", "Directional Light component wasn't added") + enter_game_mode = ("Entered game mode", "Failed to enter game mode") + exit_game_mode = ("Exited game mode", "Couldn't exit game mode") + global_skylight_component_added = ("Global Skylight (IBL) component added", "Global Skylight (IBL) component wasn't added") + global_skylight_diffuse_image_set = ("Global Skylight Diffuse Image property set", "Global Skylight Diffuse Image property wasn't set") + global_skylight_specular_image_set = ("Global Skylight Specular Image property set", "Global Skylight Specular Image property wasn't set") + ground_plane_material_asset_set = ("Ground Plane Material Asset was set", "Ground Plane Material Asset wasn't set") + ground_plane_material_component_added = ("Ground Plane Material component added", "Ground Plane Material component wasn't added") + ground_plane_mesh_asset_set = ("Ground Plane Mesh Asset property was set", "Ground Plane Mesh Asset property wasn't set") + hdri_skybox_component_added = ("HDRi Skybox component added", "HDRi Skybox component wasn't added") + hdri_skybox_cubemap_texture_set = ("HDRi Skybox Cubemap Texture property set", "HDRi Skybox Cubemap Texture property wasn't set") + mesh_component_added = ("Mesh component added", "Mesh component wasn't added") + no_assert_occurred = ("No asserts detected", "Asserts were detected") + no_error_occurred = ("No errors detected", "Errors were detected") + secondary_grid_spacing = ("Secondary Grid Spacing set", "Secondary Grid Spacing not set") + sphere_material_component_added = ("Sphere Material component added", "Sphere Material component wasn't added") + sphere_material_set = ("Sphere Material Asset was set", "Sphere Material Asset wasn't set") + sphere_mesh_asset_set = ("Sphere Mesh Asset was set", "Sphere Mesh Asset wasn't set") + viewport_set = ("Viewport set to correct size", "Viewport not set to correct size") +# fmt: on + + +def AtomGPU_BasicLevelSetup_SetsUpLevel(): + """ + Summary: + Sets up a level to match the AtomBasicLevelSetup.ppm golden image then takes a screenshot to verify the setup. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The scene can be setup for a basic level. + The test screenshot matches the appearance of the AtomBasicLevelSetup.ppm golden image. + + Test Steps: + 1. Close error windows and display helpers then update the viewport size. + 2. Create Default Level Entity. + 3. Create Grid Entity as a child entity of the Default Level Entity. + 4. Add Grid component to Grid Entity and set Secondary Grid Spacing. + 5. Create Global Skylight (IBL) Entity as a child entity of the Default Level Entity. + 6. Add HDRi Skybox component to the Global Skylight (IBL) Entity. + 7. Add Global Skylight (IBL) component to the Global Skylight (IBL) Entity. + 8. Set the Cubemap Texture property of the HDRi Skybox component. + 9. Set the Diffuse Image property of the Global Skylight (IBL) component. + 10. Set the Specular Image property of the Global Skylight (IBL) component. + 11. Create a Ground Plane Entity with a Material component that is a child entity of the Default Level Entity. + 12. Set the Material Asset property of the Material component for the Ground Plane Entity. + 13. Add the Mesh component to the Ground Plane Entity and set the Mesh component Mesh Asset property. + 14. Create a Directional Light Entity as a child entity of the Default Level Entity. + 15. Add Directional Light component to Directional Light Entity and set entity rotation. + 16. Create a Sphere Entity as a child entity of the Default Level Entity then add a Material component. + 17. Set the Material Asset property of the Material component for the Sphere Entity. + 18. Add Mesh component to Sphere Entity and set the Mesh Asset property for the Mesh component. + 19. Create a Camera Entity as a child entity of the Default Level Entity then add a Camera component. + 20. Set the Camera Entity rotation value and set the Camera component Field of View value. + 21. Enter game mode. + 22. Take screenshot. + 23. Exit game mode. + 24. Look for errors. + + :return: None + """ + + import os + from math import isclose + + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + + from Atom.atom_utils.screenshot_utils import ScreenshotHelper + + MATERIAL_COMPONENT_NAME = "Material" + MESH_COMPONENT_NAME = "Mesh" + SCREENSHOT_NAME = "AtomBasicLevelSetup" + SCREEN_WIDTH = 1280 + SCREEN_HEIGHT = 720 + DEGREE_RADIAN_FACTOR = 0.0174533 + + def initial_viewport_setup(screen_width, screen_height): + general.set_viewport_size(screen_width, screen_height) + general.update_viewport() + result = isclose( + a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) and isclose( + a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1) + + return result + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + helper.init_idle() + helper.open_level("", "Base") + + # Test steps begin. + # 1. Close error windows and display helpers then update the viewport size. + helper.close_error_windows() + helper.close_display_helpers() + general.update_viewport() + Report.critical_result(Tests.viewport_set, initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT)) + + # 2. Create Default Level Entity. + default_level_entity_name = "Default Level" + default_level_entity = EditorEntity.create_editor_entity_at( + math.Vector3(0.0, 0.0, 0.0), default_level_entity_name) + + # 3. Create Grid Entity as a child entity of the Default Level Entity. + grid_name = "Grid" + grid_entity = EditorEntity.create_editor_entity(grid_name, default_level_entity.id) + + # 4. Add Grid component to Grid Entity and set Secondary Grid Spacing. + grid_component = grid_entity.add_component(grid_name) + secondary_grid_spacing_property = "Controller|Configuration|Secondary Grid Spacing" + secondary_grid_spacing_value = 1.0 + grid_component.set_component_property_value(secondary_grid_spacing_property, secondary_grid_spacing_value) + secondary_grid_spacing_set = grid_component.get_component_property_value( + secondary_grid_spacing_property) == secondary_grid_spacing_value + Report.result(Tests.secondary_grid_spacing, secondary_grid_spacing_set) + + # 5. Create Global Skylight (IBL) Entity as a child entity of the Default Level Entity. + global_skylight_name = "Global Skylight (IBL)" + global_skylight_entity = EditorEntity.create_editor_entity(global_skylight_name, default_level_entity.id) + + # 6. Add HDRi Skybox component to the Global Skylight (IBL) Entity. + hdri_skybox_name = "HDRi Skybox" + hdri_skybox_component = global_skylight_entity.add_component(hdri_skybox_name) + Report.result(Tests.hdri_skybox_component_added, global_skylight_entity.has_component(hdri_skybox_name)) + + # 7. Add Global Skylight (IBL) component to the Global Skylight (IBL) Entity. + global_skylight_component = global_skylight_entity.add_component(global_skylight_name) + Report.result(Tests.global_skylight_component_added, global_skylight_entity.has_component(global_skylight_name)) + + # 8. Set the Cubemap Texture property of the HDRi Skybox component. + global_skylight_image_asset_path = os.path.join( + "LightingPresets", "greenwich_park_02_4k_iblskyboxcm_iblspecular.exr.streamingimage") + global_skylight_image_asset = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", global_skylight_image_asset_path, math.Uuid(), False) + hdri_skybox_cubemap_texture_property = "Controller|Configuration|Cubemap Texture" + hdri_skybox_component.set_component_property_value( + hdri_skybox_cubemap_texture_property, global_skylight_image_asset) + Report.result( + Tests.hdri_skybox_cubemap_texture_set, + hdri_skybox_component.get_component_property_value( + hdri_skybox_cubemap_texture_property) == global_skylight_image_asset) + + # 9. Set the Diffuse Image property of the Global Skylight (IBL) component. + # Re-use the same image that was used in the previous test step. + global_skylight_diffuse_image_property = "Controller|Configuration|Diffuse Image" + global_skylight_component.set_component_property_value( + global_skylight_diffuse_image_property, global_skylight_image_asset) + Report.result( + Tests.global_skylight_diffuse_image_set, + global_skylight_component.get_component_property_value( + global_skylight_diffuse_image_property) == global_skylight_image_asset) + + # 10. Set the Specular Image property of the Global Skylight (IBL) component. + # Re-use the same image that was used in the previous test step. + global_skylight_specular_image_property = "Controller|Configuration|Specular Image" + global_skylight_component.set_component_property_value( + global_skylight_specular_image_property, global_skylight_image_asset) + global_skylight_specular_image_set = global_skylight_component.get_component_property_value( + global_skylight_specular_image_property) + Report.result( + Tests.global_skylight_specular_image_set, global_skylight_specular_image_set == global_skylight_image_asset) + + # 11. Create a Ground Plane Entity with a Material component that is a child entity of the Default Level Entity. + ground_plane_name = "Ground Plane" + ground_plane_entity = EditorEntity.create_editor_entity(ground_plane_name, default_level_entity.id) + ground_plane_material_component = ground_plane_entity.add_component(MATERIAL_COMPONENT_NAME) + Report.result( + Tests.ground_plane_material_component_added, ground_plane_entity.has_component(MATERIAL_COMPONENT_NAME)) + + # 12. Set the Material Asset property of the Material component for the Ground Plane Entity. + ground_plane_entity.set_local_uniform_scale(32.0) + ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") + ground_plane_material_asset = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) + ground_plane_material_asset_property = "Default Material|Material Asset" + ground_plane_material_component.set_component_property_value( + ground_plane_material_asset_property, ground_plane_material_asset) + Report.result( + Tests.ground_plane_material_asset_set, + ground_plane_material_component.get_component_property_value( + ground_plane_material_asset_property) == ground_plane_material_asset) + + # 13. Add the Mesh component to the Ground Plane Entity and set the Mesh component Mesh Asset property. + ground_plane_mesh_component = ground_plane_entity.add_component(MESH_COMPONENT_NAME) + Report.result(Tests.mesh_component_added, ground_plane_entity.has_component(MESH_COMPONENT_NAME)) + ground_plane_mesh_asset_path = os.path.join("Objects", "plane.azmodel") + ground_plane_mesh_asset = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False) + ground_plane_mesh_asset_property = "Controller|Configuration|Mesh Asset" + ground_plane_mesh_component.set_component_property_value( + ground_plane_mesh_asset_property, ground_plane_mesh_asset) + Report.result( + Tests.ground_plane_mesh_asset_set, + ground_plane_mesh_component.get_component_property_value( + ground_plane_mesh_asset_property) == ground_plane_mesh_asset) + + # 14. Create a Directional Light Entity as a child entity of the Default Level Entity. + directional_light_name = "Directional Light" + directional_light_entity = EditorEntity.create_editor_entity_at( + math.Vector3(0.0, 0.0, 10.0), directional_light_name, default_level_entity.id) + + # 15. Add Directional Light component to Directional Light Entity and set entity rotation. + directional_light_entity.add_component(directional_light_name) + directional_light_entity_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * -90.0, 0.0, 0.0) + directional_light_entity.set_local_rotation(directional_light_entity_rotation) + Report.result( + Tests.directional_light_component_added, directional_light_entity.has_component(directional_light_name)) + + # 16. Create a Sphere Entity as a child entity of the Default Level Entity then add a Material component. + sphere_entity = EditorEntity.create_editor_entity_at( + math.Vector3(0.0, 0.0, 1.0), "Sphere", default_level_entity.id) + sphere_material_component = sphere_entity.add_component(MATERIAL_COMPONENT_NAME) + Report.result(Tests.sphere_material_component_added, sphere_entity.has_component(MATERIAL_COMPONENT_NAME)) + + # 17. Set the Material Asset property of the Material component for the Sphere Entity. + sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") + sphere_material_asset = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) + sphere_material_asset_property = "Default Material|Material Asset" + sphere_material_component.set_component_property_value(sphere_material_asset_property, sphere_material_asset) + Report.result(Tests.sphere_material_set, sphere_material_component.get_component_property_value( + sphere_material_asset_property) == sphere_material_asset) + + # 18. Add Mesh component to Sphere Entity and set the Mesh Asset property for the Mesh component. + sphere_mesh_component = sphere_entity.add_component(MESH_COMPONENT_NAME) + sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel") + sphere_mesh_asset = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False) + sphere_mesh_asset_property = "Controller|Configuration|Mesh Asset" + sphere_mesh_component.set_component_property_value(sphere_mesh_asset_property, sphere_mesh_asset) + Report.result(Tests.sphere_mesh_asset_set, sphere_mesh_component.get_component_property_value( + sphere_mesh_asset_property) == sphere_mesh_asset) + + # 19. Create a Camera Entity as a child entity of the Default Level Entity then add a Camera component. + camera_name = "Camera" + camera_entity = EditorEntity.create_editor_entity_at( + math.Vector3(5.5, -12.0, 9.0), camera_name, default_level_entity.id) + camera_component = camera_entity.add_component(camera_name) + Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name)) + + # 20. Set the Camera Entity rotation value and set the Camera component Field of View value. + camera_entity_rotation = math.Vector3( + DEGREE_RADIAN_FACTOR * -27.0, DEGREE_RADIAN_FACTOR * -12.0, DEGREE_RADIAN_FACTOR * 25.0) + camera_entity.set_local_rotation(camera_entity_rotation) + camera_fov_property = "Controller|Configuration|Field of view" + camera_fov_value = 60.0 + camera_component.set_component_property_value(camera_fov_property, camera_fov_value) + azlmbr.camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) + Report.result(Tests.camera_fov_set, camera_component.get_component_property_value( + camera_fov_property) == camera_fov_value) + + # 21. Enter game mode. + helper.enter_game_mode(Tests.enter_game_mode) + helper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 22. Take screenshot. + ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(f"{SCREENSHOT_NAME}.ppm") + + # 23. Exit game mode. + helper.exit_game_mode(Tests.exit_game_mode) + helper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0) + + # 24. Look for errors. + helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + Report.result(Tests.no_assert_occurred, not error_tracer.has_asserts) + Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomGPU_BasicLevelSetup_SetsUpLevel) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index 154b5730d7..783f71e06c 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -361,3 +361,19 @@ class EditorEntity: :return: True if "isVisible" is enabled, False otherwise. """ return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id) + + def set_local_uniform_scale(self, scale_float) -> None: + """ + Sets the "SetLocalUniformScale" value on the entity. + :param scale_float: value for "SetLocalUniformScale" to set to. + :return: None + """ + azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", self.id, scale_float) + + def set_local_rotation(self, vector3_rotation) -> None: + """ + Sets the "SetLocalRotation" value on the entity. + :param vector3_rotation: The math.Vector3 value to use for rotation on the entity (uses radians). + :return: None + """ + azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, vector3_rotation) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py index cc217f81da..ef3048d8d4 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -4,18 +4,18 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ + +import json +import math import os import time -import math +import traceback +from typing import Callable, Tuple import azlmbr import azlmbr.legacy.general as general import azlmbr.debug -import json -import traceback - -from typing import Callable, Tuple class FailFast(Exception): """ @@ -127,6 +127,31 @@ class TestHelper: if ret: return True + @staticmethod + def close_error_windows(): + """ + Closes Error Report and Error Log windows that block focus if they are visible. + :return: None + """ + if general.is_pane_visible("Error Report"): + general.close_pane("Error Report") + if general.is_pane_visible("Error Log"): + general.close_pane("Error Log") + + @staticmethod + def close_display_helpers(): + """ + Closes helper gizmos, anti-aliasing, and FPS meters. + :return: None + """ + if general.is_helpers_shown(): + general.toggle_helpers() + general.idle_wait(1.0) + general.idle_wait(1.0) + general.run_console("r_displayInfo=0") + general.run_console("r_antialiasingmode=0") + general.idle_wait(1.0) + class Timeout: # type: (float) -> None @@ -149,6 +174,7 @@ class Timeout: def timed_out(self): return time.time() > self.die_after + class Report: _results = [] _exception = None @@ -290,8 +316,8 @@ class Report: Report.info(" x: {:.2f}, y: {:.2f}, z: {:.2f}".format(vector3.x, vector3.y, vector3.z)) if magnitude is not None: Report.info(" magnitude: {:.2f}".format(magnitude)) - - + + ''' Utility for scope tracing errors and warnings. Usage: @@ -303,7 +329,7 @@ Usage: Report.result(Tests.warnings_not_found_in_section, not section_tracer.has_warnings) -''' +''' class Tracer: def __init__(self): self.warnings = [] @@ -349,10 +375,10 @@ class Tracer: self.line = args[1] self.function = args[2] self.message = args[3] - + def __str__(self): return f"Assert: [{self.filename}:{self.function}:{self.line}]: {self.message}" - + def __repr__(self): return f"[Assert: {self.message}]" @@ -360,21 +386,21 @@ class Tracer: def __init__(self, args): self.window = args[0] self.message = args[1] - + def _on_warning(self, args): warningInfo = Tracer.WarningInfo(args) self.warnings.append(warningInfo) Report.info("Tracer caught Warning: %s" % warningInfo.message) self.has_warnings = True return False - + def _on_error(self, args): errorInfo = Tracer.ErrorInfo(args) self.errors.append(errorInfo) Report.info("Tracer caught Error: %s" % errorInfo.message) self.has_errors = True return False - + def _on_assert(self, args): assertInfo = Tracer.AssertInfo(args) self.asserts.append(assertInfo) @@ -436,6 +462,7 @@ class AngleHelper: def vector3_str(vector3): return "(x: {:.2f}, y: {:.2f}, z: {:.2f})".format(vector3.x, vector3.y, vector3.z) - + + def aabb_str(aabb): return "[Min: %s, Max: %s]" % (vector3_str(aabb.min), vector3_str(aabb.max)) From 0cd1f20d39493ab6bf37285f1a37a5de95b8835a Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Wed, 6 Oct 2021 09:35:55 +0200 Subject: [PATCH 053/293] EMotion FX: Simple LOD Component to use Atom LOD override (#4464) The LOD level for skinned meshes is determined in the render phase, which is after the animation update and is also specific to the camera/target Atom renders to, which means that different render targets could end up using different LOD levels depending on how much screen space the character's bounding box takes. In order to make sure that all transformations are calculated by EMotion FX that the skinned mesh Atom wants to render are available, the Simple LOD Component takes ownership of the LOD level and uses the Atom LOD override. That way Atom adapts to the LOD level determined by the Simple LOD component and makes sure the skeletal matches with the geometry LOD levels. Signed-off-by: Benjamin Jillich --- Gems/EMotionFX/Code/CMakeLists.txt | 1 + .../Components/SimpleLODComponent.cpp | 42 +++++++++++++++++-- .../Components/SimpleLODComponent.h | 5 ++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index ed5447ba25..dace02b2ae 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -36,6 +36,7 @@ ly_add_target( PUBLIC AZ::AtomCore Gem::Atom_RPI.Public + Gem::AtomLyIntegration_CommonFeatures.Static Gem::LmbrCentral COMPILE_DEFINITIONS PUBLIC diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.cpp index 5db0fae842..aa17058adf 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.cpp @@ -142,12 +142,31 @@ namespace EMotionFX { ActorComponentNotificationBus::Handler::BusConnect(GetEntityId()); AZ::TickBus::Handler::BusConnect(); + + // Remember the lod type and level so that we can set it back to the previous one on deactivation of the component. + AZ::Render::MeshComponentRequestBus::EventResult(m_previousLodType, + GetEntityId(), + &AZ::Render::MeshComponentRequestBus::Events::GetLodType); + + if (m_actorInstance) + { + m_previousLodLevel = m_actorInstance->GetLODLevel(); + } } void SimpleLODComponent::Deactivate() { AZ::TickBus::Handler::BusDisconnect(); ActorComponentNotificationBus::Handler::BusDisconnect(); + + AZ::Render::MeshComponentRequestBus::Event(GetEntityId(), + &AZ::Render::MeshComponentRequestBus::Events::SetLodType, + m_previousLodType); + + if (m_actorInstance) + { + m_actorInstance->SetLODLevel(m_previousLodLevel); + } } void SimpleLODComponent::OnActorInstanceCreated(EMotionFX::ActorInstance* actorInstance) @@ -183,7 +202,7 @@ namespace EMotionFX return max - 1; } - void SimpleLODComponent::UpdateLodLevelByDistance(EMotionFX::ActorInstance * actorInstance, const Configuration& configuration, AZ::EntityId entityId) + void SimpleLODComponent::UpdateLodLevelByDistance(EMotionFX::ActorInstance* actorInstance, const Configuration& configuration, AZ::EntityId entityId) { if (actorInstance) { @@ -201,15 +220,30 @@ namespace EMotionFX AZ::RPI::ViewportContextPtr defaultViewportContext = viewportContextManager->GetViewportContextByName(viewportContextManager->GetDefaultViewportContextName()); const float distance = worldPos.GetDistance(defaultViewportContext->GetCameraTransform().GetTranslation()); - const size_t lodByDistance = GetLodByDistance(configuration.m_lodDistances, distance); - actorInstance->SetLODLevel(lodByDistance); + const size_t requestedLod = GetLodByDistance(configuration.m_lodDistances, distance); + actorInstance->SetLODLevel(requestedLod); if (configuration.m_enableLodSampling) { - const float animGraphSampleRate = configuration.m_lodSampleRates[lodByDistance]; + const float animGraphSampleRate = configuration.m_lodSampleRates[requestedLod]; const float updateRateInSeconds = animGraphSampleRate > 0.0f ? 1.0f / animGraphSampleRate : 0.0f; actorInstance->SetMotionSamplingRate(updateRateInSeconds); } + + // Disable the automatic mesh LOD level adjustment based on screen space in case a simple LOD component is present. + // The simple LOD component overrides the mesh LOD level and syncs the skeleton with the mesh LOD level. + AZ::Render::MeshComponentRequestBus::Event(entityId, + &AZ::Render::MeshComponentRequestBus::Events::SetLodType, + AZ::RPI::Cullable::LodType::SpecificLod); + + // When setting the actor instance LOD level, a change is just requested and with the next update it will get applied. + // This means that the current LOD level might differ from the requested one. We need to sync the Atom LOD level with the + // current LOD level of the actor instance to avoid skinning artifacts. The requested LOD level will be present and applied + // the following frame. + const size_t currentLod = actorInstance->GetLODLevel(); + AZ::Render::MeshComponentRequestBus::Event(entityId, + &AZ::Render::MeshComponentRequestBus::Events::SetLodOverride, + static_cast(currentLod)); } } } // namespace integration diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.h b/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.h index 96bebdc660..a00918e7c0 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Components/SimpleLODComponent.h @@ -17,7 +17,7 @@ #include #include - +#include namespace EMotionFX { @@ -93,6 +93,9 @@ namespace EMotionFX Configuration m_configuration; // Component configuration. EMotionFX::ActorInstance* m_actorInstance; // Associated actor instance (retrieved from Actor Component). + + AZ::RPI::Cullable::LodType m_previousLodType = AZ::RPI::Cullable::LodType::Default; + size_t m_previousLodLevel = 0; }; } // namespace Integration From 606ba45cf2c5d9902cd3d42a7bc99154894bceb4 Mon Sep 17 00:00:00 2001 From: moraaar Date: Wed, 6 Oct 2021 09:46:04 +0100 Subject: [PATCH 054/293] Fixed PhysX and Blast creation of default config files (#4497) - Avoid saving blast global configuration unnecessarily every time the editor is opened. - Fixed how to obtain the default physics material library. The relative path needs to be from the project folder, not the asset folder inside the project. It was also missing saving the physx configuration after a the default library is assigned to it. - Fixed asset id for physics material asset 'assets/physics/surfacetypemateriallibrary.physmaterial' Signed-off-by: moraaar moraaar@amazon.com --- ...llider_AddingNewGroupWorks.setreg_override | 2 +- ...er_CollisionGroupsWorkflow.setreg_override | 2 +- ...fCollidingLayersNotCollide.setreg_override | 2 +- ...onGroupSameLayerNotCollide.setreg_override | 2 +- ...roupSameCustomLayerCollide.setreg_override | 2 +- .../Registry/physxsystemconfiguration.setreg | 2 +- .../Components/BlastSystemComponent.cpp | 14 +++++++--- .../Source/Components/BlastSystemComponent.h | 1 + .../Components/EditorSystemComponent.cpp | 26 ++++++++++++++----- Gems/PhysX/Code/Source/System/PhysXSystem.cpp | 6 +++-- Gems/PhysX/Code/Source/SystemComponent.cpp | 24 ++++++++++++++--- 11 files changed, 63 insertions(+), 20 deletions(-) diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override index 7065f0dfeb..209e9a9feb 100644 --- a/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override +++ b/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override @@ -109,7 +109,7 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" + "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}" }, "loadBehavior": "QueueLoad", "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override index b82acaf0ae..65f15f8554 100644 --- a/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override +++ b/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override @@ -121,7 +121,7 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" + "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}" }, "loadBehavior": "QueueLoad", "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override index b82acaf0ae..65f15f8554 100644 --- a/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override +++ b/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override @@ -121,7 +121,7 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" + "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}" }, "loadBehavior": "QueueLoad", "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override index b82acaf0ae..65f15f8554 100644 --- a/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override +++ b/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override @@ -121,7 +121,7 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" + "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}" }, "loadBehavior": "QueueLoad", "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override index b82acaf0ae..65f15f8554 100644 --- a/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override +++ b/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override @@ -121,7 +121,7 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" + "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}" }, "loadBehavior": "QueueLoad", "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" diff --git a/AutomatedTesting/Registry/physxsystemconfiguration.setreg b/AutomatedTesting/Registry/physxsystemconfiguration.setreg index 83aad307a6..2ade83d769 100644 --- a/AutomatedTesting/Registry/physxsystemconfiguration.setreg +++ b/AutomatedTesting/Registry/physxsystemconfiguration.setreg @@ -103,7 +103,7 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" + "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}" }, "loadBehavior": "QueueLoad", "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index 21ec1a4603..b7ee805b3c 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -286,8 +286,11 @@ namespace Blast DefaultConfigurationPath, globalConfiguration); AZ_Warning("Blast", loaded, "Failed to load Blast configuration, initializing with default configs."); - SetGlobalConfiguration(globalConfiguration); - SaveConfiguration(); + ApplyGlobalConfiguration(globalConfiguration); + if (!loaded) + { + SaveConfiguration(); + } } void BlastSystemComponent::SaveConfiguration() @@ -394,8 +397,13 @@ namespace Blast void BlastSystemComponent::SetGlobalConfiguration(const BlastGlobalConfiguration& globalConfiguration) { - m_configuration = globalConfiguration; + ApplyGlobalConfiguration(globalConfiguration); SaveConfiguration(); + } + + void BlastSystemComponent::ApplyGlobalConfiguration(const BlastGlobalConfiguration& globalConfiguration) + { + m_configuration = globalConfiguration; { AZ::Data::Asset& materialLibrary = m_configuration.m_materialLibrary; diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.h b/Gems/Blast/Code/Source/Components/BlastSystemComponent.h index a43bc17aca..8f6c200870 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.h +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.h @@ -93,6 +93,7 @@ namespace Blast void InitPhysics(); void DeactivatePhysics(); + void ApplyGlobalConfiguration(const BlastGlobalConfiguration& materialLibrary); void RegisterCommands(); // Internal helper functions & classes diff --git a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp index f65768cec9..a5b6430591 100644 --- a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp +++ b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp @@ -8,7 +8,9 @@ #include "EditorSystemComponent.h" #include +#include #include +#include #include #include #include @@ -23,7 +25,7 @@ namespace PhysX { - constexpr const char* DefaultAssetFilePath = "Physics/SurfaceTypeMaterialLibrary"; + constexpr const char* DefaultAssetFilePath = "Assets/Physics/SurfaceTypeMaterialLibrary"; constexpr const char* TemplateAssetFilename = "PhysX/TemplateMaterialLibrary"; static AZStd::optional> GetMaterialLibraryTemplate() @@ -67,7 +69,7 @@ namespace PhysX assetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, relativePath.c_str(), assetType, true /*autoRegisterIfNotFound*/); AZ::Data::Asset newAsset = - AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, AZ::Data::AssetLoadBehavior::Default); + AZ::Data::AssetManager::Instance().FindOrCreateAsset(assetId, assetType, AZ::Data::AssetLoadBehavior::Default); if (auto* newMaterialLibraryData = azrtti_cast(newAsset.GetData())) { @@ -138,6 +140,14 @@ namespace PhysX if (auto retrievedMaterialLibrary = RetrieveDefaultMaterialLibrary()) { physxSystem->UpdateMaterialLibrary(retrievedMaterialLibrary.value()); + + // After setting the default material library, save the physx configuration. + auto saveCallback = []([[maybe_unused]] const PhysXSystemConfiguration& config, [[maybe_unused]] PhysXSettingsRegistryManager::Result result) + { + AZ_Warning("PhysX", result == PhysXSettingsRegistryManager::Result::Success, + "Unable to save the PhysX configuration after setting default material library."); + }; + physxSystem->GetSettingsRegistryManager().SaveSystemConfiguration(physxSystem->GetPhysXConfiguration(), saveCallback); } } } @@ -236,11 +246,15 @@ namespace PhysX if (!resultAssetId.IsValid()) { // No file for the default material library, create it - const char* assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectsourceassets@"); - AZStd::string fullPath; - AzFramework::StringFunc::Path::ConstructFull(assetRoot, DefaultAssetFilePath, assetExtension.c_str(), fullPath); + AZ::IO::Path fullPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(fullPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); + } + fullPath /= DefaultAssetFilePath; + fullPath.ReplaceExtension(AZ::IO::PathView(assetExtension)); - if (auto materialLibraryOpt = CreateMaterialLibrary(fullPath, relativePath)) + if (auto materialLibraryOpt = CreateMaterialLibrary(fullPath.Native(), relativePath)) { return materialLibraryOpt; } diff --git a/Gems/PhysX/Code/Source/System/PhysXSystem.cpp b/Gems/PhysX/Code/Source/System/PhysXSystem.cpp index ebdfc5d417..cc21285f8c 100644 --- a/Gems/PhysX/Code/Source/System/PhysXSystem.cpp +++ b/Gems/PhysX/Code/Source/System/PhysXSystem.cpp @@ -511,10 +511,12 @@ namespace PhysX materialLibrary.BlockUntilLoadComplete(); - AZ_Warning("PhysX", (materialLibrary.GetData() != nullptr), + const bool loadedSuccessfully = materialLibrary.GetData() != nullptr && !materialLibrary.IsError(); + + AZ_Warning("PhysX", loadedSuccessfully, "LoadDefaultMaterialLibrary: Default Material Library asset data is invalid."); - return materialLibrary.GetData() != nullptr && !materialLibrary.IsError(); + return loadedSuccessfully; } //TEMP -- until these are fully moved over here diff --git a/Gems/PhysX/Code/Source/SystemComponent.cpp b/Gems/PhysX/Code/Source/SystemComponent.cpp index 42c78d2c1d..f56ad43079 100644 --- a/Gems/PhysX/Code/Source/SystemComponent.cpp +++ b/Gems/PhysX/Code/Source/SystemComponent.cpp @@ -458,7 +458,13 @@ namespace PhysX { const PhysXSystemConfiguration defaultConfig = PhysXSystemConfiguration::CreateDefault(); m_physXSystem->Initialize(&defaultConfig); - registryManager.SaveSystemConfiguration(defaultConfig, {}); + + auto saveCallback = []([[maybe_unused]] const PhysXSystemConfiguration& config, [[maybe_unused]] PhysXSettingsRegistryManager::Result result) + { + AZ_Warning("PhysX", result == PhysXSettingsRegistryManager::Result::Success, + "Unable to save the default PhysX configuration."); + }; + registryManager.SaveSystemConfiguration(defaultConfig, saveCallback); } //Load the DefaultSceneConfig @@ -471,7 +477,13 @@ namespace PhysX { const AzPhysics::SceneConfiguration defaultConfig = AzPhysics::SceneConfiguration::CreateDefault(); m_physXSystem->UpdateDefaultSceneConfiguration(defaultConfig); - registryManager.SaveDefaultSceneConfiguration(defaultConfig, {}); + + auto saveCallback = []([[maybe_unused]] const AzPhysics::SceneConfiguration& config, [[maybe_unused]] PhysXSettingsRegistryManager::Result result) + { + AZ_Warning("PhysX", result == PhysXSettingsRegistryManager::Result::Success, + "Unable to save the default Scene configuration."); + }; + registryManager.SaveDefaultSceneConfiguration(defaultConfig, saveCallback); } //load the debug configuration and initialize the PhysX debug interface @@ -486,7 +498,13 @@ namespace PhysX { const Debug::DebugConfiguration defaultConfig = Debug::DebugConfiguration::CreateDefault(); debug->Initialize(defaultConfig); - registryManager.SaveDebugConfiguration(defaultConfig, {}); + + auto saveCallback = []([[maybe_unused]] const Debug::DebugConfiguration& config, [[maybe_unused]] PhysXSettingsRegistryManager::Result result) + { + AZ_Warning("PhysX", result == PhysXSettingsRegistryManager::Result::Success, + "Unable to save the default PhysX Debug configuration."); + }; + registryManager.SaveDebugConfiguration(defaultConfig, saveCallback); } } } From 5308a0fbbb729c0355a4abee490cc5d4551d0cb7 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 6 Oct 2021 11:57:42 +0100 Subject: [PATCH 055/293] Remove redundant editor mode notifications. Signed-off-by: John --- Code/Editor/Core/LevelEditorMenuHandler.cpp | 48 ++++++++------ Code/Editor/Core/LevelEditorMenuHandler.h | 12 ++-- Code/Editor/Objects/ObjectManager.cpp | 37 ++++++----- Code/Editor/Objects/ObjectManager.h | 13 ++-- .../UI/Outliner/OutlinerWidget.cpp | 22 ++++--- .../UI/Outliner/OutlinerWidget.hxx | 12 ++-- Code/Editor/QtViewPaneManager.cpp | 59 ++++++++++++++--- Code/Editor/QtViewPaneManager.h | 8 +-- .../API/ComponentModeCollectionInterface.h | 28 +++++++++ ...ewportEditorModeTrackerNotificationBus.cpp | 27 ++++++++ ...ViewportEditorModeTrackerNotificationBus.h | 5 ++ .../ComponentMode/ComponentModeCollection.cpp | 20 ++---- .../ComponentMode/ComponentModeCollection.h | 5 ++ .../ComponentMode/ComponentModeDelegate.cpp | 16 +---- .../ComponentMode/EditorComponentModeBus.h | 42 ------------- .../UI/Outliner/EntityOutlinerWidget.cpp | 22 ++++--- .../UI/Outliner/EntityOutlinerWidget.hxx | 12 ++-- .../UI/PropertyEditor/ComponentEditor.hxx | 1 - .../PropertyEditor/EntityPropertyEditor.cpp | 63 ++++++++++++------- .../PropertyEditor/EntityPropertyEditor.hxx | 13 +++- .../UnitTest/AzToolsFrameworkTestHelpers.cpp | 20 ++++-- .../UnitTest/AzToolsFrameworkTestHelpers.h | 12 ++-- .../EditorDefaultSelection.cpp | 9 +++ .../EditorTransformComponentSelection.cpp | 32 ++++++---- .../EditorTransformComponentSelection.h | 10 +-- .../aztoolsframework_files.cmake | 2 + 26 files changed, 345 insertions(+), 205 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp index e568f05167..25467756ac 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp @@ -32,6 +32,7 @@ #include // AzToolsFramework +#include #include // AzQtComponents @@ -166,15 +167,14 @@ LevelEditorMenuHandler::LevelEditorMenuHandler(MainWindow* mainWindow, QtViewPan m_mainWindow->menuBar()->setNativeMenuBar(true); #endif - ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect( - AzToolsFramework::GetEntityContextId()); + ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId()); EditorMenuRequestBus::Handler::BusConnect(); } LevelEditorMenuHandler::~LevelEditorMenuHandler() { EditorMenuRequestBus::Handler::BusDisconnect(); - ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); + ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); } void LevelEditorMenuHandler::Initialize() @@ -1186,30 +1186,38 @@ void LevelEditorMenuHandler::AddDisableActionInSimModeListener(QAction* action) })); } -void LevelEditorMenuHandler::EnteredComponentMode(const AZStd::vector& /*componentModeTypes*/) +void LevelEditorMenuHandler::OnEditorModeActivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); - if (!menuWrapper.isNull()) + if (mode == ViewportEditorMode::Component) { - // copy of menu actions - auto actions = menuWrapper.Get()->actions(); - // remove all non-reserved edit menu options - actions.erase( - std::remove_if(actions.begin(), actions.end(), [](QAction* action) - { - return !action->property("Reserved").toBool(); - }), - actions.end()); + auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); + if (!menuWrapper.isNull()) + { + // copy of menu actions + auto actions = menuWrapper.Get()->actions(); + // remove all non-reserved edit menu options + actions.erase( + std::remove_if(actions.begin(), actions.end(), [](QAction* action) + { + return !action->property("Reserved").toBool(); + }), + actions.end()); - // clear and update the menu with new actions - menuWrapper.Get()->clear(); - menuWrapper.Get()->addActions(actions); + // clear and update the menu with new actions + menuWrapper.Get()->clear(); + menuWrapper.Get()->addActions(actions); + } } } -void LevelEditorMenuHandler::LeftComponentMode(const AZStd::vector& /*componentModeTypes*/) +void LevelEditorMenuHandler::OnEditorModeDeactivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - RestoreEditMenuToDefault(); + if (mode == ViewportEditorMode::Component) + { + RestoreEditMenuToDefault(); + } } void LevelEditorMenuHandler::AddEditMenuAction(QAction* action) diff --git a/Code/Editor/Core/LevelEditorMenuHandler.h b/Code/Editor/Core/LevelEditorMenuHandler.h index 5ac8e63786..ff03c7748c 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.h +++ b/Code/Editor/Core/LevelEditorMenuHandler.h @@ -18,7 +18,7 @@ #include #include "ActionManager.h" #include "QtViewPaneManager.h" -#include +#include #endif class MainWindow; @@ -28,7 +28,7 @@ struct QtViewPane; class LevelEditorMenuHandler : public QObject - , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler + , private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler , private AzToolsFramework::EditorMenuRequestBus::Handler { Q_OBJECT @@ -88,9 +88,11 @@ private: void AddDisableActionInSimModeListener(QAction* action); - // EditorComponentModeNotificationBus - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; - void LeftComponentMode(const AZStd::vector& componentModeTypes) override; + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; + void OnEditorModeDeactivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; // EditorMenuRequestBus void AddEditMenuAction(QAction* action) override; diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp index f67cf24553..7057cc5b7b 100644 --- a/Code/Editor/Objects/ObjectManager.cpp +++ b/Code/Editor/Objects/ObjectManager.cpp @@ -30,6 +30,8 @@ #include "Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h" #include +#include +#include AZ_CVAR_EXTERNED(bool, ed_visibility_logTiming); @@ -107,14 +109,13 @@ CObjectManager::CObjectManager() m_objectsByName.reserve(1024); LoadRegistry(); - AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect( - AzToolsFramework::GetEntityContextId()); + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); } ////////////////////////////////////////////////////////////////////////// CObjectManager::~CObjectManager() { - AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); m_bExiting = true; SaveRegistry(); @@ -2306,25 +2307,33 @@ void CObjectManager::SelectObjectInRect(CBaseObject* pObj, CViewport* view, HitC } } -void CObjectManager::EnteredComponentMode(const AZStd::vector& /*componentModeTypes*/) +void CObjectManager::OnEditorModeActivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - // hide current gizmo for entity (translate/rotate/scale) - IGizmoManager* gizmoManager = GetGizmoManager(); - const size_t gizmoCount = static_cast(gizmoManager->GetGizmoCount()); - for (size_t i = 0; i < gizmoCount; ++i) + if (mode == AzToolsFramework::ViewportEditorMode::Component) { - gizmoManager->RemoveGizmo(gizmoManager->GetGizmoByIndex(static_cast(i))); + // hide current gizmo for entity (translate/rotate/scale) + IGizmoManager* gizmoManager = GetGizmoManager(); + const size_t gizmoCount = static_cast(gizmoManager->GetGizmoCount()); + for (size_t i = 0; i < gizmoCount; ++i) + { + gizmoManager->RemoveGizmo(gizmoManager->GetGizmoByIndex(static_cast(i))); + } } } -void CObjectManager::LeftComponentMode(const AZStd::vector& /*componentModeTypes*/) +void CObjectManager::OnEditorModeDeactivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - // show translate/rotate/scale gizmo again - if (IGizmoManager* gizmoManager = GetGizmoManager()) + if (mode == AzToolsFramework::ViewportEditorMode::Component) { - if (CBaseObject* selectedObject = GetIEditor()->GetSelectedObject()) + // show translate/rotate/scale gizmo again + if (IGizmoManager* gizmoManager = GetGizmoManager()) { - gizmoManager->AddGizmo(new CAxisGizmo(selectedObject)); + if (CBaseObject* selectedObject = GetIEditor()->GetSelectedObject()) + { + gizmoManager->AddGizmo(new CAxisGizmo(selectedObject)); + } } } } diff --git a/Code/Editor/Objects/ObjectManager.h b/Code/Editor/Objects/ObjectManager.h index 0ad5d8323e..7fb2342e40 100644 --- a/Code/Editor/Objects/ObjectManager.h +++ b/Code/Editor/Objects/ObjectManager.h @@ -20,8 +20,9 @@ #include "ObjectManagerEventBus.h" #include -#include +#include #include +#include #include // forward declarations. @@ -58,7 +59,7 @@ public: */ class CObjectManager : public IObjectManager - , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler + , private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler { public: //! Selection functor callback. @@ -329,9 +330,11 @@ private: void FindDisplayableObjects(DisplayContext& dc, bool bDisplay); - // EditorComponentModeNotificationBus - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; - void LeftComponentMode(const AZStd::vector& componentModeTypes) override; + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; + void OnEditorModeDeactivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; private: typedef std::map Objects; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp index 9ed7c4a144..803deb3509 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -267,8 +268,7 @@ OutlinerWidget::OutlinerWidget(QWidget* pParent, Qt::WindowFlags flags) ToolsApplicationEvents::Bus::Handler::BusConnect(); AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect(); AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusConnect(); - AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect( - AzToolsFramework::GetEntityContextId()); + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); AzToolsFramework::EditorEntityInfoNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorWindowUIRequestBus::Handler::BusConnect(); } @@ -276,7 +276,7 @@ OutlinerWidget::OutlinerWidget(QWidget* pParent, Qt::WindowFlags flags) OutlinerWidget::~OutlinerWidget() { AzToolsFramework::EditorWindowUIRequestBus::Handler::BusDisconnect(); - AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); + AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); AzToolsFramework::EditorEntityInfoNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect(); EntityHighlightMessages::Bus::Handler::BusDisconnect(); @@ -1335,14 +1335,22 @@ void OutlinerWidget::SetEditorUiEnabled(bool enable) EnableUi(enable); } -void OutlinerWidget::EnteredComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) +void OutlinerWidget::OnEditorModeActivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - EnableUi(false); + if (mode == AzToolsFramework::ViewportEditorMode::Component) + { + EnableUi(false); + } } -void OutlinerWidget::LeftComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) +void OutlinerWidget::OnEditorModeDeactivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - EnableUi(true); + if (mode == AzToolsFramework::ViewportEditorMode::Component) + { + EnableUi(true); + } } void OutlinerWidget::OnSliceInstantiated(const AZ::Data::AssetId& /*sliceAssetId*/, AZ::SliceComponent::SliceInstanceAddress& sliceAddress, const AzFramework::SliceInstantiationTicket& /*ticket*/) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx index b29032a760..364ab05eb7 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -58,7 +58,7 @@ class OutlinerWidget , private AzToolsFramework::EditorEntityContextNotificationBus::Handler , private AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler , private AzToolsFramework::EditorEntityInfoNotificationBus::Handler - , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler + , private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler , private AzToolsFramework::EditorWindowUIRequestBus::Handler { Q_OBJECT; @@ -105,9 +105,11 @@ private: void OnEntityInfoUpdatedAddChildEnd(AZ::EntityId /*parentId*/, AZ::EntityId /*childId*/) override; void OnEntityInfoUpdatedName(AZ::EntityId entityId, const AZStd::string& /*name*/) override; - // EditorComponentModeNotificationBus - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; - void LeftComponentMode(const AZStd::vector& componentModeTypes) override; + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; + void OnEditorModeDeactivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; // EditorWindowUIRequestBus overrides void SetEditorUiEnabled(bool enable) override; diff --git a/Code/Editor/QtViewPaneManager.cpp b/Code/Editor/QtViewPaneManager.cpp index eff3a7331e..0f9fd480ca 100644 --- a/Code/Editor/QtViewPaneManager.cpp +++ b/Code/Editor/QtViewPaneManager.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -44,11 +45,54 @@ #include #include #include - #include #include "ShortcutDispatcher.h" +// Helper for EditorComponentModeNotifications to be used +// as a member instead of inheriting from EBus directly. +class ViewportEditorModeNotificationsBusImpl + : public AzToolsFramework::ViewportEditorModeNotificationsBus::Handler +{ + public: + /// Set the function to be called when entering ComponentMode. + void SetEnteredComponentModeFunc( + const AZStd::function& enteredComponentModeFunc) + { + m_enteredComponentModeFunc = enteredComponentModeFunc; + } + + /// Set the function to be called when leaving ComponentMode. + void SetLeftComponentModeFunc( + const AZStd::function& leftComponentModeFunc) + { + m_leftComponentModeFunc = leftComponentModeFunc; + } + + private: + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override + { + if (mode == AzToolsFramework::ViewportEditorMode::Component) + { + m_enteredComponentModeFunc(editorModeState); + } + } + + void OnEditorModeDeactivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override + { + if (mode == AzToolsFramework::ViewportEditorMode::Component) + { + m_leftComponentModeFunc(editorModeState); + } + } + + AZStd::function m_enteredComponentModeFunc; ///< Function to call when entering ComponentMode. + AZStd::function m_leftComponentModeFunc; ///< Function to call when leaving ComponentMode. +}; + struct ViewLayoutState { QVector viewPanes; @@ -519,16 +563,17 @@ QtViewPaneManager::QtViewPaneManager(QObject* parent) , m_settings(nullptr) , m_restoreInProgress(false) , m_advancedDockManager(nullptr) + , m_componentModeNotifications(AZStd::make_unique()) { qRegisterMetaTypeStreamOperators("ViewLayoutState"); qRegisterMetaTypeStreamOperators >("QVector"); // view pane manager is interested when we enter/exit ComponentMode - m_componentModeNotifications.BusConnect(AzToolsFramework::GetEntityContextId()); + m_componentModeNotifications->BusConnect(AzToolsFramework::GetEntityContextId()); m_windowRequest.BusConnect(); - m_componentModeNotifications.SetEnteredComponentModeFunc( - [this](const AZStd::vector& /*componentModeTypes*/) + m_componentModeNotifications->SetEnteredComponentModeFunc( + [this](const AzToolsFramework::ViewportEditorModesInterface&) { // gray out panels when entering ComponentMode SetDefaultActionsEnabled(false, m_registeredPanes, [](QWidget* widget, bool on) @@ -537,8 +582,8 @@ QtViewPaneManager::QtViewPaneManager(QObject* parent) }); }); - m_componentModeNotifications.SetLeftComponentModeFunc( - [this](const AZStd::vector& /*componentModeTypes*/) + m_componentModeNotifications->SetLeftComponentModeFunc( + [this](const AzToolsFramework::ViewportEditorModesInterface&) { // enable panels again when leaving ComponentMode SetDefaultActionsEnabled(true, m_registeredPanes, [](QWidget* widget, bool on) @@ -563,7 +608,7 @@ QtViewPaneManager::QtViewPaneManager(QObject* parent) QtViewPaneManager::~QtViewPaneManager() { m_windowRequest.BusDisconnect(); - m_componentModeNotifications.BusDisconnect(); + m_componentModeNotifications->BusDisconnect(); } static bool lessThan(const QtViewPane& v1, const QtViewPane& v2) diff --git a/Code/Editor/QtViewPaneManager.h b/Code/Editor/QtViewPaneManager.h index 3ad1cc9cf7..fe568e5438 100644 --- a/Code/Editor/QtViewPaneManager.h +++ b/Code/Editor/QtViewPaneManager.h @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -34,6 +33,7 @@ #endif class QMainWindow; +class ViewportEditorModeNotificationsBusImpl; struct ViewLayoutState; namespace AzQtComponents @@ -245,9 +245,9 @@ private: QPointer m_advancedDockManager; - using EditorComponentModeNotificationBusImpl = AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBusImpl; - EditorComponentModeNotificationBusImpl m_componentModeNotifications; //!< Helper for EditorComponentModeNotificationBus so - //!< QtViewPaneManager does not need to inherit directly from it. */ + AZStd::unique_ptr + m_componentModeNotifications; //!< Helper for EditorComponentModeNotificationBus so + //!< QtViewPaneManager does not need to inherit directly from it. */ using EditorWindowRequestBusImpl = AzToolsFramework::EditorWindowRequestBusImpl; EditorWindowRequestBusImpl m_windowRequest; //!< Helper for EditorWindowRequestBus so diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h new file mode 100644 index 0000000000..39cd6bd6a3 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AzToolsFramework +{ + //! The AZ::Interface for component mode collection queries. + class ComponentModeCollectionInterface + { + public: + AZ_RTTI(ComponentModeCollectionInterface, "{DFAA4450-BBCD-47C0-9B91-FEA2DBD9B152}"); + + virtual ~ComponentModeCollectionInterface() = default; + + //! Retrieves the list of all Component types (usually one). + virtual const AZStd::vector& GetComponentTypes() const = 0; + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp new file mode 100644 index 0000000000..278f9db950 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace AzToolsFramework +{ + void ViewportEditorModeNotifications::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("ViewportEditorModeNotificationsBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Category, "Editor") + ->Attribute(AZ::Script::Attributes::Module, "editor") + ->Event("OnEditorModeActivated", &ViewportEditorModeNotifications::OnEditorModeActivated) + ->Event("OnEditorModeDeactivated", &ViewportEditorModeNotifications::OnEditorModeDeactivated) + ; + } + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index 4fcb891e61..4fb4191d45 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -34,6 +34,8 @@ namespace AzToolsFramework class ViewportEditorModesInterface { public: + AZ_RTTI(ViewportEditorModesInterface, "{2421496C-4A46-41C9-8AEF-AE2B6E43E6CF}"); + virtual ~ViewportEditorModesInterface() = default; //! Returns true if the specified editor mode is active, otherwise false. @@ -52,6 +54,9 @@ namespace AzToolsFramework using BusIdType = ViewportEditorModeTrackerInfo::IdType; ////////////////////////////////////////////////////////////////////////// + AZ_RTTI(ViewportEditorModeNotifications, "{9469DE39-6C21-423C-94FA-EF3A9616B14F}", AZ::EBusTraits); + static void Reflect(AZ::ReflectContext* context); + //! Notifies subscribers of the a given viewport to the activation of the specified editor mode. virtual void OnEditorModeActivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index df93e924b8..e816c0ce4c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -203,6 +203,11 @@ namespace AzToolsFramework } } + const AZStd::vector& ComponentModeCollection::GetComponentTypes() const + { + return m_activeComponentTypes; + } + void ComponentModeCollection::BeginComponentMode() { m_selectedComponentModeIndex = 0; @@ -211,13 +216,6 @@ namespace AzToolsFramework // notify listeners the editor has entered ComponentMode - listeners may // wish to modify state to indicate this (e.g. appearance, functionality etc.) - EditorComponentModeNotificationBus::Event( - GetEntityContextId(), &EditorComponentModeNotifications::EnteredComponentMode, - m_activeComponentTypes); - - // this call to activate the component mode editor state should eventually replace the bus call in - // ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode - // such that all of the notifications for activating/deactivating the different editor modes are in a central location m_viewportEditorModeTracker->ActivateMode({ GetEntityContextId() }, ViewportEditorMode::Component); // enable actions for the first/primary ComponentMode @@ -288,14 +286,6 @@ namespace AzToolsFramework // notify listeners the editor has left ComponentMode - listeners may // wish to modify state to indicate this (e.g. appearance, functionality etc.) - EditorComponentModeNotificationBus::Event( - GetEntityContextId(), - &EditorComponentModeNotifications::LeftComponentMode, - m_activeComponentTypes); - - // this call to deactivate the component mode editor state should eventually replace the bus call in - // ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode - // such that all of the notifications for activating/deactivating the different editor modes are in a central location m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Component); // clear stored modes and builders for this ComponentMode diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index 9e299d2323..fb35ca8971 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -21,6 +22,7 @@ namespace AzToolsFramework { /// Manages all individual ComponentModes for a single instance of Editor wide ComponentMode. class ComponentModeCollection + : public ComponentModeCollectionInterface { public: AZ_CLASS_ALLOCATOR_DECL @@ -89,6 +91,9 @@ namespace AzToolsFramework /// Called once each time a ComponentMode is added. void PopulateViewportUi(); + // ComponentModeCollectionInterface overrides ... + const AZStd::vector& GetComponentTypes() const override; + private: // Internal helper used by Select[|Prev|Next]ActiveComponentMode bool ActiveComponentModeChanged(const AZ::Uuid& previousComponentType); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeDelegate.cpp index 325fc3909b..f0baeaea7e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeDelegate.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeDelegate.cpp @@ -24,18 +24,8 @@ namespace AzToolsFramework : public EditorComponentModeNotificationBus::Handler , public AZ::BehaviorEBusHandler { - AZ_EBUS_BEHAVIOR_BINDER(EditorComponentModeNotificationBusHandler, "{AD2F4204-0913-4FC9-9A10-492538F60C70}", AZ::SystemAllocator, - EnteredComponentMode, LeftComponentMode, ActiveComponentModeChanged); - - void EnteredComponentMode(const AZStd::vector& componentTypes) override - { - Call(FN_EnteredComponentMode, componentTypes); - } - - void LeftComponentMode(const AZStd::vector& componentTypes) override - { - Call(FN_LeftComponentMode, componentTypes); - } + AZ_EBUS_BEHAVIOR_BINDER( + EditorComponentModeNotificationBusHandler, "{AD2F4204-0913-4FC9-9A10-492538F60C70}", AZ::SystemAllocator, ActiveComponentModeChanged); void ActiveComponentModeChanged(const AZ::Uuid& componentType) override { @@ -171,8 +161,6 @@ namespace AzToolsFramework ->Attribute(AZ::Script::Attributes::Category, "Editor") ->Attribute(AZ::Script::Attributes::Module, "editor") ->Handler() - ->Event("EnteredComponentMode", &EditorComponentModeNotifications::EnteredComponentMode) - ->Event("LeftComponentMode", &EditorComponentModeNotifications::LeftComponentMode) ->Event("ActiveComponentModeChanged", &EditorComponentModeNotifications::ActiveComponentModeChanged) ; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorComponentModeBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorComponentModeBus.h index 5be535e1ed..67a8291e22 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorComponentModeBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorComponentModeBus.h @@ -238,12 +238,6 @@ namespace AzToolsFramework using BusIdType = AzFramework::EntityContextId; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - /// Called when Editor enters ComponentMode - pass the list of all Component types (usually one). - virtual void EnteredComponentMode(const AZStd::vector& componentTypes) = 0; - - /// Called when Editor leaves ComponentMode - pass the list of all Component types (usually one). - virtual void LeftComponentMode(const AZStd::vector& componentTypes) = 0; - /// Called when Tab is pressed to cycle the 'selected' ComponentMode (which shortcuts/actions are active). /// Also called when directly selecting a Component in the EntityOutliner. virtual void ActiveComponentModeChanged(const AZ::Uuid& /*componentType*/) {} @@ -255,42 +249,6 @@ namespace AzToolsFramework /// Type to inherit to implement EditorComponentModeNotifications. using EditorComponentModeNotificationBus = AZ::EBus; - /// Helper for EditorComponentModeNotifications to be used - /// as a member instead of inheriting from EBus directly. - class EditorComponentModeNotificationBusImpl - : public EditorComponentModeNotificationBus::Handler - { - public: - /// Set the function to be called when entering ComponentMode. - void SetEnteredComponentModeFunc( - const AZStd::function&)>& enteredComponentModeFunc) - { - m_enteredComponentModeFunc = enteredComponentModeFunc; - } - - /// Set the function to be called when leaving ComponentMode. - void SetLeftComponentModeFunc( - const AZStd::function&)>& leftComponentModeFunc) - { - m_leftComponentModeFunc = leftComponentModeFunc; - } - - private: - // EditorComponentModeNotificationBus - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override - { - m_enteredComponentModeFunc(componentModeTypes); - } - - void LeftComponentMode(const AZStd::vector& componentModeTypes) override - { - m_leftComponentModeFunc(componentModeTypes); - } - - AZStd::function&)> m_enteredComponentModeFunc; ///< Function to call when entering ComponentMode. - AZStd::function&)> m_leftComponentModeFunc; ///< Function to call when leaving ComponentMode. - }; - /// Helper to answer if the Editor is in ComponentMode or not. inline bool InComponentMode() { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 689e5b5dc4..347057d9ba 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -291,8 +292,7 @@ namespace AzToolsFramework EntityOutlinerModelNotificationBus::Handler::BusConnect(); ToolsApplicationEvents::Bus::Handler::BusConnect(); EditorEntityContextNotificationBus::Handler::BusConnect(); - ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect( - GetEntityContextId()); + ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId()); EditorEntityInfoNotificationBus::Handler::BusConnect(); Prefab::PrefabPublicNotificationBus::Handler::BusConnect(); EditorWindowUIRequestBus::Handler::BusConnect(); @@ -302,7 +302,7 @@ namespace AzToolsFramework { EditorWindowUIRequestBus::Handler::BusDisconnect(); Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect(); - ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); + ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); EditorEntityInfoNotificationBus::Handler::BusDisconnect(); EditorPickModeNotificationBus::Handler::BusDisconnect(); EntityHighlightMessages::Bus::Handler::BusDisconnect(); @@ -1123,14 +1123,22 @@ namespace AzToolsFramework EnableUi(enable); } - void EntityOutlinerWidget::EnteredComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) + void EntityOutlinerWidget::OnEditorModeActivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - EnableUi(false); + if (mode == ViewportEditorMode::Component) + { + EnableUi(false); + } } - void EntityOutlinerWidget::LeftComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) + void EntityOutlinerWidget::OnEditorModeDeactivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - EnableUi(true); + if (mode == ViewportEditorMode::Component) + { + EnableUi(true); + } } void EntityOutlinerWidget::OnPrefabInstancePropagationBegin() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx index 78aced3587..dcf23b19c0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include @@ -58,7 +58,7 @@ namespace AzToolsFramework , private ToolsApplicationEvents::Bus::Handler , private EditorEntityContextNotificationBus::Handler , private EditorEntityInfoNotificationBus::Handler - , private ComponentModeFramework::EditorComponentModeNotificationBus::Handler + , private ViewportEditorModeNotificationsBus::Handler , private Prefab::PrefabPublicNotificationBus::Handler , private EditorWindowUIRequestBus::Handler { @@ -100,9 +100,11 @@ namespace AzToolsFramework void OnEntityInfoUpdatedAddChildEnd(AZ::EntityId /*parentId*/, AZ::EntityId /*childId*/) override; void OnEntityInfoUpdatedName(AZ::EntityId entityId, const AZStd::string& /*name*/) override; - // EditorComponentModeNotificationBus - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; - void LeftComponentMode(const AZStd::vector& componentModeTypes) override; + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; + void OnEditorModeDeactivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; // PrefabPublicNotificationBus void OnPrefabInstancePropagationBegin() override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.hxx index b2140868da..f450ec7ac9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ComponentEditor.hxx @@ -90,7 +90,6 @@ namespace AzToolsFramework void SetComponentOverridden(const bool overridden); - // Calls match EditorComponentModeNotificationBus - called from EntityPropertyEditor void EnteredComponentMode(const AZStd::vector& componentModeTypes); void LeftComponentMode(const AZStd::vector& componentModeTypes); void ActiveComponentModeChanged(const AZ::Uuid& componentType); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 87527502dd..ad62614770 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -33,6 +33,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include @@ -486,8 +487,12 @@ namespace AzToolsFramework , m_isSystemEntityEditor(false) , m_isLevelEntityEditor(isLevelEntityEditor) { + initEntityPropertyEditorResources(); + m_componentModeCollection = AZ::Interface::Get(); + AZ_Assert(m_componentModeCollection, "Could not retrieve component mode collection."); + m_prefabPublicInterface = AZ::Interface::Get(); AZ_Assert(m_prefabPublicInterface != nullptr, "EntityPropertyEditor requires a PrefabPublicInterface instance on Initialize."); @@ -5698,39 +5703,49 @@ namespace AzToolsFramework SaveComponentEditorState(); } - void EntityPropertyEditor::EnteredComponentMode(const AZStd::vector& componentModeTypes) + void EntityPropertyEditor::OnEditorModeActivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - DisableComponentActions(this, m_entityComponentActions); - SetPropertyEditorState(m_gui, false); - m_disabled = true; - - if (!componentModeTypes.empty()) + if (mode == AzToolsFramework::ViewportEditorMode::Component) { - m_componentEditorLastSelectedIndex = GetComponentEditorIndexFromType(componentModeTypes.front()); - } + DisableComponentActions(this, m_entityComponentActions); + SetPropertyEditorState(m_gui, false); + const auto& componentModeTypes = m_componentModeCollection->GetComponentTypes(); + m_disabled = true; + + if (!componentModeTypes.empty()) + { + m_componentEditorLastSelectedIndex = GetComponentEditorIndexFromType(componentModeTypes.front()); + } - for (auto componentEditor : m_componentEditors) - { - componentEditor->EnteredComponentMode(componentModeTypes); - } + for (auto componentEditor : m_componentEditors) + { + componentEditor->EnteredComponentMode(componentModeTypes); + } - // record the selected state after entering component mode - SaveComponentEditorState(); + // record the selected state after entering component mode + SaveComponentEditorState(); + } } - void EntityPropertyEditor::LeftComponentMode(const AZStd::vector& componentModeTypes) + void EntityPropertyEditor::OnEditorModeDeactivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - EnableComponentActions(this, m_entityComponentActions); - SetPropertyEditorState(m_gui, true); - m_disabled = false; - - for (auto componentEditor : m_componentEditors) + if (mode == AzToolsFramework::ViewportEditorMode::Component) { - componentEditor->LeftComponentMode(componentModeTypes); - } + EnableComponentActions(this, m_entityComponentActions); + SetPropertyEditorState(m_gui, true); + const auto& componentModeTypes = m_componentModeCollection->GetComponentTypes(); + m_disabled = false; - // record the selected state after leaving component mode - SaveComponentEditorState(); + for (auto componentEditor : m_componentEditors) + { + componentEditor->LeftComponentMode(componentModeTypes); + } + + // record the selected state after leaving component mode + SaveComponentEditorState(); + } } void EntityPropertyEditor::ActiveComponentModeChanged(const AZ::Uuid& componentType) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx index 83b275b81a..5279cefa9f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ namespace AzToolsFramework { class ComponentEditor; class ComponentPaletteWidget; + class ComponentModeCollectionInterface; struct SourceControlFileInfo; namespace AssetBrowser @@ -108,6 +110,7 @@ namespace AzToolsFramework , public AzToolsFramework::EditorEntityContextNotificationBus::Handler , public AzToolsFramework::EntityPropertyEditorRequestBus::Handler , public AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler + , private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler , public EditorInspectorComponentNotificationBus::MultiHandler , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler , public AZ::EntitySystemBus::Handler @@ -231,10 +234,14 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// // EditorComponentModeNotificationBus - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; - void LeftComponentMode(const AZStd::vector& componentModeTypes) override; void ActiveComponentModeChanged(const AZ::Uuid& componentType) override; + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; + void OnEditorModeDeactivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; + // EntityPropertEditorRequestBus void GetSelectedAndPinnedEntities(EntityIdList& selectedEntityIds) override; void GetSelectedEntities(EntityIdList& selectedEntityIds) override; @@ -627,6 +634,8 @@ namespace AzToolsFramework float m_moveFadeSecondsRemaining; AZStd::vector m_indexMapOfMovedRow; + AzToolsFramework::ComponentModeCollectionInterface* m_componentModeCollection = nullptr; + // When m_initiatingPropertyChangeNotification is set to true, it means this EntityPropertyEditor is // broadcasting a change to all listeners about a property change for a given entity. This is needed // so that we don't update the values twice for this inspector diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp index 8d30359562..a0d02f47e7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp @@ -129,7 +129,7 @@ namespace UnitTest using AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus; AzToolsFramework::EditorActionRequestBus::Handler::BusConnect(); - EditorComponentModeNotificationBus::Handler::BusConnect(GetEntityContextId()); + ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId()); m_defaultWidget.setFocus(); } @@ -137,18 +137,26 @@ namespace UnitTest { using AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus; - EditorComponentModeNotificationBus::Handler::BusDisconnect(); + ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); AzToolsFramework::EditorActionRequestBus::Handler::BusDisconnect(); } - void TestEditorActions::EnteredComponentMode([[maybe_unused]] const AZStd::vector& componentTypes) + void TestEditorActions::OnEditorModeActivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - m_componentModeWidget.setFocus(); + if (mode == ViewportEditorMode::Component) + { + m_componentModeWidget.setFocus(); + } } - void TestEditorActions::LeftComponentMode([[maybe_unused]] const AZStd::vector& componentTypes) + void TestEditorActions::OnEditorModeDeactivated( + [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) { - m_defaultWidget.setFocus(); + if (mode == ViewportEditorMode::Component) + { + m_defaultWidget.setFocus(); + } } void TestEditorActions::AddActionViaBus(int id, QAction* action) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h index c4aefecce5..4a7039423c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h @@ -23,9 +23,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -103,7 +103,7 @@ namespace UnitTest /// component mode editing. class TestEditorActions : private AzToolsFramework::EditorActionRequestBus::Handler - , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler + , private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler { // EditorActionRequestBus ... void AddActionViaBus(int id, QAction* action) override; @@ -114,9 +114,11 @@ namespace UnitTest void AttachOverride(QWidget* /*object*/) override {} void DetachOverride() override {} - // EditorComponentModeNotificationBus ... - void EnteredComponentMode(const AZStd::vector& componentTypes) override; - void LeftComponentMode(const AZStd::vector& componentTypes) override; + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; + void OnEditorModeDeactivated( + const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; public: void Connect(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index 1ad0ee8ff3..fafa1b3198 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -27,6 +27,10 @@ namespace AzToolsFramework , m_viewportEditorModeTracker(viewportEditorModeTracker) , m_componentModeCollection(viewportEditorModeTracker) { + AZ_Assert( + AZ::Interface::Get() == nullptr, "Unexpected registration of component mode collection.") + AZ::Interface::Register(&m_componentModeCollection); + ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId()); ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect(); @@ -40,6 +44,11 @@ namespace AzToolsFramework ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect(); ActionOverrideRequestBus::Handler::BusDisconnect(); m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Default); + + AZ_Assert( + AZ::Interface::Get() != nullptr, + "Unexpected unregistration of component mode collection.") + AZ::Interface::Unregister(&m_componentModeCollection); } void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index ccb72e1d50..4c1fefc622 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -1027,7 +1027,7 @@ namespace AzToolsFramework EditorTransformComponentSelectionRequestBus::Handler::BusConnect(entityContextId); ToolsApplicationNotificationBus::Handler::BusConnect(); Camera::EditorCameraNotificationBus::Handler::BusConnect(); - ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect(entityContextId); + ViewportEditorModeNotificationsBus::Handler::BusConnect(entityContextId); EditorEntityContextNotificationBus::Handler::BusConnect(); EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); @@ -1075,7 +1075,7 @@ namespace AzToolsFramework EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); EditorEntityContextNotificationBus::Handler::BusDisconnect(); - ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); + ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); Camera::EditorCameraNotificationBus::Handler::BusDisconnect(); ToolsApplicationNotificationBus::Handler::BusDisconnect(); EditorTransformComponentSelectionRequestBus::Handler::BusDisconnect(); @@ -3707,22 +3707,30 @@ namespace AzToolsFramework m_selectedEntityIdsAndManipulatorsDirty = true; } - void EditorTransformComponentSelection::EnteredComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) + void EditorTransformComponentSelection::OnEditorModeActivated( + [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) { - SetAllViewportUiVisible(false); + if (mode == ViewportEditorMode::Component) + { + SetAllViewportUiVisible(false); - EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); - EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); - ToolsApplicationNotificationBus::Handler::BusDisconnect(); + EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); + EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); + ToolsApplicationNotificationBus::Handler::BusDisconnect(); + } } - void EditorTransformComponentSelection::LeftComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) + void EditorTransformComponentSelection::OnEditorModeDeactivated( + [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) { - SetAllViewportUiVisible(true); + if (mode == ViewportEditorMode::Component) + { + SetAllViewportUiVisible(true); - ToolsApplicationNotificationBus::Handler::BusConnect(); - EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); - EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); + ToolsApplicationNotificationBus::Handler::BusConnect(); + EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); + EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); + } } void EditorTransformComponentSelection::CreateEntityManipulatorDeselectCommand(ScopedUndoBatch& undoBatch) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h index a0e87d9d6f..1e1cc6d2e1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -153,7 +153,7 @@ namespace AzToolsFramework , private EditorTransformComponentSelectionRequestBus::Handler , private ToolsApplicationNotificationBus::Handler , private Camera::EditorCameraNotificationBus::Handler - , private ComponentModeFramework::EditorComponentModeNotificationBus::Handler + , private ViewportEditorModeNotificationsBus::Handler , private EditorEntityContextNotificationBus::Handler , private EditorEntityVisibilityNotificationBus::Router , private EditorEntityLockComponentNotificationBus::Router @@ -286,9 +286,9 @@ namespace AzToolsFramework // EditorContextLockComponentNotificationBus overrides ... void OnEntityLockChanged(bool locked) override; - // EditorComponentModeNotificationBus overrides ... - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; - void LeftComponentMode(const AZStd::vector& componentModeTypes) override; + // ViewportEditorModeNotificationsBus overrides ... + void OnEditorModeActivated(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override; + void OnEditorModeDeactivated(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override; // EditorEntityContextNotificationBus overrides ... void OnStartPlayInEditor() override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index f09d4f9b72..74c5db3f5e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -30,12 +30,14 @@ set(FILES API/AssetDatabaseBus.h API/ComponentEntityObjectBus.h API/ComponentEntitySelectionBus.h + API/ComponentModeCollectionInterface.h API/EditorCameraBus.h API/EditorCameraBus.cpp API/EditorAnimationSystemRequestBus.h API/EditorEntityAPI.h API/EditorLevelNotificationBus.h API/ViewportEditorModeTrackerNotificationBus.h + API/ViewportEditorModeTrackerNotificationBus.cpp API/EditorVegetationRequestsBus.h API/EditorPythonConsoleBus.h API/EditorPythonRunnerRequestsBus.h From 317d624f6ca7b6ed867cde5c841d3abea90ab63d Mon Sep 17 00:00:00 2001 From: John Date: Wed, 6 Oct 2021 13:01:49 +0100 Subject: [PATCH 056/293] Minor formatting. Signed-off-by: John --- Code/Editor/QtViewPaneManager.cpp | 4 ++-- .../ViewportSelection/EditorDefaultSelection.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Editor/QtViewPaneManager.cpp b/Code/Editor/QtViewPaneManager.cpp index 0f9fd480ca..1ac4b9cfe3 100644 --- a/Code/Editor/QtViewPaneManager.cpp +++ b/Code/Editor/QtViewPaneManager.cpp @@ -55,14 +55,14 @@ class ViewportEditorModeNotificationsBusImpl : public AzToolsFramework::ViewportEditorModeNotificationsBus::Handler { public: - /// Set the function to be called when entering ComponentMode. + // Set the function to be called when entering ComponentMode. void SetEnteredComponentModeFunc( const AZStd::function& enteredComponentModeFunc) { m_enteredComponentModeFunc = enteredComponentModeFunc; } - /// Set the function to be called when leaving ComponentMode. + // Set the function to be called when leaving ComponentMode. void SetLeftComponentModeFunc( const AZStd::function& leftComponentModeFunc) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index fafa1b3198..1541d4678e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -29,7 +29,7 @@ namespace AzToolsFramework { AZ_Assert( AZ::Interface::Get() == nullptr, "Unexpected registration of component mode collection.") - AZ::Interface::Register(&m_componentModeCollection); + AZ::Interface::Register(&m_componentModeCollection); ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId()); ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect(); From 5cee9b43b7a6413b5459dac6ce3e52e6d37c9a97 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 6 Oct 2021 07:14:38 -0500 Subject: [PATCH 057/293] Squashed commit of Procedural Prefab work (#4481) * Squashed commit of the following: commit 964a45ead662f502ff0d63ae3528a9aa18a760f4 Merge: 8d4c1dee78 799ab8585b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Oct 1 16:16:47 2021 -0500 Merge branch 'development' into Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h commit 8d4c1dee782a1b82ded14d11f7fe879c865980a7 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 15:49:22 2021 -0500 fixing non-unity build Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit e83431b3be58f36a875b5187c03cd67368d91726 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 12:42:38 2021 -0500 fixing Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp:172:28: error: member access into incomplete type 'AZ::BehaviorContext' Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit b0523867d9605aff67710f4ab6030f327cd5558f Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 10:23:56 2021 -0500 fix for error: unused variable 'targetInstanceRef' Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 387c42ac1a4268ff8b2701c0c914e384b355e629 Merge: d87b41997e 0fb821a44b Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 10:00:46 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' of https://github.com/aws-lumberyard-dev/o3de into Feature_LY-5384_ProceduralPrefabs commit d87b41997eec9a6b0d03c1040901904d68b873fb Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 30 18:03:38 2021 -0500 fixing non-unity build Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 0fb821a44b788ab1cca61dce7c1fbdbedc2f37c0 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 30 15:43:50 2021 -0500 adding header for validation Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 30f5135f63286ce8f752df5787937f9543589cb5 Merge: 2d9e1b9f16 103dc6cfcf Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 30 11:20:15 2021 -0500 Merge branch 'development' into Feature_LY-5384_ProceduralPrefabs added a few headers as well # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 2d9e1b9f16f8861df92c58f0f83974859e615b1f Merge: 39ee7a8a80 af84e71638 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 14:22:39 2021 -0500 Merge pull request #244 from aws-lumberyard-dev/feature_lyn5880_procprefab_tooling_updates {lyn5880} adding Instantiate Procedural Prefab to the Editor commit af84e716384de048c8555fe5ccdc293e885896f9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 14:21:09 2021 -0500 updated based on feeback Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 9c83f6086203e14becb60af5ae937e8e609eb9ed Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 11:35:30 2021 -0500 small include tweak Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 11ac99a87097621796af79329bf9d9344155049e Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 10:08:53 2021 -0500 moved the seg reg key to the CPP file removed the Queue Load Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 39ee7a8a803a032652b122b73fba7007abbdbf88 Merge: 0fc7d5f361 8b4f5ded51 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 29 08:24:57 2021 -0500 Merge pull request #241 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_PythonExample Add example prefab script and FBX with 2 meshes to test it commit 941f6a00d1a6222f10acfcd55a2017be6352f723 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 28 16:07:47 2021 -0500 make sure the AZ::IO::SystemFile::Exists() before returning fullPath Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 8b4f5ded510d8c6ef47a2d2380fa49c7f6e1fd4e Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 28 14:03:11 2021 -0500 Move sceneJobHandler reset out of exception block. Add more info to error messages Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 0c82937fcd90d0c606c330f6d3e4cec8eca7edb3 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 28 13:04:37 2021 -0500 {lyn5880} adding Instantiate Procedural Prefab to the Editor Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 0fc7d5f3610f95dcdd97614a282b9f4eabfc93dc Merge: ea90e321d7 8ca6acc67d Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 28 09:23:54 2021 -0500 Merge pull request #235 from aws-lumberyard-dev/feature_lyn5394_procprefab_asset {ly5395} adding asset loading logic for procedural prefabs commit 8ca6acc67dcbd375df9813acbf0062a8a5c7809a Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Mon Sep 27 13:52:21 2021 -0500 added AZ::Prefab::PrefabGroupAssetHandler::s_Extension optimized headers Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit e446aaa4e9951e474f832299f8149142dbf6e85f Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 27 09:12:40 2021 -0500 Remove some whitespace Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ea90e321d737cd7bafbe617f9b5fbbeae3c4a7e9 Merge: f4c9fc50c3 5ae3c67cc7 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 27 09:04:58 2021 -0500 Merge pull request #238 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_PythonScript Fixes to support writing a python script to generate a prefab commit b69ebbae17826b59f3f4fb675c57be5582acf628 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 17:51:17 2021 -0500 Use raise_error instead of print Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 407b8d804841f0ba87a0c82405c9d1319435e2da Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 17:47:20 2021 -0500 Add scene_mesh_to_prefab.py example ProceduralPrefab script and multiple_mesh_one_material FBX which uses the script Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 5ae3c67cc70603ec70f53c03ee716982b55b759a Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 14:50:47 2021 -0500 Test entity cleanup Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 55da78dda5ef9bc558b65bf99d551ffebd38acef Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 14:50:28 2021 -0500 Make CastWithTypeName only return true if the object can be successfully cast Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 9f2e85bb691a86910d14477f94b9e631ee343e0b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 14:49:28 2021 -0500 Remove RemoveAllTemplates API from scripting API and use prefab system interface version instead Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 41d46d1f00a16243d3fffda32186fcd7964db78a Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 13:19:51 2021 -0500 Store watch folder in scene so source relative path can be calculated Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f4c9fc50c3ac4c3fc68e98d78b72c4f1f571b516 Merge: de2612b3b9 8bd3c0acdd Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 23 14:10:31 2021 -0500 Merge pull request #239 from aws-lumberyard-dev/fix_LY5384_script_processing_rule {ly5384} script processing rule behavior more stateless commit 8bd3c0acdd874d6421d25cc77c80da9906afefc2 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 22 15:19:30 2021 -0500 {ly5384} script processing rule beahvior more stateless Made the script processing rule beahvior more stateless so that the script name needs to be discovered each time. Disconnet from the bus after each scene script builder usage. Before it would be possible that the same script can be run more than once for each asset. Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 7afd9d4a9911adb1dc665361a09486e6852ba4f8 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 22 13:27:12 2021 -0500 Update scene_data.py to latest PrefabGroup format Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 74d1ba8853d62b75786d68a6bdeb1bfb2ca52346 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 22 13:26:27 2021 -0500 Fix GetNodeContent to return a GraphObjectProxy wrapping a nullptr instead of just returning a nullptr which causes issues for python Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ca4127353e139f9d853784ca6a74e5deeb82d6f9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 17:48:15 2021 -0500 AZ::JsonSerializationUtils update Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 30a76be51c37c1718e9b215f33b172a10bd74f08 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 17:21:52 2021 -0500 revert odd README.md merge issue added alias for PrefabBuilder.Tools Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 6c83d47d51898bcdc17c10578f0198bccd09c834 Merge: 46cb4c2a87 de2612b3b9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:52:58 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5394_procprefab_asset # Conflicts: # Gems/Prefab/PrefabBuilder/CMakeLists.txt Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 46cb4c2a8711f1adad22be24420922365707c409 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:43:19 2021 -0500 added ProceduralPrefabAssetTest to cover basics for ProceduralPrefabAsset Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit de2612b3b9a28ef130fc92d1c9d68c90790cf132 Merge: f03bbb236e 3117c54657 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:28:59 2021 -0500 Merge pull request #232 from aws-lumberyard-dev/fix_ly5384_ProceduralPrefabs_linux_compile {ly5384} Fixing Linux build issues. commit 3117c54657cb21ae2ef200dbfd1cd046c617089d Merge: 15fddd1795 f03bbb236e Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:28:48 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into fix_ly5384_ProceduralPrefabs_linux_compile commit f03bbb236eab3458fc433d35f9fb84dae88922d6 Merge: f297aa232a fccf900982 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 15:52:07 2021 -0500 Merge pull request #233 from aws-lumberyard-dev/fix_ly5384_ProceduralPrefabs_merge_fix fixing an API merge compile error commit fccf9009829b182254064ba17ab3b6e7d44919fa Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 15:50:58 2021 -0500 fixing an API merge compile error Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 762743b54744258007d8f124be95654ee6f18533 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:10:46 2021 -0500 Make sure EntityUtilityComponent is loaded in AssetBuilderApplication Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 8c4ab65598e3ebb3a0ae621feb22ef5b57e7de27 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:09:03 2021 -0500 Clean up entities and templates after python script is done Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 50a1f2a1a4f09cbd3e6256a210cd14a0fdb5b815 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 20 14:05:12 2021 -0500 ScriptProcessorRuleBehavior resets entity context Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 51a6af053d95e90e582a25ae51c5730a7e2b0973 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:40:37 2021 -0500 Add add_prefab_group Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f297aa232a2cd9ad5583b3e2b4aa1ce793c07d92 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 11:53:25 2021 -0500 Fix merge compile issue Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit fc40f5e75efbb87382bf6227966f2f905ccf6d75 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 11:18:44 2021 -0500 {ly5395} adding asset loading logic for procedural prefabs * enabling the Prefab gem for tool work * enabling prefab gem for AutomatedTesting * AssetTypeInfoHandler for procedural prefab * EnableCatalogForAsset for procedural prefab * RegisterHandler for AssetManager Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 7a2250db337fbfc693e3cf57458eb56f419b32d6 Merge: c1f3e14304 751a0fab4f Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:32:37 2021 -0500 Merge remote-tracking branch 'origin/Feature_LY-5384_ProceduralPrefabs' into origin_Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 12440233ccd987d41c248df57cee913ebb2ae2f6 Merge: 751a0fab4f f8d39e2671 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 10:25:50 2021 -0500 Merge remote-tracking branch 'origin' into feature_lyn5394_procprefab_asset commit c1f3e143048a914ab2d89146685ca5fe409dda27 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 20 14:03:53 2021 -0500 Fix merge issue Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 1990ec370df81d4b77b4646553c2b13dce18c638 Merge: 23d02ed416 fc8697edd5 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:21:10 2021 -0500 Merge branch 'development' into origin_Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp commit 751a0fab4f932ec3d7683e2d46a187eefc7addbf Merge: 23d02ed416 7b8d5629dd Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 10:10:06 2021 -0500 Merge pull request #229 from aws-lumberyard-dev/feature_lyn5394_procprefab_asset {lyn5394} adding ProceduralPrefabAsset to AZ Tools Framework commit 15fddd1795ff07e8d6ce8840a2d675713b63655c Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 10:04:06 2021 -0500 {ly5384} Fixing Linux build issues. * symbols "struct FindComponent" and "AZ::Component* FindComponent()" defined in the same scope, renamed function to FindComponentHelper * wrapped the AZ::ComponentId return for both cases Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 23d02ed4165a1db9e738057aad0b7613be8105da Merge: 0a31e39a25 0f3680a996 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 09:44:30 2021 -0500 Merge pull request #228 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_Misc Reflect Prefab/Entity constants and add failure unit tests commit 7b8d5629dd04ca1ed75c9828dbb0949f12eb2ca3 Merge: 78fe2cec6f 0a31e39a25 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 17:37:29 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5394_procprefab_asset commit 78fe2cec6fbcea9217d0b23ec056e19f144fc9a9 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 17:27:57 2021 -0500 Updated PrefabBuilder to point to new asset type for the procedural prefab Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 4da4e026582c8e7bf0fe9c7c7b39f15189c67b78 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 16:56:13 2021 -0500 {lyn5394} adding Prefab/Procedural/ProceduralPrefabAsset to AZ Tools Framework Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit c2fb7b9ccb4b7d4e8080b8830d4ceeb66cd3972c Merge: 30de326dfb a56daadc45 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 16:45:03 2021 -0500 Merge pull request #210 from aws-lumberyard-dev/feature_lyn5393_proc_prefab_behavior {LYN5393} Adding Prefab Group Behavior to output Procedural Prefab Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 0a31e39a25d36c63827424adc883e873aee20b71 Merge: 30de326dfb a56daadc45 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 16:45:03 2021 -0500 Merge pull request #210 from aws-lumberyard-dev/feature_lyn5393_proc_prefab_behavior {LYN5393} Adding Prefab Group Behavior to output Procedural Prefab commit 0f3680a9968cbbbcb9558811f8dbd287a97447ae Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 13:53:22 2021 -0500 Add failure tests and some test cleanup Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 834eab4c4bf151dfb9e49eb0a5e1f20486b6c05c Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 13:34:03 2021 -0500 Reflect InvalidTemplateId, fix reflection for InvalidComponentId Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 30de326dfbc28bbb9481bf282eb35c427469c847 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:55:16 2021 -0500 Fix merge issues Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 4bcf6b7b4f2d6285f244226b065bff65ba565094 Merge: 20c5cd7259 28fec42242 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:28:26 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs_EntityManagement' into Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 20c5cd7259235d26f1aa11e2d61ac6b8a57b8638 Merge: 050e26d609 6845942fa4 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:24:44 2021 -0500 Merge pull request #200 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_CreatePrefab API Update: Wrap PrefabSystemComponentInterface behavior commit 6845942fa419b2b6d5a0103f8d30e6515948310e Merge: 58a51c738e 65da78dcc2 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:07:33 2021 -0500 Merge pull request #208 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_SavePrefabToString API Update: AzToolsFramework::Prefab::PrefabLoaderInterface commit 65da78dcc22c4251696ebb75680928ecf83d6733 Merge: e0c5e060ab 58a51c738e Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:07:06 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs_CreatePrefab' into Feature_LY-5384_ProceduralPrefabs_SavePrefabToString Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp # Code/Framework/AzToolsFramework/Tests/Prefab/PrefabScriptingTests.cpp commit 28fec422426640540bd21b2275c7b7a90e4f8e71 Merge: c1b8b5190f d825305202 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 09:58:36 2021 -0500 Merge pull request #212 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_ComponentManagement API Update: Editor Entity Component Functions commit d825305202d5a02d60dd20fb5d0cc0ecb73f562a Merge: c280964b98 88fa6983d1 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 09:58:09 2021 -0500 Merge pull request #218 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_ComponentExplore API Update: Editor Component JSON Helper Functions commit a56daadc45e5ad8511aa5160c3afc245ca10fb83 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 16:48:41 2021 -0500 m_prefabGroupBehavior.release() -> m_prefabGroupBehavior.reset() adding error messages for the prefab processing fixed typo Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit c1a03351f55f9e8f5161c0ef0288c8e64050e399 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 16:32:42 2021 -0500 reduced the JSON for the testing framework to tree types only Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 0008866baa7882ec106e134049e2bd7b95113796 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 16:25:00 2021 -0500 enable ProceduralPrefabAsset JsonRegistrationContext Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 58a51c738e1bbd5bcad27cf1c0add4760bb8cffa Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 15 14:31:59 2021 -0500 Remove unneeded include Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit e0c5e060ab8a9cb2cfce4c083f276ab064aa08ea Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 15 14:20:04 2021 -0500 Cleanup whitespace Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 88fa6983d19ac3a0d7c4073ea390c36794d2603b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 15 13:49:20 2021 -0500 FindMatchingComponents now returns a vector of ComponentDetails which includes base class info (non-recursive) Fixed a memory leak Moved const to header Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit b57a9d4261aea85a8ddb1036307d8ad296cac859 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 10:49:32 2021 -0500 updated the DOM logic for the asset loading sake Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit f55ee9f5eabbeac998028f027e1c8adf55419a9d Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 14 13:23:13 2021 -0500 Update CreateStringPermissive to stop when enough data has been collected. Update unit tests. Fixed out of bounds behavior in EntityUtilityComponent usage of CreateStringPermissive. Updated AssetTreeFilterModel to cap the string length Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 6d6707dea8cd072261d65e0a508d1179df3892d4 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 14 10:55:38 2021 -0500 Rename GetComponentJson to GetComponentDefaultJson. Clean up GetComponentTypeIdFromName Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f4380d37a40ada353f7156b0d06b7ab60b72a151 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 14 10:29:04 2021 -0500 Move scripting ebus and handler into separate files Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 572cb58f854aa2368b18f8cf70154d471dfac047 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 10 20:27:41 2021 -0400 Renamed SearchComponents to FindMatchingComponents Added missing printf formatting Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 050e26d60931700e226a4d1a5d02d6a1d4c69915 Merge: 542bdfc5d7 c1b8b5190f Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 10 09:31:08 2021 -0400 Merge pull request #201 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_EntityManagement API Update: Editor Entity Management - Add some comments and error handling commit 875d5dc466b65d893a44e11aa9467c45cf7994e9 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 10 09:13:43 2021 -0400 Move bus and handler code into separate files Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit a2d94e24fb2cd1993835f17e7129000c00926cf7 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 17:25:35 2021 -0400 Add comments Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 16f507377f4f04c88028833f69327bd11b401b87 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 17:16:33 2021 -0400 Add error messages Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 2e6d7d40dc731989128fbe829141057b3558c88b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 16:54:20 2021 -0400 Cleanup code Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 963891eaeb8d616bb071f2a7b50cdabd994241a2 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 3 10:48:40 2021 -0500 Add and update unit tests Reflect APIs to behavior context Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 664be8eca54293407e5ce2d631375d907c1bb2f6 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 2 13:00:02 2021 -0500 Add Search and Component json output APIs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit e94fe64f366009d06b889954d292c37ea4f96fe2 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 13:37:44 2021 -0400 Make bus handler private Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 345a1b0d5edef99d5a8ea2bce2f4f3478652a4f1 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 12:30:13 2021 -0400 Address feedback Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit c280964b983635bed9e8bbfb94b2188403287d4c Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 10:12:49 2021 -0500 Address feedback Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 3b819ee827fc4c19312f2d2bc5788e2cc36de4f4 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 3 16:06:10 2021 -0500 Update unit test to verify components on saved prefab Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 0b63c0e316ec621ed17edf36109b7cd1d50ef606 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 3 12:52:46 2021 -0500 Expand test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ea59416626d9b43599cf8847585e599f8fa5fd22 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 17:32:14 2021 -0500 Add error handling Add component creation Add error testing Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 9d0f2ae33eadba0216bd245157b94692792b1a86 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:31:28 2021 -0500 enabling ProductDependencies test again Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 15d1e4730df31e71e7e3ee6d4914f19b233c1b7f Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:23:26 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5393_proc_prefab_behavior # Conflicts: # Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp # Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake # Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit ce2e4602bde26fbb34b43c73f820a97b9e229b5a Merge: 5ad0aac747 542bdfc5d7 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:14:07 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5393_proc_prefab_behavior # Conflicts: # Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp # Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake # Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 542bdfc5d762c07938f9a0f8e729070f1df9edfc Merge: 3e7564c944 4899f67986 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:09:10 2021 -0500 Merge pull request #207 from aws-lumberyard-dev/feature_lyn5392_proc_prefab_group {lyn5392} Adding PrefabGroup scene manifest rule commit 4899f67986992b7eeb5cc3b750493ed21ec7b4f3 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 16:33:24 2021 -0500 removing unneeded AZStd::move() calls Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 5ad0aac7472d24bb85990d36399a466288ecfdbc Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 16:17:52 2021 -0500 cleaned up the code finalized the unit tests fixed the code based on the tests... FTW! Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 24f289dd31292c4b9f5e5848ddc94efd986b4341 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 13:06:20 2021 -0500 Add FindComponentByTypeName and UpdateComponentForEntity APIs Add unit tests Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit c1b8b5190f973d2429731308f50c7c962d64301e Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 14:02:17 2021 -0500 Fix bus connect that should have been a bus disconnect Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit fde870d6c92e131875ec6aadda2365203a538379 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 12:57:04 2021 -0500 Fix up includes Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 8ceddd0efc90d33bc34b5287176497356e57abf9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 08:43:23 2021 -0500 WIP Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 3cc9135d87efde24430dbf1cd112bcf9b95ecaa0 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Aug 31 14:44:37 2021 -0500 Rename files Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f056b3d9578ae2f49dbc172a5929306047620be6 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Aug 31 14:14:34 2021 -0500 Remove 'editor' from bus/component name Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 0fb7a0788e879eb9dc241291f05f0acffc0b0156 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Aug 31 09:18:37 2021 -0500 {lyn5392} Adding PrefabGroup scene manifest rule * Adding PrefabGroup abstraction and concrete classes to fill out in a scene manifest * has reflections for serialization & behavior * testing the behavior using Lua * testing the serialization using JSON Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit b1756307bff9f86ae0ae1354bae8f470d19b4487 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 17:52:18 2021 -0500 Reflect SaveTemplateToString Add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ddd2bb89041c5fb8b6add2cfc02c454baab9a7d6 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 12:46:17 2021 -0500 Add warning/error messages, update module Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit e839c1cbcc340859fc6ee5cff2d802660944194b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 11:17:25 2021 -0500 Add some comments and error handling Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 347f787cc88405541889e842151de81a70598dd1 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 17:16:45 2021 -0500 Fix line endings Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit be26ab1cb16221ba879c10652b430ea31547d868 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 15:28:00 2021 -0500 Add CreatePrefabTemplate Add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 3e7564c944497b7b6cce94dbce486ed8c4561f33 Merge: 5a3c289fac 07841ee749 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 10:20:20 2021 -0500 Merge pull request #199 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_EntityManagement Add editor entity creation and unit test commit 07841ee749d2a1bc22352cbec3076ac087348676 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 16:44:57 2021 -0500 Fix line endings Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 35bc3b89cd1fcc126114ea7d61cdd21e88699080 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 15:03:35 2021 -0500 Setup CreateEditorReadyEntity to use a custom entity context Add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 82519b15510a4ec1b2daf4d883a2c4c3d9c0a347 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 09:29:20 2021 -0500 Add EditorEntityUtilityComponent for managing entities from the behavior context Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f8d39e267162db5fb2091982a7e54bc57ed108bb Merge: 43603cad5e 575faa4443 Author: Chris Galvan Date: Wed Aug 11 15:29:33 2021 -0500 Merge pull request #3049 from aws-lumberyard-dev/cgalvan/gitflow_210811 Merged stabilization/2106 to main commit 575faa4443823ed239d609692847fbd781beebcb Merge: 43603cad5e 4b817a6483 Author: Chris Galvan Date: Wed Aug 11 14:13:27 2021 -0500 Merge remote-tracking branch 'upstream/stabilization/2106' into cgalvan/gitflow_210811 Signed-off-by: Chris Galvan commit 43603cad5e715aadef47b76e24867dd41347d163 Merge: d9cce28a53 bb52475ce8 Author: Terry Michaels Date: Mon Jul 19 14:55:51 2021 -0500 Merge pull request #2271 from aws-lumberyard-dev/Foundation/miterenc/ContributingUpdate Updating CONTRIBUTING.md commit bb52475ce8c37c29b35c81b379befe5a75db1de7 Author: Terry Michaels Date: Mon Jul 19 14:55:14 2021 -0500 Updated text to be more descriptive Signed-off-by: Terry Michaels commit 697dfad486c69beb5ef40cbf6478d6ccd8753cd7 Author: Terry Michaels Date: Mon Jul 19 14:27:24 2021 -0500 Fixed typo Signed-off-by: Terry Michaels commit 650e1ab44d86664b6deab7f6cebeda40c3e1361e Author: Terry Michaels Date: Mon Jul 19 14:19:46 2021 -0500 Updating CONTRIBUTING.md Signed-off-by: Terry Michaels commit d9cce28a5387c7f5b59041869086547905f1e345 Merge: e7f787572e 486ba58628 Author: Chris Galvan Date: Mon Jul 12 14:06:57 2021 -0500 Merge pull request #2096 from aws-lumberyard-dev/cgalvan/gitflow_210712_main Merged stabilization/2106 to main commit 486ba58628488c211a6140f26caa421c38be3f0f Merge: e7f787572e 7cfde884d9 Author: Chris Galvan Date: Mon Jul 12 11:12:41 2021 -0500 Merged stabilization/2106 to development; Resolved merge conflicts Signed-off-by: Chris Galvan commit e7f787572e805c413115265e5873fb2425e2f41b Author: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Tue Jul 6 08:03:35 2021 -0700 Updates licenses to APACHE-2.0 OR MIT (#1685) Not to be committed before 7/6/2021 Signed-off-by: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> commit 837e1c737059a819d01ef4ebed7fadae42248dd8 Merge: d30de01752 efcbe2c4a1 Author: Chris Galvan Date: Fri Jul 2 12:11:27 2021 -0500 Merge pull request #1764 from aws-lumberyard-dev/cgalvan/gitflow_210702 Merged stabilization/2106 to main commit efcbe2c4a1e909182dfbd5394f9322513ba91115 Merge: d30de01752 0c43493e29 Author: Chris Galvan Date: Fri Jul 2 10:20:42 2021 -0500 Merge remote-tracking branch 'upstream/stabilization/2106' into cgalvan/gitflow_210702 Signed-off-by: Chris Galvan commit d30de01752b7eaed1f16e2163b1a75c915f061eb Author: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon Jun 28 11:20:36 2021 -0700 Updating LFS config to new endpoint (#1624) Signed-off-by: AMZN-alexpete Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * fix for "warning C4100: 'outputValueTypeId': unreferenced formal" Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * Material Editor: Added alternate skybox toggle to the toolbar Signed-off-by: Guthrie Adams Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * Squashed commit of the following: commit 964a45ead662f502ff0d63ae3528a9aa18a760f4 Merge: 8d4c1dee78 799ab8585b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Oct 1 16:16:47 2021 -0500 Merge branch 'development' into Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h commit 8d4c1dee782a1b82ded14d11f7fe879c865980a7 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 15:49:22 2021 -0500 fixing non-unity build Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit e83431b3be58f36a875b5187c03cd67368d91726 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 12:42:38 2021 -0500 fixing Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp:172:28: error: member access into incomplete type 'AZ::BehaviorContext' Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit b0523867d9605aff67710f4ab6030f327cd5558f Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 10:23:56 2021 -0500 fix for error: unused variable 'targetInstanceRef' Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 387c42ac1a4268ff8b2701c0c914e384b355e629 Merge: d87b41997e 0fb821a44b Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Fri Oct 1 10:00:46 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' of https://github.com/aws-lumberyard-dev/o3de into Feature_LY-5384_ProceduralPrefabs commit d87b41997eec9a6b0d03c1040901904d68b873fb Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 30 18:03:38 2021 -0500 fixing non-unity build Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 0fb821a44b788ab1cca61dce7c1fbdbedc2f37c0 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 30 15:43:50 2021 -0500 adding header for validation Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 30f5135f63286ce8f752df5787937f9543589cb5 Merge: 2d9e1b9f16 103dc6cfcf Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 30 11:20:15 2021 -0500 Merge branch 'development' into Feature_LY-5384_ProceduralPrefabs added a few headers as well # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 2d9e1b9f16f8861df92c58f0f83974859e615b1f Merge: 39ee7a8a80 af84e71638 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 14:22:39 2021 -0500 Merge pull request #244 from aws-lumberyard-dev/feature_lyn5880_procprefab_tooling_updates {lyn5880} adding Instantiate Procedural Prefab to the Editor commit af84e716384de048c8555fe5ccdc293e885896f9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 14:21:09 2021 -0500 updated based on feeback Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 9c83f6086203e14becb60af5ae937e8e609eb9ed Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 11:35:30 2021 -0500 small include tweak Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 11ac99a87097621796af79329bf9d9344155049e Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 29 10:08:53 2021 -0500 moved the seg reg key to the CPP file removed the Queue Load Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 39ee7a8a803a032652b122b73fba7007abbdbf88 Merge: 0fc7d5f361 8b4f5ded51 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 29 08:24:57 2021 -0500 Merge pull request #241 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_PythonExample Add example prefab script and FBX with 2 meshes to test it commit 941f6a00d1a6222f10acfcd55a2017be6352f723 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 28 16:07:47 2021 -0500 make sure the AZ::IO::SystemFile::Exists() before returning fullPath Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 8b4f5ded510d8c6ef47a2d2380fa49c7f6e1fd4e Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 28 14:03:11 2021 -0500 Move sceneJobHandler reset out of exception block. Add more info to error messages Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 0c82937fcd90d0c606c330f6d3e4cec8eca7edb3 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 28 13:04:37 2021 -0500 {lyn5880} adding Instantiate Procedural Prefab to the Editor Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 0fc7d5f3610f95dcdd97614a282b9f4eabfc93dc Merge: ea90e321d7 8ca6acc67d Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 28 09:23:54 2021 -0500 Merge pull request #235 from aws-lumberyard-dev/feature_lyn5394_procprefab_asset {ly5395} adding asset loading logic for procedural prefabs commit 8ca6acc67dcbd375df9813acbf0062a8a5c7809a Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Mon Sep 27 13:52:21 2021 -0500 added AZ::Prefab::PrefabGroupAssetHandler::s_Extension optimized headers Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit e446aaa4e9951e474f832299f8149142dbf6e85f Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 27 09:12:40 2021 -0500 Remove some whitespace Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ea90e321d737cd7bafbe617f9b5fbbeae3c4a7e9 Merge: f4c9fc50c3 5ae3c67cc7 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 27 09:04:58 2021 -0500 Merge pull request #238 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_PythonScript Fixes to support writing a python script to generate a prefab commit b69ebbae17826b59f3f4fb675c57be5582acf628 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 17:51:17 2021 -0500 Use raise_error instead of print Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 407b8d804841f0ba87a0c82405c9d1319435e2da Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 17:47:20 2021 -0500 Add scene_mesh_to_prefab.py example ProceduralPrefab script and multiple_mesh_one_material FBX which uses the script Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 5ae3c67cc70603ec70f53c03ee716982b55b759a Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 14:50:47 2021 -0500 Test entity cleanup Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 55da78dda5ef9bc558b65bf99d551ffebd38acef Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 14:50:28 2021 -0500 Make CastWithTypeName only return true if the object can be successfully cast Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 9f2e85bb691a86910d14477f94b9e631ee343e0b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 14:49:28 2021 -0500 Remove RemoveAllTemplates API from scripting API and use prefab system interface version instead Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 41d46d1f00a16243d3fffda32186fcd7964db78a Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 24 13:19:51 2021 -0500 Store watch folder in scene so source relative path can be calculated Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f4c9fc50c3ac4c3fc68e98d78b72c4f1f571b516 Merge: de2612b3b9 8bd3c0acdd Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 23 14:10:31 2021 -0500 Merge pull request #239 from aws-lumberyard-dev/fix_LY5384_script_processing_rule {ly5384} script processing rule behavior more stateless commit 8bd3c0acdd874d6421d25cc77c80da9906afefc2 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 22 15:19:30 2021 -0500 {ly5384} script processing rule beahvior more stateless Made the script processing rule beahvior more stateless so that the script name needs to be discovered each time. Disconnet from the bus after each scene script builder usage. Before it would be possible that the same script can be run more than once for each asset. Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 7afd9d4a9911adb1dc665361a09486e6852ba4f8 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 22 13:27:12 2021 -0500 Update scene_data.py to latest PrefabGroup format Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 74d1ba8853d62b75786d68a6bdeb1bfb2ca52346 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 22 13:26:27 2021 -0500 Fix GetNodeContent to return a GraphObjectProxy wrapping a nullptr instead of just returning a nullptr which causes issues for python Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ca4127353e139f9d853784ca6a74e5deeb82d6f9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 17:48:15 2021 -0500 AZ::JsonSerializationUtils update Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 30a76be51c37c1718e9b215f33b172a10bd74f08 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 17:21:52 2021 -0500 revert odd README.md merge issue added alias for PrefabBuilder.Tools Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 6c83d47d51898bcdc17c10578f0198bccd09c834 Merge: 46cb4c2a87 de2612b3b9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:52:58 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5394_procprefab_asset # Conflicts: # Gems/Prefab/PrefabBuilder/CMakeLists.txt Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 46cb4c2a8711f1adad22be24420922365707c409 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:43:19 2021 -0500 added ProceduralPrefabAssetTest to cover basics for ProceduralPrefabAsset Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit de2612b3b9a28ef130fc92d1c9d68c90790cf132 Merge: f03bbb236e 3117c54657 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:28:59 2021 -0500 Merge pull request #232 from aws-lumberyard-dev/fix_ly5384_ProceduralPrefabs_linux_compile {ly5384} Fixing Linux build issues. commit 3117c54657cb21ae2ef200dbfd1cd046c617089d Merge: 15fddd1795 f03bbb236e Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 16:28:48 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into fix_ly5384_ProceduralPrefabs_linux_compile commit f03bbb236eab3458fc433d35f9fb84dae88922d6 Merge: f297aa232a fccf900982 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 15:52:07 2021 -0500 Merge pull request #233 from aws-lumberyard-dev/fix_ly5384_ProceduralPrefabs_merge_fix fixing an API merge compile error commit fccf9009829b182254064ba17ab3b6e7d44919fa Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 15:50:58 2021 -0500 fixing an API merge compile error Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 762743b54744258007d8f124be95654ee6f18533 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:10:46 2021 -0500 Make sure EntityUtilityComponent is loaded in AssetBuilderApplication Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 8c4ab65598e3ebb3a0ae621feb22ef5b57e7de27 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:09:03 2021 -0500 Clean up entities and templates after python script is done Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 50a1f2a1a4f09cbd3e6256a210cd14a0fdb5b815 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 20 14:05:12 2021 -0500 ScriptProcessorRuleBehavior resets entity context Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 51a6af053d95e90e582a25ae51c5730a7e2b0973 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:40:37 2021 -0500 Add add_prefab_group Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f297aa232a2cd9ad5583b3e2b4aa1ce793c07d92 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 11:53:25 2021 -0500 Fix merge compile issue Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit fc40f5e75efbb87382bf6227966f2f905ccf6d75 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 11:18:44 2021 -0500 {ly5395} adding asset loading logic for procedural prefabs * enabling the Prefab gem for tool work * enabling prefab gem for AutomatedTesting * AssetTypeInfoHandler for procedural prefab * EnableCatalogForAsset for procedural prefab * RegisterHandler for AssetManager Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 7a2250db337fbfc693e3cf57458eb56f419b32d6 Merge: c1f3e14304 751a0fab4f Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:32:37 2021 -0500 Merge remote-tracking branch 'origin/Feature_LY-5384_ProceduralPrefabs' into origin_Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 12440233ccd987d41c248df57cee913ebb2ae2f6 Merge: 751a0fab4f f8d39e2671 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 10:25:50 2021 -0500 Merge remote-tracking branch 'origin' into feature_lyn5394_procprefab_asset commit c1f3e143048a914ab2d89146685ca5fe409dda27 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Sep 20 14:03:53 2021 -0500 Fix merge issue Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 1990ec370df81d4b77b4646553c2b13dce18c638 Merge: 23d02ed416 fc8697edd5 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 10:21:10 2021 -0500 Merge branch 'development' into origin_Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp commit 751a0fab4f932ec3d7683e2d46a187eefc7addbf Merge: 23d02ed416 7b8d5629dd Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 10:10:06 2021 -0500 Merge pull request #229 from aws-lumberyard-dev/feature_lyn5394_procprefab_asset {lyn5394} adding ProceduralPrefabAsset to AZ Tools Framework commit 15fddd1795ff07e8d6ce8840a2d675713b63655c Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Sep 21 10:04:06 2021 -0500 {ly5384} Fixing Linux build issues. * symbols "struct FindComponent" and "AZ::Component* FindComponent()" defined in the same scope, renamed function to FindComponentHelper * wrapped the AZ::ComponentId return for both cases Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 23d02ed4165a1db9e738057aad0b7613be8105da Merge: 0a31e39a25 0f3680a996 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 21 09:44:30 2021 -0500 Merge pull request #228 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_Misc Reflect Prefab/Entity constants and add failure unit tests commit 7b8d5629dd04ca1ed75c9828dbb0949f12eb2ca3 Merge: 78fe2cec6f 0a31e39a25 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 17:37:29 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5394_procprefab_asset commit 78fe2cec6fbcea9217d0b23ec056e19f144fc9a9 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 17:27:57 2021 -0500 Updated PrefabBuilder to point to new asset type for the procedural prefab Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 4da4e026582c8e7bf0fe9c7c7b39f15189c67b78 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 16:56:13 2021 -0500 {lyn5394} adding Prefab/Procedural/ProceduralPrefabAsset to AZ Tools Framework Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit c2fb7b9ccb4b7d4e8080b8830d4ceeb66cd3972c Merge: 30de326dfb a56daadc45 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 16:45:03 2021 -0500 Merge pull request #210 from aws-lumberyard-dev/feature_lyn5393_proc_prefab_behavior {LYN5393} Adding Prefab Group Behavior to output Procedural Prefab Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 0a31e39a25d36c63827424adc883e873aee20b71 Merge: 30de326dfb a56daadc45 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Thu Sep 16 16:45:03 2021 -0500 Merge pull request #210 from aws-lumberyard-dev/feature_lyn5393_proc_prefab_behavior {LYN5393} Adding Prefab Group Behavior to output Procedural Prefab commit 0f3680a9968cbbbcb9558811f8dbd287a97447ae Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 13:53:22 2021 -0500 Add failure tests and some test cleanup Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 834eab4c4bf151dfb9e49eb0a5e1f20486b6c05c Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 13:34:03 2021 -0500 Reflect InvalidTemplateId, fix reflection for InvalidComponentId Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 30de326dfbc28bbb9481bf282eb35c427469c847 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:55:16 2021 -0500 Fix merge issues Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 4bcf6b7b4f2d6285f244226b065bff65ba565094 Merge: 20c5cd7259 28fec42242 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:28:26 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs_EntityManagement' into Feature_LY-5384_ProceduralPrefabs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 20c5cd7259235d26f1aa11e2d61ac6b8a57b8638 Merge: 050e26d609 6845942fa4 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:24:44 2021 -0500 Merge pull request #200 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_CreatePrefab API Update: Wrap PrefabSystemComponentInterface behavior commit 6845942fa419b2b6d5a0103f8d30e6515948310e Merge: 58a51c738e 65da78dcc2 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:07:33 2021 -0500 Merge pull request #208 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_SavePrefabToString API Update: AzToolsFramework::Prefab::PrefabLoaderInterface commit 65da78dcc22c4251696ebb75680928ecf83d6733 Merge: e0c5e060ab 58a51c738e Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 10:07:06 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs_CreatePrefab' into Feature_LY-5384_ProceduralPrefabs_SavePrefabToString Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> # Conflicts: # Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp # Code/Framework/AzToolsFramework/Tests/Prefab/PrefabScriptingTests.cpp commit 28fec422426640540bd21b2275c7b7a90e4f8e71 Merge: c1b8b5190f d825305202 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 09:58:36 2021 -0500 Merge pull request #212 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_ComponentManagement API Update: Editor Entity Component Functions commit d825305202d5a02d60dd20fb5d0cc0ecb73f562a Merge: c280964b98 88fa6983d1 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 16 09:58:09 2021 -0500 Merge pull request #218 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_ComponentExplore API Update: Editor Component JSON Helper Functions commit a56daadc45e5ad8511aa5160c3afc245ca10fb83 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 16:48:41 2021 -0500 m_prefabGroupBehavior.release() -> m_prefabGroupBehavior.reset() adding error messages for the prefab processing fixed typo Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit c1a03351f55f9e8f5161c0ef0288c8e64050e399 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 16:32:42 2021 -0500 reduced the JSON for the testing framework to tree types only Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 0008866baa7882ec106e134049e2bd7b95113796 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 16:25:00 2021 -0500 enable ProceduralPrefabAsset JsonRegistrationContext Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 58a51c738e1bbd5bcad27cf1c0add4760bb8cffa Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 15 14:31:59 2021 -0500 Remove unneeded include Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit e0c5e060ab8a9cb2cfce4c083f276ab064aa08ea Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 15 14:20:04 2021 -0500 Cleanup whitespace Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 88fa6983d19ac3a0d7c4073ea390c36794d2603b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 15 13:49:20 2021 -0500 FindMatchingComponents now returns a vector of ComponentDetails which includes base class info (non-recursive) Fixed a memory leak Moved const to header Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit b57a9d4261aea85a8ddb1036307d8ad296cac859 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 15 10:49:32 2021 -0500 updated the DOM logic for the asset loading sake Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit f55ee9f5eabbeac998028f027e1c8adf55419a9d Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 14 13:23:13 2021 -0500 Update CreateStringPermissive to stop when enough data has been collected. Update unit tests. Fixed out of bounds behavior in EntityUtilityComponent usage of CreateStringPermissive. Updated AssetTreeFilterModel to cap the string length Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 6d6707dea8cd072261d65e0a508d1179df3892d4 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 14 10:55:38 2021 -0500 Rename GetComponentJson to GetComponentDefaultJson. Clean up GetComponentTypeIdFromName Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f4380d37a40ada353f7156b0d06b7ab60b72a151 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Sep 14 10:29:04 2021 -0500 Move scripting ebus and handler into separate files Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 572cb58f854aa2368b18f8cf70154d471dfac047 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 10 20:27:41 2021 -0400 Renamed SearchComponents to FindMatchingComponents Added missing printf formatting Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 050e26d60931700e226a4d1a5d02d6a1d4c69915 Merge: 542bdfc5d7 c1b8b5190f Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 10 09:31:08 2021 -0400 Merge pull request #201 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_EntityManagement API Update: Editor Entity Management - Add some comments and error handling commit 875d5dc466b65d893a44e11aa9467c45cf7994e9 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 10 09:13:43 2021 -0400 Move bus and handler code into separate files Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit a2d94e24fb2cd1993835f17e7129000c00926cf7 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 17:25:35 2021 -0400 Add comments Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 16f507377f4f04c88028833f69327bd11b401b87 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 17:16:33 2021 -0400 Add error messages Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 2e6d7d40dc731989128fbe829141057b3558c88b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 16:54:20 2021 -0400 Cleanup code Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 963891eaeb8d616bb071f2a7b50cdabd994241a2 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 3 10:48:40 2021 -0500 Add and update unit tests Reflect APIs to behavior context Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 664be8eca54293407e5ce2d631375d907c1bb2f6 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 2 13:00:02 2021 -0500 Add Search and Component json output APIs Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit e94fe64f366009d06b889954d292c37ea4f96fe2 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 13:37:44 2021 -0400 Make bus handler private Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 345a1b0d5edef99d5a8ea2bce2f4f3478652a4f1 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 12:30:13 2021 -0400 Address feedback Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit c280964b983635bed9e8bbfb94b2188403287d4c Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 9 10:12:49 2021 -0500 Address feedback Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 3b819ee827fc4c19312f2d2bc5788e2cc36de4f4 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 3 16:06:10 2021 -0500 Update unit test to verify components on saved prefab Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 0b63c0e316ec621ed17edf36109b7cd1d50ef606 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Sep 3 12:52:46 2021 -0500 Expand test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ea59416626d9b43599cf8847585e599f8fa5fd22 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 17:32:14 2021 -0500 Add error handling Add component creation Add error testing Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 9d0f2ae33eadba0216bd245157b94692792b1a86 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:31:28 2021 -0500 enabling ProductDependencies test again Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 15d1e4730df31e71e7e3ee6d4914f19b233c1b7f Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:23:26 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5393_proc_prefab_behavior # Conflicts: # Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp # Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake # Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit ce2e4602bde26fbb34b43c73f820a97b9e229b5a Merge: 5ad0aac747 542bdfc5d7 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:14:07 2021 -0500 Merge branch 'Feature_LY-5384_ProceduralPrefabs' into feature_lyn5393_proc_prefab_behavior # Conflicts: # Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp # Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake # Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 542bdfc5d762c07938f9a0f8e729070f1df9edfc Merge: 3e7564c944 4899f67986 Author: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 17:09:10 2021 -0500 Merge pull request #207 from aws-lumberyard-dev/feature_lyn5392_proc_prefab_group {lyn5392} Adding PrefabGroup scene manifest rule commit 4899f67986992b7eeb5cc3b750493ed21ec7b4f3 Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 16:33:24 2021 -0500 removing unneeded AZStd::move() calls Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 5ad0aac7472d24bb85990d36399a466288ecfdbc Author: Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 16:17:52 2021 -0500 cleaned up the code finalized the unit tests fixed the code based on the tests... FTW! Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> commit 24f289dd31292c4b9f5e5848ddc94efd986b4341 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 13:06:20 2021 -0500 Add FindComponentByTypeName and UpdateComponentForEntity APIs Add unit tests Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit c1b8b5190f973d2429731308f50c7c962d64301e Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 14:02:17 2021 -0500 Fix bus connect that should have been a bus disconnect Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit fde870d6c92e131875ec6aadda2365203a538379 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 1 12:57:04 2021 -0500 Fix up includes Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 8ceddd0efc90d33bc34b5287176497356e57abf9 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed Sep 1 08:43:23 2021 -0500 WIP Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit 3cc9135d87efde24430dbf1cd112bcf9b95ecaa0 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Aug 31 14:44:37 2021 -0500 Rename files Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f056b3d9578ae2f49dbc172a5929306047620be6 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue Aug 31 14:14:34 2021 -0500 Remove 'editor' from bus/component name Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 0fb7a0788e879eb9dc241291f05f0acffc0b0156 Author: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue Aug 31 09:18:37 2021 -0500 {lyn5392} Adding PrefabGroup scene manifest rule * Adding PrefabGroup abstraction and concrete classes to fill out in a scene manifest * has reflections for serialization & behavior * testing the behavior using Lua * testing the serialization using JSON Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> commit b1756307bff9f86ae0ae1354bae8f470d19b4487 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 17:52:18 2021 -0500 Reflect SaveTemplateToString Add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ddd2bb89041c5fb8b6add2cfc02c454baab9a7d6 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 12:46:17 2021 -0500 Add warning/error messages, update module Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit e839c1cbcc340859fc6ee5cff2d802660944194b Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 11:17:25 2021 -0500 Add some comments and error handling Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 347f787cc88405541889e842151de81a70598dd1 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 17:16:45 2021 -0500 Fix line endings Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit be26ab1cb16221ba879c10652b430ea31547d868 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 15:28:00 2021 -0500 Add CreatePrefabTemplate Add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 3e7564c944497b7b6cce94dbce486ed8c4561f33 Merge: 5a3c289fac 07841ee749 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Aug 30 10:20:20 2021 -0500 Merge pull request #199 from aws-lumberyard-dev/Feature_LY-5384_ProceduralPrefabs_EntityManagement Add editor entity creation and unit test commit 07841ee749d2a1bc22352cbec3076ac087348676 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 16:44:57 2021 -0500 Fix line endings Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 35bc3b89cd1fcc126114ea7d61cdd21e88699080 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 15:03:35 2021 -0500 Setup CreateEditorReadyEntity to use a custom entity context Add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 82519b15510a4ec1b2daf4d883a2c4c3d9c0a347 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Aug 27 09:29:20 2021 -0500 Add EditorEntityUtilityComponent for managing entities from the behavior context Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit f8d39e267162db5fb2091982a7e54bc57ed108bb Merge: 43603cad5e 575faa4443 Author: Chris Galvan Date: Wed Aug 11 15:29:33 2021 -0500 Merge pull request #3049 from aws-lumberyard-dev/cgalvan/gitflow_210811 Merged stabilization/2106 to main commit 575faa4443823ed239d609692847fbd781beebcb Merge: 43603cad5e 4b817a6483 Author: Chris Galvan Date: Wed Aug 11 14:13:27 2021 -0500 Merge remote-tracking branch 'upstream/stabilization/2106' into cgalvan/gitflow_210811 Signed-off-by: Chris Galvan commit 43603cad5e715aadef47b76e24867dd41347d163 Merge: d9cce28a53 bb52475ce8 Author: Terry Michaels Date: Mon Jul 19 14:55:51 2021 -0500 Merge pull request #2271 from aws-lumberyard-dev/Foundation/miterenc/ContributingUpdate Updating CONTRIBUTING.md commit bb52475ce8c37c29b35c81b379befe5a75db1de7 Author: Terry Michaels Date: Mon Jul 19 14:55:14 2021 -0500 Updated text to be more descriptive Signed-off-by: Terry Michaels commit 697dfad486c69beb5ef40cbf6478d6ccd8753cd7 Author: Terry Michaels Date: Mon Jul 19 14:27:24 2021 -0500 Fixed typo Signed-off-by: Terry Michaels commit 650e1ab44d86664b6deab7f6cebeda40c3e1361e Author: Terry Michaels Date: Mon Jul 19 14:19:46 2021 -0500 Updating CONTRIBUTING.md Signed-off-by: Terry Michaels commit d9cce28a5387c7f5b59041869086547905f1e345 Merge: e7f787572e 486ba58628 Author: Chris Galvan Date: Mon Jul 12 14:06:57 2021 -0500 Merge pull request #2096 from aws-lumberyard-dev/cgalvan/gitflow_210712_main Merged stabilization/2106 to main commit 486ba58628488c211a6140f26caa421c38be3f0f Merge: e7f787572e 7cfde884d9 Author: Chris Galvan Date: Mon Jul 12 11:12:41 2021 -0500 Merged stabilization/2106 to development; Resolved merge conflicts Signed-off-by: Chris Galvan commit e7f787572e805c413115265e5873fb2425e2f41b Author: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Tue Jul 6 08:03:35 2021 -0700 Updates licenses to APACHE-2.0 OR MIT (#1685) Not to be committed before 7/6/2021 Signed-off-by: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> commit 837e1c737059a819d01ef4ebed7fadae42248dd8 Merge: d30de01752 efcbe2c4a1 Author: Chris Galvan Date: Fri Jul 2 12:11:27 2021 -0500 Merge pull request #1764 from aws-lumberyard-dev/cgalvan/gitflow_210702 Merged stabilization/2106 to main commit efcbe2c4a1e909182dfbd5394f9322513ba91115 Merge: d30de01752 0c43493e29 Author: Chris Galvan Date: Fri Jul 2 10:20:42 2021 -0500 Merge remote-tracking branch 'upstream/stabilization/2106' into cgalvan/gitflow_210702 Signed-off-by: Chris Galvan commit d30de01752b7eaed1f16e2163b1a75c915f061eb Author: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon Jun 28 11:20:36 2021 -0700 Updating LFS config to new endpoint (#1624) Signed-off-by: AMZN-alexpete Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * fix for "warning C4100: 'outputValueTypeId': unreferenced formal" Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * Squashed commit of the following: commit dbd3526517bcb6553402cbc0af1f02e1f68e0707 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon Oct 4 14:30:56 2021 -0500 Increased scene manifest max size to size_t::max to match default json size limit Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit ea4a9ffd23feb3beeadc9bf6ca765c96980e9e6d Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Oct 1 19:15:25 2021 -0500 Switch to querying cache location from Settings Registry Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 1c197996132625b8e26856fc92a30f9862d9dfdb Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri Oct 1 14:42:32 2021 -0500 Update to look in cache for generated manifest instead of source folder Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit cf3c32791fd71dc48066f9783c8859d386370b95 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu Sep 30 11:09:40 2021 -0500 Added generated manifest to dependency tracking. Updated unit tests Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 56cb0d27982e61c2cf123b765def8b5c9e21b021 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 29 15:51:52 2021 -0500 Moved manifest size const to header and used that in scene builder Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 7c8016a0ba6000090b29371f253b7906c9f3d141 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 29 15:21:06 2021 -0500 Add doc comment Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit 45fd5473f5ed6fe4fe93f8d629857852bcbe5e03 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 29 15:11:36 2021 -0500 Clean up code and add unit test Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> commit d0e610cad380e2278bc18552a4d1c71c64a5d339 Author: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed Sep 29 13:21:58 2021 -0500 Source dependency reporting WIP Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> # Conflicts: # Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp (cherry picked from commit d6464dcee20ea4e6f2d40f0d3301f24be5f4dee6) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add comment on unit test globals, fix indentation Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Cleaned up scene_mesh_to_prefab.py Added comments Removed raise_error function Made mesh_group_name cleanup more comprehensive Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * fix for "warning C4100: 'message': unreferenced formal" Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> Co-authored-by: jackalbe <23512001+jackalbe@users.noreply.github.com> Co-authored-by: Guthrie Adams --- .../Editor/Scripts/scene_mesh_to_prefab.py | 162 ++++++++ AutomatedTesting/Gem/Code/enabled_gems.cmake | 3 +- .../FBXTestTexture.png | 3 + .../multiple_mesh_one_material.fbx | 3 + .../multiple_mesh_one_material.fbx.assetinfo | 8 + Code/Framework/AzCore/AzCore/Math/Uuid.cpp | 12 +- Code/Framework/AzCore/AzCore/Math/Uuid.h | 3 +- Code/Framework/AzCore/Tests/UUIDTests.cpp | 23 ++ .../AzFramework/Entity/BehaviorEntity.cpp | 2 + .../Application/ToolsApplication.cpp | 4 +- .../AzToolsFrameworkModule.cpp | 2 + .../Entity/EntityUtilityComponent.cpp | 351 ++++++++++++++++++ .../Entity/EntityUtilityComponent.h | 90 +++++ .../FocusMode/FocusModeInterface.h | 1 + .../AzToolsFramework/Prefab/PrefabLoader.cpp | 44 ++- .../AzToolsFramework/Prefab/PrefabLoader.h | 3 + .../Prefab/PrefabLoaderInterface.h | 1 - .../Prefab/PrefabLoaderScriptingBus.h | 45 +++ .../Prefab/PrefabSystemComponent.cpp | 20 +- .../Prefab/PrefabSystemComponent.h | 7 +- .../Prefab/PrefabSystemComponentInterface.h | 3 +- .../Prefab/PrefabSystemScriptingBus.h | 38 ++ .../Prefab/PrefabSystemScriptingHandler.cpp | 75 ++++ .../Prefab/PrefabSystemScriptingHandler.h | 39 ++ .../Procedural/ProceduralPrefabAsset.cpp | 144 +++++++ .../Prefab/Procedural/ProceduralPrefabAsset.h | 90 +++++ .../Prefab/ScriptingPrefabLoader.cpp | 37 ++ .../Prefab/ScriptingPrefabLoader.h | 42 +++ .../UI/Prefab/PrefabIntegrationManager.cpp | 73 ++++ .../UI/Prefab/PrefabIntegrationManager.h | 2 + .../aztoolsframework_files.cmake | 10 + .../Entity/EntityUtilityComponentTests.cpp | 252 +++++++++++++ .../Tests/Prefab/PrefabScriptingTests.cpp | 173 +++++++++ .../Prefab/ProceduralPrefabAssetTests.cpp | 135 +++++++ .../Tests/aztoolsframeworktests_files.cmake | 3 + .../AssetBuilder/AssetBuilderApplication.cpp | 2 + .../native/ui/AssetTreeFilterModel.cpp | 5 +- .../SceneCore/Containers/GraphObjectProxy.cpp | 2 +- .../SceneAPI/SceneCore/Containers/Scene.cpp | 11 + .../SceneAPI/SceneCore/Containers/Scene.h | 4 + .../SceneCore/Containers/SceneGraph.cpp | 2 +- .../SceneCore/Containers/SceneManifest.cpp | 3 +- .../SceneCore/Containers/SceneManifest.h | 2 + .../SceneCore/Events/AssetImportRequest.cpp | 27 +- .../SceneCore/Events/AssetImportRequest.h | 19 + .../Import/ManifestImportRequestHandler.cpp | 8 +- .../Import/ManifestImportRequestHandler.h | 1 + .../Behaviors/ScriptProcessorRuleBehavior.cpp | 117 +++--- .../Behaviors/ScriptProcessorRuleBehavior.h | 8 +- Gems/Prefab/PrefabBuilder/CMakeLists.txt | 9 +- .../PrefabBuilder/PrefabBuilderModule.cpp | 4 +- .../Prefab/PrefabBuilder/PrefabBuilderTests.h | 1 + .../PrefabBuilder/PrefabGroup/IPrefabGroup.h | 25 ++ .../PrefabGroup/PrefabBehaviorTests.cpp | 161 ++++++++ .../PrefabGroup/PrefabBehaviorTests.inl | 104 ++++++ .../PrefabBuilder/PrefabGroup/PrefabGroup.cpp | 136 +++++++ .../PrefabBuilder/PrefabGroup/PrefabGroup.h | 64 ++++ .../PrefabGroup/PrefabGroupBehavior.cpp | 251 +++++++++++++ .../PrefabGroup/PrefabGroupBehavior.h | 55 +++ .../PrefabGroup/PrefabGroupTests.cpp | 161 ++++++++ .../PrefabGroup/ProceduralAssetHandler.cpp | 185 +++++++++ .../PrefabGroup/ProceduralAssetHandler.h | 39 ++ .../Prefab/PrefabBuilder/PrefabGroupTests.cpp | 162 ++++++++ .../PrefabBuilder/prefabbuilder_files.cmake | 7 + .../prefabbuilder_tests_files.cmake | 3 + .../Editor/Scripts/scene_api/scene_data.py | 9 + .../SceneBuilder/SceneBuilderWorker.cpp | 96 +++++ .../Source/SceneBuilder/SceneBuilderWorker.h | 5 + .../Tests/SceneBuilder/SceneBuilderTests.cpp | 200 ++++++++++ 69 files changed, 3696 insertions(+), 95 deletions(-) create mode 100644 AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py create mode 100644 AutomatedTesting/multiple_mesh_one_material/FBXTestTexture.png create mode 100644 AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx create mode 100644 AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx.assetinfo create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderScriptingBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.h create mode 100644 Code/Framework/AzToolsFramework/Tests/Entity/EntityUtilityComponentTests.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/Prefab/PrefabScriptingTests.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/Prefab/ProceduralPrefabAssetTests.cpp create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/IPrefabGroup.h create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.cpp create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.inl create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.cpp create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.h create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.h create mode 100644 Gems/Prefab/PrefabBuilder/PrefabGroupTests.cpp diff --git a/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py new file mode 100644 index 0000000000..d5a7acfe91 --- /dev/null +++ b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py @@ -0,0 +1,162 @@ +# +# 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 +# +# +import os, traceback, binascii, sys, json, pathlib +import azlmbr.math +import azlmbr.bus + +# +# SceneAPI Processor +# + + +def log_exception_traceback(): + exc_type, exc_value, exc_tb = sys.exc_info() + data = traceback.format_exception(exc_type, exc_value, exc_tb) + print(str(data)) + +def get_mesh_node_names(sceneGraph): + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + meshDataList = [] + node = sceneGraph.get_root() + children = [] + paths = [] + + while node.IsValid(): + # store children to process after siblings + if sceneGraph.has_node_child(node): + children.append(sceneGraph.get_node_child(node)) + + nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) + paths.append(nodeName.get_path()) + + # store any node that has mesh data content + nodeContent = sceneGraph.get_node_content(node) + if nodeContent.CastWithTypeName('MeshData'): + if sceneGraph.is_node_end_point(node) is False: + if (len(nodeName.get_path())): + meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) + + # advance to next node + if sceneGraph.has_node_sibling(node): + node = sceneGraph.get_node_sibling(node) + elif children: + node = children.pop() + else: + node = azlmbr.scene.graph.NodeIndex() + + return meshDataList, paths + +def update_manifest(scene): + import json + import uuid, os + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + graph = sceneData.SceneGraph(scene.graph) + # Get a list of all the mesh nodes, as well as all the nodes + mesh_name_list, all_node_paths = get_mesh_node_names(graph) + scene_manifest = sceneData.SceneManifest() + + clean_filename = scene.sourceFilename.replace('.', '_') + + # Compute the filename of the scene file + source_basepath = scene.watchFolder + source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath)) + source_filename_only = os.path.basename(clean_filename) + + created_entities = [] + + # Loop every mesh node in the scene + for activeMeshIndex in range(len(mesh_name_list)): + mesh_name = mesh_name_list[activeMeshIndex] + mesh_path = mesh_name.get_path() + # Create a unique mesh group name using the filename + node name + mesh_group_name = '{}_{}'.format(source_filename_only, mesh_name.get_name()) + # Remove forbidden filename characters from the name since this will become a file on disk later + mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\") + # Add the MeshGroup to the manifest and give it a unique ID + mesh_group = scene_manifest.add_mesh_group(mesh_group_name) + mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}' + # Set our current node as the only node that is included in this MeshGroup + scene_manifest.mesh_group_select_node(mesh_group, mesh_path) + + # Explicitly remove all other nodes to prevent implicit inclusions + for node in all_node_paths: + if node != mesh_path: + scene_manifest.mesh_group_unselect_node(mesh_group, node) + + # Create an editor entity + entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name) + # Add an EditorMeshComponent to the entity + editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent") + # Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension + # The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel + # The assetHint will be converted to an AssetId later during prefab loading + json_update = json.dumps({ + "Controller": { "Configuration": { "ModelAsset": { + "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}} + }); + # Apply the JSON above to the component we created + result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update) + + if not result: + raise RuntimeError("UpdateComponentForEntity failed") + + # Keep track of the entity we set up, we'll add them all to the prefab we're creating later + created_entities.append(entity_id) + + # Create a prefab with all our entities + prefab_filename = source_filename_only + ".prefab" + created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", created_entities, prefab_filename) + + if created_template_id == azlmbr.prefab.InvalidTemplateId: + raise RuntimeError("CreatePrefab {} failed".format(prefab_filename)) + + # Convert the prefab to a JSON string + output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id) + + if output.IsSuccess(): + jsonString = output.GetValue() + uuid = azlmbr.math.Uuid_CreateRandom().ToString() + jsonResult = json.loads(jsonString) + # Add a PrefabGroup to the manifest and store the JSON on it + scene_manifest.add_prefab_group(source_filename_only, uuid, jsonResult) + else: + raise RuntimeError("SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename)) + + # Convert the manifest to a JSON string and return it + new_manifest = scene_manifest.export() + + return new_manifest + +sceneJobHandler = None + +def on_update_manifest(args): + try: + scene = args[0] + return update_manifest(scene) + except RuntimeError as err: + print (f'ERROR - {err}') + log_exception_traceback() + + global sceneJobHandler + sceneJobHandler = None + +# try to create SceneAPI handler for processing +try: + import azlmbr.scene as sceneApi + if (sceneJobHandler == None): + sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() + sceneJobHandler.connect() + sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) +except: + sceneJobHandler = None diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index 0d281661b9..30740a489d 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -21,7 +21,6 @@ set(ENABLED_GEMS QtForPython PythonAssetBuilder Metastream - Camera EMotionFX AtomTressFX @@ -53,6 +52,6 @@ set(ENABLED_GEMS AWSCore AWSClientAuth AWSMetrics - + PrefabBuilder AudioSystem ) diff --git a/AutomatedTesting/multiple_mesh_one_material/FBXTestTexture.png b/AutomatedTesting/multiple_mesh_one_material/FBXTestTexture.png new file mode 100644 index 0000000000..4f52364cb3 --- /dev/null +++ b/AutomatedTesting/multiple_mesh_one_material/FBXTestTexture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:827a63985273229050bf4f63030bcc666f045091fe81cf8157a9ca23b40074b6 +size 3214 diff --git a/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx new file mode 100644 index 0000000000..d9deb899f0 --- /dev/null +++ b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8d24963e6e8765205bc79cbe2304fc39f1245ee75249e2834a71c96c3cab824 +size 22700 diff --git a/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx.assetinfo b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx.assetinfo new file mode 100644 index 0000000000..fe18a16cb5 --- /dev/null +++ b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx.assetinfo @@ -0,0 +1,8 @@ +{ + "values": [ + { + "$type": "ScriptProcessorRule", + "scriptFilename": "Editor/Scripts/scene_mesh_to_prefab.py" + } + ] +} \ No newline at end of file diff --git a/Code/Framework/AzCore/AzCore/Math/Uuid.cpp b/Code/Framework/AzCore/AzCore/Math/Uuid.cpp index d875e28a1e..410d235a37 100644 --- a/Code/Framework/AzCore/AzCore/Math/Uuid.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Uuid.cpp @@ -135,18 +135,12 @@ namespace AZ { stringLength = strlen(uuidString); } - if (stringLength > MaxPermissiveStringSize) - { - if (!skipWarnings) - { - AZ_Warning("Math", false, "Can't create UUID from string length %zu over maximum %zu", stringLength, MaxPermissiveStringSize); - } - return Uuid::CreateNull(); - } + size_t newLength{ 0 }; char createString[MaxPermissiveStringSize]; - for (size_t curPos = 0; curPos < stringLength; ++curPos) + // Loop until we get to the end of the string OR stop once we've accumulated a full UUID string worth of data + for (size_t curPos = 0; curPos < stringLength && newLength < ValidUuidStringLength; ++curPos) { char curChar = uuidString[curPos]; switch (curChar) diff --git a/Code/Framework/AzCore/AzCore/Math/Uuid.h b/Code/Framework/AzCore/AzCore/Math/Uuid.h index ea920e45c8..6b77e7ec3e 100644 --- a/Code/Framework/AzCore/AzCore/Math/Uuid.h +++ b/Code/Framework/AzCore/AzCore/Math/Uuid.h @@ -42,8 +42,9 @@ namespace AZ //VER_AZ_RANDOM_CRC32 = 6, // 0 1 1 0 }; + static constexpr int ValidUuidStringLength = 32; /// Number of characters (data only, no extra formatting) in a valid UUID string static const size_t MaxStringBuffer = 39; /// 32 Uuid + 4 dashes + 2 brackets + 1 terminate - + Uuid() {} Uuid(const char* string, size_t stringLength = 0) { *this = CreateString(string, stringLength); } diff --git a/Code/Framework/AzCore/Tests/UUIDTests.cpp b/Code/Framework/AzCore/Tests/UUIDTests.cpp index a18dc33c4f..64b9048a62 100644 --- a/Code/Framework/AzCore/Tests/UUIDTests.cpp +++ b/Code/Framework/AzCore/Tests/UUIDTests.cpp @@ -247,4 +247,27 @@ namespace UnitTest Uuid right = Uuid::CreateStringPermissive(permissiveStr1); EXPECT_EQ(left, right); } + + TEST_F(UuidTests, CreateStringPermissive_StringWithExtraData_Succeeds) + { + const char uuidStr[] = "{34D44249-E599-4B30-811F-4215C2DEA269}"; + Uuid left = Uuid::CreateString(uuidStr); + + const char permissiveStr[] = "0x34D44249-0xE5994B30-0x811F4215-0xC2DEA269 Hello World"; + Uuid right = Uuid::CreateStringPermissive(permissiveStr); + EXPECT_EQ(left, right); + + } + + TEST_F(UuidTests, CreateStringPermissive_StringWithLotsOfExtraData_Succeeds) + { + const char uuidStr[] = "{34D44249-E599-4B30-811F-4215C2DEA269}"; + Uuid left = Uuid::CreateString(uuidStr); + + const char permissiveStr[] = "0x34D44249-0xE5994B30-0x811F4215-0xC2DEA269 Hello World this is a really long string " + "with lots of extra data to make sure we can parse a long string without failing as long as the uuid is in " + "the beginning of the string then we should succeed"; + Uuid right = Uuid::CreateStringPermissive(permissiveStr); + EXPECT_EQ(left, right); + } } diff --git a/Code/Framework/AzFramework/AzFramework/Entity/BehaviorEntity.cpp b/Code/Framework/AzFramework/AzFramework/Entity/BehaviorEntity.cpp index 725f71a3c9..5d82cf488a 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/BehaviorEntity.cpp +++ b/Code/Framework/AzFramework/AzFramework/Entity/BehaviorEntity.cpp @@ -133,6 +133,8 @@ namespace AzFramework behaviorContext->Class("Entity") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) ->Attribute(AZ::Script::Attributes::ConstructorOverride, &Internal::BehaviorEntityScriptConstructor) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "entity") ->Constructor() ->Constructor() ->Constructor() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index c54735fe91..fbd066ec6e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QFileInfo::d_ptr': class 'QSharedDataPointer' needs to have dll-interface to be used by clients of class 'QFileInfo' @@ -271,7 +272,8 @@ namespace AzToolsFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), - azrtti_typeid() + azrtti_typeid(), + azrtti_typeid() }); return components; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp index 05d67d9d71..d2a88df544 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp @@ -53,6 +53,7 @@ #include #include #include +#include AZ_DEFINE_BUDGET(AzToolsFramework); @@ -71,6 +72,7 @@ namespace AzToolsFramework Components::EditorSelectionAccentSystemComponent::CreateDescriptor(), EditorEntityContextComponent::CreateDescriptor(), EditorEntityFixupComponent::CreateDescriptor(), + EntityUtilityComponent::CreateDescriptor(), ContainerEntitySystemComponent::CreateDescriptor(), FocusModeSystemComponent::CreateDescriptor(), SliceMetadataEntityContextComponent::CreateDescriptor(), diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.cpp new file mode 100644 index 0000000000..7fb998f012 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + void ComponentDetails::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Field("TypeInfo", &ComponentDetails::m_typeInfo) + ->Field("BaseClasses", &ComponentDetails::m_baseClasses); + + serializeContext->RegisterGenericType>(); + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "entity") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Property("TypeInfo", BehaviorValueProperty(&ComponentDetails::m_typeInfo)) + ->Property("BaseClasses", BehaviorValueProperty(&ComponentDetails::m_baseClasses)) + ->Method("__repr__", [](const ComponentDetails& obj) + { + std::ostringstream result; + bool first = true; + + for (const auto& baseClass : obj.m_baseClasses) + { + if (!first) + { + result << ", "; + } + + first = false; + result << baseClass.c_str(); + } + + return AZStd::string::format("%s, Base Classes: <%s>", obj.m_typeInfo.c_str(), result.str().c_str()); + }) + ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString); + } + } + + AZ::EntityId EntityUtilityComponent::CreateEditorReadyEntity(const AZStd::string& entityName) + { + auto* newEntity = m_entityContext->CreateEntity(entityName.c_str()); + + if (!newEntity) + { + AZ_Error("EditorEntityUtility", false, "Failed to create new entity %s", entityName.c_str()); + return AZ::EntityId(); + } + + AzToolsFramework::EditorEntityContextRequestBus::Broadcast( + &AzToolsFramework::EditorEntityContextRequestBus::Events::AddRequiredComponents, *newEntity); + + newEntity->Init(); + auto newEntityId = newEntity->GetId(); + + m_createdEntities.emplace_back(newEntityId); + + return newEntityId; + } + + AZ::TypeId GetComponentTypeIdFromName(const AZStd::string& typeName) + { + // Try to create a TypeId first. We won't show any warnings if this fails as the input might be a class name instead + AZ::TypeId typeId = AZ::TypeId::CreateStringPermissive(typeName.data()); + + // If the typeId is null, try a lookup by class name + if (typeId.IsNull()) + { + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + + auto typeNameCrc = AZ::Crc32(typeName.data()); + auto typeUuidList = serializeContext->FindClassId(typeNameCrc); + + // TypeId is invalid or class name is invalid + if (typeUuidList.empty()) + { + AZ_Error("EntityUtilityComponent", false, "Provided type %s is either an invalid TypeId or does not match any class names", typeName.c_str()); + return AZ::TypeId::CreateNull(); + } + + typeId = typeUuidList[0]; + } + + return typeId; + } + + AZ::Component* FindComponentHelper(AZ::EntityId entityId, const AZ::TypeId& typeId, AZ::ComponentId componentId, bool createComponent = false) + { + AZ::Entity* entity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId); + + if (!entity) + { + AZ_Error("EntityUtilityComponent", false, "Invalid entityId %s", entityId.ToString().c_str()); + return nullptr; + } + + AZ::Component* component = nullptr; + if (componentId != AZ::InvalidComponentId) + { + component = entity->FindComponent(componentId); + } + else + { + component = entity->FindComponent(typeId); + } + + if (!component && createComponent) + { + component = entity->CreateComponent(typeId); + } + + if (!component) + { + AZ_Error( + "EntityUtilityComponent", false, "Failed to find component (%s) on entity %s (%s)", + componentId != AZ::InvalidComponentId ? AZStd::to_string(componentId).c_str() + : typeId.ToString().c_str(), + entityId.ToString().c_str(), + entity->GetName().c_str()); + return nullptr; + } + + return component; + } + + AzFramework::BehaviorComponentId EntityUtilityComponent::GetOrAddComponentByTypeName(AZ::EntityId entityId, const AZStd::string& typeName) + { + AZ::TypeId typeId = GetComponentTypeIdFromName(typeName); + + if (typeId.IsNull()) + { + return AzFramework::BehaviorComponentId(AZ::InvalidComponentId); + } + + AZ::Component* component = FindComponentHelper(entityId, typeId, AZ::InvalidComponentId, true); + + return component ? AzFramework::BehaviorComponentId(component->GetId()) : + AzFramework::BehaviorComponentId(AZ::InvalidComponentId); + } + + bool EntityUtilityComponent::UpdateComponentForEntity(AZ::EntityId entityId, AzFramework::BehaviorComponentId componentId, const AZStd::string& json) + { + if (!componentId.IsValid()) + { + AZ_Error("EntityUtilityComponent", false, "Invalid componentId passed to UpdateComponentForEntity"); + return false; + } + + AZ::Component* component = FindComponentHelper(entityId, AZ::TypeId::CreateNull(), componentId); + + if (!component) + { + return false; + } + + using namespace AZ::JsonSerializationResult; + + AZ::JsonDeserializerSettings settings = AZ::JsonDeserializerSettings{}; + settings.m_reporting = []([[maybe_unused]] AZStd::string_view message, ResultCode result, AZStd::string_view) -> auto + { + if (result.GetProcessing() == Processing::Halted) + { + AZ_Error("EntityUtilityComponent", false, "JSON %s\n", message.data()); + } + else if (result.GetOutcome() > Outcomes::PartialDefaults) + { + AZ_Warning("EntityUtilityComponent", false, "JSON %s\n", message.data()); + } + return result; + }; + + rapidjson::Document doc; + doc.Parse(json.data(), json.size()); + ResultCode resultCode = AZ::JsonSerialization::Load(*component, doc, settings); + + return resultCode.GetProcessing() != Processing::Halted; + } + + AZStd::string EntityUtilityComponent::GetComponentDefaultJson(const AZStd::string& typeName) + { + AZ::TypeId typeId = GetComponentTypeIdFromName(typeName); + + if (typeId.IsNull()) + { + // GetComponentTypeIdFromName already does error handling + return ""; + } + + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + + const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(typeId); + + if (!classData) + { + AZ_Error("EntityUtilityComponent", false, "Failed to find ClassData for typeId %s (%s)", typeId.ToString().c_str(), typeName.c_str()); + return ""; + } + + void* component = classData->m_factory->Create("Component"); + rapidjson::Document document; + AZ::JsonSerializerSettings settings; + settings.m_keepDefaults = true; + + auto resultCode = AZ::JsonSerialization::Store(document, document.GetAllocator(), component, nullptr, typeId, settings); + + // Clean up the allocated component ASAP, we don't need it anymore + classData->m_factory->Destroy(component); + + if (resultCode.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted) + { + AZ_Error("EntityUtilityComponent", false, "Failed to serialize component to json (%s): %s", + typeName.c_str(), resultCode.ToString(typeName).c_str()) + return ""; + } + + AZStd::string jsonString; + AZ::Outcome outcome = AZ::JsonSerializationUtils::WriteJsonString(document, jsonString); + + if (!outcome.IsSuccess()) + { + AZ_Error("EntityUtilityComponent", false, "Failed to write component json to string: %s", outcome.GetError().c_str()); + return ""; + } + + return jsonString; + } + + AZStd::vector EntityUtilityComponent::FindMatchingComponents(const AZStd::string& searchTerm) + { + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + + if (m_typeInfo.empty()) + { + serializeContext->EnumerateDerived( + [this, serializeContext](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid& /*typeId*/) + { + auto& typeInfo = m_typeInfo.emplace_back(classData->m_typeId, classData->m_name, AZStd::vector{}); + + serializeContext->EnumerateBase( + [&typeInfo](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid&) + { + if (classData) + { + AZStd::get<2>(typeInfo).emplace_back(classData->m_name); + } + return true; + }, + classData->m_typeId); + + return true; + }); + } + + AZStd::vector matches; + + for (const auto& [typeId, typeName, baseClasses] : m_typeInfo) + { + if (AZStd::wildcard_match(searchTerm, typeName)) + { + ComponentDetails details; + details.m_typeInfo = AZStd::string::format("%s %s", typeId.ToString().c_str(), typeName.c_str()); + details.m_baseClasses = baseClasses; + + matches.emplace_back(AZStd::move(details)); + } + } + + return matches; + } + + void EntityUtilityComponent::ResetEntityContext() + { + for (AZ::EntityId entityId : m_createdEntities) + { + m_entityContext->DestroyEntityById(entityId); + } + + m_createdEntities.clear(); + m_entityContext->ResetContext(); + } + + void EntityUtilityComponent::Reflect(AZ::ReflectContext* context) + { + ComponentDetails::Reflect(context); + + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class(); + } + + if (auto* behaviorContext = azrtti_cast(context)) + { + behaviorContext->ConstantProperty("InvalidComponentId", BehaviorConstant(AZ::InvalidComponentId)) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "Entity") + ->Attribute(AZ::Script::Attributes::Module, "entity"); + + behaviorContext->EBus("EntityUtilityBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::Category, "Entity") + ->Attribute(AZ::Script::Attributes::Module, "entity") + ->Event("CreateEditorReadyEntity", &EntityUtilityBus::Events::CreateEditorReadyEntity) + ->Event("GetOrAddComponentByTypeName", &EntityUtilityBus::Events::GetOrAddComponentByTypeName) + ->Event("UpdateComponentForEntity", &EntityUtilityBus::Events::UpdateComponentForEntity) + ->Event("FindMatchingComponents", &EntityUtilityBus::Events::FindMatchingComponents) + ->Event("GetComponentDefaultJson", &EntityUtilityBus::Events::GetComponentDefaultJson) + ; + } + } + + void EntityUtilityComponent::Activate() + { + m_entityContext = AZStd::make_unique(UtilityEntityContextId); + m_entityContext->InitContext(); + EntityUtilityBus::Handler::BusConnect(); + } + + void EntityUtilityComponent::Deactivate() + { + EntityUtilityBus::Handler::BusDisconnect(); + m_entityContext = nullptr; + } +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.h new file mode 100644 index 0000000000..af7c353163 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EntityUtilityComponent.h @@ -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 + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + struct ComponentDetails + { + AZ_TYPE_INFO(AzToolsFramework::ComponentDetails, "{107D8379-4AD4-4547-BEE1-184B120F23E9}"); + + static void Reflect(AZ::ReflectContext* context); + + AZStd::string m_typeInfo; + AZStd::vector m_baseClasses; + }; + + // This ebus is intended to provide behavior-context friendly APIs to create and manage entities + struct EntityUtilityTraits : AZ::EBusTraits + { + AZ_RTTI(AzToolsFramework::EntityUtilityTraits, "{A6305CAE-C825-43F9-A44D-E503910912AF}"); + + virtual ~EntityUtilityTraits() = default; + + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + + // Creates an entity with the default editor components attached and initializes the entity + virtual AZ::EntityId CreateEditorReadyEntity(const AZStd::string& entityName) = 0; + + virtual AzFramework::BehaviorComponentId GetOrAddComponentByTypeName(AZ::EntityId entity, const AZStd::string& typeName) = 0; + + virtual bool UpdateComponentForEntity(AZ::EntityId entity, AzFramework::BehaviorComponentId component, const AZStd::string& json) = 0; + + // Gets a JSON string containing describing the default serialization state of the specified component + virtual AZStd::string GetComponentDefaultJson(const AZStd::string& typeName) = 0; + + // Returns a list of matching component type names. Supports wildcard search terms + virtual AZStd::vector FindMatchingComponents(const AZStd::string& searchTerm) = 0; + + virtual void ResetEntityContext() = 0; + }; + + using EntityUtilityBus = AZ::EBus; + + struct EntityUtilityComponent : AZ::Component + , EntityUtilityBus::Handler + { + inline const static AZ::Uuid UtilityEntityContextId = AZ::Uuid("{9C277B88-E79E-4F8A-BAFF-A4C175BD565F}"); + + AZ_COMPONENT(EntityUtilityComponent, "{47205907-A0EA-4FFF-A620-04D20C04A379}"); + + AZ::EntityId CreateEditorReadyEntity(const AZStd::string& entityName) override; + AzFramework::BehaviorComponentId GetOrAddComponentByTypeName(AZ::EntityId entity, const AZStd::string& typeName) override; + bool UpdateComponentForEntity(AZ::EntityId entity, AzFramework::BehaviorComponentId component, const AZStd::string& json) override; + AZStd::string GetComponentDefaultJson(const AZStd::string& typeName) override; + AZStd::vector FindMatchingComponents(const AZStd::string& searchTerm) override; + void ResetEntityContext() override; + + static void Reflect(AZ::ReflectContext* context); + + protected: + void Activate() override; + void Deactivate() override; + + // Our own entity context. This API is intended mostly for use in Asset Builders where there is no editor context + // Additionally, an entity context is needed when using the Behavior Entity class + AZStd::unique_ptr m_entityContext; + + // TypeId, TypeName, Vector + AZStd::vector>> m_typeInfo; + + // Keep track of the entities we create so they can be reset + AZStd::vector m_createdEntities; + }; +}; // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h index 75e3bab60f..5455e8d773 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h @@ -10,6 +10,7 @@ #include #include +#include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp index 09439724cd..07bda45c8a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp @@ -50,17 +50,19 @@ namespace AzToolsFramework auto settingsRegistry = AZ::SettingsRegistry::Get(); AZ_Assert(settingsRegistry, "Settings registry is not set"); - + [[maybe_unused]] bool result = settingsRegistry->Get(m_projectPathWithOsSeparator.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); AZ_Warning("Prefab", result, "Couldn't retrieve project root path"); m_projectPathWithSlashSeparator = AZ::IO::Path(m_projectPathWithOsSeparator.Native(), '/').MakePreferred(); AZ::Interface::Register(this); + m_scriptingPrefabLoader.Connect(this); } void PrefabLoader::UnregisterPrefabLoaderInterface() { + m_scriptingPrefabLoader.Disconnect(); AZ::Interface::Unregister(this); } @@ -568,7 +570,7 @@ namespace AzToolsFramework (pathStr.find_first_of(AZ_FILESYSTEM_INVALID_CHARACTERS) == AZStd::string::npos) && (pathStr.back() != '\\' && pathStr.back() != '/'); } - + AZ::IO::Path PrefabLoader::GetFullPath(AZ::IO::PathView path) { AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path).MakePreferred(); @@ -596,26 +598,38 @@ namespace AzToolsFramework { // The asset system provided us with a valid root folder and relative path, so return it. fullPath = AZ::IO::Path(rootFolder) / assetInfo.m_relativePath; + return fullPath; } else { - // If for some reason the Asset system couldn't provide a relative path, provide some fallback logic. + // attempt to find the absolute from the Cache folder + AZStd::string assetRootFolder; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(assetRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + } + fullPath = AZ::IO::Path(assetRootFolder) / path; + if (fullPath.IsAbsolute() && AZ::IO::SystemFile::Exists(fullPath.c_str())) + { + return fullPath; + } + } - // Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow - // the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside - // a unit test, so just execute the fallback logic without an error. - [[maybe_unused]] bool assetProcessorReady = false; - AzFramework::AssetSystemRequestBus::BroadcastResult( - assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady); + // If for some reason the Asset system couldn't provide a relative path, provide some fallback logic. - AZ_Error( - "Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.", - AZ_STRING_ARG(path.Native())); + // Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow + // the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside + // a unit test, so just execute the fallback logic without an error. + [[maybe_unused]] bool assetProcessorReady = false; + AzFramework::AssetSystemRequestBus::BroadcastResult( + assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady); - // If a relative path was passed in, make it relative to the project root. - fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator); - } + AZ_Error( + "Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.", + AZ_STRING_ARG(path.Native())); + // If a relative path was passed in, make it relative to the project root. + fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator); return fullPath; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h index 15f201e027..da2c3f3161 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace AZ { @@ -114,6 +115,7 @@ namespace AzToolsFramework void SetSaveAllPrefabsPreference(SaveAllPrefabsPreference saveAllPrefabsPreference) override; private: + /** * Copies the template dom provided and manipulates it into the proper format to be saved to disk. * @param templateRef The template whose dom we want to transform into the proper format to be saved to disk. @@ -177,6 +179,7 @@ namespace AzToolsFramework AZStd::optional> StoreTemplateIntoFileFormat(TemplateId templateId); PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr; + ScriptingPrefabLoader m_scriptingPrefabLoader; AZ::IO::Path m_projectPathWithOsSeparator; AZ::IO::Path m_projectPathWithSlashSeparator; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h index a428f8a7b9..b4586ad5bf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h @@ -99,7 +99,6 @@ namespace AzToolsFramework // Generates a new path static AZ::IO::Path GeneratePath(); }; - } // namespace Prefab } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderScriptingBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderScriptingBus.h new file mode 100644 index 0000000000..6e9d64b147 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderScriptingBus.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + namespace Prefab + { + // Ebus for script-friendly APIs for the prefab loader + struct PrefabLoaderScriptingTraits : AZ::EBusTraits + { + AZ_TYPE_INFO(PrefabLoaderScriptingTraits, "{C344B7D8-8299-48C9-8450-26E1332EA011}"); + + virtual ~PrefabLoaderScriptingTraits() = default; + + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + + /** + * Saves a Prefab Template into the provided output string. + * Converts Prefab Template form into .prefab form by collapsing nested Template info + * into a source path and patches. + * @param templateId Id of the template to be saved + * @return Will contain the serialized template json on success + */ + virtual AZ::Outcome SaveTemplateToString(TemplateId templateId) = 0; + }; + + using PrefabLoaderScriptingBus = AZ::EBus; + + } // namespace Prefab +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 896e40d929..b1fdf9784d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -36,12 +37,14 @@ namespace AzToolsFramework m_instanceToTemplatePropagator.RegisterInstanceToTemplateInterface(); m_prefabPublicHandler.RegisterPrefabPublicHandlerInterface(); m_prefabPublicRequestHandler.Connect(); + m_prefabSystemScriptingHandler.Connect(this); AZ::SystemTickBus::Handler::BusConnect(); } void PrefabSystemComponent::Deactivate() { AZ::SystemTickBus::Handler::BusDisconnect(); + m_prefabSystemScriptingHandler.Disconnect(); m_prefabPublicRequestHandler.Disconnect(); m_prefabPublicHandler.UnregisterPrefabPublicHandlerInterface(); m_instanceToTemplatePropagator.UnregisterInstanceToTemplateInterface(); @@ -58,13 +61,24 @@ namespace AzToolsFramework AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover::Reflect(context); PrefabPublicRequestHandler::Reflect(context); PrefabLoader::Reflect(context); + PrefabSystemScriptingHandler::Reflect(context); - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) + if (AZ::SerializeContext* serialize = azrtti_cast(context)) { serialize->Class()->Version(1); } + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + + behaviorContext->EBus("PrefabLoaderScriptingBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "prefab") + ->Attribute(AZ::Script::Attributes::Category, "Prefab") + ->Event("SaveTemplateToString", &PrefabLoaderScriptingBus::Events::SaveTemplateToString); + ; + } + AZ::JsonRegistrationContext* jsonRegistration = azrtti_cast(context); if (jsonRegistration) { @@ -145,7 +159,7 @@ namespace AzToolsFramework newInstance->SetTemplateId(newTemplateId); } } - + void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude) { UpdatePrefabInstances(templateId, immediate, instanceToExclude); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h index f640eb2f1b..480bb83121 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace AZ { @@ -219,7 +220,7 @@ namespace AzToolsFramework const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity = nullptr, InstanceOptionalReference parent = AZStd::nullopt, bool shouldCreateLinks = true) override; - + PrefabDom& FindTemplateDom(TemplateId templateId) override; /** @@ -244,7 +245,7 @@ namespace AzToolsFramework private: AZ_DISABLE_COPY_MOVE(PrefabSystemComponent); - + /** * Builds a new Prefab Template out of entities and instances and returns the first instance comprised of * these entities and instances. @@ -412,6 +413,8 @@ namespace AzToolsFramework // Handler of the public Prefab requests. PrefabPublicRequestHandler m_prefabPublicRequestHandler; + + PrefabSystemScriptingHandler m_prefabSystemScriptingHandler; }; } // namespace Prefab } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h index 54ca951841..66d85ccee9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponentInterface.h @@ -78,8 +78,7 @@ namespace AzToolsFramework AZStd::unique_ptr containerEntity = nullptr, InstanceOptionalReference parent = AZStd::nullopt, bool shouldCreateLinks = true) = 0; }; - - + } // namespace Prefab } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingBus.h new file mode 100644 index 0000000000..f83bd2c6f1 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingBus.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + namespace Prefab + { + // Bus that exposes a script-friendly interface to the PrefabSystemComponent + struct PrefabSystemScriptingEbusTraits : AZ::EBusTraits + { + using MutexType = AZ::NullMutex; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + + virtual TemplateId CreatePrefabTemplate( + const AZStd::vector& entityIds, const AZStd::string& filePath) = 0; + }; + + using PrefabSystemScriptingBus = AZ::EBus; + + } // namespace Prefab +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp new file mode 100644 index 0000000000..d34e2cfc92 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +namespace AzToolsFramework::Prefab +{ + void PrefabSystemScriptingHandler::Reflect(AZ::ReflectContext* context) + { + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->ConstantProperty("InvalidTemplateId", BehaviorConstant(InvalidTemplateId)) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "prefab") + ->Attribute(AZ::Script::Attributes::Category, "Prefab"); + + behaviorContext->EBus("PrefabSystemScriptingBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "prefab") + ->Attribute(AZ::Script::Attributes::Category, "Prefab") + ->Event("CreatePrefab", &PrefabSystemScriptingBus::Events::CreatePrefabTemplate); + } + } + + void PrefabSystemScriptingHandler::Connect(PrefabSystemComponentInterface* prefabSystemComponentInterface) + { + AZ_Assert(prefabSystemComponentInterface != nullptr, "prefabSystemComponentInterface must not be null"); + m_prefabSystemComponentInterface = prefabSystemComponentInterface; + PrefabSystemScriptingBus::Handler::BusConnect(); + } + + void PrefabSystemScriptingHandler::Disconnect() + { + PrefabSystemScriptingBus::Handler::BusDisconnect(); + } + + TemplateId PrefabSystemScriptingHandler::CreatePrefabTemplate(const AZStd::vector& entityIds, const AZStd::string& filePath) + { + AZStd::vector entities; + + for (const auto& entityId : entityIds) + { + AZ::Entity* entity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId); + + AZ_Warning( + "PrefabSystemComponent", entity, "EntityId %s was not found and will not be added to the prefab", + entityId.ToString().c_str()); + + if (entity) + { + entities.push_back(entity); + } + } + + auto prefab = m_prefabSystemComponentInterface->CreatePrefab(entities, {}, AZ::IO::PathView(AZStd::string_view(filePath))); + + if (!prefab) + { + AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str()); + return InvalidTemplateId; + } + + return prefab->GetTemplateId(); + } +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.h new file mode 100644 index 0000000000..809690bf35 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once +#include + +namespace AzToolsFramework +{ + namespace Prefab + { + class PrefabSystemScriptingHandler + : PrefabSystemScriptingBus::Handler + { + public: + static void Reflect(AZ::ReflectContext* context); + + PrefabSystemScriptingHandler() = default; + + void Connect(PrefabSystemComponentInterface* prefabSystemComponentInterface); + void Disconnect(); + + private: + AZ_DISABLE_COPY(PrefabSystemScriptingHandler); + + ////////////////////////////////////////////////////////////////////////// + // PrefabSystemScriptingBus implementation + TemplateId CreatePrefabTemplate(const AZStd::vector& entityIds, const AZStd::string& filePath) override; + ////////////////////////////////////////////////////////////////////////// + + PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr; + }; + } // namespace Prefab +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.cpp new file mode 100644 index 0000000000..465d83e94b --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#include +#include +#include +#include +#include + +namespace AZ::Prefab +{ + static constexpr const char s_useProceduralPrefabsKey[] = "/O3DE/Preferences/Prefabs/UseProceduralPrefabs"; + + // ProceduralPrefabAsset + + ProceduralPrefabAsset::ProceduralPrefabAsset(const AZ::Data::AssetId& assetId) + : AZ::Data::AssetData(assetId) + , m_templateId(AzToolsFramework::Prefab::InvalidTemplateId) + { + } + + void ProceduralPrefabAsset::Reflect(AZ::ReflectContext* context) + { + PrefabDomData::Reflect(context); + + if (auto* serializeContext = azrtti_cast(context); serializeContext != nullptr) + { + serializeContext->Class() + ->Version(1) + ->Field("Template Name", &ProceduralPrefabAsset::m_templateName) + ->Field("Template ID", &ProceduralPrefabAsset::m_templateId); + } + } + + const AZStd::string& ProceduralPrefabAsset::GetTemplateName() const + { + return m_templateName; + } + + void ProceduralPrefabAsset::SetTemplateName(AZStd::string templateName) + { + m_templateName = AZStd::move(templateName); + } + + AzToolsFramework::Prefab::TemplateId ProceduralPrefabAsset::GetTemplateId() const + { + return m_templateId; + } + + void ProceduralPrefabAsset::SetTemplateId(AzToolsFramework::Prefab::TemplateId templateId) + { + m_templateId = templateId; + } + + bool ProceduralPrefabAsset::UseProceduralPrefabs() + { + bool useProceduralPrefabs = false; + bool result = AZ::SettingsRegistry::Get()->GetObject(useProceduralPrefabs, s_useProceduralPrefabsKey); + return result && useProceduralPrefabs; + } + + // PrefabDomData + + void PrefabDomData::Reflect(AZ::ReflectContext* context) + { + if (auto* jsonContext = azrtti_cast(context)) + { + jsonContext->Serializer()->HandlesType(); + } + + AZ::SerializeContext* serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Version(1); + } + } + + void PrefabDomData::CopyValue(const rapidjson::Value& inputValue) + { + m_prefabDom.CopyFrom(inputValue, m_prefabDom.GetAllocator()); + } + + const AzToolsFramework::Prefab::PrefabDom& PrefabDomData::GetValue() const + { + return m_prefabDom; + } + + // PrefabDomDataJsonSerializer + + AZ::JsonSerializationResult::Result PrefabDomDataJsonSerializer::Load( + void* outputValue, + [[maybe_unused]] const AZ::Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) + { + AZ_Assert(outputValueTypeId == azrtti_typeid(), + "PrefabDomDataJsonSerializer Load against output typeID that was not PrefabDomData"); + AZ_Assert(outputValue, "PrefabDomDataJsonSerializer Load against null output"); + + namespace JSR = AZ::JsonSerializationResult; + JSR::ResultCode result(JSR::Tasks::ReadField); + + if (inputValue.IsObject() == false) + { + result.Combine(context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, "Missing object")); + return context.Report(result, "Prefab should be an object."); + } + + if (inputValue.MemberCount() < 1) + { + result.Combine(context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, "Missing members")); + return context.Report(result, "Prefab should have multiple members."); + } + + auto* outputVariable = reinterpret_cast(outputValue); + outputVariable->CopyValue(inputValue); + return context.Report(result, "Loaded procedural prefab"); + } + + AZ::JsonSerializationResult::Result PrefabDomDataJsonSerializer::Store( + rapidjson::Value& outputValue, + const void* inputValue, + [[maybe_unused]] const void* defaultValue, + [[maybe_unused]] const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) + { + AZ_Assert(inputValue, "Input value for PrefabDomDataJsonSerializer can't be null."); + AZ_Assert(azrtti_typeid() == valueTypeId, + "Unable to Serialize because the provided type is not PrefabGroup::PrefabDomData."); + + const PrefabDomData* prefabDomData = reinterpret_cast(inputValue); + + namespace JSR = AZ::JsonSerializationResult; + JSR::ResultCode result(JSR::Tasks::WriteValue); + outputValue.SetObject(); + outputValue.CopyFrom(prefabDomData->GetValue(), context.GetJsonAllocator()); + return context.Report(result, "Stored procedural prefab"); + } +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h new file mode 100644 index 0000000000..dd57389b7b --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h @@ -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 + * + */ +#pragma once + +#include +#include +#include +#include + +namespace AZ::Prefab +{ + //! A wrapper around the JSON DOM type so that the assets can read in and write out + //! JSON directly since Prefabs are JSON serialized entity-component data + class PrefabDomData final + { + public: + AZ_RTTI(PrefabDomData, "{C73A3360-D772-4D41-9118-A039BF9340C1}"); + AZ_CLASS_ALLOCATOR(PrefabDomData, AZ::SystemAllocator, 0); + + PrefabDomData() = default; + ~PrefabDomData() = default; + + static void Reflect(AZ::ReflectContext* context); + + void CopyValue(const rapidjson::Value& inputValue); + const AzToolsFramework::Prefab::PrefabDom& GetValue() const; + + private: + AzToolsFramework::Prefab::PrefabDom m_prefabDom; + }; + + //! Registered to help read/write JSON for the PrefabDomData::m_prefabDom + class PrefabDomDataJsonSerializer final + : public AZ::BaseJsonSerializer + { + public: + AZ_RTTI(PrefabDomDataJsonSerializer, "{9FC48652-A00B-4EFA-8FD9-345A8E625439}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR(PrefabDomDataJsonSerializer, AZ::SystemAllocator, 0); + + ~PrefabDomDataJsonSerializer() override = default; + + AZ::JsonSerializationResult::Result Load( + void* outputValue, + const AZ::Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) override; + + AZ::JsonSerializationResult::Result Store( + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) override; + }; + + //! An asset type to register templates into the Prefab system so that they + //! can instantiate like Authored Prefabs + class ProceduralPrefabAsset + : public AZ::Data::AssetData + { + public: + AZ_CLASS_ALLOCATOR(ProceduralPrefabAsset, AZ::SystemAllocator, 0); + AZ_RTTI(ProceduralPrefabAsset, "{9B7C8459-471E-4EAD-A363-7990CC4065A9}", AZ::Data::AssetData); + + static bool UseProceduralPrefabs(); + + ProceduralPrefabAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId()); + ~ProceduralPrefabAsset() override = default; + ProceduralPrefabAsset(const ProceduralPrefabAsset& rhs) = delete; + ProceduralPrefabAsset& operator=(const ProceduralPrefabAsset& rhs) = delete; + + const AZStd::string& GetTemplateName() const; + void SetTemplateName(AZStd::string templateName); + + AzToolsFramework::Prefab::TemplateId GetTemplateId() const; + void SetTemplateId(AzToolsFramework::Prefab::TemplateId templateId); + + static void Reflect(AZ::ReflectContext* context); + + private: + AZStd::string m_templateName; + AzToolsFramework::Prefab::TemplateId m_templateId; + }; + +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.cpp new file mode 100644 index 0000000000..bee8a8bc3b --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.cpp @@ -0,0 +1,37 @@ +/* + * 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 + +namespace AzToolsFramework::Prefab +{ + void ScriptingPrefabLoader::Connect(PrefabLoaderInterface* prefabLoaderInterface) + { + AZ_Assert(prefabLoaderInterface, "prefabLoaderInterface must not be null"); + + m_prefabLoaderInterface = prefabLoaderInterface; + PrefabLoaderScriptingBus::Handler::BusConnect(); + } + + void ScriptingPrefabLoader::Disconnect() + { + PrefabLoaderScriptingBus::Handler::BusDisconnect(); + } + + AZ::Outcome ScriptingPrefabLoader::SaveTemplateToString(TemplateId templateId) + { + AZStd::string json; + + if (m_prefabLoaderInterface->SaveTemplateToString(templateId, json)) + { + return AZ::Success(json); + } + + return AZ::Failure(); + } +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.h new file mode 100644 index 0000000000..ec6219909e --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/ScriptingPrefabLoader.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework +{ + namespace Prefab + { + /** + * The Scripting Prefab Loader handles scripting-friendly API requests for the prefab loader + */ + class ScriptingPrefabLoader + : private PrefabLoaderScriptingBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(ScriptingPrefabLoader, AZ::SystemAllocator, 0); + AZ_RTTI(ScriptingPrefabLoader, "{ABC3C989-4D4F-41E7-B25B-B0FEF97177E6}"); + + void Connect(PrefabLoaderInterface* prefabLoaderInterface); + void Disconnect(); + + private: + + ////////////////////////////////////////////////////////////////////////// + // PrefabLoaderRequestBus implementation + AZ::Outcome SaveTemplateToString(TemplateId templateId) override; + ////////////////////////////////////////////////////////////////////////// + + PrefabLoaderInterface* m_prefabLoaderInterface = nullptr; + }; + } // namespace Prefab +} // namespace AzToolsFramework + diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 07dcd2ab20..d4b227c4ff 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -218,6 +222,16 @@ namespace AzToolsFramework instantiateAction, &QAction::triggered, instantiateAction, [] { ContextMenu_InstantiatePrefab(); }); } + // Instantiate Procedural Prefab + if (AZ::Prefab::ProceduralPrefabAsset::UseProceduralPrefabs()) + { + QAction* action = menu->addAction(QObject::tr("Instantiate Procedural Prefab...")); + action->setToolTip(QObject::tr("Instantiates a procedural prefab file in a prefab.")); + + QObject::connect( + action, &QAction::triggered, action, [] { ContextMenu_InstantiateProceduralPrefab(); }); + } + menu->addSeparator(); bool itemWasShown = false; @@ -435,6 +449,38 @@ namespace AzToolsFramework } } + void PrefabIntegrationManager::ContextMenu_InstantiateProceduralPrefab() + { + AZStd::string prefabAssetPath; + bool hasUserForProceduralPrefabAsset = QueryUserForProceduralPrefabAsset(prefabAssetPath); + + if (hasUserForProceduralPrefabAsset) + { + AZ::EntityId parentId; + AZ::Vector3 position = AZ::Vector3::CreateZero(); + + EntityIdList selectedEntities; + ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities); + if (selectedEntities.size() == 1) + { + parentId = selectedEntities.front(); + AZ::TransformBus::EventResult(position, parentId, &AZ::TransformInterface::GetWorldTranslation); + } + else + { + // otherwise return since it needs to be inside an authored prefab + return; + } + + // Instantiating from context menu always puts the instance at the root level + auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(prefabAssetPath, parentId, position); + if (!createPrefabOutcome.IsSuccess()) + { + WarnUserOfError("Prefab Instantiation Error", createPrefabOutcome.GetError()); + } + } + } + void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity) { s_prefabFocusInterface->FocusOnOwningPrefab(containerEntity); @@ -690,6 +736,33 @@ namespace AzToolsFramework return true; } + bool PrefabIntegrationManager::QueryUserForProceduralPrefabAsset(AZStd::string& outPrefabAssetPath) + { + using namespace AzToolsFramework; + auto selection = AssetBrowser::AssetSelectionModel::AssetTypeSelection(azrtti_typeid()); + EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection); + + if (!selection.IsValid()) + { + return false; + } + + auto product = azrtti_cast(selection.GetResult()); + if (product == nullptr) + { + return false; + } + + outPrefabAssetPath = product->GetRelativePath(); + + auto asset = AZ::Data::AssetManager::Instance().GetAsset( + product->GetAssetId(), + azrtti_typeid(), + AZ::Data::AssetLoadBehavior::Default); + + return asset.BlockUntilLoadComplete() != AZ::Data::AssetData::AssetStatus::Error; + } + void PrefabIntegrationManager::WarnUserOfError(AZStd::string_view title, AZStd::string_view message) { QWidget* activeWindow = QApplication::activeWindow(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 44e30b2013..696c05991c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -91,6 +91,7 @@ namespace AzToolsFramework // Context menu item handlers static void ContextMenu_CreatePrefab(AzToolsFramework::EntityIdList selectedEntities); static void ContextMenu_InstantiatePrefab(); + static void ContextMenu_InstantiateProceduralPrefab(); static void ContextMenu_EditPrefab(AZ::EntityId containerEntity); static void ContextMenu_SavePrefab(AZ::EntityId containerEntity); static void ContextMenu_DeleteSelected(); @@ -101,6 +102,7 @@ namespace AzToolsFramework const AZStd::string& suggestedName, const char* initialTargetDirectory, AZ::u32 prefabUserSettingsId, QWidget* activeWindow, AZStd::string& outPrefabName, AZStd::string& outPrefabFilePath); static bool QueryUserForPrefabFilePath(AZStd::string& outPrefabFilePath); + static bool QueryUserForProceduralPrefabAsset(AZStd::string& outPrefabAssetPath); static void WarnUserOfError(AZStd::string_view title, AZStd::string_view message); // Path and filename generation diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 0866b225c1..ff7fe58f1e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -152,6 +152,8 @@ set(FILES Entity/SliceEditorEntityOwnershipService.h Entity/SliceEditorEntityOwnershipService.cpp Entity/SliceEditorEntityOwnershipServiceBus.h + Entity/EntityUtilityComponent.h + Entity/EntityUtilityComponent.cpp Fingerprinting/TypeFingerprinter.h Fingerprinting/TypeFingerprinter.cpp FocusMode/FocusModeInterface.h @@ -646,9 +648,15 @@ set(FILES Prefab/PrefabLoader.h Prefab/PrefabLoader.cpp Prefab/PrefabLoaderInterface.h + Prefab/PrefabLoaderScriptingBus.h + Prefab/ScriptingPrefabLoader.h + Prefab/ScriptingPrefabLoader.cpp Prefab/PrefabSystemComponent.h Prefab/PrefabSystemComponent.cpp Prefab/PrefabSystemComponentInterface.h + Prefab/PrefabSystemScriptingBus.h + Prefab/PrefabSystemScriptingHandler.h + Prefab/PrefabSystemScriptingHandler.cpp Prefab/Instance/Instance.h Prefab/Instance/Instance.cpp Prefab/Instance/InstanceSerializer.h @@ -671,6 +679,8 @@ set(FILES Prefab/Instance/TemplateInstanceMapperInterface.h Prefab/Link/Link.h Prefab/Link/Link.cpp + Prefab/Procedural/ProceduralPrefabAsset.h + Prefab/Procedural/ProceduralPrefabAsset.cpp Prefab/PrefabPublicHandler.h Prefab/PrefabPublicHandler.cpp Prefab/PrefabPublicInterface.h diff --git a/Code/Framework/AzToolsFramework/Tests/Entity/EntityUtilityComponentTests.cpp b/Code/Framework/AzToolsFramework/Tests/Entity/EntityUtilityComponentTests.cpp new file mode 100644 index 0000000000..fce44d4833 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/Entity/EntityUtilityComponentTests.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +namespace UnitTest +{ + // Global variables for communicating between Lua test code and C++ + AZ::EntityId g_globalEntityId = AZ::EntityId{}; + AZStd::string g_globalString = ""; + AzFramework::BehaviorComponentId g_globalComponentId = {}; + AZStd::vector g_globalComponentDetails = {}; + bool g_globalBool = false; + + class EntityUtilityComponentTests + : public ToolsApplicationFixture + { + void InitProperties() + { + AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface::Get(); + + ASSERT_NE(componentApplicationRequests, nullptr); + + auto behaviorContext = componentApplicationRequests->GetBehaviorContext(); + + ASSERT_NE(behaviorContext, nullptr); + + behaviorContext->Property("g_globalEntityId", BehaviorValueProperty(&g_globalEntityId)); + behaviorContext->Property("g_globalString", BehaviorValueProperty(&g_globalString)); + behaviorContext->Property("g_globalComponentId", BehaviorValueProperty(&g_globalComponentId)); + behaviorContext->Property("g_globalBool", BehaviorValueProperty(&g_globalBool)); + behaviorContext->Property("g_globalComponentDetails", BehaviorValueProperty(&g_globalComponentDetails)); + + g_globalEntityId = AZ::EntityId{}; + g_globalString = AZStd::string{}; + g_globalComponentId = AzFramework::BehaviorComponentId{}; + g_globalBool = false; + g_globalComponentDetails = AZStd::vector{}; + } + + void SetUpEditorFixtureImpl() override + { + InitProperties(); + } + + void TearDownEditorFixtureImpl() override + { + g_globalString.set_capacity(0); // Free all memory + g_globalComponentDetails.set_capacity(0); + } + }; + + TEST_F(EntityUtilityComponentTests, CreateEntity) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + my_entity = Entity(g_globalEntityId) + g_globalString = my_entity:GetName() + )LUA"); + + EXPECT_NE(g_globalEntityId, AZ::EntityId{}); + EXPECT_STREQ(g_globalString.c_str(), "test"); + + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(g_globalEntityId); + + ASSERT_NE(entity, nullptr); + + // Test cleaning up, make sure the entity is destroyed + AzToolsFramework::EntityUtilityBus::Broadcast(&AzToolsFramework::EntityUtilityBus::Events::ResetEntityContext); + + entity = AZ::Interface::Get()->FindEntity(g_globalEntityId); + + ASSERT_EQ(entity, nullptr); + } + + TEST_F(EntityUtilityComponentTests, CreateEntityEmptyName) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("") + )LUA"); + + EXPECT_NE(g_globalEntityId, AZ::EntityId{}); + + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(g_globalEntityId); + + ASSERT_NE(entity, nullptr); + } + + TEST_F(EntityUtilityComponentTests, FindComponent) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0 TransformComponent") + )LUA"); + + EXPECT_TRUE(g_globalComponentId.IsValid()); + } + + TEST_F(EntityUtilityComponentTests, InvalidComponentName) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + AZ_TEST_START_TRACE_SUPPRESSION; + sc.Execute(R"LUA( + ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "ThisIsNotAComponent-Error") + )LUA"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(g_globalComponentId.IsValid()); + } + + TEST_F(EntityUtilityComponentTests, InvalidComponentId) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + AZ_TEST_START_TRACE_SUPPRESSION; + sc.Execute(R"LUA( + ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "{1234-hello-world-this-is-not-an-id}") + )LUA"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // Should get 1 error stating the type id is not valid + EXPECT_FALSE(g_globalComponentId.IsValid()); + } + + TEST_F(EntityUtilityComponentTests, CreateComponent) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "ScriptEditorComponent") + )LUA"); + + EXPECT_TRUE(g_globalComponentId.IsValid()); + } + + TEST_F(EntityUtilityComponentTests, UpdateComponent) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + comp_id = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(g_globalEntityId, "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent") + json_update = [[ + { + "Transform Data": { "Rotate": [0.0, 0.1, 180.0] } + } + ]] + g_globalBool = EntityUtilityBus.Broadcast.UpdateComponentForEntity(g_globalEntityId, comp_id, json_update); + )LUA"); + + EXPECT_TRUE(g_globalBool); + EXPECT_NE(g_globalEntityId, AZ::EntityId(AZ::EntityId::InvalidEntityId)); + + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(g_globalEntityId); + + auto* transformComponent = entity->FindComponent(); + + ASSERT_NE(transformComponent, nullptr); + + AZ::Vector3 localRotation = transformComponent->GetLocalRotationQuaternion().GetEulerDegrees(); + + EXPECT_EQ(localRotation, AZ::Vector3(.0f, 0.1f, 180.0f)); + } + + TEST_F(EntityUtilityComponentTests, GetComponentJson) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + g_globalString = EntityUtilityBus.Broadcast.GetComponentDefaultJson("ScriptEditorComponent") + )LUA"); + + EXPECT_STRNE(g_globalString.c_str(), ""); + } + + TEST_F(EntityUtilityComponentTests, GetComponentJsonDoesNotExist) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + AZ_TEST_START_TRACE_SUPPRESSION; + sc.Execute(R"LUA( + g_globalString = EntityUtilityBus.Broadcast.GetComponentDefaultJson("404") + )LUA"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 error: Failed to find component id for type name 404 + + EXPECT_STREQ(g_globalString.c_str(), ""); + } + + TEST_F(EntityUtilityComponentTests, SearchComponents) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + g_globalComponentDetails = EntityUtilityBus.Broadcast.FindMatchingComponents("Transform*") + )LUA"); + + // There should be 2 transform components + EXPECT_EQ(g_globalComponentDetails.size(), 2); + } + + TEST_F(EntityUtilityComponentTests, SearchComponentsNotFound) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + g_globalComponentDetails = EntityUtilityBus.Broadcast.FindMatchingComponents("404") + )LUA"); + + EXPECT_EQ(g_globalComponentDetails.size(), 0); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabScriptingTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabScriptingTests.cpp new file mode 100644 index 0000000000..7e61c50629 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabScriptingTests.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include +#include +#include + +namespace UnitTest +{ + TemplateId g_globalTemplateId = {}; + AZStd::string g_globalPrefabString = ""; + + class PrefabScriptingTest : public PrefabTestFixture + { + void InitProperties() const + { + AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface::Get(); + + ASSERT_NE(componentApplicationRequests, nullptr); + + auto behaviorContext = componentApplicationRequests->GetBehaviorContext(); + + ASSERT_NE(behaviorContext, nullptr); + + behaviorContext->Property("g_globalTemplateId", BehaviorValueProperty(&g_globalTemplateId)); + behaviorContext->Property("g_globalPrefabString", BehaviorValueProperty(&g_globalPrefabString)); + + g_globalTemplateId = TemplateId{}; + g_globalPrefabString = AZStd::string{}; + } + + void SetUpEditorFixtureImpl() override + { + InitProperties(); + } + + void TearDownEditorFixtureImpl() override + { + g_globalPrefabString.set_capacity(0); // Free all memory + } + }; + + TEST_F(PrefabScriptingTest, PrefabScripting_CreatePrefab) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + entities = vector_EntityId() + entities:push_back(my_id) + g_globalTemplateId = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "test.prefab") + )LUA"); + + EXPECT_NE(g_globalTemplateId, TemplateId{}); + + auto prefabSystemComponentInterface = AZ::Interface::Get(); + + ASSERT_NE(prefabSystemComponentInterface, nullptr); + + TemplateReference templateRef = prefabSystemComponentInterface->FindTemplate(g_globalTemplateId); + + EXPECT_TRUE(templateRef); + } + + TEST_F(PrefabScriptingTest, PrefabScripting_CreatePrefab_NoEntities) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + entities = vector_EntityId() + g_globalTemplateId = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "test.prefab") + )LUA"); + + EXPECT_NE(g_globalTemplateId, TemplateId{}); + + auto prefabSystemComponentInterface = AZ::Interface::Get(); + + ASSERT_NE(prefabSystemComponentInterface, nullptr); + + TemplateReference templateRef = prefabSystemComponentInterface->FindTemplate(g_globalTemplateId); + + EXPECT_TRUE(templateRef); + } + + TEST_F(PrefabScriptingTest, PrefabScripting_CreatePrefab_NoPath) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + AZ_TEST_START_TRACE_SUPPRESSION; + sc.Execute(R"LUA( + my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + entities = vector_EntityId() + template_id = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "") + )LUA"); + /* + error: PrefabSystemComponent::CreateTemplateFromInstance - Attempted to create a prefab template from an instance without a source file path. Unable to proceed. + error: Failed to create a Template associated with file path during CreatePrefab. + error: Failed to create prefab + */ + AZ_TEST_STOP_TRACE_SUPPRESSION(3); + } + + TEST_F(PrefabScriptingTest, PrefabScripting_SaveToString) + { + AZ::ScriptContext sc; + auto behaviorContext = AZ::Interface::Get()->GetBehaviorContext(); + + sc.BindTo(behaviorContext); + sc.Execute(R"LUA( + my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test") + entities = vector_EntityId() + entities:push_back(my_id) + template_id = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "test.prefab") + my_result = PrefabLoaderScriptingBus.Broadcast.SaveTemplateToString(template_id) + + if my_result:IsSuccess() then + g_globalPrefabString = my_result:GetValue() + end + )LUA"); + + auto prefabSystemComponentInterface = AZ::Interface::Get(); + prefabSystemComponentInterface->RemoveAllTemplates(); + + EXPECT_STRNE(g_globalPrefabString.c_str(), ""); + TemplateId templateFromString = AZ::Interface::Get()->LoadTemplateFromString(g_globalPrefabString); + + EXPECT_NE(templateFromString, InvalidTemplateId); + + // Create another entity for comparison purposes + AZ::EntityId entityId; + AzToolsFramework::EntityUtilityBus::BroadcastResult( + entityId, &AzToolsFramework::EntityUtilityBus::Events::CreateEditorReadyEntity, "test"); + + AZ::Entity* testEntity = AZ::Interface::Get()->FindEntity(entityId); + + // Instantiate the prefab we saved + AZStd::unique_ptr instance = prefabSystemComponentInterface->InstantiatePrefab(templateFromString); + + EXPECT_NE(instance, nullptr); + + AZStd::vector loadedEntities; + + // Get the entities from the instance + instance->GetConstEntities( + [&loadedEntities](const AZ::Entity& entity) + { + loadedEntities.push_back(&entity); + return true; + }); + + // Make sure the instance has an entity with the same number of components as our test entity + EXPECT_EQ(loadedEntities.size(), 1); + EXPECT_EQ(loadedEntities[0]->GetComponents().size(), testEntity->GetComponents().size()); + + g_globalPrefabString.set_capacity(0); // Free all memory + } + +} diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/ProceduralPrefabAssetTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/ProceduralPrefabAssetTests.cpp new file mode 100644 index 0000000000..0b9e73bbac --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/ProceduralPrefabAssetTests.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +namespace UnitTest +{ + class ProceduralPrefabAssetTest + : public PrefabTestFixture + { + void SetUpEditorFixtureImpl() override + { + AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface::Get(); + ASSERT_NE(componentApplicationRequests, nullptr); + + auto* behaviorContext = componentApplicationRequests->GetBehaviorContext(); + ASSERT_NE(behaviorContext, nullptr); + + auto* jsonRegistrationContext = componentApplicationRequests->GetJsonRegistrationContext(); + ASSERT_NE(jsonRegistrationContext, nullptr); + + auto* serializeContext = componentApplicationRequests->GetSerializeContext(); + ASSERT_NE(serializeContext, nullptr); + + AZ::Prefab::ProceduralPrefabAsset::Reflect(serializeContext); + AZ::Prefab::ProceduralPrefabAsset::Reflect(behaviorContext); + AZ::Prefab::ProceduralPrefabAsset::Reflect(jsonRegistrationContext); + } + + void TearDownEditorFixtureImpl() override + { + AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface::Get(); + componentApplicationRequests->GetJsonRegistrationContext()->EnableRemoveReflection(); + AZ::Prefab::ProceduralPrefabAsset::Reflect(componentApplicationRequests->GetJsonRegistrationContext()); + } + }; + + TEST_F(ProceduralPrefabAssetTest, ReflectContext_AccessMethods_Works) + { + AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface::Get(); + + auto* serializeContext = componentApplicationRequests->GetSerializeContext(); + EXPECT_TRUE(!serializeContext->CreateAny(azrtti_typeid()).empty()); + EXPECT_TRUE(!serializeContext->CreateAny(azrtti_typeid()).empty()); + + auto* jsonRegistrationContext = componentApplicationRequests->GetJsonRegistrationContext(); + EXPECT_TRUE(jsonRegistrationContext->GetSerializerForSerializerType(azrtti_typeid())); + } + + TEST_F(ProceduralPrefabAssetTest, ProceduralPrefabAsset_AccessMethods_Works) + { + const auto templateId = TemplateId(1); + const auto prefabString = "fake.prefab"; + + AZ::Prefab::ProceduralPrefabAsset asset{}; + asset.SetTemplateId(templateId); + EXPECT_EQ(asset.GetTemplateId(), templateId); + + asset.SetTemplateName(prefabString); + EXPECT_EQ(asset.GetTemplateName(), prefabString); + } + + TEST_F(ProceduralPrefabAssetTest, PrefabDomData_AccessMethods_Works) + { + AzToolsFramework::Prefab::PrefabDom dom; + dom.SetObject(); + dom.AddMember("boolValue", true, dom.GetAllocator()); + + AZ::Prefab::PrefabDomData prefabDomData; + prefabDomData.CopyValue(dom); + + const AzToolsFramework::Prefab::PrefabDom& result = prefabDomData.GetValue(); + EXPECT_TRUE(result.HasMember("boolValue")); + EXPECT_TRUE(result.FindMember("boolValue")->value.GetBool()); + } + + TEST_F(ProceduralPrefabAssetTest, PrefabDomDataJsonSerializer_Load_Works) + { + AZ::Prefab::PrefabDomData prefabDomData; + + AzToolsFramework::Prefab::PrefabDom dom; + dom.SetObject(); + dom.AddMember("member", "value", dom.GetAllocator()); + + AZ::Prefab::PrefabDomDataJsonSerializer prefabDomDataJsonSerializer; + AZ::JsonDeserializerSettings settings; + settings.m_reporting = [](auto, auto, auto) + { + AZ::JsonSerializationResult::ResultCode result(AZ::JsonSerializationResult::Tasks::ReadField); + return result; + }; + AZ::JsonDeserializerContext context{ settings }; + + auto result = prefabDomDataJsonSerializer.Load(&prefabDomData, azrtti_typeid(prefabDomData), dom, context); + EXPECT_EQ(result.GetResultCode().GetOutcome(), AZ::JsonSerializationResult::Outcomes::DefaultsUsed); + EXPECT_TRUE(prefabDomData.GetValue().HasMember("member")); + EXPECT_STREQ(prefabDomData.GetValue().FindMember("member")->value.GetString(), "value"); + } + + TEST_F(ProceduralPrefabAssetTest, PrefabDomDataJsonSerializer_Store_Works) + { + AzToolsFramework::Prefab::PrefabDom dom; + dom.SetObject(); + dom.AddMember("member", "value", dom.GetAllocator()); + + AZ::Prefab::PrefabDomData prefabDomData; + prefabDomData.CopyValue(dom); + + AZ::Prefab::PrefabDomDataJsonSerializer prefabDomDataJsonSerializer; + AzToolsFramework::Prefab::PrefabDom outputValue; + AZ::JsonSerializerSettings settings; + settings.m_reporting = [](auto, auto, auto) + { + AZ::JsonSerializationResult::ResultCode result(AZ::JsonSerializationResult::Tasks::WriteValue); + return result; + }; + AZ::JsonSerializerContext context{ settings, outputValue.GetAllocator() }; + auto result = prefabDomDataJsonSerializer.Store(outputValue, &prefabDomData, nullptr, azrtti_typeid(prefabDomData), context); + EXPECT_EQ(result.GetResultCode().GetOutcome(), AZ::JsonSerializationResult::Outcomes::DefaultsUsed); + EXPECT_TRUE(outputValue.HasMember("member")); + EXPECT_STREQ(outputValue.FindMember("member")->value.GetString(), "value"); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index 11ea5a0b38..87d522c4a6 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -27,6 +27,7 @@ set(FILES Entity/EditorEntityHelpersTests.cpp Entity/EditorEntitySearchComponentTests.cpp Entity/EditorEntitySelectionTests.cpp + Entity/EntityUtilityComponentTests.cpp EntityIdQLabelTests.cpp EntityInspectorTests.cpp EntityOwnershipService/EntityOwnershipServiceTestFixture.cpp @@ -91,6 +92,8 @@ set(FILES Prefab/SpawnableSortEntitiesTestFixture.cpp Prefab/SpawnableSortEntitiesTestFixture.h Prefab/SpawnableSortEntitiesTests.cpp + Prefab/PrefabScriptingTests.cpp + Prefab/ProceduralPrefabAssetTests.cpp PropertyIntCtrlCommonTests.h PropertyIntSliderCtrlTests.cpp PropertyIntSpinCtrlTests.cpp diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp index 9c9c517020..da2edcc51f 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderApplication.cpp @@ -36,6 +36,7 @@ #include #include #include +#include namespace AssetBuilder { @@ -80,6 +81,7 @@ AZ::ComponentTypeList AssetBuilderApplication::GetRequiredSystemComponents() con azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), }); return components; diff --git a/Code/Tools/AssetProcessor/native/ui/AssetTreeFilterModel.cpp b/Code/Tools/AssetProcessor/native/ui/AssetTreeFilterModel.cpp index 50a472c44d..c33fc59d97 100644 --- a/Code/Tools/AssetProcessor/native/ui/AssetTreeFilterModel.cpp +++ b/Code/Tools/AssetProcessor/native/ui/AssetTreeFilterModel.cpp @@ -62,7 +62,10 @@ namespace AssetProcessor { searchStr = searchStr.mid(0, subidPos); } - AZ::Uuid filterAsUuid = AZ::Uuid::CreateStringPermissive(searchStr.toUtf8(), 0); + + // Cap the string to some reasonable length, we don't want to try parsing an entire book + size_t cappedStringLength = searchStr.length() > 60 ? 60 : searchStr.length(); + AZ::Uuid filterAsUuid = AZ::Uuid::CreateStringPermissive(searchStr.toUtf8(), cappedStringLength); return DescendantMatchesFilter(*assetTreeItem, filter, filterAsUuid); } diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.cpp b/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.cpp index ab260eba4d..1efec493c1 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Containers/GraphObjectProxy.cpp @@ -194,8 +194,8 @@ namespace AZ if (baseClass) { m_behaviorClass = behaviorClass; + return true; } - return true; } return false; } diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/Scene.cpp b/Code/Tools/SceneAPI/SceneCore/Containers/Scene.cpp index b6c7eef90f..31b74405d2 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/Scene.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Containers/Scene.cpp @@ -47,6 +47,16 @@ namespace AZ return m_sourceGuid; } + void Scene::SetWatchFolder(const AZStd::string& watchFolder) + { + m_watchFolder = watchFolder; + } + + const AZStd::string& Scene::GetWatchFolder() const + { + return m_watchFolder; + } + void Scene::SetManifestFilename(const AZStd::string& name) { m_manifestFilename = name; @@ -111,6 +121,7 @@ namespace AZ ->Property("sourceGuid", BehaviorValueGetter(&Scene::m_sourceGuid), nullptr) ->Property("graph", BehaviorValueGetter(&Scene::m_graph), nullptr) ->Property("manifest", BehaviorValueGetter(&Scene::m_manifest), nullptr) + ->Property("watchFolder", BehaviorValueGetter(&Scene::m_watchFolder), nullptr) ->Constant("SceneOrientation_YUp", BehaviorConstant(SceneOrientation::YUp)) ->Constant("SceneOrientation_ZUp", BehaviorConstant(SceneOrientation::ZUp)) ->Constant("SceneOrientation_XUp", BehaviorConstant(SceneOrientation::XUp)) diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/Scene.h b/Code/Tools/SceneAPI/SceneCore/Containers/Scene.h index 49320c4592..0185c23178 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/Scene.h +++ b/Code/Tools/SceneAPI/SceneCore/Containers/Scene.h @@ -34,6 +34,9 @@ namespace AZ const AZStd::string& GetSourceFilename() const; const Uuid& GetSourceGuid() const; + void SetWatchFolder(const AZStd::string& watchFolder); + const AZStd::string& GetWatchFolder() const; + void SetManifestFilename(const AZStd::string& name); void SetManifestFilename(AZStd::string&& name); const AZStd::string& GetManifestFilename() const; @@ -59,6 +62,7 @@ namespace AZ AZStd::string m_name; AZStd::string m_manifestFilename; AZStd::string m_sourceFilename; + AZStd::string m_watchFolder; Uuid m_sourceGuid; SceneGraph m_graph; SceneManifest m_manifest; diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp b/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp index cae0dc45d5..3d00dccec3 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp @@ -97,7 +97,7 @@ namespace AZ GraphObjectProxy* proxy = aznew GraphObjectProxy(graphObject); return proxy; } - return nullptr; + return aznew GraphObjectProxy(nullptr); }); } } diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp b/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp index 664c5f1272..8e3f06b4cb 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.cpp @@ -36,8 +36,7 @@ namespace AZ { namespace Containers { - //! Protects from allocating too much memory. The choice of a 5MB threshold is arbitrary. - const size_t MaxSceneManifestFileSizeInBytes = 5 * 1024 * 1024; + const char ErrorWindowName[] = "SceneManifest"; diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.h b/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.h index 4386d4fd8c..f3838096ad 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.h +++ b/Code/Tools/SceneAPI/SceneCore/Containers/SceneManifest.h @@ -41,6 +41,8 @@ namespace AZ AZ_RTTI(SceneManifest, "{9274AD17-3212-4651-9F3B-7DCCB080E467}"); + static constexpr size_t MaxSceneManifestFileSizeInBytes = AZStd::numeric_limits::max(); + virtual ~SceneManifest(); static AZStd::shared_ptr SceneManifestConstDataConverter( diff --git a/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.cpp b/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.cpp index a182e4f02d..c98fa63916 100644 --- a/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -73,6 +74,10 @@ namespace AZ { } + void AssetImportRequest::GetGeneratedManifestExtension(AZStd::string& /*result*/) + { + } + void AssetImportRequest::GetSupportedFileExtensions(AZStd::unordered_set& /*extensions*/) { } @@ -103,14 +108,34 @@ namespace AZ AZ_UNUSED(value); } + void AssetImportRequest::GetManifestDependencyPaths(AZStd::vector&) + { + } + AZStd::shared_ptr AssetImportRequest::LoadSceneFromVerifiedPath(const AZStd::string& assetFilePath, const Uuid& sourceGuid, - RequestingApplication requester, const Uuid& loadingComponentUuid) + RequestingApplication requester, const Uuid& loadingComponentUuid) { AZStd::string sceneName; AzFramework::StringFunc::Path::GetFileName(assetFilePath.c_str(), sceneName); AZStd::shared_ptr scene = AZStd::make_shared(AZStd::move(sceneName)); AZ_Assert(scene, "Unable to create new scene for asset importing."); + Data::AssetInfo assetInfo; + AZStd::string watchFolder; + bool result = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, sourceGuid, assetInfo, watchFolder); + + if (result) + { + scene->SetWatchFolder(watchFolder); + } + else + { + AZ_Error( + "AssetImportRequest", false, "Failed to get watch folder for source %s", + sourceGuid.ToString().c_str()); + } + // Unique pointer, will deactivate and clean up once going out of scope. SceneCore::EntityConstructor::EntityPointer loaders = SceneCore::EntityConstructor::BuildEntity("Scene Loading", loadingComponentUuid); diff --git a/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.h b/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.h index 8b6e119f99..a2446c5ff8 100644 --- a/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.h +++ b/Code/Tools/SceneAPI/SceneCore/Events/AssetImportRequest.h @@ -78,6 +78,8 @@ namespace AZ virtual void GetSupportedFileExtensions(AZStd::unordered_set& extensions); //! Gets the file extension for the manifest. virtual void GetManifestExtension(AZStd::string& result); + //! Gets the file extension for the generated manifest. + virtual void GetGeneratedManifestExtension(AZStd::string& result); //! Before asset loading starts this is called to allow for any required initialization. virtual ProcessingResult PrepareForAssetLoading(Containers::Scene& scene, RequestingApplication requester); @@ -97,6 +99,23 @@ namespace AZ // Get scene processing project setting: UseCustomNormal virtual void AreCustomNormalsUsed(bool & value); + /*! + Optional method for reporting source file dependencies that may exist in the scene manifest + Paths is a vector of JSON Path strings, relative to the IRule object + For example, the following path: /scriptFilename + Would match with this manifest: + + { + "values": [ + { + "$type": "Test", + "scriptFilename": "file.py" + } + ] + } + */ + virtual void GetManifestDependencyPaths(AZStd::vector& paths); + //! Utility function to load an asset and manifest from file by using the EBus functions above. //! @param assetFilePath The absolute path to the source file (not the manifest). //! @param sourceGuid The guid assigned to the source file (not the manifest). diff --git a/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp b/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp index 39045da5b9..f7d3f073b9 100644 --- a/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.cpp @@ -56,8 +56,14 @@ namespace AZ result = s_extension; } + void ManifestImportRequestHandler::GetGeneratedManifestExtension(AZStd::string& result) + { + result = s_extension; + result.append(s_generated); + } + Events::LoadingResult ManifestImportRequestHandler::LoadAsset(Containers::Scene& scene, const AZStd::string& path, - const Uuid& /*guid*/, RequestingApplication /*requester*/) + const Uuid& /*guid*/, RequestingApplication /*requester*/) { AZStd::string manifestPath = path + s_extension; diff --git a/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h b/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h index 7659f6908f..00c802cb6b 100644 --- a/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h +++ b/Code/Tools/SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h @@ -31,6 +31,7 @@ namespace AZ static void Reflect(ReflectContext* context); void GetManifestExtension(AZStd::string& result) override; + void GetGeneratedManifestExtension(AZStd::string& result) override; Events::LoadingResult LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid, RequestingApplication requester) override; diff --git a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp index 2e6503d195..8d413b6038 100644 --- a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp +++ b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -99,6 +102,7 @@ namespace AZ::SceneAPI::Behaviors { AZStd::string result; CallResult(result, FN_OnUpdateManifest, scene); + ScriptBuildingNotificationBusHandler::BusDisconnect(); return result; } @@ -110,6 +114,7 @@ namespace AZ::SceneAPI::Behaviors { ExportProductList result; CallResult(result, FN_OnPrepareForExport, scene, outputDirectory, platformIdentifier, productList); + ScriptBuildingNotificationBusHandler::BusDisconnect(); return result; } @@ -168,21 +173,9 @@ namespace AZ::SceneAPI::Behaviors UnloadPython(); } - bool ScriptProcessorRuleBehavior::LoadPython(const AZ::SceneAPI::Containers::Scene& scene) + bool ScriptProcessorRuleBehavior::LoadPython(const AZ::SceneAPI::Containers::Scene& scene, AZStd::string& scriptPath) { - if (m_editorPythonEventsInterface && !m_scriptFilename.empty()) - { - return true; - } - - // get project folder - auto settingsRegistry = AZ::SettingsRegistry::Get(); - AZ::IO::FixedMaxPath projectPath; - if (!settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) - { - return false; - } - + int scriptDiscoveryAttempts = 0; const AZ::SceneAPI::Containers::SceneManifest& manifest = scene.GetManifest(); auto view = Containers::MakeDerivedFilterView(manifest.GetValueStorage()); for (const auto& scriptItem : view) @@ -194,9 +187,21 @@ namespace AZ::SceneAPI::Behaviors continue; } + ++scriptDiscoveryAttempts; + // check for file exist via absolute path if (!IO::FileIOBase::GetInstance()->Exists(scriptFilename.c_str())) { + // get project folder + auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ::IO::FixedMaxPath projectPath; + if (!settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) + { + AZ_Error("scene", false, "With (%s) could not find Project Path during script discovery.", + scene.GetManifestFilename().c_str()); + return false; + } + // check for script in the project folder AZ::IO::FixedMaxPath projectScriptPath = projectPath / scriptFilename; if (!IO::FileIOBase::GetInstance()->Exists(projectScriptPath.c_str())) @@ -209,32 +214,47 @@ namespace AZ::SceneAPI::Behaviors scriptFilename = AZStd::move(projectScriptPath); } - // lazy load the Python interface - auto editorPythonEventsInterface = AZ::Interface::Get(); - if (editorPythonEventsInterface->IsPythonActive() == false) - { - const bool silenceWarnings = false; - if (editorPythonEventsInterface->StartPython(silenceWarnings) == false) - { - editorPythonEventsInterface = nullptr; - } - } + scriptPath = scriptFilename.c_str(); + break; + } - // both Python and the script need to be ready - if (editorPythonEventsInterface == nullptr || scriptFilename.empty()) - { - AZ_Warning("scene", false,"The scene manifest (%s) attempted to use script(%s) but Python is not enabled;" - "please add the EditorPythonBinding gem & PythonAssetBuilder gem to your project.", - scene.GetManifestFilename().c_str(), scriptFilename.c_str()); + if (scriptPath.empty()) + { + AZ_Warning("scene", scriptDiscoveryAttempts == 0, + "The scene manifest (%s) attempted to use script rule, but no script file path could be found.", + scene.GetManifestFilename().c_str()); + return false; + } + + // already prepared the Python VM? + if (m_editorPythonEventsInterface) + { + return true; + } - return false; + // lazy load the Python interface + auto editorPythonEventsInterface = AZ::Interface::Get(); + if (editorPythonEventsInterface->IsPythonActive() == false) + { + const bool silenceWarnings = false; + if (editorPythonEventsInterface->StartPython(silenceWarnings) == false) + { + editorPythonEventsInterface = nullptr; } + } - m_editorPythonEventsInterface = editorPythonEventsInterface; - m_scriptFilename = scriptFilename.c_str(); - return true; + // both Python and the script need to be ready + if (editorPythonEventsInterface == nullptr) + { + AZ_Warning("scene", false, + "The scene manifest (%s) attempted to prepare Python but Python can not start", + scene.GetManifestFilename().c_str()); + + return false; } - return false; + + m_editorPythonEventsInterface = editorPythonEventsInterface; + return true; } void ScriptProcessorRuleBehavior::UnloadPython() @@ -251,11 +271,13 @@ namespace AZ::SceneAPI::Behaviors { using namespace AzToolsFramework; - auto executeCallback = [this, &context]() + AZStd::string scriptPath; + + auto executeCallback = [&context, &scriptPath]() { // set up script's hook callback EditorPythonRunnerRequestBus::Broadcast(&EditorPythonRunnerRequestBus::Events::ExecuteByFilename, - m_scriptFilename.c_str()); + scriptPath.c_str()); // call script's callback to allow extra products ExportProductList extraProducts; @@ -279,7 +301,7 @@ namespace AZ::SceneAPI::Behaviors } }; - if (LoadPython(context.GetScene())) + if (LoadPython(context.GetScene(), scriptPath)) { EditorPythonConsoleNotificationHandler logger; m_editorPythonEventsInterface->ExecuteWithLock(executeCallback); @@ -306,23 +328,19 @@ namespace AZ::SceneAPI::Behaviors { using namespace AzToolsFramework; - // This behavior persists on the same AssetBuilder. Clear the script file name so that if - // this builder processes a scene file with a script file name, and then later processes - // a scene without a script file name, it won't run the old script on the new scene. - m_scriptFilename.clear(); - if (action != ManifestAction::Update) { return Events::ProcessingResult::Ignored; } - if (LoadPython(scene)) + AZStd::string scriptPath; + if (LoadPython(scene, scriptPath)) { AZStd::string manifestUpdate; - auto executeCallback = [this, &scene, &manifestUpdate]() + auto executeCallback = [&scene, &manifestUpdate, &scriptPath]() { EditorPythonRunnerRequestBus::Broadcast(&EditorPythonRunnerRequestBus::Events::ExecuteByFilename, - m_scriptFilename.c_str()); + scriptPath.c_str()); ScriptBuildingNotificationBus::BroadcastResult(manifestUpdate, &ScriptBuildingNotificationBus::Events::OnUpdateManifest, scene); @@ -331,6 +349,9 @@ namespace AZ::SceneAPI::Behaviors EditorPythonConsoleNotificationHandler logger; m_editorPythonEventsInterface->ExecuteWithLock(executeCallback); + EntityUtilityBus::Broadcast(&EntityUtilityBus::Events::ResetEntityContext); + AZ::Interface::Get()->RemoveAllTemplates(); + // attempt to load the manifest string back to a JSON-scene-manifest auto sceneManifestLoader = AZStd::make_unique(); auto loadOutcome = sceneManifestLoader->LoadFromString(manifestUpdate); @@ -347,4 +368,8 @@ namespace AZ::SceneAPI::Behaviors return Events::ProcessingResult::Ignored; } + void ScriptProcessorRuleBehavior::GetManifestDependencyPaths(AZStd::vector& paths) + { + paths.emplace_back("/scriptFilename"); + } } // namespace AZ diff --git a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.h b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.h index fa70a12b0d..a9ddf88df9 100644 --- a/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.h +++ b/Code/Tools/SceneAPI/SceneData/Behaviors/ScriptProcessorRuleBehavior.h @@ -37,6 +37,7 @@ namespace AZ::SceneAPI::Behaviors , public Events::AssetImportRequestBus::Handler { public: + AZ_COMPONENT(ScriptProcessorRuleBehavior, "{24054E73-1B92-43B0-AC13-174B2F0E3F66}", SceneCore::BehaviorComponent); ~ScriptProcessorRuleBehavior() override = default; @@ -44,22 +45,21 @@ namespace AZ::SceneAPI::Behaviors SCENE_DATA_API void Activate() override; SCENE_DATA_API void Deactivate() override; static void Reflect(ReflectContext* context); - + // AssetImportRequestBus::Handler SCENE_DATA_API Events::ProcessingResult UpdateManifest( Containers::Scene& scene, ManifestAction action, RequestingApplication requester) override; - + SCENE_DATA_API void GetManifestDependencyPaths(AZStd::vector& paths) override; protected: - bool LoadPython(const AZ::SceneAPI::Containers::Scene& scene); + bool LoadPython(const AZ::SceneAPI::Containers::Scene& scene, AZStd::string& scriptPath); void UnloadPython(); bool DoPrepareForExport(Events::PreExportEventContext& context); private: AzToolsFramework::EditorPythonEventsInterface* m_editorPythonEventsInterface = nullptr; - AZStd::string m_scriptFilename; struct ExportEventHandler; AZStd::shared_ptr m_exportEventHandler; diff --git a/Gems/Prefab/PrefabBuilder/CMakeLists.txt b/Gems/Prefab/PrefabBuilder/CMakeLists.txt index 450b8d0408..9aedbd3d99 100644 --- a/Gems/Prefab/PrefabBuilder/CMakeLists.txt +++ b/Gems/Prefab/PrefabBuilder/CMakeLists.txt @@ -13,6 +13,9 @@ endif() ly_add_target( NAME PrefabBuilder.Static STATIC NAMESPACE Gem + INCLUDE_DIRECTORIES + PRIVATE + . FILES_CMAKE prefabbuilder_files.cmake BUILD_DEPENDENCIES @@ -20,6 +23,9 @@ ly_add_target( AZ::AzCore AZ::AzToolsFramework AZ::AssetBuilderSDK + AZ::SceneCore + AZ::SceneData + 3rdParty::RapidJSON ) ly_add_target( @@ -35,7 +41,8 @@ ly_add_target( Gem::PrefabBuilder.Static ) -# the prefab builder only needs to be active in builders +# create an alias for the tool version +ly_create_alias(NAME PrefabBuilder.Tools NAMESPACE Gem TARGETS Gem::PrefabBuilder.Builders) # we automatically add this gem, if it is present, to all our known set of builder applications: ly_enable_gems(GEMS PrefabBuilder) diff --git a/Gems/Prefab/PrefabBuilder/PrefabBuilderModule.cpp b/Gems/Prefab/PrefabBuilder/PrefabBuilderModule.cpp index 762f459d9d..2bf7026549 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabBuilderModule.cpp +++ b/Gems/Prefab/PrefabBuilder/PrefabBuilderModule.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace AZ::Prefab { @@ -22,7 +23,8 @@ namespace AZ::Prefab : Module() { m_descriptors.insert(m_descriptors.end(), { - PrefabBuilderComponent::CreateDescriptor() + PrefabBuilderComponent::CreateDescriptor(), + AZ::SceneAPI::Behaviors::PrefabGroupBehavior::CreateDescriptor() }); } }; diff --git a/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.h b/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.h index 3aea173ba4..2aec317e69 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.h +++ b/Gems/Prefab/PrefabBuilder/PrefabBuilderTests.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace UnitTest { diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/IPrefabGroup.h b/Gems/Prefab/PrefabBuilder/PrefabGroup/IPrefabGroup.h new file mode 100644 index 0000000000..c2f8313b95 --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/IPrefabGroup.h @@ -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 + * + */ +#pragma once + +#include +#include +#include + +namespace AZ::SceneAPI::DataTypes +{ + class IPrefabGroup + : public ISceneNodeGroup + { + public: + AZ_RTTI(IPrefabGroup, "{7E50FAEF-3379-4521-99C5-B428FDEE3B7B}", ISceneNodeGroup); + + ~IPrefabGroup() override = default; + virtual AzToolsFramework::Prefab::PrefabDomConstReference GetPrefabDomRef() const = 0; + }; +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.cpp new file mode 100644 index 0000000000..856aba979b --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace UnitTest +{ + class PrefabBehaviorTests + : public PrefabBuilderTests + { + public: + static void SetUpTestCase() + { + // Allocator needed by SceneCore + if (!AZ::AllocatorInstance().IsReady()) + { + AZ::AllocatorInstance().Create(); + } + AZ::SceneAPI::SceneCoreStandaloneAllocator::Initialize(AZ::Environment::GetInstance()); + } + + static void TearDownTestCase() + { + AZ::SceneAPI::SceneCoreStandaloneAllocator::TearDown(); + AZ::AllocatorInstance().Destroy(); + } + + void SetUp() override + { + PrefabBuilderTests::SetUp(); + m_prefabGroupBehavior = AZStd::make_unique(); + m_prefabGroupBehavior->Activate(); + + // Mocking the asset system replacing the AssetSystem::AssetSystemComponent + AZ::Entity* systemEntity = m_app.FindEntity(AZ::SystemEntityId); + systemEntity->FindComponent()->Deactivate(); + using namespace testing; + ON_CALL(m_assetSystemRequestMock, GetSourceInfoBySourcePath(_, _, _)).WillByDefault([](auto* path, auto& info, auto&) + { + return PrefabBehaviorTests::OnGetSourceInfoBySourcePath(path, info); + }); + m_assetSystemRequestMock.BusConnect(); + } + + void TearDown() override + { + m_assetSystemRequestMock.BusDisconnect(); + + m_prefabGroupBehavior->Deactivate(); + m_prefabGroupBehavior.reset(); + + PrefabBuilderTests::TearDown(); + } + + static bool OnGetSourceInfoBySourcePath(AZStd::string_view sourcePath, AZ::Data::AssetInfo& assetInfo) + { + if (sourcePath == AZStd::string_view("mock")) + { + assetInfo.m_assetId = AZ::Uuid::CreateRandom(); + assetInfo.m_assetType = azrtti_typeid(); + assetInfo.m_relativePath = "mock/path"; + assetInfo.m_sizeBytes = 0; + } + return true; + } + + struct TestPreExportEventContext + { + TestPreExportEventContext() + : m_scene("test_context") + { + using namespace AZ::SceneAPI::Events; + m_preExportEventContext = AZStd::make_unique(m_productList, m_outputDirectory, m_scene, "mock"); + } + + void SetOutputDirectory(AZStd::string outputDirectory) + { + using namespace AZ::SceneAPI::Events; + m_outputDirectory = AZStd::move(outputDirectory); + m_preExportEventContext = AZStd::make_unique(m_productList, m_outputDirectory, m_scene, "mock"); + } + + AZStd::unique_ptr m_preExportEventContext; + AZ::SceneAPI::Events::ExportProductList m_productList; + AZStd::string m_outputDirectory; + AZ::SceneAPI::Containers::Scene m_scene; + }; + + AZStd::unique_ptr m_prefabGroupBehavior; + testing::NiceMock m_assetSystemRequestMock; + }; + + TEST_F(PrefabBehaviorTests, PrefabBehavior_EmptyContextIgnored_Works) + { + auto context = TestPreExportEventContext{}; + + auto result = AZ::SceneAPI::Events::ProcessingResult::Failure; + AZ::SceneAPI::Events::CallProcessorBus::BroadcastResult( + result, + &AZ::SceneAPI::Events::CallProcessorBus::Events::Process, + context.m_preExportEventContext.get()); + + EXPECT_EQ(result, AZ::SceneAPI::Events::ProcessingResult::Ignored); + } + + TEST_F(PrefabBehaviorTests, PrefabBehavior_SimplePrefab_Works) + { + auto context = TestPreExportEventContext{}; + + // check for the file at /mock/fake_prefab.procprefab + AZ::Test::ScopedAutoTempDirectory tempDir; + context.SetOutputDirectory(tempDir.GetDirectory()); + + auto jsonOutcome = AZ::JsonSerializationUtils::ReadJsonString(Data::jsonPrefab); + ASSERT_TRUE(jsonOutcome); + + auto prefabGroup = AZStd::make_shared(); + prefabGroup.get()->SetId(AZ::Uuid::CreateRandom()); + prefabGroup.get()->SetName("fake_prefab"); + prefabGroup.get()->SetPrefabDom(AZStd::move(jsonOutcome.GetValue())); + context.m_scene.GetManifest().AddEntry(prefabGroup); + context.m_scene.SetSource("mock", AZ::Uuid::CreateRandom()); + + auto result = AZ::SceneAPI::Events::ProcessingResult::Failure; + AZ::SceneAPI::Events::CallProcessorBus::BroadcastResult( + result, + &AZ::SceneAPI::Events::CallProcessorBus::Events::Process, + context.m_preExportEventContext.get()); + + EXPECT_EQ(result, AZ::SceneAPI::Events::ProcessingResult::Success); + + AZStd::string pathStr; + AzFramework::StringFunc::Path::ConstructFull(tempDir.GetDirectory(), "mock/fake_prefab.procprefab", pathStr, true); + if (!AZ::IO::SystemFile::Exists(pathStr.c_str())) + { + AZ_Warning("testing", false, "The product asset (%s) is missing", pathStr.c_str()); + } + } +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.inl b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.inl new file mode 100644 index 0000000000..b39f782a1e --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabBehaviorTests.inl @@ -0,0 +1,104 @@ +/* + * 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 + * + */ + +namespace UnitTest +{ + namespace Data + { + const char* jsonPrefab = R"JSON( + { + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "test_template_1", + "Components": { + "Component_[12122553907433030840]": { + "$type": "EditorVisibilityComponent", + "Id": 12122553907433030840 + }, + "Component_[5666150279650800686]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 5666150279650800686, + "Parent Entity": "" + }, + "Component_[8790726658974076423]": { + "$type": "EditorOnlyEntityComponent", + "Id": 8790726658974076423 + } + } + }, + "Entities": { + "Entity_[1588652751483]": { + "Id": "Entity_[1588652751483]", + "Name": "root", + "Components": { + "Component_[11872748096995986607]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 11872748096995986607, + "Parent Entity": "ContainerEntity", + "Transform Data": { + "Rotate": [ + 0.0, + 0.10000000149011612, + 180.0 + ] + } + }, + "Component_[12138841758570858610]": { + "$type": "EditorVisibilityComponent", + "Id": 12138841758570858610 + }, + "Component_[15735658354806796004]": { + "$type": "EditorOnlyEntityComponent", + "Id": 15735658354806796004 + } + } + }, + "Entity_[1592947718779]": { + "Id": "Entity_[1592947718779]", + "Name": "cube", + "Components": { + "Component_[2505301170249328189]": { + "$type": "EditorOnlyEntityComponent", + "Id": 2505301170249328189 + }, + "Component_[3716170894544198343]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 3716170894544198343, + "Parent Entity": "Entity_[1588652751483]" + }, + "Component_[5862175558847453681]": { + "$type": "EditorVisibilityComponent", + "Id": 5862175558847453681 + } + } + }, + "Entity_[1597242686075]": { + "Id": "Entity_[1597242686075]", + "Name": "cubeKid", + "Components": { + "Component_[10128771992421174485]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 10128771992421174485, + "Parent Entity": "Entity_[1592947718779]" + }, + "Component_[14936165953779771344]": { + "$type": "EditorVisibilityComponent", + "Id": 14936165953779771344 + }, + "Component_[403416213715997356]": { + "$type": "EditorOnlyEntityComponent", + "Id": 403416213715997356 + } + } + } + } + } + )JSON"; + + } +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.cpp new file mode 100644 index 0000000000..f4dd37b86c --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ::SceneAPI::SceneData +{ + // PrefabGroup + + PrefabGroup::PrefabGroup() + : m_id(Uuid::CreateNull()) + , m_name() + { + } + + const AZStd::string& PrefabGroup::GetName() const + { + return m_name; + } + + void PrefabGroup::SetName(AZStd::string name) + { + m_name = AZStd::move(name); + } + + const Uuid& PrefabGroup::GetId() const + { + return m_id; + } + + void PrefabGroup::SetId(Uuid id) + { + m_id = AZStd::move(id); + } + + Containers::RuleContainer& PrefabGroup::GetRuleContainer() + { + return m_rules; + } + + const Containers::RuleContainer& PrefabGroup::GetRuleContainerConst() const + { + return m_rules; + } + + DataTypes::ISceneNodeSelectionList& PrefabGroup::GetSceneNodeSelectionList() + { + return m_nodeSelectionList; + } + + const DataTypes::ISceneNodeSelectionList& PrefabGroup::GetSceneNodeSelectionList() const + { + return m_nodeSelectionList; + } + + void PrefabGroup::SetPrefabDom(AzToolsFramework::Prefab::PrefabDom prefabDom) + { + m_prefabDomData = AZStd::make_shared(); + m_prefabDomData->CopyValue(prefabDom); + } + + AzToolsFramework::Prefab::PrefabDomConstReference PrefabGroup::GetPrefabDomRef() const + { + if (m_prefabDomData) + { + return m_prefabDomData->GetValue(); + } + return {}; + } + + void PrefabGroup::Reflect(ReflectContext* context) + { + SerializeContext* serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Version(1); + + serializeContext->Class() + ->Version(1) + ->Field("name", &PrefabGroup::m_name) + ->Field("nodeSelectionList", &PrefabGroup::m_nodeSelectionList) + ->Field("rules", &PrefabGroup::m_rules) + ->Field("id", &PrefabGroup::m_id) + ->Field("prefabDomData", &PrefabGroup::m_prefabDomData); + } + + BehaviorContext* behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + auto setPrefabDomData = [](PrefabGroup& self, const AZStd::string& json) + { + auto jsonOutcome = JsonSerializationUtils::ReadJsonString(json); + if (jsonOutcome.IsSuccess()) + { + self.SetPrefabDom(AZStd::move(jsonOutcome.GetValue())); + return true; + } + AZ_Error("prefab", false, "Set PrefabDom failed (%s)", jsonOutcome.GetError().c_str()); + return false; + }; + + auto getPrefabDomData = [](const PrefabGroup& self) -> AZStd::string + { + if (self.GetPrefabDomRef().has_value() == false) + { + return {}; + } + AZStd::string buffer; + JsonSerializationUtils::WriteJsonString(self.GetPrefabDomRef().value(), buffer); + return buffer; + }; + + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(Script::Attributes::Scope, Script::Attributes::ScopeFlags::Common) + ->Attribute(Script::Attributes::Module, "prefab") + ->Property("name", BehaviorValueProperty(&PrefabGroup::m_name)) + ->Property("id", BehaviorValueProperty(&PrefabGroup::m_id)) + ->Property("prefabDomData", getPrefabDomData, setPrefabDomData); + } + } +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.h b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.h new file mode 100644 index 0000000000..e5c47186eb --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroup.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + class ReflectContext; +} + +namespace AZ::SceneAPI::Containers +{ + class Scene; +} + +namespace AZ::SceneAPI::SceneData +{ + class PrefabGroup final + : public DataTypes::IPrefabGroup + { + public: + AZ_RTTI(PrefabGroup, "{99FE3C6F-5B55-4D8B-8013-2708010EC715}", DataTypes::IPrefabGroup); + AZ_CLASS_ALLOCATOR(PrefabGroup, SystemAllocator, 0); + + static void Reflect(AZ::ReflectContext* context); + + PrefabGroup(); + ~PrefabGroup() override = default; + + // DataTypes::IPrefabGroup + AzToolsFramework::Prefab::PrefabDomConstReference GetPrefabDomRef() const override; + const AZStd::string& GetName() const override; + const Uuid& GetId() const override; + Containers::RuleContainer& GetRuleContainer() override; + const Containers::RuleContainer& GetRuleContainerConst() const override; + DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList() override; + const DataTypes::ISceneNodeSelectionList& GetSceneNodeSelectionList() const override; + + // Concrete API + void SetId(Uuid id); + void SetName(AZStd::string name); + void SetPrefabDom(AzToolsFramework::Prefab::PrefabDom prefabDom); + + private: + SceneNodeSelectionList m_nodeSelectionList; + Containers::RuleContainer m_rules; + AZStd::string m_name; + Uuid m_id; + AZStd::shared_ptr m_prefabDomData; + }; +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp new file mode 100644 index 0000000000..13828e5f8c --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ::SceneAPI::Behaviors +{ + // + // ExportEventHandler + // + + struct PrefabGroupBehavior::ExportEventHandler final + : public AZ::SceneAPI::SceneCore::ExportingComponent + { + using PreExportEventContextFunction = AZStd::function; + PreExportEventContextFunction m_preExportEventContextFunction; + AZ::Prefab::PrefabGroupAssetHandler m_prefabGroupAssetHandler; + + ExportEventHandler() = delete; + + ExportEventHandler(PreExportEventContextFunction function) + : m_preExportEventContextFunction(AZStd::move(function)) + { + BindToCall(&ExportEventHandler::PrepareForExport); + AZ::SceneAPI::SceneCore::ExportingComponent::Activate(); + } + + ~ExportEventHandler() + { + AZ::SceneAPI::SceneCore::ExportingComponent::Deactivate(); + } + + Events::ProcessingResult PrepareForExport(Events::PreExportEventContext& context) + { + return m_preExportEventContextFunction(context); + } + }; + + // + // PrefabGroupBehavior + // + + void PrefabGroupBehavior::Activate() + { + m_exportEventHandler = AZStd::make_shared([this](auto& context) + { + return this->OnPrepareForExport(context); + }); + } + + void PrefabGroupBehavior::Deactivate() + { + m_exportEventHandler.reset(); + } + + AZStd::unique_ptr PrefabGroupBehavior::CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup) const + { + using namespace AzToolsFramework::Prefab; + + auto* prefabLoaderInterface = AZ::Interface::Get(); + if (!prefabLoaderInterface) + { + AZ_Error("prefab", false, "Could not get PrefabLoaderInterface"); + return {}; + } + + // write to a UTF-8 string buffer + auto prefabDomRef = prefabGroup->GetPrefabDomRef(); + if (!prefabDomRef) + { + AZ_Error("prefab", false, "PrefabGroup(%s) missing PrefabDom", prefabGroup->GetName().c_str()); + return {}; + } + + const AzToolsFramework::Prefab::PrefabDom& prefabDom = prefabDomRef.value(); + rapidjson::StringBuffer sb; + rapidjson::Writer> writer(sb); + if (prefabDom.Accept(writer) == false) + { + AZ_Error("prefab", false, "Could not write PrefabGroup(%s) to JSON", prefabGroup->GetName().c_str()); + return {}; + } + + // validate the PrefabDom will make a valid Prefab template instance + auto templateId = prefabLoaderInterface->LoadTemplateFromString(sb.GetString(), prefabGroup->GetName().c_str()); + if (templateId == InvalidTemplateId) + { + AZ_Error("prefab", false, "PrefabGroup(%s) Could not write load template", prefabGroup->GetName().c_str()); + return {}; + } + + auto* prefabSystemComponentInterface = AZ::Interface::Get(); + if (!prefabSystemComponentInterface) + { + AZ_Error("prefab", false, "Could not get PrefabSystemComponentInterface"); + return {}; + } + + // create instance to update the asset hints + auto instance = prefabSystemComponentInterface->InstantiatePrefab(templateId); + if (!instance) + { + AZ_Error("prefab", false, "PrefabGroup(%s) Could not instantiate prefab", prefabGroup->GetName().c_str()); + return {}; + } + + auto* instanceToTemplateInterface = AZ::Interface::Get(); + if (!instanceToTemplateInterface) + { + AZ_Error("prefab", false, "Could not get InstanceToTemplateInterface"); + return {}; + } + + // fill out a JSON DOM + auto proceduralPrefab = AZStd::make_unique(rapidjson::kObjectType); + instanceToTemplateInterface->GenerateDomForInstance(*proceduralPrefab.get(), *instance.get()); + return proceduralPrefab; + } + + bool PrefabGroupBehavior::WriteOutProductAsset( + Events::PreExportEventContext& context, + const SceneData::PrefabGroup* prefabGroup, + const rapidjson::Document& doc) const + { + // Retrieve source asset info so we can get a string with the relative path to the asset + bool assetInfoResult; + Data::AssetInfo info; + AZStd::string watchFolder; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + assetInfoResult, + &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + context.GetScene().GetSourceFilename().c_str(), + info, + watchFolder); + + AZ::IO::FixedMaxPath assetPath(info.m_relativePath); + assetPath.ReplaceFilename(prefabGroup->GetName().c_str()); + + AZStd::string filePath = AZ::SceneAPI::Utilities::FileUtilities::CreateOutputFileName( + assetPath.c_str(), + context.GetOutputDirectory(), + AZ::Prefab::PrefabGroupAssetHandler::s_Extension); + + AZ::IO::FileIOStream fileStream(filePath.c_str(), AZ::IO::OpenMode::ModeWrite); + if (fileStream.IsOpen() == false) + { + AZ_Error("prefab", false, "File path(%s) could not open for write", filePath.c_str()); + return false; + } + + // write to a UTF-8 string buffer + rapidjson::StringBuffer sb; + rapidjson::Writer> writer(sb); + if (doc.Accept(writer) == false) + { + AZ_Error("prefab", false, "PrefabGroup(%s) Could not buffer JSON", prefabGroup->GetName().c_str()); + return false; + } + + const auto bytesWritten = fileStream.Write(sb.GetSize(), sb.GetString()); + if (bytesWritten > 1) + { + AZ::u32 subId = AZ::Crc32(filePath.c_str()); + context.GetProductList().AddProduct( + filePath, + context.GetScene().GetSourceGuid(), + azrtti_typeid(), + {}, + AZStd::make_optional(subId)); + + return true; + } + return false; + } + + Events::ProcessingResult PrefabGroupBehavior::OnPrepareForExport(Events::PreExportEventContext& context) const + { + AZStd::vector prefabGroupCollection; + const Containers::SceneManifest& manifest = context.GetScene().GetManifest(); + + for (size_t i = 0; i < manifest.GetEntryCount(); ++i) + { + const auto* group = azrtti_cast(manifest.GetValue(i).get()); + if (group) + { + prefabGroupCollection.push_back(group); + } + } + + if (prefabGroupCollection.empty()) + { + return AZ::SceneAPI::Events::ProcessingResult::Ignored; + } + + for (const auto* prefabGroup : prefabGroupCollection) + { + auto result = CreateProductAssetData(prefabGroup); + if (!result) + { + return Events::ProcessingResult::Failure; + } + + if (WriteOutProductAsset(context, prefabGroup, *result.get()) == false) + { + return Events::ProcessingResult::Failure; + } + } + + return Events::ProcessingResult::Success; + } + + void PrefabGroupBehavior::Reflect(ReflectContext* context) + { + AZ::SceneAPI::SceneData::PrefabGroup::Reflect(context); + Prefab::ProceduralPrefabAsset::Reflect(context); + + SerializeContext* serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class()->Version(1); + } + } +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h new file mode 100644 index 0000000000..b57d30695a --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + class ReflectContext; +} + +namespace AZ::SceneAPI::Events +{ + class PreExportEventContext; +} + +namespace AZ::SceneAPI::Behaviors +{ + class PrefabGroupBehavior + : public SceneCore::BehaviorComponent + { + public: + AZ_COMPONENT(PrefabGroupBehavior, "{13DC2819-CAC2-4977-91D7-C870087072AB}", SceneCore::BehaviorComponent); + + ~PrefabGroupBehavior() override = default; + + void Activate() override; + void Deactivate() override; + static void Reflect(ReflectContext* context); + + private: + Events::ProcessingResult OnPrepareForExport(Events::PreExportEventContext& context) const; + AZStd::unique_ptr CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup) const; + + bool WriteOutProductAsset( + Events::PreExportEventContext& context, + const SceneData::PrefabGroup* prefabGroup, + const rapidjson::Document& doc) const; + + struct ExportEventHandler; + AZStd::shared_ptr m_exportEventHandler; + }; +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp new file mode 100644 index 0000000000..9fb935ce9f --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupTests.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include + +namespace UnitTest +{ + TEST_F(PrefabBuilderTests, PrefabGroup_FindsRequiredReflection_True) + { + using namespace AZ::SceneAPI; + auto* serializeContext = m_app.GetSerializeContext(); + ASSERT_NE(nullptr, serializeContext); + SceneData::PrefabGroup::Reflect(serializeContext); + SceneData::PrefabGroup::Reflect(m_app.GetJsonRegistrationContext()); + ASSERT_NE(nullptr, serializeContext->FindClassData(azrtti_typeid())); + ASSERT_NE(nullptr, serializeContext->FindClassData(azrtti_typeid())); + + auto findElementWithName = [](const AZ::SerializeContext::ClassData* classData, const char* name) + { + auto it = AZStd::find_if(classData->m_elements.begin(), classData->m_elements.end(), [name](const auto& element) + { + return strcmp(element.m_name, name) == 0; + }); + return it != classData->m_elements.end(); + }; + + auto* prefabGroupClassData = serializeContext->FindClassData(azrtti_typeid()); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "name")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "nodeSelectionList")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "rules")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "id")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "prefabDomData")); + + m_app.GetJsonRegistrationContext()->EnableRemoveReflection(); + SceneData::PrefabGroup::Reflect(m_app.GetJsonRegistrationContext()); + } + + TEST_F(PrefabBuilderTests, PrefabGroup_JsonWithPrefabArbitraryPrefab_Works) + { + namespace JSR = AZ::JsonSerializationResult; + using namespace AZ::SceneAPI; + auto* serializeContext = m_app.GetSerializeContext(); + ASSERT_NE(nullptr, serializeContext); + SceneData::PrefabGroup::Reflect(serializeContext); + AZ::Prefab::ProceduralPrefabAsset::Reflect(serializeContext); + SceneData::PrefabGroup::Reflect(m_app.GetJsonRegistrationContext()); + AZ::Prefab::ProceduralPrefabAsset::Reflect(m_app.GetJsonRegistrationContext()); + + // fill out a PrefabGroup using JSON + AZStd::string_view input = R"JSON( + { + "name" : "tester", + "id" : "{49698DBC-B447-49EF-9B56-25BB29342AFB}", + "prefabDomData" : {"foo": "bar"} + })JSON"; + + rapidjson::Document document; + document.Parse(input.data(), input.size()); + ASSERT_FALSE(document.HasParseError()); + + SceneData::PrefabGroup instancePrefabGroup; + EXPECT_EQ(AZ::JsonSerialization::Load(instancePrefabGroup, document).GetOutcome(), JSR::Outcomes::PartialDefaults); + + ASSERT_TRUE(instancePrefabGroup.GetPrefabDomRef().has_value()); + const AzToolsFramework::Prefab::PrefabDom& dom = instancePrefabGroup.GetPrefabDomRef().value(); + EXPECT_TRUE(dom.IsObject()); + EXPECT_TRUE(dom.GetObject().HasMember("foo")); + EXPECT_STREQ(dom.GetObject().FindMember("foo")->value.GetString(), "bar"); + EXPECT_STREQ(instancePrefabGroup.GetName().c_str(), "tester"); + EXPECT_STREQ(instancePrefabGroup.GetId().ToString().c_str(), "{49698DBC-B447-49EF-9B56-25BB29342AFB}"); + + m_app.GetJsonRegistrationContext()->EnableRemoveReflection(); + SceneData::PrefabGroup::Reflect(m_app.GetJsonRegistrationContext()); + AZ::Prefab::ProceduralPrefabAsset::Reflect(m_app.GetJsonRegistrationContext()); + } + + TEST_F(PrefabBuilderTests, PrefabGroup_InvalidPrefabJson_Detected) + { + using namespace AZ::SceneAPI; + + AZStd::string_view input = R"JSON( + { + bad json that will not parse + })JSON"; + + rapidjson::Document document; + document.Parse(input.data(), input.size()); + + SceneData::PrefabGroup prefabGroup; + prefabGroup.SetId(AZ::Uuid::CreateRandom()); + prefabGroup.SetName("tester"); + prefabGroup.SetPrefabDom(AZStd::move(document)); + + const AzToolsFramework::Prefab::PrefabDom& dom = prefabGroup.GetPrefabDomRef().value(); + EXPECT_TRUE(dom.IsNull()); + EXPECT_STREQ("tester", prefabGroup.GetName().c_str()); + } + + struct PrefabBuilderBehaviorTests + : public PrefabBuilderTests + { + void SetUp() override + { + using namespace AZ::SceneAPI; + + PrefabBuilderTests::SetUp(); + SceneData::PrefabGroup::Reflect(m_app.GetSerializeContext()); + SceneData::PrefabGroup::Reflect(m_app.GetBehaviorContext()); + SceneData::PrefabGroup::Reflect(m_app.GetJsonRegistrationContext()); + m_scriptContext = AZStd::make_unique(); + m_scriptContext->BindTo(m_app.GetBehaviorContext()); + } + + void TearDown() override + { + using namespace AZ::SceneAPI; + m_app.GetJsonRegistrationContext()->EnableRemoveReflection(); + SceneData::PrefabGroup::Reflect(m_app.GetJsonRegistrationContext()); + + m_scriptContext.reset(); + PrefabBuilderTests::TearDown(); + } + + void ExpectExecute(AZStd::string_view script) + { + EXPECT_TRUE(m_scriptContext->Execute(script.data())); + } + + AZStd::unique_ptr m_scriptContext; + }; + + TEST_F(PrefabBuilderBehaviorTests, PrefabGroup_PrefabGroupClass_Exists) + { + ExpectExecute("group = PrefabGroup()"); + ExpectExecute("assert(group)"); + ExpectExecute("assert(group.name)"); + ExpectExecute("assert(group.id)"); + ExpectExecute("assert(group.prefabDomData)"); + } + + TEST_F(PrefabBuilderBehaviorTests, PrefabGroup_PrefabGroupAssignment_Works) + { + ExpectExecute("group = PrefabGroup()"); + ExpectExecute("group.name = 'tester'"); + ExpectExecute("group.id = Uuid.CreateString('{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}', 0)"); + ExpectExecute("group.prefabDomData = '{\"foo\": \"bar\"}'"); + ExpectExecute("assert(group.name == 'tester')"); + ExpectExecute("assert(tostring(group.id) == '{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}')"); + ExpectExecute("assert(group.prefabDomData == '{\\n \"foo\": \"bar\"\\n}')"); + } +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp new file mode 100644 index 0000000000..17ed4d9c0c --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ::Prefab +{ + // AssetTypeInfoHandler + + class PrefabGroupAssetHandler::AssetTypeInfoHandler final + : public AZ::AssetTypeInfoBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(AssetTypeInfoHandler, AZ::SystemAllocator, 0); + AssetTypeInfoHandler(); + ~AssetTypeInfoHandler() override; + AZ::Data::AssetType GetAssetType() const override; + const char* GetAssetTypeDisplayName() const override; + const char* GetGroup() const override; + const char* GetBrowserIcon() const override; + void GetAssetTypeExtensions(AZStd::vector& extensions) override; + }; + + PrefabGroupAssetHandler::AssetTypeInfoHandler::AssetTypeInfoHandler() + { + AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid()); + } + + PrefabGroupAssetHandler::AssetTypeInfoHandler::~AssetTypeInfoHandler() + { + AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid()); + } + + AZ::Data::AssetType PrefabGroupAssetHandler::AssetTypeInfoHandler::GetAssetType() const + { + return azrtti_typeid(); + } + + const char* PrefabGroupAssetHandler::AssetTypeInfoHandler::GetAssetTypeDisplayName() const + { + return "Procedural Prefab"; + } + + const char* PrefabGroupAssetHandler::AssetTypeInfoHandler::GetGroup() const + { + return "Prefab"; + } + + const char* PrefabGroupAssetHandler::AssetTypeInfoHandler::GetBrowserIcon() const + { + return "Icons/Components/Box.png"; + } + + void PrefabGroupAssetHandler::AssetTypeInfoHandler::GetAssetTypeExtensions(AZStd::vector& extensions) + { + extensions.push_back(PrefabGroupAssetHandler::s_Extension); + } + + // PrefabGroupAssetHandler + + AZStd::string_view PrefabGroupAssetHandler::s_Extension{ "procprefab" }; + + PrefabGroupAssetHandler::PrefabGroupAssetHandler() + { + auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); + if (assetCatalog) + { + assetCatalog->EnableCatalogForAsset(azrtti_typeid()); + assetCatalog->AddExtension(s_Extension.data()); + } + if (AZ::Data::AssetManager::IsReady()) + { + AZ::Data::AssetManager::Instance().RegisterHandler(this, azrtti_typeid()); + } + m_assetTypeInfoHandler = AZStd::make_shared(); + } + + PrefabGroupAssetHandler::~PrefabGroupAssetHandler() + { + m_assetTypeInfoHandler.reset(); + if (AZ::Data::AssetManager::IsReady()) + { + AZ::Data::AssetManager::Instance().UnregisterHandler(this); + } + } + + AZ::Data::AssetData* PrefabGroupAssetHandler::CreateAsset([[maybe_unused]] const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) + { + if (type != azrtti_typeid()) + { + AZ_Error("prefab", false, "Invalid asset type! Only handle 'ProceduralPrefabAsset'"); + return nullptr; + } + return aznew ProceduralPrefabAsset{}; + } + + void PrefabGroupAssetHandler::DestroyAsset(AZ::Data::AssetData* ptr) + { + // Note: the PrefabLoaderInterface will handle the lifetime of the Prefab Template + delete ptr; + } + + void PrefabGroupAssetHandler::GetHandledAssetTypes(AZStd::vector& assetTypes) + { + assetTypes.push_back(azrtti_typeid()); + } + + AZ::Data::AssetHandler::LoadResult PrefabGroupAssetHandler::LoadAssetData( + const AZ::Data::Asset& asset, + AZStd::shared_ptr stream, + [[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) + { + using namespace AzToolsFramework::Prefab; + + auto* proceduralPrefabAsset = asset.GetAs(); + if (!proceduralPrefabAsset) + { + AZ_Error("prefab", false, "This should be a ProceduralPrefabAsset type, as this is the only type we process!"); + return LoadResult::Error; + } + + AZStd::string buffer; + buffer.resize(stream->GetLoadedSize()); + stream->Read(stream->GetLoadedSize(), buffer.data()); + + auto jsonOutcome = AZ::JsonSerializationUtils::ReadJsonString(buffer); + if (jsonOutcome.IsSuccess() == false) + { + AZ_Error("prefab", false, "Asset JSON failed to compile %s", jsonOutcome.GetError().c_str()); + return LoadResult::Error; + } + const auto& jsonDoc = jsonOutcome.GetValue(); + + if (jsonDoc.IsObject() == false) + { + return LoadResult::Error; + } + + if (jsonDoc.FindMember("Source") == jsonDoc.MemberEnd()) + { + return LoadResult::Error; + } + const auto& templateName = jsonDoc["Source"]; + + AZStd::string stringJson; + auto stringOutcome = AZ::JsonSerializationUtils::WriteJsonString(jsonDoc, stringJson); + if (stringOutcome.IsSuccess() == false) + { + AZ_Error("prefab", false, "Could not write to JSON string %s", stringOutcome.GetError().c_str()); + return LoadResult::Error; + } + + // prepare the template + auto* prefabLoaderInterface = AZ::Interface::Get(); + if (!prefabLoaderInterface) + { + return LoadResult::Error; + } + + auto templateId = prefabLoaderInterface->LoadTemplateFromString(stringJson.data(), templateName.GetString()); + if (templateId == InvalidTemplateId) + { + return LoadResult::Error; + } + + proceduralPrefabAsset->SetTemplateId(templateId); + proceduralPrefabAsset->SetTemplateName(templateName.GetString()); + return LoadResult::LoadComplete; + } + + AZStd::unique_ptr s_PrefabGroupAssetHandler; +} + diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.h b/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.h new file mode 100644 index 0000000000..301f8a467a --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/ProceduralAssetHandler.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include + +namespace AZ::Prefab +{ + class PrefabGroupAssetHandler final + : public AZ::Data::AssetHandler + { + public: + AZ_CLASS_ALLOCATOR(PrefabGroupAssetHandler, AZ::SystemAllocator, 0); + PrefabGroupAssetHandler(); + ~PrefabGroupAssetHandler() override; + + static AZStd::string_view s_Extension; + + protected: + AZ::Data::AssetData* CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override; + void DestroyAsset(AZ::Data::AssetData* ptr) override; + void GetHandledAssetTypes(AZStd::vector& assetTypes) override; + AZ::Data::AssetHandler::LoadResult LoadAssetData( + const AZ::Data::Asset& asset, + AZStd::shared_ptr stream, + const AZ::Data::AssetFilterCB& assetLoadFilterCB) override; + + class AssetTypeInfoHandler; + AZStd::shared_ptr m_assetTypeInfoHandler; + }; +} diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroupTests.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroupTests.cpp new file mode 100644 index 0000000000..a63c0caa69 --- /dev/null +++ b/Gems/Prefab/PrefabBuilder/PrefabGroupTests.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace UnitTest +{ + TEST_F(PrefabBuilderTests, PrefabGroup_FindsRequiredReflection_True) + { + using namespace AZ::SceneAPI; + auto* serializeContext = m_app.GetSerializeContext(); + ASSERT_NE(nullptr, serializeContext); + SceneData::PrefabGroup::Reflect(serializeContext); + ASSERT_NE(nullptr, serializeContext->FindClassData(azrtti_typeid())); + ASSERT_NE(nullptr, serializeContext->FindClassData(azrtti_typeid())); + + auto findElementWithName = [](const AZ::SerializeContext::ClassData* classData, const char* name) + { + auto it = AZStd::find_if(classData->m_elements.begin(), classData->m_elements.end(), [name](const auto& element) + { + return strcmp(element.m_name, name) == 0; + }); + return it != classData->m_elements.end(); + }; + + auto* prefabGroupClassData = serializeContext->FindClassData(azrtti_typeid()); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "name")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "nodeSelectionList")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "rules")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "id")); + EXPECT_TRUE(findElementWithName(prefabGroupClassData, "prefabDomBuffer")); + } + + TEST_F(PrefabBuilderTests, PrefabGroup_JsonWithPrefabArbitraryPrefab_Works) + { + using namespace AZ::SceneAPI; + auto* serializeContext = m_app.GetSerializeContext(); + ASSERT_NE(nullptr, serializeContext); + SceneData::PrefabGroup::Reflect(serializeContext); + + // fill out a PrefabGroup using JSON + AZStd::string_view input = R"JSON( + { + "name" : "tester", + "id" : "{49698DBC-B447-49EF-9B56-25BB29342AFB}", + "prefabDomBuffer" : "{\"foo\":\"bar\"}" + })JSON"; + + rapidjson::Document document; + document.Parse(input.data(), input.size()); + ASSERT_FALSE(document.HasParseError()); + + SceneData::PrefabGroup instancePrefabGroup; + AZ::JsonSerialization::Load(instancePrefabGroup, document); + + const auto& dom = instancePrefabGroup.GetPrefabDom(); + EXPECT_TRUE(dom.GetObject().HasMember("foo")); + EXPECT_STREQ(dom.GetObject().FindMember("foo")->value.GetString(), "bar"); + EXPECT_STREQ(instancePrefabGroup.GetName().c_str(), "tester"); + EXPECT_STREQ( + instancePrefabGroup.GetId().ToString().c_str(), + "{49698DBC-B447-49EF-9B56-25BB29342AFB}"); + EXPECT_TRUE(instancePrefabGroup.GetPrefabDom().IsObject()); + } + + TEST_F(PrefabBuilderTests, PrefabGroup_InvalidPrefabJson_Detected) + { + using namespace AZ::SceneAPI; + + AZStd::string_view input = R"JSON( + { + bad json that will not parse + })JSON"; + + rapidjson::Document document; + document.Parse(input.data(), input.size()); + + SceneData::PrefabGroup prefabGroup; + prefabGroup.SetId(AZStd::move(AZ::Uuid::CreateRandom())); + prefabGroup.SetName(AZStd::move("tester")); + prefabGroup.SetPrefabDom(AZStd::move(document)); + + const auto& dom = prefabGroup.GetPrefabDom(); + EXPECT_TRUE(dom.IsNull()); + EXPECT_STREQ("tester", prefabGroup.GetName().c_str()); + } + + TEST_F(PrefabBuilderTests, PrefabGroup_InvalidPrefabJsonBuffer_Detected) + { + using namespace AZ::SceneAPI; + + AZStd::string_view inputJson = R"JSON( + { + bad json that will not parse + })JSON"; + + SceneData::PrefabGroup prefabGroup; + prefabGroup.SetId(AZStd::move(AZ::Uuid::CreateRandom())); + prefabGroup.SetName(AZStd::move("tester")); + prefabGroup.SetPrefabDomBuffer(std::move(inputJson)); + + const auto& dom = prefabGroup.GetPrefabDom(); + EXPECT_TRUE(dom.IsNull()); + EXPECT_STREQ("tester", prefabGroup.GetName().c_str()); + } + + struct PrefabBuilderBehaviorTests + : public PrefabBuilderTests + { + void SetUp() override + { + using namespace AZ::SceneAPI; + + PrefabBuilderTests::SetUp(); + SceneData::PrefabGroup::Reflect(m_app.GetSerializeContext()); + SceneData::PrefabGroup::Reflect(m_app.GetBehaviorContext()); + m_scriptContext = AZStd::make_unique(); + m_scriptContext->BindTo(m_app.GetBehaviorContext()); + } + + void TearDown() override + { + m_scriptContext.reset(); + PrefabBuilderTests::TearDown(); + } + + void ExpectExecute(AZStd::string_view script) + { + EXPECT_TRUE(m_scriptContext->Execute(script.data())); + } + + AZStd::unique_ptr m_scriptContext; + }; + + TEST_F(PrefabBuilderBehaviorTests, PrefabGroup_PrefabGroupClass_Exists) + { + ExpectExecute("group = PrefabGroup()"); + ExpectExecute("assert(group)"); + ExpectExecute("assert(group.name)"); + ExpectExecute("assert(group.id)"); + ExpectExecute("assert(group.prefabDomBuffer)"); + } + + TEST_F(PrefabBuilderBehaviorTests, PrefabGroup_PrefabGroupAssignment_Works) + { + ExpectExecute("group = PrefabGroup()"); + ExpectExecute("group.name = 'tester'"); + ExpectExecute("group.id = Uuid.CreateString('{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}', 0)"); + ExpectExecute("group.prefabDomBuffer = '{}'"); + ExpectExecute("assert(group.name == 'tester')"); + ExpectExecute("assert(tostring(group.id) == '{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}')"); + ExpectExecute("assert(group.prefabDomBuffer == '{}')"); + } +} diff --git a/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake b/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake index 9cdf90d951..4f3bf860be 100644 --- a/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake +++ b/Gems/Prefab/PrefabBuilder/prefabbuilder_files.cmake @@ -9,4 +9,11 @@ set(FILES PrefabBuilderComponent.h PrefabBuilderComponent.cpp + PrefabGroup/IPrefabGroup.h + PrefabGroup/PrefabGroup.cpp + PrefabGroup/PrefabGroup.h + PrefabGroup/PrefabGroupBehavior.cpp + PrefabGroup/PrefabGroupBehavior.h + PrefabGroup/ProceduralAssetHandler.cpp + PrefabGroup/ProceduralAssetHandler.h ) diff --git a/Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake b/Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake index 3f1ae0388b..faf2f88b5e 100644 --- a/Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake +++ b/Gems/Prefab/PrefabBuilder/prefabbuilder_tests_files.cmake @@ -9,4 +9,7 @@ set(FILES PrefabBuilderTests.h PrefabBuilderTests.cpp + PrefabGroup/PrefabGroupTests.cpp + PrefabGroup/PrefabBehaviorTests.cpp + PrefabGroup/PrefabBehaviorTests.inl ) diff --git a/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/scene_data.py b/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/scene_data.py index 2c63e5f90c..2578efeae2 100755 --- a/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/scene_data.py +++ b/Gems/PythonAssetBuilder/Editor/Scripts/scene_api/scene_data.py @@ -104,6 +104,15 @@ class SceneManifest(): self.manifest['values'].append(meshGroup) return meshGroup + def add_prefab_group(self, name, id, json) -> dict: + prefabGroup = {} + prefabGroup['$type'] = '{99FE3C6F-5B55-4D8B-8013-2708010EC715} PrefabGroup' + prefabGroup['name'] = name + prefabGroup['id'] = id + prefabGroup['prefabDomData'] = json + self.manifest['values'].append(prefabGroup) + return prefabGroup + def mesh_group_select_node(self, meshGroup, nodeName): meshGroup['nodeSelectionList']['selectedNodes'].append(nodeName) diff --git a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp index c1a1252c6b..1d3cd60e49 100644 --- a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp +++ b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,9 @@ #include #include +#include +#include +#include #include #include @@ -81,6 +85,93 @@ namespace SceneBuilder return m_cachedFingerprint.c_str(); } + void SceneBuilderWorker::PopulateSourceDependencies(const AZStd::string& manifestJson, AZStd::vector& sourceFileDependencies) + { + auto readJsonOutcome = AZ::JsonSerializationUtils::ReadJsonString(manifestJson); + AZStd::string errorMsg; + if (!readJsonOutcome.IsSuccess()) + { + // This may be an old format xml file. We don't have any dependencies in the old format so there's no point trying to parse an xml + return; + } + + rapidjson::Document document = readJsonOutcome.TakeValue(); + + auto manifestObject = document.GetObject(); + auto valuesIterator = manifestObject.FindMember("values"); + auto valuesArray = valuesIterator->value.GetArray(); + + AZStd::vector paths; + AZ::SceneAPI::Events::AssetImportRequestBus::Broadcast( + &AZ::SceneAPI::Events::AssetImportRequestBus::Events::GetManifestDependencyPaths, paths); + + for (const auto& value : valuesArray) + { + auto object = value.GetObject(); + + for (const auto& path : paths) + { + rapidjson::Pointer pointer(path.c_str()); + + auto dependencyValue = pointer.Get(object); + + if (dependencyValue && dependencyValue->IsString()) + { + AZStd::string dependency = dependencyValue->GetString(); + + sourceFileDependencies.emplace_back(AssetBuilderSDK::SourceFileDependency( + dependency, AZ::Uuid::CreateNull(), AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute)); + } + } + } + } + + bool SceneBuilderWorker::ManifestDependencyCheck(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) + { + AZStd::string manifestExtension; + AZStd::string generatedManifestExtension; + + AZ::SceneAPI::Events::AssetImportRequestBus::Broadcast( + &AZ::SceneAPI::Events::AssetImportRequestBus::Events::GetManifestExtension, manifestExtension); + AZ::SceneAPI::Events::AssetImportRequestBus::Broadcast( + &AZ::SceneAPI::Events::AssetImportRequestBus::Events::GetGeneratedManifestExtension, generatedManifestExtension); + + if (manifestExtension.empty() || generatedManifestExtension.empty()) + { + AZ_Error("SceneBuilderWorker", false, "Failed to get scene manifest extension"); + return false; + } + + AZ::SettingsRegistryInterface::FixedValueString assetCacheRoot; + AZ::SettingsRegistry::Get()->Get(assetCacheRoot, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder); + + auto manifestPath = (AZ::IO::Path(request.m_watchFolder) / (request.m_sourceFile + manifestExtension)); + auto generatedManifestPath = (AZ::IO::Path(assetCacheRoot) / (request.m_sourceFile + generatedManifestExtension)); + + auto populateDependenciesFunc = [&response](const AZStd::string& path) + { + auto readFileOutcome = AZ::Utils::ReadFile(path, AZ::SceneAPI::Containers::SceneManifest::MaxSceneManifestFileSizeInBytes); + if (!readFileOutcome.IsSuccess()) + { + AZ_Error("SceneBuilderWorker", false, "%s", readFileOutcome.GetError().c_str()); + return; + } + + PopulateSourceDependencies(readFileOutcome.TakeValue(), response.m_sourceFileDependencyList); + }; + + if (AZ::IO::FileIOBase::GetInstance()->Exists(manifestPath.Native().c_str())) + { + populateDependenciesFunc(manifestPath.Native()); + } + else if (AZ::IO::FileIOBase::GetInstance()->Exists(generatedManifestPath.Native().c_str())) + { + populateDependenciesFunc(generatedManifestPath.Native()); + } + + return true; + } + void SceneBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) { // Check for shutdown @@ -118,6 +209,11 @@ namespace SceneBuilder sourceFileDependencyInfo.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards; response.m_sourceFileDependencyList.push_back(sourceFileDependencyInfo); + if (!ManifestDependencyCheck(request, response)) + { + return; + } + response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; } diff --git a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.h b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.h index 3ecc657a3a..32456f9b2d 100644 --- a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.h +++ b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace AssetBuilderSDK { @@ -45,11 +46,15 @@ namespace SceneBuilder public: ~SceneBuilderWorker() override = default; + void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response); void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response); void ShutDown() override; const char* GetFingerprint() const; + static void PopulateSourceDependencies( + const AZStd::string& manifestJson, AZStd::vector& sourceFileDependencies); + static bool ManifestDependencyCheck(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response); static AZ::Uuid GetUUID(); void PopulateProductDependencies(const AZ::SceneAPI::Events::ExportProduct& exportProduct, const char* watchFolder, AssetBuilderSDK::JobProduct& jobProduct) const; diff --git a/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp b/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp index 5d0105f080..ba1a186e5a 100644 --- a/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp +++ b/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp @@ -11,11 +11,14 @@ #include #include #include +#include #include #include #include +#include #include #include +#include using namespace AZ; using namespace SceneBuilder; @@ -193,3 +196,200 @@ TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_ProductAn TestSuccessCase(exportProduct, expectedPathDependencies, { dependencyId }); } + +struct ImportHandler + : SceneAPI::Events::AssetImportRequestBus::Handler +{ + ImportHandler() + { + BusConnect(); + } + + ~ImportHandler() override + { + BusDisconnect(); + } + + void GetManifestDependencyPaths(AZStd::vector& paths) override + { + paths.emplace_back("/scriptFilename"); + paths.emplace_back("/layer1/layer2/0/target"); + } + + void GetManifestExtension(AZStd::string& result) override + { + result = ".test"; + } + + void GetGeneratedManifestExtension(AZStd::string& result) override + { + result = ".test.gen"; + } +}; + +using SourceDependencyTests = UnitTest::ScopedAllocatorSetupFixture; + +namespace SourceDependencyJson +{ + constexpr const char* TestJson = R"JSON( +{ + "values": [ + { + "$type": "Test1", + "scriptFilename": "a/test/path.png" + }, + { + "$type": "Test2", + "layer1" : { + "layer2" : [ + { + "target": "value.png", + "otherData": "value2.png" + }, + { + "target" : "wrong.png" + } + ] + } + } + ] +} + )JSON"; +} + +TEST_F(SourceDependencyTests, SourceDependencyTest) +{ + ImportHandler handler; + AZStd::vector dependencies; + + SceneBuilderWorker::PopulateSourceDependencies(SourceDependencyJson::TestJson, dependencies); + + ASSERT_EQ(dependencies.size(), 2); + ASSERT_STREQ(dependencies[0].m_sourceFileDependencyPath.c_str(), "a/test/path.png"); + ASSERT_STREQ(dependencies[1].m_sourceFileDependencyPath.c_str(), "value.png"); +} + +struct SettingsRegistryMock : AZ::Interface::Registrar +{ + bool Get(FixedValueString& result, AZStd::string_view) const override + { + result = "cache"; + return true; + } + + void SetApplyPatchSettings(const AZ::JsonApplyPatchSettings& /*applyPatchSettings*/) override{} + void GetApplyPatchSettings(AZ::JsonApplyPatchSettings& /*applyPatchSettings*/) override{} + + MOCK_CONST_METHOD1(GetType, Type (AZStd::string_view)); + MOCK_CONST_METHOD2(Visit, bool (Visitor&, AZStd::string_view)); + MOCK_CONST_METHOD2(Visit, bool (const VisitorCallback&, AZStd::string_view)); + MOCK_METHOD1(RegisterNotifier, NotifyEventHandler (const NotifyCallback&)); + MOCK_METHOD1(RegisterNotifier, NotifyEventHandler (NotifyCallback&&)); + MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler (const PreMergeEventCallback&)); + MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler (PreMergeEventCallback&&)); + MOCK_METHOD1(RegisterPostMergeEvent, PostMergeEventHandler (const PostMergeEventCallback&)); + MOCK_METHOD1(RegisterPostMergeEvent, PostMergeEventHandler (PostMergeEventCallback&&)); + MOCK_CONST_METHOD2(Get, bool (bool&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool (s64&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool (u64&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool (double&, AZStd::string_view)); + MOCK_CONST_METHOD2(Get, bool (AZStd::string&, AZStd::string_view)); + MOCK_CONST_METHOD3(GetObject, bool (void*, Uuid, AZStd::string_view)); + MOCK_METHOD2(Set, bool (AZStd::string_view, bool)); + MOCK_METHOD2(Set, bool (AZStd::string_view, s64)); + MOCK_METHOD2(Set, bool (AZStd::string_view, u64)); + MOCK_METHOD2(Set, bool (AZStd::string_view, double)); + MOCK_METHOD2(Set, bool (AZStd::string_view, AZStd::string_view)); + MOCK_METHOD2(Set, bool (AZStd::string_view, const char*)); + MOCK_METHOD3(SetObject, bool (AZStd::string_view, const void*, Uuid)); + MOCK_METHOD1(Remove, bool (AZStd::string_view)); + MOCK_METHOD3(MergeCommandLineArgument, bool (AZStd::string_view, AZStd::string_view, const CommandLineArgumentSettings&)); + MOCK_METHOD2(MergeSettings, bool (AZStd::string_view, Format)); + MOCK_METHOD4(MergeSettingsFile, bool (AZStd::string_view, Format, AZStd::string_view, AZStd::vector*)); + MOCK_METHOD5(MergeSettingsFolder, bool (AZStd::string_view, const Specializations&, AZStd::string_view, AZStd::string_view, AZStd::vector*)); + MOCK_METHOD1(SetUseFileIO, void (bool)); +}; + +struct SourceDependencyMockedIOTests : UnitTest::ScopedAllocatorSetupFixture + , UnitTest::SetRestoreFileIOBaseRAII +{ + SourceDependencyMockedIOTests() + : UnitTest::SetRestoreFileIOBaseRAII(m_ioMock) + { + + } + + void SetUp() override + { + using namespace ::testing; + + ON_CALL(m_ioMock, Open(_, _, _)) + .WillByDefault(Invoke( + [](auto, auto, IO::HandleType& handle) + { + handle = 1234; + return AZ::IO::Result(AZ::IO::ResultCode::Success); + })); + + ON_CALL(m_ioMock, Size(An(), _)).WillByDefault(Invoke([](auto, AZ::u64& size) + { + size = strlen(SourceDependencyJson::TestJson); + return AZ::IO::ResultCode::Success; + })); + + EXPECT_CALL(m_ioMock, Read(_, _, _, _, _)) + .WillRepeatedly(Invoke( + [](auto, void* buffer, auto, auto, AZ::u64* bytesRead) + { + memcpy(buffer, SourceDependencyJson::TestJson, strlen(SourceDependencyJson::TestJson)); + *bytesRead = strlen(SourceDependencyJson::TestJson); + return AZ::IO::ResultCode::Success; + })); + + EXPECT_CALL(m_ioMock, Close(_)).WillRepeatedly(Return(AZ::IO::ResultCode::Success)); + } + + IO::NiceFileIOBaseMock m_ioMock; +}; + +TEST_F(SourceDependencyMockedIOTests, RegularManifestHasPriority) +{ + ImportHandler handler; + SettingsRegistryMock settingsRegistry; + + AssetBuilderSDK::CreateJobsRequest request; + AssetBuilderSDK::CreateJobsResponse response; + + request.m_sourceFile = "file.fbx"; + + using namespace ::testing; + + AZStd::string genPath = AZStd::string("cache").append(1, AZ_TRAIT_OS_PATH_SEPARATOR).append("file.fbx.test.gen"); + + EXPECT_CALL(m_ioMock, Exists(StrEq("file.fbx.test"))).WillRepeatedly(Return(true)); + EXPECT_CALL(m_ioMock, Exists(StrEq(genPath.c_str()))).Times(Exactly(0)); + + ASSERT_TRUE(SceneBuilderWorker::ManifestDependencyCheck(request, response)); + ASSERT_EQ(response.m_sourceFileDependencyList.size(), 2); +} + +TEST_F(SourceDependencyMockedIOTests, GeneratedManifestTest) +{ + ImportHandler handler; + SettingsRegistryMock settingsRegistry; + + AssetBuilderSDK::CreateJobsRequest request; + AssetBuilderSDK::CreateJobsResponse response; + + request.m_sourceFile = "file.fbx"; + + using namespace ::testing; + + AZStd::string genPath = AZStd::string("cache").append(1, AZ_TRAIT_OS_PATH_SEPARATOR).append("file.fbx.test.gen"); + + EXPECT_CALL(m_ioMock, Exists(StrEq("file.fbx.test"))).WillRepeatedly(Return(false)); + EXPECT_CALL(m_ioMock, Exists(StrEq(genPath.c_str()))).WillRepeatedly(Return(true)); + + ASSERT_TRUE(SceneBuilderWorker::ManifestDependencyCheck(request, response)); + ASSERT_EQ(response.m_sourceFileDependencyList.size(), 2); +} From acfbed8a58d37512ef75c1098ed807cd8699444c Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 6 Oct 2021 06:32:28 -0700 Subject: [PATCH 058/293] Fix minor PR feedback Signed-off-by: nggieber --- scripts/o3de/o3de/manifest.py | 67 ++++++++++++++++------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index ccb5cda761..32bab05de8 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -197,7 +197,7 @@ def load_o3de_manifest(manifest_path: pathlib.Path = None) -> dict: return json_data -def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> None: +def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> bool: """ Save the json dictionary to the supplied manifest file or ~/.o3de/o3de_manifest.json if None @@ -206,16 +206,13 @@ def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> N """ if not manifest_path: manifest_path = get_o3de_manifest() - backup_name = utils.backup_file(manifest_path) with manifest_path.open('w') as s: try: s.write(json.dumps(json_data, indent=4) + '\n') - except Exception as e: + return True + except OSError as e: logger.error(f'Manifest json failed to save: {str(e)}') - os.unlink(manifest_path) - os.rename(backup_name, manifest_path) - finally: - os.unlink(backup_name) + return False def get_gems_from_subdirectories(external_subdirs: list) -> list: @@ -239,13 +236,6 @@ def get_gems_from_subdirectories(external_subdirs: list) -> list: return gem_directories -# Data query methods -def get_this_engine() -> dict: - json_data = load_o3de_manifest() - engine_data = find_engine_data(json_data) - return engine_data - - def get_engines() -> list: json_data = load_o3de_manifest() engine_list = json_data['engines'] if 'engines' in json_data else [] @@ -431,21 +421,32 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa return list(filter(filter_project_and_gem_templates_out, get_all_templates())) -def get_json_data(object_typename: str = None, - object_path: str or pathlib.Path = None, - object_validator = callable) -> dict or None: - if not object_typename or not object_validator: - logger.error(f'Missing object info.') +def get_json_file_path(object_typename: str = None, + object_path: str or pathlib.Path = None) -> pathlib.Path: + if not object_typename: + logger.error(f'Missing object typename.') if not object_path: logger.error(f'{object_typename} Path {object_path} has not been registered.') return None object_path = pathlib.Path(object_path).resolve() - object_json = object_path / f'{object_typename}.json' + return object_path / f'{object_typename}.json' + + +def get_json_data_file(object_typename: str = None, + object_json: str or pathlib.Path = None, + object_validator = callable) -> dict or None: + if not object_typename: + logger.error(f'Missing object typename.') + if not object_json.is_file(): logger.error(f'{object_typename} json {object_json} is not present.') return None + + if not object_validator: + logger.error(f'Missing object validator.') + if not object_validator(object_json): logger.error(f'{object_typename} json {object_json} is not valid.') return None @@ -454,12 +455,19 @@ def get_json_data(object_typename: str = None, try: object_json_data = json.load(f) except json.JSONDecodeError as e: - logger.warn(f'{object_json} failed to load: {str(e)}') + logger.warn(f'{object_json} failed to load: {e}') else: return object_json_data return None +def get_json_data(object_typename: str = None, + object_path: str or pathlib.Path = None, + object_validator = callable) -> dict or None: + object_json = get_json_file_path(object_typename, object_path) + + return get_json_data_file(object_typename, object_json, object_validator) + def get_engine_json_data(engine_name: str = None, engine_path: str or pathlib.Path = None) -> dict or None: @@ -527,22 +535,7 @@ def get_repo_json_data(repo_uri: str = None) -> dict or None: repo_json = get_repo_path(repo_uri=repo_uri) - if not repo_json.is_file(): - logger.error(f'Repo json {repo_json} is not present.') - return None - if not validation.valid_o3de_repo_json(repo_json): - logger.error(f'Repo json {repo_json} is not valid.') - return None - - with repo_json.open('r') as f: - try: - repo_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{repo_json} failed to load: {str(e)}') - else: - return repo_json_data - - return None + get_json_data_file("Repo", repo_json, validation.valid_o3de_repo_json) def get_repo_path(repo_uri: str = None, cache_folder: str = None) -> pathlib.Path: if not cache_folder: From a40af98394c543d2ad736fd76f5325028351f9c2 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Wed, 6 Oct 2021 14:52:59 +0100 Subject: [PATCH 059/293] Add focus camera and custom camera input (#4493) * add focus camera and custom camera input Signed-off-by: hultonha * very minor tidy before publishing PR Signed-off-by: hultonha * small updates after PR feedback Signed-off-by: hultonha --- .../EditorModularViewportCameraComposer.cpp | 43 +++++++-- .../EditorModularViewportCameraComposer.h | 2 + .../EditorPreferencesPageViewportCamera.cpp | 12 ++- .../EditorPreferencesPageViewportCamera.h | 1 + Code/Editor/EditorViewportSettings.cpp | 11 +++ Code/Editor/EditorViewportSettings.h | 3 + .../AzFramework/Viewport/CameraInput.cpp | 90 +++++++++++++++++-- .../AzFramework/Viewport/CameraInput.h | 54 +++++++++++ 8 files changed, 197 insertions(+), 19 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index 29cf348ab5..c492010336 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -95,6 +95,7 @@ namespace SandboxEditor cameras.AddCamera(m_firstPersonPanCamera); cameras.AddCamera(m_firstPersonTranslateCamera); cameras.AddCamera(m_firstPersonScrollCamera); + cameras.AddCamera(m_firstPersonFocusCamera); cameras.AddCamera(m_pivotCamera); }); @@ -111,6 +112,7 @@ namespace SandboxEditor viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::BeginCursorCapture); } }; + const auto showCursor = [viewportId = m_viewportId] { if (SandboxEditor::CameraCaptureCursorForLook()) @@ -172,19 +174,34 @@ namespace SandboxEditor return SandboxEditor::CameraScrollSpeed(); }; + const auto pivotFn = [] + { + // use the manipulator transform as the pivot point + AZStd::optional entityPivot; + AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( + entityPivot, AzToolsFramework::GetEntityContextId(), + &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); + + if (entityPivot.has_value()) + { + return entityPivot->GetTranslation(); + } + + // otherwise just use the identity + return AZ::Vector3::CreateZero(); + }; + + m_firstPersonFocusCamera = + AZStd::make_shared(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusLook); + + m_firstPersonFocusCamera->SetPivotFn(pivotFn); + m_pivotCamera = AZStd::make_shared(SandboxEditor::CameraPivotChannelId()); m_pivotCamera->SetPivotFn( - []([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) + [pivotFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { - // use the manipulator transform as the pivot point - AZStd::optional entityPivot; - AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( - entityPivot, AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); - - // otherwise just use the identity - return entityPivot.value_or(AZ::Transform::CreateIdentity()).GetTranslation(); + return pivotFn(); }); m_pivotRotateCamera = AZStd::make_shared(SandboxEditor::CameraPivotLookChannelId()); @@ -244,11 +261,17 @@ namespace SandboxEditor return SandboxEditor::CameraPanInvertedY(); }; + m_pivotFocusCamera = + AZStd::make_shared(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusPivot); + + m_pivotFocusCamera->SetPivotFn(pivotFn); + m_pivotCamera->m_pivotCameras.AddCamera(m_pivotRotateCamera); m_pivotCamera->m_pivotCameras.AddCamera(m_pivotTranslateCamera); m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyScrollCamera); m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyMoveCamera); m_pivotCamera->m_pivotCameras.AddCamera(m_pivotPanCamera); + m_pivotCamera->m_pivotCameras.AddCamera(m_pivotFocusCamera); } void EditorModularViewportCameraComposer::OnEditorModularViewportCameraComposerSettingsChanged() @@ -257,12 +280,14 @@ namespace SandboxEditor m_firstPersonTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); m_firstPersonPanCamera->SetPanInputChannelId(SandboxEditor::CameraFreePanChannelId()); m_firstPersonRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraFreeLookChannelId()); + m_firstPersonFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId()); m_pivotCamera->SetPivotInputChannelId(SandboxEditor::CameraPivotChannelId()); m_pivotTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); m_pivotPanCamera->SetPanInputChannelId(SandboxEditor::CameraPivotPanChannelId()); m_pivotRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraPivotLookChannelId()); m_pivotDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraPivotDollyChannelId()); + m_pivotFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId()); } void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId) diff --git a/Code/Editor/EditorModularViewportCameraComposer.h b/Code/Editor/EditorModularViewportCameraComposer.h index e691ca1c89..90103dba43 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.h +++ b/Code/Editor/EditorModularViewportCameraComposer.h @@ -42,12 +42,14 @@ namespace SandboxEditor AZStd::shared_ptr m_firstPersonPanCamera; AZStd::shared_ptr m_firstPersonTranslateCamera; AZStd::shared_ptr m_firstPersonScrollCamera; + AZStd::shared_ptr m_firstPersonFocusCamera; AZStd::shared_ptr m_pivotCamera; AZStd::shared_ptr m_pivotRotateCamera; AZStd::shared_ptr m_pivotTranslateCamera; AZStd::shared_ptr m_pivotDollyScrollCamera; AZStd::shared_ptr m_pivotDollyMoveCamera; AZStd::shared_ptr m_pivotPanCamera; + AZStd::shared_ptr m_pivotFocusCamera; AzFramework::ViewportId m_viewportId; }; diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.cpp b/Code/Editor/EditorPreferencesPageViewportCamera.cpp index 55b631e1f6..b632163186 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.cpp +++ b/Code/Editor/EditorPreferencesPageViewportCamera.cpp @@ -91,7 +91,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Field("FreePan", &CameraInputSettings::m_freePanChannelId) ->Field("PivotLook", &CameraInputSettings::m_pivotLookChannelId) ->Field("PivotDolly", &CameraInputSettings::m_pivotDollyChannelId) - ->Field("PivotPan", &CameraInputSettings::m_pivotPanChannelId); + ->Field("PivotPan", &CameraInputSettings::m_pivotPanChannelId) + ->Field("Focus", &CameraInputSettings::m_focusChannelId); serialize.Class() ->Version(1) @@ -206,14 +207,17 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->DataElement( AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotPanChannelId, "Pivot Pan", "Key/button to begin camera pivot pan") + ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) + ->DataElement( + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_focusChannelId, "Focus", "Key/button to focus camera pivot") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames); editContext->Class("Viewport Preferences", "Viewport Preferences") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20)) ->DataElement( - AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportCamera::m_cameraMovementSettings, - "Camera Movement Settings", "Camera Movement Settings") + AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportCamera::m_cameraMovementSettings, "Camera Movement Settings", + "Camera Movement Settings") ->DataElement( AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportCamera::m_cameraInputSettings, "Camera Input Settings", "Camera Input Settings"); @@ -281,6 +285,7 @@ void CEditorPreferencesPage_ViewportCamera::OnApply() SandboxEditor::SetCameraPivotLookChannelId(m_cameraInputSettings.m_pivotLookChannelId); SandboxEditor::SetCameraPivotDollyChannelId(m_cameraInputSettings.m_pivotDollyChannelId); SandboxEditor::SetCameraPivotPanChannelId(m_cameraInputSettings.m_pivotPanChannelId); + SandboxEditor::SetCameraFocusChannelId(m_cameraInputSettings.m_focusChannelId); SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Broadcast( &SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Events::OnEditorModularViewportCameraComposerSettingsChanged); @@ -316,4 +321,5 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings() m_cameraInputSettings.m_pivotLookChannelId = SandboxEditor::CameraPivotLookChannelId().GetName(); m_cameraInputSettings.m_pivotDollyChannelId = SandboxEditor::CameraPivotDollyChannelId().GetName(); m_cameraInputSettings.m_pivotPanChannelId = SandboxEditor::CameraPivotPanChannelId().GetName(); + m_cameraInputSettings.m_focusChannelId = SandboxEditor::CameraFocusChannelId().GetName(); } diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.h b/Code/Editor/EditorPreferencesPageViewportCamera.h index 01dc4664f6..cd31141c4a 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.h +++ b/Code/Editor/EditorPreferencesPageViewportCamera.h @@ -86,6 +86,7 @@ private: AZStd::string m_pivotLookChannelId; AZStd::string m_pivotDollyChannelId; AZStd::string m_pivotPanChannelId; + AZStd::string m_focusChannelId; }; CameraMovementSettings m_cameraMovementSettings; diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index fe8efecd17..c2539b008c 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -50,6 +50,7 @@ namespace SandboxEditor constexpr AZStd::string_view CameraPivotLookIdSetting = "/Amazon/Preferences/Editor/Camera/PivotLookId"; constexpr AZStd::string_view CameraPivotDollyIdSetting = "/Amazon/Preferences/Editor/Camera/PivotDollyId"; constexpr AZStd::string_view CameraPivotPanIdSetting = "/Amazon/Preferences/Editor/Camera/PivotPanId"; + constexpr AZStd::string_view CameraFocusIdSetting = "/Amazon/Preferences/Editor/Camera/FocusId"; template void SetRegistry(const AZStd::string_view setting, T&& value) @@ -462,4 +463,14 @@ namespace SandboxEditor { SetRegistry(CameraPivotPanIdSetting, cameraPivotPanId); } + + AzFramework::InputChannelId CameraFocusChannelId() + { + return AzFramework::InputChannelId(GetRegistry(CameraFocusIdSetting, AZStd::string("keyboard_key_alphanumeric_X")).c_str()); + } + + void SetCameraFocusChannelId(AZStd::string_view cameraFocusId) + { + SetRegistry(CameraFocusIdSetting, cameraFocusId); + } } // namespace SandboxEditor diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index d1271017c6..0253b01621 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -136,4 +136,7 @@ namespace SandboxEditor SANDBOX_API AzFramework::InputChannelId CameraPivotPanChannelId(); SANDBOX_API void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId); + + SANDBOX_API AzFramework::InputChannelId CameraFocusChannelId(); + SANDBOX_API void SetCameraFocusChannelId(AZStd::string_view cameraFocusId); } // namespace SandboxEditor diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index a3eb4d8329..13f5303eaf 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -623,15 +623,24 @@ namespace AzFramework { Camera nextCamera = targetCamera; - const auto pivotDirection = targetCamera.m_offset.GetNormalized(); - nextCamera.m_offset -= pivotDirection * delta; - const auto pivotDot = targetCamera.m_offset.Dot(nextCamera.m_offset); - const auto distance = nextCamera.m_offset.GetLength() * AZ::GetSign(pivotDot); + // handle case where pivot and offset may be the same to begin with + // choose negative y-axis for offset to default to moving the camera backwards from the pivot (standard centered pivot behavior) + const auto pivotDirection = [&targetCamera] + { + if (const auto offsetLength = targetCamera.m_offset.GetLength(); AZ::IsCloseMag(offsetLength, 0.0f)) + { + return -AZ::Vector3::CreateAxisY(); + } + else + { + return targetCamera.m_offset / offsetLength; + } + }(); - const auto minDistance = 0.01f; - if (distance < minDistance || pivotDot < 0.0f) + nextCamera.m_offset -= pivotDirection * delta; + if (pivotDirection.Dot(nextCamera.m_offset) < 0.0f) { - nextCamera.m_offset = pivotDirection * minDistance; + nextCamera.m_offset = pivotDirection * 0.001f; } return nextCamera; @@ -771,6 +780,73 @@ namespace AzFramework return camera; } + FocusCameraInput::FocusCameraInput(const InputChannelId& focusChannelId, FocusOffsetFn offsetFn) + : m_focusChannelId(focusChannelId) + , m_offsetFn(offsetFn) + { + } + + bool FocusCameraInput::HandleEvents( + const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) + { + if (const auto* input = AZStd::get_if(&event)) + { + if (input->m_channelId == m_focusChannelId && input->m_state == InputChannel::State::Began) + { + BeginActivation(); + } + } + + return !Idle(); + } + + Camera FocusCameraInput::StepCamera( + const Camera& targetCamera, + [[maybe_unused]] const ScreenVector& cursorDelta, + [[maybe_unused]] float scrollDelta, + [[maybe_unused]] float deltaTime) + { + if (Beginning()) + { + // as the camera starts, record the camera we would like to end up as + m_nextCamera.m_offset = m_offsetFn(m_pivotFn().GetDistance(targetCamera.Translation())); + const auto angles = + EulerAngles(AZ::Matrix3x3::CreateFromMatrix3x4(AZ::Matrix3x4::CreateLookAt(targetCamera.Translation(), m_pivotFn()))); + m_nextCamera.m_pitch = angles.GetX(); + m_nextCamera.m_yaw = angles.GetZ(); + m_nextCamera.m_pivot = targetCamera.m_pivot; + } + + // end the behavior when the camera is in alignment + if (AZ::IsCloseMag(targetCamera.m_pitch, m_nextCamera.m_pitch) && AZ::IsCloseMag(targetCamera.m_yaw, m_nextCamera.m_yaw)) + { + EndActivation(); + } + + return m_nextCamera; + } + + void FocusCameraInput::SetPivotFn(PivotFn pivotFn) + { + m_pivotFn = AZStd::move(pivotFn); + } + + void FocusCameraInput::SetFocusInputChannelId(const InputChannelId& focusChannelId) + { + m_focusChannelId = focusChannelId; + } + + bool CustomCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta) + { + return m_handleEventsFn(*this, event, cursorDelta, scrollDelta); + } + + Camera CustomCameraInput::StepCamera( + const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime) + { + return m_stepCameraFn(*this, targetCamera, cursorDelta, scrollDelta, deltaTime); + } + InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize) { const auto& inputChannelId = inputChannel.GetInputChannelId(); diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index c44d951292..9b1988f5ec 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -617,6 +617,60 @@ namespace AzFramework return true; } + //! Callback to use for FocusCameraInput when a free look camera is being used. + //! @note This is when offset is zero. + inline AZ::Vector3 FocusLook(float) + { + return AZ::Vector3::CreateZero(); + } + + //! Callback to use for FocusCameraInput when a pivot camera is being used. + //! @note This is when offset is non zero. + inline AZ::Vector3 FocusPivot(const float length) + { + return AZ::Vector3::CreateAxisY(-length); + } + + using FocusOffsetFn = AZStd::function; + + //! A focus behavior to align the camera view to the position returned by the pivot function. + //! @note This only alters the camera orientation, the translation is unaffected. + class FocusCameraInput : public CameraInput + { + public: + using PivotFn = AZStd::function; + + FocusCameraInput(const InputChannelId& focusChannelId, FocusOffsetFn offsetFn); + + // CameraInput overrides ... + bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; + Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; + + //! Override the default behavior for how a pivot point is calculated. + void SetPivotFn(PivotFn pivotFn); + + void SetFocusInputChannelId(const InputChannelId& focusChannelId); + + private: + InputChannelId m_focusChannelId; //!< Input channel to begin the focus camera input. + Camera m_nextCamera; + PivotFn m_pivotFn; + FocusOffsetFn m_offsetFn; + }; + + //! Provides a CameraInput type that can be implemented without needing to create a new type deriving from CameraInput. + //! This can be very useful for specific use cases that are less generally applicable. + class CustomCameraInput : public CameraInput + { + public: + // CameraInput overrides ... + bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; + Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; + + AZStd::function m_handleEventsFn; + AZStd::function m_stepCameraFn; + }; + //! Map from a generic InputChannel event to a camera specific InputEvent. InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize); } // namespace AzFramework From 79bd15aabd4d3cc017903928c4c52c5383c4f3aa Mon Sep 17 00:00:00 2001 From: John Date: Wed, 6 Oct 2021 15:45:51 +0100 Subject: [PATCH 060/293] Disable TIAF job Signed-off-by: John --- scripts/build/Platform/Windows/build_config.json | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index c607c3d821..7c39661273 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -31,7 +31,6 @@ ], "steps": [ "profile_vs2019", - "test_impact_analysis_profile_vs2019", "asset_profile_vs2019", "test_cpu_profile_vs2019" ] From 9ecbf4b8e6ddcdc7ad21034ef27144d58cc8c693 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Wed, 6 Oct 2021 07:56:07 -0700 Subject: [PATCH 061/293] Removed debugging pragmas Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../View/Widgets/VariablePanel/GraphVariablesTableView.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp index 5f76820975..5b78c62bac 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/GraphVariablesTableView.cpp @@ -37,8 +37,6 @@ #include #include -#pragma optimize("", off) - namespace ScriptCanvasEditor { @@ -1414,6 +1412,3 @@ namespace ScriptCanvasEditor #include } - - -#pragma optimize("", on) From 032939d395696754b3bfd74752fc7c48976ab734 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Wed, 6 Oct 2021 08:42:17 -0700 Subject: [PATCH 062/293] Fix AtomTressFX shader compile error Case Sensitivity (#4513) Signed-off-by: Steve Pham --- Gems/AtomTressFX/Assets/Shaders/HairSimulationCompute.azsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomTressFX/Assets/Shaders/HairSimulationCompute.azsl b/Gems/AtomTressFX/Assets/Shaders/HairSimulationCompute.azsl index f8d178206a..496aa5c7da 100644 --- a/Gems/AtomTressFX/Assets/Shaders/HairSimulationCompute.azsl +++ b/Gems/AtomTressFX/Assets/Shaders/HairSimulationCompute.azsl @@ -31,7 +31,7 @@ // THE SOFTWARE. // //-------------------------------------------------------------------------------------- -#include +#include #include //-------------------------------------------------------------------------------------- From 4b6c93f2893388cbad57a3ebeae8fd59d52e215a Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Wed, 6 Oct 2021 10:48:01 -0500 Subject: [PATCH 063/293] Bugfixes for terrain surface data. (#4508) * Bugfixes for terrain surface data. 1. Changed the TerrainSurfaceDataSystem component to query for all the surface types, now that we have them. 2. Added dependency tracking to the TerrainSurfaceGradientList component so that it will refresh terrain data when any of its data changes. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Addressed PR feedback Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../TerrainSurfaceDataSystemComponent.cpp | 10 +++++ .../TerrainSurfaceGradientListComponent.cpp | 44 +++++++++++++++++-- .../TerrainSurfaceGradientListComponent.h | 8 ++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp index 04c94b24d6..0346ff7281 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp @@ -156,9 +156,19 @@ namespace Terrain point.m_entityId = GetEntityId(); point.m_position = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), terrainHeight); point.m_normal = terrain->GetNormal(inPosition); + + // Always add a "terrain" or "terrainHole" tag. const AZ::Crc32 terrainTag = isHole ? SurfaceData::Constants::s_terrainHoleTagCrc : SurfaceData::Constants::s_terrainTagCrc; SurfaceData::AddMaxValueForMasks(point.m_masks, terrainTag, 1.0f); + + // Add all of the surface tags that the terrain has at this point. + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet surfaceWeights; + terrain->GetSurfaceWeights(point.m_position, surfaceWeights); + for (auto& tag : surfaceWeights) + { + SurfaceData::AddMaxValueForMasks(point.m_masks, tag.m_surfaceType, tag.m_weight); + } surfacePointList.push_back(point); } // Only one handler should exist. diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp index 2fbd6a4814..958e175cf3 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp @@ -12,6 +12,7 @@ #include #include +#include namespace Terrain { @@ -33,7 +34,8 @@ namespace Terrain ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement( - AZ::Edit::UIHandlers::Default, &TerrainSurfaceGradientMapping::m_gradientEntityId, "Gradient Entity", "ID of Entity providing a gradient.") + AZ::Edit::UIHandlers::Default, &TerrainSurfaceGradientMapping::m_gradientEntityId, + "Gradient Entity", "ID of Entity providing a gradient.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->UIElement("GradientPreviewer", "Previewer") ->Attribute(AZ::Edit::Attributes::NameLabelOverride, "") @@ -68,7 +70,8 @@ namespace Terrain ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement( - AZ::Edit::UIHandlers::Default, &TerrainSurfaceGradientListConfig::m_gradientSurfaceMappings, "Gradient to Surface Mappings", "Maps Gradient Entities to Surfaces.") + AZ::Edit::UIHandlers::Default, &TerrainSurfaceGradientListConfig::m_gradientSurfaceMappings, + "Gradient to Surface Mappings", "Maps Gradient Entities to Surfaces.") ; } } @@ -109,12 +112,36 @@ namespace Terrain void TerrainSurfaceGradientListComponent::Activate() { + LmbrCentral::DependencyNotificationBus::Handler::BusConnect(GetEntityId()); Terrain::TerrainAreaSurfaceRequestBus::Handler::BusConnect(GetEntityId()); + + // Make sure we get update notifications whenever this entity or any dependent gradient entity changes in any way. + // We'll use that to notify the terrain system that the surface information needs to be refreshed. + m_dependencyMonitor.Reset(); + m_dependencyMonitor.ConnectOwner(GetEntityId()); + m_dependencyMonitor.ConnectDependency(GetEntityId()); + + for (auto& surfaceMapping : m_configuration.m_gradientSurfaceMappings) + { + if (surfaceMapping.m_gradientEntityId != GetEntityId()) + { + m_dependencyMonitor.ConnectDependency(surfaceMapping.m_gradientEntityId); + } + } + + // Notify that the area has changed. + OnCompositionChanged(); } void TerrainSurfaceGradientListComponent::Deactivate() { + m_dependencyMonitor.Reset(); + Terrain::TerrainAreaSurfaceRequestBus::Handler::BusDisconnect(); + LmbrCentral::DependencyNotificationBus::Handler::BusDisconnect(); + + // Since this surface data will no longer exist, notify the terrain system to refresh the area. + OnCompositionChanged(); } bool TerrainSurfaceGradientListComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) @@ -137,7 +164,9 @@ namespace Terrain return false; } - void TerrainSurfaceGradientListComponent::GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const + void TerrainSurfaceGradientListComponent::GetSurfaceWeights( + const AZ::Vector3& inPosition, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const { outSurfaceWeights.clear(); @@ -146,7 +175,8 @@ namespace Terrain for (const auto& mapping : m_configuration.m_gradientSurfaceMappings) { float weight = 0.0f; - GradientSignal::GradientRequestBus::EventResult(weight, mapping.m_gradientEntityId, &GradientSignal::GradientRequestBus::Events::GetValue, params); + GradientSignal::GradientRequestBus::EventResult(weight, + mapping.m_gradientEntityId, &GradientSignal::GradientRequestBus::Events::GetValue, params); AzFramework::SurfaceData::SurfaceTagWeight tagWeight; tagWeight.m_surfaceType = mapping.m_surfaceTag; @@ -154,4 +184,10 @@ namespace Terrain outSurfaceWeights.emplace(tagWeight); } } + + void TerrainSurfaceGradientListComponent::OnCompositionChanged() + { + TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId()); + } + } // namespace Terrain diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h index 799038354c..bb30029f35 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -47,6 +49,7 @@ namespace Terrain class TerrainSurfaceGradientListComponent : public AZ::Component , public Terrain::TerrainAreaSurfaceRequestBus::Handler + , private LmbrCentral::DependencyNotificationBus::Handler { public: template @@ -72,6 +75,11 @@ namespace Terrain void GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const override; private: + ////////////////////////////////////////////////////////////////////////// + // LmbrCentral::DependencyNotificationBus + void OnCompositionChanged() override; + TerrainSurfaceGradientListConfig m_configuration; + LmbrCentral::DependencyMonitor m_dependencyMonitor; }; } // namespace Terrain From 49dd0d633196f55f0d83113b609dc58054317410 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Wed, 6 Oct 2021 11:06:28 -0500 Subject: [PATCH 064/293] Update with PR feedback. Use direct ratio on hardware concurrency with a set min and an a number excluded for O3DE threads Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- .../AzCore/AzCore/Jobs/JobManagerComponent.cpp | 11 ++++++++--- .../AzCore/Task/TaskGraphSystemComponent.cpp | 15 ++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp index 2cd740bf9e..e98711049c 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp @@ -20,8 +20,9 @@ #include -AZ_CVAR(uint32_t, cl_numeratorJobThreads, 1, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system multiplier on the number of hw threads the machine supports to create at initialization"); -AZ_CVAR(uint32_t, cl_denominatorJobThreads, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system divisor on the number of hw threads the machine supports to create at initialization"); +AZ_CVAR(float, cl_jobThreadsConcurrencyRatio, 0.5f, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system multiplier on the number of hw threads the machine creates at initialization"); +AZ_CVAR(uint32_t, cl_jobThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system number of hardware threads that are reserved for O3DE system threads"); +AZ_CVAR(uint32_t, cl_jobThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system minimum number of worker threads to create after scaling the number of hw threads"); namespace AZ { @@ -53,7 +54,11 @@ namespace AZ int numberOfWorkerThreads = m_numberOfWorkerThreads; if (numberOfWorkerThreads <= 0) // spawn default number of threads { - numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), cl_numeratorJobThreads * AZStd::thread::hardware_concurrency() / cl_denominatorJobThreads); + // calc number of job threads = cl_jobThreadsConcurrencyRatio * (number of hardware threads - cl_jobThreadsNumReserved), + // min = cl_jobThreadsMinNumber, + // max = number of hardware threads - cl_jobThreadsNumReserved + uint32_t scaledHardwareThreads = AZ::GetMax( cl_jobThreadsMinNumber, static_cast(AZStd::floor( 0.5f + AZ::GetClamp(cl_jobThreadsConcurrencyRatio, 0.0f, 1.0f) * static_cast(AZStd::thread::hardware_concurrency() - cl_jobThreadsNumReserved)))); + numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), scaledHardwareThreads); #if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS); #endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp index 198969dbce..6548d9d162 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -11,11 +11,13 @@ #include #include #include +#include // Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system. AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)"); -AZ_CVAR(uint32_t, cl_numeratorTaskGraphThreads, 3, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph multiplier on the number of hw threads the machine supports to create at initialization"); -AZ_CVAR(uint32_t, cl_denominatorTaskGraphThreads, 4, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph divisor on the number of hw threads the machine supports to create at initialization"); +AZ_CVAR(float, cl_taskGraphThreadsConcurrencyRatio, 0.75f, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph calculate the number of worker threads to spawn by scaling the number of hw threads, value is clamped between 0.0f and 1.0f"); +AZ_CVAR(uint32_t, cl_taskGraphThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph number of hardware threads that are reserved for O3DE system threads"); +AZ_CVAR(uint32_t, cl_taskGraphThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph minimum number of worker threads to create after scaling the number of hw threads"); static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService"); @@ -27,10 +29,13 @@ namespace AZ if (Interface::Get() == nullptr) { - uint32_t numThreads = cl_numeratorTaskGraphThreads * AZStd::thread::hardware_concurrency() / cl_denominatorTaskGraphThreads; - m_taskExecutor = aznew TaskExecutor(numThreads); + // calc number of worker threads = cl_taskGraphThreadsConcurrencyRatio * (number of hardware threads - cl_taskGraphThreadsNumReserved), + // min = cl_taskGraphThreadsMinNumber, + // max = number of hardware threads - cl_taskGraphThreadsNumReserved + uint32_t scaledHardwareThreads = AZ::GetMax( cl_taskGraphThreadsMinNumber, static_cast(AZStd::floor( 0.5f + AZ::GetClamp(cl_taskGraphThreadsConcurrencyRatio, 0.0f, 1.0f) * static_cast(AZStd::thread::hardware_concurrency() - cl_taskGraphThreadsNumReserved)))); + m_taskExecutor = aznew TaskExecutor(scaledHardwareThreads); TaskExecutor::SetInstance(m_taskExecutor); - Interface::Register(this); + Interface::Register(this); } } From 8f1a589fcff92f6953dc6a9e5b41658cac8a0e43 Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Wed, 6 Oct 2021 09:27:20 -0700 Subject: [PATCH 065/293] Send message to post_ar_build SNS topic after build finished (#4442) * Send message to post_ar_build SNS topic after build finished Signed-off-by: shiranj * Add build number to SNS message Signed-off-by: shiranj --- scripts/build/Jenkins/Jenkinsfile | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 5fe19ddf46..ffca69a14f 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -793,27 +793,32 @@ catch(Exception e) { } finally { try { - if(env.SNS_TOPIC) { - snsPublish( - topicArn: env.SNS_TOPIC, - subject:'Build Result', - message:"${currentBuild.currentResult}:${BUILD_URL}:${env.RECREATE_VOLUME}:${env.CLEAN_OUTPUT_DIRECTORY}:${env.CLEAN_ASSETS}" - ) - } node('controller') { if("${currentBuild.currentResult}" == "SUCCESS") { + buildFailure = "" emailBody = "${BUILD_URL}\nSuccess!" } else { buildFailure = tm('${BUILD_FAILURE_ANALYZER}') emailBody = "${BUILD_URL}\n${buildFailure}!" - if(env.SNS_TOPIC_BUILD_FAILURE) { - message_json = ["build_url":env.BUILD_URL, "repository_name":env.REPOSITORY_NAME, "branch_name":env.BRANCH_NAME, "build_failure":buildFailure] - snsPublish( - topicArn: env.SNS_TOPIC_BUILD_FAILURE, - subject:'Build Failure', - message:JsonOutput.toJson(message_json) - ) - } + + } + if(env.POST_AR_BUILD_SNS_TOPIC) { + message_json = [ + "build_url": env.BUILD_URL, + "build_number": env.BUILD_NUMBER, + "repository_name": env.REPOSITORY_NAME, + "branch_name": env.BRANCH_NAME, + "build_result": "${currentBuild.currentResult}", + "build_failure": buildFailure, + "recreate_volume": env.RECREATE_VOLUME, + "clean_output_directory": env.CLEAN_OUTPUT_DIRECTORY, + "clean_assets": env.CLEAN_ASSETS + ] + snsPublish( + topicArn: env.POST_AR_BUILD_SNS_TOPIC, + subject:'Build Result', + message:JsonOutput.toJson(message_json) + ) } emailext ( body: "${emailBody}", From 15ecf3c65aa1a8123d08bbbf39fb707403f9083b Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Wed, 6 Oct 2021 12:41:51 -0400 Subject: [PATCH 066/293] Hair - fixing per object UI control per object (#4507) - Deferred material array index was not passed every frame (the objects' material array is built during the frame) Signed-off-by: Adi-Amazon --- .../Code/Rendering/HairFeatureProcessor.cpp | 22 +++++++++----- .../Code/Rendering/HairRenderObject.cpp | 30 +++++++++++-------- .../Code/Rendering/HairRenderObject.h | 7 ++++- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp index e4f1b02a88..7c8ce74f8e 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp @@ -226,27 +226,34 @@ namespace AZ // Prepare materials array for the per pass srg std::vector hairObjectsRenderMaterials; - uint32_t obj = 0; - for (auto objIter = m_hairRenderObjects.begin(); objIter != m_hairRenderObjects.end(); ++objIter, ++obj) + uint32_t objectIndex = 0; + for (auto& renderObject : m_hairRenderObjects) { - HairRenderObject* renderObject = objIter->get(); if (!renderObject->IsEnabled()) { continue; } - renderObject->Update(); + + renderObject->SetRenderIndex(objectIndex); // [To Do] Hair - update the following parameters for dynamic LOD control // should change or when parameters are being changed on the editor side. // float Distance = sqrtf( m_activeScene.scene->GetCameraPos().x * m_activeScene.scene->GetCameraPos().x + // m_activeScene.scene->GetCameraPos().y * m_activeScene.scene->GetCameraPos().y + // m_activeScene.scene->GetCameraPos().z * m_activeScene.scene->GetCameraPos().z); -// objIter->get()->UpdateRenderingParameters( -// renderingSettings, m_nScreenWidth * m_nScreenHeight * AVE_FRAGS_PER_PIXEL, m_deltaTime, Distance); + const float distanceFromCamera = 1.0f; // fixed distance until LOD mechanism is worked on + const float updateShadows = false; // same here - currently cheap self shadow approx + renderObject->UpdateRenderingParameters( nullptr, RESERVED_PIXELS_FOR_OIT, distanceFromCamera, updateShadows); - // this will be used for the constant buffer + // this will be used in the constant buffer to set the material array used by the resolve pass hairObjectsRenderMaterials.push_back(renderObject->GetHairRenderParams()); + + // The data update for the GPU bind - this should be the very last thing done after the + // data has been read and / or altered on the CPU side. + renderObject->Update(); + ++objectIndex; } + FillHairMaterialsArray(hairObjectsRenderMaterials); } @@ -532,4 +539,3 @@ namespace AZ } // namespace Hair } // namespace Render } // namespace AZ - diff --git a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp index a89a3eb1b8..baf986daf6 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.cpp @@ -878,6 +878,11 @@ namespace AZ const AMD::TressFXRenderingSettings* parameters, const int nodePoolSize, float distance, bool shadowUpdate /*= false*/) { + if (!parameters) + { + parameters = m_renderSettings; + } + // Update Render Parameters // If you alter FiberRadius make sure to change it also in the material properties // passed by the Feature Processor for the shading. @@ -888,7 +893,7 @@ namespace AZ // original TressFX lighting parameters - two specular lobes approximating // the Marschner R and and TRT lobes + diffuse component. - m_renderCB->MatKValue = {{{0.f, parameters->m_HairKDiffuse, parameters->m_HairKSpec1, parameters->m_HairSpecExp1}}}; + m_renderCB->MatKValue = { {{0.f, parameters->m_HairKDiffuse, parameters->m_HairKSpec1, parameters->m_HairSpecExp1}} }; m_renderCB->HairKs2 = parameters->m_HairKSpec2; m_renderCB->HairEx2 = parameters->m_HairSpecExp2; @@ -903,11 +908,13 @@ namespace AZ m_strandCB->TipPercentage = parameters->m_TipPercentage; m_strandCB->StrandUVTilingFactor = parameters->m_StrandUVTilingFactor; m_strandCB->FiberRatio = parameters->m_FiberRatio; + m_strandCB->EnableThinTip = parameters->m_EnableThinTip; + m_strandCB->EnableStrandUV = parameters->m_EnableStrandUV; // Reset LOD hair density for the frame m_LODHairDensity = 1.f; + float fiberRadius = parameters->m_FiberRadius; - float FiberRadius = parameters->m_FiberRadius; if (parameters->m_EnableHairLOD) { float MinLODDist = shadowUpdate ? @@ -922,23 +929,18 @@ namespace AZ float DistanceRatio = AZStd::min((distance - MinLODDist) / AZStd::max(MaxLODDist - MinLODDist, 0.00001f), 1.f); // Lerp: x + s(y-x) - float MaxLODFiberRadius = FiberRadius * (shadowUpdate ? parameters->m_ShadowLODWidthMultiplier : parameters->m_LODWidthMultiplier); - FiberRadius = FiberRadius + (DistanceRatio * (MaxLODFiberRadius - FiberRadius)); + float MaxLODFiberRadius = fiberRadius * (shadowUpdate ? parameters->m_ShadowLODWidthMultiplier : parameters->m_LODWidthMultiplier); + fiberRadius = fiberRadius + (DistanceRatio * (MaxLODFiberRadius - fiberRadius)); // Lerp: x + s(y-x) m_LODHairDensity = 1.f + (DistanceRatio * ((shadowUpdate ? parameters->m_ShadowLODPercent : parameters->m_LODPercent) - 1.f)); } } - m_strandCB->FiberRadius = FiberRadius; - - m_strandCB->NumVerticesPerStrand = m_NumVerticesPerStrand; // Always constant - m_strandCB->EnableThinTip = parameters->m_EnableThinTip; + m_strandCB->FiberRadius = fiberRadius; + m_strandCB->NumVerticesPerStrand = m_NumVerticesPerStrand; // Constant through the run per object m_strandCB->NodePoolSize = nodePoolSize; - m_strandCB->RenderParamsIndex = m_RenderIndex; // Always constant - - m_strandCB->EnableStrandUV = parameters->m_EnableStrandUV; - m_strandCB->EnableStrandTangent = parameters->m_EnableStrandTangent; + m_strandCB->RenderParamsIndex = m_RenderIndex; // Per Objects specific according to its index in the FP } //!===================================================================================== @@ -977,8 +979,10 @@ namespace AZ UpdateSimulationParameters(simSettings, SIMULATION_TIME_STEP); // [To Do] Hair - change to be dynamically calculated - const float distanceFromCamera = 1.0; + const float distanceFromCamera = 1.0f; const float updateShadows = false; + m_renderSettings = renderSettings; + m_simSettings = simSettings; UpdateRenderingParameters(renderSettings, RESERVED_PIXELS_FOR_OIT, distanceFromCamera, updateShadows); if (!GetShaders()) diff --git a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h index c81d2b9079..fa4095eed0 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h +++ b/Gems/AtomTressFX/Code/Rendering/HairRenderObject.h @@ -269,6 +269,7 @@ namespace AZ void UpdateSimulationParameters(const AMD::TressFXSimulationSettings* settings, float timeStep); void SetWind(const Vector3& windDir, float windMag, int frame); + void SetRenderIndex(uint32_t renderIndex) { m_RenderIndex = renderIndex; } void ResetPositions() { m_simCB->g_ResetPositions = 1.0f; } void IncreaseSimulationFrame() @@ -315,6 +316,10 @@ namespace AZ float m_frameDeltaTime = 0.02; + //! The following are the configuration settings that might be required during the update. + AMD::TressFXSimulationSettings* m_simSettings = nullptr; + AMD::TressFXRenderingSettings* m_renderSettings = nullptr; + //! Hair asset information uint32_t m_TotalIndices = 0; uint32_t m_NumTotalVertices = 0; @@ -331,7 +336,7 @@ namespace AZ //! Controls reset / copy base hair state uint32_t m_SimulationFrame = 0; - // [To Do] - verify if still required + //! The index used as a look up into the material array during the resolve pass uint32_t m_RenderIndex = 0; //!----------------------------------------------------------------- From 8928c90cc47428ef7cded1af95b483653964bbb2 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 6 Oct 2021 10:13:49 -0700 Subject: [PATCH 067/293] Makes Editor depend on LuaIDE (#4514) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Tools/Standalone/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Tools/Standalone/CMakeLists.txt b/Code/Tools/Standalone/CMakeLists.txt index 78047dd6cf..12bdb8f453 100644 --- a/Code/Tools/Standalone/CMakeLists.txt +++ b/Code/Tools/Standalone/CMakeLists.txt @@ -38,3 +38,5 @@ ly_add_target( PRIVATE STANDALONETOOLS_ENABLE_LUA_IDE ) + +ly_add_dependencies(Editor LuaIDE) From 0848a9cdf958c430f2a7ec68a6462688d0588b93 Mon Sep 17 00:00:00 2001 From: allisaurus <34254888+allisaurus@users.noreply.github.com> Date: Wed, 6 Oct 2021 10:26:51 -0700 Subject: [PATCH 068/293] Add field names, tooltips to AWSClientAuth gem AuthenticationProviderScriptCanvasRequestBus nodes (#4451) Signed-off-by: Stanko --- .../Source/AWSClientAuthSystemComponent.cpp | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp index 198f29ebf7..dbde19aad6 100644 --- a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp +++ b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp @@ -33,7 +33,7 @@ namespace AWSClientAuth AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { - serialize->Class()->Version(0); + serialize->Class()->Version(1); if (AZ::EditContext* ec = serialize->GetEditContext()) { @@ -55,26 +55,44 @@ namespace AWSClientAuth ->Enum<(int)ProviderNameEnum::AWSCognitoIDP>("ProviderNameEnum_AWSCognitoIDP") ->Enum<(int)ProviderNameEnum::LoginWithAmazon>("ProviderNameEnum_LoginWithAmazon") ->Enum<(int)ProviderNameEnum::Google>("ProviderNameEnum_Google"); - behaviorContext->EBus("AuthenticationProviderRequestBus") ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Event("Initialize", &AuthenticationProviderScriptCanvasRequestBus::Events::Initialize) - ->Event("IsSignedIn", &AuthenticationProviderScriptCanvasRequestBus::Events::IsSignedIn) - ->Event("GetAuthenticationTokens", &AuthenticationProviderScriptCanvasRequestBus::Events::GetAuthenticationTokens) + ->Event("IsSignedIn", &AuthenticationProviderScriptCanvasRequestBus::Events::IsSignedIn, + { { { "Provider name", "The identity provider name" } } }) + ->Event("GetAuthenticationTokens", &AuthenticationProviderScriptCanvasRequestBus::Events::GetAuthenticationTokens, + { { { "Provider name", "The identity provider name" } } }) ->Event( "PasswordGrantSingleFactorSignInAsync", - &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantSingleFactorSignInAsync) + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantSingleFactorSignInAsync, + { { { "Provider name", "The identity provider" }, { "Username", "The client's username" }, { "Password", "The client's password" } } }) ->Event( "PasswordGrantMultiFactorSignInAsync", - &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorSignInAsync) + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorSignInAsync, + { { { "Provider name", "The identity provider name" }, + { "Username", "The client's username" }, + { "Password", "The client's password" } } }) ->Event( "PasswordGrantMultiFactorConfirmSignInAsync", - &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorConfirmSignInAsync) - ->Event("DeviceCodeGrantSignInAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantSignInAsync) - ->Event("DeviceCodeGrantConfirmSignInAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantConfirmSignInAsync) - ->Event("RefreshTokensAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::RefreshTokensAsync) - ->Event("GetTokensWithRefreshAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::GetTokensWithRefreshAsync) - ->Event("SignOut", &AuthenticationProviderScriptCanvasRequestBus::Events::SignOut); + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorConfirmSignInAsync, + { { { "Provider name", "The identity provider name" }, + { "Username", "The client's username" }, + { "Confirmation code", "The client's confirmation code" } } }) + ->Event( + "DeviceCodeGrantSignInAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantSignInAsync, + { { { "Provider name", "The identity provider name" } } }) + ->Event( + "DeviceCodeGrantConfirmSignInAsync", + &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantConfirmSignInAsync, + { { { "Provider name", "The identity provider name" } } }) + ->Event( + "RefreshTokensAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::RefreshTokensAsync, + { { { "Provider name", "The identity provider name" } } }) + ->Event("GetTokensWithRefreshAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::GetTokensWithRefreshAsync, + { { { "Provider name", "The identity provider name" } } }) + ->Event( + "SignOut", &AuthenticationProviderScriptCanvasRequestBus::Events::SignOut, + { { { "Provider name", "The identity provider name" } } }); behaviorContext->EBus("AWSCognitoAuthorizationRequestBus") ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) From 46ae0d3f1ca824690ca0cfd6a8741be1186ffab0 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 6 Oct 2021 10:39:31 -0700 Subject: [PATCH 069/293] fix linux build error on unique_ptr deletion Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Editor/View/Windows/Tools/UpgradeTool/Controller.cpp | 6 +++++- .../Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp index 138532be0f..dbcd176ee5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.cpp @@ -35,7 +35,6 @@ #include #include -// #include namespace ScriptCanvasEditor { @@ -63,6 +62,11 @@ namespace ScriptCanvasEditor ModelNotificationsBus::Handler::BusConnect(); } + Controller::~Controller() + { + delete m_view; + } + void Controller::AddLogEntries() { const AZStd::vector* logs = nullptr; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h index 298f755d56..9842ea3da4 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/Controller.h @@ -52,6 +52,7 @@ namespace ScriptCanvasEditor AZ_CLASS_ALLOCATOR(Controller, AZ::SystemAllocator, 0); explicit Controller(QWidget* parent = nullptr); + ~Controller(); private: static constexpr int ColumnAsset = 0; @@ -59,7 +60,7 @@ namespace ScriptCanvasEditor static constexpr int ColumnBrowse = 2; static constexpr int ColumnStatus = 3; - AZStd::unique_ptr m_view; + Ui::View* m_view = nullptr; int m_handledAssetCount = 0; void AddLogEntries(); From 4f51b53558d88d59993f305fad84c352b33ba2e6 Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Wed, 6 Oct 2021 10:56:49 -0700 Subject: [PATCH 070/293] [GameLift][FlexMatch] Update session interface for clients to make matchmaking requests (#4450) * [GameLift][FlexMatch] Update session interface for clients to make matchmaking requests Signed-off-by: Junbo Liang --- .../Matchmaking/IMatchmakingRequests.h | 63 ++++++++++ .../Matchmaking/MatchmakingNotifications.h | 62 ++++++++++ .../Matchmaking/MatchmakingRequests.cpp | 78 ++++++++++++ .../Matchmaking/MatchmakingRequests.h | 66 ++++++++++ .../AzFramework/Session/ISessionRequests.h | 89 +------------- ...essionRequests.cpp => SessionRequests.cpp} | 3 +- .../AzFramework/Session/SessionRequests.h | 107 +++++++++++++++++ .../AzFramework/azframework_files.cmake | 7 +- .../Request/AWSGameLiftAcceptMatchRequest.h | 29 +++++ .../AWSGameLiftCreateSessionOnQueueRequest.h | 2 +- .../Request/AWSGameLiftCreateSessionRequest.h | 2 +- .../Request/AWSGameLiftJoinSessionRequest.h | 2 +- .../AWSGameLiftSearchSessionsRequest.h | 2 +- .../AWSGameLiftStartMatchmakingRequest.h | 59 +++++++++ .../AWSGameLiftStopMatchmakingRequest.h | 29 +++++ .../Include/Request/IAWSGameLiftRequests.h | 23 ++++ .../Source/AWSGameLiftClientManager.cpp | 32 +++++ .../Source/AWSGameLiftClientManager.h | 62 ++++++++++ .../AWSGameLiftClientSystemComponent.cpp | 113 ++++++++++++------ .../Source/AWSGameLiftClientSystemComponent.h | 3 + .../Request/AWSGameLiftAcceptMatchRequest.cpp | 43 +++++++ .../AWSGameLiftStartMatchmakingRequest.cpp | 93 ++++++++++++++ .../AWSGameLiftStopMatchmakingRequest.cpp | 41 +++++++ .../awsgamelift_client_files.cmake | 6 + 24 files changed, 885 insertions(+), 131 deletions(-) create mode 100644 Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h create mode 100644 Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h create mode 100644 Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.cpp create mode 100644 Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h rename Code/Framework/AzFramework/AzFramework/Session/{ISessionRequests.cpp => SessionRequests.cpp} (98%) create mode 100644 Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h new file mode 100644 index 0000000000..22b65f8340 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AzFramework +{ + //! IMatchmakingRequests + //! Pure virtual session interface class to abstract the details of session handling from application code. + class IMatchmakingRequests + { + public: + AZ_RTTI(IMatchmakingRequests, "{BC0B74DA-A448-4F40-9B50-9D73142829D5}"); + + IMatchmakingRequests() = default; + virtual ~IMatchmakingRequests() = default; + + // Registers a player's acceptance or rejection of a proposed matchmaking. + // @param acceptMatchRequest The request of AcceptMatch operation + virtual void AcceptMatch(const AcceptMatchRequest& acceptMatchRequest) = 0; + + // Create a game match for a group of players. + // @param startMatchmakingRequest The request of StartMatchmaking operation + // @return A unique identifier for a matchmaking ticket + virtual AZStd::string StartMatchmaking(const StartMatchmakingRequest& startMatchmakingRequest) = 0; + + // Cancels a matchmaking ticket that is currently being processed. + // @param stopMatchmakingRequest The request of StopMatchmaking operation + virtual void StopMatchmaking(const StopMatchmakingRequest& stopMatchmakingRequest) = 0; + }; + + //! IMatchmakingAsyncRequests + //! Async version of IMatchmakingRequests + class IMatchmakingAsyncRequests + { + public: + AZ_RTTI(ISessionAsyncRequests, "{53513480-2D02-493C-B44E-96AA27F42429}"); + + IMatchmakingAsyncRequests() = default; + virtual ~IMatchmakingAsyncRequests() = default; + + // AcceptMatch Async + // @param acceptMatchRequest The request of AcceptMatch operation + virtual void AcceptMatchAsync(const AcceptMatchRequest& acceptMatchRequest) = 0; + + // StartMatchmaking Async + // @param startMatchmakingRequest The request of StartMatchmaking operation + virtual void StartMatchmakingAsync(const StartMatchmakingRequest& startMatchmakingRequest) = 0; + + // StopMatchmaking Async + // @param stopMatchmakingRequest The request of StopMatchmaking operation + virtual void StopMatchmakingAsync(const StopMatchmakingRequest& stopMatchmakingRequest) = 0; + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h new file mode 100644 index 0000000000..ad61971a11 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzFramework +{ + //! MatchmakingAsyncRequestNotifications + //! The notifications correspond to matchmaking async requests + class MatchmakingAsyncRequestNotifications + : public AZ::EBusTraits + { + public: + // Safeguard handler for multi-threaded use case + using MutexType = AZStd::recursive_mutex; + + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + + // OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes + virtual void OnAcceptMatchAsyncComplete() = 0; + + // OnStartMatchmakingAsyncComplete is fired once StartMatchmakingAsync completes + // @param matchmakingTicketId The unique identifier for the matchmaking ticket + virtual void OnStartMatchmakingAsyncComplete(const AZStd::string& matchmakingTicketId) = 0; + + // OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes + virtual void OnStopMatchmakingAsyncComplete() = 0; + }; + using MatchmakingAsyncRequestNotificationBus = AZ::EBus; + + //! MatchmakingNotifications + //! The matchmaking notifications to listen for performing required operations + class MatchAcceptanceNotifications + : public AZ::EBusTraits + { + public: + // Safeguard handler for multi-threaded use case + using MutexType = AZStd::recursive_mutex; + + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + + // OnMatchAcceptance is fired when DescribeMatchmaking ticket status is REQUIRES_ACCEPTANCE + virtual void OnMatchAcceptance() = 0; + }; + using MatchAcceptanceNotificationBus = AZ::EBus; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.cpp b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.cpp new file mode 100644 index 0000000000..b6c8c55fa4 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AzFramework +{ + void AcceptMatchRequest::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("acceptMatch", &AcceptMatchRequest::m_acceptMatch) + ->Field("playerIds", &AcceptMatchRequest::m_playerIds) + ->Field("ticketId", &AcceptMatchRequest::m_ticketId); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("AcceptMatchRequest", "The container for AcceptMatch request parameters") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement(AZ::Edit::UIHandlers::Default, &AcceptMatchRequest::m_acceptMatch, "AcceptMatch", + "Player response to accept or reject match") + ->DataElement(AZ::Edit::UIHandlers::Default, &AcceptMatchRequest::m_playerIds, "PlayerIds", + "A list of unique identifiers for players delivering the response") + ->DataElement(AZ::Edit::UIHandlers::Default, &AcceptMatchRequest::m_ticketId, "TicketId", + "A unique identifier for a matchmaking ticket"); + } + } + } + + void StartMatchmakingRequest::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("ticketId", &StartMatchmakingRequest::m_ticketId); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("StartMatchmakingRequest", "The container for StartMatchmaking request parameters") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement(AZ::Edit::UIHandlers::Default, &StartMatchmakingRequest::m_ticketId, "TicketId", + "A unique identifier for a matchmaking ticket"); + } + } + } + + void StopMatchmakingRequest::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("ticketId", &StopMatchmakingRequest::m_ticketId); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("StopMatchmakingRequest", "The container for StopMatchmaking request parameters") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement(AZ::Edit::UIHandlers::Default, &StopMatchmakingRequest::m_ticketId, "TicketId", + "A unique identifier for a matchmaking ticket"); + } + } + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h new file mode 100644 index 0000000000..58e335696f --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AZ +{ + class ReflectContext; +} + +namespace AzFramework +{ + //! AcceptMatchRequest + //! The container for AcceptMatch request parameters. + struct AcceptMatchRequest + { + AZ_RTTI(AcceptMatchRequest, "{AD289D76-CEE2-424F-847E-E62AA83B7D79}"); + static void Reflect(AZ::ReflectContext* context); + + AcceptMatchRequest() = default; + virtual ~AcceptMatchRequest() = default; + + // Player response to accept or reject match + bool m_acceptMatch; + // A list of unique identifiers for players delivering the response + AZStd::vector m_playerIds; + // A unique identifier for a matchmaking ticket + AZStd::string m_ticketId; + }; + + //! StartMatchmakingRequest + //! The container for StartMatchmaking request parameters. + struct StartMatchmakingRequest + { + AZ_RTTI(StartMatchmakingRequest, "{70B47776-E8E7-4993-BEC3-5CAEC3D48E47}"); + static void Reflect(AZ::ReflectContext* context); + + StartMatchmakingRequest() = default; + virtual ~StartMatchmakingRequest() = default; + + // A unique identifier for a matchmaking ticket + AZStd::string m_ticketId; + }; + + //! StopMatchmakingRequest + //! The container for StopMatchmaking request parameters. + struct StopMatchmakingRequest + { + AZ_RTTI(StopMatchmakingRequest, "{6132E293-65EF-4DC2-A8A0-00269697229D}"); + static void Reflect(AZ::ReflectContext* context); + + StopMatchmakingRequest() = default; + virtual ~StopMatchmakingRequest() = default; + + // A unique identifier for a matchmaking ticket + AZStd::string m_ticketId; + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h b/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h index 0323686442..bdc3fe1444 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h +++ b/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h @@ -10,98 +10,11 @@ #include #include -#include #include -#include +#include namespace AzFramework { - struct SessionConfig; - - //! CreateSessionRequest - //! The container for CreateSession request parameters. - struct CreateSessionRequest - { - AZ_RTTI(CreateSessionRequest, "{E39C2A45-89C9-4CFB-B337-9734DC798930}"); - static void Reflect(AZ::ReflectContext* context); - - CreateSessionRequest() = default; - virtual ~CreateSessionRequest() = default; - - // A unique identifier for a player or entity creating the session. - AZStd::string m_creatorId; - - // A collection of custom properties for a session. - AZStd::unordered_map m_sessionProperties; - - // A descriptive label that is associated with a session. - AZStd::string m_sessionName; - - // The maximum number of players that can be connected simultaneously to the session. - uint64_t m_maxPlayer = 0; - }; - - //! SearchSessionsRequest - //! The container for SearchSessions request parameters. - struct SearchSessionsRequest - { - AZ_RTTI(SearchSessionsRequest, "{B49207A8-8549-4ADB-B7D9-D7A4932F9B4B}"); - static void Reflect(AZ::ReflectContext* context); - - SearchSessionsRequest() = default; - virtual ~SearchSessionsRequest() = default; - - // String containing the search criteria for the session search. If no filter expression is included, the request returns results - // for all active sessions. - AZStd::string m_filterExpression; - - // Instructions on how to sort the search results. If no sort expression is included, the request returns results in random order. - AZStd::string m_sortExpression; - - // The maximum number of results to return. - uint8_t m_maxResult = 0; - - // A token that indicates the start of the next sequential page of results. - AZStd::string m_nextToken; - }; - - //! SearchSessionsResponse - //! The container for SearchSession request results. - struct SearchSessionsResponse - { - AZ_RTTI(SearchSessionsResponse, "{F93DE7DC-D381-4E08-8A3B-0B08F7C38714}"); - static void Reflect(AZ::ReflectContext* context); - - SearchSessionsResponse() = default; - virtual ~SearchSessionsResponse() = default; - - // A collection of sessions that match the search criteria and sorted in specific order. - AZStd::vector m_sessionConfigs; - - // A token that indicates the start of the next sequential page of results. - AZStd::string m_nextToken; - }; - - //! JoinSessionRequest - //! The container for JoinSession request parameters. - struct JoinSessionRequest - { - AZ_RTTI(JoinSessionRequest, "{519769E8-3CDE-4385-A0D7-24DBB3685657}"); - static void Reflect(AZ::ReflectContext* context); - - JoinSessionRequest() = default; - virtual ~JoinSessionRequest() = default; - - // A unique identifier for the session. - AZStd::string m_sessionId; - - // A unique identifier for a player. Player IDs are developer-defined. - AZStd::string m_playerId; - - // Developer-defined information related to a player. - AZStd::string m_playerData; - }; - //! ISessionRequests //! Pure virtual session interface class to abstract the details of session handling from application code. class ISessionRequests diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.cpp b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.cpp similarity index 98% rename from Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.cpp rename to Code/Framework/AzFramework/AzFramework/Session/SessionRequests.cpp index 5536d9a47d..a7ffaa2491 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.cpp +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.cpp @@ -6,9 +6,10 @@ * */ +#include #include #include -#include +#include #include namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h new file mode 100644 index 0000000000..1ae018e1ef --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AZ +{ + class ReflectContext; +} + +namespace AzFramework +{ + struct SessionConfig; + + //! CreateSessionRequest + //! The container for CreateSession request parameters. + struct CreateSessionRequest + { + AZ_RTTI(CreateSessionRequest, "{E39C2A45-89C9-4CFB-B337-9734DC798930}"); + static void Reflect(AZ::ReflectContext* context); + + CreateSessionRequest() = default; + virtual ~CreateSessionRequest() = default; + + // A unique identifier for a player or entity creating the session. + AZStd::string m_creatorId; + + // A collection of custom properties for a session. + AZStd::unordered_map m_sessionProperties; + + // A descriptive label that is associated with a session. + AZStd::string m_sessionName; + + // The maximum number of players that can be connected simultaneously to the session. + uint64_t m_maxPlayer = 0; + }; + + //! SearchSessionsRequest + //! The container for SearchSessions request parameters. + struct SearchSessionsRequest + { + AZ_RTTI(SearchSessionsRequest, "{B49207A8-8549-4ADB-B7D9-D7A4932F9B4B}"); + static void Reflect(AZ::ReflectContext* context); + + SearchSessionsRequest() = default; + virtual ~SearchSessionsRequest() = default; + + // String containing the search criteria for the session search. If no filter expression is included, the request returns results + // for all active sessions. + AZStd::string m_filterExpression; + + // Instructions on how to sort the search results. If no sort expression is included, the request returns results in random order. + AZStd::string m_sortExpression; + + // The maximum number of results to return. + uint8_t m_maxResult = 0; + + // A token that indicates the start of the next sequential page of results. + AZStd::string m_nextToken; + }; + + //! SearchSessionsResponse + //! The container for SearchSession request results. + struct SearchSessionsResponse + { + AZ_RTTI(SearchSessionsResponse, "{F93DE7DC-D381-4E08-8A3B-0B08F7C38714}"); + static void Reflect(AZ::ReflectContext* context); + + SearchSessionsResponse() = default; + virtual ~SearchSessionsResponse() = default; + + // A collection of sessions that match the search criteria and sorted in specific order. + AZStd::vector m_sessionConfigs; + + // A token that indicates the start of the next sequential page of results. + AZStd::string m_nextToken; + }; + + //! JoinSessionRequest + //! The container for JoinSession request parameters. + struct JoinSessionRequest + { + AZ_RTTI(JoinSessionRequest, "{519769E8-3CDE-4385-A0D7-24DBB3685657}"); + static void Reflect(AZ::ReflectContext* context); + + JoinSessionRequest() = default; + virtual ~JoinSessionRequest() = default; + + // A unique identifier for the session. + AZStd::string m_sessionId; + + // A unique identifier for a player. Player IDs are developer-defined. + AZStd::string m_playerId; + + // Developer-defined information related to a player. + AZStd::string m_playerData; + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index e752e5ae04..c5616d84c0 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -167,6 +167,10 @@ set(FILES Logging/MissingAssetLogger.cpp Logging/MissingAssetLogger.h Logging/MissingAssetNotificationBus.h + Matchmaking/IMatchmakingRequests.h + Matchmaking/MatchmakingRequests.cpp + Matchmaking/MatchmakingRequests.h + Matchmaking/MatchmakingNotifications.h Scene/Scene.h Scene/Scene.inl Scene/Scene.cpp @@ -181,8 +185,9 @@ set(FILES Script/ScriptRemoteDebugging.cpp Script/ScriptRemoteDebugging.h Session/ISessionHandlingRequests.h - Session/ISessionRequests.cpp Session/ISessionRequests.h + Session/SessionRequests.cpp + Session/SessionRequests.h Session/SessionConfig.cpp Session/SessionConfig.h Session/SessionNotifications.h diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h new file mode 100644 index 0000000000..415550b6bc --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AWSGameLift +{ + //! AWSGameLiftAcceptMatchRequest + //! GameLift accept match request which corresponds to Amazon GameLift + //! Registers a player's acceptance or rejection of a proposed FlexMatch match. + //! AcceptMatchRequest + struct AWSGameLiftAcceptMatchRequest + : public AzFramework::AcceptMatchRequest + { + public: + AZ_RTTI(AWSGameLiftAcceptMatchRequest, "{8372B297-88E8-4C13-B31D-BE87236CA416}", AzFramework::AcceptMatchRequest); + static void Reflect(AZ::ReflectContext* context); + + AWSGameLiftAcceptMatchRequest() = default; + virtual ~AWSGameLiftAcceptMatchRequest() = default; + }; +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h index be2c766d7e..a9b06c5bc9 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h index 75440868c9..4fab16ca70 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h index 32f549c7d5..07d6da3870 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h index 655c83252e..bfc2dc630e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h new file mode 100644 index 0000000000..cd30bc45ab --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AWSGameLift +{ + //! AWSGameLiftPlayerInformation + //! Information on each player to be matched + //! This information must include a player ID, and may contain player attributes and latency data to be used in the matchmaking process + //! After a successful match, Player objects contain the name of the team the player is assigned to + struct AWSGameLiftPlayerInformation + { + AZ_RTTI(AWSGameLiftPlayerInformation, "{B62C118E-C55D-4903-8ECB-E58E8CA613C4}"); + static void Reflect(AZ::ReflectContext* context); + + AWSGameLiftPlayerInformation() = default; + virtual ~AWSGameLiftPlayerInformation() = default; + + // A map of region names to latencies in millseconds, that indicates + // the amount of latency that a player experiences when connected to AWS Regions + AZStd::unordered_map m_latencyInMs; + // A collection of key:value pairs containing player information for use in matchmaking + // Player attribute keys must match the playerAttributes used in a matchmaking rule set + // Example: {"skill": "{\"N\": \"23\"}", "gameMode": "{\"S\": \"deathmatch\"}"} + AZStd::unordered_map m_playerAttributes; + // A unique identifier for a player + AZStd::string m_playerId; + // Name of the team that the player is assigned to in a match + AZStd::string m_team; + }; + + //! AWSGameLiftStartMatchmakingRequest + //! GameLift start matchmaking request which corresponds to Amazon GameLift + //! Uses FlexMatch to create a game match for a group of players based on custom matchmaking rules + //! StartMatchmakingRequest + struct AWSGameLiftStartMatchmakingRequest + : public AzFramework::StartMatchmakingRequest + { + public: + AZ_RTTI(AWSGameLiftStartMatchmakingRequest, "{D273DF71-9C55-48C1-95F9-8D7B66B9CF3E}", AzFramework::StartMatchmakingRequest); + static void Reflect(AZ::ReflectContext* context); + + AWSGameLiftStartMatchmakingRequest() = default; + virtual ~AWSGameLiftStartMatchmakingRequest() = default; + + // Name of the matchmaking configuration to use for this request + AZStd::string m_configurationName; + // Information on each player to be matched + AZStd::vector m_players; + }; +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h new file mode 100644 index 0000000000..81d811d32d --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AWSGameLift +{ + //! AWSGameLiftStopMatchmakingRequest + //! GameLift stop matchmaking request which corresponds to Amazon GameLift + //! Cancels a matchmaking ticket or match backfill ticket that is currently being processed. + //! StopMatchmakingRequest + struct AWSGameLiftStopMatchmakingRequest + : public AzFramework::StopMatchmakingRequest + { + public: + AZ_RTTI(AWSGameLiftStopMatchmakingRequest, "{2766BC03-9F84-4346-A52B-49129BBAF38B}", AzFramework::StopMatchmakingRequest); + static void Reflect(AZ::ReflectContext* context); + + AWSGameLiftStopMatchmakingRequest() = default; + virtual ~AWSGameLiftStopMatchmakingRequest() = default; + }; +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/IAWSGameLiftRequests.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/IAWSGameLiftRequests.h index 25445553f4..10269dc8c3 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/IAWSGameLiftRequests.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/IAWSGameLiftRequests.h @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace AWSGameLift @@ -71,4 +72,26 @@ namespace AWSGameLift static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; }; using AWSGameLiftSessionRequestBus = AZ::EBus; + + // IMatchmakingAsyncRequests EBus wrapper for scripting + class AWSGameLiftMatchmakingAsyncRequests + : public AZ::EBusTraits + { + public: + using MutexType = AZStd::recursive_mutex; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + }; + using AWSGameLiftMatchmakingAsyncRequestBus = AZ::EBus; + + // IMatchmakingRequests EBus wrapper for scripting + class AWSGameLiftMatchmakingRequests + : public AZ::EBusTraits + { + public: + using MutexType = AZStd::recursive_mutex; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + }; + using AWSGameLiftMatchmakingRequestBus = AZ::EBus; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp index f9249d1ad2..ae4fb162d6 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp @@ -112,6 +112,16 @@ namespace AWSGameLift return AZ::Uuid::CreateRandom().ToString(includeBrackets, includeDashes); } + void AWSGameLiftClientManager::AcceptMatch(const AzFramework::AcceptMatchRequest& acceptMatchRequest) + { + AZ_UNUSED(acceptMatchRequest); + } + + void AWSGameLiftClientManager::AcceptMatchAsync(const AzFramework::AcceptMatchRequest& acceptMatchRequest) + { + AZ_UNUSED(acceptMatchRequest); + } + AZStd::string AWSGameLiftClientManager::CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest) { AZStd::string result = ""; @@ -349,6 +359,28 @@ namespace AWSGameLift return response; } + AZStd::string AWSGameLiftClientManager::StartMatchmaking(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) + { + AZ_UNUSED(startMatchmakingRequest); + + return AZStd::string{}; + } + + void AWSGameLiftClientManager::StartMatchmakingAsync(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) + { + AZ_UNUSED(startMatchmakingRequest); + } + + void AWSGameLiftClientManager::StopMatchmaking(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) + { + AZ_UNUSED(stopMatchmakingRequest); + } + + void AWSGameLiftClientManager::StopMatchmakingAsync(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) + { + AZ_UNUSED(stopMatchmakingRequest); + } + void AWSGameLiftClientManager::SetGameLiftClient(AZStd::shared_ptr gameliftClient) { m_gameliftClient.swap(gameliftClient); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h index 1b9296d20a..d7211d0472 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h @@ -9,6 +9,8 @@ #pragma once #include +#include + #include namespace Aws @@ -26,6 +28,54 @@ namespace AWSGameLift struct AWSGameLiftJoinSessionRequest; struct AWSGameLiftSearchSessionsRequest; + // MatchAcceptanceNotificationBus EBus handler for scripting + class AWSGameLiftMatchAcceptanceNotificationBusHandler + : public AzFramework::MatchAcceptanceNotificationBus::Handler + , public AZ::BehaviorEBusHandler + { + public: + AZ_EBUS_BEHAVIOR_BINDER( + AWSGameLiftMatchAcceptanceNotificationBusHandler, + "{CBE057D3-F5CE-46D3-B02D-8A6A1446B169}", + AZ::SystemAllocator, + OnMatchAcceptance); + + void OnMatchAcceptance() override + { + Call(FN_OnMatchAcceptance); + } + }; + + // MatchmakingAsyncRequestNotificationBus EBus handler for scripting + class AWSGameLiftMatchmakingAsyncRequestNotificationBusHandler + : public AzFramework::MatchmakingAsyncRequestNotificationBus::Handler + , public AZ::BehaviorEBusHandler + { + public: + AZ_EBUS_BEHAVIOR_BINDER( + AWSGameLiftMatchmakingAsyncRequestNotificationBusHandler, + "{2045EE8F-2AB7-4ED0-9614-3496A1A43677}", + AZ::SystemAllocator, + OnAcceptMatchAsyncComplete, + OnStartMatchmakingAsyncComplete, + OnStopMatchmakingAsyncComplete); + + void OnAcceptMatchAsyncComplete() override + { + Call(FN_OnAcceptMatchAsyncComplete); + } + + void OnStartMatchmakingAsyncComplete(const AZStd::string& matchmakingTicketId) override + { + Call(FN_OnStartMatchmakingAsyncComplete, matchmakingTicketId); + } + + void OnStopMatchmakingAsyncComplete() override + { + Call(FN_OnStopMatchmakingAsyncComplete); + } + }; + // SessionAsyncRequestNotificationBus EBus handler for scripting class AWSGameLiftSessionAsyncRequestNotificationBusHandler : public AzFramework::SessionAsyncRequestNotificationBus::Handler @@ -66,6 +116,8 @@ namespace AWSGameLift //! GameLift client manager to support game and player session related client requests class AWSGameLiftClientManager : public AWSGameLiftRequestBus::Handler + , public AWSGameLiftMatchmakingAsyncRequestBus::Handler + , public AWSGameLiftMatchmakingRequestBus::Handler , public AWSGameLiftSessionAsyncRequestBus::Handler , public AWSGameLiftSessionRequestBus::Handler { @@ -91,12 +143,22 @@ namespace AWSGameLift bool ConfigureGameLiftClient(const AZStd::string& region) override; AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) override; + // AWSGameLiftMatchmakingAsyncRequestBus interface implementation + void AcceptMatchAsync(const AzFramework::AcceptMatchRequest& acceptMatchRequest) override; + void StartMatchmakingAsync(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) override; + void StopMatchmakingAsync(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) override; + // AWSGameLiftSessionAsyncRequestBus interface implementation void CreateSessionAsync(const AzFramework::CreateSessionRequest& createSessionRequest) override; void JoinSessionAsync(const AzFramework::JoinSessionRequest& joinSessionRequest) override; void SearchSessionsAsync(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override; void LeaveSessionAsync() override; + // AWSGameLiftMatchmakingRequestBus interface implementation + void AcceptMatch(const AzFramework::AcceptMatchRequest& acceptMatchRequest) override; + AZStd::string StartMatchmaking(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) override; + void StopMatchmaking(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) override; + // AWSGameLiftSessionRequestBus interface implementation AZStd::string CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest) override; bool JoinSession(const AzFramework::JoinSessionRequest& joinSessionRequest) override; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp index ceb7376b85..db201920f6 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp @@ -13,10 +13,13 @@ #include #include +#include #include #include #include #include +#include +#include #include @@ -29,18 +32,13 @@ namespace AWSGameLift void AWSGameLiftClientSystemComponent::Reflect(AZ::ReflectContext* context) { - ReflectCreateSessionRequest(context); - AWSGameLiftCreateSessionOnQueueRequest::Reflect(context); - AWSGameLiftCreateSessionRequest::Reflect(context); - AWSGameLiftJoinSessionRequest::Reflect(context); - AWSGameLiftSearchSessionsRequest::Reflect(context); - ReflectSearchSessionsResponse(context); + ReflectGameLiftMatchmaking(context); + ReflectGameLiftSession(context); if (AZ::SerializeContext* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(0) - ; + ->Version(1); if (AZ::EditContext* editContext = serialize->GetEditContext()) { @@ -50,8 +48,7 @@ namespace AWSGameLift "Create the GameLift client manager that handles communication between game clients and the GameLift service.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ; + ->Attribute(AZ::Edit::Attributes::AutoExpand, true); } } @@ -63,33 +60,7 @@ namespace AWSGameLift {{{"Region", ""}}}) ->Event("CreatePlayerId", &AWSGameLiftRequestBus::Events::CreatePlayerId, {{{"IncludeBrackets", ""}, - {"IncludeDashes", ""}}}) - ; - behaviorContext->EBus("AWSGameLiftSessionAsyncRequestBus") - ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") - ->Event("CreateSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::CreateSessionAsync, - {{{"CreateSessionRequest", ""}}}) - ->Event("JoinSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::JoinSessionAsync, - {{{"JoinSessionRequest", ""}}}) - ->Event("SearchSessionsAsync", &AWSGameLiftSessionAsyncRequestBus::Events::SearchSessionsAsync, - {{{"SearchSessionsRequest", ""}}}) - ->Event("LeaveSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::LeaveSessionAsync) - ; - behaviorContext - ->EBus("AWSGameLiftSessionAsyncRequestNotificationBus") - ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") - ->Handler() - ; - behaviorContext->EBus("AWSGameLiftSessionRequestBus") - ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") - ->Event("CreateSession", &AWSGameLiftSessionRequestBus::Events::CreateSession, - {{{"CreateSessionRequest", ""}}}) - ->Event("JoinSession", &AWSGameLiftSessionRequestBus::Events::JoinSession, - {{{"JoinSessionRequest", ""}}}) - ->Event("SearchSessions", &AWSGameLiftSessionRequestBus::Events::SearchSessions, - {{{"SearchSessionsRequest", ""}}}) - ->Event("LeaveSession", &AWSGameLiftSessionRequestBus::Events::LeaveSession) - ; + {"IncludeDashes", ""}}}); } } @@ -126,6 +97,74 @@ namespace AWSGameLift { m_gameliftClientManager->DeactivateManager(); } + + void AWSGameLiftClientSystemComponent::ReflectGameLiftMatchmaking(AZ::ReflectContext* context) + { + AWSGameLiftAcceptMatchRequest::Reflect(context); + AWSGameLiftStartMatchmakingRequest::Reflect(context); + AWSGameLiftStopMatchmakingRequest::Reflect(context); + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("AWSGameLiftMatchmakingAsyncRequestBus") + ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") + ->Event("AcceptMatchAsync", &AWSGameLiftMatchmakingAsyncRequestBus::Events::AcceptMatchAsync, + { { { "AcceptMatchRequest", "" } } }) + ->Event("StartMatchmakingAsync", &AWSGameLiftMatchmakingAsyncRequestBus::Events::StartMatchmakingAsync, + { { { "StartMatchmakingRequest", "" } } }) + ->Event("StopMatchmakingAsync", &AWSGameLiftMatchmakingAsyncRequestBus::Events::StopMatchmakingAsync, + { { { "StopMatchmakingRequest", "" } } }); + + behaviorContext->EBus("AWSGameLiftMatchmakingAsyncRequestNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") + ->Handler(); + + behaviorContext->EBus("AWSGameLiftMatchmakingRequestBus") + ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") + ->Event("AcceptMatch", &AWSGameLiftMatchmakingRequestBus::Events::AcceptMatch, { { { "AcceptMatchRequest", "" } } }) + ->Event("StartMatchmaking", &AWSGameLiftMatchmakingRequestBus::Events::StartMatchmaking, + { { { "StartMatchmakingRequest", "" } } }) + ->Event("StopMatchmaking", &AWSGameLiftMatchmakingRequestBus::Events::StopMatchmaking, + { { { "StopMatchmakingRequest", "" } } }); + + behaviorContext->EBus("AWSGameLiftMatchAcceptanceNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") + ->Handler(); + } + } + + void AWSGameLiftClientSystemComponent::ReflectGameLiftSession(AZ::ReflectContext* context) + { + ReflectCreateSessionRequest(context); + AWSGameLiftCreateSessionOnQueueRequest::Reflect(context); + AWSGameLiftCreateSessionRequest::Reflect(context); + AWSGameLiftJoinSessionRequest::Reflect(context); + AWSGameLiftSearchSessionsRequest::Reflect(context); + ReflectSearchSessionsResponse(context); + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("AWSGameLiftSessionAsyncRequestBus") + ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") + ->Event("CreateSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::CreateSessionAsync, + { { { "CreateSessionRequest", "" } } }) + ->Event("JoinSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::JoinSessionAsync, { { { "JoinSessionRequest", "" } } }) + ->Event("SearchSessionsAsync", &AWSGameLiftSessionAsyncRequestBus::Events::SearchSessionsAsync, + { { { "SearchSessionsRequest", "" } } }) + ->Event("LeaveSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::LeaveSessionAsync); + + behaviorContext->EBus("AWSGameLiftSessionAsyncRequestNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") + ->Handler(); + + behaviorContext->EBus("AWSGameLiftSessionRequestBus") + ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift") + ->Event("CreateSession", &AWSGameLiftSessionRequestBus::Events::CreateSession, { { { "CreateSessionRequest", "" } } }) + ->Event("JoinSession", &AWSGameLiftSessionRequestBus::Events::JoinSession, { { { "JoinSessionRequest", "" } } }) + ->Event("SearchSessions", &AWSGameLiftSessionRequestBus::Events::SearchSessions, { { { "SearchSessionsRequest", "" } } }) + ->Event("LeaveSession", &AWSGameLiftSessionRequestBus::Events::LeaveSession); + } + } void AWSGameLiftClientSystemComponent::ReflectCreateSessionRequest(AZ::ReflectContext* context) { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h index bac24d44fa..f54461b918 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h @@ -43,6 +43,9 @@ namespace AWSGameLift void SetGameLiftClientManager(AZStd::unique_ptr gameliftClientManager); private: + static void ReflectGameLiftMatchmaking(AZ::ReflectContext* context); + static void ReflectGameLiftSession(AZ::ReflectContext* context); + static void ReflectCreateSessionRequest(AZ::ReflectContext* context); static void ReflectSearchSessionsResponse(AZ::ReflectContext* context); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp new file mode 100644 index 0000000000..8a8327b92b --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +#include + +namespace AWSGameLift +{ + void AWSGameLiftAcceptMatchRequest::Reflect(AZ::ReflectContext* context) + { + AzFramework::AcceptMatchRequest::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("AWSGameLiftAcceptMatchRequest", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AWSGameLiftAcceptMatchRequest") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("AcceptMatch", BehaviorValueProperty(&AWSGameLiftAcceptMatchRequest::m_acceptMatch)) + ->Property("PlayerIds", BehaviorValueProperty(&AWSGameLiftAcceptMatchRequest::m_playerIds)) + ->Property("TicketId", BehaviorValueProperty(&AWSGameLiftAcceptMatchRequest::m_ticketId)); + } + } +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp new file mode 100644 index 0000000000..03d802fd36 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +#include + +namespace AWSGameLift +{ + void AWSGameLiftPlayerInformation::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("latencyInMs", &AWSGameLiftPlayerInformation::m_latencyInMs) + ->Field("playerAttributes", &AWSGameLiftPlayerInformation::m_playerAttributes) + ->Field("playerId", &AWSGameLiftPlayerInformation::m_playerId) + ->Field("team", &AWSGameLiftPlayerInformation::m_team); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("AWSGameLiftPlayerInformation", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_latencyInMs, "LatencyInMs", + "A set of values, expressed in milliseconds, that indicates the amount of latency that" + "a player experiences when connected to AWS Regions") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_playerAttributes, "PlayerAttributes", + "A collection of key:value pairs containing player information for use in matchmaking") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_playerId, "PlayerId", + "A unique identifier for a player") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_team, "Team", + "Name of the team that the player is assigned to in a match"); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AWSGameLiftPlayerInformation") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("LatencyInMs", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_latencyInMs)) + ->Property("PlayerAttributes", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_playerAttributes)) + ->Property("PlayerId", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_playerId)) + ->Property("Team", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_team)); + } + } + + void AWSGameLiftStartMatchmakingRequest::Reflect(AZ::ReflectContext* context) + { + AzFramework::StartMatchmakingRequest::Reflect(context); + AWSGameLiftPlayerInformation::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("configurationName", &AWSGameLiftStartMatchmakingRequest::m_configurationName) + ->Field("players", &AWSGameLiftStartMatchmakingRequest::m_players); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("AWSGameLiftStartMatchmakingRequest", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement(AZ::Edit::UIHandlers::Default, &AWSGameLiftStartMatchmakingRequest::m_configurationName, "ConfigurationName", + "Name of the matchmaking configuration to use for this request") + ->DataElement(AZ::Edit::UIHandlers::Default, &AWSGameLiftStartMatchmakingRequest::m_players, "Players", + "Information on each player to be matched."); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AWSGameLiftStartMatchmakingRequest") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("TicketId", BehaviorValueProperty(&AWSGameLiftStartMatchmakingRequest::m_ticketId)) + ->Property("ConfigurationName", BehaviorValueProperty(&AWSGameLiftStartMatchmakingRequest::m_configurationName)) + ->Property("Players", BehaviorValueProperty(&AWSGameLiftStartMatchmakingRequest::m_players)); + } + } +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp new file mode 100644 index 0000000000..bcea1fa8fe --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +#include + +namespace AWSGameLift +{ + void AWSGameLiftStopMatchmakingRequest::Reflect(AZ::ReflectContext* context) + { + AzFramework::StopMatchmakingRequest::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("AWSGameLiftStopMatchmakingRequest", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AWSGameLiftStopMatchmakingRequest") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("TicketId", BehaviorValueProperty(&AWSGameLiftStopMatchmakingRequest::m_ticketId)); + } + } +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake index 771bdf0c08..0c7ca68eea 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake @@ -7,10 +7,13 @@ # set(FILES + Include/Request/AWSGameLiftAcceptMatchRequest.h Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h Include/Request/AWSGameLiftCreateSessionRequest.h Include/Request/AWSGameLiftJoinSessionRequest.h Include/Request/AWSGameLiftSearchSessionsRequest.h + Include/Request/AWSGameLiftStartMatchmakingRequest.h + Include/Request/AWSGameLiftStopMatchmakingRequest.h Include/Request/IAWSGameLiftRequests.h Source/Activity/AWSGameLiftActivityUtils.cpp Source/Activity/AWSGameLiftActivityUtils.h @@ -28,8 +31,11 @@ set(FILES Source/AWSGameLiftClientManager.h Source/AWSGameLiftClientSystemComponent.cpp Source/AWSGameLiftClientSystemComponent.h + Source/Request/AWSGameLiftAcceptMatchRequest.cpp Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp Source/Request/AWSGameLiftCreateSessionRequest.cpp Source/Request/AWSGameLiftJoinSessionRequest.cpp Source/Request/AWSGameLiftSearchSessionsRequest.cpp + Source/Request/AWSGameLiftStartMatchmakingRequest.cpp + Source/Request/AWSGameLiftStopMatchmakingRequest.cpp ) From ee5ab1770bdd4d6beeae1117a763934affd13617 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Mon, 4 Oct 2021 15:54:50 -0700 Subject: [PATCH 071/293] [XCB] Respond to keyboard state changes This allows the keyboard to correctly store modifier keys, as the keyboard state changes. Signed-off-by: Chris Burel --- .../AzFramework/XcbInputDeviceKeyboard.cpp | 103 ++++++++++++++---- .../Xcb/AzFramework/XcbInputDeviceKeyboard.h | 5 + 2 files changed, 89 insertions(+), 19 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp index c971c3b793..d9db239522 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp @@ -20,6 +20,15 @@ namespace AzFramework { + // xcb-xkb does not provide a generic event type, so we define our own. + // These fields are enough to get to the xkbType field, which can then be + // read to typecast the event to the right concrete type. + struct XcbXkbGenericEventT + { + uint8_t response_type; + uint8_t xkbType; + }; + XcbInputDeviceKeyboard::XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice) : InputDeviceKeyboard::Implementation(inputDevice) { @@ -39,19 +48,22 @@ namespace AzFramework return; } - XcbStdFreePtr xkbUseExtensionReply{ - xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr) - }; - if (!xkbUseExtensionReply) + int initializeXkbExtensionSuccess = xkb_x11_setup_xkb_extension( + connection, + 1, + 0, + XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, + nullptr, + nullptr, + &m_xkbEventCode, + nullptr + ); + + if (!initializeXkbExtensionSuccess) { AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension"); return; } - if (!xkbUseExtensionReply->supported) - { - AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension"); - return; - } m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection); @@ -59,6 +71,43 @@ namespace AzFramework m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS)); m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId)); + const uint16_t affectMap = + XCB_XKB_MAP_PART_KEY_TYPES + | XCB_XKB_MAP_PART_KEY_SYMS + | XCB_XKB_MAP_PART_MODIFIER_MAP + | XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS + | XCB_XKB_MAP_PART_KEY_ACTIONS + | XCB_XKB_MAP_PART_KEY_BEHAVIORS + | XCB_XKB_MAP_PART_VIRTUAL_MODS + | XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP + ; + + const uint16_t selectedEvents = + XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY + | XCB_XKB_EVENT_TYPE_MAP_NOTIFY + | XCB_XKB_EVENT_TYPE_STATE_NOTIFY + ; + + XcbStdFreePtr error{xcb_request_check( + connection, + xcb_xkb_select_events( + connection, + /* deviceSpec = */ XCB_XKB_ID_USE_CORE_KBD, + /* affectWhich = */ selectedEvents, + /* clear = */ 0, + /* selectAll = */ selectedEvents, + /* affectMap = */ affectMap, + /* map = */ affectMap, + /* details = */ nullptr + ) + )}; + + if (error) + { + AZ_Warning("ApplicationLinux", false, "failed to select notify events from XKB"); + return; + } + m_initialized = true; } @@ -93,30 +142,38 @@ namespace AzFramework return; } - switch (event->response_type & ~0x80) + const auto responseType = event->response_type & ~0x80; + if (responseType == XCB_KEY_PRESS) { - case XCB_KEY_PRESS: - { - auto* keyPress = reinterpret_cast(event); + const auto* keyPress = reinterpret_cast(event); - const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail); - if (key) + if (const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail)) { QueueRawKeyEvent(*key, true); } - break; } - case XCB_KEY_RELEASE: + else if (responseType == XCB_KEY_RELEASE) { - auto* keyRelease = reinterpret_cast(event); + const auto* keyRelease = reinterpret_cast(event); const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail); if (key) { QueueRawKeyEvent(*key, false); } - break; } + else if (responseType == m_xkbEventCode) + { + const auto* xkbEvent = reinterpret_cast(event); + switch (xkbEvent->xkbType) + { + case XCB_XKB_STATE_NOTIFY: + { + const auto* stateNotifyEvent = reinterpret_cast(event); + UpdateState(stateNotifyEvent); + break; + } + } } } @@ -268,4 +325,12 @@ namespace AzFramework default: return nullptr; } } + + void XcbInputDeviceKeyboard::UpdateState(const xcb_xkb_state_notify_event_t* state) + { + if (m_initialized) + { + xkb_state_update_mask(m_xkbState.get(), state->baseMods, state->latchedMods, state->lockedMods, state->baseGroup, state->latchedGroup, state->lockedGroup); + } + } } // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h index de65941a67..9adc9ad758 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h @@ -13,6 +13,8 @@ #include #include +struct xcb_xkb_state_notify_event_t; + namespace AzFramework { class XcbInputDeviceKeyboard @@ -37,10 +39,13 @@ namespace AzFramework private: [[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const; + void UpdateState(const xcb_xkb_state_notify_event_t* state); + XcbUniquePtr m_xkbContext; XcbUniquePtr m_xkbKeymap; XcbUniquePtr m_xkbState; int m_coreDeviceId{-1}; + uint8_t m_xkbEventCode{0}; bool m_initialized{false}; }; } // namespace AzFramework From ba4842675065fde92054af9f17f39033d797549d Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Mon, 4 Oct 2021 15:56:04 -0700 Subject: [PATCH 072/293] [XCB] Generate raw text events as well as key press events Fixes LYN-6997 Signed-off-by: Chris Burel --- .../AzFramework/XcbInputDeviceKeyboard.cpp | 28 ++++++++++++++++++- .../Xcb/AzFramework/XcbInputDeviceKeyboard.h | 3 ++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp index d9db239522..454313ec5b 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp @@ -119,15 +119,17 @@ namespace AzFramework bool XcbInputDeviceKeyboard::HasTextEntryStarted() const { - return false; + return m_hasTextEntryStarted; } void XcbInputDeviceKeyboard::TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) { + m_hasTextEntryStarted = true; } void XcbInputDeviceKeyboard::TextEntryStop() { + m_hasTextEntryStarted = false; } void XcbInputDeviceKeyboard::TickInputDevice() @@ -147,6 +149,8 @@ namespace AzFramework { const auto* keyPress = reinterpret_cast(event); + QueueRawTextEvent(TextFromKeycode(m_xkbState.get(), keyPress->detail)); + if (const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail)) { QueueRawKeyEvent(*key, true); @@ -326,6 +330,28 @@ namespace AzFramework } } + AZStd::string XcbInputDeviceKeyboard::TextFromKeycode(xkb_state* state, xkb_keycode_t code) + { + // Find out how much of a buffer we need + const size_t size = xkb_state_key_get_utf8(state, code, nullptr, 0); + if (!size) + { + return {}; + } + // xkb_state_key_get_utf8 will null-terminate the resulting string, and + // will truncate the result to `size - 1` if there is not enough space + // for the null byte. The first call returns the size of the resulting + // string without including the null byte. AZStd::string internally + // includes space for the null byte, but that is not included in its + // `size()`. xkb_state_key_get_utf8 will always set `buf[size - 1] = + // 0`, so add 1 to `chars.size()` to include that internal null byte in + // the string. + AZStd::string chars; + chars.resize_no_construct(size); + xkb_state_key_get_utf8(state, code, chars.data(), chars.size() + 1); + return chars; + } + void XcbInputDeviceKeyboard::UpdateState(const xcb_xkb_state_notify_event_t* state) { if (m_initialized) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h index 9adc9ad758..00383abf6c 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h @@ -39,6 +39,8 @@ namespace AzFramework private: [[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const; + static AZStd::string TextFromKeycode(xkb_state* state, xkb_keycode_t code); + void UpdateState(const xcb_xkb_state_notify_event_t* state); XcbUniquePtr m_xkbContext; @@ -47,5 +49,6 @@ namespace AzFramework int m_coreDeviceId{-1}; uint8_t m_xkbEventCode{0}; bool m_initialized{false}; + bool m_hasTextEntryStarted{false}; }; } // namespace AzFramework From b1b52c201f085afcf8c472a2ea3f2225311918e2 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 5 Oct 2021 12:12:40 -0700 Subject: [PATCH 073/293] [XCB] Add test fixtures for xcb connection and keyboard setup Signed-off-by: Chris Burel --- .../Platform/Common/Xcb/MockXcbInterface.cpp | 38 +++++- .../Platform/Common/Xcb/MockXcbInterface.h | 17 ++- .../Common/Xcb/XcbBaseTestFixture.cpp | 25 ++++ .../Platform/Common/Xcb/XcbBaseTestFixture.h | 29 +++++ .../Xcb/XcbInputDeviceKeyboardTests.cpp | 121 +++++++++++------- .../Xcb/azframework_xcb_tests_files.cmake | 2 + 6 files changed, 177 insertions(+), 55 deletions(-) create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.cpp create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.h diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp index 64c3967fdc..4797f1133d 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp @@ -28,6 +28,10 @@ xcb_generic_event_t* xcb_poll_for_event(xcb_connection_t* c) { return MockXcbInterface::Instance()->xcb_poll_for_event(c); } +xcb_generic_error_t* xcb_request_check(xcb_connection_t* c, xcb_void_cookie_t cookie) +{ + return MockXcbInterface::Instance()->xcb_request_check(c, cookie); +} // ---------------------------------------------------------------------------- // xcb-xkb @@ -39,6 +43,10 @@ xcb_xkb_use_extension_reply_t* xcb_xkb_use_extension_reply(xcb_connection_t* c, { return MockXcbInterface::Instance()->xcb_xkb_use_extension_reply(c, cookie, e); } +xcb_void_cookie_t xcb_xkb_select_events(xcb_connection_t* c, xcb_xkb_device_spec_t deviceSpec, uint16_t affectWhich, uint16_t clear, uint16_t selectAll, uint16_t affectMap, uint16_t map, const void* details) +{ + return MockXcbInterface::Instance()->xcb_xkb_select_events(c, deviceSpec, affectWhich, clear, selectAll, affectMap, map, details); +} // ---------------------------------------------------------------------------- // xkb-x11 @@ -46,7 +54,7 @@ int32_t xkb_x11_get_core_keyboard_device_id(xcb_connection_t* connection) { return MockXcbInterface::Instance()->xkb_x11_get_core_keyboard_device_id(connection); } -struct xkb_keymap* xkb_x11_keymap_new_from_device(struct xkb_context* context, xcb_connection_t* connection, int32_t device_id, enum xkb_keymap_compile_flags flags) +xkb_keymap* xkb_x11_keymap_new_from_device(xkb_context* context, xcb_connection_t* connection, int32_t device_id, xkb_keymap_compile_flags flags) { return MockXcbInterface::Instance()->xkb_x11_keymap_new_from_device(context, connection, device_id, flags); } @@ -54,28 +62,46 @@ xkb_state* xkb_x11_state_new_from_device(xkb_keymap* keymap, xcb_connection_t* c { return MockXcbInterface::Instance()->xkb_x11_state_new_from_device(keymap, connection, device_id); } +int xkb_x11_setup_xkb_extension( + xcb_connection_t* connection, + uint16_t major_xkb_version, + uint16_t minor_xkb_version, + xkb_x11_setup_xkb_extension_flags flags, + uint16_t* major_xkb_version_out, + uint16_t* minor_xkb_version_out, + uint8_t* base_event_out, + uint8_t* base_error_out) +{ + return MockXcbInterface::Instance()->xkb_x11_setup_xkb_extension( + connection, major_xkb_version, minor_xkb_version, flags, major_xkb_version_out, minor_xkb_version_out, base_event_out, + base_error_out); +} // ---------------------------------------------------------------------------- // xkbcommon -xkb_context* xkb_context_new(enum xkb_context_flags flags) +xkb_context* xkb_context_new(xkb_context_flags flags) { return MockXcbInterface::Instance()->xkb_context_new(flags); } -void xkb_context_unref(xkb_context *context) +void xkb_context_unref(xkb_context* context) { return MockXcbInterface::Instance()->xkb_context_unref(context); } -void xkb_keymap_unref(xkb_keymap *keymap) +void xkb_keymap_unref(xkb_keymap* keymap) { return MockXcbInterface::Instance()->xkb_keymap_unref(keymap); } -void xkb_state_unref(xkb_state *state) +void xkb_state_unref(xkb_state* state) { return MockXcbInterface::Instance()->xkb_state_unref(state); } -xkb_keysym_t xkb_state_key_get_one_sym(xkb_state *state, xkb_keycode_t key) +xkb_keysym_t xkb_state_key_get_one_sym(xkb_state* state, xkb_keycode_t key) { return MockXcbInterface::Instance()->xkb_state_key_get_one_sym(state, key); } +int xkb_state_key_get_utf8(xkb_state* state, xkb_keycode_t key, char* buffer, size_t size) +{ + return MockXcbInterface::Instance()->xkb_state_key_get_utf8(state, key, buffer, size); +} } diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h index ecda005830..4adb73caeb 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h @@ -17,6 +17,7 @@ #include #undef explicit #include +#include #include "Printers.h" @@ -35,6 +36,14 @@ struct xkb_keymap struct xkb_state { + enum class Modifier + { + None = 0, + Shift = 1, + Ctrl = 1 << 1, + Alt = 1 << 2, + }; + Modifier m_modifiers; }; class MockXcbInterface @@ -48,7 +57,7 @@ public: MockXcbInterface(MockXcbInterface&&) = delete; MockXcbInterface& operator=(const MockXcbInterface&) = delete; MockXcbInterface& operator=(MockXcbInterface&&) = delete; - ~MockXcbInterface() + virtual ~MockXcbInterface() { self = nullptr; } @@ -59,22 +68,26 @@ public: MOCK_CONST_METHOD2(xcb_connect, xcb_connection_t*(const char* displayname, int* screenp)); MOCK_CONST_METHOD1(xcb_disconnect, void(xcb_connection_t* c)); MOCK_CONST_METHOD1(xcb_poll_for_event, xcb_generic_event_t*(xcb_connection_t* c)); + MOCK_CONST_METHOD2(xcb_request_check, xcb_generic_error_t*(xcb_connection_t* c, xcb_void_cookie_t cookie)); // xcb-xkb MOCK_CONST_METHOD3(xcb_xkb_use_extension, xcb_xkb_use_extension_cookie_t(xcb_connection_t* c, uint16_t wantedMajor, uint16_t wantedMinor)); MOCK_CONST_METHOD3(xcb_xkb_use_extension_reply, xcb_xkb_use_extension_reply_t*(xcb_connection_t* c, xcb_xkb_use_extension_cookie_t cookie, xcb_generic_error_t** e)); + MOCK_CONST_METHOD8(xcb_xkb_select_events, xcb_void_cookie_t(xcb_connection_t* c, xcb_xkb_device_spec_t deviceSpec, uint16_t affectWhich, uint16_t clear, uint16_t selectAll, uint16_t affectMap, uint16_t map, const void* details)); // xkb-x11 MOCK_CONST_METHOD1(xkb_x11_get_core_keyboard_device_id, int32_t(xcb_connection_t* connection)); MOCK_CONST_METHOD4(xkb_x11_keymap_new_from_device, xkb_keymap*(xkb_context* context, xcb_connection_t* connection, int32_t device_id, xkb_keymap_compile_flags flags)); MOCK_CONST_METHOD3(xkb_x11_state_new_from_device, xkb_state*(xkb_keymap* keymap, xcb_connection_t* connection, int32_t device_id)); + MOCK_CONST_METHOD8(xkb_x11_setup_xkb_extension, int(xcb_connection_t* connection, uint16_t major_xkb_version, uint16_t minor_xkb_version, xkb_x11_setup_xkb_extension_flags flags, uint16_t* major_xkb_version_out, uint16_t* minor_xkb_version_out, uint8_t* base_event_out, uint8_t* base_error_out)); // xkbcommon MOCK_CONST_METHOD1(xkb_context_new, xkb_context*(xkb_context_flags flags)); MOCK_CONST_METHOD1(xkb_context_unref, void(xkb_context* context)); MOCK_CONST_METHOD1(xkb_keymap_unref, void(xkb_keymap* keymap)); MOCK_CONST_METHOD1(xkb_state_unref, void(xkb_state* state)); - MOCK_CONST_METHOD2(xkb_state_key_get_one_sym, xkb_keysym_t(xkb_state *state, xkb_keycode_t key)); + MOCK_CONST_METHOD2(xkb_state_key_get_one_sym, xkb_keysym_t(xkb_state* state, xkb_keycode_t key)); + MOCK_CONST_METHOD4(xkb_state_key_get_utf8, int(struct xkb_state* state, xkb_keycode_t key, char* buffer, size_t size)); private: static inline MockXcbInterface* self = nullptr; diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.cpp new file mode 100644 index 0000000000..937cb04e14 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.cpp @@ -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 + * + */ + +#include "XcbBaseTestFixture.h" + +namespace AzFramework +{ + void XcbBaseTestFixture::SetUp() + { + using testing::Return; + using testing::_; + + testing::Test::SetUp(); + + EXPECT_CALL(m_interface, xcb_connect(_, _)) + .WillOnce(Return(&m_connection)); + EXPECT_CALL(m_interface, xcb_disconnect(&m_connection)) + .Times(1); + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.h new file mode 100644 index 0000000000..8e9b008fc1 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbBaseTestFixture.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include "MockXcbInterface.h" + +namespace AzFramework +{ + // Sets up mock behavior for the xcb library, providing an xcb_connection_t that is returned from a call to xcb_connect + class XcbBaseTestFixture + : public testing::Test + { + public: + void SetUp() override; + + protected: + testing::NiceMock m_interface; + xcb_connection_t m_connection{}; + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp index 1b494c9525..9eb93fb4ae 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include @@ -15,6 +16,7 @@ #include #include "MockXcbInterface.h" #include "Actions.h" +#include "XcbBaseTestFixture.h" template xcb_generic_event_t MakeEvent(T event) @@ -24,26 +26,74 @@ xcb_generic_event_t MakeEvent(T event) namespace AzFramework { - TEST(XcbInputDeviceKeyboard, InputChannelsUpdateStateFromXcbEvents) + // Sets up default behavior for mock keyboard responses to xcb methods + class XcbInputDeviceKeyboardTests + : public XcbBaseTestFixture { - using testing::Return; + void SetUp() override + { + using testing::Return; + using testing::SetArgPointee; + using testing::_; + + XcbBaseTestFixture::SetUp(); + EXPECT_CALL(m_interface, xkb_context_new(XKB_CONTEXT_NO_FLAGS)) + .WillOnce(Return(&m_xkbContext)); + EXPECT_CALL(m_interface, xkb_context_unref(&m_xkbContext)) + .Times(1); + + EXPECT_CALL(m_interface, xkb_x11_keymap_new_from_device(&m_xkbContext, &m_connection, s_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS)) + .WillOnce(Return(&m_xkbKeymap)); + EXPECT_CALL(m_interface, xkb_keymap_unref(&m_xkbKeymap)) + .Times(1); + + EXPECT_CALL(m_interface, xkb_x11_state_new_from_device(&m_xkbKeymap, &m_connection, s_coreDeviceId)) + .WillOnce(Return(&m_xkbState)); + EXPECT_CALL(m_interface, xkb_state_unref(&m_xkbState)) + .Times(1); + + ON_CALL(m_interface, xkb_x11_setup_xkb_extension(&m_connection, 1, 0, XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, _, _, _, _)) + .WillByDefault(DoAll( + SetArgPointee<6>(s_xkbEventCode), // Set the "base_event_out" argument to the xkbEventCode, the value to identify XKB events + Return(1) + )); + + constexpr unsigned int xcbXkbSelectEventsSequence = 1; + ON_CALL(m_interface, xcb_xkb_select_events(&m_connection, _, _, _, _, _, _, _)) + .WillByDefault(Return(xcb_void_cookie_t{/*.sequence = */ xcbXkbSelectEventsSequence})); + ON_CALL(m_interface, xcb_request_check(&m_connection, testing::Field(&xcb_void_cookie_t::sequence, testing::Eq(xcbXkbSelectEventsSequence)))) + .WillByDefault(Return(nullptr)); // indicates success + + ON_CALL(m_interface, xkb_x11_get_core_keyboard_device_id(&m_connection)) + .WillByDefault(Return(s_coreDeviceId)); + + ON_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey)) + .WillByDefault(Return(XKB_KEY_a)) + ; + } + + protected: + xkb_context m_xkbContext{}; + xkb_keymap m_xkbKeymap{}; + xkb_state m_xkbState{}; + static constexpr int32_t s_coreDeviceId{1}; + static constexpr uint8_t s_xkbEventCode{85}; + static constexpr xcb_keycode_t s_keycodeForAKey{38}; + }; + + TEST_F(XcbInputDeviceKeyboardTests, InputChannelsUpdateStateFromXcbEvents) + { + using testing::DoAll; using testing::Eq; + using testing::Return; + using testing::SetArgPointee; using testing::_; - MockXcbInterface interface; - - xcb_connection_t connection{}; - xkb_context xkbContext{}; - xkb_keymap xkbKeymap{}; - xkb_state xkbState{}; - const int32_t coreDeviceId{1}; - - constexpr xcb_keycode_t keycodeForAKey = 38; const AZStd::array events { MakeEvent(xcb_key_press_event_t{ /*.response_type = */ XCB_KEY_PRESS, - /*.detail = */ keycodeForAKey, + /*.detail = */ s_keycodeForAKey, /*.sequence = */ 0, /*.time = */ 0, /*.root = */ 0, @@ -59,7 +109,7 @@ namespace AzFramework }), MakeEvent(xcb_key_release_event_t{ /*.response_type = */ XCB_KEY_RELEASE, - /*.detail = */ keycodeForAKey, + /*.detail = */ s_keycodeForAKey, /*.sequence = */ 0, /*.time = */ 0, /*.root = */ 0, @@ -75,51 +125,28 @@ namespace AzFramework }), }; - EXPECT_CALL(interface, xcb_connect(_, _)) - .WillOnce(Return(&connection)); - EXPECT_CALL(interface, xcb_disconnect(&connection)) - .Times(1); - - EXPECT_CALL(interface, xkb_context_new(XKB_CONTEXT_NO_FLAGS)) - .WillOnce(Return(&xkbContext)); - EXPECT_CALL(interface, xkb_context_unref(&xkbContext)) - .Times(1); - - EXPECT_CALL(interface, xkb_x11_keymap_new_from_device(&xkbContext, &connection, coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS)) - .WillOnce(Return(&xkbKeymap)); - EXPECT_CALL(interface, xkb_keymap_unref(&xkbKeymap)) - .Times(1); - - EXPECT_CALL(interface, xkb_x11_state_new_from_device(&xkbKeymap, &connection, coreDeviceId)) - .WillOnce(Return(&xkbState)); - EXPECT_CALL(interface, xkb_state_unref(&xkbState)) - .Times(1); - - EXPECT_CALL(interface, xcb_xkb_use_extension(&connection, 1, 0)); - EXPECT_CALL(interface, xcb_xkb_use_extension_reply(&connection, _, _)) - .WillOnce(ReturnMalloc( - /* .response_type =*/static_cast(XCB_XKB_USE_EXTENSION), - /* .supported =*/ static_cast(1)) - ); - EXPECT_CALL(interface, xkb_x11_get_core_keyboard_device_id(&connection)) - .WillRepeatedly(Return(coreDeviceId)); - // Set the expectations for the events that will be generated // nullptr entries represent when the event queue is empty, and will cause // PumpSystemEventLoopUntilEmpty to return // event pointers are freed by the calling code, so we malloc new copies // here - EXPECT_CALL(interface, xcb_poll_for_event(&connection)) + EXPECT_CALL(m_interface, xcb_poll_for_event(&m_connection)) .WillOnce(ReturnMalloc(events[0])) .WillOnce(Return(nullptr)) .WillOnce(ReturnMalloc(events[1])) .WillOnce(Return(nullptr)) ; - EXPECT_CALL(interface, xkb_state_key_get_one_sym(&xkbState, keycodeForAKey)) - .WillOnce(Return(XKB_KEY_a)) - .WillOnce(Return(XKB_KEY_a)) - ; + EXPECT_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey)) + .Times(2); + + EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0)) + .WillRepeatedly(Return(1)); + EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, _, 2)) + .WillRepeatedly(DoAll( + SetArgPointee<2>('a'), + Return(1) + )); Application application; application.Start({}, {}); diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake index aebd28222b..0ba1ece9c7 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake @@ -13,5 +13,7 @@ set(FILES MockXcbInterface.h Printers.cpp Printers.h + XcbBaseTestFixture.cpp + XcbBaseTestFixture.h XcbInputDeviceKeyboardTests.cpp ) From 3e0535e2110538fdf2376b1aae3edd19551daf37 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 5 Oct 2021 15:38:24 -0700 Subject: [PATCH 074/293] [XCB] Add tests to cover text events from key presses Signed-off-by: Chris Burel --- .../Tests/Platform/Common/Xcb/Matchers.h | 17 ++ .../Platform/Common/Xcb/MockXcbInterface.cpp | 12 + .../Platform/Common/Xcb/MockXcbInterface.h | 12 +- .../Xcb/XcbInputDeviceKeyboardTests.cpp | 237 +++++++++++++++++- .../Xcb/azframework_xcb_tests_files.cmake | 1 + 5 files changed, 261 insertions(+), 18 deletions(-) create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Matchers.h diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Matchers.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Matchers.h new file mode 100644 index 0000000000..77acb1c3e4 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/Matchers.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +inline testing::PolymorphicMatcher> StrEq(const AZStd::string& str) +{ + return ::testing::MakePolymorphicMatcher(testing::internal::StrEqualityMatcher(str, true, true)); +} diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp index 4797f1133d..b15809a4c6 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.cpp @@ -103,5 +103,17 @@ int xkb_state_key_get_utf8(xkb_state* state, xkb_keycode_t key, char* buffer, si { return MockXcbInterface::Instance()->xkb_state_key_get_utf8(state, key, buffer, size); } +xkb_state_component xkb_state_update_mask( + xkb_state* state, + xkb_mod_mask_t depressed_mods, + xkb_mod_mask_t latched_mods, + xkb_mod_mask_t locked_mods, + xkb_layout_index_t depressed_layout, + xkb_layout_index_t latched_layout, + xkb_layout_index_t locked_layout) +{ + return MockXcbInterface::Instance()->xkb_state_update_mask( + state, depressed_mods, latched_mods, locked_mods, depressed_layout, latched_layout, locked_layout); +} } diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h index 4adb73caeb..b57751344e 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/MockXcbInterface.h @@ -36,14 +36,7 @@ struct xkb_keymap struct xkb_state { - enum class Modifier - { - None = 0, - Shift = 1, - Ctrl = 1 << 1, - Alt = 1 << 2, - }; - Modifier m_modifiers; + xkb_mod_mask_t m_modifiers{}; }; class MockXcbInterface @@ -87,7 +80,8 @@ public: MOCK_CONST_METHOD1(xkb_keymap_unref, void(xkb_keymap* keymap)); MOCK_CONST_METHOD1(xkb_state_unref, void(xkb_state* state)); MOCK_CONST_METHOD2(xkb_state_key_get_one_sym, xkb_keysym_t(xkb_state* state, xkb_keycode_t key)); - MOCK_CONST_METHOD4(xkb_state_key_get_utf8, int(struct xkb_state* state, xkb_keycode_t key, char* buffer, size_t size)); + MOCK_CONST_METHOD4(xkb_state_key_get_utf8, int(xkb_state* state, xkb_keycode_t key, char* buffer, size_t size)); + MOCK_CONST_METHOD7(xkb_state_update_mask, xkb_state_component(xkb_state* state, xkb_mod_mask_t depressed_mods, xkb_mod_mask_t latched_mods, xkb_mod_mask_t locked_mods, xkb_layout_index_t depressed_layout, xkb_layout_index_t latched_layout, xkb_layout_index_t locked_layout)); private: static inline MockXcbInterface* self = nullptr; diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp index 9eb93fb4ae..c01cf1e7cd 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp @@ -14,7 +14,9 @@ #include #include +#include #include "MockXcbInterface.h" +#include "Matchers.h" #include "Actions.h" #include "XcbBaseTestFixture.h" @@ -58,7 +60,7 @@ namespace AzFramework Return(1) )); - constexpr unsigned int xcbXkbSelectEventsSequence = 1; + constexpr unsigned int xcbXkbSelectEventsSequence = 342; ON_CALL(m_interface, xcb_xkb_select_events(&m_connection, _, _, _, _, _, _, _)) .WillByDefault(Return(xcb_void_cookie_t{/*.sequence = */ xcbXkbSelectEventsSequence})); ON_CALL(m_interface, xcb_request_check(&m_connection, testing::Field(&xcb_void_cookie_t::sequence, testing::Eq(xcbXkbSelectEventsSequence)))) @@ -70,15 +72,64 @@ namespace AzFramework ON_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey)) .WillByDefault(Return(XKB_KEY_a)) ; + ON_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForShiftLKey)) + .WillByDefault(Return(XKB_KEY_Shift_L)) + ; + + ON_CALL(m_interface, xkb_state_update_mask(&m_xkbState, _, _, _, _, _, _)) + .WillByDefault(testing::Invoke(this, &XcbInputDeviceKeyboardTests::UpdateStateMask)); + + ON_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0)) + .WillByDefault(Return(1)); + ON_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithoutShift, s_keycodeForAKey, _, 2)) + .WillByDefault(DoAll( + SetArgPointee<2>('a'), + Return(1) + )); + ON_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithShift, s_keycodeForAKey, _, 2)) + .WillByDefault(DoAll( + SetArgPointee<2>('A'), + Return(1) + )); + } + + private: + xkb_state_component UpdateStateMask( + xkb_state* state, + xkb_mod_mask_t depressed_mods, + xkb_mod_mask_t latched_mods, + xkb_mod_mask_t locked_mods, + xkb_layout_index_t depressed_layout, + xkb_layout_index_t latched_layout, + xkb_layout_index_t locked_layout) + { + state->m_modifiers = depressed_mods | locked_mods; + return {}; } protected: xkb_context m_xkbContext{}; xkb_keymap m_xkbKeymap{}; xkb_state m_xkbState{}; + const testing::Matcher m_matchesStateWithoutShift = testing::AllOf(&m_xkbState, testing::Field(&xkb_state::m_modifiers, 0)); + const testing::Matcher m_matchesStateWithShift = testing::AllOf(&m_xkbState, testing::Field(&xkb_state::m_modifiers, XCB_MOD_MASK_SHIFT)); + static constexpr int32_t s_coreDeviceId{1}; static constexpr uint8_t s_xkbEventCode{85}; + static constexpr xcb_keycode_t s_keycodeForAKey{38}; + static constexpr xcb_keycode_t s_keycodeForShiftLKey{50}; + }; + + class InputTextNotificationListener + : public InputTextNotificationBus::Handler + { + public: + InputTextNotificationListener() + { + BusConnect(); + } + MOCK_METHOD2(OnInputTextEvent, void(const AZStd::string& /*textUTF8*/, bool& /*o_hasBeenConsumed*/)); }; TEST_F(XcbInputDeviceKeyboardTests, InputChannelsUpdateStateFromXcbEvents) @@ -140,14 +191,6 @@ namespace AzFramework EXPECT_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey)) .Times(2); - EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0)) - .WillRepeatedly(Return(1)); - EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, _, 2)) - .WillRepeatedly(DoAll( - SetArgPointee<2>('a'), - Return(1) - )); - Application application; application.Start({}, {}); @@ -169,4 +212,180 @@ namespace AzFramework application.Stop(); } + + TEST_F(XcbInputDeviceKeyboardTests, TextEnteredFromXcbKeyPressEvents) + { + using testing::DoAll; + using testing::Eq; + using testing::Return; + using testing::SetArgPointee; + using testing::_; + + // press a + // release a + // press shift + // press a + // release a + // release shift + const AZStd::array events + { + MakeEvent(xcb_key_press_event_t{ + /*.response_type = */ XCB_KEY_PRESS, + /*.detail = */ s_keycodeForAKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), + MakeEvent(xcb_key_release_event_t{ + /*.response_type = */ XCB_KEY_RELEASE, + /*.detail = */ s_keycodeForAKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), + MakeEvent(xcb_xkb_state_notify_event_t{ + /*.response_type = */ s_xkbEventCode, + /*.xkbType = */ XCB_XKB_STATE_NOTIFY, + /*.sequence = */ 0, + /*.time = */ 0, + /*.deviceID = */ s_coreDeviceId, + /*.mods = */ XCB_MOD_MASK_SHIFT, + /*.baseMods = */ XCB_MOD_MASK_SHIFT, + /*.latchedMods = */ 0, + /*.lockedMods = */ 0, + /*.group = */ 0, + /*.baseGroup = */ 0, + /*.latchedGroup = */ 0, + /*.lockedGroup = */ 0, + /*.compatState = */ XCB_MOD_MASK_SHIFT, + /*.grabMods = */ XCB_MOD_MASK_SHIFT, + /*.compatGrabMods = */ XCB_MOD_MASK_SHIFT, + /*.lookupMods = */ XCB_MOD_MASK_SHIFT, + /*.compatLoockupMods = */ XCB_MOD_MASK_SHIFT, + /*.ptrBtnState = */ 0, + /*.changed = */ 0, + /*.keycode = */ s_keycodeForShiftLKey, + /*.eventType = */ XCB_KEY_PRESS, + /*.requestMajor = */ 0, + /*.requestMinor = */ 0, + }), + MakeEvent(xcb_key_press_event_t{ + /*.response_type = */ XCB_KEY_PRESS, + /*.detail = */ s_keycodeForAKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), + MakeEvent(xcb_key_release_event_t{ + /*.response_type = */ XCB_KEY_RELEASE, + /*.detail = */ s_keycodeForAKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), + MakeEvent(xcb_xkb_state_notify_event_t{ + /*.response_type = */ s_xkbEventCode, + /*.xkbType = */ XCB_XKB_STATE_NOTIFY, + /*.sequence = */ 0, + /*.time = */ 0, + /*.deviceID = */ s_coreDeviceId, + /*.mods = */ 0, + /*.baseMods = */ 0, + /*.latchedMods = */ 0, + /*.lockedMods = */ 0, + /*.group = */ 0, + /*.baseGroup = */ 0, + /*.latchedGroup = */ 0, + /*.lockedGroup = */ 0, + /*.compatState = */ 0, + /*.grabMods = */ 0, + /*.compatGrabMods = */ 0, + /*.lookupMods = */ 0, + /*.compatLoockupMods = */ 0, + /*.ptrBtnState = */ 0, + /*.changed = */ 0, + /*.keycode = */ s_keycodeForShiftLKey, + /*.eventType = */ XCB_KEY_RELEASE, + /*.requestMajor = */ 0, + /*.requestMinor = */ 0, + }), + }; + + // Set the expectations for the events that will be generated + // nullptr entries represent when the event queue is empty, and will cause + // PumpSystemEventLoopUntilEmpty to return + // event pointers are freed by the calling code, so we malloc new copies + // here + EXPECT_CALL(m_interface, xcb_poll_for_event(&m_connection)) + .WillOnce(ReturnMalloc(events[0])) + .WillOnce(Return(nullptr)) + .WillOnce(ReturnMalloc(events[1])) + .WillOnce(Return(nullptr)) + .WillOnce(ReturnMalloc(events[2])) + .WillOnce(ReturnMalloc(events[3])) + .WillOnce(Return(nullptr)) + .WillOnce(ReturnMalloc(events[4])) + .WillOnce(ReturnMalloc(events[5])) + .WillRepeatedly(Return(nullptr)) + ; + + EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForAKey, nullptr, 0)) + .Times(2); + EXPECT_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithoutShift, s_keycodeForAKey, _, 2)) + .Times(1); + EXPECT_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithShift, s_keycodeForAKey, _, 2)) + .Times(1); + + InputTextNotificationListener textListener; + EXPECT_CALL(textListener, OnInputTextEvent(StrEq("a"), _)).Times(1); + EXPECT_CALL(textListener, OnInputTextEvent(StrEq("A"), _)).Times(1); + + Application application; + application.Start({}, {}); + + for (int i = 0; i < 4; ++i) + { + application.PumpSystemEventLoopUntilEmpty(); + application.TickSystem(); + application.Tick(); + } + + application.Stop(); + } } // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake index 0ba1ece9c7..762d5d74fe 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake @@ -9,6 +9,7 @@ set(FILES Actions.h Main.cpp + Matchers.h MockXcbInterface.cpp MockXcbInterface.h Printers.cpp From 8668d8b2fe9c4e2f7c7c4f057b3ea4c25b58fddd Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Wed, 6 Oct 2021 09:09:05 -0700 Subject: [PATCH 075/293] [XCB] Avoid emitting text events when a key press does not generate text Many keys will generate key press events but return an empty string from `xkb_state_key_get_utf8`, like modifier keys, arrow keys, function keys, etc. This checks if the string retrieved from such a key press is empty before emitting an associated text event for it, to avoid notifying a potentially large number of listeners about an empty string. Signed-off-by: Chris Burel --- .../AzFramework/XcbInputDeviceKeyboard.cpp | 9 +++- .../Xcb/XcbInputDeviceKeyboardTests.cpp | 54 ++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp index 454313ec5b..de326df200 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp @@ -148,8 +148,13 @@ namespace AzFramework if (responseType == XCB_KEY_PRESS) { const auto* keyPress = reinterpret_cast(event); - - QueueRawTextEvent(TextFromKeycode(m_xkbState.get(), keyPress->detail)); + { + auto text = TextFromKeycode(m_xkbState.get(), keyPress->detail); + if (!text.empty()) + { + QueueRawTextEvent(AZStd::move(text)); + } + } if (const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail)) { diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp index c01cf1e7cd..3abbcdc564 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp @@ -91,6 +91,9 @@ namespace AzFramework SetArgPointee<2>('A'), Return(1) )); + + ON_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForShiftLKey, nullptr, 0)) + .WillByDefault(Return(0)); } private: @@ -261,6 +264,24 @@ namespace AzFramework /*.same_screen = */ 0, /*.pad0 = */ 0 }), + // Pressing a modifier key will generate a key press event followed + // by a state notify event + MakeEvent(xcb_key_press_event_t{ + /*.response_type = */ XCB_KEY_PRESS, + /*.detail = */ s_keycodeForShiftLKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), MakeEvent(xcb_xkb_state_notify_event_t{ /*.response_type = */ s_xkbEventCode, /*.xkbType = */ XCB_XKB_STATE_NOTIFY, @@ -319,6 +340,22 @@ namespace AzFramework /*.same_screen = */ 0, /*.pad0 = */ 0 }), + MakeEvent(xcb_key_release_event_t{ + /*.response_type = */ XCB_KEY_RELEASE, + /*.detail = */ s_keycodeForShiftLKey, + /*.sequence = */ 0, + /*.time = */ 0, + /*.root = */ 0, + /*.event = */ 0, + /*.child = */ 0, + /*.root_x = */ 0, + /*.root_y = */ 0, + /*.event_x = */ 0, + /*.event_y = */ 0, + /*.state = */ 0, + /*.same_screen = */ 0, + /*.pad0 = */ 0 + }), MakeEvent(xcb_xkb_state_notify_event_t{ /*.response_type = */ s_xkbEventCode, /*.xkbType = */ XCB_XKB_STATE_NOTIFY, @@ -353,15 +390,17 @@ namespace AzFramework // event pointers are freed by the calling code, so we malloc new copies // here EXPECT_CALL(m_interface, xcb_poll_for_event(&m_connection)) - .WillOnce(ReturnMalloc(events[0])) + .WillOnce(ReturnMalloc(events[0])) // press a .WillOnce(Return(nullptr)) - .WillOnce(ReturnMalloc(events[1])) + .WillOnce(ReturnMalloc(events[1])) // release a .WillOnce(Return(nullptr)) - .WillOnce(ReturnMalloc(events[2])) - .WillOnce(ReturnMalloc(events[3])) + .WillOnce(ReturnMalloc(events[2])) // press shift + .WillOnce(ReturnMalloc(events[3])) // state notify shift is down + .WillOnce(ReturnMalloc(events[4])) // press a .WillOnce(Return(nullptr)) - .WillOnce(ReturnMalloc(events[4])) - .WillOnce(ReturnMalloc(events[5])) + .WillOnce(ReturnMalloc(events[5])) // release a + .WillOnce(ReturnMalloc(events[6])) // release shift + .WillOnce(ReturnMalloc(events[7])) // state notify shift is up .WillRepeatedly(Return(nullptr)) ; @@ -372,6 +411,9 @@ namespace AzFramework EXPECT_CALL(m_interface, xkb_state_key_get_utf8(m_matchesStateWithShift, s_keycodeForAKey, _, 2)) .Times(1); + EXPECT_CALL(m_interface, xkb_state_key_get_utf8(&m_xkbState, s_keycodeForShiftLKey, nullptr, 0)) + .Times(1); + InputTextNotificationListener textListener; EXPECT_CALL(textListener, OnInputTextEvent(StrEq("a"), _)).Times(1); EXPECT_CALL(textListener, OnInputTextEvent(StrEq("A"), _)).Times(1); From 39cf3f51cc27f62458f8db7c915e35f8bfb4b16a Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Wed, 6 Oct 2021 11:43:41 -0700 Subject: [PATCH 076/293] Update wix installer folders to match the new binary locations. Signed-off-by: AMZN-Phil --- .../Platform/Windows/Packaging/Bootstrapper.wxs | 2 +- cmake/Platform/Windows/Packaging/Shortcuts.wxs | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmake/Platform/Windows/Packaging/Bootstrapper.wxs b/cmake/Platform/Windows/Packaging/Bootstrapper.wxs index 079c20e212..f3af199bc2 100644 --- a/cmake/Platform/Windows/Packaging/Bootstrapper.wxs +++ b/cmake/Platform/Windows/Packaging/Bootstrapper.wxs @@ -20,7 +20,7 @@ + Value="[InstallFolder]\bin\Windows\profile\Default\o3de.exe"/> diff --git a/cmake/Platform/Windows/Packaging/Shortcuts.wxs b/cmake/Platform/Windows/Packaging/Shortcuts.wxs index fefd15294a..fbfa174d06 100644 --- a/cmake/Platform/Windows/Packaging/Shortcuts.wxs +++ b/cmake/Platform/Windows/Packaging/Shortcuts.wxs @@ -18,7 +18,9 @@ - + + + @@ -52,18 +54,18 @@ From f68d2676a0caaf9ef31b6daf8ecd01df6ffa45af Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Wed, 6 Oct 2021 14:51:28 -0500 Subject: [PATCH 077/293] Terrain/mbalfour/terrain macro material component (#4500) * Initial TerrainMacroMaterial Component. The APIs will likely need to be adjusted once it gets hooked up to the renderer. It also would benefit from better UX to prevent users from selecting the wrong material types, but there are separate tickets for the Editor to add features to allow for that. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Addressed PR feedback. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * More PR feedback - add create/destroy notifications. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../DefaultTerrainMacroMaterial.material | 8 + .../Terrain/TerrainMacroMaterial.materialtype | 46 +++ .../Code/Source/EditorTerrainModule.cpp | 2 + Gems/Terrain/Code/Source/TerrainModule.cpp | 2 + .../TerrainMacroMaterialComponent.cpp | 287 ++++++++++++++++++ .../TerrainMacroMaterialComponent.h | 92 ++++++ .../EditorTerrainMacroMaterialComponent.cpp | 52 ++++ .../EditorTerrainMacroMaterialComponent.h | 32 ++ .../TerrainRenderer/TerrainMacroMaterialBus.h | 78 +++++ .../Code/terrain_editor_shared_files.cmake | 2 + Gems/Terrain/Code/terrain_files.cmake | 3 + 11 files changed, 604 insertions(+) create mode 100644 Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material create mode 100644 Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype create mode 100644 Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp create mode 100644 Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h create mode 100644 Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp create mode 100644 Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.h create mode 100644 Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h diff --git a/Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material b/Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material new file mode 100644 index 0000000000..afaf7e1947 --- /dev/null +++ b/Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material @@ -0,0 +1,8 @@ +{ + "description": "", + "materialType": "TerrainMacroMaterial.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 1, + "properties": { + } +} diff --git a/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype b/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype new file mode 100644 index 0000000000..0a4f6d0229 --- /dev/null +++ b/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype @@ -0,0 +1,46 @@ +{ + "description": "A material for providing terrain with low-fidelity color and normals. This material will get blended with surface detail materials.", + "propertyLayout": { + "version": 1, + "groups": [ + { + "id": "settings", + "displayName": "Settings" + } + ], + "properties": { + "macroColor": [ + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + } + + ], + "macroNormal": [ + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture.", + "type": "Bool", + "defaultValue": true + } + ] + } + }, + "shaders": [ + { + "file": "../../Shaders/Terrain/TerrainPBR_ForwardPass.shader" + }, + { + "file": "../../Shaders/Terrain/Terrain_Shadowmap.shader" + }, + { + "file": "../../Shaders/Terrain/Terrain_DepthPass.shader" + } + ], + "functors": [ + ] +} diff --git a/Gems/Terrain/Code/Source/EditorTerrainModule.cpp b/Gems/Terrain/Code/Source/EditorTerrainModule.cpp index 9107ea8541..94c6f5c3c6 100644 --- a/Gems/Terrain/Code/Source/EditorTerrainModule.cpp +++ b/Gems/Terrain/Code/Source/EditorTerrainModule.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace Terrain { @@ -24,6 +25,7 @@ namespace Terrain { Terrain::EditorTerrainHeightGradientListComponent::CreateDescriptor(), Terrain::EditorTerrainLayerSpawnerComponent::CreateDescriptor(), + Terrain::EditorTerrainMacroMaterialComponent::CreateDescriptor(), Terrain::EditorTerrainSurfaceGradientListComponent::CreateDescriptor(), Terrain::EditorTerrainSystemComponent::CreateDescriptor(), Terrain::EditorTerrainWorldComponent::CreateDescriptor(), diff --git a/Gems/Terrain/Code/Source/TerrainModule.cpp b/Gems/Terrain/Code/Source/TerrainModule.cpp index 6aeddc3cd5..878c6b44c8 100644 --- a/Gems/Terrain/Code/Source/TerrainModule.cpp +++ b/Gems/Terrain/Code/Source/TerrainModule.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace Terrain { @@ -31,6 +32,7 @@ namespace Terrain TerrainWorldRendererComponent::CreateDescriptor(), TerrainHeightGradientListComponent::CreateDescriptor(), TerrainLayerSpawnerComponent::CreateDescriptor(), + TerrainMacroMaterialComponent::CreateDescriptor(), TerrainSurfaceGradientListComponent::CreateDescriptor(), TerrainSurfaceDataSystemComponent::CreateDescriptor(), }); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp new file mode 100644 index 0000000000..55653c64fa --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace Terrain +{ + AZ::Data::AssetId TerrainMacroMaterialConfig::s_macroMaterialTypeAssetId{}; + + void TerrainMacroMaterialConfig::Reflect(AZ::ReflectContext* context) + { + AZ::SerializeContext* serialize = azrtti_cast(context); + if (serialize) + { + serialize->Class() + ->Version(1) + ->Field("MacroMaterial", &TerrainMacroMaterialConfig::m_materialAsset) + ; + + // The edit context for this appears in EditorTerrainMacroMaterialComponent.cpp. + } + } + + AZ::Data::AssetId TerrainMacroMaterialConfig::GetTerrainMacroMaterialTypeAssetId() + { + // Get the Asset ID for the TerrainMacroMaterial material type and store it in a class static so that we don't have to look it + // up again. + if (!s_macroMaterialTypeAssetId.IsValid()) + { + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + s_macroMaterialTypeAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, TerrainMacroMaterialTypeAsset, + azrtti_typeid(), false); + AZ_Assert(s_macroMaterialTypeAssetId.IsValid(), "The asset '%s' couldn't be found.", TerrainMacroMaterialTypeAsset); + } + + return s_macroMaterialTypeAssetId; + } + + bool TerrainMacroMaterialConfig::IsMaterialTypeCorrect(const AZ::Data::AssetId& assetId) + { + // We'll verify that whatever material we try to load has this material type as a dependency, as a way to implicitly detect + // that we're only trying to use terrain macro materials even before we load the asset. + auto macroMaterialTypeAssetId = GetTerrainMacroMaterialTypeAssetId(); + + // Get the dependencies for the requested asset. + AZ::Outcome, AZStd::string> result; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + result, &AZ::Data::AssetCatalogRequestBus::Events::GetDirectProductDependencies, assetId); + + // If any of the dependencies match the TerrainMacroMaterial materialtype asset, then this should be the correct type of material. + if (result) + { + for (auto& dependency : result.GetValue()) + { + if (dependency.m_assetId == macroMaterialTypeAssetId) + { + return true; + } + } + } + + // Didn't have the expected dependency, so it must not be the right material type. + return false; + } + + AZ::Outcome TerrainMacroMaterialConfig::ValidateMaterialAsset(void* newValue, const AZ::Uuid& valueType) + { + if (azrtti_typeid>() != valueType) + { + AZ_Assert(false, "Unexpected value type"); + return AZ::Failure(AZStd::string("Unexpectedly received something other than a material asset for the MacroMaterial!")); + } + + auto newMaterialAsset = *static_cast*>(newValue); + + if (!IsMaterialTypeCorrect(newMaterialAsset.GetId())) + { + return AZ::Failure(AZStd::string::format( + "The selected MacroMaterial ('%s') needs to use the TerrainMacroMaterial material type.", + newMaterialAsset.GetHint().c_str())); + } + + return AZ::Success(); + } + + + void TerrainMacroMaterialComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.push_back(AZ_CRC_CE("TerrainMacroMaterialProviderService")); + } + + void TerrainMacroMaterialComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.push_back(AZ_CRC_CE("TerrainMacroMaterialProviderService")); + } + + void TerrainMacroMaterialComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService")); + } + + void TerrainMacroMaterialComponent::Reflect(AZ::ReflectContext* context) + { + TerrainMacroMaterialConfig::Reflect(context); + + AZ::SerializeContext* serialize = azrtti_cast(context); + if (serialize) + { + serialize->Class() + ->Version(0) + ->Field("Configuration", &TerrainMacroMaterialComponent::m_configuration) + ; + } + } + + TerrainMacroMaterialComponent::TerrainMacroMaterialComponent(const TerrainMacroMaterialConfig& configuration) + : m_configuration(configuration) + { + } + + void TerrainMacroMaterialComponent::Activate() + { + // Clear out our shape bounds and make sure the material is queued to load. + m_cachedShapeBounds = AZ::Aabb::CreateNull(); + m_configuration.m_materialAsset.QueueLoad(); + + // Don't mark our material as active until it's finished loading and is valid. + m_macroMaterialActive = false; + + // Listen for the material asset to complete loading. + AZ::Data::AssetBus::Handler::BusConnect(m_configuration.m_materialAsset.GetId()); + } + + void TerrainMacroMaterialComponent::Deactivate() + { + TerrainMacroMaterialRequestBus::Handler::BusDisconnect(); + + AZ::Data::AssetBus::Handler::BusDisconnect(); + m_configuration.m_materialAsset.Release(); + + m_macroMaterialInstance.reset(); + + // Send out any notifications as appropriate based on the macro material destruction. + HandleMaterialStateChange(); + } + + bool TerrainMacroMaterialComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) + { + if (auto config = azrtti_cast(baseConfig)) + { + m_configuration = *config; + return true; + } + return false; + } + + bool TerrainMacroMaterialComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const + { + if (auto config = azrtti_cast(outBaseConfig)) + { + *config = m_configuration; + return true; + } + return false; + } + + void TerrainMacroMaterialComponent::OnShapeChanged([[maybe_unused]] ShapeComponentNotifications::ShapeChangeReasons reasons) + { + // This should only get called while the macro material is active. If it gets called while the macro material isn't active, + // we've got a bug where we haven't managed the bus connections properly. + AZ_Assert(m_macroMaterialActive, "The ShapeComponentNotificationBus connection is out of sync with the material load."); + + AZ::Aabb oldShapeBounds = m_cachedShapeBounds; + + LmbrCentral::ShapeComponentRequestsBus::EventResult( + m_cachedShapeBounds, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); + + TerrainMacroMaterialNotificationBus::Broadcast( + &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialRegionChanged, + GetEntityId(), oldShapeBounds, m_cachedShapeBounds); + } + + void TerrainMacroMaterialComponent::HandleMaterialStateChange() + { + // We only want our component to appear active during the time that the macro material is loaded and valid. The logic below + // will handle all transition possibilities to notify if we've become active, inactive, or just changed. We'll also only + // keep a valid up-to-date copy of the shape bounds while the material is valid, since we don't need it any other time. + + bool wasPreviouslyActive = m_macroMaterialActive; + bool isNowActive = (m_macroMaterialInstance != nullptr); + + // Set our state to active or inactive, based on whether or not the macro material instance is now valid. + m_macroMaterialActive = isNowActive; + + // Handle the different inactive/active transition possibilities. + + if (!wasPreviouslyActive && !isNowActive) + { + // Do nothing, we haven't yet successfully loaded a valid material. + } + else if (!wasPreviouslyActive && isNowActive) + { + // We've transitioned from inactive to active, so send out a message saying that we've been created and start tracking the + // overall shape bounds. + + // Get the current shape bounds. + LmbrCentral::ShapeComponentRequestsBus::EventResult( + m_cachedShapeBounds, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); + + // Start listening for terrain macro material requests. + TerrainMacroMaterialRequestBus::Handler::BusConnect(GetEntityId()); + + // Start listening for shape changes. + LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId()); + + TerrainMacroMaterialNotificationBus::Broadcast( + &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialCreated, GetEntityId(), m_macroMaterialInstance, + m_cachedShapeBounds); + } + else if (wasPreviouslyActive && !isNowActive) + { + // Stop listening to macro material requests or shape changes, and send out a notification that we no longer have a valid + // macro material. + + TerrainMacroMaterialRequestBus::Handler::BusDisconnect(); + LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect(); + + m_cachedShapeBounds = AZ::Aabb::CreateNull(); + + TerrainMacroMaterialNotificationBus::Broadcast( + &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialDestroyed, GetEntityId()); + } + else + { + // We were active both before and after, so just send out a material changed event. + + TerrainMacroMaterialNotificationBus::Broadcast( + &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialChanged, GetEntityId(), m_macroMaterialInstance); + } + } + + void TerrainMacroMaterialComponent::OnAssetReady(AZ::Data::Asset asset) + { + m_configuration.m_materialAsset = asset; + + if (m_configuration.m_materialAsset.Get()->GetMaterialTypeAsset().GetId() == + TerrainMacroMaterialConfig::GetTerrainMacroMaterialTypeAssetId()) + { + m_macroMaterialInstance = AZ::RPI::Material::FindOrCreate(m_configuration.m_materialAsset); + } + else + { + AZ_Error("Terrain", false, "Material '%s' has the wrong material type.", m_configuration.m_materialAsset.GetHint().c_str()); + m_macroMaterialInstance.reset(); + } + + // Clear the material asset reference to make sure we don't prevent hot-reloading. + m_configuration.m_materialAsset.Release(); + + HandleMaterialStateChange(); + } + + void TerrainMacroMaterialComponent::OnAssetReloaded(AZ::Data::Asset asset) + { + OnAssetReady(asset); + } + + void TerrainMacroMaterialComponent::GetTerrainMacroMaterialData( + AZ::Data::Instance& macroMaterial, AZ::Aabb& macroMaterialRegion) + { + macroMaterial = m_macroMaterialInstance; + macroMaterialRegion = m_cachedShapeBounds; + } +} diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h new file mode 100644 index 0000000000..b60f6b2a94 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + + +namespace LmbrCentral +{ + template + class EditorWrappedComponentBase; +} + +namespace Terrain +{ + class TerrainMacroMaterialConfig + : public AZ::ComponentConfig + { + public: + AZ_CLASS_ALLOCATOR(TerrainMacroMaterialConfig, AZ::SystemAllocator, 0); + AZ_RTTI(TerrainMacroMaterialConfig, "{9DBAFFF0-FD20-4594-8884-E3266D8CCAC8}", AZ::ComponentConfig); + static void Reflect(AZ::ReflectContext* context); + + AZ::Data::Asset m_materialAsset = { AZ::Data::AssetLoadBehavior::QueueLoad }; + + static AZ::Data::AssetId GetTerrainMacroMaterialTypeAssetId(); + static bool IsMaterialTypeCorrect(const AZ::Data::AssetId&); + AZ::Outcome ValidateMaterialAsset(void* newValue, const AZ::Uuid& valueType); + + private: + static inline constexpr const char* TerrainMacroMaterialTypeAsset = "materials/terrain/terrainmacromaterial.azmaterialtype"; + static AZ::Data::AssetId s_macroMaterialTypeAssetId; + + }; + + class TerrainMacroMaterialComponent + : public AZ::Component + , public TerrainMacroMaterialRequestBus::Handler + , private LmbrCentral::ShapeComponentNotificationsBus::Handler + , private AZ::Data::AssetBus::Handler + { + public: + template + friend class LmbrCentral::EditorWrappedComponentBase; + AZ_COMPONENT(TerrainMacroMaterialComponent, "{F82379FB-E2AE-4F75-A6F4-1AE5F5DA42E8}"); + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services); + static void Reflect(AZ::ReflectContext* context); + + TerrainMacroMaterialComponent(const TerrainMacroMaterialConfig& configuration); + TerrainMacroMaterialComponent() = default; + ~TerrainMacroMaterialComponent() = default; + + ////////////////////////////////////////////////////////////////////////// + // AZ::Component interface implementation + void Activate() override; + void Deactivate() override; + bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; + bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; + + void GetTerrainMacroMaterialData(AZ::Data::Instance& macroMaterial, AZ::Aabb& macroMaterialRegion) override; + + private: + //////////////////////////////////////////////////////////////////////// + // ShapeComponentNotificationsBus + void OnShapeChanged(ShapeComponentNotifications::ShapeChangeReasons reasons) override; + + ////////////////////////////////////////////////////////////////////////// + // AZ::Data::AssetBus::Handler + void OnAssetReady(AZ::Data::Asset asset) override; + void OnAssetReloaded(AZ::Data::Asset asset) override; + + void HandleMaterialStateChange(); + + TerrainMacroMaterialConfig m_configuration; + AZ::Aabb m_cachedShapeBounds; + AZ::Data::Instance m_macroMaterialInstance; + bool m_macroMaterialActive{ false }; + }; +} diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp new file mode 100644 index 0000000000..07472d1b85 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace Terrain +{ + void EditorTerrainMacroMaterialComponent::Reflect(AZ::ReflectContext* context) + { + BaseClassType::ReflectSubClass( + context, 1, + &LmbrCentral::EditorWrappedComponentBaseVersionConverter + ); + + AZ::SerializeContext* serializeContext = azrtti_cast(context); + + if (serializeContext) + { + AZ::EditContext* editContext = serializeContext->GetEditContext(); + + // The edit context for TerrainMacroMaterialConfig is specified here to make it easier to add custom filtering to the + // asset picker for the material asset so that we can eventually only display materials that inherit from the proper + // material type. + if (editContext) + { + editContext + ->Class( + "Terrain Macro Material Component", "Provide a terrain macro material for a region of the world") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_materialAsset, "Macro Material", + "Terrain macro material for use by any terrain inside the bounding box on this entity.") + // This is disabled until ChangeValidate can support the Asset type. :( + //->Attribute(AZ::Edit::Attributes::ChangeValidate, &TerrainMacroMaterialConfig::ValidateMaterialAsset) + ; + } + } + + } +} diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.h new file mode 100644 index 0000000000..a2fddf5768 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace Terrain +{ + class EditorTerrainMacroMaterialComponent + : public LmbrCentral::EditorWrappedComponentBase + { + public: + using BaseClassType = LmbrCentral::EditorWrappedComponentBase; + AZ_EDITOR_COMPONENT(EditorTerrainMacroMaterialComponent, "{24D87D5F-6845-4F1F-81DC-05B4CEBA3EF4}", BaseClassType); + static void Reflect(AZ::ReflectContext* context); + + static constexpr const char* const s_categoryName = "Terrain"; + static constexpr const char* const s_componentName = "Terrain Macro Material"; + static constexpr const char* const s_componentDescription = "Provides a macro material for a region to the terrain renderer"; + static constexpr const char* const s_icon = "Editor/Icons/Components/TerrainLayerRenderer.svg"; + static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/TerrainLayerRenderer.svg"; + static constexpr const char* const s_helpUrl = ""; + }; +} diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h new file mode 100644 index 0000000000..c0618a7f66 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace Terrain +{ + /** + * Request terrain macro material data. + */ + class TerrainMacroMaterialRequests + : public AZ::ComponentBus + { + public: + //////////////////////////////////////////////////////////////////////// + // EBusTraits + using MutexType = AZStd::recursive_mutex; + //////////////////////////////////////////////////////////////////////// + + virtual ~TerrainMacroMaterialRequests() = default; + + // Get the terrain macro material and the region that it covers. + virtual void GetTerrainMacroMaterialData(AZ::Data::Instance& macroMaterial, AZ::Aabb& macroMaterialRegion) = 0; + }; + + using TerrainMacroMaterialRequestBus = AZ::EBus; + + /** + * Notifications for when the terrain macro material data changes. + */ + class TerrainMacroMaterialNotifications : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + + virtual void OnTerrainMacroMaterialCreated( + [[maybe_unused]] AZ::EntityId macroMaterialEntity, + [[maybe_unused]] AZ::Data::Instance macroMaterial, + [[maybe_unused]] const AZ::Aabb& macroMaterialRegion) + { + } + + virtual void OnTerrainMacroMaterialChanged( + [[maybe_unused]] AZ::EntityId macroMaterialEntity, + [[maybe_unused]] AZ::Data::Instance macroMaterial) + { + } + + virtual void OnTerrainMacroMaterialRegionChanged( + [[maybe_unused]] AZ::EntityId macroMaterialEntity, + [[maybe_unused]] const AZ::Aabb& oldRegion, + [[maybe_unused]] const AZ::Aabb& newRegion) + { + } + + virtual void OnTerrainMacroMaterialDestroyed([[maybe_unused]] AZ::EntityId macroMaterialEntity) + { + } + }; + using TerrainMacroMaterialNotificationBus = AZ::EBus; + +} diff --git a/Gems/Terrain/Code/terrain_editor_shared_files.cmake b/Gems/Terrain/Code/terrain_editor_shared_files.cmake index efb68eca31..2db46dc264 100644 --- a/Gems/Terrain/Code/terrain_editor_shared_files.cmake +++ b/Gems/Terrain/Code/terrain_editor_shared_files.cmake @@ -25,4 +25,6 @@ set(FILES Source/EditorTerrainModule.h Source/TerrainModule.cpp Source/TerrainModule.h + Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp + Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.h ) diff --git a/Gems/Terrain/Code/terrain_files.cmake b/Gems/Terrain/Code/terrain_files.cmake index 6d190b7d5e..5739ed6079 100644 --- a/Gems/Terrain/Code/terrain_files.cmake +++ b/Gems/Terrain/Code/terrain_files.cmake @@ -24,8 +24,11 @@ set(FILES Source/Components/TerrainWorldDebuggerComponent.h Source/Components/TerrainWorldRendererComponent.cpp Source/Components/TerrainWorldRendererComponent.h + Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp + Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h Source/TerrainRenderer/TerrainFeatureProcessor.cpp Source/TerrainRenderer/TerrainFeatureProcessor.h + Source/TerrainRenderer/TerrainMacroMaterialBus.h Source/TerrainSystem/TerrainSystem.cpp Source/TerrainSystem/TerrainSystem.h Source/TerrainSystem/TerrainSystemBus.h From f009e06cab8f1af7e0c74a24421b97b38955e517 Mon Sep 17 00:00:00 2001 From: kritin Date: Wed, 6 Oct 2021 13:20:48 -0700 Subject: [PATCH 078/293] responding to code reviews Signed-off-by: kritin --- ...flows_ExistingLevel_EntityComponentCRUD.py | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py index 803b9e9a11..39cacf9af5 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py @@ -53,10 +53,9 @@ def BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD(): 03. create child entity and set a name 04. delete child entity 05. add mesh component to parent entity - 07. delete parent entity - Close editor without saving + 06. delete parent entity """ - import os + from editor_python_test_tools.utils import Report from editor_python_test_tools.editor_entity_utils import EditorEntity @@ -66,50 +65,35 @@ def BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD(): import azlmbr.legacy.general as general import azlmbr.object - # 01. load an existing level - test_level = 'Simple' general.open_level_no_prompt(test_level) Report.result(Tests.load_level, general.get_current_level_name() == test_level) - # 02. create parent entity and set name # Delete any exiting entity and Create a new Entity at the root level - search_filter = azlmbr.entity.SearchFilter() all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) parent_entity = EditorEntity.create_editor_entity("Parent_1") Report.result(Tests.create_entity, parent_entity.exists()) - # 03. Create child Entity to above created parent entity and set a name - child_1_entity = EditorEntity.create_editor_entity("Child_1", parent_entity.id ) Report.result(Tests.create_child_entity, child_1_entity.exists()) - # 04. delete_Child_entity - child_1_entity.delete() Report.result(Tests.delete_child_entity, not child_1_entity.exists()) - # 05. add mesh component to parent entity - parent_entity.add_component("Mesh") Report.result(Tests.add_mesh_component, parent_entity.has_component("Mesh")) - - # 7. delete parent entity - + # 06. delete parent entity parent_entity.delete() Report.result(Tests.delete_entity, not parent_entity.exists()) - # Close editor without saving - editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt') - if __name__ == "__main__": from editor_python_test_tools.utils import Report From 0657f6f7ec0b9f571e4852b6621bd9eff8a163e6 Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Wed, 6 Oct 2021 14:01:52 -0700 Subject: [PATCH 079/293] [LYN-7050] Add matchmaking ticket tracker component (#4485) Signed-off-by: onecent1101 --- .../AWSGameLiftClientLocalTicketTracker.cpp | 169 +++++++++ .../AWSGameLiftClientLocalTicketTracker.h | 62 +++ .../Source/AWSGameLiftClientManager.cpp | 31 +- .../Source/AWSGameLiftClientManager.h | 18 +- .../AWSGameLiftClientSystemComponent.cpp | 38 +- .../Source/AWSGameLiftClientSystemComponent.h | 15 +- .../Request/IAWSGameLiftInternalRequests.h | 43 +++ .../IAWSGameLiftMatchmakingInternalRequests.h | 39 ++ ...WSGameLiftClientLocalTicketTrackerTest.cpp | 353 ++++++++++++++++++ .../Tests/AWSGameLiftClientManagerTest.cpp | 89 +++-- .../Tests/AWSGameLiftClientMocks.h | 3 + .../AWSGameLiftClientSystemComponentTest.cpp | 27 +- .../awsgamelift_client_files.cmake | 5 + .../awsgamelift_client_tests_files.cmake | 1 + .../Source/AWSGameLiftSessionConstants.h | 1 + 15 files changed, 799 insertions(+), 95 deletions(-) create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftInternalRequests.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftMatchmakingInternalRequests.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp new file mode 100644 index 0000000000..9ae168aea9 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace AWSGameLift +{ + AWSGameLiftClientLocalTicketTracker::AWSGameLiftClientLocalTicketTracker() + : m_status(TicketTrackerStatus::Idle) + , m_pollingPeriodInMS(AWSGameLiftClientDefaultPollingPeriodInMS) + { + } + + void AWSGameLiftClientLocalTicketTracker::ActivateTracker() + { + AZ::Interface::Register(this); + } + + void AWSGameLiftClientLocalTicketTracker::DeactivateTracker() + { + AZ::Interface::Unregister(this); + StopPolling(); + } + + void AWSGameLiftClientLocalTicketTracker::StartPolling( + const AZStd::string& ticketId, const AZStd::string& playerId) + { + AZStd::lock_guard lock(m_trackerMutex); + if (m_status == TicketTrackerStatus::Running) + { + AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket tracker is running."); + return; + } + m_status = TicketTrackerStatus::Running; + m_trackerThread = AZStd::thread(AZStd::bind( + &AWSGameLiftClientLocalTicketTracker::ProcessPolling, this, ticketId, playerId)); + } + + void AWSGameLiftClientLocalTicketTracker::StopPolling() + { + AZStd::lock_guard lock(m_trackerMutex); + m_status = TicketTrackerStatus::Idle; + if (m_trackerThread.joinable()) + { + m_trackerThread.join(); + } + } + + void AWSGameLiftClientLocalTicketTracker::ProcessPolling( + const AZStd::string& ticketId, const AZStd::string& playerId) + { + while (m_status == TicketTrackerStatus::Running) + { + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); + if (gameliftClient) + { + Aws::GameLift::Model::DescribeMatchmakingRequest request; + request.AddTicketIds(ticketId.c_str()); + + auto describeMatchmakingOutcome = gameliftClient->DescribeMatchmaking(request); + if (describeMatchmakingOutcome.IsSuccess()) + { + if (describeMatchmakingOutcome.GetResult().GetTicketList().size() == 1) + { + auto ticket = describeMatchmakingOutcome.GetResult().GetTicketList().front(); + if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED) + { + m_status = TicketTrackerStatus::Idle; + AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, + "Matchmaking ticket %s is complete.", ticket.GetTicketId().c_str()); + RequestPlayerJoinMatch(ticket, playerId); + return; + } + else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::TIMED_OUT || + ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::FAILED || + ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::CANCELLED) + { + m_status = TicketTrackerStatus::Idle; + AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Matchmaking ticket %s is not complete, %s", + ticket.GetTicketId().c_str(), ticket.GetStatusReason().c_str()); + return; + } + else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::REQUIRES_ACCEPTANCE) + { + // broadcast acceptance requires to player + } + else + { + AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is processing, %s.", + ticket.GetTicketId().c_str(), ticket.GetStatusReason().c_str()); + } + } + else + { + AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Unable to find expected ticket with id %s", ticketId.c_str()); + } + } + else + { + AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftErrorMessageTemplate, + describeMatchmakingOutcome.GetError().GetExceptionName().c_str(), + describeMatchmakingOutcome.GetError().GetMessage().c_str()); + } + } + else + { + AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftClientMissingErrorMessage); + } + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(m_pollingPeriodInMS)); + } + } + + void AWSGameLiftClientLocalTicketTracker::RequestPlayerJoinMatch( + const Aws::GameLift::Model::MatchmakingTicket& ticket, const AZStd::string& playerId) + { + auto connectionInfo = ticket.GetGameSessionConnectionInfo(); + AzFramework::SessionConnectionConfig sessionConnectionConfig; + sessionConnectionConfig.m_ipAddress = connectionInfo.GetIpAddress().c_str(); + for (auto matchedPlayer : connectionInfo.GetMatchedPlayerSessions()) + { + if (playerId.compare(matchedPlayer.GetPlayerId().c_str()) == 0) + { + sessionConnectionConfig.m_playerSessionId = matchedPlayer.GetPlayerSessionId().c_str(); + break; + } + } + sessionConnectionConfig.m_port = static_cast(connectionInfo.GetPort()); + + if (!sessionConnectionConfig.m_playerSessionId.empty()) + { + AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, + "Requesting and validating player session %s to connect to the match ...", + sessionConnectionConfig.m_playerSessionId.c_str()); + bool result = + AZ::Interface::Get()->RequestPlayerJoinSession(sessionConnectionConfig); + if (result) + { + AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, + "Started connection process, and connection validation is in process."); + } + else + { + AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, + "Failed to start connection process."); + } + } + else + { + AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, + "Player session id is missing for player % to join the match.", playerId.c_str()); + } + } +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h new file mode 100644 index 0000000000..7b317a0485 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include + +#include + +namespace AWSGameLift +{ + enum TicketTrackerStatus + { + Idle, + Running + }; + + //! AWSGameLiftClientLocalTicketTracker + //! GameLift client ticket tracker to describe submitted matchmaking ticket periodically, + //! and join player to the match once matchmaking ticket is complete. + //! For use in production, please see GameLifts guidance about matchmaking at volume. + //! The continuous polling approach here is only suitable for low volume matchmaking and is meant to aid with development only + class AWSGameLiftClientLocalTicketTracker + : public IAWSGameLiftMatchmakingInternalRequests + { + public: + static constexpr const char AWSGameLiftClientLocalTicketTrackerName[] = "AWSGameLiftClientLocalTicketTracker"; + // Set ticket polling period to 10 seconds + // https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-client.html#match-client-track + static constexpr const uint64_t AWSGameLiftClientDefaultPollingPeriodInMS = 10000; + + AWSGameLiftClientLocalTicketTracker(); + virtual ~AWSGameLiftClientLocalTicketTracker() = default; + + virtual void ActivateTracker(); + virtual void DeactivateTracker(); + + // IAWSGameLiftMatchmakingInternalRequests interface implementation + void StartPolling(const AZStd::string& ticketId, const AZStd::string& playerId) override; + void StopPolling() override; + + protected: + // For testing friendly access + uint64_t m_pollingPeriodInMS; + TicketTrackerStatus m_status; + + private: + void ProcessPolling(const AZStd::string& ticketId, const AZStd::string& playerId); + void RequestPlayerJoinMatch(const Aws::GameLift::Model::MatchmakingTicket& ticket, const AZStd::string& playerId); + + AZStd::mutex m_trackerMutex; + AZStd::thread m_trackerThread; + }; +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp index ae4fb162d6..ee731993aa 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp @@ -17,11 +17,13 @@ #include #include +#include #include #include #include #include #include +#include #include @@ -31,11 +33,6 @@ namespace AWSGameLift AZ_CVAR(AZ::CVarFixedString, cl_gameliftLocalEndpoint, "", nullptr, AZ::ConsoleFunctorFlags::Null, "The local endpoint to test with GameLiftLocal SDK."); #endif - AWSGameLiftClientManager::AWSGameLiftClientManager() - { - m_gameliftClient.reset(); - } - void AWSGameLiftClientManager::ActivateManager() { AZ::Interface::Register(this); @@ -62,8 +59,7 @@ namespace AWSGameLift bool AWSGameLiftClientManager::ConfigureGameLiftClient(const AZStd::string& region) { - m_gameliftClient.reset(); - + AZ::Interface::Get()->SetGameLiftClient(nullptr); Aws::Client::ClientConfiguration clientConfig; // Set up client endpoint or region AZStd::string localEndpoint = ""; @@ -103,7 +99,8 @@ namespace AWSGameLift AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientCredentialMissingErrorMessage); return false; } - m_gameliftClient = AZStd::make_shared(credentialResult.result, clientConfig); + AZ::Interface::Get()->SetGameLiftClient( + AZStd::make_shared(credentialResult.result, clientConfig)); return true; } @@ -194,15 +191,15 @@ namespace AWSGameLift AZStd::string AWSGameLiftClientManager::CreateSessionHelper( const AWSGameLiftCreateSessionRequest& createSessionRequest) { - AZStd::shared_ptr gameLiftClient = m_gameliftClient; + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); AZStd::string result = ""; - if (!gameLiftClient) + if (!gameliftClient) { AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage); } else { - result = CreateSessionActivity::CreateSession(*gameLiftClient, createSessionRequest); + result = CreateSessionActivity::CreateSession(*gameliftClient, createSessionRequest); } return result; } @@ -210,7 +207,7 @@ namespace AWSGameLift AZStd::string AWSGameLiftClientManager::CreateSessionOnQueueHelper( const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest) { - AZStd::shared_ptr gameliftClient = m_gameliftClient; + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); AZStd::string result; if (!gameliftClient) { @@ -265,7 +262,7 @@ namespace AWSGameLift bool AWSGameLiftClientManager::JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest) { - AZStd::shared_ptr gameliftClient = m_gameliftClient; + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); bool result = false; if (!gameliftClient) { @@ -345,8 +342,7 @@ namespace AWSGameLift AzFramework::SearchSessionsResponse AWSGameLiftClientManager::SearchSessionsHelper( const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) const { - AZStd::shared_ptr gameliftClient = m_gameliftClient; - + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); AzFramework::SearchSessionsResponse response; if (!gameliftClient) { @@ -380,9 +376,4 @@ namespace AWSGameLift { AZ_UNUSED(stopMatchmakingRequest); } - - void AWSGameLiftClientManager::SetGameLiftClient(AZStd::shared_ptr gameliftClient) - { - m_gameliftClient.swap(gameliftClient); - } } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h index d7211d0472..fbdc1d6104 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h @@ -13,14 +13,6 @@ #include -namespace Aws -{ - namespace GameLift - { - class GameLiftClient; - } -} - namespace AWSGameLift { struct AWSGameLiftCreateSessionRequest; @@ -127,13 +119,11 @@ namespace AWSGameLift "Missing AWS region for GameLift client."; static constexpr const char AWSGameLiftClientCredentialMissingErrorMessage[] = "Missing AWS credential for GameLift client."; - static constexpr const char AWSGameLiftClientMissingErrorMessage[] = - "GameLift client is not configured yet."; static constexpr const char AWSGameLiftCreateSessionRequestInvalidErrorMessage[] = "Invalid GameLift CreateSession or CreateSessionOnQueue request."; - AWSGameLiftClientManager(); + AWSGameLiftClientManager() = default; virtual ~AWSGameLiftClientManager() = default; virtual void ActivateManager(); @@ -165,16 +155,10 @@ namespace AWSGameLift AzFramework::SearchSessionsResponse SearchSessions(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override; void LeaveSession() override; - protected: - // Use for automation tests only to inject mock objects. - void SetGameLiftClient(AZStd::shared_ptr gameliftClient); - private: AZStd::string CreateSessionHelper(const AWSGameLiftCreateSessionRequest& createSessionRequest); AZStd::string CreateSessionOnQueueHelper(const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest); bool JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest); AzFramework::SearchSessionsResponse SearchSessionsHelper(const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) const; - - AZStd::shared_ptr m_gameliftClient; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp index db201920f6..ea5fff99a3 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -27,7 +28,8 @@ namespace AWSGameLift { AWSGameLiftClientSystemComponent::AWSGameLiftClientSystemComponent() { - m_gameliftClientManager = AZStd::make_unique(); + m_gameliftManager = AZStd::make_unique(); + m_gameliftTicketTracker = AZStd::make_unique(); } void AWSGameLiftClientSystemComponent::Reflect(AZ::ReflectContext* context) @@ -90,12 +92,20 @@ namespace AWSGameLift void AWSGameLiftClientSystemComponent::Activate() { - m_gameliftClientManager->ActivateManager(); + AZ::Interface::Register(this); + + m_gameliftClient.reset(); + m_gameliftManager->ActivateManager(); + m_gameliftTicketTracker->ActivateTracker(); } void AWSGameLiftClientSystemComponent::Deactivate() { - m_gameliftClientManager->DeactivateManager(); + m_gameliftTicketTracker->DeactivateTracker(); + m_gameliftManager->DeactivateManager(); + m_gameliftClient.reset(); + + AZ::Interface::Unregister(this); } void AWSGameLiftClientSystemComponent::ReflectGameLiftMatchmaking(AZ::ReflectContext* context) @@ -213,9 +223,25 @@ namespace AWSGameLift } } - void AWSGameLiftClientSystemComponent::SetGameLiftClientManager(AZStd::unique_ptr gameliftClientManager) + AZStd::shared_ptr AWSGameLiftClientSystemComponent::GetGameLiftClient() const + { + return m_gameliftClient; + } + + void AWSGameLiftClientSystemComponent::SetGameLiftClient(AZStd::shared_ptr gameliftClient) + { + m_gameliftClient.swap(gameliftClient); + } + + void AWSGameLiftClientSystemComponent::SetGameLiftClientManager(AZStd::unique_ptr gameliftManager) + { + m_gameliftManager.reset(); + m_gameliftManager = AZStd::move(gameliftManager); + } + + void AWSGameLiftClientSystemComponent::SetGameLiftClientTicketTracker(AZStd::unique_ptr gameliftTicketTracker) { - m_gameliftClientManager.reset(); - m_gameliftClientManager = AZStd::move(gameliftClientManager); + m_gameliftTicketTracker.reset(); + m_gameliftTicketTracker = AZStd::move(gameliftTicketTracker); } } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h index f54461b918..30d4ee0106 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.h @@ -11,6 +11,9 @@ #include #include +#include +#include + namespace AWSGameLift { class AWSGameLiftClientManager; @@ -18,6 +21,7 @@ namespace AWSGameLift //! Gem client system component. Responsible for creating the gamelift client manager. class AWSGameLiftClientSystemComponent : public AZ::Component + , public IAWSGameLiftInternalRequests { public: AZ_COMPONENT(AWSGameLiftClientSystemComponent, "{d481c15c-732a-4eea-9853-4965ed1bc2be}"); @@ -32,6 +36,10 @@ namespace AWSGameLift static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + // IAWSGameLiftInternalRequests interface implementation + AZStd::shared_ptr GetGameLiftClient() const override; + void SetGameLiftClient(AZStd::shared_ptr gameliftClient) override; + protected: //////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation @@ -40,7 +48,8 @@ namespace AWSGameLift void Deactivate() override; //////////////////////////////////////////////////////////////////////// - void SetGameLiftClientManager(AZStd::unique_ptr gameliftClientManager); + void SetGameLiftClientManager(AZStd::unique_ptr gameliftManager); + void SetGameLiftClientTicketTracker(AZStd::unique_ptr gameliftTicketTracker); private: static void ReflectGameLiftMatchmaking(AZ::ReflectContext* context); @@ -49,7 +58,9 @@ namespace AWSGameLift static void ReflectCreateSessionRequest(AZ::ReflectContext* context); static void ReflectSearchSessionsResponse(AZ::ReflectContext* context); - AZStd::unique_ptr m_gameliftClientManager; + AZStd::shared_ptr m_gameliftClient; + AZStd::unique_ptr m_gameliftManager; + AZStd::unique_ptr m_gameliftTicketTracker; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftInternalRequests.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftInternalRequests.h new file mode 100644 index 0000000000..dbac9a798a --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftInternalRequests.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace Aws +{ + namespace GameLift + { + class GameLiftClient; + } +} // namespace Aws + +namespace AWSGameLift +{ + //! IAWSGameLiftRequests + //! GameLift Gem internal interface which is used to fetch gem global GameLift client + class IAWSGameLiftInternalRequests + { + public: + AZ_RTTI(IAWSGameLiftInternalRequests, "{DC0CC1C4-21EE-4A41-B428-D12D697F88A2}"); + + IAWSGameLiftInternalRequests() = default; + virtual ~IAWSGameLiftInternalRequests() = default; + + //! GetGameLiftClient + //! Get GameLift client to interact with Amazon GameLift service + //! @return Shared pointer to the GameLift client + virtual AZStd::shared_ptr GetGameLiftClient() const = 0; + + //! SetGameLiftClient + //! Set GameLift client to provided GameLift client + //! @param gameliftClient Input new GameLift client + virtual void SetGameLiftClient(AZStd::shared_ptr gameliftClient) = 0; + }; +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftMatchmakingInternalRequests.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftMatchmakingInternalRequests.h new file mode 100644 index 0000000000..81d04314af --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/IAWSGameLiftMatchmakingInternalRequests.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AWSGameLift +{ + //! IAWSGameLiftMatchmakingInternalRequests + //! GameLift Gem matchmaking internal interfaces which is used to communicate + //! with client side ticket tracker to sync matchmaking ticket data and join + //! player to the match + class IAWSGameLiftMatchmakingInternalRequests + { + public: + AZ_RTTI(IAWSGameLiftMatchmakingInternalRequests, "{C2DA440E-74E0-411E-813D-5880B50B0C9E}"); + + IAWSGameLiftMatchmakingInternalRequests() = default; + virtual ~IAWSGameLiftMatchmakingInternalRequests() = default; + + //! StartPolling + //! Request to start process for polling matchmaking ticket based on given ticket id and player id + //! @param ticketId The requested matchmaking ticket id + //! @param playerId The requested matchmaking player id + virtual void StartPolling(const AZStd::string& ticketId, const AZStd::string& playerId) = 0; + + //! StopPolling + //! Request to stop process for polling matchmaking ticket + virtual void StopPolling() = 0; + }; +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp new file mode 100644 index 0000000000..6e688b28e3 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include +#include + +#include + +using namespace AWSGameLift; + +static constexpr const uint64_t TEST_RACKER_POLLING_PERIOD_MS = 100; +static constexpr const uint64_t TEST_WAIT_BUFFER_TIME_MS = 10; +static constexpr const uint64_t TEST_WAIT_MAXIMUM_TIME_MS = 10000; + +class TestAWSGameLiftClientLocalTicketTracker + : public AWSGameLiftClientLocalTicketTracker +{ +public: + TestAWSGameLiftClientLocalTicketTracker() = default; + virtual ~TestAWSGameLiftClientLocalTicketTracker() = default; + + void SetUp() + { + ActivateTracker(); + m_pollingPeriodInMS = TEST_RACKER_POLLING_PERIOD_MS; + } + + void TearDown() + { + DeactivateTracker(); + } + + bool IsTrackerIdle() + { + return m_status == TicketTrackerStatus::Idle; + } +}; + +class AWSGameLiftClientLocalTicketTrackerTest + : public AWSGameLiftClientFixture + , public IAWSGameLiftInternalRequests +{ +protected: + void SetUp() override + { + AWSGameLiftClientFixture::SetUp(); + + AZ::Interface::Register(this); + + m_gameliftClientMockPtr = AZStd::make_shared(); + m_gameliftClientTicketTracker = AZStd::make_unique(); + m_gameliftClientTicketTracker->SetUp(); + } + + void TearDown() override + { + m_gameliftClientTicketTracker->TearDown(); + m_gameliftClientTicketTracker.reset(); + m_gameliftClientMockPtr.reset(); + + AZ::Interface::Unregister(this); + + AWSGameLiftClientFixture::TearDown(); + } + + AZStd::shared_ptr GetGameLiftClient() const + { + return m_gameliftClientMockPtr; + } + + void SetGameLiftClient(AZStd::shared_ptr gameliftClient) + { + AZ_UNUSED(gameliftClient); + m_gameliftClientMockPtr.reset(); + } + + void WaitForProcessFinish(uint64_t expectedNum) + { + int processingTime = 0; + while (processingTime < TEST_WAIT_MAXIMUM_TIME_MS) + { + if (::UnitTest::TestRunner::Instance().m_numAssertsFailed == expectedNum) + { + AZ_TEST_STOP_TRACE_SUPPRESSION(expectedNum); + return; + } + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(TEST_WAIT_BUFFER_TIME_MS)); + processingTime += TEST_WAIT_BUFFER_TIME_MS; + } + } + + void WaitForProcessFinish() + { + int processingTime = 0; + while (processingTime < TEST_WAIT_MAXIMUM_TIME_MS) + { + if (m_gameliftClientTicketTracker->IsTrackerIdle()) + { + return; + } + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(TEST_WAIT_BUFFER_TIME_MS)); + processingTime += TEST_WAIT_BUFFER_TIME_MS; + } + } + +public: + AZStd::unique_ptr m_gameliftClientTicketTracker; + AZStd::shared_ptr m_gameliftClientMockPtr; +}; + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithoutClientSetup_GetExpectedErrors) +{ + AZ::Interface::Get()->SetGameLiftClient(nullptr); + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_MultipleCallsWithoutClientSetup_GetExpectedErrors) +{ + AZ::Interface::Get()->SetGameLiftClient(nullptr); + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButWithFailedOutcome_GetExpectedErrors) +{ + Aws::Client::AWSError error; + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(error); + + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithMoreThanOneTicket_GetExpectedErrors) +{ + Aws::GameLift::Model::DescribeMatchmakingResult result; + result.AddTicketList(Aws::GameLift::Model::MatchmakingTicket()); + result.AddTicketList(Aws::GameLift::Model::MatchmakingTicket()); + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(result); + + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_FALSE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallWithCompleteStatus_ProcessStopsAndGetExpectedResult) +{ + Aws::GameLift::Model::GameSessionConnectionInfo connectionInfo; + connectionInfo.SetIpAddress("DummyIpAddress"); + connectionInfo.SetPort(123); + connectionInfo.AddMatchedPlayerSessions( + Aws::GameLift::Model::MatchedPlayerSession() + .WithPlayerId("player1") + .WithPlayerSessionId("playersession1")); + + Aws::GameLift::Model::MatchmakingTicket ticket; + ticket.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED); + ticket.SetGameSessionConnectionInfo(connectionInfo); + + Aws::GameLift::Model::DescribeMatchmakingResult result; + result.AddTicketList(ticket); + + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + SessionHandlingClientRequestsMock handlerMock; + EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(true)); + + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButNoPlayerSession_ProcessStopsAndGetExpectedError) +{ + Aws::GameLift::Model::GameSessionConnectionInfo connectionInfo; + connectionInfo.SetIpAddress("DummyIpAddress"); + connectionInfo.SetPort(123); + + Aws::GameLift::Model::MatchmakingTicket ticket; + ticket.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED); + ticket.SetGameSessionConnectionInfo(connectionInfo); + + Aws::GameLift::Model::DescribeMatchmakingResult result; + result.AddTicketList(ticket); + + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButFailedToJoinMatch_ProcessStopsAndGetExpectedError) +{ + Aws::GameLift::Model::GameSessionConnectionInfo connectionInfo; + connectionInfo.SetIpAddress("DummyIpAddress"); + connectionInfo.SetPort(123); + connectionInfo.AddMatchedPlayerSessions( + Aws::GameLift::Model::MatchedPlayerSession() + .WithPlayerId("player1") + .WithPlayerSessionId("playersession1")); + + Aws::GameLift::Model::MatchmakingTicket ticket; + ticket.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED); + ticket.SetGameSessionConnectionInfo(connectionInfo); + + Aws::GameLift::Model::DescribeMatchmakingResult result; + result.AddTicketList(ticket); + + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + SessionHandlingClientRequestsMock handlerMock; + EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(false)); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButTicketTimeOut_ProcessStopsAndGetExpectedError) +{ + Aws::GameLift::Model::MatchmakingTicket ticket; + ticket.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::TIMED_OUT); + + Aws::GameLift::Model::DescribeMatchmakingResult result; + result.AddTicketList(ticket); + + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButTicketFailed_ProcessStopsAndGetExpectedError) +{ + Aws::GameLift::Model::MatchmakingTicket ticket; + ticket.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::FAILED); + + Aws::GameLift::Model::DescribeMatchmakingResult result; + result.AddTicketList(ticket); + + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallButTicketCancelled_ProcessStopsAndGetExpectedError) +{ + Aws::GameLift::Model::MatchmakingTicket ticket; + ticket.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::CANCELLED); + + Aws::GameLift::Model::DescribeMatchmakingResult result; + result.AddTicketList(ticket); + + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(1); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallAndTicketCompleteAtLast_ProcessContinuesAndStop) +{ + Aws::GameLift::Model::MatchmakingTicket ticket1; + ticket1.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::QUEUED); + + Aws::GameLift::Model::DescribeMatchmakingResult result1; + result1.AddTicketList(ticket1); + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome1(result1); + + Aws::GameLift::Model::GameSessionConnectionInfo connectionInfo; + connectionInfo.SetIpAddress("DummyIpAddress"); + connectionInfo.SetPort(123); + connectionInfo.AddMatchedPlayerSessions( + Aws::GameLift::Model::MatchedPlayerSession() + .WithPlayerId("player1") + .WithPlayerSessionId("playersession1")); + + Aws::GameLift::Model::MatchmakingTicket ticket2; + ticket2.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED); + ticket2.SetGameSessionConnectionInfo(connectionInfo); + + Aws::GameLift::Model::DescribeMatchmakingResult result2; + result2.AddTicketList(ticket2); + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome2(result2); + + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .WillOnce(::testing::Return(outcome1)) + .WillOnce(::testing::Return(outcome2)); + + SessionHandlingClientRequestsMock handlerMock; + EXPECT_CALL(handlerMock, RequestPlayerJoinSession(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(true)); + + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp index caa5113a25..e7612618ee 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp @@ -23,8 +23,7 @@ #include #include #include - -#include +#include using namespace AWSGameLift; @@ -117,38 +116,19 @@ public: MOCK_METHOD0(GetDefaultConfig, AWSCore::AwsApiJobConfig*()); }; -class TestAWSGameLiftClientManager - : public AWSGameLiftClientManager -{ -public: - TestAWSGameLiftClientManager() - { - m_gameliftClientMockPtr = nullptr; - } - ~TestAWSGameLiftClientManager() - { - m_gameliftClientMockPtr = nullptr; - } - - void SetUpMockClient() - { - m_gameliftClientMockPtr = AZStd::make_shared(); - SetGameLiftClient(m_gameliftClientMockPtr); - } - - AZStd::shared_ptr m_gameliftClientMockPtr; -}; - class AWSGameLiftClientManagerTest : public AWSGameLiftClientFixture + , public IAWSGameLiftInternalRequests { protected: void SetUp() override { AWSGameLiftClientFixture::SetUp(); - m_gameliftClientManager = AZStd::make_unique(); - m_gameliftClientManager->SetUpMockClient(); + AZ::Interface::Register(this); + + m_gameliftClientMockPtr = AZStd::make_shared(); + m_gameliftClientManager = AZStd::make_unique(); m_gameliftClientManager->ActivateManager(); } @@ -156,10 +136,24 @@ protected: { m_gameliftClientManager->DeactivateManager(); m_gameliftClientManager.reset(); + m_gameliftClientMockPtr.reset(); + + AZ::Interface::Unregister(this); AWSGameLiftClientFixture::TearDown(); } + AZStd::shared_ptr GetGameLiftClient() const + { + return m_gameliftClientMockPtr; + } + + void SetGameLiftClient(AZStd::shared_ptr gameliftClient) + { + AZ_UNUSED(gameliftClient); + m_gameliftClientMockPtr.reset(); + } + AWSGameLiftSearchSessionsRequest GetValidSearchSessionsRequest() { AWSGameLiftSearchSessionsRequest request; @@ -230,7 +224,8 @@ protected: } public: - AZStd::unique_ptr m_gameliftClientManager; + AZStd::unique_ptr m_gameliftClientManager; + AZStd::shared_ptr m_gameliftClientMockPtr; }; TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutRegion_GetFalseAsResult) @@ -319,7 +314,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithValidRequest_GetSucce Aws::GameLift::Model::CreateGameSessionResult result; result.SetGameSession(Aws::GameLift::Model::GameSession()); Aws::GameLift::Model::CreateGameSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreateGameSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); m_gameliftClientManager->CreateSession(request); @@ -331,7 +326,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithValidRequest_GetError request.m_aliasId = "dummyAlias"; Aws::Client::AWSError error; Aws::GameLift::Model::CreateGameSessionOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreateGameSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); AZ_TEST_START_TRACE_SUPPRESSION; @@ -357,7 +352,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithValidRequest_Get Aws::GameLift::Model::CreateGameSessionResult result; result.SetGameSession(Aws::GameLift::Model::GameSession()); Aws::GameLift::Model::CreateGameSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreateGameSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -373,7 +368,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithValidRequest_Get request.m_aliasId = "dummyAlias"; Aws::Client::AWSError error; Aws::GameLift::Model::CreateGameSessionOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreateGameSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreateGameSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -403,7 +398,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithValidRequest_G Aws::GameLift::Model::StartGameSessionPlacementResult result; result.SetGameSessionPlacement(Aws::GameLift::Model::GameSessionPlacement()); Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, StartGameSessionPlacement(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); m_gameliftClientManager->CreateSession(request); @@ -416,7 +411,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueue_CallWithValidRequest_G request.m_placementId = "dummyPlacementId"; Aws::Client::AWSError error; Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, StartGameSessionPlacement(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); AZ_TEST_START_TRACE_SUPPRESSION; @@ -434,7 +429,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueueAsync_CallWithValidRequ Aws::GameLift::Model::StartGameSessionPlacementResult result; result.SetGameSessionPlacement(Aws::GameLift::Model::GameSessionPlacement()); Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, StartGameSessionPlacement(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -451,7 +446,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSessionOnQueueAsync_CallWithValidRequ request.m_placementId = "dummyPlacementId"; Aws::Client::AWSError error; Aws::GameLift::Model::StartGameSessionPlacementOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), StartGameSessionPlacement(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, StartGameSessionPlacement(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -489,7 +484,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestButNoReques Aws::GameLift::Model::CreatePlayerSessionResult result; result.SetPlayerSession(Aws::GameLift::Model::PlayerSession()); Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); AZ_TEST_START_TRACE_SUPPRESSION; @@ -505,7 +500,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequest_GetErrorOu request.m_playerId = "dummyPlayerId"; Aws::Client::AWSError error; Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); AZ_TEST_START_TRACE_SUPPRESSION; @@ -524,7 +519,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestAndRequestH Aws::GameLift::Model::CreatePlayerSessionResult result; result.SetPlayerSession(Aws::GameLift::Model::PlayerSession()); Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); auto response = m_gameliftClientManager->JoinSession(request); @@ -541,7 +536,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithValidRequestAndRequestH Aws::GameLift::Model::CreatePlayerSessionResult result; result.SetPlayerSession(Aws::GameLift::Model::PlayerSession()); Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); auto response = m_gameliftClientManager->JoinSession(request); @@ -567,7 +562,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestButNoR Aws::GameLift::Model::CreatePlayerSessionResult result; result.SetPlayerSession(Aws::GameLift::Model::PlayerSession()); Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -586,7 +581,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequest_GetEr request.m_playerId = "dummyPlayerId"; Aws::Client::AWSError error; Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -608,7 +603,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestAndReq Aws::GameLift::Model::CreatePlayerSessionResult result; result.SetPlayerSession(Aws::GameLift::Model::PlayerSession()); Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -628,7 +623,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithValidRequestAndReq Aws::GameLift::Model::CreatePlayerSessionResult result; result.SetPlayerSession(Aws::GameLift::Model::PlayerSession()); Aws::GameLift::Model::CreatePlayerSessionOutcome outcome(result); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), CreatePlayerSession(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, CreatePlayerSession(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; @@ -642,7 +637,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessions_CallWithValidRequestAndError Aws::Client::AWSError error; Aws::GameLift::Model::SearchGameSessionsOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, SearchGameSessions(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); @@ -657,7 +652,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessions_CallWithValidRequestAndSucce AWSGameLiftSearchSessionsRequest request = GetValidSearchSessionsRequest(); Aws::GameLift::Model::SearchGameSessionsOutcome outcome = GetValidSearchGameSessionsOutcome(); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, SearchGameSessions(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); @@ -703,7 +698,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAnd Aws::Client::AWSError error; Aws::GameLift::Model::SearchGameSessionsOutcome outcome(error); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, SearchGameSessions(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); @@ -724,7 +719,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAnd EXPECT_CALL(coreHandlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get())); Aws::GameLift::Model::SearchGameSessionsOutcome outcome = GetValidSearchGameSessionsOutcome(); - EXPECT_CALL(*(m_gameliftClientManager->m_gameliftClientMockPtr), SearchGameSessions(::testing::_)) + EXPECT_CALL(*m_gameliftClientMockPtr, SearchGameSessions(::testing::_)) .Times(1) .WillOnce(::testing::Return(outcome)); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h index a161168159..5c09f43e08 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,6 +41,7 @@ public: MOCK_CONST_METHOD1(CreateGameSession, Model::CreateGameSessionOutcome(const Model::CreateGameSessionRequest&)); MOCK_CONST_METHOD1(CreatePlayerSession, Model::CreatePlayerSessionOutcome(const Model::CreatePlayerSessionRequest&)); + MOCK_CONST_METHOD1(DescribeMatchmaking, Model::DescribeMatchmakingOutcome(const Model::DescribeMatchmakingRequest&)); MOCK_CONST_METHOD1(SearchGameSessions, Model::SearchGameSessionsOutcome(const Model::SearchGameSessionsRequest&)); MOCK_CONST_METHOD1(StartGameSessionPlacement, Model::StartGameSessionPlacementOutcome(const Model::StartGameSessionPlacementRequest&)); }; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientSystemComponentTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientSystemComponentTest.cpp index df6fb0d666..096a182819 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientSystemComponentTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientSystemComponentTest.cpp @@ -13,10 +13,9 @@ #include #include +#include #include -#include - using namespace AWSGameLift; class AWSGameLiftClientManagerMock @@ -30,6 +29,17 @@ public: MOCK_METHOD0(DeactivateManager, void()); }; +class AWSGameLiftClientLocalTicketTrackerMock + : public AWSGameLiftClientLocalTicketTracker +{ +public: + AWSGameLiftClientLocalTicketTrackerMock() = default; + ~AWSGameLiftClientLocalTicketTrackerMock() = default; + + MOCK_METHOD0(ActivateTracker, void()); + MOCK_METHOD0(DeactivateTracker, void()); +}; + class TestAWSGameLiftClientSystemComponent : public AWSGameLiftClientSystemComponent { @@ -37,20 +47,29 @@ public: TestAWSGameLiftClientSystemComponent() { m_gameliftClientManagerMockPtr = nullptr; + m_gameliftClientTicketTrackerMockPtr = nullptr; } ~TestAWSGameLiftClientSystemComponent() { m_gameliftClientManagerMockPtr = nullptr; + m_gameliftClientTicketTrackerMockPtr = nullptr; } void SetUpMockManager() { - AZStd::unique_ptr gameliftClientManagerMock = AZStd::make_unique(); + AZStd::unique_ptr gameliftClientManagerMock = + AZStd::make_unique(); m_gameliftClientManagerMockPtr = gameliftClientManagerMock.get(); SetGameLiftClientManager(AZStd::move(gameliftClientManagerMock)); + + AZStd::unique_ptr gameliftClientTicketTrackerMock = + AZStd::make_unique(); + m_gameliftClientTicketTrackerMockPtr = gameliftClientTicketTrackerMock.get(); + SetGameLiftClientTicketTracker(AZStd::move(gameliftClientTicketTrackerMock)); } AWSGameLiftClientManagerMock* m_gameliftClientManagerMockPtr; + AWSGameLiftClientLocalTicketTrackerMock* m_gameliftClientTicketTrackerMockPtr; }; class AWSCoreSystemComponentMock @@ -145,8 +164,10 @@ TEST_F(AWSGameLiftClientSystemComponentTest, ActivateDeactivate_Call_GameLiftCli { m_entity->Init(); EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientManagerMockPtr), ActivateManager()).Times(1); + EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientTicketTrackerMockPtr), ActivateTracker()).Times(1); m_entity->Activate(); EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientManagerMockPtr), DeactivateManager()).Times(1); + EXPECT_CALL(*(m_gameliftClientSystemComponent->m_gameliftClientTicketTrackerMockPtr), DeactivateTracker()).Times(1); m_entity->Deactivate(); } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake index 0c7ca68eea..d3b9d8d1b9 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake @@ -7,6 +7,7 @@ # set(FILES + ../AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h Include/Request/AWSGameLiftAcceptMatchRequest.h Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h Include/Request/AWSGameLiftCreateSessionRequest.h @@ -27,6 +28,8 @@ set(FILES Source/Activity/AWSGameLiftLeaveSessionActivity.h Source/Activity/AWSGameLiftSearchSessionsActivity.cpp Source/Activity/AWSGameLiftSearchSessionsActivity.h + Source/AWSGameLiftClientLocalTicketTracker.cpp + Source/AWSGameLiftClientLocalTicketTracker.h Source/AWSGameLiftClientManager.cpp Source/AWSGameLiftClientManager.h Source/AWSGameLiftClientSystemComponent.cpp @@ -38,4 +41,6 @@ set(FILES Source/Request/AWSGameLiftSearchSessionsRequest.cpp Source/Request/AWSGameLiftStartMatchmakingRequest.cpp Source/Request/AWSGameLiftStopMatchmakingRequest.cpp + Source/Request/IAWSGameLiftInternalRequests.h + Source/Request/IAWSGameLiftMatchmakingInternalRequests.h ) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake index 6614eabb46..130ed28e4e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake @@ -12,6 +12,7 @@ set(FILES Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp Tests/AWSGameLiftClientFixture.h + Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp Tests/AWSGameLiftClientManagerTest.cpp Tests/AWSGameLiftClientMocks.h Tests/AWSGameLiftClientSystemComponentTest.cpp diff --git a/Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h b/Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h index 588bd51380..e29df324d3 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h @@ -17,4 +17,5 @@ namespace AWSGameLift static const char* AWSGameLiftSessionStatusReasons[2] = { "NotSet", "Interrupted" }; static constexpr const char AWSGameLiftErrorMessageTemplate[] = "Exception: %s, Message: %s"; + static constexpr const char AWSGameLiftClientMissingErrorMessage[] = "GameLift client is not configured yet."; } // namespace AWSGameLift From ba107c06b618dfdf933ccefd6f7de2ce7bf0d3d7 Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Wed, 6 Oct 2021 14:02:28 -0700 Subject: [PATCH 080/293] [LYN-6779] AWSNativeSDK update and AWSCore platform cmake update (#4231) Signed-off-by: onecent1101 --- Gems/AWSCore/Code/CMakeLists.txt | 16 ++--- .../Public/Framework/AWSApiJobConfig.h | 7 ++ .../Android/AWSCoreEditor_Traits_Android.h | 0 .../Android/AWSCoreEditor_Traits_Platform.h | 0 .../Platform/Android/AWSCore_Traits_Android.h | 10 +++ .../Android/AWSCore_Traits_Platform.h | 10 +++ .../Platform/Android/GetCertsPath_Android.cpp | 66 +++++++++---------- .../platform_android_editor_files.cmake} | 0 ...platform_android_editor_tests_files.cmake} | 0 .../Android/platform_android_files.cmake | 13 ++++ .../Platform/Common/GetCertsPath_Null.cpp | 56 ++++++++-------- .../Linux/AWSCoreEditor_Traits_Linux.h | 0 .../Linux/AWSCoreEditor_Traits_Platform.h | 0 .../Platform/Linux/AWSCore_Traits_Linux.h | 10 +++ .../Platform/Linux/AWSCore_Traits_Platform.h | 10 +++ .../Linux/platform_linux_editor_files.cmake} | 0 .../platform_linux_editor_tests_files.cmake} | 0 .../Linux/platform_linux_files.cmake} | 2 + .../Platform/Mac/AWSCoreEditor_Traits_Mac.h | 0 .../Mac/AWSCoreEditor_Traits_Platform.h | 0 .../Code/Platform/Mac/AWSCore_Traits_Mac.h | 10 +++ .../Platform/Mac/AWSCore_Traits_Platform.h | 10 +++ .../Mac/platform_mac_editor_files.cmake} | 0 .../platform_mac_editor_tests_files.cmake} | 3 +- .../Platform/Mac/platform_mac_files.cmake | 2 + .../Windows/AWSCoreEditor_Traits_Platform.h | 0 .../Windows/AWSCoreEditor_Traits_Windows.h | 0 .../Windows/AWSCore_Traits_Platform.h | 10 +++ .../Platform/Windows/AWSCore_Traits_Windows.h | 10 +++ .../platform_windows_editor_files.cmake} | 0 .../platform_windows_editor_tests_files.cmake | 19 ++++++ .../Windows/platform_windows_files.cmake | 13 ++++ .../iOS/AWSCoreEditor_Traits_Platform.h | 0 .../Platform/iOS/AWSCoreEditor_Traits_iOS.h | 0 .../Platform/iOS/AWSCore_Traits_Platform.h | 10 +++ .../Code/Platform/iOS/AWSCore_Traits_iOS.h | 10 +++ .../iOS/platform_ios_editor_files.cmake} | 0 .../platform_ios_editor_tests_files.cmake} | 3 +- .../Platform/iOS/platform_ios_files.cmake | 2 + .../Source/Editor/UI/AWSCoreEditorMenu.cpp | 2 +- .../Code/Source/Framework/AWSApiJobConfig.cpp | 10 --- .../awscore_editor_tests_windows_files.cmake | 19 ------ .../Android/BuiltInPackages_android.cmake | 2 +- .../Platform/iOS/BuiltInPackages_ios.cmake | 2 +- 44 files changed, 232 insertions(+), 105 deletions(-) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Android/AWSCoreEditor_Traits_Android.h (100%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Android/AWSCoreEditor_Traits_Platform.h (100%) create mode 100644 Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Android.h create mode 100644 Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Platform.h rename Gems/AWSCore/Code/{Source/Framework => }/Platform/Android/GetCertsPath_Android.cpp (97%) rename Gems/AWSCore/Code/{Include/Private/Editor/Platform/Android/platform_android_files.cmake => Platform/Android/platform_android_editor_files.cmake} (100%) rename Gems/AWSCore/Code/{Tests/Editor/Platform/Linux/awscore_editor_tests_linux_files.cmake => Platform/Android/platform_android_editor_tests_files.cmake} (100%) create mode 100644 Gems/AWSCore/Code/Platform/Android/platform_android_files.cmake rename Gems/AWSCore/Code/{Source/Framework => }/Platform/Common/GetCertsPath_Null.cpp (97%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Linux/AWSCoreEditor_Traits_Linux.h (100%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Linux/AWSCoreEditor_Traits_Platform.h (100%) create mode 100644 Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Linux.h create mode 100644 Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Platform.h rename Gems/AWSCore/Code/{Include/Private/Editor/Platform/Linux/platform_linux_files.cmake => Platform/Linux/platform_linux_editor_files.cmake} (100%) rename Gems/AWSCore/Code/{Tests/Editor/Platform/Mac/awscore_editor_tests_mac_files.cmake => Platform/Linux/platform_linux_editor_tests_files.cmake} (100%) rename Gems/AWSCore/Code/{Source/Framework/Platform/Windows/platform_windows_files.cmake => Platform/Linux/platform_linux_files.cmake} (82%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Mac/AWSCoreEditor_Traits_Mac.h (100%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Mac/AWSCoreEditor_Traits_Platform.h (100%) create mode 100644 Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Mac.h create mode 100644 Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Platform.h rename Gems/AWSCore/Code/{Include/Private/Editor/Platform/Mac/platform_mac_files.cmake => Platform/Mac/platform_mac_editor_files.cmake} (100%) rename Gems/AWSCore/Code/{Source/Framework/Platform/Android/platform_android_files.cmake => Platform/Mac/platform_mac_editor_tests_files.cmake} (84%) rename Gems/AWSCore/Code/{Source/Framework => }/Platform/Mac/platform_mac_files.cmake (82%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Windows/AWSCoreEditor_Traits_Platform.h (100%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/Windows/AWSCoreEditor_Traits_Windows.h (100%) create mode 100644 Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Platform.h create mode 100644 Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Windows.h rename Gems/AWSCore/Code/{Include/Private/Editor/Platform/Windows/platform_windows_files.cmake => Platform/Windows/platform_windows_editor_files.cmake} (100%) create mode 100644 Gems/AWSCore/Code/Platform/Windows/platform_windows_editor_tests_files.cmake create mode 100644 Gems/AWSCore/Code/Platform/Windows/platform_windows_files.cmake rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/iOS/AWSCoreEditor_Traits_Platform.h (100%) rename Gems/AWSCore/Code/{Include/Private/Editor => }/Platform/iOS/AWSCoreEditor_Traits_iOS.h (100%) create mode 100644 Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_Platform.h create mode 100644 Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h rename Gems/AWSCore/Code/{Include/Private/Editor/Platform/iOS/platform_ios_files.cmake => Platform/iOS/platform_ios_editor_files.cmake} (100%) rename Gems/AWSCore/Code/{Source/Framework/Platform/Linux/platform_linux_files.cmake => Platform/iOS/platform_ios_editor_tests_files.cmake} (82%) rename Gems/AWSCore/Code/{Source/Framework => }/Platform/iOS/platform_ios_files.cmake (82%) delete mode 100644 Gems/AWSCore/Code/Tests/Editor/Platform/Windows/awscore_editor_tests_windows_files.cmake diff --git a/Gems/AWSCore/Code/CMakeLists.txt b/Gems/AWSCore/Code/CMakeLists.txt index 808436b7fd..7559f4720b 100644 --- a/Gems/AWSCore/Code/CMakeLists.txt +++ b/Gems/AWSCore/Code/CMakeLists.txt @@ -6,18 +6,18 @@ # # -ly_get_list_relative_pal_filename(pal_editor_include_dir ${CMAKE_CURRENT_LIST_DIR}/Include/Private/Editor/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(pal_cafile_include_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Framework/Platform/${PAL_PLATFORM_NAME}) +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) ly_add_target( NAME AWSCore.Static STATIC NAMESPACE Gem FILES_CMAKE awscore_files.cmake - ${pal_cafile_include_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PUBLIC Include/Public + ${pal_dir} PRIVATE Include/Private BUILD_DEPENDENCIES @@ -65,11 +65,11 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) NAMESPACE Gem FILES_CMAKE awscore_editor_files.cmake - ${pal_editor_include_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_editor_files.cmake INCLUDE_DIRECTORIES PRIVATE Include/Private - ${pal_editor_include_dir} + ${pal_dir} PUBLIC Include/Public BUILD_DEPENDENCIES @@ -164,12 +164,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAMESPACE Gem FILES_CMAKE awscore_editor_tests_files.cmake - ${pal_editor_include_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake - Tests/Editor/Platform/${PAL_PLATFORM_NAME}/awscore_editor_tests_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_editor_files.cmake + ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_editor_tests_files.cmake INCLUDE_DIRECTORIES PRIVATE Include/Private - ${pal_editor_include_dir} + ${pal_dir} Include/Public Tests COMPILE_DEFINITIONS diff --git a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h index 9d8b0a5e93..0f25c648d0 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h @@ -13,12 +13,15 @@ #include #include +#include + // The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly. // AWSAllocator.h(70): warning C4996: 'std::allocator::pointer': warning STL4010: Various members of std::allocator are deprecated in C++17. // Use std::allocator_traits instead of accessing these members directly. // You can define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option") +#include #include #include #include @@ -136,7 +139,11 @@ namespace AWSCore Override> writeRateLimiter; Override> readRateLimiter; Override httpLibOverride; +#if AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE + Override followRedirects; +#else Override followRedirects; +#endif Override caFile; /// Applys settings changes made after first use. diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Android/AWSCoreEditor_Traits_Android.h b/Gems/AWSCore/Code/Platform/Android/AWSCoreEditor_Traits_Android.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Android/AWSCoreEditor_Traits_Android.h rename to Gems/AWSCore/Code/Platform/Android/AWSCoreEditor_Traits_Android.h diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Android/AWSCoreEditor_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Android/AWSCoreEditor_Traits_Platform.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Android/AWSCoreEditor_Traits_Platform.h rename to Gems/AWSCore/Code/Platform/Android/AWSCoreEditor_Traits_Platform.h diff --git a/Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Android.h b/Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Android.h new file mode 100644 index 0000000000..2cacfb0d34 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Android.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 1 diff --git a/Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Platform.h new file mode 100644 index 0000000000..6beeb3442d --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Android/AWSCore_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Gems/AWSCore/Code/Source/Framework/Platform/Android/GetCertsPath_Android.cpp b/Gems/AWSCore/Code/Platform/Android/GetCertsPath_Android.cpp similarity index 97% rename from Gems/AWSCore/Code/Source/Framework/Platform/Android/GetCertsPath_Android.cpp rename to Gems/AWSCore/Code/Platform/Android/GetCertsPath_Android.cpp index 9dbacce2dd..557e29c3b6 100644 --- a/Gems/AWSCore/Code/Source/Framework/Platform/Android/GetCertsPath_Android.cpp +++ b/Gems/AWSCore/Code/Platform/Android/GetCertsPath_Android.cpp @@ -1,33 +1,33 @@ -/* - * 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 -// The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly. -// AWSAllocator.h(70): warning C4996: 'std::allocator::pointer': warning STL4010: Various members of std::allocator are deprecated in -// C++17. Use std::allocator_traits instead of accessing these members directly. You can define -// _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received -// this warning. -AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING -#include -#include - -namespace AWSCore -{ - namespace Platform - { - Aws::String GetCaCertBundlePath() - { - AZStd::string publicStoragePath = AZ::Android::Utils::GetAppPublicStoragePath(); - publicStoragePath.append("/certificates/aws/cacert.pem"); - - return publicStoragePath.c_str(); - } - } // namespace Platform -} +/* + * 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 +// The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly. +// AWSAllocator.h(70): warning C4996: 'std::allocator::pointer': warning STL4010: Various members of std::allocator are deprecated in +// C++17. Use std::allocator_traits instead of accessing these members directly. You can define +// _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received +// this warning. +AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING +#include +#include + +namespace AWSCore +{ + namespace Platform + { + Aws::String GetCaCertBundlePath() + { + AZStd::string publicStoragePath = AZ::Android::Utils::GetAppPublicStoragePath(); + publicStoragePath.append("/certificates/aws/cacert.pem"); + + return publicStoragePath.c_str(); + } + } // namespace Platform +} diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Android/platform_android_files.cmake b/Gems/AWSCore/Code/Platform/Android/platform_android_editor_files.cmake similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Android/platform_android_files.cmake rename to Gems/AWSCore/Code/Platform/Android/platform_android_editor_files.cmake diff --git a/Gems/AWSCore/Code/Tests/Editor/Platform/Linux/awscore_editor_tests_linux_files.cmake b/Gems/AWSCore/Code/Platform/Android/platform_android_editor_tests_files.cmake similarity index 100% rename from Gems/AWSCore/Code/Tests/Editor/Platform/Linux/awscore_editor_tests_linux_files.cmake rename to Gems/AWSCore/Code/Platform/Android/platform_android_editor_tests_files.cmake diff --git a/Gems/AWSCore/Code/Platform/Android/platform_android_files.cmake b/Gems/AWSCore/Code/Platform/Android/platform_android_files.cmake new file mode 100644 index 0000000000..e5b02beeac --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Android/platform_android_files.cmake @@ -0,0 +1,13 @@ +# +# 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 +# +# + +set(FILES + AWSCore_Traits_Platform.h + AWSCore_Traits_Android.h + GetCertsPath_Android.cpp +) diff --git a/Gems/AWSCore/Code/Source/Framework/Platform/Common/GetCertsPath_Null.cpp b/Gems/AWSCore/Code/Platform/Common/GetCertsPath_Null.cpp similarity index 97% rename from Gems/AWSCore/Code/Source/Framework/Platform/Common/GetCertsPath_Null.cpp rename to Gems/AWSCore/Code/Platform/Common/GetCertsPath_Null.cpp index 5731327fb2..45bb45000f 100644 --- a/Gems/AWSCore/Code/Source/Framework/Platform/Common/GetCertsPath_Null.cpp +++ b/Gems/AWSCore/Code/Platform/Common/GetCertsPath_Null.cpp @@ -1,28 +1,28 @@ -/* - * 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 -// The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly. -// AWSAllocator.h(70): warning C4996: 'std::allocator::pointer': warning STL4010: Various members of std::allocator are deprecated in -// C++17. Use std::allocator_traits instead of accessing these members directly. You can define -// _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received -// this warning. -AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -namespace AWSCore -{ - namespace Platform - { - Aws::String GetCaCertBundlePath() - { - return ""; // no-op - } - } // namespace Platform -} // namespace GridMate +/* + * 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 +// The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly. +// AWSAllocator.h(70): warning C4996: 'std::allocator::pointer': warning STL4010: Various members of std::allocator are deprecated in +// C++17. Use std::allocator_traits instead of accessing these members directly. You can define +// _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received +// this warning. +AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option") +#include +AZ_POP_DISABLE_WARNING + +namespace AWSCore +{ + namespace Platform + { + Aws::String GetCaCertBundlePath() + { + return ""; // no-op + } + } // namespace Platform +} // namespace GridMate diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Linux/AWSCoreEditor_Traits_Linux.h b/Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Linux.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Linux/AWSCoreEditor_Traits_Linux.h rename to Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Linux.h diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Linux/AWSCoreEditor_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Platform.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Linux/AWSCoreEditor_Traits_Platform.h rename to Gems/AWSCore/Code/Platform/Linux/AWSCoreEditor_Traits_Platform.h diff --git a/Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Linux.h b/Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Linux.h new file mode 100644 index 0000000000..d7b1f32461 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Linux.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 0 diff --git a/Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Platform.h new file mode 100644 index 0000000000..d6ef9ceb4d --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Linux/AWSCore_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Linux/platform_linux_files.cmake b/Gems/AWSCore/Code/Platform/Linux/platform_linux_editor_files.cmake similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Linux/platform_linux_files.cmake rename to Gems/AWSCore/Code/Platform/Linux/platform_linux_editor_files.cmake diff --git a/Gems/AWSCore/Code/Tests/Editor/Platform/Mac/awscore_editor_tests_mac_files.cmake b/Gems/AWSCore/Code/Platform/Linux/platform_linux_editor_tests_files.cmake similarity index 100% rename from Gems/AWSCore/Code/Tests/Editor/Platform/Mac/awscore_editor_tests_mac_files.cmake rename to Gems/AWSCore/Code/Platform/Linux/platform_linux_editor_tests_files.cmake diff --git a/Gems/AWSCore/Code/Source/Framework/Platform/Windows/platform_windows_files.cmake b/Gems/AWSCore/Code/Platform/Linux/platform_linux_files.cmake similarity index 82% rename from Gems/AWSCore/Code/Source/Framework/Platform/Windows/platform_windows_files.cmake rename to Gems/AWSCore/Code/Platform/Linux/platform_linux_files.cmake index 0abbd1adb8..1661434740 100644 --- a/Gems/AWSCore/Code/Source/Framework/Platform/Windows/platform_windows_files.cmake +++ b/Gems/AWSCore/Code/Platform/Linux/platform_linux_files.cmake @@ -7,5 +7,7 @@ # set(FILES + AWSCore_Traits_Platform.h + AWSCore_Traits_Linux.h ../Common/GetCertsPath_Null.cpp ) diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Mac/AWSCoreEditor_Traits_Mac.h b/Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Mac.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Mac/AWSCoreEditor_Traits_Mac.h rename to Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Mac.h diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Mac/AWSCoreEditor_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Platform.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Mac/AWSCoreEditor_Traits_Platform.h rename to Gems/AWSCore/Code/Platform/Mac/AWSCoreEditor_Traits_Platform.h diff --git a/Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Mac.h b/Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Mac.h new file mode 100644 index 0000000000..d7b1f32461 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Mac.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 0 diff --git a/Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Platform.h new file mode 100644 index 0000000000..2d33c834f9 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Mac/AWSCore_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Mac/platform_mac_files.cmake b/Gems/AWSCore/Code/Platform/Mac/platform_mac_editor_files.cmake similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Mac/platform_mac_files.cmake rename to Gems/AWSCore/Code/Platform/Mac/platform_mac_editor_files.cmake diff --git a/Gems/AWSCore/Code/Source/Framework/Platform/Android/platform_android_files.cmake b/Gems/AWSCore/Code/Platform/Mac/platform_mac_editor_tests_files.cmake similarity index 84% rename from Gems/AWSCore/Code/Source/Framework/Platform/Android/platform_android_files.cmake rename to Gems/AWSCore/Code/Platform/Mac/platform_mac_editor_tests_files.cmake index 278e4a1c9d..07f96644ab 100644 --- a/Gems/AWSCore/Code/Source/Framework/Platform/Android/platform_android_files.cmake +++ b/Gems/AWSCore/Code/Platform/Mac/platform_mac_editor_tests_files.cmake @@ -6,6 +6,5 @@ # # -set(FILES - GetCertsPath_Android.cpp +set(FILES ) diff --git a/Gems/AWSCore/Code/Source/Framework/Platform/Mac/platform_mac_files.cmake b/Gems/AWSCore/Code/Platform/Mac/platform_mac_files.cmake similarity index 82% rename from Gems/AWSCore/Code/Source/Framework/Platform/Mac/platform_mac_files.cmake rename to Gems/AWSCore/Code/Platform/Mac/platform_mac_files.cmake index 0abbd1adb8..3e5e99cc05 100644 --- a/Gems/AWSCore/Code/Source/Framework/Platform/Mac/platform_mac_files.cmake +++ b/Gems/AWSCore/Code/Platform/Mac/platform_mac_files.cmake @@ -7,5 +7,7 @@ # set(FILES + AWSCore_Traits_Platform.h + AWSCore_Traits_Mac.h ../Common/GetCertsPath_Null.cpp ) diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Windows/AWSCoreEditor_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Platform.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Windows/AWSCoreEditor_Traits_Platform.h rename to Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Platform.h diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Windows/AWSCoreEditor_Traits_Windows.h b/Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Windows.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Windows/AWSCoreEditor_Traits_Windows.h rename to Gems/AWSCore/Code/Platform/Windows/AWSCoreEditor_Traits_Windows.h diff --git a/Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Platform.h b/Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Platform.h new file mode 100644 index 0000000000..f6ccf10b88 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Windows.h b/Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Windows.h new file mode 100644 index 0000000000..d7b1f32461 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Windows/AWSCore_Traits_Windows.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 0 diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/Windows/platform_windows_files.cmake b/Gems/AWSCore/Code/Platform/Windows/platform_windows_editor_files.cmake similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/Windows/platform_windows_files.cmake rename to Gems/AWSCore/Code/Platform/Windows/platform_windows_editor_files.cmake diff --git a/Gems/AWSCore/Code/Platform/Windows/platform_windows_editor_tests_files.cmake b/Gems/AWSCore/Code/Platform/Windows/platform_windows_editor_tests_files.cmake new file mode 100644 index 0000000000..3b87d2f3bb --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Windows/platform_windows_editor_tests_files.cmake @@ -0,0 +1,19 @@ +# +# 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 +# +# + +set(FILES + ../../Tests/Editor/AWSCoreEditorSystemComponentTest.cpp + ../../Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp + ../../Tests/Editor/Attribution/AWSCoreAttributionMetricTest.cpp + ../../Tests/Editor/Attribution/AWSCoreAttributionSystemComponentTest.cpp + ../../Tests/Editor/Attribution/AWSAttributionServiceApiTest.cpp + ../../Tests/Editor/UI/AWSCoreEditorMenuTest.cpp + ../../Tests/Editor/UI/AWSCoreEditorUIFixture.h + ../../Tests/Editor/UI/AWSCoreResourceMappingToolActionTest.cpp + ../../Tests/Editor/AWSCoreEditorManagerTest.cpp +) diff --git a/Gems/AWSCore/Code/Platform/Windows/platform_windows_files.cmake b/Gems/AWSCore/Code/Platform/Windows/platform_windows_files.cmake new file mode 100644 index 0000000000..aa0119d042 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/Windows/platform_windows_files.cmake @@ -0,0 +1,13 @@ +# +# 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 +# +# + +set(FILES + AWSCore_Traits_Platform.h + AWSCore_Traits_Windows.h + ../Common/GetCertsPath_Null.cpp +) diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/iOS/AWSCoreEditor_Traits_Platform.h b/Gems/AWSCore/Code/Platform/iOS/AWSCoreEditor_Traits_Platform.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/iOS/AWSCoreEditor_Traits_Platform.h rename to Gems/AWSCore/Code/Platform/iOS/AWSCoreEditor_Traits_Platform.h diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/iOS/AWSCoreEditor_Traits_iOS.h b/Gems/AWSCore/Code/Platform/iOS/AWSCoreEditor_Traits_iOS.h similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/iOS/AWSCoreEditor_Traits_iOS.h rename to Gems/AWSCore/Code/Platform/iOS/AWSCoreEditor_Traits_iOS.h diff --git a/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_Platform.h b/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_Platform.h new file mode 100644 index 0000000000..7384900938 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h b/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h new file mode 100644 index 0000000000..d7b1f32461 --- /dev/null +++ b/Gems/AWSCore/Code/Platform/iOS/AWSCore_Traits_iOS.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 0 diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Platform/iOS/platform_ios_files.cmake b/Gems/AWSCore/Code/Platform/iOS/platform_ios_editor_files.cmake similarity index 100% rename from Gems/AWSCore/Code/Include/Private/Editor/Platform/iOS/platform_ios_files.cmake rename to Gems/AWSCore/Code/Platform/iOS/platform_ios_editor_files.cmake diff --git a/Gems/AWSCore/Code/Source/Framework/Platform/Linux/platform_linux_files.cmake b/Gems/AWSCore/Code/Platform/iOS/platform_ios_editor_tests_files.cmake similarity index 82% rename from Gems/AWSCore/Code/Source/Framework/Platform/Linux/platform_linux_files.cmake rename to Gems/AWSCore/Code/Platform/iOS/platform_ios_editor_tests_files.cmake index 0abbd1adb8..07f96644ab 100644 --- a/Gems/AWSCore/Code/Source/Framework/Platform/Linux/platform_linux_files.cmake +++ b/Gems/AWSCore/Code/Platform/iOS/platform_ios_editor_tests_files.cmake @@ -6,6 +6,5 @@ # # -set(FILES - ../Common/GetCertsPath_Null.cpp +set(FILES ) diff --git a/Gems/AWSCore/Code/Source/Framework/Platform/iOS/platform_ios_files.cmake b/Gems/AWSCore/Code/Platform/iOS/platform_ios_files.cmake similarity index 82% rename from Gems/AWSCore/Code/Source/Framework/Platform/iOS/platform_ios_files.cmake rename to Gems/AWSCore/Code/Platform/iOS/platform_ios_files.cmake index 0abbd1adb8..c73796afe3 100644 --- a/Gems/AWSCore/Code/Source/Framework/Platform/iOS/platform_ios_files.cmake +++ b/Gems/AWSCore/Code/Platform/iOS/platform_ios_files.cmake @@ -7,5 +7,7 @@ # set(FILES + AWSCore_Traits_Platform.h + AWSCore_Traits_iOS.h ../Common/GetCertsPath_Null.cpp ) diff --git a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp index 0b485609ad..d55510930e 100644 --- a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp +++ b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp @@ -78,7 +78,7 @@ namespace AWSCore void AWSCoreEditorMenu::InitializeResourceMappingToolAction() { -#ifdef AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED +#if AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED AWSCoreResourceMappingToolAction* resourceMappingTool = new AWSCoreResourceMappingToolAction(QObject::tr(AWSResourceMappingToolActionText), this); QObject::connect(resourceMappingTool, &QAction::triggered, this, diff --git a/Gems/AWSCore/Code/Source/Framework/AWSApiJobConfig.cpp b/Gems/AWSCore/Code/Source/Framework/AWSApiJobConfig.cpp index cc51213e09..0f15c862d5 100644 --- a/Gems/AWSCore/Code/Source/Framework/AWSApiJobConfig.cpp +++ b/Gems/AWSCore/Code/Source/Framework/AWSApiJobConfig.cpp @@ -12,16 +12,6 @@ #include #include -// The AWS Native SDK AWSAllocator triggers a warning due to accessing members of std::allocator directly. -// AWSAllocator.h(70): warning C4996: 'std::allocator::pointer': warning STL4010: Various members of std::allocator are deprecated in C++17. -// Use std::allocator_traits instead of accessing these members directly. -// You can define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. - -AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - - namespace AWSCore { void AwsApiJobConfig::ApplySettings() diff --git a/Gems/AWSCore/Code/Tests/Editor/Platform/Windows/awscore_editor_tests_windows_files.cmake b/Gems/AWSCore/Code/Tests/Editor/Platform/Windows/awscore_editor_tests_windows_files.cmake deleted file mode 100644 index 0d47bbe795..0000000000 --- a/Gems/AWSCore/Code/Tests/Editor/Platform/Windows/awscore_editor_tests_windows_files.cmake +++ /dev/null @@ -1,19 +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 -# -# - -set(FILES - ../../AWSCoreEditorSystemComponentTest.cpp - ../../Attribution/AWSCoreAttributionManagerTest.cpp - ../../Attribution/AWSCoreAttributionMetricTest.cpp - ../../Attribution/AWSCoreAttributionSystemComponentTest.cpp - ../../Attribution/AWSAttributionServiceApiTest.cpp - ../../UI/AWSCoreEditorMenuTest.cpp - ../../UI/AWSCoreEditorUIFixture.h - ../../UI/AWSCoreResourceMappingToolActionTest.cpp - ../../AWSCoreEditorManagerTest.cpp -) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index 4d17e4b20b..c1a770d1ff 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -18,7 +18,7 @@ ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux # platform-specific: ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-android TARGETS tiff PACKAGE_HASH 252b99e5886ec59fdccf38603c1399dd3fc02d878641aba35a7f8d2504065a06) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-android TARGETS freetype PACKAGE_HASH df9e4d559ea0f03b0666b48c79813b1cd4d9624429148a249865de9f5c2c11cd) -ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev6-android TARGETS AWSNativeSDK PACKAGE_HASH 1624ba9aaf03d001ed0ffc57d2f945ff82590e75a7ea868de35043cf673e82fb) +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.9.50-rev1-android TARGETS AWSNativeSDK PACKAGE_HASH 33771499f9080cbaab613459927e52911e68f94fa356397885e85005efbd1490) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-android TARGETS Lua PACKAGE_HASH 1f638e94a17a87fe9e588ea456d5893876094b4db191234380e4c4eb9e06c300) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS PhysX PACKAGE_HASH b8cb6aa46b2a21671f6cb1f6a78713a3ba88824d0447560ff5ce6c01014b9f43) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-android TARGETS mikkelsen PACKAGE_HASH 075e8e4940884971063b5a9963014e2e517246fa269c07c7dc55b8cf2cd99705) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index c9de80c809..abfba29e5a 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -19,7 +19,7 @@ ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux # platform-specific: ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-ios TARGETS tiff PACKAGE_HASH d864beb0c955a55f28c2a993843afb2ecf6e01519ddfc857cedf34fc5db68d49) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-ios TARGETS freetype PACKAGE_HASH 3ac3c35e056ae4baec2e40caa023d76a7a3320895ef172b6655e9261b0dc2e29) -ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev3-ios TARGETS AWSNativeSDK PACKAGE_HASH 1246219a213ccfff76b526011febf521586d44dbc1753e474f8fb5fd861654a4) +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-ios TARGETS AWSNativeSDK PACKAGE_HASH d10e7496ca705577032821011beaf9f2507689f23817bfa0ed4d2a2758afcd02) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-ios TARGETS Lua PACKAGE_HASH c2d3c4e67046c293049292317a7d60fdb8f23effeea7136aefaef667163e5ffe) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-ios TARGETS PhysX PACKAGE_HASH b1bbc1fc068d2c6e1eb18eecd4e8b776adc516833e8da3dcb1970cef2a8f0cbd) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-ios TARGETS mikkelsen PACKAGE_HASH 976aaa3ccd8582346132a10af253822ccc5d5bcc9ea5ba44d27848f65ee88a8a) From 8fc8baa5792cbdabfdc8581db994c203556c52b9 Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Wed, 6 Oct 2021 17:03:03 -0500 Subject: [PATCH 081/293] Terrain FP now pulls data from Terrain system (#4492) * Feature processor now pulls data instead of the render component pushing it. This results in fewer and cheaper heightmap rebuilds. The feature processor can also handle dirty regions correctly now, although it doesn't seem like they are being passed in correctly yet. Signed-off-by: Ken Pruiksma * Fixing issues with initialization, dirty region tracking, and total rendered world size. Signed-off-by: Ken Pruiksma * Fixing bug with resizing the world Signed-off-by: Ken Pruiksma * Decreasing the scope of a mutex Signed-off-by: Ken Pruiksma * Fixes from PR review Signed-off-by: Ken Pruiksma * Fixed a math issue with float rounding. Fixed static AZ::Name usage. Signed-off-by: Ken Pruiksma * Removing unused variable Signed-off-by: Ken Pruiksma --- .../TerrainWorldRendererComponent.cpp | 71 -------- .../TerrainWorldRendererComponent.h | 5 - .../TerrainFeatureProcessor.cpp | 163 +++++++++++++----- .../TerrainRenderer/TerrainFeatureProcessor.h | 49 ++---- 4 files changed, 142 insertions(+), 146 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp index f3eed41717..9cd9ce9fb2 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.cpp @@ -13,8 +13,6 @@ #include #include -#include - #include #include #include @@ -135,17 +133,13 @@ namespace Terrain { m_terrainFeatureProcessor = scene->EnableFeatureProcessor(); } - - AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect(); m_terrainRendererActive = true; } void TerrainWorldRendererComponent::Deactivate() { // On component deactivation, unregister the feature processor and remove it from the default scene. - m_terrainRendererActive = false; - AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect(); if (AZ::RPI::Scene* scene = GetScene(); scene) { @@ -178,69 +172,4 @@ namespace Terrain } return false; } - - void TerrainWorldRendererComponent::OnTerrainDataDestroyBegin() - { - // If the terrain is being destroyed, remove all existing terrain data from the feature processor. - - if (m_terrainFeatureProcessor) - { - m_terrainFeatureProcessor->RemoveTerrainData(); - } - } - - void TerrainWorldRendererComponent::OnTerrainDataChanged([[maybe_unused]] const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask) - { - // Block other threads from accessing the surface data bus while we are in GetValue (which may call into the SurfaceData bus). - // We lock our surface data mutex *before* checking / setting "isRequestInProgress" so that we prevent race conditions - // that create false detection of cyclic dependencies when multiple requests occur on different threads simultaneously. - // (One case where this was previously able to occur was in rapid updating of the Preview widget on the - // GradientSurfaceDataComponent in the Editor when moving the threshold sliders back and forth rapidly) - auto& surfaceDataContext = SurfaceData::SurfaceDataSystemRequestBus::GetOrCreateContext(false); - typename SurfaceData::SurfaceDataSystemRequestBus::Context::DispatchLockGuard scopeLock(surfaceDataContext.m_contextMutex); - - AZ::Vector2 queryResolution = AZ::Vector2(1.0f); - AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( - queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution); - - AZ::Aabb worldBounds = AZ::Aabb::CreateNull(); - AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( - worldBounds, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb); - - - AZ::Transform transform = AZ::Transform::CreateTranslation(worldBounds.GetCenter()); - - uint32_t width = aznumeric_cast( - (float)worldBounds.GetXExtent() / queryResolution.GetX()); - uint32_t height = aznumeric_cast( - (float)worldBounds.GetYExtent() / queryResolution.GetY()); - AZStd::vector pixels; - pixels.resize_no_construct(width * height); - const uint32_t pixelDataSize = width * height * sizeof(float); - memset(pixels.data(), 0, pixelDataSize); - - for (uint32_t y = 0; y < height; y++) - { - for (uint32_t x = 0; x < width; x++) - { - bool terrainExists = true; - float terrainHeight = 0.0f; - AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( - terrainHeight, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, - (x * queryResolution.GetX()) + worldBounds.GetMin().GetX(), - (y * queryResolution.GetY()) + worldBounds.GetMin().GetY(), - AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, - &terrainExists); - - pixels[(y * width) + x] = - (terrainHeight - worldBounds.GetMin().GetZ()) / worldBounds.GetExtents().GetZ(); - } - } - - if (m_terrainFeatureProcessor) - { - m_terrainFeatureProcessor->UpdateTerrainData(transform, worldBounds, queryResolution.GetX(), width, height, pixels); - } - } - } diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h index cd2a4ea5aa..354b2fde34 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldRendererComponent.h @@ -9,8 +9,6 @@ #pragma once #include -#include -#include namespace LmbrCentral { @@ -54,7 +52,6 @@ namespace Terrain class TerrainWorldRendererComponent : public AZ::Component - , public AzFramework::Terrain::TerrainDataNotificationBus::Handler { public: template @@ -77,8 +74,6 @@ namespace Terrain bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; protected: - void OnTerrainDataDestroyBegin() override; - void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override; AZ::RPI::Scene* GetScene() const; diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index 59984a1b92..560fe1eb60 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -10,40 +10,41 @@ #include #include +#include #include #include +#include #include #include -#include +#include + #include #include #include #include -#include -#include #include #include -#include +#include #include #include + #include #include #include #include -#include -#include -#include -#include -#include + #include +#include + namespace Terrain { namespace { [[maybe_unused]] const char* TerrainFPName = "TerrainFeatureProcessor"; + const char* TerrainHeightmapChars = "TerrainHeightmap"; } namespace MaterialInputs @@ -71,7 +72,9 @@ namespace Terrain void TerrainFeatureProcessor::Activate() { m_areaData = {}; + m_dirtyRegion = AZ::Aabb::CreateNull(); Initialize(); + AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect(); } void TerrainFeatureProcessor::Initialize() @@ -99,13 +102,16 @@ namespace Terrain AZ_Error(TerrainFPName, false, "Failed to create Terrain render buffers!"); return; } + OnTerrainDataChanged(AZ::Aabb::CreateNull(), TerrainDataChangedMask::HeightData); } void TerrainFeatureProcessor::Deactivate() { + AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect(); + AZ::RPI::MaterialReloadNotificationBus::Handler::BusDisconnect(); + m_patchModel = {}; m_areaData = {}; - AZ::RPI::MaterialReloadNotificationBus::Handler::BusDisconnect(); } void TerrainFeatureProcessor::Render(const AZ::RPI::FeatureProcessor::RenderPacket& packet) @@ -113,51 +119,126 @@ namespace Terrain ProcessSurfaces(packet); } - void TerrainFeatureProcessor::UpdateTerrainData( - const AZ::Transform& transform, - const AZ::Aabb& worldBounds, - float sampleSpacing, - uint32_t width, uint32_t height, const AZStd::vector& heightData) + void TerrainFeatureProcessor::OnTerrainDataDestroyBegin() { - if (!worldBounds.IsValid()) + m_areaData = {}; + } + + void TerrainFeatureProcessor::OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) + { + if (dataChangedMask != TerrainDataChangedMask::HeightData && dataChangedMask != TerrainDataChangedMask::Settings) { return; } + AZ::Aabb worldBounds = AZ::Aabb::CreateNull(); + AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( + worldBounds, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb); + + const AZ::Aabb& regionToUpdate = dirtyRegion.IsValid() ? dirtyRegion : worldBounds; + + m_dirtyRegion.AddAabb(regionToUpdate); + m_dirtyRegion.Clamp(worldBounds); + + AZ::Transform transform = AZ::Transform::CreateTranslation(worldBounds.GetCenter()); + + AZ::Vector2 queryResolution = AZ::Vector2(1.0f); + AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( + queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution); + m_areaData.m_transform = transform; m_areaData.m_heightScale = worldBounds.GetZExtent(); m_areaData.m_terrainBounds = worldBounds; - m_areaData.m_heightmapImageHeight = height; - m_areaData.m_heightmapImageWidth = width; - m_areaData.m_sampleSpacing = sampleSpacing; + m_areaData.m_heightmapImageWidth = aznumeric_cast(worldBounds.GetXExtent() / queryResolution.GetX()); + m_areaData.m_heightmapImageHeight = aznumeric_cast(worldBounds.GetYExtent() / queryResolution.GetY()); + m_areaData.m_updateWidth = aznumeric_cast(m_dirtyRegion.GetXExtent() / queryResolution.GetX()); + m_areaData.m_updateHeight = aznumeric_cast(m_dirtyRegion.GetYExtent() / queryResolution.GetY()); + // Currently query resolution is multidimensional but the rendering system only supports this changing in one dimension. + m_areaData.m_sampleSpacing = queryResolution.GetX(); + m_areaData.m_propertiesDirty = true; + } + + void TerrainFeatureProcessor::UpdateTerrainData() + { + static const AZ::Name TerrainHeightmapName = AZ::Name(TerrainHeightmapChars); + + uint32_t width = m_areaData.m_updateWidth; + uint32_t height = m_areaData.m_updateHeight; + const AZ::Aabb& worldBounds = m_areaData.m_terrainBounds; + float queryResolution = m_areaData.m_sampleSpacing; + + AZ::RHI::Size worldSize = AZ::RHI::Size(m_areaData.m_heightmapImageWidth, m_areaData.m_heightmapImageHeight, 1); + + if (!m_areaData.m_heightmapImage || m_areaData.m_heightmapImage->GetDescriptor().m_size != worldSize) + { + // World size changed, so the whole world needs updating. + width = worldSize.m_width; + height = worldSize.m_height; + m_dirtyRegion = worldBounds; + + AZ::Data::Instance imagePool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); + AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D( + AZ::RHI::ImageBindFlags::ShaderRead, width, height, AZ::RHI::Format::R16_UNORM + ); + m_areaData.m_heightmapImage = AZ::RPI::AttachmentImage::Create(*imagePool.get(), imageDescriptor, TerrainHeightmapName, nullptr, nullptr); + AZ_Error(TerrainFPName, m_areaData.m_heightmapImage, "Failed to initialize the heightmap image!"); + } + + AZStd::vector pixels; + pixels.reserve(width * height); - // Create heightmap image data { - m_areaData.m_propertiesDirty = true; + // Block other threads from accessing the surface data bus while we are in GetHeightFromFloats (which may call into the SurfaceData bus). + // We lock our surface data mutex *before* checking / setting "isRequestInProgress" so that we prevent race conditions + // that create false detection of cyclic dependencies when multiple requests occur on different threads simultaneously. + // (One case where this was previously able to occur was in rapid updating of the Preview widget on the + // GradientSurfaceDataComponent in the Editor when moving the threshold sliders back and forth rapidly) - AZ::RHI::Size imageSize; - imageSize.m_width = width; - imageSize.m_height = height; + auto& surfaceDataContext = SurfaceData::SurfaceDataSystemRequestBus::GetOrCreateContext(false); + typename SurfaceData::SurfaceDataSystemRequestBus::Context::DispatchLockGuard scopeLock(surfaceDataContext.m_contextMutex); - AZStd::vector uint16Heights; - uint16Heights.reserve(heightData.size()); - for (float sampleHeight : heightData) + for (uint32_t y = 0; y < height; y++) { - float clampedSample = AZ::GetClamp(sampleHeight, 0.0f, 1.0f); - constexpr uint16_t MaxUint16 = 0xFFFF; - uint16Heights.push_back(aznumeric_cast(clampedSample * MaxUint16)); + for (uint32_t x = 0; x < width; x++) + { + bool terrainExists = true; + float terrainHeight = 0.0f; + AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( + terrainHeight, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, + (x * queryResolution) + m_dirtyRegion.GetMin().GetX(), + (y * queryResolution) + m_dirtyRegion.GetMin().GetY(), + AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, + &terrainExists); + + float clampedHeight = AZ::GetClamp((terrainHeight - worldBounds.GetMin().GetZ()) / worldBounds.GetExtents().GetZ(), 0.0f, 1.0f); + float expandedHeight = AZStd::roundf(clampedHeight * AZStd::numeric_limits::max()); + uint16_t uint16Height = aznumeric_cast(expandedHeight); + + pixels.push_back(uint16Height); + } } - - AZ::Data::Instance streamingImagePool = AZ::RPI::ImageSystemInterface::Get()->GetSystemStreamingPool(); - m_areaData.m_heightmapImage = AZ::RPI::StreamingImage::CreateFromCpuData(*streamingImagePool, - AZ::RHI::ImageDimension::Image2D, - imageSize, - AZ::RHI::Format::R16_UNORM, - (uint8_t*)uint16Heights.data(), - heightData.size() * sizeof(uint16_t)); - AZ_Error(TerrainFPName, m_areaData.m_heightmapImage, "Failed to initialize the heightmap image!"); } + if (m_areaData.m_heightmapImage) + { + const float left = (m_dirtyRegion.GetMin().GetX() - worldBounds.GetMin().GetX()) / queryResolution; + const float top = (m_dirtyRegion.GetMin().GetY() - worldBounds.GetMin().GetY()) / queryResolution; + AZ::RHI::ImageUpdateRequest imageUpdateRequest; + imageUpdateRequest.m_imageSubresourcePixelOffset.m_left = aznumeric_cast(left); + imageUpdateRequest.m_imageSubresourcePixelOffset.m_top = aznumeric_cast(top); + imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerRow = width * sizeof(uint16_t); + imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerImage = width * height * sizeof(uint16_t); + imageUpdateRequest.m_sourceSubresourceLayout.m_rowCount = height; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_width = width; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_height = height; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_depth = 1; + imageUpdateRequest.m_sourceData = pixels.data(); + imageUpdateRequest.m_image = m_areaData.m_heightmapImage->GetRHIImage(); + + m_areaData.m_heightmapImage->UpdateImageContents(imageUpdateRequest); + } + + m_dirtyRegion = AZ::Aabb::CreateNull(); } void TerrainFeatureProcessor::ProcessSurfaces(const FeatureProcessor::RenderPacket& process) @@ -169,8 +250,10 @@ namespace Terrain return; } - if (m_areaData.m_propertiesDirty && m_materialInstance) + if (m_areaData.m_propertiesDirty && m_materialInstance && m_materialInstance->CanCompile()) { + UpdateTerrainData(); + m_areaData.m_propertiesDirty = false; m_sectorData.clear(); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h index 32f88565c2..d8df9b328c 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h @@ -9,24 +9,12 @@ #pragma once #include -#include -#include -#include -#include -#include -#include +#include -#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include namespace AZ::RPI @@ -35,6 +23,7 @@ namespace AZ::RPI { class AsyncAssetLoader; } + class Material; class Model; } @@ -43,6 +32,7 @@ namespace Terrain class TerrainFeatureProcessor final : public AZ::RPI::FeatureProcessor , private AZ::RPI::MaterialReloadNotificationBus::Handler + , private AzFramework::Terrain::TerrainDataNotificationBus::Handler { public: AZ_RTTI(TerrainFeatureProcessor, "{D7DAC1F9-4A9F-4D3C-80AE-99579BF8AB1C}", AZ::RPI::FeatureProcessor); @@ -54,26 +44,13 @@ namespace Terrain TerrainFeatureProcessor() = default; ~TerrainFeatureProcessor() = default; - // AZ::Component overrides... + // AZ::RPI::FeatureProcessor overrides... void Activate() override; void Deactivate() override; - - // AZ::RPI::FeatureProcessor overrides... void Render(const AZ::RPI::FeatureProcessor::RenderPacket& packet) override; - // AZ::RPI::MaterialReloadNotificationBus::Handler overrides... - void OnMaterialReinitialized(const AZ::Data::Instance& material) override; - void SetWorldSize(AZ::Vector2 sizeInMeters); - void UpdateTerrainData(const AZ::Transform& transform, const AZ::Aabb& worldBounds, float sampleSpacing, - uint32_t width, uint32_t height, const AZStd::vector& heightData); - - void RemoveTerrainData() - { - m_areaData = {}; - } - private: struct ShaderTerrainData // Must align with struct in Object Srg @@ -104,10 +81,19 @@ namespace Terrain AZStd::vector m_indices; }; + // AZ::RPI::MaterialReloadNotificationBus::Handler overrides... + void OnMaterialReinitialized(const AZ::Data::Instance& material) override; + + // AzFramework::Terrain::TerrainDataNotificationBus overrides... + void OnTerrainDataDestroyBegin() override; + void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override; + void Initialize(); void InitializeTerrainPatch(uint16_t gridSize, float gridSpacing, PatchData& patchdata); bool InitializePatchModel(); + void UpdateTerrainData(); + void ProcessSurfaces(const FeatureProcessor::RenderPacket& process); AZ::Outcome> CreateBufferAsset( @@ -132,14 +118,17 @@ namespace Terrain AZ::Transform m_transform{ AZ::Transform::CreateIdentity() }; AZ::Aabb m_terrainBounds{ AZ::Aabb::CreateNull() }; float m_heightScale{ 0.0f }; - AZ::Data::Instance m_heightmapImage; + AZ::Data::Instance m_heightmapImage; uint32_t m_heightmapImageWidth{ 0 }; uint32_t m_heightmapImageHeight{ 0 }; + uint32_t m_updateWidth{ 0 }; + uint32_t m_updateHeight{ 0 }; bool m_propertiesDirty{ true }; float m_sampleSpacing{ 0.0f }; }; TerrainAreaData m_areaData; + AZ::Aabb m_dirtyRegion{ AZ::Aabb::CreateNull() }; struct SectorData { From 029ad32c84117536f04d7b9c12d779df26081171 Mon Sep 17 00:00:00 2001 From: Pip Potter <61438964+lmbr-pip@users.noreply.github.com> Date: Wed, 6 Oct 2021 15:24:21 -0700 Subject: [PATCH 082/293] lyn7131: Ensure AWS credential Cvars are not logged or shown in plain text (#4519) Signed-off-by: rppotter --- .../Private/Credential/AWSCVarCredentialHandler.h | 2 +- .../Source/Credential/AWSCVarCredentialHandler.cpp | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Gems/AWSCore/Code/Include/Private/Credential/AWSCVarCredentialHandler.h b/Gems/AWSCore/Code/Include/Private/Credential/AWSCVarCredentialHandler.h index 542177dcc4..388f8eefd5 100644 --- a/Gems/AWSCore/Code/Include/Private/Credential/AWSCVarCredentialHandler.h +++ b/Gems/AWSCore/Code/Include/Private/Credential/AWSCVarCredentialHandler.h @@ -21,7 +21,7 @@ namespace AWSCore { public: AWSCVarCredentialHandler() = default; - ~AWSCVarCredentialHandler() = default; + ~AWSCVarCredentialHandler() override = default; //! Activate handler and its credentials provider, make sure activation //! invoked after AWSNativeSDK init to avoid memory leak diff --git a/Gems/AWSCore/Code/Source/Credential/AWSCVarCredentialHandler.cpp b/Gems/AWSCore/Code/Source/Credential/AWSCVarCredentialHandler.cpp index 83487f665d..8102efa2f8 100644 --- a/Gems/AWSCore/Code/Source/Credential/AWSCVarCredentialHandler.cpp +++ b/Gems/AWSCore/Code/Source/Credential/AWSCVarCredentialHandler.cpp @@ -5,15 +5,14 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ - #include #include namespace AWSCore { - AZ_CVAR(AZ::CVarFixedString, cl_awsAccessKey, "", nullptr, AZ::ConsoleFunctorFlags::Null, "Override AWS access key"); - AZ_CVAR(AZ::CVarFixedString, cl_awsSecretKey, "", nullptr, AZ::ConsoleFunctorFlags::Null, "Override AWS secret key"); + AZ_CVAR(AZ::CVarFixedString, cl_awsAccessKey, "", nullptr, AZ::ConsoleFunctorFlags::IsInvisible, "Override AWS access key"); + AZ_CVAR(AZ::CVarFixedString, cl_awsSecretKey, "", nullptr, AZ::ConsoleFunctorFlags::IsInvisible, "Override AWS secret key"); static constexpr char AWSCVARCREDENTIALHANDLER_ALLOC_TAG[] = "AWSCVarCredentialHandler"; @@ -36,12 +35,12 @@ namespace AWSCore std::shared_ptr AWSCVarCredentialHandler::GetCredentialsProvider() { - auto accessKey = static_cast(cl_awsAccessKey); - auto secretKey = static_cast(cl_awsSecretKey); + const auto accessKey = static_cast(cl_awsAccessKey); + const auto secretKey = static_cast(cl_awsSecretKey); if (!accessKey.empty() && !secretKey.empty()) { - AZStd::lock_guard credentialsLock{m_credentialMutex}; + AZStd::lock_guard credentialsLock{ m_credentialMutex }; m_cvarCredentialsProvider = Aws::MakeShared( AWSCVARCREDENTIALHANDLER_ALLOC_TAG, accessKey.c_str(), secretKey.c_str()); return m_cvarCredentialsProvider; @@ -52,7 +51,7 @@ namespace AWSCore void AWSCVarCredentialHandler::ResetCredentialsProvider() { // Must reset credential provider after AWSNativeSDKs init or before AWSNativeSDKs shutdown - AZStd::lock_guard credentialsLock{m_credentialMutex}; + AZStd::lock_guard credentialsLock{ m_credentialMutex }; m_cvarCredentialsProvider.reset(); } } // namespace AWSCore From d36041d1b74060b9cd69a74e0d880e3c624791db Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 6 Oct 2021 15:48:54 -0700 Subject: [PATCH 083/293] Update based on feedback. Adding event to MPSystemComponent for receiving a server acceptance packet. The editor system component subscribes to this event and tells the server we're ready for entity updates Signed-off-by: Gene Walters --- .../Code/Include/Multiplayer/IMultiplayer.h | 5 ++++ .../MultiplayerEditorSystemComponent.cpp | 10 +++++++ .../Editor/MultiplayerEditorSystemComponent.h | 7 +++++ .../Source/MultiplayerSystemComponent.cpp | 27 ++++++++----------- .../Code/Source/MultiplayerSystemComponent.h | 2 ++ 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h index e32b6188eb..e32a5bd0f3 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h @@ -44,6 +44,7 @@ namespace Multiplayer using ClientDisconnectedEvent = AZ::Event<>; using ConnectionAcquiredEvent = AZ::Event; + using ServerAcceptanceReceivedEvent = AZ::Event<>; using SessionInitEvent = AZ::Event; using SessionShutdownEvent = AZ::Event; @@ -102,6 +103,10 @@ namespace Multiplayer //! @param handler The ConnectionAcquiredEvent Handler to add virtual void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) = 0; + //! Adds a ServerAcceptanceReceived Handler which is invoked when the client receives the accept packet from the server. + //! @param handler The ServerAcceptanceReceived Handler to add + virtual void AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler) = 0; + //! Adds a SessionInitEvent Handler which is invoked when a new network session starts. //! @param handler The SessionInitEvent Handler to add virtual void AddSessionInitHandler(SessionInitEvent::Handler& handler) = 0; diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index d13c6538db..3a48135bc3 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -62,6 +62,7 @@ namespace Multiplayer } MultiplayerEditorSystemComponent::MultiplayerEditorSystemComponent() + : m_serverAcceptanceReceivedHandler([this](){OnServerAcceptanceReceived();}) { ; } @@ -70,6 +71,7 @@ namespace Multiplayer { AzFramework::GameEntityContextEventBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + AZ::Interface::Get()->AddServerAcceptanceReceivedHandler(m_serverAcceptanceReceivedHandler); } void MultiplayerEditorSystemComponent::Deactivate() @@ -245,4 +247,12 @@ namespace Multiplayer void MultiplayerEditorSystemComponent::OnGameEntitiesReset() { } + + void MultiplayerEditorSystemComponent::OnServerAcceptanceReceived() + { + // We're now accepting the connection to the EditorServer. + // In normal game clients SendReadyForEntityUpdates will be enabled once the appropriate level's root spawnable is loaded, + // but since we're in Editor, we're already in the level. + AZ::Interface::Get()->SendReadyForEntityUpdates(true); + } } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h index 6a9e6a79b6..b1e9335697 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h @@ -8,6 +8,8 @@ #pragma once +#include "Multiplayer/IMultiplayer.h" + #include #include @@ -45,6 +47,9 @@ namespace Multiplayer MultiplayerEditorSystemComponent(); ~MultiplayerEditorSystemComponent() override = default; + //! Called once the editor receives the server's accept packet + void OnServerAcceptanceReceived(); + //! AZ::Component overrides. //! @{ void Activate() override; @@ -71,5 +76,7 @@ namespace Multiplayer IEditor* m_editor = nullptr; AzFramework::ProcessWatcher* m_serverProcess = nullptr; AzNetworking::ConnectionId m_editorConnId; + + ServerAcceptanceReceivedEvent::Handler m_serverAcceptanceReceivedHandler; }; } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 9b04cd98d4..d05139cb41 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -489,23 +489,13 @@ namespace Multiplayer { m_didHandshake = true; - // If this is an Editor then we're now accepting the connection to the EditorServer. - // In normal game clients SendReadyForEntityUpdates will be enabled once the appropriate level's root spawnable is loaded, - // but since we're in Editor, we're already in the level. - AZ::ApplicationTypeQuery applicationType; - AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::QueryApplicationType, applicationType); - if (applicationType.IsEditor()) - { - SendReadyForEntityUpdates(true); - } - else - { - AZ::CVarFixedString commandString = "sv_map " + packet.GetMap(); - AZ::Interface::Get()->PerformCommand(commandString.c_str()); + AZ::CVarFixedString commandString = "sv_map " + packet.GetMap(); + AZ::Interface::Get()->PerformCommand(commandString.c_str()); - AZ::CVarFixedString loadLevelString = "LoadLevel " + packet.GetMap(); - AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); - } + AZ::CVarFixedString loadLevelString = "LoadLevel " + packet.GetMap(); + AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); + + m_serverAcceptanceReceivedEvent.Signal(); return true; } @@ -800,6 +790,11 @@ namespace Multiplayer handler.Connect(m_connAcquiredEvent); } + void MultiplayerSystemComponent::AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler) + { + handler.Connect(m_serverAcceptanceReceivedEvent); + } + void MultiplayerSystemComponent::AddSessionInitHandler(SessionInitEvent::Handler& handler) { handler.Connect(m_initEvent); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index ba014f814a..4a4cdd4265 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -111,6 +111,7 @@ namespace Multiplayer void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override; void AddSessionInitHandler(SessionInitEvent::Handler& handler) override; void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override; + void AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler) override; bool StartHosting(uint16_t port, bool isDedicated = true) override; bool Connect(AZStd::string remoteAddress, uint16_t port) override; void Terminate(AzNetworking::DisconnectReason reason) override; @@ -151,6 +152,7 @@ namespace Multiplayer SessionInitEvent m_initEvent; SessionShutdownEvent m_shutdownEvent; ConnectionAcquiredEvent m_connAcquiredEvent; + ServerAcceptanceReceivedEvent m_serverAcceptanceReceivedEvent; ClientDisconnectedEvent m_clientDisconnectedEvent; AZStd::queue m_pendingConnectionTickets; From 50fe8bc04dcc652cb5bec4334d6c740400acfa55 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 6 Oct 2021 16:35:21 -0700 Subject: [PATCH 084/293] pass in AZ::Utils::GetProjectPath().c_str() directly since converting projectpath is not needed Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorSystemComponent.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 3a48135bc3..55a05e33a7 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -144,13 +144,11 @@ namespace Multiplayer } // Start the configured server if it's available - AZStd::string projectPath(AZ::Utils::GetProjectPath().c_str()); - AZStd::replace(projectPath.begin(), projectPath.end(), AZ::IO::WindowsPathSeparator, AZ::IO::PosixPathSeparator); AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZStd::string::format( R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s")", serverPath.c_str(), - projectPath.c_str(), + AZ::Utils::GetProjectPath().c_str(), static_cast(sv_defaultPlayerSpawnAsset).c_str()); processLaunchInfo.m_showWindow = true; processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; From 7e6d35b046fc640ea95ccec04448510b8c99fb09 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 6 Oct 2021 20:11:29 -0700 Subject: [PATCH 085/293] small fix to include using <> Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorSystemComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h index b1e9335697..4e4c6b677f 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h @@ -8,7 +8,7 @@ #pragma once -#include "Multiplayer/IMultiplayer.h" +#include #include From 3f2881ea4688285e8dc4685af2b6947cf68882a5 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Thu, 7 Oct 2021 10:00:18 +0100 Subject: [PATCH 086/293] Simplify viewport interaction model reset functionality (#4524) * simplify entity reset functionality Signed-off-by: hultonha * remove reference to removed shortcuts Signed-off-by: hultonha --- Code/Editor/Core/LevelEditorMenuHandler.cpp | 2 - .../EditorTransformComponentSelection.cpp | 44 +------------------ ...torTransformComponentSelectionRequestBus.h | 2 - 3 files changed, 2 insertions(+), 46 deletions(-) diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp index e568f05167..b53076361e 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp @@ -487,8 +487,6 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe editMenu.AddAction(AzToolsFramework::EditPivot); editMenu.AddAction(AzToolsFramework::EditReset); editMenu.AddAction(AzToolsFramework::EditResetManipulator); - editMenu.AddAction(AzToolsFramework::EditResetLocal); - editMenu.AddAction(AzToolsFramework::EditResetWorld); // Hide Selection editMenu.AddAction(AzToolsFramework::HideSelection); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index ccb72e1d50..dacae038d4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -103,10 +103,6 @@ namespace AzToolsFramework static const char* const ResetEntityTransformDesc = "Reset transform based on manipulator mode"; static const char* const ResetManipulatorTitle = "Reset Manipulator"; static const char* const ResetManipulatorDesc = "Reset the manipulator to recenter it on the selected entity"; - static const char* const ResetTransformLocalTitle = "Reset Transform (Local)"; - static const char* const ResetTransformLocalDesc = "Reset transform to local space"; - static const char* const ResetTransformWorldTitle = "Reset Transform (World)"; - static const char* const ResetTransformWorldDesc = "Reset transform to world space"; static const char* const EntityBoxSelectUndoRedoDesc = "Box Select Entities"; static const char* const EntityDeselectUndoRedoDesc = "Deselect Entity"; @@ -2424,45 +2420,9 @@ namespace AzToolsFramework AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::Key_R) }, EditResetManipulator, ResetManipulatorTitle, ResetManipulatorDesc, - AZStd::bind(AZStd::mem_fn(&EditorTransformComponentSelection::DelegateClearManipulatorOverride), this)); - - AddAction( - m_actions, { QKeySequence(Qt::ALT + Qt::Key_R) }, EditResetLocal, ResetTransformLocalTitle, ResetTransformLocalDesc, - [this]() - { - switch (m_mode) - { - case Mode::Rotation: - ResetOrientationForSelectedEntitiesLocal(); - break; - case Mode::Scale: - CopyScaleToSelectedEntitiesIndividualWorld(1.0f); - break; - case Mode::Translation: - // do nothing - break; - } - }); - - AddAction( - m_actions, { QKeySequence(Qt::SHIFT + Qt::Key_R) }, EditResetWorld, ResetTransformWorldTitle, ResetTransformWorldDesc, - [this]() + [this] { - switch (m_mode) - { - case Mode::Rotation: - { - // begin an undo batch so operations inside CopyOrientation... and - // DelegateClear... are grouped into a single undo/redo - ScopedUndoBatch undoBatch{ ResetTransformWorldTitle }; - CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity()); - ClearManipulatorOrientationOverride(); - } - break; - case Mode::Scale: - case Mode::Translation: - break; - } + DelegateClearManipulatorOverride(); }); AddAction( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h index d0c106a15e..35f5b0ba99 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h @@ -31,8 +31,6 @@ namespace AzToolsFramework constexpr inline AZ::Crc32 EditPivot = AZ_CRC_CE("com.o3de.action.editortransform.editpivot"); constexpr inline AZ::Crc32 EditReset = AZ_CRC_CE("com.o3de.action.editortransform.editreset"); constexpr inline AZ::Crc32 EditResetManipulator = AZ_CRC_CE("com.o3de.action.editortransform.editresetmanipulator"); - constexpr inline AZ::Crc32 EditResetLocal = AZ_CRC_CE("com.o3de.action.editortransform.editresetlocal"); - constexpr inline AZ::Crc32 EditResetWorld = AZ_CRC_CE("com.o3de.action.editortransform.editresetworld"); constexpr inline AZ::Crc32 ViewportUiVisible = AZ_CRC_CE("com.o3de.action.editortransform.viewportuivisible"); //@} From 3d1ec83f78e66e36e931a9ee50508b1397d14dbc Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Thu, 7 Oct 2021 10:01:30 +0100 Subject: [PATCH 087/293] Update naming to CameraInput types (#4527) * rename public facing Pivot cameras to Orbit - previous rename was a mistake Signed-off-by: hultonha * some more comment and naming updates to improve camera documentation Signed-off-by: hultonha --- .../EditorModularViewportCameraComposer.cpp | 76 +++++++++---------- .../EditorModularViewportCameraComposer.h | 16 ++-- .../EditorPreferencesPageViewportCamera.cpp | 52 ++++++------- .../EditorPreferencesPageViewportCamera.h | 10 +-- Code/Editor/EditorViewportSettings.cpp | 50 ++++++------ Code/Editor/EditorViewportSettings.h | 20 ++--- .../AzFramework/Viewport/CameraInput.cpp | 46 +++++------ .../AzFramework/Viewport/CameraInput.h | 73 +++++++++++------- .../AzFramework/Tests/CameraInputTests.cpp | 50 ++++++------ 9 files changed, 204 insertions(+), 189 deletions(-) diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp index c492010336..ce4a0a2e33 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.cpp +++ b/Code/Editor/EditorModularViewportCameraComposer.cpp @@ -96,7 +96,7 @@ namespace SandboxEditor cameras.AddCamera(m_firstPersonTranslateCamera); cameras.AddCamera(m_firstPersonScrollCamera); cameras.AddCamera(m_firstPersonFocusCamera); - cameras.AddCamera(m_pivotCamera); + cameras.AddCamera(m_orbitCamera); }); return controller; @@ -135,7 +135,7 @@ namespace SandboxEditor m_firstPersonRotateCamera->SetActivationEndedFn(showCursor); m_firstPersonPanCamera = AZStd::make_shared( - SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan, AzFramework::TranslatePivot); + SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan, AzFramework::TranslatePivotLook); m_firstPersonPanCamera->m_panSpeedFn = [] { @@ -155,7 +155,7 @@ namespace SandboxEditor const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds(); m_firstPersonTranslateCamera = AZStd::make_shared( - translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot); + translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook); m_firstPersonTranslateCamera->m_translateSpeedFn = [] { @@ -167,7 +167,7 @@ namespace SandboxEditor return SandboxEditor::CameraBoostMultiplier(); }; - m_firstPersonScrollCamera = AZStd::make_shared(); + m_firstPersonScrollCamera = AZStd::make_shared(); m_firstPersonScrollCamera->m_scrollSpeedFn = [] { @@ -196,82 +196,82 @@ namespace SandboxEditor m_firstPersonFocusCamera->SetPivotFn(pivotFn); - m_pivotCamera = AZStd::make_shared(SandboxEditor::CameraPivotChannelId()); + m_orbitCamera = AZStd::make_shared(SandboxEditor::CameraOrbitChannelId()); - m_pivotCamera->SetPivotFn( + m_orbitCamera->SetPivotFn( [pivotFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { return pivotFn(); }); - m_pivotRotateCamera = AZStd::make_shared(SandboxEditor::CameraPivotLookChannelId()); + m_orbitRotateCamera = AZStd::make_shared(SandboxEditor::CameraOrbitLookChannelId()); - m_pivotRotateCamera->m_rotateSpeedFn = [] + m_orbitRotateCamera->m_rotateSpeedFn = [] { return SandboxEditor::CameraRotateSpeed(); }; - m_pivotRotateCamera->m_invertYawFn = [] + m_orbitRotateCamera->m_invertYawFn = [] { - return SandboxEditor::CameraPivotYawRotationInverted(); + return SandboxEditor::CameraOrbitYawRotationInverted(); }; - m_pivotTranslateCamera = AZStd::make_shared( - translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslateOffset); + m_orbitTranslateCamera = AZStd::make_shared( + translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslateOffsetOrbit); - m_pivotTranslateCamera->m_translateSpeedFn = [] + m_orbitTranslateCamera->m_translateSpeedFn = [] { return SandboxEditor::CameraTranslateSpeed(); }; - m_pivotTranslateCamera->m_boostMultiplierFn = [] + m_orbitTranslateCamera->m_boostMultiplierFn = [] { return SandboxEditor::CameraBoostMultiplier(); }; - m_pivotDollyScrollCamera = AZStd::make_shared(); + m_orbitDollyScrollCamera = AZStd::make_shared(); - m_pivotDollyScrollCamera->m_scrollSpeedFn = [] + m_orbitDollyScrollCamera->m_scrollSpeedFn = [] { return SandboxEditor::CameraScrollSpeed(); }; - m_pivotDollyMoveCamera = AZStd::make_shared(SandboxEditor::CameraPivotDollyChannelId()); + m_orbitDollyMoveCamera = AZStd::make_shared(SandboxEditor::CameraOrbitDollyChannelId()); - m_pivotDollyMoveCamera->m_motionSpeedFn = [] + m_orbitDollyMoveCamera->m_motionSpeedFn = [] { return SandboxEditor::CameraDollyMotionSpeed(); }; - m_pivotPanCamera = AZStd::make_shared( - SandboxEditor::CameraPivotPanChannelId(), AzFramework::LookPan, AzFramework::TranslateOffset); + m_orbitPanCamera = AZStd::make_shared( + SandboxEditor::CameraOrbitPanChannelId(), AzFramework::LookPan, AzFramework::TranslateOffsetOrbit); - m_pivotPanCamera->m_panSpeedFn = [] + m_orbitPanCamera->m_panSpeedFn = [] { return SandboxEditor::CameraPanSpeed(); }; - m_pivotPanCamera->m_invertPanXFn = [] + m_orbitPanCamera->m_invertPanXFn = [] { return SandboxEditor::CameraPanInvertedX(); }; - m_pivotPanCamera->m_invertPanYFn = [] + m_orbitPanCamera->m_invertPanYFn = [] { return SandboxEditor::CameraPanInvertedY(); }; - m_pivotFocusCamera = - AZStd::make_shared(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusPivot); + m_orbitFocusCamera = + AZStd::make_shared(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusOrbit); - m_pivotFocusCamera->SetPivotFn(pivotFn); + m_orbitFocusCamera->SetPivotFn(pivotFn); - m_pivotCamera->m_pivotCameras.AddCamera(m_pivotRotateCamera); - m_pivotCamera->m_pivotCameras.AddCamera(m_pivotTranslateCamera); - m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyScrollCamera); - m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyMoveCamera); - m_pivotCamera->m_pivotCameras.AddCamera(m_pivotPanCamera); - m_pivotCamera->m_pivotCameras.AddCamera(m_pivotFocusCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitRotateCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitTranslateCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyScrollCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyMoveCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitPanCamera); + m_orbitCamera->m_orbitCameras.AddCamera(m_orbitFocusCamera); } void EditorModularViewportCameraComposer::OnEditorModularViewportCameraComposerSettingsChanged() @@ -282,12 +282,12 @@ namespace SandboxEditor m_firstPersonRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraFreeLookChannelId()); m_firstPersonFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId()); - m_pivotCamera->SetPivotInputChannelId(SandboxEditor::CameraPivotChannelId()); - m_pivotTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); - m_pivotPanCamera->SetPanInputChannelId(SandboxEditor::CameraPivotPanChannelId()); - m_pivotRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraPivotLookChannelId()); - m_pivotDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraPivotDollyChannelId()); - m_pivotFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId()); + m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId()); + m_orbitTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds); + m_orbitPanCamera->SetPanInputChannelId(SandboxEditor::CameraOrbitPanChannelId()); + m_orbitRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraOrbitLookChannelId()); + m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId()); + m_orbitFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId()); } void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId) diff --git a/Code/Editor/EditorModularViewportCameraComposer.h b/Code/Editor/EditorModularViewportCameraComposer.h index 90103dba43..9cfd6f3554 100644 --- a/Code/Editor/EditorModularViewportCameraComposer.h +++ b/Code/Editor/EditorModularViewportCameraComposer.h @@ -41,15 +41,15 @@ namespace SandboxEditor AZStd::shared_ptr m_firstPersonRotateCamera; AZStd::shared_ptr m_firstPersonPanCamera; AZStd::shared_ptr m_firstPersonTranslateCamera; - AZStd::shared_ptr m_firstPersonScrollCamera; + AZStd::shared_ptr m_firstPersonScrollCamera; AZStd::shared_ptr m_firstPersonFocusCamera; - AZStd::shared_ptr m_pivotCamera; - AZStd::shared_ptr m_pivotRotateCamera; - AZStd::shared_ptr m_pivotTranslateCamera; - AZStd::shared_ptr m_pivotDollyScrollCamera; - AZStd::shared_ptr m_pivotDollyMoveCamera; - AZStd::shared_ptr m_pivotPanCamera; - AZStd::shared_ptr m_pivotFocusCamera; + AZStd::shared_ptr m_orbitCamera; + AZStd::shared_ptr m_orbitRotateCamera; + AZStd::shared_ptr m_orbitTranslateCamera; + AZStd::shared_ptr m_orbitDollyScrollCamera; + AZStd::shared_ptr m_orbitDollyMoveCamera; + AZStd::shared_ptr m_orbitPanCamera; + AZStd::shared_ptr m_orbitFocusCamera; AzFramework::ViewportId m_viewportId; }; diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.cpp b/Code/Editor/EditorPreferencesPageViewportCamera.cpp index b632163186..16176bc241 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.cpp +++ b/Code/Editor/EditorPreferencesPageViewportCamera.cpp @@ -73,7 +73,7 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Field("TranslateSmoothing", &CameraMovementSettings::m_translateSmoothing) ->Field("TranslateSmoothness", &CameraMovementSettings::m_translateSmoothness) ->Field("CaptureCursorLook", &CameraMovementSettings::m_captureCursorLook) - ->Field("PivotYawRotationInverted", &CameraMovementSettings::m_pivotYawRotationInverted) + ->Field("OrbitYawRotationInverted", &CameraMovementSettings::m_orbitYawRotationInverted) ->Field("PanInvertedX", &CameraMovementSettings::m_panInvertedX) ->Field("PanInvertedY", &CameraMovementSettings::m_panInvertedY); @@ -86,12 +86,12 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Field("TranslateUp", &CameraInputSettings::m_translateUpChannelId) ->Field("TranslateDown", &CameraInputSettings::m_translateDownChannelId) ->Field("Boost", &CameraInputSettings::m_boostChannelId) - ->Field("Pivot", &CameraInputSettings::m_pivotChannelId) + ->Field("Orbit", &CameraInputSettings::m_orbitChannelId) ->Field("FreeLook", &CameraInputSettings::m_freeLookChannelId) ->Field("FreePan", &CameraInputSettings::m_freePanChannelId) - ->Field("PivotLook", &CameraInputSettings::m_pivotLookChannelId) - ->Field("PivotDolly", &CameraInputSettings::m_pivotDollyChannelId) - ->Field("PivotPan", &CameraInputSettings::m_pivotPanChannelId) + ->Field("OrbitLook", &CameraInputSettings::m_orbitLookChannelId) + ->Field("OrbitDolly", &CameraInputSettings::m_orbitDollyChannelId) + ->Field("OrbitPan", &CameraInputSettings::m_orbitPanChannelId) ->Field("Focus", &CameraInputSettings::m_focusChannelId); serialize.Class() @@ -144,8 +144,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial ->Attribute(AZ::Edit::Attributes::Min, minValue) ->Attribute(AZ::Edit::Attributes::Visibility, &CameraMovementSettings::TranslateSmoothingVisibility) ->DataElement( - AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_pivotYawRotationInverted, "Camera Pivot Yaw Inverted", - "Inverted yaw rotation while pivoting") + AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_orbitYawRotationInverted, "Camera Orbit Yaw Inverted", + "Inverted yaw rotation while orbiting") ->DataElement( AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_panInvertedX, "Invert Pan X", "Invert direction of pan in local X axis") @@ -186,8 +186,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial "Key/button to move the camera more quickly") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotChannelId, "Pivot", - "Key/button to begin the camera pivot behavior") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitChannelId, "Orbit", + "Key/button to begin the camera orbit behavior") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_freeLookChannelId, "Free Look", @@ -197,19 +197,19 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_freePanChannelId, "Free Pan", "Key/button to begin camera free pan") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotLookChannelId, "Pivot Look", - "Key/button to begin camera pivot look") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitLookChannelId, "Orbit Look", + "Key/button to begin camera orbit look") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotDollyChannelId, "Pivot Dolly", - "Key/button to begin camera pivot dolly") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitDollyChannelId, "Orbit Dolly", + "Key/button to begin camera orbit dolly") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotPanChannelId, "Pivot Pan", - "Key/button to begin camera pivot pan") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitPanChannelId, "Orbit Pan", + "Key/button to begin camera orbit pan") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames) ->DataElement( - AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_focusChannelId, "Focus", "Key/button to focus camera pivot") + AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_focusChannelId, "Focus", "Key/button to focus camera orbit") ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames); editContext->Class("Viewport Preferences", "Viewport Preferences") @@ -268,7 +268,7 @@ void CEditorPreferencesPage_ViewportCamera::OnApply() SandboxEditor::SetCameraTranslateSmoothness(m_cameraMovementSettings.m_translateSmoothness); SandboxEditor::SetCameraTranslateSmoothingEnabled(m_cameraMovementSettings.m_translateSmoothing); SandboxEditor::SetCameraCaptureCursorForLook(m_cameraMovementSettings.m_captureCursorLook); - SandboxEditor::SetCameraPivotYawRotationInverted(m_cameraMovementSettings.m_pivotYawRotationInverted); + SandboxEditor::SetCameraOrbitYawRotationInverted(m_cameraMovementSettings.m_orbitYawRotationInverted); SandboxEditor::SetCameraPanInvertedX(m_cameraMovementSettings.m_panInvertedX); SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_panInvertedY); @@ -279,12 +279,12 @@ void CEditorPreferencesPage_ViewportCamera::OnApply() SandboxEditor::SetCameraTranslateUpChannelId(m_cameraInputSettings.m_translateUpChannelId); SandboxEditor::SetCameraTranslateDownChannelId(m_cameraInputSettings.m_translateDownChannelId); SandboxEditor::SetCameraTranslateBoostChannelId(m_cameraInputSettings.m_boostChannelId); - SandboxEditor::SetCameraPivotChannelId(m_cameraInputSettings.m_pivotChannelId); + SandboxEditor::SetCameraOrbitChannelId(m_cameraInputSettings.m_orbitChannelId); SandboxEditor::SetCameraFreeLookChannelId(m_cameraInputSettings.m_freeLookChannelId); SandboxEditor::SetCameraFreePanChannelId(m_cameraInputSettings.m_freePanChannelId); - SandboxEditor::SetCameraPivotLookChannelId(m_cameraInputSettings.m_pivotLookChannelId); - SandboxEditor::SetCameraPivotDollyChannelId(m_cameraInputSettings.m_pivotDollyChannelId); - SandboxEditor::SetCameraPivotPanChannelId(m_cameraInputSettings.m_pivotPanChannelId); + SandboxEditor::SetCameraOrbitLookChannelId(m_cameraInputSettings.m_orbitLookChannelId); + SandboxEditor::SetCameraOrbitDollyChannelId(m_cameraInputSettings.m_orbitDollyChannelId); + SandboxEditor::SetCameraOrbitPanChannelId(m_cameraInputSettings.m_orbitPanChannelId); SandboxEditor::SetCameraFocusChannelId(m_cameraInputSettings.m_focusChannelId); SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Broadcast( @@ -304,7 +304,7 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings() m_cameraMovementSettings.m_translateSmoothness = SandboxEditor::CameraTranslateSmoothness(); m_cameraMovementSettings.m_translateSmoothing = SandboxEditor::CameraTranslateSmoothingEnabled(); m_cameraMovementSettings.m_captureCursorLook = SandboxEditor::CameraCaptureCursorForLook(); - m_cameraMovementSettings.m_pivotYawRotationInverted = SandboxEditor::CameraPivotYawRotationInverted(); + m_cameraMovementSettings.m_orbitYawRotationInverted = SandboxEditor::CameraOrbitYawRotationInverted(); m_cameraMovementSettings.m_panInvertedX = SandboxEditor::CameraPanInvertedX(); m_cameraMovementSettings.m_panInvertedY = SandboxEditor::CameraPanInvertedY(); @@ -315,11 +315,11 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings() m_cameraInputSettings.m_translateUpChannelId = SandboxEditor::CameraTranslateUpChannelId().GetName(); m_cameraInputSettings.m_translateDownChannelId = SandboxEditor::CameraTranslateDownChannelId().GetName(); m_cameraInputSettings.m_boostChannelId = SandboxEditor::CameraTranslateBoostChannelId().GetName(); - m_cameraInputSettings.m_pivotChannelId = SandboxEditor::CameraPivotChannelId().GetName(); + m_cameraInputSettings.m_orbitChannelId = SandboxEditor::CameraOrbitChannelId().GetName(); m_cameraInputSettings.m_freeLookChannelId = SandboxEditor::CameraFreeLookChannelId().GetName(); m_cameraInputSettings.m_freePanChannelId = SandboxEditor::CameraFreePanChannelId().GetName(); - m_cameraInputSettings.m_pivotLookChannelId = SandboxEditor::CameraPivotLookChannelId().GetName(); - m_cameraInputSettings.m_pivotDollyChannelId = SandboxEditor::CameraPivotDollyChannelId().GetName(); - m_cameraInputSettings.m_pivotPanChannelId = SandboxEditor::CameraPivotPanChannelId().GetName(); + m_cameraInputSettings.m_orbitLookChannelId = SandboxEditor::CameraOrbitLookChannelId().GetName(); + m_cameraInputSettings.m_orbitDollyChannelId = SandboxEditor::CameraOrbitDollyChannelId().GetName(); + m_cameraInputSettings.m_orbitPanChannelId = SandboxEditor::CameraOrbitPanChannelId().GetName(); m_cameraInputSettings.m_focusChannelId = SandboxEditor::CameraFocusChannelId().GetName(); } diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.h b/Code/Editor/EditorPreferencesPageViewportCamera.h index cd31141c4a..fdc86b0f89 100644 --- a/Code/Editor/EditorPreferencesPageViewportCamera.h +++ b/Code/Editor/EditorPreferencesPageViewportCamera.h @@ -54,7 +54,7 @@ private: float m_translateSmoothness; bool m_translateSmoothing; bool m_captureCursorLook; - bool m_pivotYawRotationInverted; + bool m_orbitYawRotationInverted; bool m_panInvertedX; bool m_panInvertedY; @@ -80,12 +80,12 @@ private: AZStd::string m_translateUpChannelId; AZStd::string m_translateDownChannelId; AZStd::string m_boostChannelId; - AZStd::string m_pivotChannelId; + AZStd::string m_orbitChannelId; AZStd::string m_freeLookChannelId; AZStd::string m_freePanChannelId; - AZStd::string m_pivotLookChannelId; - AZStd::string m_pivotDollyChannelId; - AZStd::string m_pivotPanChannelId; + AZStd::string m_orbitLookChannelId; + AZStd::string m_orbitDollyChannelId; + AZStd::string m_orbitPanChannelId; AZStd::string m_focusChannelId; }; diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index c2539b008c..2354c6d63a 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -28,7 +28,7 @@ namespace SandboxEditor constexpr AZStd::string_view CameraRotateSpeedSetting = "/Amazon/Preferences/Editor/Camera/RotateSpeed"; constexpr AZStd::string_view CameraScrollSpeedSetting = "/Amazon/Preferences/Editor/Camera/DollyScrollSpeed"; constexpr AZStd::string_view CameraDollyMotionSpeedSetting = "/Amazon/Preferences/Editor/Camera/DollyMotionSpeed"; - constexpr AZStd::string_view CameraPivotYawRotationInvertedSetting = "/Amazon/Preferences/Editor/Camera/YawRotationInverted"; + constexpr AZStd::string_view CameraOrbitYawRotationInvertedSetting = "/Amazon/Preferences/Editor/Camera/YawRotationInverted"; constexpr AZStd::string_view CameraPanInvertedXSetting = "/Amazon/Preferences/Editor/Camera/PanInvertedX"; constexpr AZStd::string_view CameraPanInvertedYSetting = "/Amazon/Preferences/Editor/Camera/PanInvertedY"; constexpr AZStd::string_view CameraPanSpeedSetting = "/Amazon/Preferences/Editor/Camera/PanSpeed"; @@ -44,12 +44,12 @@ namespace SandboxEditor constexpr AZStd::string_view CameraTranslateUpIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpId"; constexpr AZStd::string_view CameraTranslateDownIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpDownId"; constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId"; - constexpr AZStd::string_view CameraPivotIdSetting = "/Amazon/Preferences/Editor/Camera/PivotId"; + constexpr AZStd::string_view CameraOrbitIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitId"; constexpr AZStd::string_view CameraFreeLookIdSetting = "/Amazon/Preferences/Editor/Camera/FreeLookId"; constexpr AZStd::string_view CameraFreePanIdSetting = "/Amazon/Preferences/Editor/Camera/FreePanId"; - constexpr AZStd::string_view CameraPivotLookIdSetting = "/Amazon/Preferences/Editor/Camera/PivotLookId"; - constexpr AZStd::string_view CameraPivotDollyIdSetting = "/Amazon/Preferences/Editor/Camera/PivotDollyId"; - constexpr AZStd::string_view CameraPivotPanIdSetting = "/Amazon/Preferences/Editor/Camera/PivotPanId"; + constexpr AZStd::string_view CameraOrbitLookIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitLookId"; + constexpr AZStd::string_view CameraOrbitDollyIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitDollyId"; + constexpr AZStd::string_view CameraOrbitPanIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitPanId"; constexpr AZStd::string_view CameraFocusIdSetting = "/Amazon/Preferences/Editor/Camera/FocusId"; template @@ -240,14 +240,14 @@ namespace SandboxEditor SetRegistry(CameraDollyMotionSpeedSetting, speed); } - bool CameraPivotYawRotationInverted() + bool CameraOrbitYawRotationInverted() { - return GetRegistry(CameraPivotYawRotationInvertedSetting, false); + return GetRegistry(CameraOrbitYawRotationInvertedSetting, false); } - void SetCameraPivotYawRotationInverted(const bool inverted) + void SetCameraOrbitYawRotationInverted(const bool inverted) { - SetRegistry(CameraPivotYawRotationInvertedSetting, inverted); + SetRegistry(CameraOrbitYawRotationInvertedSetting, inverted); } bool CameraPanInvertedX() @@ -404,14 +404,14 @@ namespace SandboxEditor SetRegistry(CameraTranslateBoostIdSetting, cameraTranslateBoostId); } - AzFramework::InputChannelId CameraPivotChannelId() + AzFramework::InputChannelId CameraOrbitChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraPivotIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str()); } - void SetCameraPivotChannelId(AZStd::string_view cameraPivotId) + void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId) { - SetRegistry(CameraPivotIdSetting, cameraPivotId); + SetRegistry(CameraOrbitIdSetting, cameraOrbitId); } AzFramework::InputChannelId CameraFreeLookChannelId() @@ -434,34 +434,34 @@ namespace SandboxEditor SetRegistry(CameraFreePanIdSetting, cameraFreePanId); } - AzFramework::InputChannelId CameraPivotLookChannelId() + AzFramework::InputChannelId CameraOrbitLookChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraPivotLookIdSetting, AZStd::string("mouse_button_left")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str()); } - void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId) + void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId) { - SetRegistry(CameraPivotLookIdSetting, cameraPivotLookId); + SetRegistry(CameraOrbitLookIdSetting, cameraOrbitLookId); } - AzFramework::InputChannelId CameraPivotDollyChannelId() + AzFramework::InputChannelId CameraOrbitDollyChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraPivotDollyIdSetting, AZStd::string("mouse_button_right")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraOrbitDollyIdSetting, AZStd::string("mouse_button_right")).c_str()); } - void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId) + void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId) { - SetRegistry(CameraPivotDollyIdSetting, cameraPivotDollyId); + SetRegistry(CameraOrbitDollyIdSetting, cameraOrbitDollyId); } - AzFramework::InputChannelId CameraPivotPanChannelId() + AzFramework::InputChannelId CameraOrbitPanChannelId() { - return AzFramework::InputChannelId(GetRegistry(CameraPivotPanIdSetting, AZStd::string("mouse_button_middle")).c_str()); + return AzFramework::InputChannelId(GetRegistry(CameraOrbitPanIdSetting, AZStd::string("mouse_button_middle")).c_str()); } - void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId) + void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId) { - SetRegistry(CameraPivotPanIdSetting, cameraPivotPanId); + SetRegistry(CameraOrbitPanIdSetting, cameraOrbitPanId); } AzFramework::InputChannelId CameraFocusChannelId() diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index 0253b01621..c1394f7404 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -71,8 +71,8 @@ namespace SandboxEditor SANDBOX_API float CameraDollyMotionSpeed(); SANDBOX_API void SetCameraDollyMotionSpeed(float speed); - SANDBOX_API bool CameraPivotYawRotationInverted(); - SANDBOX_API void SetCameraPivotYawRotationInverted(bool inverted); + SANDBOX_API bool CameraOrbitYawRotationInverted(); + SANDBOX_API void SetCameraOrbitYawRotationInverted(bool inverted); SANDBOX_API bool CameraPanInvertedX(); SANDBOX_API void SetCameraPanInvertedX(bool inverted); @@ -119,8 +119,8 @@ namespace SandboxEditor SANDBOX_API AzFramework::InputChannelId CameraTranslateBoostChannelId(); SANDBOX_API void SetCameraTranslateBoostChannelId(AZStd::string_view cameraTranslateBoostId); - SANDBOX_API AzFramework::InputChannelId CameraPivotChannelId(); - SANDBOX_API void SetCameraPivotChannelId(AZStd::string_view cameraPivotId); + SANDBOX_API AzFramework::InputChannelId CameraOrbitChannelId(); + SANDBOX_API void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId); SANDBOX_API AzFramework::InputChannelId CameraFreeLookChannelId(); SANDBOX_API void SetCameraFreeLookChannelId(AZStd::string_view cameraFreeLookId); @@ -128,14 +128,14 @@ namespace SandboxEditor SANDBOX_API AzFramework::InputChannelId CameraFreePanChannelId(); SANDBOX_API void SetCameraFreePanChannelId(AZStd::string_view cameraFreePanId); - SANDBOX_API AzFramework::InputChannelId CameraPivotLookChannelId(); - SANDBOX_API void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId); + SANDBOX_API AzFramework::InputChannelId CameraOrbitLookChannelId(); + SANDBOX_API void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId); - SANDBOX_API AzFramework::InputChannelId CameraPivotDollyChannelId(); - SANDBOX_API void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId); + SANDBOX_API AzFramework::InputChannelId CameraOrbitDollyChannelId(); + SANDBOX_API void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId); - SANDBOX_API AzFramework::InputChannelId CameraPivotPanChannelId(); - SANDBOX_API void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId); + SANDBOX_API AzFramework::InputChannelId CameraOrbitPanChannelId(); + SANDBOX_API void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId); SANDBOX_API AzFramework::InputChannelId CameraFocusChannelId(); SANDBOX_API void SetCameraFocusChannelId(AZStd::string_view cameraFocusId); diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index 13f5303eaf..ddee63e191 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -533,8 +533,8 @@ namespace AzFramework m_translateCameraInputChannelIds = translateCameraInputChannelIds; } - PivotCameraInput::PivotCameraInput(const InputChannelId& pivotChannelId) - : m_pivotChannelId(pivotChannelId) + OrbitCameraInput::OrbitCameraInput(const InputChannelId& orbitChannelId) + : m_orbitChannelId(orbitChannelId) { m_pivotFn = []([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { @@ -542,11 +542,11 @@ namespace AzFramework }; } - bool PivotCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta) + bool OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta) { if (const auto* input = AZStd::get_if(&event)) { - if (input->m_channelId == m_pivotChannelId) + if (input->m_channelId == m_orbitChannelId) { if (input->m_state == InputChannel::State::Began) { @@ -561,13 +561,13 @@ namespace AzFramework if (Active()) { - return m_pivotCameras.HandleEvents(event, cursorDelta, scrollDelta); + return m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta); } return !Idle(); } - Camera PivotCameraInput::StepCamera( + Camera OrbitCameraInput::StepCamera( const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime) { Camera nextCamera = targetCamera; @@ -581,12 +581,12 @@ namespace AzFramework if (Active()) { MovePivotDetached(nextCamera, m_pivotFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY())); - nextCamera = m_pivotCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime); + nextCamera = m_orbitCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime); } if (Ending()) { - m_pivotCameras.Reset(); + m_orbitCameras.Reset(); nextCamera.m_pivot = nextCamera.Translation(); nextCamera.m_offset = AZ::Vector3::CreateZero(); @@ -595,12 +595,12 @@ namespace AzFramework return nextCamera; } - void PivotCameraInput::SetPivotInputChannelId(const InputChannelId& pivotChanneId) + void OrbitCameraInput::SetOrbitInputChannelId(const InputChannelId& orbitChanneId) { - m_pivotChannelId = pivotChanneId; + m_orbitChannelId = orbitChanneId; } - PivotDollyScrollCameraInput::PivotDollyScrollCameraInput() + OrbitDollyScrollCameraInput::OrbitDollyScrollCameraInput() { m_scrollSpeedFn = []() constexpr { @@ -608,7 +608,7 @@ namespace AzFramework }; } - bool PivotDollyScrollCameraInput::HandleEvents( + bool OrbitDollyScrollCameraInput::HandleEvents( const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta) { if (const auto* scroll = AZStd::get_if(&event)) @@ -619,7 +619,7 @@ namespace AzFramework return !Idle(); } - static Camera PivotDolly(const Camera& targetCamera, const float delta) + static Camera OrbitDolly(const Camera& targetCamera, const float delta) { Camera nextCamera = targetCamera; @@ -646,18 +646,18 @@ namespace AzFramework return nextCamera; } - Camera PivotDollyScrollCameraInput::StepCamera( + Camera OrbitDollyScrollCameraInput::StepCamera( const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta, [[maybe_unused]] const float deltaTime) { - const auto nextCamera = PivotDolly(targetCamera, aznumeric_cast(scrollDelta) * m_scrollSpeedFn()); + const auto nextCamera = OrbitDolly(targetCamera, aznumeric_cast(scrollDelta) * m_scrollSpeedFn()); EndActivation(); return nextCamera; } - PivotDollyMotionCameraInput::PivotDollyMotionCameraInput(const InputChannelId& dollyChannelId) + OrbitDollyMotionCameraInput::OrbitDollyMotionCameraInput(const InputChannelId& dollyChannelId) : m_dollyChannelId(dollyChannelId) { m_motionSpeedFn = []() constexpr @@ -666,28 +666,28 @@ namespace AzFramework }; } - bool PivotDollyMotionCameraInput::HandleEvents( + bool OrbitDollyMotionCameraInput::HandleEvents( const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta) { HandleActivationEvents(event, m_dollyChannelId, cursorDelta, m_clickDetector, *this); return CameraInputUpdatingAfterMotion(*this); } - Camera PivotDollyMotionCameraInput::StepCamera( + Camera OrbitDollyMotionCameraInput::StepCamera( const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta, [[maybe_unused]] const float deltaTime) { - return PivotDolly(targetCamera, aznumeric_cast(cursorDelta.m_y) * m_motionSpeedFn()); + return OrbitDolly(targetCamera, aznumeric_cast(cursorDelta.m_y) * m_motionSpeedFn()); } - void PivotDollyMotionCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId) + void OrbitDollyMotionCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId) { m_dollyChannelId = dollyChannelId; } - ScrollTranslationCameraInput::ScrollTranslationCameraInput() + LookScrollTranslationCameraInput::LookScrollTranslationCameraInput() { m_scrollSpeedFn = []() constexpr { @@ -695,7 +695,7 @@ namespace AzFramework }; } - bool ScrollTranslationCameraInput::HandleEvents( + bool LookScrollTranslationCameraInput::HandleEvents( const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta) { if (const auto* scroll = AZStd::get_if(&event)) @@ -706,7 +706,7 @@ namespace AzFramework return !Idle(); } - Camera ScrollTranslationCameraInput::StepCamera( + Camera LookScrollTranslationCameraInput::StepCamera( const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta, diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index 9b1988f5ec..2b7cc3ea9e 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -30,8 +30,11 @@ namespace AzFramework AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation); //! A simple camera representation using spherical coordinates as input (pitch, yaw, pivot and offset). - //! The cameras transform and view can be obtained through accessor functions that use the internal + //! The camera's transform and view can be obtained through accessor functions that use the internal //! spherical coordinates to calculate the position and orientation. + //! @note Modifying m_pivot directly and leaving m_offset as zero will produce a free look camera effect, giving + //! m_offset a value (e.g. in negative Y only) will produce an orbit camera effect, modifying X and Z of m_offset + //! will further alter the camera translation in relation to m_pivot so it appears off center. struct Camera { AZ::Vector3 m_pivot = AZ::Vector3::CreateZero(); //!< Pivot point to rotate about (modified in world space). @@ -291,7 +294,7 @@ namespace AzFramework Cameras m_cameras; //!< Represents a collection of camera inputs that together provide a camera controller. private: - ScreenVector m_motionDelta; //!< The delta used for look/pivot/pan (rotation + translation) - two dimensional. + ScreenVector m_motionDelta; //!< The delta used for look/orbit/pan (rotation + translation) - two dimensional. CursorState m_cursorState; //!< The current and previous position of the cursor (used to calculate movement delta). float m_scrollDelta = 0.0f; //!< The delta used for dolly/movement (translation) - one dimensional. bool m_handlingEvents = false; //!< Is the camera system currently handling events (events are consumed and not propagated). @@ -316,7 +319,7 @@ namespace AzFramework return AZStd::fmod(yaw + AZ::Constants::TwoPi, AZ::Constants::TwoPi); } - //! A camera input to handle motion deltas that can rotate or pivot the camera. + //! A camera input to handle motion deltas that can change the orientation of the camera (update pitch and yaw). class RotateCameraInput : public CameraInput { public: @@ -348,15 +351,16 @@ namespace AzFramework //! PanAxes build function that will return a pair of pan axes depending on the camera orientation. using PanAxesFn = AZStd::function; - //! PanAxes to use while in 'look' camera behavior (free look). + //! PanAxes to use while in 'look' or 'orbit' camera behavior. inline PanAxes LookPan(const Camera& camera) { const AZ::Matrix3x3 orientation = camera.Rotation(); return { orientation.GetBasisX(), orientation.GetBasisZ() }; } - //! PanAxes to use while in 'pivot' camera behavior. - inline PanAxes PivotPan(const Camera& camera) + //! Optional PanAxes to use while in 'orbit' camera behavior. + //! @note This will move the camera in the local X/Y plane instead of usual X/Z plane. + inline PanAxes OrbitPan(const Camera& camera) { const AZ::Matrix3x3 orientation = camera.Rotation(); @@ -370,14 +374,23 @@ namespace AzFramework return { basisX, basisY }; } + //! TranslationDeltaFn is used by PanCameraInput and TranslateCameraInput + //! @note Choose the appropriate function if the behavior should be operating as a free look camera (TranslatePivotLook) + //! or an orbit camera (TranslateOffsetOrbit). using TranslationDeltaFn = AZStd::function; - inline void TranslatePivot(Camera& camera, const AZ::Vector3& delta) + //! Update the pivot camera position. + //! @note delta will need to have been transformed to world space, e.g. To move the camera right, (1, 0, 0) must + //! first be transformed by the orientation of the camera before being applied to m_pivot. + inline void TranslatePivotLook(Camera& camera, const AZ::Vector3& delta) { camera.m_pivot += delta; } - inline void TranslateOffset(Camera& camera, const AZ::Vector3& delta) + //! Update the offset camera position. + //! @note delta still needs to be transformed to world space (as with TranslatePivotLook) but internally this is undone + //! to be performed in local space when being applied to m_offset. + inline void TranslateOffsetOrbit(Camera& camera, const AZ::Vector3& delta) { camera.m_offset += camera.View().TransformVector(delta); } @@ -409,7 +422,7 @@ namespace AzFramework //! Axes to use while translating the camera. using TranslationAxesFn = AZStd::function; - //! TranslationAxes to use while in 'look' camera behavior (free look). + //! TranslationAxes to use while in 'look' or 'orbit' camera behavior. inline AZ::Matrix3x3 LookTranslation(const Camera& camera) { const AZ::Matrix3x3 orientation = camera.Rotation(); @@ -421,8 +434,8 @@ namespace AzFramework return AZ::Matrix3x3::CreateFromColumns(basisX, basisY, basisZ); } - //! TranslationAxes to use while in 'pivot' camera behavior. - inline AZ::Matrix3x3 PivotTranslation(const Camera& camera) + //! Optional TranslationAxes to use while in 'orbit' camera behavior. + inline AZ::Matrix3x3 OrbitTranslation(const Camera& camera) { const AZ::Matrix3x3 orientation = camera.Rotation(); @@ -535,11 +548,11 @@ namespace AzFramework bool m_boost = false; //!< Is the translation speed currently being multiplied/scaled upwards. }; - //! A camera input to handle discrete scroll events that can modify the camera pivot distance. - class PivotDollyScrollCameraInput : public CameraInput + //! A camera input to handle discrete scroll events that can modify the camera offset. + class OrbitDollyScrollCameraInput : public CameraInput { public: - PivotDollyScrollCameraInput(); + OrbitDollyScrollCameraInput(); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -548,11 +561,11 @@ namespace AzFramework AZStd::function m_scrollSpeedFn; }; - //! A camera input to handle motion deltas that can modify the camera pivot distance. - class PivotDollyMotionCameraInput : public CameraInput + //! A camera input to handle motion deltas that can modify the camera offset. + class OrbitDollyMotionCameraInput : public CameraInput { public: - explicit PivotDollyMotionCameraInput(const InputChannelId& dollyChannelId); + explicit OrbitDollyMotionCameraInput(const InputChannelId& dollyChannelId); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -569,10 +582,10 @@ namespace AzFramework }; //! A camera input to handle discrete scroll events that can scroll (translate) the camera along its forward axis. - class ScrollTranslationCameraInput : public CameraInput + class LookScrollTranslationCameraInput : public CameraInput { public: - ScrollTranslationCameraInput(); + LookScrollTranslationCameraInput(); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; @@ -583,36 +596,36 @@ namespace AzFramework //! A camera input that doubles as its own set of camera inputs. //! It is 'exclusive', so does not overlap with other sibling camera inputs - it runs its own set of camera inputs as 'children'. - class PivotCameraInput : public CameraInput + class OrbitCameraInput : public CameraInput { public: using PivotFn = AZStd::function; - explicit PivotCameraInput(const InputChannelId& pivotChannelId); + explicit OrbitCameraInput(const InputChannelId& orbitChannelId); // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; bool Exclusive() const override; - void SetPivotInputChannelId(const InputChannelId& pivotChanneId); + void SetOrbitInputChannelId(const InputChannelId& orbitChanneId); - Cameras m_pivotCameras; //!< The camera inputs to run when this camera input is active (only these will run as it is exclusive). + Cameras m_orbitCameras; //!< The camera inputs to run when this camera input is active (only these will run as it is exclusive). //! Override the default behavior for how a pivot point is calculated. void SetPivotFn(PivotFn pivotFn); private: - InputChannelId m_pivotChannelId; //!< Input channel to begin the pivot camera input. - PivotFn m_pivotFn; //!< The pivot position to use for this pivot camera (how is the pivot point calculated/retrieved). + InputChannelId m_orbitChannelId; //!< Input channel to begin the orbit camera input. + PivotFn m_pivotFn; //!< The pivot position to use for this orbit camera (how is the pivot point calculated/retrieved). }; - inline void PivotCameraInput::SetPivotFn(PivotFn pivotFn) + inline void OrbitCameraInput::SetPivotFn(PivotFn pivotFn) { m_pivotFn = AZStd::move(pivotFn); } - inline bool PivotCameraInput::Exclusive() const + inline bool OrbitCameraInput::Exclusive() const { return true; } @@ -624,9 +637,9 @@ namespace AzFramework return AZ::Vector3::CreateZero(); } - //! Callback to use for FocusCameraInput when a pivot camera is being used. + //! Callback to use for FocusCameraInput when a orbit camera is being used. //! @note This is when offset is non zero. - inline AZ::Vector3 FocusPivot(const float length) + inline AZ::Vector3 FocusOrbit(const float length) { return AZ::Vector3::CreateAxisY(-length); } @@ -667,7 +680,9 @@ namespace AzFramework bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override; + //! HandleEvents delegates directly to m_handleEventsFn. AZStd::function m_handleEventsFn; + //! StepCamera delegates directly to m_stepCameraFn. AZStd::function m_stepCameraFn; }; diff --git a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp index 1e0c805587..a89fb0bd84 100644 --- a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp +++ b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp @@ -53,31 +53,31 @@ namespace UnitTest }; m_firstPersonTranslateCamera = AZStd::make_shared( - m_translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot); + m_translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook); - m_pivotCamera = AZStd::make_shared(m_pivotChannelId); - m_pivotCamera->SetPivotFn( + m_orbitCamera = AZStd::make_shared(m_orbitChannelId); + m_orbitCamera->SetPivotFn( [this](const AZ::Vector3&, const AZ::Vector3&) { return m_pivot; }); - auto pivotRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Left); + auto orbitRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Left); // set rotate speed to be a value that will scale motion delta (pixels moved) by a thousandth. - pivotRotateCamera->m_rotateSpeedFn = []() + orbitRotateCamera->m_rotateSpeedFn = []() { return 0.001f; }; - auto pivotTranslateCamera = AZStd::make_shared( - m_translateCameraInputChannelIds, AzFramework::PivotTranslation, AzFramework::TranslateOffset); + auto orbitTranslateCamera = AZStd::make_shared( + m_translateCameraInputChannelIds, AzFramework::OrbitTranslation, AzFramework::TranslateOffsetOrbit); - m_pivotCamera->m_pivotCameras.AddCamera(pivotRotateCamera); - m_pivotCamera->m_pivotCameras.AddCamera(pivotTranslateCamera); + m_orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera); + m_orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera); m_cameraSystem->m_cameras.AddCamera(m_firstPersonRotateCamera); m_cameraSystem->m_cameras.AddCamera(m_firstPersonTranslateCamera); - m_cameraSystem->m_cameras.AddCamera(m_pivotCamera); + m_cameraSystem->m_cameras.AddCamera(m_orbitCamera); // these tests rely on using motion delta, not cursor positions (default is true) AzFramework::ed_cameraSystemUseCursor = false; @@ -87,7 +87,7 @@ namespace UnitTest { AzFramework::ed_cameraSystemUseCursor = true; - m_pivotCamera.reset(); + m_orbitCamera.reset(); m_firstPersonRotateCamera.reset(); m_firstPersonTranslateCamera.reset(); @@ -97,11 +97,11 @@ namespace UnitTest AllocatorsTestFixture::TearDown(); } - AzFramework::InputChannelId m_pivotChannelId = AzFramework::InputChannelId("keyboard_key_modifier_alt_l"); + AzFramework::InputChannelId m_orbitChannelId = AzFramework::InputChannelId("keyboard_key_modifier_alt_l"); AzFramework::TranslateCameraInputChannelIds m_translateCameraInputChannelIds; AZStd::shared_ptr m_firstPersonRotateCamera; AZStd::shared_ptr m_firstPersonTranslateCamera; - AZStd::shared_ptr m_pivotCamera; + AZStd::shared_ptr m_orbitCamera; AZ::Vector3 m_pivot = AZ::Vector3::CreateZero(); //! This is approximately Pi/2 * 1000 - this can be used to rotate the camera 90 degrees (pitch or yaw based @@ -109,17 +109,17 @@ namespace UnitTest inline static const int PixelMotionDelta = 1570; }; - TEST_F(CameraInputFixture, BeginAndEndPivotCameraInputConsumesCorrectEvents) + TEST_F(CameraInputFixture, BeginAndEndOrbitCameraInputConsumesCorrectEvents) { - // begin pivot camera + // begin orbit camera const bool consumed1 = HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceKeyboard::Key::ModifierAltL, AzFramework::InputChannel::State::Began }); - // begin listening for pivot rotate (click detector) - event is not consumed + // begin listening for orbit rotate (click detector) - event is not consumed const bool consumed2 = HandleEventAndUpdate( AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began }); - // begin pivot rotate (mouse has moved sufficient distance to initiate) + // begin orbit rotate (mouse has moved sufficient distance to initiate) const bool consumed3 = HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{ 5 }); - // end pivot (mouse up) - event is not consumed + // end orbit (mouse up) - event is not consumed const bool consumed4 = HandleEventAndUpdate( AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Ended }); @@ -260,10 +260,10 @@ namespace UnitTest EXPECT_TRUE(activationEnded); } - TEST_F(CameraInputFixture, PivotCameraInputHandlesLookAtPointAndSelfAtSamePositionWhenPivoting) + TEST_F(CameraInputFixture, OrbitCameraInputHandlesLookAtPointAndSelfAtSamePositionWhenOrbiting) { // create pathological lookAtFn that just returns the same position as the camera - m_pivotCamera->SetPivotFn( + m_orbitCamera->SetPivotFn( [](const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) { return position; @@ -275,7 +275,7 @@ namespace UnitTest AZ::Transform::CreateFromQuaternionAndTranslation( AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), expectedCameraPosition)); - HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); // verify the camera yaw has not changed and pivot point matches the expected camera position using ::testing::FloatNear; @@ -321,14 +321,14 @@ namespace UnitTest EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3::CreateZero())); } - TEST_F(CameraInputFixture, PivotRotateCameraInputRotatesPitchOffsetByNinetyDegreesWithRequiredPixelDelta) + TEST_F(CameraInputFixture, OrbitRotateCameraInputRotatesPitchOffsetByNinetyDegreesWithRequiredPixelDelta) { const auto cameraStartingPosition = AZ::Vector3::CreateAxisY(-20.0f); m_targetCamera.m_pivot = cameraStartingPosition; m_pivot = AZ::Vector3::CreateAxisY(-10.0f); - HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); HandleEventAndUpdate( AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began }); HandleEventAndUpdate(AzFramework::VerticalMotionEvent{ PixelMotionDelta }); @@ -344,14 +344,14 @@ namespace UnitTest EXPECT_THAT(m_camera.Translation(), IsCloseTolerance(expectedCameraEndingPosition, 0.01f)); } - TEST_F(CameraInputFixture, PivotRotateCameraInputRotatesYawOffsetByNinetyDegreesWithRequiredPixelDelta) + TEST_F(CameraInputFixture, OrbitRotateCameraInputRotatesYawOffsetByNinetyDegreesWithRequiredPixelDelta) { const auto cameraStartingPosition = AZ::Vector3(15.0f, -20.0f, 0.0f); m_targetCamera.m_pivot = cameraStartingPosition; m_pivot = AZ::Vector3(10.0f, -10.0f, 0.0f); - HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); HandleEventAndUpdate( AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began }); HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{ -PixelMotionDelta }); From 77c23b6c8f59aa1a0ee9026c670be36981f664c7 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Thu, 7 Oct 2021 08:27:48 -0400 Subject: [PATCH 088/293] Hierarchy imgui debugger, first take Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugHierarchyReporter.cpp | 200 ++++++++++++++++++ .../Debug/MultiplayerDebugHierarchyReporter.h | 52 +++++ .../Debug/MultiplayerDebugSystemComponent.cpp | 24 +++ .../Debug/MultiplayerDebugSystemComponent.h | 5 + .../Code/multiplayer_debug_files.cmake | 2 + 5 files changed, 283 insertions(+) create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp new file mode 100644 index 0000000000..32e9a776a4 --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp @@ -0,0 +1,200 @@ +/* + * 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 "MultiplayerDebugHierarchyReporter.h" + +#include +#include +#include +#include + +#if defined(IMGUI_ENABLED) +#include +#endif + +#pragma optimize("", off) + +namespace Multiplayer +{ + MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() + : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug")) + { + CollectHierarchyRoots(); + + AZ::EntitySystemBus::Handler::BusConnect(); + m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); + } + + MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter() + { + AZ::EntitySystemBus::Handler::BusDisconnect(); + } + + // -------------------------------------------------------------------------------------------- + void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() + { +#if defined(IMGUI_ENABLED) + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), + "Hierarchy, Root entity name [%s]: %4zu members", + rootComponent->GetEntity()->GetName().c_str(), + hierarchicalChildren.size())) + { + ImGui::Separator(); + ImGui::Columns(4, "hierarchy_columns"); + ImGui::Text("EntityId"); + ImGui::NextColumn(); + ImGui::Text("NetEntityId"); + ImGui::NextColumn(); + ImGui::Text("Entity Name"); + ImGui::NextColumn(); + ImGui::Text("Role"); + ImGui::NextColumn(); + + ImGui::Separator(); + ImGui::Columns(4, "hierarchy child info"); + + bool firstEntity = true; + for (const AZ::Entity* entity : hierarchicalChildren) + { + ImGui::Text("%s", entity->GetId().ToString().c_str()); + ImGui::NextColumn(); + ImGui::Text("%u", GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId())); + ImGui::NextColumn(); + ImGui::Text("%s", entity->GetName().c_str()); + ImGui::NextColumn(); + + if (firstEntity) + { + ImGui::Text("Root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Inner root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Child node"); + } + ImGui::NextColumn(); + + firstEntity = false; + } + + ImGui::Columns(1); + ImGui::TreePop(); + } + } + } + } +#endif + } + + + void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay() + { + if (!m_hierarchyRoots.empty()) + { + if (m_debugDisplay == nullptr) + { + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId); + m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + } + + const AZ::u32 stateBefore = m_debugDisplay->GetState(); + m_debugDisplay->SetColor(AZ::Colors::White); + + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + azsprintf(m_statusBuffer, "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(), + aznumeric_cast(hierarchicalChildren.size())); + + AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation(); + constexpr bool centerText = true; + m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + } + } + } + + m_debugDisplay->SetState(stateBefore); + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + m_hierarchyRoots.erase(rootComponent); + } + } + } + + void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() + { + AZStd::vector gatheredEntries; + const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) + { + gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); + for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) + { + if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) + { + gatheredEntries.push_back(visEntry); + } + } + } + ); + + for (const AzFramework::VisibilityEntry* entry : gatheredEntries) + { + const AZ::Entity* entity = static_cast(entry->m_userData); + if (auto* rootComponent = entity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h new file mode 100644 index 0000000000..98a131614c --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace Multiplayer +{ + class MultiplayerDebugHierarchyReporter + : public AZ::EntitySystemBus::Handler + { + public: + MultiplayerDebugHierarchyReporter(); + ~MultiplayerDebugHierarchyReporter() override; + + //! main update loop + void OnImGuiUpdate(); + + //! Draws bandwidth text over entities + void UpdateDebugOverlay(); + + //! EntitySystemBus overrides. + void OnEntityActivated(const AZ::EntityId& entityId) override; + void OnEntityDeactivated(const AZ::EntityId& entityId) override; + + private: + AZ::ScheduledEvent m_updateDebugOverlay; + + AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; + + struct HierarchyRootInfo + { + NetworkHierarchyRootComponent* m_rootComponent = nullptr; + NetworkHierarchyChangedEvent::Handler m_changedEvent; + NetworkHierarchyLeaveEvent::Handler m_leaveEvent; + }; + + AZStd::unordered_map m_hierarchyRoots; + void CollectHierarchyRoots(); + + char m_statusBuffer[100] = {}; + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 422b2f0cae..b23bc677f0 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -71,6 +71,7 @@ namespace Multiplayer ImGui::Checkbox("Networking Stats", &m_displayNetworkingStats); ImGui::Checkbox("Multiplayer Stats", &m_displayMultiplayerStats); ImGui::Checkbox("Multiplayer Entity Stats", &m_displayPerEntityStats); + ImGui::Checkbox("Multiplayer Hierarchy Debugger", &m_displayHierarchyDebugger); ImGui::EndMenu(); } } @@ -464,6 +465,29 @@ namespace Multiplayer } } } + + if (m_displayHierarchyDebugger) + { + if (ImGui::Begin("Multiplayer Hierarchy Debugger", &m_displayHierarchyDebugger)) + { + if (m_hierarchyDebugger == nullptr) + { + m_hierarchyDebugger = AZStd::make_unique(); + } + + if (m_hierarchyDebugger) + { + m_hierarchyDebugger->OnImGuiUpdate(); + } + } + } + else + { + if (m_hierarchyDebugger) + { + m_hierarchyDebugger.reset(); + } + } } #endif } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h index 7b3c852f58..9becf1543c 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.h @@ -8,6 +8,8 @@ #pragma once +#include "MultiplayerDebugHierarchyReporter.h" + #include #include #include @@ -62,5 +64,8 @@ namespace Multiplayer bool m_displayPerEntityStats = false; AZStd::unique_ptr m_reporter; + + bool m_displayHierarchyDebugger = false; + AZStd::unique_ptr m_hierarchyDebugger; }; } diff --git a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake index 37a1c91640..1d85dd8149 100644 --- a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake @@ -9,6 +9,8 @@ set(FILES Source/Debug/MultiplayerDebugByteReporter.cpp Source/Debug/MultiplayerDebugByteReporter.h + Source/Debug/MultiplayerDebugHierarchyReporter.cpp + Source/Debug/MultiplayerDebugHierarchyReporter.h Source/Debug/MultiplayerDebugPerEntityReporter.cpp Source/Debug/MultiplayerDebugPerEntityReporter.h Source/Debug/MultiplayerDebugModule.cpp From d1947c68c96e3b042851a20ad027266f44edc809 Mon Sep 17 00:00:00 2001 From: AMZN-AlexOteiza <82234181+AMZN-AlexOteiza@users.noreply.github.com> Date: Thu, 7 Oct 2021 13:29:09 +0100 Subject: [PATCH 089/293] Added extra output and callstack information for improving debugging automated tests (#4528) Signed-off-by: AMZN-AlexOteiza --- Code/Editor/CryEdit.cpp | 2 ++ Code/Framework/AzCore/AzCore/Debug/Trace.cpp | 2 ++ Code/Legacy/CrySystem/DebugCallStack.cpp | 3 +++ 3 files changed, 7 insertions(+) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 4aa3d22114..abba2bb9c6 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -2124,6 +2124,8 @@ bool CCryEditApp::FixDanglingSharedMemory(const QString& sharedMemName) const int CCryEditApp::ExitInstance(int exitCode) { + AZ_TracePrintf("Exit", "Called ExitInstance() with exit code: 0x%x", exitCode); + if (m_pEditor) { m_pEditor->OnBeginShutdownSequence(); diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp index 14504cc282..3edcbaa273 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp @@ -224,6 +224,8 @@ namespace AZ void Debug::Trace::Terminate(int exitCode) { + AZ_TracePrintf("Exit", "Called Terminate() with exit code: 0x%x", exitCode); + AZ::Debug::Trace::PrintCallstack("Exit"); Platform::Terminate(exitCode); } diff --git a/Code/Legacy/CrySystem/DebugCallStack.cpp b/Code/Legacy/CrySystem/DebugCallStack.cpp index 8018e46d69..19fe4ce8df 100644 --- a/Code/Legacy/CrySystem/DebugCallStack.cpp +++ b/Code/Legacy/CrySystem/DebugCallStack.cpp @@ -222,6 +222,9 @@ void UpdateFPExceptionsMaskForThreads() ////////////////////////////////////////////////////////////////////////// int DebugCallStack::handleException(EXCEPTION_POINTERS* exception_pointer) { + AZ_TracePrintf("Exit", "Exception with exit code: 0x%x", exception_pointer->ExceptionRecord->ExceptionCode); + AZ::Debug::Trace::PrintCallstack("Exit"); + if (gEnv == NULL) { return EXCEPTION_EXECUTE_HANDLER; From a2c16fa24fb1f0f9509542b9f0404e2204454e1d Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Thu, 7 Oct 2021 10:51:22 -0500 Subject: [PATCH 090/293] adjust the default number of worker threads created by the TaskGraph & Job systems Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp | 2 +- .../Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp index e98711049c..59f9c5f6a2 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp @@ -20,7 +20,7 @@ #include -AZ_CVAR(float, cl_jobThreadsConcurrencyRatio, 0.5f, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system multiplier on the number of hw threads the machine creates at initialization"); +AZ_CVAR(float, cl_jobThreadsConcurrencyRatio, 0.6f, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system multiplier on the number of hw threads the machine creates at initialization"); AZ_CVAR(uint32_t, cl_jobThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system number of hardware threads that are reserved for O3DE system threads"); AZ_CVAR(uint32_t, cl_jobThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system minimum number of worker threads to create after scaling the number of hw threads"); diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp index 6548d9d162..5ae0fb0394 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -15,7 +15,7 @@ // Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system. AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)"); -AZ_CVAR(float, cl_taskGraphThreadsConcurrencyRatio, 0.75f, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph calculate the number of worker threads to spawn by scaling the number of hw threads, value is clamped between 0.0f and 1.0f"); +AZ_CVAR(float, cl_taskGraphThreadsConcurrencyRatio, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph calculate the number of worker threads to spawn by scaling the number of hw threads, value is clamped between 0.0f and 1.0f"); AZ_CVAR(uint32_t, cl_taskGraphThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph number of hardware threads that are reserved for O3DE system threads"); AZ_CVAR(uint32_t, cl_taskGraphThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph minimum number of worker threads to create after scaling the number of hw threads"); @@ -33,7 +33,7 @@ namespace AZ // min = cl_taskGraphThreadsMinNumber, // max = number of hardware threads - cl_taskGraphThreadsNumReserved uint32_t scaledHardwareThreads = AZ::GetMax( cl_taskGraphThreadsMinNumber, static_cast(AZStd::floor( 0.5f + AZ::GetClamp(cl_taskGraphThreadsConcurrencyRatio, 0.0f, 1.0f) * static_cast(AZStd::thread::hardware_concurrency() - cl_taskGraphThreadsNumReserved)))); - m_taskExecutor = aznew TaskExecutor(scaledHardwareThreads); + m_taskExecutor = aznew TaskExecutor(scaledHardwareThreads); TaskExecutor::SetInstance(m_taskExecutor); Interface::Register(this); } From 863a7c8382d484378ffc648324cb993eb7e8fd2a Mon Sep 17 00:00:00 2001 From: John Date: Thu, 7 Oct 2021 17:19:22 +0100 Subject: [PATCH 091/293] Address PR comments. Signed-off-by: John --- Code/Editor/Core/LevelEditorMenuHandler.cpp | 12 ++++++------ Code/Editor/QtViewPaneManager.h | 2 +- .../API/ComponentModeCollectionInterface.h | 3 ++- .../API/ViewportEditorModeTrackerNotificationBus.cpp | 2 +- .../ComponentMode/ComponentModeCollection.cpp | 5 +++-- .../ComponentMode/ComponentModeCollection.h | 2 +- .../UI/PropertyEditor/EntityPropertyEditor.cpp | 4 ++-- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp index 25467756ac..ec92622f02 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp @@ -1191,8 +1191,8 @@ void LevelEditorMenuHandler::OnEditorModeActivated( { if (mode == ViewportEditorMode::Component) { - auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); - if (!menuWrapper.isNull()) + if (auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); + !menuWrapper.isNull()) { // copy of menu actions auto actions = menuWrapper.Get()->actions(); @@ -1222,8 +1222,8 @@ void LevelEditorMenuHandler::OnEditorModeDeactivated( void LevelEditorMenuHandler::AddEditMenuAction(QAction* action) { - auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); - if (!menuWrapper.isNull()) + if (auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); + !menuWrapper.isNull()) { menuWrapper.Get()->addAction(action); } @@ -1247,8 +1247,8 @@ void LevelEditorMenuHandler::AddMenuAction(AZStd::string_view categoryId, QActio void LevelEditorMenuHandler::RestoreEditMenuToDefault() { - auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); - if (!menuWrapper.isNull()) + if (auto menuWrapper = m_actionManager->FindMenu(s_editMenuId); + !menuWrapper.isNull()) { menuWrapper.Get()->clear(); PopulateEditMenu(menuWrapper); diff --git a/Code/Editor/QtViewPaneManager.h b/Code/Editor/QtViewPaneManager.h index fe568e5438..0515ae726e 100644 --- a/Code/Editor/QtViewPaneManager.h +++ b/Code/Editor/QtViewPaneManager.h @@ -247,7 +247,7 @@ private: AZStd::unique_ptr m_componentModeNotifications; //!< Helper for EditorComponentModeNotificationBus so - //!< QtViewPaneManager does not need to inherit directly from it. */ + //!< QtViewPaneManager does not need to inherit directly from it. */ using EditorWindowRequestBusImpl = AzToolsFramework::EditorWindowRequestBusImpl; EditorWindowRequestBusImpl m_windowRequest; //!< Helper for EditorWindowRequestBus so diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h index 39cd6bd6a3..4f9d72cb4d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentModeCollectionInterface.h @@ -23,6 +23,7 @@ namespace AzToolsFramework virtual ~ComponentModeCollectionInterface() = default; //! Retrieves the list of all Component types (usually one). - virtual const AZStd::vector& GetComponentTypes() const = 0; + //! @note If called outside of component mode, an empty vector will be returned. + virtual AZStd::vector GetComponentTypes() const = 0; }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp index 278f9db950..a61ea088d0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.cpp @@ -13,7 +13,7 @@ namespace AzToolsFramework { void ViewportEditorModeNotifications::Reflect(AZ::ReflectContext* context) { - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + if (auto* behaviorContext = azrtti_cast(context)) { behaviorContext->EBus("ViewportEditorModeNotificationsBus") ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index e816c0ce4c..1768cb5920 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -203,9 +203,10 @@ namespace AzToolsFramework } } - const AZStd::vector& ComponentModeCollection::GetComponentTypes() const + AZStd::vector ComponentModeCollection::GetComponentTypes() const { - return m_activeComponentTypes; + // If in component mode, return the active component types, otherwise return an empty vector + return InComponentMode() ? m_activeComponentTypes : AZStd::vector{}; } void ComponentModeCollection::BeginComponentMode() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h index fb35ca8971..3b7690b969 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.h @@ -92,7 +92,7 @@ namespace AzToolsFramework void PopulateViewportUi(); // ComponentModeCollectionInterface overrides ... - const AZStd::vector& GetComponentTypes() const override; + AZStd::vector GetComponentTypes() const override; private: // Internal helper used by Select[|Prev|Next]ActiveComponentMode diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index ad62614770..9ffe8021e3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -5710,7 +5710,7 @@ namespace AzToolsFramework { DisableComponentActions(this, m_entityComponentActions); SetPropertyEditorState(m_gui, false); - const auto& componentModeTypes = m_componentModeCollection->GetComponentTypes(); + const auto componentModeTypes = m_componentModeCollection->GetComponentTypes(); m_disabled = true; if (!componentModeTypes.empty()) @@ -5735,7 +5735,7 @@ namespace AzToolsFramework { EnableComponentActions(this, m_entityComponentActions); SetPropertyEditorState(m_gui, true); - const auto& componentModeTypes = m_componentModeCollection->GetComponentTypes(); + const auto componentModeTypes = m_componentModeCollection->GetComponentTypes(); m_disabled = false; for (auto componentEditor : m_componentEditors) From a114077e726c95fbb21721ce4c7eb4fb2b7145ce Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Thu, 7 Oct 2021 12:53:33 -0400 Subject: [PATCH 092/293] Final touches on the first pass of imgui hierarchy debugger Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugHierarchyDebugger.cpp | 198 ++++++++++++++++++ .../Debug/MultiplayerDebugHierarchyDebugger.h | 55 +++++ .../MultiplayerDebugHierarchyReporter.cpp | 45 +++- .../Debug/MultiplayerDebugHierarchyReporter.h | 13 +- 4 files changed, 298 insertions(+), 13 deletions(-) create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp create mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp new file mode 100644 index 0000000000..393f67474b --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp @@ -0,0 +1,198 @@ +/* + * 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 "MultiplayerDebugHierarchyDebugger.h" + +#include +#include +#include +#include + +#if defined(IMGUI_ENABLED) +#include +#endif + +namespace Multiplayer +{ + MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() + : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug")) + { + CollectHierarchyRoots(); + + AZ::EntitySystemBus::Handler::BusConnect(); + m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); + } + + MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter() + { + AZ::EntitySystemBus::Handler::BusDisconnect(); + } + + // -------------------------------------------------------------------------------------------- + void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() + { +#if defined(IMGUI_ENABLED) + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), + "Hierarchy, Root entity name [%s]: %4zu members", + rootComponent->GetEntity()->GetName().c_str(), + hierarchicalChildren.size())) + { + ImGui::Separator(); + ImGui::Columns(4, "hierarchy_columns"); + ImGui::Text("EntityId"); + ImGui::NextColumn(); + ImGui::Text("NetEntityId"); + ImGui::NextColumn(); + ImGui::Text("Entity Name"); + ImGui::NextColumn(); + ImGui::Text("Role"); + ImGui::NextColumn(); + + ImGui::Separator(); + ImGui::Columns(4, "hierarchy child info"); + + bool firstEntity = true; + for (const AZ::Entity* entity : hierarchicalChildren) + { + ImGui::Text("%s", entity->GetId().ToString().c_str()); + ImGui::NextColumn(); + ImGui::Text("%u", GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId())); + ImGui::NextColumn(); + ImGui::Text("%s", entity->GetName().c_str()); + ImGui::NextColumn(); + + if (firstEntity) + { + ImGui::Text("Root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Inner root node"); + } + else if (entity->FindComponent()) + { + ImGui::Text("Child node"); + } + ImGui::NextColumn(); + + firstEntity = false; + } + + ImGui::Columns(1); + ImGui::TreePop(); + } + } + } + } +#endif + } + + + void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay() + { + if (!m_hierarchyRoots.empty()) + { + if (m_debugDisplay == nullptr) + { + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId); + m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + } + + const AZ::u32 stateBefore = m_debugDisplay->GetState(); + m_debugDisplay->SetColor(AZ::Colors::White); + + for (const auto& root : m_hierarchyRoots) + { + if (const auto* rootComponent = root.second.m_rootComponent) + { + if (rootComponent->IsHierarchicalRoot()) + { + const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); + + azsprintf(m_statusBuffer, "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(), + aznumeric_cast(hierarchicalChildren.size())); + + AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation(); + constexpr bool centerText = true; + m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); + } + } + } + + m_debugDisplay->SetState(stateBefore); + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } + + void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId) + { + if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) + { + if (auto* rootComponent = childEntity->FindComponent()) + { + m_hierarchyRoots.erase(rootComponent); + } + } + } + + void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() + { + AZStd::vector gatheredEntries; + const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) + { + gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); + for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) + { + if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) + { + gatheredEntries.push_back(visEntry); + } + } + } + ); + + for (const AzFramework::VisibilityEntry* entry : gatheredEntries) + { + const AZ::Entity* entity = static_cast(entry->m_userData); + if (auto* rootComponent = entity->FindComponent()) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } + } + } +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h new file mode 100644 index 0000000000..978664b96b --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace Multiplayer +{ + /** + * \brief Reports hierarchy information in the scene. + */ + class MultiplayerDebugHierarchyReporter + : public AZ::EntitySystemBus::Handler + { + public: + MultiplayerDebugHierarchyReporter(); + ~MultiplayerDebugHierarchyReporter() override; + + //! main update loop + void OnImGuiUpdate(); + + //! Draws hierarchy information over hierarchy root entities + void UpdateDebugOverlay(); + + //! EntitySystemBus overrides. + void OnEntityActivated(const AZ::EntityId& entityId) override; + void OnEntityDeactivated(const AZ::EntityId& entityId) override; + + private: + AZ::ScheduledEvent m_updateDebugOverlay; + + AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; + + struct HierarchyRootInfo + { + NetworkHierarchyRootComponent* m_rootComponent = nullptr; + NetworkHierarchyChangedEvent::Handler m_changedEvent; + NetworkHierarchyLeaveEvent::Handler m_leaveEvent; + }; + + AZStd::unordered_map m_hierarchyRoots; + void CollectHierarchyRoots(); + + char m_statusBuffer[100] = {}; + }; +} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp index 32e9a776a4..7c38a340eb 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.cpp @@ -8,6 +8,8 @@ #include "MultiplayerDebugHierarchyReporter.h" +#include +#include #include #include #include @@ -17,8 +19,6 @@ #include #endif -#pragma optimize("", off) - namespace Multiplayer { MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() @@ -39,6 +39,9 @@ namespace Multiplayer void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() { #if defined(IMGUI_ENABLED) + ImGui::Text("Hierarchies"); + ImGui::Separator(); + for (const auto& root : m_hierarchyRoots) { if (const auto* rootComponent = root.second.m_rootComponent) @@ -48,7 +51,7 @@ namespace Multiplayer const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), - "Hierarchy, Root entity name [%s]: %4zu members", + "[%s] %4zu members", rootComponent->GetEntity()->GetName().c_str(), hierarchicalChildren.size())) { @@ -99,6 +102,16 @@ namespace Multiplayer } } } + + ImGui::Separator(); + if (ImGui::InputFloat("Awareness Radius", &m_awarenessRadius)) + { + CollectHierarchyRoots(); + } + if (ImGui::Button("Refresh")) + { + CollectHierarchyRoots(); + } #endif } @@ -168,9 +181,18 @@ namespace Multiplayer void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() { + m_hierarchyRoots.clear(); + AZ::Sphere awarenessSphere(AZ::Vector3::CreateZero(), m_awarenessRadius); + + const auto viewportContextManager = AZ::Interface::Get(); + if (const auto viewportContext = viewportContextManager->GetDefaultViewportContext()) + { + awarenessSphere.SetCenter(viewportContext->GetCameraTransform().GetTranslation()); + } + AZStd::vector gatheredEntries; - const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); - AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, + [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) { gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) @@ -188,12 +210,15 @@ namespace Multiplayer const AZ::Entity* entity = static_cast(entry->m_userData); if (auto* rootComponent = entity->FindComponent()) { - HierarchyRootInfo info; - info.m_rootComponent = rootComponent; - rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); - rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); + if (awarenessSphere.GetCenter().GetDistanceEstimate(entity->GetTransform()->GetWorldTranslation()) < m_awarenessRadius) + { + HierarchyRootInfo info; + info.m_rootComponent = rootComponent; + rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); + rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); - m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); + } } } } diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h index 98a131614c..2ce7e055a0 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyReporter.h @@ -15,6 +15,9 @@ namespace Multiplayer { + /** + * /brief Provides ImGui and debug draw hierarchy information at runtime. + */ class MultiplayerDebugHierarchyReporter : public AZ::EntitySystemBus::Handler { @@ -22,15 +25,17 @@ namespace Multiplayer MultiplayerDebugHierarchyReporter(); ~MultiplayerDebugHierarchyReporter() override; - //! main update loop + //! Main update loop. void OnImGuiUpdate(); - //! Draws bandwidth text over entities + //! Draws hierarchy information over hierarchy root entities. void UpdateDebugOverlay(); //! EntitySystemBus overrides. + //! @{ void OnEntityActivated(const AZ::EntityId& entityId) override; void OnEntityDeactivated(const AZ::EntityId& entityId) override; + //! @} private: AZ::ScheduledEvent m_updateDebugOverlay; @@ -46,7 +51,9 @@ namespace Multiplayer AZStd::unordered_map m_hierarchyRoots; void CollectHierarchyRoots(); - + char m_statusBuffer[100] = {}; + + float m_awarenessRadius = 1000.f; }; } From ecd358a53e76a2d66f538d24975142900d1a0b1a Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Thu, 7 Oct 2021 12:56:44 -0400 Subject: [PATCH 093/293] Cleaning up Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../MultiplayerDebugHierarchyDebugger.cpp | 198 ------------------ .../Debug/MultiplayerDebugHierarchyDebugger.h | 55 ----- 2 files changed, 253 deletions(-) delete mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp delete mode 100644 Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp deleted file mode 100644 index 393f67474b..0000000000 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "MultiplayerDebugHierarchyDebugger.h" - -#include -#include -#include -#include - -#if defined(IMGUI_ENABLED) -#include -#endif - -namespace Multiplayer -{ - MultiplayerDebugHierarchyReporter::MultiplayerDebugHierarchyReporter() - : m_updateDebugOverlay([this]() { UpdateDebugOverlay(); }, AZ::Name("UpdateHierarchyDebug")) - { - CollectHierarchyRoots(); - - AZ::EntitySystemBus::Handler::BusConnect(); - m_updateDebugOverlay.Enqueue(AZ::TimeMs{ 0 }, true); - } - - MultiplayerDebugHierarchyReporter::~MultiplayerDebugHierarchyReporter() - { - AZ::EntitySystemBus::Handler::BusDisconnect(); - } - - // -------------------------------------------------------------------------------------------- - void MultiplayerDebugHierarchyReporter::OnImGuiUpdate() - { -#if defined(IMGUI_ENABLED) - for (const auto& root : m_hierarchyRoots) - { - if (const auto* rootComponent = root.second.m_rootComponent) - { - if (rootComponent->IsHierarchicalRoot()) - { - const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); - - if (ImGui::TreeNode(rootComponent->GetEntity()->GetName().c_str(), - "Hierarchy, Root entity name [%s]: %4zu members", - rootComponent->GetEntity()->GetName().c_str(), - hierarchicalChildren.size())) - { - ImGui::Separator(); - ImGui::Columns(4, "hierarchy_columns"); - ImGui::Text("EntityId"); - ImGui::NextColumn(); - ImGui::Text("NetEntityId"); - ImGui::NextColumn(); - ImGui::Text("Entity Name"); - ImGui::NextColumn(); - ImGui::Text("Role"); - ImGui::NextColumn(); - - ImGui::Separator(); - ImGui::Columns(4, "hierarchy child info"); - - bool firstEntity = true; - for (const AZ::Entity* entity : hierarchicalChildren) - { - ImGui::Text("%s", entity->GetId().ToString().c_str()); - ImGui::NextColumn(); - ImGui::Text("%u", GetMultiplayer()->GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId())); - ImGui::NextColumn(); - ImGui::Text("%s", entity->GetName().c_str()); - ImGui::NextColumn(); - - if (firstEntity) - { - ImGui::Text("Root node"); - } - else if (entity->FindComponent()) - { - ImGui::Text("Inner root node"); - } - else if (entity->FindComponent()) - { - ImGui::Text("Child node"); - } - ImGui::NextColumn(); - - firstEntity = false; - } - - ImGui::Columns(1); - ImGui::TreePop(); - } - } - } - } -#endif - } - - - void MultiplayerDebugHierarchyReporter::UpdateDebugOverlay() - { - if (!m_hierarchyRoots.empty()) - { - if (m_debugDisplay == nullptr) - { - AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; - AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId); - m_debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); - } - - const AZ::u32 stateBefore = m_debugDisplay->GetState(); - m_debugDisplay->SetColor(AZ::Colors::White); - - for (const auto& root : m_hierarchyRoots) - { - if (const auto* rootComponent = root.second.m_rootComponent) - { - if (rootComponent->IsHierarchicalRoot()) - { - const AZStd::vector& hierarchicalChildren = rootComponent->GetHierarchicalEntities(); - - azsprintf(m_statusBuffer, "Hierarchy [%s] %u members", rootComponent->GetEntity()->GetName().c_str(), - aznumeric_cast(hierarchicalChildren.size())); - - AZ::Vector3 entityPosition = rootComponent->GetEntity()->GetTransform()->GetWorldTranslation(); - constexpr bool centerText = true; - m_debugDisplay->DrawTextLabel(entityPosition, 1.0f, m_statusBuffer, centerText, 0, 0); - } - } - } - - m_debugDisplay->SetState(stateBefore); - } - } - - void MultiplayerDebugHierarchyReporter::OnEntityActivated(const AZ::EntityId& entityId) - { - if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) - { - if (auto* rootComponent = childEntity->FindComponent()) - { - HierarchyRootInfo info; - info.m_rootComponent = rootComponent; - rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); - rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); - - m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); - } - } - } - - void MultiplayerDebugHierarchyReporter::OnEntityDeactivated(const AZ::EntityId& entityId) - { - if (const AZ::Entity* childEntity = AZ::Interface::Get()->FindEntity(entityId)) - { - if (auto* rootComponent = childEntity->FindComponent()) - { - m_hierarchyRoots.erase(rootComponent); - } - } - } - - void MultiplayerDebugHierarchyReporter::CollectHierarchyRoots() - { - AZStd::vector gatheredEntries; - const AZ::Sphere awarenessSphere = AZ::Sphere(AZ::Vector3::CreateZero(), 1000.f); - AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(awarenessSphere, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData) - { - gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); - for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) - { - if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) - { - gatheredEntries.push_back(visEntry); - } - } - } - ); - - for (const AzFramework::VisibilityEntry* entry : gatheredEntries) - { - const AZ::Entity* entity = static_cast(entry->m_userData); - if (auto* rootComponent = entity->FindComponent()) - { - HierarchyRootInfo info; - info.m_rootComponent = rootComponent; - rootComponent->BindNetworkHierarchyChangedEventHandler(info.m_changedEvent); - rootComponent->BindNetworkHierarchyLeaveEventHandler(info.m_leaveEvent); - - m_hierarchyRoots.insert(AZStd::make_pair(rootComponent, info)); - } - } - } -} diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h deleted file mode 100644 index 978664b96b..0000000000 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugHierarchyDebugger.h +++ /dev/null @@ -1,55 +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 - * - */ - -#pragma once - -#include -#include -#include -#include - -namespace Multiplayer -{ - /** - * \brief Reports hierarchy information in the scene. - */ - class MultiplayerDebugHierarchyReporter - : public AZ::EntitySystemBus::Handler - { - public: - MultiplayerDebugHierarchyReporter(); - ~MultiplayerDebugHierarchyReporter() override; - - //! main update loop - void OnImGuiUpdate(); - - //! Draws hierarchy information over hierarchy root entities - void UpdateDebugOverlay(); - - //! EntitySystemBus overrides. - void OnEntityActivated(const AZ::EntityId& entityId) override; - void OnEntityDeactivated(const AZ::EntityId& entityId) override; - - private: - AZ::ScheduledEvent m_updateDebugOverlay; - - AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; - - struct HierarchyRootInfo - { - NetworkHierarchyRootComponent* m_rootComponent = nullptr; - NetworkHierarchyChangedEvent::Handler m_changedEvent; - NetworkHierarchyLeaveEvent::Handler m_leaveEvent; - }; - - AZStd::unordered_map m_hierarchyRoots; - void CollectHierarchyRoots(); - - char m_statusBuffer[100] = {}; - }; -} From 3c50fdc671b1d1e1ef562b3a0b2f1a3840ac81a0 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 7 Oct 2021 11:58:01 -0500 Subject: [PATCH 094/293] =?UTF-8?q?First=20phase=20of=20refactoring=20atom?= =?UTF-8?q?=20thumbnail=20and=20preview=20rendering=20into=20a=20reusable?= =?UTF-8?q?=20system=20that=20can=20be=20used=20for=20additional=20thumbna?= =?UTF-8?q?il=20types=20and=20capturing=20preview=20images=20for=20other?= =?UTF-8?q?=20purposes.=20=20Our=20=E2=80=A2=20Removed=20classes=20for=20i?= =?UTF-8?q?nitialization=20and=20teardown=20steps=20of=20the=20renderer=20?= =?UTF-8?q?=E2=80=A2=20Moved=20initialization=20and=20teardown=20logic=20b?= =?UTF-8?q?ack=20to=20the=20renderer=20constructor=20and=20destructor=20?= =?UTF-8?q?=E2=80=A2=20Combined=20thumbnail=20render=20context=20and=20dat?= =?UTF-8?q?a=20with=20the=20main=20renderer=20class=20=E2=80=A2=20Made=20a?= =?UTF-8?q?ll=20render=20data=20private=20and=20instead=20implemented=20a?= =?UTF-8?q?=20public=20interface=20=E2=80=A2=20Remaining=20steps=20were=20?= =?UTF-8?q?simplified=20and=20updated=20to=20work=20directly=20with=20the?= =?UTF-8?q?=20new=20public=20interface=20=E2=80=A2=20Changed=20the=20waiti?= =?UTF-8?q?ng=20for=20assets=20to=20load=20state=20to=20poll=20asset=20sta?= =?UTF-8?q?tus=20on=20tick=20because=20we=20were=20timing=20out=20there=20?= =?UTF-8?q?anyway=20=E2=80=A2=20Unified=20redundant=20camera=20configurati?= =?UTF-8?q?on=20variables=20and=20made=20sure=20they=20were=20used=20consi?= =?UTF-8?q?stently=20when=20initializing=20and=20updating=20the=20scene=20?= =?UTF-8?q?and=20camera=20=E2=80=A2=20Changed=20interface=20for=20custom?= =?UTF-8?q?=20feature=20processor=20request=20API=20to=20build=20a=20set?= =?UTF-8?q?=20instead=20of=20returning=20a=20vector=20=E2=80=A2=20Moved=20?= =?UTF-8?q?initialization=20of=20the=20thumbnail=20renderer=20and=20previe?= =?UTF-8?q?w=20factory=20after=20asset=20catalog=20has=20loaded?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../ThumbnailFeatureProcessorProviderBus.h | 2 +- .../EditorCommonFeaturesSystemComponent.cpp | 12 +- .../EditorCommonFeaturesSystemComponent.h | 4 + .../Rendering/CommonThumbnailRenderer.cpp | 364 +++++++++++++++--- .../Rendering/CommonThumbnailRenderer.h | 104 ++++- .../Rendering/ThumbnailRendererContext.h | 42 -- .../Rendering/ThumbnailRendererData.h | 70 ---- .../ThumbnailRendererSteps/CaptureStep.cpp | 97 +---- .../ThumbnailRendererSteps/CaptureStep.h | 11 +- .../FindThumbnailToRenderStep.cpp | 48 +-- .../FindThumbnailToRenderStep.h | 4 +- .../ThumbnailRendererSteps/InitializeStep.cpp | 191 --------- .../ThumbnailRendererSteps/InitializeStep.h | 37 -- .../ReleaseResourcesStep.cpp | 57 --- .../ReleaseResourcesStep.h | 30 -- .../ThumbnailRendererStep.h | 6 +- .../WaitForAssetsToLoadStep.cpp | 72 +--- .../WaitForAssetsToLoadStep.h | 16 +- ...egration_commonfeatures_editor_files.cmake | 6 - 19 files changed, 451 insertions(+), 722 deletions(-) delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h index 8030c3ae05..a4d76809ba 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h @@ -24,7 +24,7 @@ namespace AZ { public: //! Get a list of custom feature processors to register with thumbnail renderer - virtual const AZStd::vector& GetCustomFeatureProcessors() const = 0; + virtual void GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; }; using ThumbnailFeatureProcessorProviderBus = AZ::EBus; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 896e88f4e2..8be947ae26 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -82,12 +82,11 @@ namespace AZ void EditorCommonFeaturesSystemComponent::Activate() { - m_renderer = AZStd::make_unique(); - m_previewerFactory = AZStd::make_unique (); m_skinnedMeshDebugDisplay = AZStd::make_unique(); AzToolsFramework::EditorLevelNotificationBus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect(); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); } @@ -95,6 +94,7 @@ namespace AZ { AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect(); m_skinnedMeshDebugDisplay.reset(); @@ -191,6 +191,14 @@ namespace AZ } } + void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) + { + AZ::TickBus::QueueFunction([this](){ + m_renderer = AZStd::make_unique(); + m_previewerFactory = AZStd::make_unique(); + }); + } + const AzToolsFramework::AssetBrowser::PreviewerFactory* EditorCommonFeaturesSystemComponent::GetPreviewerFactory( const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index 2560bf7e11..d26886c4ae 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -28,6 +28,7 @@ namespace AZ , public AzToolsFramework::EditorLevelNotificationBus::Handler , public AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler , public AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler + , public AzFramework::AssetCatalogEventBus::Handler , public AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: @@ -56,6 +57,9 @@ namespace AZ void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override; + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + // AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler overrides... const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp index 9c69fdd995..d12d9df892 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp @@ -6,15 +6,42 @@ * */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include -#include #include #include -#include -#include #include +#include namespace AZ { @@ -23,69 +50,297 @@ namespace AZ namespace Thumbnails { CommonThumbnailRenderer::CommonThumbnailRenderer() - : m_data(new ThumbnailRendererData) { // CommonThumbnailRenderer supports both models and materials, but we connect on materialAssetType // since MaterialOrModelThumbnail dispatches event on materialAssetType address too AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); - SystemTickBus::Handler::BusConnect(); ThumbnailFeatureProcessorProviderBus::Handler::BusConnect(); + SystemTickBus::Handler::BusConnect(); - m_steps[Step::Initialize] = AZStd::make_shared(this); - m_steps[Step::FindThumbnailToRender] = AZStd::make_shared(this); - m_steps[Step::WaitForAssetsToLoad] = AZStd::make_shared(this); - m_steps[Step::Capture] = AZStd::make_shared(this); - m_steps[Step::ReleaseResources] = AZStd::make_shared(this); + m_entityContext = AZStd::make_unique(); + m_entityContext->InitContext(); - m_minimalFeatureProcessors = - { - "AZ::Render::TransformServiceFeatureProcessor", - "AZ::Render::MeshFeatureProcessor", - "AZ::Render::SimplePointLightFeatureProcessor", - "AZ::Render::SimpleSpotLightFeatureProcessor", - "AZ::Render::PointLightFeatureProcessor", - // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow - // flickering [ATOM-13568] - // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. - // Possibly re-enable with [GFX TODO][ATOM-13639] - // "AZ::Render::DirectionalLightFeatureProcessor", - "AZ::Render::DiskLightFeatureProcessor", - "AZ::Render::CapsuleLightFeatureProcessor", - "AZ::Render::QuadLightFeatureProcessor", - "AZ::Render::DecalTextureArrayFeatureProcessor", - "AZ::Render::ImageBasedLightFeatureProcessor", - "AZ::Render::PostProcessFeatureProcessor", - "AZ::Render::SkyBoxFeatureProcessor" - }; + // Create and register a scene with all required feature processors + AZStd::unordered_set featureProcessors; + ThumbnailFeatureProcessorProviderBus::Broadcast( + &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors, featureProcessors); + + RPI::SceneDescriptor sceneDesc; + sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); + m_scene = RPI::Scene::CreateScene(sceneDesc); + + // Bind m_frameworkScene to the entity context's AzFramework::Scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation."); + + Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(m_sceneName); + AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); + + m_frameworkScene = createSceneOutcome.TakeValue(); + m_frameworkScene->SetSubsystem(m_scene); + m_frameworkScene->SetSubsystem(m_entityContext.get()); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = m_pipelineName; + pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; + + // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue + // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost + pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; + m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(m_renderPipeline); + m_scene->Activate(); + RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + m_passHierarchy.push_back(m_pipelineName); + m_passHierarchy.push_back("CopyToSwapChain"); + + // Connect camera to pipeline's default view after camera entity activated + Matrix4x4 viewToClipMatrix; + MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); + m_view = RPI::View::CreateView(Name("MainCamera"), RPI::View::UsageCamera); + m_view->SetViewToClipMatrix(viewToClipMatrix); + m_renderPipeline->SetDefaultView(m_view); + + // Create preview model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, m_entityContext->GetContextId(), &AzFramework::EntityContextRequestBus::Events::CreateEntity, + "ThumbnailPreviewModel"); + m_modelEntity->CreateComponent(Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Init(); + m_modelEntity->Activate(); + + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultModelAsset.Create(DefaultModelAssetId, true); + + m_steps[CommonThumbnailRenderer::Step::FindThumbnailToRender] = AZStd::make_shared(this); + m_steps[CommonThumbnailRenderer::Step::WaitForAssetsToLoad] = AZStd::make_shared(this); + m_steps[CommonThumbnailRenderer::Step::Capture] = AZStd::make_shared(this); + SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); } CommonThumbnailRenderer::~CommonThumbnailRenderer() { - if (m_currentStep != Step::None) - { - CommonThumbnailRenderer::SetStep(Step::ReleaseResources); - } AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); SystemTickBus::Handler::BusDisconnect(); ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect(); + + SetStep(CommonThumbnailRenderer::Step::None); + + if (m_modelEntity) + { + AzFramework::EntityContextRequestBus::Event( + m_entityContext->GetContextId(), &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + } + + m_scene->Deactivate(); + m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); + RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_frameworkScene->UnsetSubsystem(m_scene); + m_frameworkScene->UnsetSubsystem(m_entityContext.get()); } void CommonThumbnailRenderer::SetStep(Step step) { - if (m_currentStep != Step::None) + auto stepItr = m_steps.find(m_currentStep); + if (stepItr != m_steps.end()) { - m_steps[m_currentStep]->Stop(); + stepItr->second->Stop(); } + m_currentStep = step; - m_steps[m_currentStep]->Start(); + + stepItr = m_steps.find(m_currentStep); + if (stepItr != m_steps.end()) + { + stepItr->second->Start(); + } } - Step CommonThumbnailRenderer::GetStep() const + CommonThumbnailRenderer::Step CommonThumbnailRenderer::GetStep() const { return m_currentStep; } + void CommonThumbnailRenderer::SelectThumbnail() + { + if (!m_thumbnailInfoQueue.empty()) + { + // pop the next thumbnailkey to be rendered from the queue + m_currentThubnailInfo = m_thumbnailInfoQueue.front(); + m_thumbnailInfoQueue.pop(); + + SetStep(CommonThumbnailRenderer::Step::WaitForAssetsToLoad); + } + } + + void CommonThumbnailRenderer::CancelThumbnail() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + m_currentThubnailInfo.m_key, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + } + + void CommonThumbnailRenderer::CompleteThumbnail() + { + SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + } + + void CommonThumbnailRenderer::LoadAssets() + { + // Determine if thumbnailkey contains a material asset or set a default material + const Data::AssetId materialAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::MaterialAsset::RTTI_Type()); + m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, true); + + // Determine if thumbnailkey contains a model asset or set a default model + const Data::AssetId modelAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::ModelAsset::RTTI_Type()); + m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, true); + + // Determine if thumbnailkey contains a lighting preset asset or set a default lighting preset + const Data::AssetId lightingPresetAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::AnyAsset::RTTI_Type()); + m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, true); + } + + void CommonThumbnailRenderer::UpdateLoadAssets() + { + if (m_materialAsset.IsReady() && m_modelAsset.IsReady() && m_lightingPresetAsset.IsReady()) + { + SetStep(CommonThumbnailRenderer::Step::Capture); + return; + } + + if (m_materialAsset.IsError() || m_modelAsset.IsError() || m_lightingPresetAsset.IsError()) + { + CancelLoadAssets(); + return; + } + } + + void CommonThumbnailRenderer::CancelLoadAssets() + { + AZ_Warning( + "CommonThumbnailRenderer", m_materialAsset.IsReady(), "Asset failed to load in time: %s", + m_materialAsset.ToString().c_str()); + AZ_Warning( + "CommonThumbnailRenderer", m_modelAsset.IsReady(), "Asset failed to load in time: %s", + m_modelAsset.ToString().c_str()); + AZ_Warning( + "CommonThumbnailRenderer", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", + m_lightingPresetAsset.ToString().c_str()); + CancelThumbnail(); + } + + void CommonThumbnailRenderer::UpdateScene() + { + UpdateModel(); + UpdateLighting(); + UpdateCamera(); + } + + void CommonThumbnailRenderer::UpdateModel() + { + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, + m_materialAsset.GetId()); + + Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); + } + + void CommonThumbnailRenderer::UpdateLighting() + { + auto preset = m_lightingPresetAsset->GetDataAs(); + if (preset) + { + auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); + auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); + auto directionalLightFeatureProcessor = + m_scene->GetFeatureProcessor(); + auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + skyboxFeatureProcessor->Enable(true); + skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); + + Camera::Configuration cameraConfig; + cameraConfig.m_fovRadians = FieldOfView; + cameraConfig.m_nearClipDistance = NearDist; + cameraConfig.m_farClipDistance = FarDist; + cameraConfig.m_frustumWidth = 100.0f; + cameraConfig.m_frustumHeight = 100.0f; + + AZStd::vector lightHandles; + + preset->ApplyLightingPreset( + iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, + cameraConfig, lightHandles); + } + } + + void CommonThumbnailRenderer::UpdateCamera() + { + // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it + Vector3 center = {}; + float radius = {}; + m_modelAsset->GetAabb().GetAsSphere(center, radius); + + const auto distance = radius + NearDist; + const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); + const auto cameraPosition = center - cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); + const auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); + m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); + } + + RPI::AttachmentReadback::CallbackFunction CommonThumbnailRenderer::GetCaptureCallback() + { + return [this](const RPI::AttachmentReadback::ReadbackResult& result) + { + if (result.m_dataBuffer) + { + QImage image( + result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, + result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888); + + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + m_currentThubnailInfo.m_key, + &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, QPixmap::fromImage(image)); + } + else + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + m_currentThubnailInfo.m_key, + &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + } + }; + } + + bool CommonThumbnailRenderer::StartCapture() + { + if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) + { + renderToTexturePass->ResizeOutput(m_currentThubnailInfo.m_size, m_currentThubnailInfo.m_size); + } + + m_renderPipeline->AddToRenderTickOnce(); + + bool startedCapture = false; + Render::FrameCaptureRequestBus::BroadcastResult( + startedCapture, &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, + AZStd::string("Output"), GetCaptureCallback(), RPI::PassAttachmentReadbackOption::Output); + return startedCapture; + } + + void CommonThumbnailRenderer::EndCapture() + { + m_renderPipeline->RemoveFromRenderTick(); + } + bool CommonThumbnailRenderer::Installed() const { return true; @@ -96,24 +351,31 @@ namespace AZ AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); } - const AZStd::vector& CommonThumbnailRenderer::GetCustomFeatureProcessors() const + void CommonThumbnailRenderer::GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const { - return m_minimalFeatureProcessors; + featureProcessors.insert({ + "AZ::Render::TransformServiceFeatureProcessor", + "AZ::Render::MeshFeatureProcessor", + "AZ::Render::SimplePointLightFeatureProcessor", + "AZ::Render::SimpleSpotLightFeatureProcessor", + "AZ::Render::PointLightFeatureProcessor", + // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow + // flickering [ATOM-13568] + // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. + // Possibly re-enable with [GFX TODO][ATOM-13639] + // "AZ::Render::DirectionalLightFeatureProcessor", + "AZ::Render::DiskLightFeatureProcessor", + "AZ::Render::CapsuleLightFeatureProcessor", + "AZ::Render::QuadLightFeatureProcessor", + "AZ::Render::DecalTextureArrayFeatureProcessor", + "AZ::Render::ImageBasedLightFeatureProcessor", + "AZ::Render::PostProcessFeatureProcessor", + "AZ::Render::SkyBoxFeatureProcessor" }); } - AZStd::shared_ptr CommonThumbnailRenderer::GetData() const - { - return m_data; - } - void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) { - m_data->m_thumbnailSize = thumbnailSize; - m_data->m_thumbnailQueue.push(thumbnailKey); - if (m_currentStep == Step::None) - { - SetStep(Step::Initialize); - } + m_thumbnailInfoQueue.push({ thumbnailKey, thumbnailSize }); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h index 7c3b17e104..2b1ccbd4e6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h @@ -8,15 +8,24 @@ #pragma once +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include -#include +namespace AzFramework +{ + class Scene; +} // Disables warning messages triggered by the Qt library -// 4251: class needs to have dll-interface to be used by clients of class +// 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") #include @@ -32,10 +41,9 @@ namespace AZ //! Provides custom rendering of material and model thumbnails class CommonThumbnailRenderer - : public ThumbnailRendererContext - , private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler - , private SystemTickBus::Handler - , private ThumbnailFeatureProcessorProviderBus::Handler + : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler + , public SystemTickBus::Handler + , public ThumbnailFeatureProcessorProviderBus::Handler { public: AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0) @@ -43,10 +51,33 @@ namespace AZ CommonThumbnailRenderer(); ~CommonThumbnailRenderer(); - //! ThumbnailRendererContext overrides... - void SetStep(Step step) override; - Step GetStep() const override; - AZStd::shared_ptr GetData() const override; + enum class Step : AZ::s8 + { + None, + FindThumbnailToRender, + WaitForAssetsToLoad, + Capture + }; + + void SetStep(Step step); + Step GetStep() const; + + void SelectThumbnail(); + void CancelThumbnail(); + void CompleteThumbnail(); + + void LoadAssets(); + void UpdateLoadAssets(); + void CancelLoadAssets(); + + void UpdateScene(); + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + RPI::AttachmentReadback::CallbackFunction GetCaptureCallback(); + bool StartCapture(); + void EndCapture(); private: //! ThumbnailerRendererRequestsBus::Handler interface overrides... @@ -57,12 +88,53 @@ namespace AZ void OnSystemTick() override; //! Render::ThumbnailFeatureProcessorProviderBus::Handler interface overrides... - const AZStd::vector& GetCustomFeatureProcessors() const override; + void GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = Constants::HalfPi; + static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; + + RPI::ScenePtr m_scene; + AZStd::string m_sceneName = "Material Thumbnail Scene"; + AZStd::string m_pipelineName = "Material Thumbnail Pipeline"; + AZStd::shared_ptr m_frameworkScene; + RPI::RenderPipelinePtr m_renderPipeline; + RPI::ViewPtr m_view; + AZStd::vector m_passHierarchy; + AZStd::unique_ptr m_entityContext; + + //! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function. + struct ThumbnailInfo + { + AzToolsFramework::Thumbnailer::SharedThumbnailKey m_key; + int m_size = 512; + }; + AZStd::queue m_thumbnailInfoQueue; + ThumbnailInfo m_currentThubnailInfo; AZStd::unordered_map> m_steps; - Step m_currentStep = Step::None; - AZStd::shared_ptr m_data; - AZStd::vector m_minimalFeatureProcessors; + Step m_currentStep = CommonThumbnailRenderer::Step::None; + + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + Data::Asset m_lightingPresetAsset; + + //! Model asset about to be rendered + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + Data::Asset m_modelAsset; + + //! Material asset about to be rendered + static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; + const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); + Data::Asset m_defaultMaterialAsset; + Data::Asset m_materialAsset; + + Entity* m_modelEntity = nullptr; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h deleted file mode 100644 index d3bb2be64a..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h +++ /dev/null @@ -1,42 +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 - * - */ - -#pragma once - -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - struct ThumbnailRendererData; - - enum class Step - { - None, - Initialize, - FindThumbnailToRender, - WaitForAssetsToLoad, - Capture, - ReleaseResources - }; - - //! An interface for ThumbnailRendererSteps to communicate with thumbnail renderer - class ThumbnailRendererContext - { - public: - virtual void SetStep(Step step) = 0; - virtual Step GetStep() const = 0; - virtual AZStd::shared_ptr GetData() const = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h deleted file mode 100644 index c471cf90d7..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h +++ /dev/null @@ -1,70 +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 - * - */ - -#pragma once - -#include "Atom/RPI.Reflect/Model/ModelAsset.h" - -#include -#include -#include -#include -#include -#include - -namespace AzFramework -{ - class Scene; -} - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! ThumbnailRendererData encapsulates all data used by thumbnail renderer and caches assets - struct ThumbnailRendererData final - { - static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - - RPI::ScenePtr m_scene; - AZStd::string m_sceneName = "Material Thumbnail Scene"; - AZStd::string m_pipelineName = "Material Thumbnail Pipeline"; - AZStd::shared_ptr m_frameworkScene; - RPI::RenderPipelinePtr m_renderPipeline; - AZStd::unique_ptr m_entityContext; - AZStd::vector m_passHierarchy; - - RPI::ViewPtr m_view = nullptr; - Entity* m_modelEntity = nullptr; - - int m_thumbnailSize = 512; - - //! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function. - AZStd::queue m_thumbnailQueue; - //! Current thumbnail key being rendered. - AzToolsFramework::Thumbnailer::SharedThumbnailKey m_thumbnailKeyRendered; - - Data::Asset m_lightingPresetAsset; - - Data::Asset m_defaultModelAsset; - //! Model asset about to be rendered - Data::Asset m_modelAsset; - - Data::Asset m_defaultMaterialAsset; - //! Material asset about to be rendered - Data::Asset m_materialAsset; - - AZStd::unordered_set m_assetsToLoad; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp index f728d56bbc..0686ffb971 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp @@ -6,19 +6,8 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include namespace AZ { @@ -26,104 +15,42 @@ namespace AZ { namespace Thumbnails { - CaptureStep::CaptureStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) + CaptureStep::CaptureStep(CommonThumbnailRenderer* renderer) + : ThumbnailRendererStep(renderer) { } void CaptureStep::Start() { - if (!m_context->GetData()->m_materialAsset || - !m_context->GetData()->m_modelAsset) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - return; - } - Render::MaterialComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, - m_context->GetData()->m_materialAsset.GetId()); - Render::MeshComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MeshComponentRequestBus::Events::SetModelAsset, - m_context->GetData()->m_modelAsset); - RepositionCamera(); - m_readyToCapture = true; m_ticksToCapture = 1; + m_renderer->UpdateScene(); TickBus::Handler::BusConnect(); } void CaptureStep::Stop() { - m_context->GetData()->m_renderPipeline->RemoveFromRenderTick(); + m_renderer->EndCapture(); TickBus::Handler::BusDisconnect(); Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); } - void CaptureStep::RepositionCamera() const - { - // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it - const Aabb& aabb = m_context->GetData()->m_modelAsset->GetAabb(); - Vector3 modelCenter; - float radius; - aabb.GetAsSphere(modelCenter, radius); - - float distance = StartingDistanceMultiplier * - GetMax(GetMax(aabb.GetExtents().GetX(), aabb.GetExtents().GetY()), aabb.GetExtents().GetZ()) + - DepthNear; - const Quaternion cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), StartingRotationAngle); - Vector3 cameraPosition(modelCenter.GetX(), modelCenter.GetY() - distance, modelCenter.GetZ()); - cameraPosition = cameraRotation.TransformVector(cameraPosition); - auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); - m_context->GetData()->m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); - } - void CaptureStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { - if (m_readyToCapture && m_ticksToCapture-- <= 0) + if (m_ticksToCapture-- <= 0) { - m_context->GetData()->m_renderPipeline->AddToRenderTickOnce(); - - RPI::AttachmentReadback::CallbackFunction readbackCallback = [&](const RPI::AttachmentReadback::ReadbackResult& result) - { - if (!result.m_dataBuffer) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - return; - } - uchar* data = result.m_dataBuffer.get()->data(); - QImage image( - data, result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888); - QPixmap pixmap; - pixmap.convertFromImage(image); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, - pixmap); - }; - - Render::FrameCaptureNotificationBus::Handler::BusConnect(); - bool startedCapture = false; - Render::FrameCaptureRequestBus::BroadcastResult( - startedCapture, - &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, - m_context->GetData()->m_passHierarchy, AZStd::string("Output"), readbackCallback, RPI::PassAttachmentReadbackOption::Output); // Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick. - if (startedCapture) + if (m_renderer->StartCapture()) { - m_readyToCapture = false; + Render::FrameCaptureNotificationBus::Handler::BusConnect(); + TickBus::Handler::BusDisconnect(); } } } - void CaptureStep::OnCaptureFinished([[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) + void CaptureStep::OnCaptureFinished( + [[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) { - m_context->SetStep(Step::FindThumbnailToRender); + m_renderer->CompleteThumbnail(); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h index e93828e3b8..46d642ce53 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h @@ -25,27 +25,18 @@ namespace AZ , private Render::FrameCaptureNotificationBus::Handler { public: - CaptureStep(ThumbnailRendererContext* context); + CaptureStep(CommonThumbnailRenderer* renderer); void Start() override; void Stop() override; private: - //! Places the camera so that the entire model is visible - void RepositionCamera() const; - //! AZ::TickBus::Handler interface overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; //! Render::FrameCaptureNotificationBus::Handler overrides... void OnCaptureFinished(Render::FrameCaptureResult result, const AZStd::string& info) override; - - static constexpr float DepthNear = 0.01f; - static constexpr float StartingDistanceMultiplier = 1.75f; - static constexpr float StartingRotationAngle = Constants::QuarterPi / 2.0f; - //! This flag is needed to wait one frame after each frame capture to reset FrameCaptureSystemComponent - bool m_readyToCapture = true; //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials int m_ticksToCapture = 0; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp index 826ec4ae0d..d9c978605a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp @@ -6,11 +6,7 @@ * */ -#include -#include -#include -#include -#include +#include #include namespace AZ @@ -19,8 +15,8 @@ namespace AZ { namespace Thumbnails { - FindThumbnailToRenderStep::FindThumbnailToRenderStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) + FindThumbnailToRenderStep::FindThumbnailToRenderStep(CommonThumbnailRenderer* renderer) + : ThumbnailRendererStep(renderer) { } @@ -36,43 +32,7 @@ namespace AZ void FindThumbnailToRenderStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { - PickNextThumbnail(); - } - - void FindThumbnailToRenderStep::PickNextThumbnail() - { - if (!m_context->GetData()->m_thumbnailQueue.empty()) - { - // pop the next thumbnailkey to be rendered from the queue - m_context->GetData()->m_thumbnailKeyRendered = m_context->GetData()->m_thumbnailQueue.front(); - m_context->GetData()->m_thumbnailQueue.pop(); - - // Find whether thumbnailkey contains a material asset or set a default material - m_context->GetData()->m_materialAsset = m_context->GetData()->m_defaultMaterialAsset; - Data::AssetId materialAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::MaterialAsset::RTTI_Type()); - if (materialAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(materialAssetId).second) - { - m_context->GetData()->m_materialAsset.Create(materialAssetId); - m_context->GetData()->m_materialAsset.QueueLoad(); - } - } - - // Find whether thumbnailkey contains a model asset or set a default model - m_context->GetData()->m_modelAsset = m_context->GetData()->m_defaultModelAsset; - Data::AssetId modelAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::ModelAsset::RTTI_Type()); - if (modelAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(modelAssetId).second) - { - m_context->GetData()->m_modelAsset.Create(modelAssetId); - m_context->GetData()->m_modelAsset.QueueLoad(); - } - } - - m_context->SetStep(Step::WaitForAssetsToLoad); - } + m_renderer->SelectThumbnail(); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h index e63bc5dce5..6ba9b974a1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h @@ -22,7 +22,7 @@ namespace AZ , private TickBus::Handler { public: - FindThumbnailToRenderStep(ThumbnailRendererContext* context); + FindThumbnailToRenderStep(CommonThumbnailRenderer* renderer); void Start() override; void Stop() override; @@ -31,8 +31,6 @@ namespace AZ //! AZ::TickBus::Handler interface overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - void PickNextThumbnail(); }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp deleted file mode 100644 index 6f74627bee..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - InitializeStep::InitializeStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void InitializeStep::Start() - { - auto data = m_context->GetData(); - - data->m_entityContext = AZStd::make_unique(); - data->m_entityContext->InitContext(); - - // Create and register a scene with all required feature processors - RPI::SceneDescriptor sceneDesc; - - AZ::EBusAggregateResults> results; - ThumbnailFeatureProcessorProviderBus::BroadcastResult(results, &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors); - - AZStd::set featureProcessorNames; - for (auto& resultCollection : results.values) - { - for (auto& featureProcessorName : resultCollection) - { - if (featureProcessorNames.emplace(featureProcessorName).second) - { - sceneDesc.m_featureProcessorNames.push_back(featureProcessorName); - } - } - } - - data->m_scene = RPI::Scene::CreateScene(sceneDesc); - - // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene - auto* sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation."); - Outcome, AZStd::string> createSceneOutcome = - sceneSystem->CreateScene(data->m_sceneName); - AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); // This should never happen unless scene creation has changed. - data->m_frameworkScene = createSceneOutcome.TakeValue(); - data->m_frameworkScene->SetSubsystem(data->m_scene); - - data->m_frameworkScene->SetSubsystem(data->m_entityContext.get()); - // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene - RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = data->m_pipelineName; - pipelineDesc.m_rootPassTemplate = "ThumbnailPipelineRenderToTexture"; - // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue - // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost - pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; - data->m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - data->m_scene->AddRenderPipeline(data->m_renderPipeline); - data->m_scene->Activate(); - RPI::RPISystemInterface::Get()->RegisterScene(data->m_scene); - data->m_passHierarchy.push_back(data->m_pipelineName); - data->m_passHierarchy.push_back("CopyToSwapChain"); - - // Connect camera to pipeline's default view after camera entity activated - Name viewName = Name("MainCamera"); - data->m_view = RPI::View::CreateView(viewName, RPI::View::UsageCamera); - - Matrix4x4 viewToClipMatrix; - MakePerspectiveFovMatrixRH(viewToClipMatrix, - Constants::QuarterPi, - AspectRatio, - NearDist, - FarDist, true); - data->m_view->SetViewToClipMatrix(viewToClipMatrix); - - data->m_renderPipeline->SetDefaultView(data->m_view); - - // Create lighting preset - data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(ThumbnailRendererData::LightingPresetPath); - if (data->m_lightingPresetAsset.IsReady()) - { - auto preset = data->m_lightingPresetAsset->GetDataAs(); - if (preset) - { - auto iblFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto postProcessFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId())->GetOrCreateExposureControlSettingsInterface(); - auto directionalLightFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto skyboxFeatureProcessor = data->m_scene->GetFeatureProcessor(); - skyboxFeatureProcessor->Enable(true); - skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); - - Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = Constants::HalfPi; - cameraConfig.m_nearClipDistance = NearDist; - cameraConfig.m_farClipDistance = FarDist; - cameraConfig.m_frustumWidth = 100.0f; - cameraConfig.m_frustumHeight = 100.0f; - - AZStd::vector lightHandles; - - preset->ApplyLightingPreset( - iblFeatureProcessor, - skyboxFeatureProcessor, - exposureControlSettingInterface, - directionalLightFeatureProcessor, - cameraConfig, - lightHandles); - } - } - - // Create preview model - AzFramework::EntityContextRequestBus::EventResult(data->m_modelEntity, data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); - data->m_modelEntity->CreateComponent(Render::MeshComponentTypeId); - data->m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); - data->m_modelEntity->CreateComponent(azrtti_typeid()); - data->m_modelEntity->Init(); - data->m_modelEntity->Activate(); - - // preload default model - Data::AssetId defaultModelAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultModelAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultModelPath, - RPI::ModelAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultModelAssetId.IsValid(), "Default model asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultModelPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultModelAssetId).second) - { - data->m_defaultModelAsset.Create(defaultModelAssetId); - data->m_defaultModelAsset.QueueLoad(); - } - - // preload default material - Data::AssetId defaultMaterialAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultMaterialAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultMaterialPath, - RPI::MaterialAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultMaterialAssetId.IsValid(), "Default material asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultMaterialPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultMaterialAssetId).second) - { - data->m_defaultMaterialAsset.Create(defaultMaterialAssetId); - data->m_defaultMaterialAsset.QueueLoad(); - } - - m_context->SetStep(Step::FindThumbnailToRender); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h deleted file mode 100644 index cdac492e80..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h +++ /dev/null @@ -1,37 +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 - * - */ - -#pragma once - -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! InitializeStep sets up RPI system and scene and prepares it for rendering thumbnail entities - //! This step is only called once when CommonThumbnailRenderer begins rendering its first thumbnail - class InitializeStep - : public ThumbnailRendererStep - { - public: - InitializeStep(ThumbnailRendererContext* context); - - void Start() override; - - private: - static constexpr float AspectRatio = 1.0f; - static constexpr float NearDist = 0.1f; - static constexpr float FarDist = 100.0f; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp deleted file mode 100644 index a14f48e408..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - ReleaseResourcesStep::ReleaseResourcesStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void ReleaseResourcesStep::Start() - { - auto data = m_context->GetData(); - - data->m_defaultMaterialAsset.Release(); - data->m_defaultModelAsset.Release(); - data->m_materialAsset.Release(); - data->m_modelAsset.Release(); - data->m_lightingPresetAsset.Release(); - - if (data->m_modelEntity) - { - AzFramework::EntityContextRequestBus::Event(data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::DestroyEntity, data->m_modelEntity); - data->m_modelEntity = nullptr; - } - - data->m_scene->Deactivate(); - data->m_scene->RemoveRenderPipeline(data->m_renderPipeline->GetId()); - RPI::RPISystemInterface::Get()->UnregisterScene(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_entityContext.get()); - data->m_scene = nullptr; - data->m_frameworkScene = nullptr; - data->m_renderPipeline = nullptr; - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h deleted file mode 100644 index 4858b90b96..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h +++ /dev/null @@ -1,30 +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 - * - */ - -#pragma once - -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ReleaseResourcesStep - : public ThumbnailRendererStep - { - public: - ReleaseResourcesStep(ThumbnailRendererContext* context); - - void Start() override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h index cc10f91525..0a629e7e25 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h @@ -14,13 +14,13 @@ namespace AZ { namespace Thumbnails { - class ThumbnailRendererContext; + class CommonThumbnailRenderer; //! ThumbnailRendererStep decouples CommonThumbnailRenderer logic into easy-to-understand and debug pieces class ThumbnailRendererStep { public: - explicit ThumbnailRendererStep(ThumbnailRendererContext* context) : m_context(context) {} + explicit ThumbnailRendererStep(CommonThumbnailRenderer* renderer) : m_renderer(renderer) {} virtual ~ThumbnailRendererStep() = default; //! Start is called when step begins execution @@ -29,7 +29,7 @@ namespace AZ virtual void Stop() {} protected: - ThumbnailRendererContext* m_context; + CommonThumbnailRenderer* m_renderer; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp index 4f32bc4b68..53a5b596d4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp @@ -7,9 +7,7 @@ */ #include "Thumbnails/ThumbnailerBus.h" - -#include -#include +#include #include #include @@ -19,81 +17,33 @@ namespace AZ { namespace Thumbnails { - WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) + WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(CommonThumbnailRenderer* renderer) + : ThumbnailRendererStep(renderer) { } void WaitForAssetsToLoadStep::Start() { - LoadNextAsset(); + m_renderer->LoadAssets(); + m_timeRemainingS = TimeOutS; + TickBus::Handler::BusConnect(); } void WaitForAssetsToLoadStep::Stop() { - Data::AssetBus::Handler::BusDisconnect(); TickBus::Handler::BusDisconnect(); - m_context->GetData()->m_assetsToLoad.clear(); } - void WaitForAssetsToLoadStep::LoadNextAsset() + void WaitForAssetsToLoadStep::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - if (m_context->GetData()->m_assetsToLoad.empty()) + m_timeRemainingS -= deltaTime; + if (m_timeRemainingS > 0.0f) { - // When all assets are loaded, render the thumbnail itself - m_context->SetStep(Step::Capture); + m_renderer->UpdateLoadAssets(); } else { - // Pick the the next asset and wait until its ready - const auto assetIdIt = m_context->GetData()->m_assetsToLoad.begin(); - m_context->GetData()->m_assetsToLoad.erase(assetIdIt); - m_assetId = *assetIdIt; - Data::AssetBus::Handler::BusConnect(m_assetId); - // If asset is already loaded, then AssetEvents will call OnAssetReady instantly and we don't need to wait this time - if (Data::AssetBus::Handler::BusIsConnected()) - { - TickBus::Handler::BusConnect(); - m_timeRemainingS = TimeOutS; - } - } - } - - void WaitForAssetsToLoadStep::OnAssetReady([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - LoadNextAsset(); - } - - void WaitForAssetsToLoadStep::OnAssetError([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - - void WaitForAssetsToLoadStep::OnAssetCanceled([[maybe_unused]] Data::AssetId assetId) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - - void WaitForAssetsToLoadStep::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) - { - m_timeRemainingS -= deltaTime; - if (m_timeRemainingS < 0) - { - auto assetIdStr = m_assetId.ToString(); - AZ_Warning("CommonThumbnailRenderer", false, "Timed out waiting for asset %s to load.", assetIdStr.c_str()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); + m_renderer->CancelLoadAssets(); } } } // namespace Thumbnails diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h index 921d1511ca..0202ef1045 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h @@ -8,7 +8,6 @@ #pragma once -#include #include namespace AZ @@ -20,29 +19,20 @@ namespace AZ //! WaitForAssetsToLoadStep pauses further rendering until all assets used for rendering a thumbnail have been loaded class WaitForAssetsToLoadStep : public ThumbnailRendererStep - , private Data::AssetBus::Handler , private TickBus::Handler { public: - WaitForAssetsToLoadStep(ThumbnailRendererContext* context); + WaitForAssetsToLoadStep(CommonThumbnailRenderer* renderer); void Start() override; void Stop() override; private: - void LoadNextAsset(); - - // AZ::Data::AssetBus::Handler - void OnAssetReady(Data::Asset asset) override; - void OnAssetError(Data::Asset asset) override; - void OnAssetCanceled(Data::AssetId assetId) override; - //! AZ::TickBus::Handler interface overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - static constexpr float TimeOutS = 3.0f; - Data::AssetId m_assetId; - float m_timeRemainingS = 0; + static constexpr float TimeOutS = 5.0f; + float m_timeRemainingS = TimeOutS; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 174eb30b31..ffc3f257b0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -104,19 +104,13 @@ set(FILES Source/Thumbnails/Preview/CommonPreviewerFactory.h Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp Source/Thumbnails/Rendering/CommonThumbnailRenderer.h - Source/Thumbnails/Rendering/ThumbnailRendererData.h - Source/Thumbnails/Rendering/ThumbnailRendererContext.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp From dd5272c2ae5365a5b69db9280756df19ca0a65ed Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 7 Oct 2021 12:21:48 -0500 Subject: [PATCH 095/293] Renaming/moving preview renderer files Signed-off-by: Guthrie Adams --- .../{CommonThumbnailRenderer.cpp => CommonPreviewRenderer.cpp} | 0 .../{CommonThumbnailRenderer.h => CommonPreviewRenderer.h} | 0 .../CaptureStep.cpp => CommonPreviewRendererCaptureState.cpp} | 0 .../CaptureStep.h => CommonPreviewRendererCaptureState.h} | 0 ...umbnailToRenderStep.cpp => CommonPreviewRendererIdleState.cpp} | 0 ...ndThumbnailToRenderStep.h => CommonPreviewRendererIdleState.h} | 0 ...ForAssetsToLoadStep.cpp => CommonPreviewRendererLoadState.cpp} | 0 ...WaitForAssetsToLoadStep.h => CommonPreviewRendererLoadState.h} | 0 .../ThumbnailRendererStep.h => CommonPreviewRendererState.h} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{CommonThumbnailRenderer.cpp => CommonPreviewRenderer.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{CommonThumbnailRenderer.h => CommonPreviewRenderer.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{ThumbnailRendererSteps/CaptureStep.cpp => CommonPreviewRendererCaptureState.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{ThumbnailRendererSteps/CaptureStep.h => CommonPreviewRendererCaptureState.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp => CommonPreviewRendererIdleState.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{ThumbnailRendererSteps/FindThumbnailToRenderStep.h => CommonPreviewRendererIdleState.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp => CommonPreviewRendererLoadState.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{ThumbnailRendererSteps/WaitForAssetsToLoadStep.h => CommonPreviewRendererLoadState.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/{ThumbnailRendererSteps/ThumbnailRendererStep.h => CommonPreviewRendererState.h} (100%) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h From cdca77acd1f5d5f9748d1ac0fc9fce2874c08cfc Mon Sep 17 00:00:00 2001 From: smurly Date: Thu, 7 Oct 2021 10:56:10 -0700 Subject: [PATCH 096/293] Reflection Probe component test for parallel execution (#4532) Signed-off-by: Scott Murray --- .../Atom/TestSuite_Main_Optimized.py | 3 + ...omEditorComponents_ReflectionProbeAdded.py | 194 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index 47b2204d56..f5ac411a01 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -42,5 +42,8 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module + class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py new file mode 100644 index 0000000000..9b13eb2c7e --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py @@ -0,0 +1,194 @@ +""" +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: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + reflection_probe_creation = ( + "Reflection Probe Entity successfully created", + "Reflection Probe Entity failed to be created") + reflection_probe_component = ( + "Entity has a Reflection Probe component", + "Entity failed to find Reflection Probe component") + reflection_probe_disabled = ( + "Reflection Probe component disabled", + "Reflection Probe component was not disabled.") + reflection_map_generated = ( + "Reflection Probe cubemap generated", + "Reflection Probe cubemap not generated") + box_shape_component = ( + "Entity has a Box Shape component", + "Entity did not have a Box Shape component") + reflection_probe_enabled = ( + "Reflection Probe component enabled", + "Reflection Probe component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_ReflectionProbe_AddedToEntity(): + """ + Summary: + Tests the Reflection Probe component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a Reflection Probe entity with no components. + 2) Add a Reflection Probe component to Reflection Probe entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Verify Reflection Probe component not enabled. + 6) Add Shape component since it is required by the Reflection Probe component. + 7) Verify Reflection Probe component is enabled. + 8) Enter/Exit game mode. + 9) Test IsHidden. + 10) Test IsVisible. + 11) Verify cubemap generation + 12) Delete Reflection Probe entity. + 13) UNDO deletion. + 14) REDO deletion. + 15) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.render as render + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + helper.init_idle() + helper.open_level("", "Base") + + # Test steps begin. + # 1. Create a Reflection Probe entity with no components. + reflection_probe_name = "Reflection Probe" + reflection_probe_entity = EditorEntity.create_editor_entity_at( + math.Vector3(512.0, 512.0, 34.0), reflection_probe_name) + Report.critical_result(Tests.reflection_probe_creation, reflection_probe_entity.exists()) + + # 2. Add a Reflection Probe component to Reflection Probe entity. + reflection_probe_component = reflection_probe_entity.add_component(reflection_probe_name) + Report.critical_result( + Tests.reflection_probe_component, + reflection_probe_entity.has_component(reflection_probe_name)) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not reflection_probe_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, reflection_probe_entity.exists()) + + # 5. Verify Reflection Probe component not enabled. + Report.result(Tests.reflection_probe_disabled, not reflection_probe_component.is_enabled()) + + # 6. Add Box Shape component since it is required by the Reflection Probe component. + box_shape = "Box Shape" + reflection_probe_entity.add_component(box_shape) + Report.result(Tests.box_shape_component, reflection_probe_entity.has_component(box_shape)) + + # 7. Verify Reflection Probe component is enabled. + Report.result(Tests.reflection_probe_enabled, reflection_probe_component.is_enabled()) + + # 8. Enter/Exit game mode. + helper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + helper.exit_game_mode(Tests.exit_game_mode) + + # 9. Test IsHidden. + reflection_probe_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, reflection_probe_entity.is_hidden() is True) + + # 10. Test IsVisible. + reflection_probe_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, reflection_probe_entity.is_visible() is True) + + # 11. Verify cubemap generation + render.EditorReflectionProbeBus(azlmbr.bus.Event, "BakeReflectionProbe", reflection_probe_entity.id) + Report.result( + Tests.reflection_map_generated, + helper.wait_for_condition( + lambda: reflection_probe_component.get_component_property_value("Cubemap|Baked Cubemap Path") != "", + 20.0)) + + # 12. Delete Reflection Probe entity. + reflection_probe_entity.delete() + Report.result(Tests.entity_deleted, not reflection_probe_entity.exists()) + + # 13. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, reflection_probe_entity.exists()) + + # 14. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not reflection_probe_entity.exists()) + + # 15. Look for errors or asserts. + helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_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(AtomEditorComponents_ReflectionProbe_AddedToEntity) From 5f83485a1d51100dd5662a821a5485b38f5ffd4a Mon Sep 17 00:00:00 2001 From: jiaweig <51759646+jiaweig-amzn@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:00:28 -0700 Subject: [PATCH 097/293] PALify driver info. No warnings if info is empty. (#4533) Signed-off-by: jiaweig --- .../RHI.Reflect/PhysicalDeviceDescriptor.cpp | 7 ++++++ .../Android/PhysicalDeviceDriverInfo.setreg | 23 +++++++++++++++++++ .../Linux/PhysicalDeviceDriverInfo.setreg | 23 +++++++++++++++++++ .../Mac/PhysicalDeviceDriverInfo.setreg | 23 +++++++++++++++++++ .../Windows}/PhysicalDeviceDriverInfo.setreg | 0 .../iOS/PhysicalDeviceDriverInfo.setreg | 23 +++++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 Gems/Atom/RHI/Registry/Platform/Android/PhysicalDeviceDriverInfo.setreg create mode 100644 Gems/Atom/RHI/Registry/Platform/Linux/PhysicalDeviceDriverInfo.setreg create mode 100644 Gems/Atom/RHI/Registry/Platform/Mac/PhysicalDeviceDriverInfo.setreg rename Gems/Atom/RHI/Registry/{ => Platform/Windows}/PhysicalDeviceDriverInfo.setreg (100%) create mode 100644 Gems/Atom/RHI/Registry/Platform/iOS/PhysicalDeviceDriverInfo.setreg diff --git a/Gems/Atom/RHI/Code/Source/RHI.Reflect/PhysicalDeviceDescriptor.cpp b/Gems/Atom/RHI/Code/Source/RHI.Reflect/PhysicalDeviceDescriptor.cpp index 17819ab1f5..9da4f583ac 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Reflect/PhysicalDeviceDescriptor.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Reflect/PhysicalDeviceDescriptor.cpp @@ -86,6 +86,13 @@ namespace AZ PhysicalDeviceDriverValidator::ValidationResult PhysicalDeviceDriverValidator::ValidateDriverVersion(const PhysicalDeviceDescriptor& descriptor) const { + // [GFX TODO] Add driver info for other platforms besides Windows. Currently, avoid spamming warnings. + // ATOM-14967 [RHI][Metal] - Address driver version validator for Mac + if (m_driverInfo.size() == 0) + { + return ValidationResult::MissingInfo; + } + auto iter = m_driverInfo.find(descriptor.m_vendorId); if (iter == m_driverInfo.end()) diff --git a/Gems/Atom/RHI/Registry/Platform/Android/PhysicalDeviceDriverInfo.setreg b/Gems/Atom/RHI/Registry/Platform/Android/PhysicalDeviceDriverInfo.setreg new file mode 100644 index 0000000000..a0df86c923 --- /dev/null +++ b/Gems/Atom/RHI/Registry/Platform/Android/PhysicalDeviceDriverInfo.setreg @@ -0,0 +1,23 @@ +// +// 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 +// +// +// + +{ + "O3DE": + { + "Atom": + { + "RHI": + { + "PhysicalDeviceDriverInfo": + { + } + } + } + } +} diff --git a/Gems/Atom/RHI/Registry/Platform/Linux/PhysicalDeviceDriverInfo.setreg b/Gems/Atom/RHI/Registry/Platform/Linux/PhysicalDeviceDriverInfo.setreg new file mode 100644 index 0000000000..a0df86c923 --- /dev/null +++ b/Gems/Atom/RHI/Registry/Platform/Linux/PhysicalDeviceDriverInfo.setreg @@ -0,0 +1,23 @@ +// +// 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 +// +// +// + +{ + "O3DE": + { + "Atom": + { + "RHI": + { + "PhysicalDeviceDriverInfo": + { + } + } + } + } +} diff --git a/Gems/Atom/RHI/Registry/Platform/Mac/PhysicalDeviceDriverInfo.setreg b/Gems/Atom/RHI/Registry/Platform/Mac/PhysicalDeviceDriverInfo.setreg new file mode 100644 index 0000000000..a0df86c923 --- /dev/null +++ b/Gems/Atom/RHI/Registry/Platform/Mac/PhysicalDeviceDriverInfo.setreg @@ -0,0 +1,23 @@ +// +// 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 +// +// +// + +{ + "O3DE": + { + "Atom": + { + "RHI": + { + "PhysicalDeviceDriverInfo": + { + } + } + } + } +} diff --git a/Gems/Atom/RHI/Registry/PhysicalDeviceDriverInfo.setreg b/Gems/Atom/RHI/Registry/Platform/Windows/PhysicalDeviceDriverInfo.setreg similarity index 100% rename from Gems/Atom/RHI/Registry/PhysicalDeviceDriverInfo.setreg rename to Gems/Atom/RHI/Registry/Platform/Windows/PhysicalDeviceDriverInfo.setreg diff --git a/Gems/Atom/RHI/Registry/Platform/iOS/PhysicalDeviceDriverInfo.setreg b/Gems/Atom/RHI/Registry/Platform/iOS/PhysicalDeviceDriverInfo.setreg new file mode 100644 index 0000000000..a0df86c923 --- /dev/null +++ b/Gems/Atom/RHI/Registry/Platform/iOS/PhysicalDeviceDriverInfo.setreg @@ -0,0 +1,23 @@ +// +// 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 +// +// +// + +{ + "O3DE": + { + "Atom": + { + "RHI": + { + "PhysicalDeviceDriverInfo": + { + } + } + } + } +} From 58194b70c0e72675cd78cda101284af8ddf52c68 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 7 Oct 2021 13:27:14 -0500 Subject: [PATCH 098/293] Updated code to compile and reflect changes after renaming files Signed-off-by: Guthrie Adams --- ...=> PreviewerFeatureProcessorProviderBus.h} | 10 +- .../EditorCommonFeaturesSystemComponent.cpp | 2 +- .../EditorCommonFeaturesSystemComponent.h | 6 +- .../Code/Source/Material/MaterialThumbnail.h | 2 +- .../Rendering/CommonPreviewRenderer.cpp | 92 +++++++++---------- .../Rendering/CommonPreviewRenderer.h | 34 +++---- .../CommonPreviewRendererCaptureState.cpp | 16 ++-- .../CommonPreviewRendererCaptureState.h | 10 +- .../CommonPreviewRendererIdleState.cpp | 14 +-- .../CommonPreviewRendererIdleState.h | 10 +- .../CommonPreviewRendererLoadState.cpp | 16 ++-- .../CommonPreviewRendererLoadState.h | 11 ++- .../Rendering/CommonPreviewRendererState.h | 16 ++-- ...egration_commonfeatures_editor_files.cmake | 20 ++-- 14 files changed, 129 insertions(+), 130 deletions(-) rename Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/{ThumbnailFeatureProcessorProviderBus.h => PreviewerFeatureProcessorProviderBus.h} (67%) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h similarity index 67% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h index a4d76809ba..ef0e586348 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h @@ -16,18 +16,18 @@ namespace AZ { namespace Thumbnails { - //! ThumbnailFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation + //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation //! Duplicates will be ignored - //! You can check minimal feature processors that are already registered in CommonThumbnailRenderer.cpp - class ThumbnailFeatureProcessorProviderRequests + //! You can check minimal feature processors that are already registered in CommonPreviewRenderer.cpp + class PreviewerFeatureProcessorProviderRequests : public AZ::EBusTraits { public: //! Get a list of custom feature processors to register with thumbnail renderer - virtual void GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; + virtual void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; }; - using ThumbnailFeatureProcessorProviderBus = AZ::EBus; + using PreviewerFeatureProcessorProviderBus = AZ::EBus; } // namespace Thumbnails } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 8be947ae26..0355351654 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -194,7 +194,7 @@ namespace AZ void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) { AZ::TickBus::QueueFunction([this](){ - m_renderer = AZStd::make_unique(); + m_renderer = AZStd::make_unique(); m_previewerFactory = AZStd::make_unique(); }); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index d26886c4ae..90dc5fcf2e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -11,10 +11,10 @@ #include #include #include -#include #include -#include +#include #include +#include namespace AZ { @@ -73,7 +73,7 @@ namespace AZ AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" }; float m_envProbeHeight{ 200.0f }; - AZStd::unique_ptr m_renderer; + AZStd::unique_ptr m_renderer; AZStd::unique_ptr m_previewerFactory; }; } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h index dba922a1b2..d323a04a1f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #endif namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp index d12d9df892..b24de64b42 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp @@ -37,10 +37,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include namespace AZ @@ -49,13 +49,13 @@ namespace AZ { namespace Thumbnails { - CommonThumbnailRenderer::CommonThumbnailRenderer() + CommonPreviewRenderer::CommonPreviewRenderer() { - // CommonThumbnailRenderer supports both models and materials, but we connect on materialAssetType + // CommonPreviewRenderer supports both models and materials, but we connect on materialAssetType // since MaterialOrModelThumbnail dispatches event on materialAssetType address too AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); - ThumbnailFeatureProcessorProviderBus::Handler::BusConnect(); + PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); SystemTickBus::Handler::BusConnect(); m_entityContext = AZStd::make_unique(); @@ -63,8 +63,8 @@ namespace AZ // Create and register a scene with all required feature processors AZStd::unordered_set featureProcessors; - ThumbnailFeatureProcessorProviderBus::Broadcast( - &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors, featureProcessors); + PreviewerFeatureProcessorProviderBus::Broadcast( + &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); RPI::SceneDescriptor sceneDesc; sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); @@ -118,19 +118,19 @@ namespace AZ m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); m_defaultModelAsset.Create(DefaultModelAssetId, true); - m_steps[CommonThumbnailRenderer::Step::FindThumbnailToRender] = AZStd::make_shared(this); - m_steps[CommonThumbnailRenderer::Step::WaitForAssetsToLoad] = AZStd::make_shared(this); - m_steps[CommonThumbnailRenderer::Step::Capture] = AZStd::make_shared(this); - SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + m_steps[CommonPreviewRenderer::State::IdleState] = AZStd::make_shared(this); + m_steps[CommonPreviewRenderer::State::LoadState] = AZStd::make_shared(this); + m_steps[CommonPreviewRenderer::State::CaptureState] = AZStd::make_shared(this); + SetState(CommonPreviewRenderer::State::IdleState); } - CommonThumbnailRenderer::~CommonThumbnailRenderer() + CommonPreviewRenderer::~CommonPreviewRenderer() { AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); SystemTickBus::Handler::BusDisconnect(); - ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect(); + PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); - SetStep(CommonThumbnailRenderer::Step::None); + SetState(CommonPreviewRenderer::State::None); if (m_modelEntity) { @@ -146,29 +146,29 @@ namespace AZ m_frameworkScene->UnsetSubsystem(m_entityContext.get()); } - void CommonThumbnailRenderer::SetStep(Step step) + void CommonPreviewRenderer::SetState(State state) { - auto stepItr = m_steps.find(m_currentStep); + auto stepItr = m_steps.find(m_currentState); if (stepItr != m_steps.end()) { stepItr->second->Stop(); } - m_currentStep = step; + m_currentState = state; - stepItr = m_steps.find(m_currentStep); + stepItr = m_steps.find(m_currentState); if (stepItr != m_steps.end()) { stepItr->second->Start(); } } - CommonThumbnailRenderer::Step CommonThumbnailRenderer::GetStep() const + CommonPreviewRenderer::State CommonPreviewRenderer::GetState() const { - return m_currentStep; + return m_currentState; } - void CommonThumbnailRenderer::SelectThumbnail() + void CommonPreviewRenderer::SelectThumbnail() { if (!m_thumbnailInfoQueue.empty()) { @@ -176,23 +176,23 @@ namespace AZ m_currentThubnailInfo = m_thumbnailInfoQueue.front(); m_thumbnailInfoQueue.pop(); - SetStep(CommonThumbnailRenderer::Step::WaitForAssetsToLoad); + SetState(CommonPreviewRenderer::State::LoadState); } } - void CommonThumbnailRenderer::CancelThumbnail() + void CommonPreviewRenderer::CancelThumbnail() { AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( m_currentThubnailInfo.m_key, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + SetState(CommonPreviewRenderer::State::IdleState); } - void CommonThumbnailRenderer::CompleteThumbnail() + void CommonPreviewRenderer::CompleteThumbnail() { - SetStep(CommonThumbnailRenderer::Step::FindThumbnailToRender); + SetState(CommonPreviewRenderer::State::IdleState); } - void CommonThumbnailRenderer::LoadAssets() + void CommonPreviewRenderer::LoadAssets() { // Determine if thumbnailkey contains a material asset or set a default material const Data::AssetId materialAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::MaterialAsset::RTTI_Type()); @@ -207,11 +207,11 @@ namespace AZ m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, true); } - void CommonThumbnailRenderer::UpdateLoadAssets() + void CommonPreviewRenderer::UpdateLoadAssets() { if (m_materialAsset.IsReady() && m_modelAsset.IsReady() && m_lightingPresetAsset.IsReady()) { - SetStep(CommonThumbnailRenderer::Step::Capture); + SetState(CommonPreviewRenderer::State::CaptureState); return; } @@ -222,28 +222,28 @@ namespace AZ } } - void CommonThumbnailRenderer::CancelLoadAssets() + void CommonPreviewRenderer::CancelLoadAssets() { AZ_Warning( - "CommonThumbnailRenderer", m_materialAsset.IsReady(), "Asset failed to load in time: %s", + "CommonPreviewRenderer", m_materialAsset.IsReady(), "Asset failed to load in time: %s", m_materialAsset.ToString().c_str()); AZ_Warning( - "CommonThumbnailRenderer", m_modelAsset.IsReady(), "Asset failed to load in time: %s", + "CommonPreviewRenderer", m_modelAsset.IsReady(), "Asset failed to load in time: %s", m_modelAsset.ToString().c_str()); AZ_Warning( - "CommonThumbnailRenderer", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", + "CommonPreviewRenderer", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", m_lightingPresetAsset.ToString().c_str()); CancelThumbnail(); } - void CommonThumbnailRenderer::UpdateScene() + void CommonPreviewRenderer::UpdateScene() { UpdateModel(); UpdateLighting(); UpdateCamera(); } - void CommonThumbnailRenderer::UpdateModel() + void CommonPreviewRenderer::UpdateModel() { Render::MaterialComponentRequestBus::Event( m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, @@ -253,7 +253,7 @@ namespace AZ m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); } - void CommonThumbnailRenderer::UpdateLighting() + void CommonPreviewRenderer::UpdateLighting() { auto preset = m_lightingPresetAsset->GetDataAs(); if (preset) @@ -283,7 +283,7 @@ namespace AZ } } - void CommonThumbnailRenderer::UpdateCamera() + void CommonPreviewRenderer::UpdateCamera() { // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it Vector3 center = {}; @@ -297,7 +297,7 @@ namespace AZ m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); } - RPI::AttachmentReadback::CallbackFunction CommonThumbnailRenderer::GetCaptureCallback() + RPI::AttachmentReadback::CallbackFunction CommonPreviewRenderer::GetCaptureCallback() { return [this](const RPI::AttachmentReadback::ReadbackResult& result) { @@ -320,7 +320,7 @@ namespace AZ }; } - bool CommonThumbnailRenderer::StartCapture() + bool CommonPreviewRenderer::StartCapture() { if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) { @@ -336,22 +336,22 @@ namespace AZ return startedCapture; } - void CommonThumbnailRenderer::EndCapture() + void CommonPreviewRenderer::EndCapture() { m_renderPipeline->RemoveFromRenderTick(); } - bool CommonThumbnailRenderer::Installed() const + bool CommonPreviewRenderer::Installed() const { return true; } - void CommonThumbnailRenderer::OnSystemTick() + void CommonPreviewRenderer::OnSystemTick() { AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); } - void CommonThumbnailRenderer::GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const + void CommonPreviewRenderer::GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const { featureProcessors.insert({ "AZ::Render::TransformServiceFeatureProcessor", @@ -373,7 +373,7 @@ namespace AZ "AZ::Render::SkyBoxFeatureProcessor" }); } - void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) + void CommonPreviewRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) { m_thumbnailInfoQueue.push({ thumbnailKey, thumbnailSize }); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h index 2b1ccbd4e6..259063cfdf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -37,30 +37,30 @@ namespace AZ { namespace Thumbnails { - class ThumbnailRendererStep; + class CommonPreviewRendererState; //! Provides custom rendering of material and model thumbnails - class CommonThumbnailRenderer + class CommonPreviewRenderer : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler , public SystemTickBus::Handler - , public ThumbnailFeatureProcessorProviderBus::Handler + , public PreviewerFeatureProcessorProviderBus::Handler { public: - AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0) + AZ_CLASS_ALLOCATOR(CommonPreviewRenderer, AZ::SystemAllocator, 0) - CommonThumbnailRenderer(); - ~CommonThumbnailRenderer(); + CommonPreviewRenderer(); + ~CommonPreviewRenderer(); - enum class Step : AZ::s8 + enum class State : AZ::s8 { None, - FindThumbnailToRender, - WaitForAssetsToLoad, - Capture + IdleState, + LoadState, + CaptureState }; - void SetStep(Step step); - Step GetStep() const; + void SetState(State state); + State GetState() const; void SelectThumbnail(); void CancelThumbnail(); @@ -87,8 +87,8 @@ namespace AZ //! SystemTickBus::Handler interface overrides... void OnSystemTick() override; - //! Render::ThumbnailFeatureProcessorProviderBus::Handler interface overrides... - void GetCustomFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + //! Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... + void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; static constexpr float AspectRatio = 1.0f; static constexpr float NearDist = 0.001f; @@ -114,8 +114,8 @@ namespace AZ AZStd::queue m_thumbnailInfoQueue; ThumbnailInfo m_currentThubnailInfo; - AZStd::unordered_map> m_steps; - Step m_currentStep = CommonThumbnailRenderer::Step::None; + AZStd::unordered_map> m_steps; + State m_currentState = CommonPreviewRenderer::State::None; static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp index 0686ffb971..e77b9709ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp @@ -6,8 +6,8 @@ * */ -#include -#include +#include +#include namespace AZ { @@ -15,26 +15,26 @@ namespace AZ { namespace Thumbnails { - CaptureStep::CaptureStep(CommonThumbnailRenderer* renderer) - : ThumbnailRendererStep(renderer) + CommonPreviewRendererCaptureState::CommonPreviewRendererCaptureState(CommonPreviewRenderer* renderer) + : CommonPreviewRendererState(renderer) { } - void CaptureStep::Start() + void CommonPreviewRendererCaptureState::Start() { m_ticksToCapture = 1; m_renderer->UpdateScene(); TickBus::Handler::BusConnect(); } - void CaptureStep::Stop() + void CommonPreviewRendererCaptureState::Stop() { m_renderer->EndCapture(); TickBus::Handler::BusDisconnect(); Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); } - void CaptureStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) + void CommonPreviewRendererCaptureState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { if (m_ticksToCapture-- <= 0) { @@ -47,7 +47,7 @@ namespace AZ } } - void CaptureStep::OnCaptureFinished( + void CommonPreviewRendererCaptureState::OnCaptureFinished( [[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) { m_renderer->CompleteThumbnail(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h index 46d642ce53..c19f12d9bb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h @@ -10,7 +10,7 @@ #include #include -#include +#include namespace AZ { @@ -18,14 +18,14 @@ namespace AZ { namespace Thumbnails { - //! CaptureStep renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished - class CaptureStep - : public ThumbnailRendererStep + //! CommonPreviewRendererCaptureState renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished + class CommonPreviewRendererCaptureState + : public CommonPreviewRendererState , private TickBus::Handler , private Render::FrameCaptureNotificationBus::Handler { public: - CaptureStep(CommonThumbnailRenderer* renderer); + CommonPreviewRendererCaptureState(CommonPreviewRenderer* renderer); void Start() override; void Stop() override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp index d9c978605a..b272faef30 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp @@ -6,8 +6,8 @@ * */ -#include -#include +#include +#include namespace AZ { @@ -15,22 +15,22 @@ namespace AZ { namespace Thumbnails { - FindThumbnailToRenderStep::FindThumbnailToRenderStep(CommonThumbnailRenderer* renderer) - : ThumbnailRendererStep(renderer) + CommonPreviewRendererIdleState::CommonPreviewRendererIdleState(CommonPreviewRenderer* renderer) + : CommonPreviewRendererState(renderer) { } - void FindThumbnailToRenderStep::Start() + void CommonPreviewRendererIdleState::Start() { TickBus::Handler::BusConnect(); } - void FindThumbnailToRenderStep::Stop() + void CommonPreviewRendererIdleState::Stop() { TickBus::Handler::BusDisconnect(); } - void FindThumbnailToRenderStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) + void CommonPreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { m_renderer->SelectThumbnail(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h index 6ba9b974a1..3278149b98 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AZ { @@ -16,13 +16,13 @@ namespace AZ { namespace Thumbnails { - //! FindThumbnailToRenderStep checks whether there are any new thumbnails that need to be rendered every tick - class FindThumbnailToRenderStep - : public ThumbnailRendererStep + //! CommonPreviewRendererIdleState checks whether there are any new thumbnails that need to be rendered every tick + class CommonPreviewRendererIdleState + : public CommonPreviewRendererState , private TickBus::Handler { public: - FindThumbnailToRenderStep(CommonThumbnailRenderer* renderer); + CommonPreviewRendererIdleState(CommonPreviewRenderer* renderer); void Start() override; void Stop() override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp index 53a5b596d4..dcac673de2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp @@ -6,10 +6,8 @@ * */ -#include "Thumbnails/ThumbnailerBus.h" -#include -#include -#include +#include +#include namespace AZ { @@ -17,24 +15,24 @@ namespace AZ { namespace Thumbnails { - WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(CommonThumbnailRenderer* renderer) - : ThumbnailRendererStep(renderer) + CommonPreviewRendererLoadState::CommonPreviewRendererLoadState(CommonPreviewRenderer* renderer) + : CommonPreviewRendererState(renderer) { } - void WaitForAssetsToLoadStep::Start() + void CommonPreviewRendererLoadState::Start() { m_renderer->LoadAssets(); m_timeRemainingS = TimeOutS; TickBus::Handler::BusConnect(); } - void WaitForAssetsToLoadStep::Stop() + void CommonPreviewRendererLoadState::Stop() { TickBus::Handler::BusDisconnect(); } - void WaitForAssetsToLoadStep::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + void CommonPreviewRendererLoadState::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { m_timeRemainingS -= deltaTime; if (m_timeRemainingS > 0.0f) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h index 0202ef1045..438fd774ca 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h @@ -8,7 +8,8 @@ #pragma once -#include +#include +#include namespace AZ { @@ -16,13 +17,13 @@ namespace AZ { namespace Thumbnails { - //! WaitForAssetsToLoadStep pauses further rendering until all assets used for rendering a thumbnail have been loaded - class WaitForAssetsToLoadStep - : public ThumbnailRendererStep + //! CommonPreviewRendererLoadState pauses further rendering until all assets used for rendering a thumbnail have been loaded + class CommonPreviewRendererLoadState + : public CommonPreviewRendererState , private TickBus::Handler { public: - WaitForAssetsToLoadStep(CommonThumbnailRenderer* renderer); + CommonPreviewRendererLoadState(CommonPreviewRenderer* renderer); void Start() override; void Stop() override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h index 0a629e7e25..9dbf50ab0e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h @@ -14,22 +14,22 @@ namespace AZ { namespace Thumbnails { - class CommonThumbnailRenderer; + class CommonPreviewRenderer; - //! ThumbnailRendererStep decouples CommonThumbnailRenderer logic into easy-to-understand and debug pieces - class ThumbnailRendererStep + //! CommonPreviewRendererState decouples CommonPreviewRenderer logic into easy-to-understand and debug pieces + class CommonPreviewRendererState { public: - explicit ThumbnailRendererStep(CommonThumbnailRenderer* renderer) : m_renderer(renderer) {} - virtual ~ThumbnailRendererStep() = default; + explicit CommonPreviewRendererState(CommonPreviewRenderer* renderer) : m_renderer(renderer) {} + virtual ~CommonPreviewRendererState() = default; - //! Start is called when step begins execution + //! Start is called when state begins execution virtual void Start() {} - //! Stop is called when step ends execution + //! Stop is called when state ends execution virtual void Stop() {} protected: - CommonThumbnailRenderer* m_renderer; + CommonPreviewRenderer* m_renderer; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index ffc3f257b0..e96f199f5e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -9,7 +9,7 @@ set(FILES Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h - Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h + Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h Source/Module.cpp Source/Animation/EditorAttachmentComponent.h Source/Animation/EditorAttachmentComponent.cpp @@ -102,15 +102,15 @@ set(FILES Source/Thumbnails/Preview/CommonPreviewer.ui Source/Thumbnails/Preview/CommonPreviewerFactory.cpp Source/Thumbnails/Preview/CommonPreviewerFactory.h - Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp - Source/Thumbnails/Rendering/CommonThumbnailRenderer.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h + Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp + Source/Thumbnails/Rendering/CommonPreviewRenderer.h + Source/Thumbnails/Rendering/CommonPreviewRendererState.h + Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp + Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h + Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp + Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h + Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp + Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp From a1380940270920ba659c15a89ba811922db9d7a0 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 7 Oct 2021 14:34:29 -0500 Subject: [PATCH 099/293] Updated create-template logic to prefer the SanitizedCppName when running replacements on cpp file contents. Signed-off-by: Chris Galvan --- scripts/o3de/o3de/engine_template.py | 39 +++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 802641bd3a..06fab8752e 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -402,7 +402,7 @@ def create_template(source_path: pathlib.Path, # if no template path, error if not template_path: logger.info(f'Template path empty. Using source name {source_name}') - template_path = source_name + template_path = pathlib.Path(source_name) if not template_path.is_absolute(): default_templates_folder = manifest.get_registered(default_folder='templates') template_path = default_templates_folder / template_path @@ -518,21 +518,52 @@ def create_template(source_path: pathlib.Path, replacements.append((source_name.upper(), '${NameUpper}')) replacements.append((source_name, '${Name}')) replacements.append((sanitized_source_name, '${SanitizedCppName}')) + sanitized_name_index = len(replacements) - 1 - def _transform_into_template(s_data: object) -> (bool, str): + def _is_cpp_file(file_path: pathlib.Path) -> bool: + """ + Internal helper method to check if a file is a C++ file based + on its extension, so we can determine if we need to prefer + the ${SanitizedCppName} + :param file_path: The input file path + :return: bool: Whether or not the input file path has a C++ extension + """ + name, ext = os.path.splitext(file_path) + + return ext == ".h" or ext == ".hpp" or ext == ".inl" or ext == ".cpp" or ext == ".hxx" + + def _transform_into_template(s_data: object, + prefer_sanitized_name: bool = False) -> (bool, str): """ Internal function to transform any data into templated data :param s_data: the input data, this could be file data or file name data + :param prefer_sanitized_name: Optionally swap the sanitized name with the normal name + This can be necessary when creating the template, the source + name and sanitized source name might be the same, but C++ + files will need to prefer the sanitized version, or else + there might be compile errors (e.g. '-' characters in the name) :return: bool: whether or not the returned data MAY need to be transformed to instantiate it t_data: potentially transformed data 0 for success or non 0 failure code """ + def swap_sanitized_name_and_normal(): + replacements[sanitized_name_index-1], replacements[sanitized_name_index] = \ + replacements[sanitized_name_index], replacements[sanitized_name_index-1] + # copy the src data to the transformed data, then operate only on transformed data t_data = str(s_data) + # If we need to prefer the sanitized name, then swap it for the normal + if prefer_sanitized_name: + swap_sanitized_name_and_normal() + # run all the replacements for replacement in replacements: t_data = t_data.replace(replacement[0], replacement[1]) + # Once we are done running the replacements, reset the list if we had modified it + if prefer_sanitized_name: + swap_sanitized_name_and_normal() + if not keep_license_text: t_data = _replace_license_text(t_data) @@ -704,7 +735,7 @@ def create_template(source_path: pathlib.Path, # open the file and attempt to transform it with open(entry_abs, 'r') as s: source_data = s.read() - templated, source_data = _transform_into_template(source_data) + templated, source_data = _transform_into_template(source_data, _is_cpp_file(entry_abs)) # if the file type is a file that we expect to fins license header and we don't find any # warn that the we didn't find the license info, this makes it easy to make sure we didn't @@ -840,7 +871,7 @@ def create_template(source_path: pathlib.Path, # open the file and attempt to transform it with open(entry_abs, 'r') as s: source_data = s.read() - templated, source_data = _transform_into_template(source_data) + templated, source_data = _transform_into_template(source_data, _is_cpp_file(entry_abs)) # if the file type is a file that we expect to fins license header and we don't find any # warn that the we didn't find the license info, this makes it easy to make sure we didn't From 9b86749a838334e5065e9a4bcd574d8edd6a12ef Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 7 Oct 2021 13:01:05 -0700 Subject: [PATCH 100/293] Making sure unit tests using iMultiplayers implement the new AddServerAcceptance events; misc cleanup Signed-off-by: Gene Walters --- Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h | 1 + Gems/Multiplayer/Code/Tests/MockInterfaces.h | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h index 7f98d22702..5a528ed497 100644 --- a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h +++ b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h @@ -328,6 +328,7 @@ namespace Multiplayer void Terminate([[maybe_unused]] AzNetworking::DisconnectReason reason) override {} void AddClientDisconnectedHandler([[maybe_unused]] ClientDisconnectedEvent::Handler& handler) override {} void AddConnectionAcquiredHandler([[maybe_unused]] ConnectionAcquiredEvent::Handler& handler) override {} + void AddServerAcceptanceReceivedHandler([[maybe_unused]] ServerAcceptanceReceivedEvent::Handler& handler) override {} void AddSessionInitHandler([[maybe_unused]] SessionInitEvent::Handler& handler) override {} void AddSessionShutdownHandler([[maybe_unused]] SessionShutdownEvent::Handler& handler) override {} void SendReadyForEntityUpdates([[maybe_unused]] bool readyForEntityUpdates) override {} diff --git a/Gems/Multiplayer/Code/Tests/MockInterfaces.h b/Gems/Multiplayer/Code/Tests/MockInterfaces.h index 44024f67ab..527aeb51bc 100644 --- a/Gems/Multiplayer/Code/Tests/MockInterfaces.h +++ b/Gems/Multiplayer/Code/Tests/MockInterfaces.h @@ -29,9 +29,10 @@ namespace UnitTest MOCK_METHOD1(AddClientDisconnectedHandler, void(AZ::Event<>::Handler&)); MOCK_METHOD1(AddNotifyClientMigrationHandler, void(Multiplayer::NotifyClientMigrationEvent::Handler&)); MOCK_METHOD1(AddNotifyEntityMigrationEventHandler, void(Multiplayer::NotifyEntityMigrationEvent::Handler&)); - MOCK_METHOD1(AddConnectionAcquiredHandler, void(AZ::Event::Handler&)); - MOCK_METHOD1(AddSessionInitHandler, void(AZ::Event::Handler&)); - MOCK_METHOD1(AddSessionShutdownHandler, void(AZ::Event::Handler&)); + MOCK_METHOD1(AddConnectionAcquiredHandler, void(Multiplayer::ConnectionAcquiredEvent::Handler&)); + MOCK_METHOD1(AddServerAcceptanceReceivedHandler, void(Multiplayer::ServerAcceptanceReceivedEvent::Handler&)); + MOCK_METHOD1(AddSessionInitHandler, void(Multiplayer::SessionInitEvent::Handler&)); + MOCK_METHOD1(AddSessionShutdownHandler, void(Multiplayer::SessionShutdownEvent::Handler&)); MOCK_METHOD3(SendNotifyClientMigrationEvent, void(const Multiplayer::HostId&, uint64_t, Multiplayer::ClientInputId)); MOCK_METHOD2(SendNotifyEntityMigrationEvent, void(const Multiplayer::ConstNetworkEntityHandle&, const Multiplayer::HostId&)); MOCK_METHOD1(SendReadyForEntityUpdates, void(bool)); From 5f52664026774c549d1fefbf4141be884873b8d4 Mon Sep 17 00:00:00 2001 From: allisaurus <34254888+allisaurus@users.noreply.github.com> Date: Thu, 7 Oct 2021 13:04:10 -0700 Subject: [PATCH 101/293] Add missing field labels to AWSMetrics node SubmitMetrics (#4534) * Add missing field labels to AWSMetrics node SubmitMetrics * Add periods to tooltips to be consistent w/ other metrics nodes Signed-off-by: Stanko --- Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp b/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp index 6850fe694b..7f320f398a 100644 --- a/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp +++ b/Gems/AWSMetrics/Code/Source/AWSMetricsSystemComponent.cpp @@ -74,7 +74,12 @@ namespace AWSMetrics { behaviorContext->EBus("AWSMetricsRequestBus", "Generate and submit metrics to the metrics analytics pipeline") ->Attribute(AZ::Script::Attributes::Category, "AWSMetrics") - ->Event("SubmitMetrics", &AWSMetricsRequestBus::Events::SubmitMetrics) + ->Event( + "SubmitMetrics", &AWSMetricsRequestBus::Events::SubmitMetrics, + { { { "Metrics Attributes list", "The list of metrics attributes to submit." }, + { "Event priority", "Priority of the event. Defaults to 0, which is highest priority." }, + { "Event source override", "Event source used to override the default, 'AWSMetricGem'." }, + { "Buffer metrics", "Whether to buffer metrics and send them in a batch." } } }) ->Event("FlushMetrics", &AWSMetricsRequestBus::Events::FlushMetrics) ; From e1c02cc146a0e0ccb2b2e25d0068237a8c1bae6b Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 7 Oct 2021 15:32:57 -0500 Subject: [PATCH 102/293] Updated cpp file extension check per PR feedback. Signed-off-by: Chris Galvan --- scripts/o3de/o3de/engine_template.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 06fab8752e..cba7539aaa 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -59,6 +59,14 @@ binary_file_ext = { '.motionset' } +cpp_file_ext = { + '.cpp', + '.h', + '.hpp', + '.hxx', + '.inl' +} + expect_license_info_ext = { '.cpp', '.h', @@ -530,7 +538,7 @@ def create_template(source_path: pathlib.Path, """ name, ext = os.path.splitext(file_path) - return ext == ".h" or ext == ".hpp" or ext == ".inl" or ext == ".cpp" or ext == ".hxx" + return ext.lower() in cpp_file_ext def _transform_into_template(s_data: object, prefer_sanitized_name: bool = False) -> (bool, str): From 42e748760d501ea8472e89abd4f8c9681b1037be Mon Sep 17 00:00:00 2001 From: rhhong Date: Mon, 16 Aug 2021 21:43:49 -0700 Subject: [PATCH 103/293] Loading actor in editor using asset system. Signed-off-by: rhhong --- .../CommandSystem/Source/ActorCommands.cpp | 11 +- .../CommandSystem/Source/ImporterCommands.cpp | 46 +++----- .../Source/SelectionCommands.cpp | 15 --- .../RCExt/Actor/ActorGroupExporter.cpp | 1 - .../Pipeline/RCExt/Actor/ActorGroupExporter.h | 3 +- .../EMotionFX/Code/EMotionFX/Source/Actor.cpp | 22 ---- Gems/EMotionFX/Code/EMotionFX/Source/Actor.h | 9 -- .../Code/EMotionFX/Source/ActorManager.cpp | 103 +++++++++++------ .../Code/EMotionFX/Source/ActorManager.h | 21 ++-- .../EMotionFX/Source/AutoRegisteredActor.h | 109 ------------------ .../EMStudioSDK/Source/FileManager.cpp | 4 - .../EMStudioSDK/Source/MainWindow.cpp | 5 - .../Source/RenderPlugin/RenderPlugin.cpp | 4 +- .../Source/ResetSettingsDialog.cpp | 3 +- .../Source/SceneManager/ActorsWindow.cpp | 6 - .../Code/EMotionFX/emotionfx_files.cmake | 1 - .../Source/Integration/Assets/ActorAsset.cpp | 3 - .../Source/Integration/Assets/ActorAsset.h | 4 +- 18 files changed, 108 insertions(+), 262 deletions(-) delete mode 100644 Gems/EMotionFX/Code/EMotionFX/Source/AutoRegisteredActor.h diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp index 85bb726822..57e206560a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp @@ -22,6 +22,7 @@ #include "CommandManager.h" #include #include +#include namespace CommandSystem @@ -729,7 +730,8 @@ namespace CommandSystem m_oldWorkspaceDirtyFlag = GetCommandManager()->GetWorkspaceDirtyFlag(); // get rid of the actor - EMotionFX::GetActorManager().UnregisterActor(EMotionFX::GetActorManager().FindSharedActorByID(actor->GetID())); + const AZ::Data::AssetId actorAssetId = EMotionFX::GetActorManager().FindAssetIdByActorId(actor->GetID()); + EMotionFX::GetActorManager().UnregisterActor(actorAssetId); // mark the workspace as dirty GetCommandManager()->SetWorkspaceDirtyFlag(true); @@ -818,7 +820,6 @@ namespace CommandSystem { continue; } - // ignore visualization actor instances if (actorInstance->GetIsUsedForVisualization()) { @@ -849,12 +850,6 @@ namespace CommandSystem // get the current actor EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i); - // ignore runtime-owned actors - if (actor->GetIsOwnedByRuntime()) - { - continue; - } - // ignore visualization actors if (actor->GetIsUsedForVisualization()) { diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp index 168de93e38..4b23bd2e0a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp @@ -17,6 +17,7 @@ #include #include "CommandManager.h" #include +#include namespace CommandSystem @@ -65,35 +66,24 @@ namespace CommandSystem filename = EMotionFX::EMotionFXManager::ResolvePath(filename.c_str()); } + AZ::Data::AssetId actorAssetId; + EBUS_EVENT_RESULT( + actorAssetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, filename.c_str(), AZ::Data::s_invalidAssetType, false); + // check if we have already loaded the actor - EMotionFX::Actor* actorFromManager = EMotionFX::GetActorManager().FindActorByFileName(filename.c_str()); - if (actorFromManager) + const size_t actorIndex = EMotionFX::GetActorManager().FindActorIndex(actorAssetId); + if (actorIndex != InvalidIndex) { - AZStd::to_string(outResult, actorFromManager->GetID()); return true; } - // init the settings - EMotionFX::Importer::ActorSettings settings; - - // extract default values from the command syntax automatically, if they aren't specified explicitly - settings.m_loadLimits = parameters.GetValueAsBool("loadLimits", this); - settings.m_loadMorphTargets = parameters.GetValueAsBool("loadMorphTargets", this); - settings.m_loadSkeletalLoDs = parameters.GetValueAsBool("loadSkeletalLODs", this); - settings.m_dualQuatSkinning = parameters.GetValueAsBool("dualQuatSkinning", this); - - // try to load the actor - AZStd::shared_ptr actor {EMotionFX::GetImporter().LoadActor(filename.c_str(), &settings)}; - if (!actor) - { - outResult = AZStd::string::format("Failed to load actor from '%s'. File may not exist at this path or may have incorrect permissions", filename.c_str()); - return false; - } - - // Because the actor is directly loaded from disk (without going through an actor asset), we need to ask for a blocking - // load for the asset that actor is depend on. - actor->Finalize(EMotionFX::Actor::LoadRequirement::RequireBlockingLoad); + // Do a blocking load of the asset. + AZ::Data::Asset actorAsset = + AZ::Data::AssetManager::Instance().GetAsset( + actorAssetId, AZ::Data::AssetLoadBehavior::Default); + actorAsset.BlockUntilLoadComplete(); + EMotionFX::Actor* actor = actorAsset->GetActor(); // set the actor id in case we have specified it as parameter if (actorID != MCORE_INVALIDINDEX32) { @@ -113,7 +103,6 @@ namespace CommandSystem GetCommandManager()->ExecuteCommandInsideCommand(AZStd::string::format("Select -actorID %i", actor->GetID()).c_str(), outResult); } - // mark the workspace as dirty m_oldWorkspaceDirtyFlag = GetCommandManager()->GetWorkspaceDirtyFlag(); GetCommandManager()->SetWorkspaceDirtyFlag(true); @@ -121,7 +110,8 @@ namespace CommandSystem // return the id of the newly created actor AZStd::to_string(outResult, actor->GetID()); - EMotionFX::GetActorManager().RegisterActor(AZStd::move(actor)); + // Register actor asset. + EMotionFX::GetActorManager().RegisterActor(actorAsset); return true; } @@ -145,14 +135,14 @@ namespace CommandSystem } // find the actor based on the given id - AZStd::shared_ptr actor = EMotionFX::GetActorManager().FindSharedActorByID(actorID); - if (actor == nullptr) + AZ::Data::AssetId actorAssetId = EMotionFX::GetActorManager().FindAssetIdByActorId(actorID); + if (!actorAssetId.IsValid()) { outResult = AZStd::string::format("Cannot remove actor. Actor ID %i is not valid.", actorID); return false; } - EMotionFX::GetActorManager().UnregisterActor(actor); + EMotionFX::GetActorManager().UnregisterActor(actorAssetId); // update our render actors AZStd::string updateRenderActorsResult; diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/SelectionCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/SelectionCommands.cpp index bcc9769c44..7e1a9fe0f5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/SelectionCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/SelectionCommands.cpp @@ -183,11 +183,6 @@ namespace CommandSystem for (size_t i = 0; i < numActors; ++i) { EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i); - - if (actor->GetIsOwnedByRuntime()) - { - continue; - } if (unselect == false) { @@ -211,11 +206,6 @@ namespace CommandSystem return false; } - if (actor->GetIsOwnedByRuntime()) - { - return false; - } - if (unselect == false) { selection.AddActor(actor); @@ -244,11 +234,6 @@ namespace CommandSystem { EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i); - if (actor->GetIsOwnedByRuntime()) - { - continue; - } - if (AzFramework::StringFunc::Equal(valueString.c_str(), actor->GetName(), false /* no case */)) { if (unselect == false) diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp index 4cba50138a..3d5e4fa413 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h index e94137b317..d2db7d91c5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h @@ -8,7 +8,6 @@ #pragma once #include -#include #include #include #include @@ -44,7 +43,7 @@ namespace EMotionFX static AZStd::optional GetFirstProductByType( const ActorGroupExportContext& context, AZ::Data::AssetType type); - AutoRegisteredActor m_actor; + AZStd::shared_ptr m_actor; AZStd::vector m_actorMaterialReferences; }; } // namespace Pipeline diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 3e592113b1..861271fdb3 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -91,9 +91,6 @@ namespace EMotionFX m_simulatedObjectSetup = AZStd::make_shared(this); m_optimizeSkeleton = false; -#if defined(EMFX_DEVELOPMENT_BUILD) - m_isOwnedByRuntime = false; -#endif // EMFX_DEVELOPMENT_BUILD // make sure we have at least allocated the first LOD of materials and facial setups m_materials.reserve(4); // reserve space for 4 lods @@ -2074,25 +2071,6 @@ namespace EMotionFX return m_usedForVisualization; } - void Actor::SetIsOwnedByRuntime(bool isOwnedByRuntime) - { -#if defined(EMFX_DEVELOPMENT_BUILD) - m_isOwnedByRuntime = isOwnedByRuntime; -#else - AZ_UNUSED(isOwnedByRuntime); -#endif - } - - - bool Actor::GetIsOwnedByRuntime() const - { -#if defined(EMFX_DEVELOPMENT_BUILD) - return m_isOwnedByRuntime; -#else - return true; -#endif - } - const AZ::Aabb& Actor::GetStaticAabb() const { return m_staticAabb; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h index aa5c5df45c..dc83972d40 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h @@ -720,12 +720,6 @@ namespace EMotionFX void SetIsUsedForVisualization(bool flag); bool GetIsUsedForVisualization() const; - /** - * Marks the actor as used by the engine runtime, as opposed to the tool suite. - */ - void SetIsOwnedByRuntime(bool isOwnedByRuntime); - bool GetIsOwnedByRuntime() const; - /** * Recursively find the parent bone that is enabled in a given LOD, starting from a given node. * For example if you have a finger bone, while the finger bones are disabled in the skeletal LOD, this function will return the index to the hand bone. @@ -940,8 +934,5 @@ namespace EMotionFX bool m_usedForVisualization; /**< Indicates if the actor is used for visualization specific things and is not used as a normal in-game actor. */ bool m_optimizeSkeleton; /**< Indicates if we should perform/ */ bool m_isReady = false; /**< If actor as well as its dependent files are fully loaded and initialized.*/ -#if defined(EMFX_DEVELOPMENT_BUILD) - bool m_isOwnedByRuntime; /**< Set if the actor is used/owned by the engine runtime. */ -#endif // EMFX_DEVELOPMENT_BUILD }; } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp index 681efb6039..d20d0cf11c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp @@ -31,7 +31,7 @@ namespace EMotionFX SetScheduler(MultiThreadScheduler::Create()); // reserve memory - m_actors.reserve(512); + m_actorAssets.reserve(32); m_actorInstances.reserve(1024); m_rootActorInstances.reserve(1024); } @@ -111,20 +111,23 @@ namespace EMotionFX // register the actor - void ActorManager::RegisterActor(AZStd::shared_ptr actor) + void ActorManager::RegisterActor(ActorAssetData actorAsset) { LockActors(); // check if we already registered - if (FindActorIndex(actor.get()) != InvalidIndex) + if (FindActorIndex(actorAsset.GetId()) != InvalidIndex) { - MCore::LogWarning("EMotionFX::ActorManager::RegisterActor() - The actor at location 0x%x has already been registered as actor, most likely already by the LoadActor of the importer.", actor.get()); + MCore::LogWarning( + "EMotionFX::ActorManager::RegisterActor() - The actor at location 0x%x has already been registered as actor, most likely " + "already by the LoadActor of the importer.", + actorAsset.GetAs()->GetActor()); UnlockActors(); return; } // register it - m_actors.emplace_back(AZStd::move(actor)); + m_actorAssets.emplace_back(AZStd::move(actorAsset)); UnlockActors(); } @@ -146,60 +149,82 @@ namespace EMotionFX Actor* ActorManager::FindActorByName(const char* actorName) const { // get the number of actors and iterate through them - const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [actorName](const AZStd::shared_ptr& a) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [actorName](const ActorAssetData& a) { - return a->GetNameString() == actorName; + return a.GetAs()->GetActor()->GetNameString() == actorName; }); - return (found != m_actors.end()) ? found->get() : nullptr; + return (found != m_actorAssets.end()) ? found->GetAs()->GetActor() : nullptr; } // find the actor for a given filename Actor* ActorManager::FindActorByFileName(const char* fileName) const { - const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [fileName](const AZStd::shared_ptr& a) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [fileName](const ActorAssetData& a) { - return AzFramework::StringFunc::Equal(a->GetFileNameString().c_str(), fileName, false /* no case */); + return AzFramework::StringFunc::Equal( + a.GetAs()->GetActor()->GetFileNameString().c_str(), fileName, false /* no case */); }); - return (found != m_actors.end()) ? found->get() : nullptr; + return (found != m_actorAssets.end()) ? found->GetAs()->GetActor() : nullptr; } // find the leader actor record for a given actor - size_t ActorManager::FindActorIndex(Actor* actor) const + size_t ActorManager::FindActorIndex(AZ::Data::AssetId assetId) const { - const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [actor](const AZStd::shared_ptr& a) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [assetId](const ActorAssetData& a) { - return a.get() == actor; + return a.GetId() == assetId; }); - return (found != m_actors.end()) ? AZStd::distance(m_actors.begin(), found) : InvalidIndex; + return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex; } + size_t ActorManager::FindActorIndex(const Actor* actor) const + { + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [actor](const ActorAssetData& a) + { + return a.GetAs()->GetActor() == actor; + }); + + return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex; + } // find the actor for a given actor name size_t ActorManager::FindActorIndexByName(const char* actorName) const { - const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [actorName](const AZStd::shared_ptr& a) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [actorName](const ActorAssetData& a) { - return a->GetNameString() == actorName; + return a.GetAs()->GetActor()->GetNameString() == actorName; }); - return (found != m_actors.end()) ? AZStd::distance(m_actors.begin(), found) : InvalidIndex; + return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex; } // find the actor for a given actor filename size_t ActorManager::FindActorIndexByFileName(const char* filename) const { - const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [filename](const AZStd::shared_ptr& a) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [filename](const ActorAssetData& a) { - return a->GetFileNameString() == filename; + return a.GetAs()->GetActor()->GetFileNameString() == filename; }); - return (found != m_actors.end()) ? AZStd::distance(m_actors.begin(), found) : InvalidIndex; + return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex; } @@ -237,22 +262,26 @@ namespace EMotionFX // find the actor by the identification number Actor* ActorManager::FindActorByID(uint32 id) const { - const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [id](const AZStd::shared_ptr& a) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [id](const ActorAssetData& a) { - return a->GetID() == id; + return a.GetAs()->GetActor()->GetID() == id; }); - return (found != m_actors.end()) ? found->get() : nullptr; + return (found != m_actorAssets.end()) ? found->GetAs()->GetActor() : nullptr; } - AZStd::shared_ptr ActorManager::FindSharedActorByID(uint32 id) const + AZ::Data::AssetId ActorManager::FindAssetIdByActorId(uint32 id) const { - const auto found = AZStd::find_if(m_actors.begin(), m_actors.end(), [id](const AZStd::shared_ptr& a) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [id](const ActorAssetData& a) { - return a->GetID() == id; + return a.GetAs()->GetActor()->GetID() == id; }); - return (found != m_actors.end()) ? *found : nullptr; + return (found != m_actorAssets.end()) ? found->GetId() : AZ::Data::AssetId(); } @@ -264,14 +293,20 @@ namespace EMotionFX // unregister an actor - void ActorManager::UnregisterActor(const AZStd::shared_ptr& actor) + void ActorManager::UnregisterActor(AZ::Data::AssetId actorAssetID) { LockActors(); - auto result = AZStd::find(m_actors.begin(), m_actors.end(), actor); - if (result != m_actors.end()) + const auto found = AZStd::find_if( + m_actorAssets.begin(), m_actorAssets.end(), + [actorAssetID](const ActorAssetData& a) + { + return a.GetId() == actorAssetID; + }); + if (found != m_actorAssets.end()) { - m_actors.erase(result); + m_actorAssets.erase(found); } + UnlockActors(); } @@ -297,7 +332,7 @@ namespace EMotionFX LockActors(); // clear all actors - m_actors.clear(); + m_actorAssets.clear(); // TODO: what if there are still references to the actors inside the list of registered actor instances? UnlockActors(); @@ -390,7 +425,7 @@ namespace EMotionFX Actor* ActorManager::GetActor(size_t nr) const { - return m_actors[nr].get(); + return m_actorAssets[nr].GetAs()->GetActor(); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h index ff78250141..e4ce0d6c94 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h @@ -16,7 +16,8 @@ #include #include #include - +#include +#include namespace EMotionFX { @@ -41,13 +42,14 @@ namespace EMotionFX friend class EMotionFXManager; public: + using ActorAssetData = AZ::Data::Asset; static ActorManager* Create(); /** * Register an actor. * @param actor The actor to register. */ - void RegisterActor(AZStd::shared_ptr actor); + void RegisterActor(ActorAssetData actorAsset); /** * Unregister all actors. @@ -60,14 +62,14 @@ namespace EMotionFX * Unregister a specific actor. * @param actor The actor you passed to the RegisterActor function sometime before. */ - void UnregisterActor(const AZStd::shared_ptr& actor); + void UnregisterActor(AZ::Data::AssetId actorAssetID); /** * Get the number of registered actors. * This does not include the clones that have been optionally created. * @result The number of registered actors. */ - MCORE_INLINE size_t GetNumActors() const { return m_actors.size(); } + MCORE_INLINE size_t GetNumActors() const { return m_actorAssets.size(); } /** * Get a given actor. @@ -99,7 +101,8 @@ namespace EMotionFX * @param actor The actor object you once passed to RegisterActor. * @result Returns the actor number, which is in range of [0..GetNumActors()-1], or returns MCORE_INVALIDINDEX32 when not found. */ - size_t FindActorIndex(Actor* actor) const; + size_t FindActorIndex(AZ::Data::AssetId assetId) const; + size_t FindActorIndex(const Actor* actor) const; /** * Find the actor number for a given actor name. @@ -160,7 +163,7 @@ namespace EMotionFX */ Actor* FindActorByID(uint32 id) const; - AZStd::shared_ptr FindSharedActorByID(uint32 id) const; + AZ::Data::AssetId FindAssetIdByActorId(uint32 id) const; /** * Check if the given actor instance is registered. @@ -255,9 +258,9 @@ namespace EMotionFX void UnlockActors(); private: - AZStd::vector m_actorInstances; /**< The registered actor instances. */ - AZStd::vector> m_actors; /**< The registered actors. */ - AZStd::vector m_rootActorInstances; /**< Root actor instances (roots of all attachment chains). */ + AZStd::vector m_actorInstances; /**< The registered actor instances. */ + AZStd::vector m_actorAssets; + AZStd::vector m_rootActorInstances; /**< Root actor instances (roots of all attachment chains). */ ActorUpdateScheduler* m_scheduler; /**< The update scheduler to use. */ MCore::MutexRecursive m_actorLock; /**< The multithread lock for touching the actors array. */ MCore::MutexRecursive m_actorInstanceLock; /**< The multithread lock for touching the actor instances array. */ diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/AutoRegisteredActor.h b/Gems/EMotionFX/Code/EMotionFX/Source/AutoRegisteredActor.h deleted file mode 100644 index 8304976b15..0000000000 --- a/Gems/EMotionFX/Code/EMotionFX/Source/AutoRegisteredActor.h +++ /dev/null @@ -1,109 +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 - * - */ - -#pragma once - -#include -#include -#include - -namespace EMotionFX -{ - class Actor; - - /** - * @brief An Actor pointer that unregisters itself when it goes out of - * scope - * - * This class allows for simple functionality of automatically registering - * and unregistering an actor from the manager. Its primary use case is the - * ActorAsset, that shares ownership with the manager. But it can also be - * used anywhere that needs to make an Actor that needs to be in the - * Manager for a given period of time. A good example of this is anything - * that needs Actor commands to work on an actor that is made in a given - * scope. One main place where this happens is in the Actor asset processor - * code. - */ - class AutoRegisteredActor - { - public: - AutoRegisteredActor() = default; - - template - AutoRegisteredActor(AZStd::shared_ptr actor) - : m_actor(AZStd::move(actor)) - { - Register(m_actor); - } - template - AutoRegisteredActor(AZStd::unique_ptr actor) - : m_actor(AZStd::move(actor)) - { - Register(m_actor); - } - - // This class is not copyable, because a given actor cannot be - // registered with the manager multiple times - AutoRegisteredActor(const AutoRegisteredActor&) = delete; - AutoRegisteredActor& operator=(const AutoRegisteredActor&) = delete; - - AutoRegisteredActor(AutoRegisteredActor&& other) noexcept - { - *this = AZStd::move(other); - } - - AutoRegisteredActor& operator=(AutoRegisteredActor&& other) noexcept - { - if (this != &other) - { - Unregister(m_actor); - m_actor = AZStd::move(other.m_actor); - } - return *this; - } - - ~AutoRegisteredActor() - { - Unregister(m_actor); - } - - Actor* operator->() const - { - return m_actor.operator->(); - } - - operator bool() const - { - return static_cast(m_actor); - } - - Actor* get() const - { - return m_actor.get(); - } - - private: - void Register(const AZStd::shared_ptr& actor) - { - if (actor) - { - GetActorManager().RegisterActor(actor); - } - } - - void Unregister(const AZStd::shared_ptr& actor) - { - if (actor) - { - GetActorManager().UnregisterActor(actor); - } - } - - AZStd::shared_ptr m_actor; - }; -} // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp index 2d65a228b7..17438dd59a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp @@ -112,10 +112,6 @@ namespace EMStudio for (size_t i = 0; i < actorCount; ++i) { EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i); - if (actor->GetIsOwnedByRuntime()) - { - continue; - } if (AzFramework::StringFunc::Equal(filename, actor->GetFileName())) { diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp index 002634ea90..b75fb71060 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -1792,11 +1792,6 @@ namespace EMStudio { EMotionFX::Actor* actor = selectionList.GetActorInstance(i)->GetActor(); - if (actor->GetIsOwnedByRuntime()) - { - continue; - } - if (AZStd::find(savingActors.begin(), savingActors.end(), actor) == savingActors.end()) { savingActors.push_back(actor); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp index db0c355002..c74cb3cb0f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp @@ -389,7 +389,7 @@ namespace EMStudio // get the current actor and the number of clones EMotionFX::Actor* actor = EMotionFX::GetActorManager().GetActor(i); - if (actor->GetIsOwnedByRuntime() || !actor->IsReady()) + if (!actor->IsReady()) { continue; } @@ -421,7 +421,7 @@ namespace EMStudio // At this point the render actor could point to an already deleted actor. // In case the actor got deleted we might get an unexpected flag as result. - if (!found || (found && actor->GetIsOwnedByRuntime()) || (!actor->IsReady())) + if (!found || (!actor->IsReady())) { DestroyEMStudioActor(actor); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/ResetSettingsDialog.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/ResetSettingsDialog.cpp index 2f45a89ea2..5c15f4b6be 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/ResetSettingsDialog.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/ResetSettingsDialog.cpp @@ -65,8 +65,7 @@ namespace EMStudio m_actorCheckbox = new QCheckBox("Actors"); m_actorCheckbox->setObjectName("EMFX.ResetSettingsDialog.Actors"); - const bool hasActors = HasEntityInEditor( - EMotionFX::GetActorManager(), &EMotionFX::ActorManager::GetNumActors, &EMotionFX::ActorManager::GetActor); + const bool hasActors = EMotionFX::GetActorManager().GetNumActors() > 0; m_actorCheckbox->setChecked(hasActors); m_actorCheckbox->setDisabled(!hasActors); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/SceneManager/ActorsWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/SceneManager/ActorsWindow.cpp index 5012ee2578..c1e35967ec 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/SceneManager/ActorsWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/SceneManager/ActorsWindow.cpp @@ -123,12 +123,6 @@ namespace EMStudio continue; } - // ignore engine actors - if (actor->GetIsOwnedByRuntime()) - { - continue; - } - // create a tree item for the new attachment QTreeWidgetItem* newItem = new QTreeWidgetItem(m_treeWidget); diff --git a/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake b/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake index b12cbe102f..9947850471 100644 --- a/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake +++ b/Gems/EMotionFX/Code/EMotionFX/emotionfx_files.cmake @@ -25,7 +25,6 @@ set(FILES Source/AttachmentNode.h Source/AttachmentSkin.cpp Source/AttachmentSkin.h - Source/AutoRegisteredActor.h Source/BaseObject.cpp Source/BaseObject.h Source/CompressedKeyFrames.h diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp index 5082d4b739..5b546c1155 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp @@ -6,7 +6,6 @@ * */ -#include #include #include #include @@ -64,8 +63,6 @@ namespace EMotionFX &actorSettings, ""); - // Set the is owned by runtime flag before finalizing the actor, as that uses the flag already. - assetData->m_emfxActor->SetIsOwnedByRuntime(true); assetData->m_emfxActor->Finalize(); // Clear out the EMFX raw asset data. diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h index 8732c6a448..3bd2c38640 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h @@ -15,7 +15,7 @@ #include #include -#include +//#include namespace EMotionFX @@ -58,7 +58,7 @@ namespace EMotionFX void InitRenderActor(); private: - AutoRegisteredActor m_emfxActor; ///< Pointer to shared EMotionFX actor + AZStd::shared_ptr m_emfxActor; AZStd::unique_ptr m_renderActor; }; From bc88d2b3819765f227cd95376e2b067535e6a123 Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 17 Aug 2021 11:54:42 -0700 Subject: [PATCH 104/293] Address feedback from Chris. Simplified get asset call and etc. Signed-off-by: rhhong --- .../CommandSystem/Source/ImporterCommands.cpp | 2 +- .../Code/EMotionFX/Source/ActorManager.cpp | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp index 4b23bd2e0a..80ef93c331 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp @@ -111,7 +111,7 @@ namespace CommandSystem AZStd::to_string(outResult, actor->GetID()); // Register actor asset. - EMotionFX::GetActorManager().RegisterActor(actorAsset); + EMotionFX::GetActorManager().RegisterActor(AZStd::move(actorAsset)); return true; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp index d20d0cf11c..0779e55f85 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp @@ -121,7 +121,7 @@ namespace EMotionFX MCore::LogWarning( "EMotionFX::ActorManager::RegisterActor() - The actor at location 0x%x has already been registered as actor, most likely " "already by the LoadActor of the importer.", - actorAsset.GetAs()->GetActor()); + actorAsset->GetActor()); UnlockActors(); return; } @@ -153,10 +153,10 @@ namespace EMotionFX m_actorAssets.begin(), m_actorAssets.end(), [actorName](const ActorAssetData& a) { - return a.GetAs()->GetActor()->GetNameString() == actorName; + return a->GetActor()->GetNameString() == actorName; }); - return (found != m_actorAssets.end()) ? found->GetAs()->GetActor() : nullptr; + return (found != m_actorAssets.end()) ? (*found)->GetActor() : nullptr; } @@ -168,10 +168,10 @@ namespace EMotionFX [fileName](const ActorAssetData& a) { return AzFramework::StringFunc::Equal( - a.GetAs()->GetActor()->GetFileNameString().c_str(), fileName, false /* no case */); + a->GetActor()->GetFileNameString().c_str(), fileName, false /* no case */); }); - return (found != m_actorAssets.end()) ? found->GetAs()->GetActor() : nullptr; + return (found != m_actorAssets.end()) ? (*found)->GetActor() : nullptr; } @@ -194,7 +194,7 @@ namespace EMotionFX m_actorAssets.begin(), m_actorAssets.end(), [actor](const ActorAssetData& a) { - return a.GetAs()->GetActor() == actor; + return a->GetActor() == actor; }); return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex; @@ -207,7 +207,7 @@ namespace EMotionFX m_actorAssets.begin(), m_actorAssets.end(), [actorName](const ActorAssetData& a) { - return a.GetAs()->GetActor()->GetNameString() == actorName; + return a->GetActor()->GetNameString() == actorName; }); return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex; @@ -221,7 +221,7 @@ namespace EMotionFX m_actorAssets.begin(), m_actorAssets.end(), [filename](const ActorAssetData& a) { - return a.GetAs()->GetActor()->GetFileNameString() == filename; + return a->GetActor()->GetFileNameString() == filename; }); return (found != m_actorAssets.end()) ? AZStd::distance(m_actorAssets.begin(), found) : InvalidIndex; @@ -266,10 +266,10 @@ namespace EMotionFX m_actorAssets.begin(), m_actorAssets.end(), [id](const ActorAssetData& a) { - return a.GetAs()->GetActor()->GetID() == id; + return a->GetActor()->GetID() == id; }); - return (found != m_actorAssets.end()) ? found->GetAs()->GetActor() : nullptr; + return (found != m_actorAssets.end()) ? (*found)->GetActor() : nullptr; } AZ::Data::AssetId ActorManager::FindAssetIdByActorId(uint32 id) const @@ -278,7 +278,7 @@ namespace EMotionFX m_actorAssets.begin(), m_actorAssets.end(), [id](const ActorAssetData& a) { - return a.GetAs()->GetActor()->GetID() == id; + return a->GetActor()->GetID() == id; }); return (found != m_actorAssets.end()) ? found->GetId() : AZ::Data::AssetId(); @@ -425,7 +425,7 @@ namespace EMotionFX Actor* ActorManager::GetActor(size_t nr) const { - return m_actorAssets[nr].GetAs()->GetActor(); + return m_actorAssets[nr]->GetActor(); } From bf38f0748097b981a8fa06aa3785c88fac9eeacb Mon Sep 17 00:00:00 2001 From: Yuriy Toporovskyy Date: Mon, 13 Sep 2021 11:59:08 -0400 Subject: [PATCH 105/293] Allow buffer to take any size, including 0 Signed-off-by: Yuriy Toporovskyy --- .../Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp index f3744fe119..8bf518e277 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshOutputStreamManager.cpp @@ -74,6 +74,9 @@ namespace AZ creator.End(m_bufferAsset); } + + // default value of 256mb supports roughly 42 character instances at 100,000 vertices per character x 64 bytes per vertex (12 byte position + 12 byte previous frame position + 12 byte normal + 16 byte tangent + 12 byte bitangent) + // This includes only the output of the skinning compute shader, not the input buffers or bone transforms AZ_CVAR( int, r_skinnedMeshInstanceMemoryPoolSize, @@ -95,10 +98,8 @@ namespace AZ } m_needsInit = false; - // 256mb supports roughly 42 character instances at 100,000 vertices per character x 64 bytes per vertex (12 byte position + 12 byte previous frame position + 12 byte normal + 16 byte tangent + 12 byte bitangent) - // This includes only the output of the skinning compute shader, not the input buffers or bone transforms const AZ::u64 sizeInMb = r_skinnedMeshInstanceMemoryPoolSize; - m_sizeInBytes = AZ::GetMax(sizeInMb, 256ull) * (1024u * 1024u); + m_sizeInBytes = sizeInMb * (1024u * 1024u); CalculateAlignment(); From 7650683902d01ea5d66c6c2d44c6cf9107af02a8 Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 17 Aug 2021 16:17:27 -0700 Subject: [PATCH 106/293] Defer the nodeWindowPlugin reinit to main thread update. Set the actor file name through actor asset. Signed-off-by: rhhong --- .../Source/NodeWindow/NodeWindowPlugin.cpp | 11 ++++++++++- .../Source/NodeWindow/NodeWindowPlugin.h | 4 ++++ .../Code/Source/Integration/Assets/ActorAsset.cpp | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.cpp index 6b7beb20de..4629e8dc54 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.cpp @@ -327,7 +327,16 @@ namespace EMStudio void NodeWindowPlugin::OnActorReady([[maybe_unused]] EMotionFX::Actor* actor) { - ReInit(); + m_reinitRequested = true; + } + + void NodeWindowPlugin::ProcessFrame([[maybe_unused]] float timePassedInSeconds) + { + if (m_reinitRequested) + { + ReInit(); + m_reinitRequested = false; + } } //----------------------------------------------------------------------------------------- diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h index 157486df10..4c530fffdc 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h @@ -60,6 +60,8 @@ namespace EMStudio EMStudioPlugin* Clone() override; void ReInit(); + void ProcessFrame(float timePassedInSeconds) override; + public slots: void OnNodeChanged(); void VisibilityChanged(bool isVisible); @@ -87,5 +89,7 @@ namespace EMStudio AZStd::unique_ptr m_actorInfo; AZStd::unique_ptr m_nodeInfo; + + bool m_reinitRequested = false; }; } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp index 5b546c1155..64117fa814 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp @@ -63,6 +63,7 @@ namespace EMotionFX &actorSettings, ""); + assetData->m_emfxActor->SetFileName(asset.GetHint().c_str()); assetData->m_emfxActor->Finalize(); // Clear out the EMFX raw asset data. From 0b49cc38a74d772d5b55fda1d08e31db9e6edb8c Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 17 Aug 2021 18:19:14 -0700 Subject: [PATCH 107/293] fix broken build Signed-off-by: rhhong --- .../EMotionFX/Code/Source/Integration/System/SystemComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 08e99f97d0..cf2f9beaa4 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include From 5369df41953403b4fd0cb66bd3edb8e28461ad94 Mon Sep 17 00:00:00 2001 From: rhhong Date: Mon, 23 Aug 2021 21:30:46 -0700 Subject: [PATCH 108/293] remove extra line Signed-off-by: rhhong --- Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h index 3bd2c38640..c256fa5283 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h @@ -15,7 +15,6 @@ #include #include -//#include namespace EMotionFX From 4767d2a8917f84a72916248a4f7966e39089011a Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 24 Aug 2021 11:36:13 -0700 Subject: [PATCH 109/293] Fix unit test Signed-off-by: rhhong --- .../CommandSystem/Source/ImporterCommands.cpp | 5 + Gems/EMotionFX/Code/Tests/ActorFixture.cpp | 17 ++- Gems/EMotionFX/Code/Tests/ActorFixture.h | 7 +- .../Tests/AdditiveMotionSamplingTests.cpp | 16 +-- .../Code/Tests/AnimGraphDeferredInitTests.cpp | 1 + .../Code/Tests/BlendTreeRagdollNodeTests.cpp | 2 +- .../Code/Tests/ColliderCommandTests.cpp | 107 ++++++++++-------- .../Code/Tests/Integration/CanAddActor.cpp | 14 +-- .../Code/Tests/MotionExtractionBusTests.cpp | 1 + .../Code/Tests/MultiThreadSchedulerTests.cpp | 2 + .../AnimGraph/AnimGraphActivateTests.cpp | 8 +- .../AnimGraph/AnimGraphModelTests.cpp | 9 +- .../ProvidesUI/Menus/FileMenu/CanReset.cpp | 9 +- .../Ragdoll/CanCopyPasteColliders.cpp | 10 +- .../Ragdoll/CanCopyPasteJointLimits.cpp | 6 +- .../Code/Tests/RagdollCommandTests.cpp | 58 +++++----- .../Tests/SimulatedObjectCommandTests.cpp | 92 +++++++-------- .../Code/Tests/SimulatedObjectModelTests.cpp | 8 +- .../Tests/SimulatedObjectSerializeTests.cpp | 6 +- .../EMotionFX/Code/Tests/SkeletalLODTests.cpp | 4 +- .../Tests/TestAssetCode/TestActorAssets.cpp | 3 +- .../Tests/TestAssetCode/TestActorAssets.h | 12 ++ .../Code/Tests/UI/CanAddJointAndChildren.cpp | 9 +- .../Code/Tests/UI/CanAddSimulatedObject.cpp | 85 ++++++++------ .../Code/Tests/UI/CanAddToSimulatedObject.cpp | 17 ++- .../CanChangeParametersInSimulatedObject.cpp | 8 +- .../Code/Tests/UI/CanUseFileMenu.cpp | 25 ++-- .../Code/Tests/UI/CanUseLayoutMenu.cpp | 1 - .../Code/Tests/UI/ClothColliderTests.cpp | 5 +- .../Code/Tests/UI/LODSkinnedMeshTests.cpp | 17 +-- .../Code/Tests/UI/RagdollEditTests.cpp | 9 +- 31 files changed, 341 insertions(+), 232 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp index 80ef93c331..ea3f816e86 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp @@ -69,6 +69,11 @@ namespace CommandSystem AZ::Data::AssetId actorAssetId; EBUS_EVENT_RESULT( actorAssetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, filename.c_str(), AZ::Data::s_invalidAssetType, false); + if (!actorAssetId.IsValid()) + { + outResult = AZStd::string::format("Cannot import actor. Cannot find asset at path %s.", filename.c_str()); + return false; + } // check if we have already loaded the actor const size_t actorIndex = EMotionFX::GetActorManager().FindActorIndex(actorAssetId); diff --git a/Gems/EMotionFX/Code/Tests/ActorFixture.cpp b/Gems/EMotionFX/Code/Tests/ActorFixture.cpp index e77df103e0..31c3a0c721 100644 --- a/Gems/EMotionFX/Code/Tests/ActorFixture.cpp +++ b/Gems/EMotionFX/Code/Tests/ActorFixture.cpp @@ -10,12 +10,15 @@ #include #include #include +#include #include #include #include #include #include +#include + namespace EMotionFX { @@ -23,8 +26,9 @@ namespace EMotionFX { SystemComponentFixture::SetUp(); - m_actor = ActorFactory::CreateAndInit(); - m_actorInstance = ActorInstance::Create(m_actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId); + m_actorInstance = ActorInstance::Create(m_actorAsset->GetActor()); } void ActorFixture::TearDown() @@ -35,6 +39,7 @@ namespace EMotionFX m_actorInstance = nullptr; } + GetEMotionFX().GetActorManager()->UnregisterAllActors(); SystemComponentFixture::TearDown(); } @@ -71,7 +76,7 @@ namespace EMotionFX AZ::ObjectStream::FilterDescriptor loadFilter(nullptr, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES); SimulatedObjectSetup* setup = AZ::Utils::LoadObjectFromBuffer(data.data(), data.size(), serializeContext, loadFilter); - setup->InitAfterLoad(m_actor.get()); + setup->InitAfterLoad(m_actorAsset->GetActor()); return setup; } @@ -80,4 +85,10 @@ namespace EMotionFX { return { "Bip01__pelvis", "l_upLeg", "l_loLeg", "l_ankle" }; } + + + Actor* ActorFixture::GetActor() + { + return m_actorAsset->GetActor(); + } } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/ActorFixture.h b/Gems/EMotionFX/Code/Tests/ActorFixture.h index 9fee056292..fad6a2c463 100644 --- a/Gems/EMotionFX/Code/Tests/ActorFixture.h +++ b/Gems/EMotionFX/Code/Tests/ActorFixture.h @@ -9,8 +9,7 @@ #pragma once #include "SystemComponentFixture.h" -#include - +#include namespace EMotionFX { @@ -31,7 +30,9 @@ namespace EMotionFX AZStd::vector GetTestJointNames() const; protected: - AutoRegisteredActor m_actor{}; + Actor* GetActor(); + + AZ::Data::Asset m_actorAsset; ActorInstance* m_actorInstance = nullptr; }; } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/AdditiveMotionSamplingTests.cpp b/Gems/EMotionFX/Code/Tests/AdditiveMotionSamplingTests.cpp index 4171598801..114d5c08fb 100644 --- a/Gems/EMotionFX/Code/Tests/AdditiveMotionSamplingTests.cpp +++ b/Gems/EMotionFX/Code/Tests/AdditiveMotionSamplingTests.cpp @@ -26,7 +26,7 @@ namespace EMotionFX public: void CreateSubMotionLikeBindPose(const std::string& name) { - const Skeleton* skeleton = m_actor->GetSkeleton(); + const Skeleton* skeleton = GetActor()->GetSkeleton(); size_t jointIndex = InvalidIndex; const Node* node = skeleton->FindNodeAndIndexByName(name.c_str(), jointIndex); ASSERT_NE(node, nullptr); @@ -40,7 +40,7 @@ namespace EMotionFX void CreateSubMotion(const std::string& name, const Transform& transform) { // Find and store the joint index. - const Skeleton* skeleton = m_actor->GetSkeleton(); + const Skeleton* skeleton = GetActor()->GetSkeleton(); size_t jointIndex = InvalidIndex; const Node* node = skeleton->FindNodeAndIndexByName(name.c_str(), jointIndex); ASSERT_NE(node, nullptr); @@ -55,7 +55,7 @@ namespace EMotionFX ActorFixture::SetUp(); // Get the joint that isn't in the motion data. - Node* footNode = m_actor->GetSkeleton()->FindNodeAndIndexByName("l_ball", m_footIndex); + Node* footNode = GetActor()->GetSkeleton()->FindNodeAndIndexByName("l_ball", m_footIndex); ASSERT_NE(footNode, nullptr); ASSERT_NE(m_footIndex, InvalidIndex32); @@ -98,7 +98,7 @@ namespace EMotionFX TEST_F(MotionSamplingFixture, SampleAdditiveJoint) { - const Skeleton* skeleton = m_actor->GetSkeleton(); + const Skeleton* skeleton = GetActor()->GetSkeleton(); // Sample the joints that exist in our actor skeleton as well as inside the motion data. const Pose* bindPose = m_actorInstance->GetTransformData()->GetBindPose(); @@ -106,7 +106,7 @@ namespace EMotionFX { // Sample the motion. Transform transform = Transform::CreateZero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that. - m_motion->CalcNodeTransform(m_motionInstance, &transform, m_actor.get(), skeleton->GetNode(jointIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false); + m_motion->CalcNodeTransform(m_motionInstance, &transform, GetActor(), skeleton->GetNode(jointIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false); const Transform& bindTransform = bindPose->GetLocalSpaceTransform(jointIndex); EXPECT_THAT(transform, IsClose(bindTransform)); @@ -114,7 +114,7 @@ namespace EMotionFX // Sample the motion for the foot node. Transform footTransform = Transform::CreateZero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that. - m_motion->CalcNodeTransform(m_motionInstance, &footTransform, m_actor.get(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false); + m_motion->CalcNodeTransform(m_motionInstance, &footTransform, GetActor(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false); // Make sure we get an identity transform back as we try to sample a node that doesn't have a submotion in an additive motion. EXPECT_THAT(footTransform, IsClose(Transform::CreateIdentity())); @@ -125,7 +125,7 @@ namespace EMotionFX // Make sure we do not get an identity transform back now that it is a non-additive motion. footTransform.Zero(); // Set all to Zero, not identity as this methods might return identity and we want to verify that. const Transform& expectedFootTransform = m_actorInstance->GetTransformData()->GetCurrentPose()->GetLocalSpaceTransform(m_footIndex); - m_motion->CalcNodeTransform(m_motionInstance, &footTransform, m_actor.get(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false); + m_motion->CalcNodeTransform(m_motionInstance, &footTransform, GetActor(), skeleton->GetNode(m_footIndex), /*timeValue=*/0.0f, /*enableRetargeting=*/false); EXPECT_THAT(footTransform, IsClose(expectedFootTransform)); } @@ -134,7 +134,7 @@ namespace EMotionFX // Sample a pose from the motion. Pose pose; pose.LinkToActorInstance(m_actorInstance); - pose.InitFromBindPose(m_actor.get()); + pose.InitFromBindPose(GetActor()); pose.Zero(); m_motion->Update(&pose, &pose, m_motionInstance); diff --git a/Gems/EMotionFX/Code/Tests/AnimGraphDeferredInitTests.cpp b/Gems/EMotionFX/Code/Tests/AnimGraphDeferredInitTests.cpp index 0449005659..4448deff27 100644 --- a/Gems/EMotionFX/Code/Tests/AnimGraphDeferredInitTests.cpp +++ b/Gems/EMotionFX/Code/Tests/AnimGraphDeferredInitTests.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Tests/BlendTreeRagdollNodeTests.cpp b/Gems/EMotionFX/Code/Tests/BlendTreeRagdollNodeTests.cpp index a01d333e95..4608917523 100644 --- a/Gems/EMotionFX/Code/Tests/BlendTreeRagdollNodeTests.cpp +++ b/Gems/EMotionFX/Code/Tests/BlendTreeRagdollNodeTests.cpp @@ -105,7 +105,7 @@ namespace EMotionFX TEST_P(RagdollRootNodeFixture, RagdollRootNodeIsSimulatedTests) { - Physics::RagdollConfiguration& ragdollConfig = m_actor->GetPhysicsSetup()->GetRagdollConfig(); + Physics::RagdollConfiguration& ragdollConfig = GetActor()->GetPhysicsSetup()->GetRagdollConfig(); AZStd::vector& ragdollNodes = ragdollConfig.m_nodes; const RagdollRootNodeParam& param = GetParam(); const AZStd::string ragdollRootNodeName = param.m_ragdollRootNode.c_str(); diff --git a/Gems/EMotionFX/Code/Tests/ColliderCommandTests.cpp b/Gems/EMotionFX/Code/Tests/ColliderCommandTests.cpp index 6314253eee..a6cadc5c2f 100644 --- a/Gems/EMotionFX/Code/Tests/ColliderCommandTests.cpp +++ b/Gems/EMotionFX/Code/Tests/ColliderCommandTests.cpp @@ -24,13 +24,13 @@ namespace EMotionFX CommandSystem::CommandManager commandManager; MCore::CommandGroup commandGroup; - const AZ::u32 actorId = m_actor->GetID(); + const AZ::u32 actorId = GetActor()->GetID(); const AZStd::vector jointNames = GetTestJointNames(); const size_t jointCount = jointNames.size(); // 1. Add colliders - const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(GetActor()); for (const AZStd::string& jointName : jointNames) { CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid(), &commandGroup); @@ -39,23 +39,27 @@ namespace EMotionFX } EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - const AZStd::string serializedAfterAdd = SerializePhysicsSetup(m_actor.get()); - EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(jointCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); + const AZStd::string serializedAfterAdd = SerializePhysicsSetup(GetActor()); + EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ( + jointCount, + PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Box)); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(GetActor())); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(jointCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); - EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ( + jointCount, + PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Box)); + EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(GetActor())); // 2. Remove colliders commandGroup.RemoveAllCommands(); - const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(GetActor()); size_t colliderIndexToRemove = 1; for (const AZStd::string& jointName : jointNames) @@ -64,18 +68,24 @@ namespace EMotionFX } EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - const AZStd::string serializedAfterRemove = SerializePhysicsSetup(m_actor.get()); - EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Capsule)); + const AZStd::string serializedAfterRemove = SerializePhysicsSetup(GetActor()); + EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ( + 0, + PhysicsSetupUtils::CountColliders( + GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Capsule)); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(GetActor())); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Capsule)); - EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ( + 0, + PhysicsSetupUtils::CountColliders( + GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Capsule)); + EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(GetActor())); } TEST_F(ColliderCommandTests, AddRemove1000Colliders) @@ -84,11 +94,11 @@ namespace EMotionFX CommandSystem::CommandManager commandManager; MCore::CommandGroup commandGroup; - const AZ::u32 actorId = m_actor->GetID(); + const AZ::u32 actorId = GetActor()->GetID(); const AZStd::string jointName = "Bip01__pelvis"; // 1. Add colliders - const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(GetActor()); const size_t colliderCount = 1000; for (AZ::u32 i = 0; i < colliderCount; ++i) { @@ -96,51 +106,51 @@ namespace EMotionFX } EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - const AZStd::string serializedAfterAdd = SerializePhysicsSetup(m_actor.get()); - EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); + const AZStd::string serializedAfterAdd = SerializePhysicsSetup(GetActor()); + EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(GetActor())); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); - EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); + EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(GetActor())); // 2. Clear colliders commandGroup.RemoveAllCommands(); - const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(GetActor()); CommandColliderHelpers::ClearColliders(actorId, jointName, PhysicsSetup::HitDetection, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - const AZStd::string serializedAfterRemove = SerializePhysicsSetup(m_actor.get()); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); + const AZStd::string serializedAfterRemove = SerializePhysicsSetup(GetActor()); + EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(GetActor())); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection)); - EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); - EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(m_actor.get())); + EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection)); + EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box)); + EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(GetActor())); } TEST_F(ColliderCommandTests, AutoSizingColliders) { CommandSystem::CommandManager commandManager; - const AZ::u32 actorId = m_actor->GetID(); + const AZ::u32 actorId = GetActor()->GetID(); const AZStd::vector jointNames = GetTestJointNames(); ASSERT_TRUE(jointNames.size() > 0) << "The joint names test data needs at least one joint for this test."; const AZStd::string& jointName = jointNames[0]; CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid()); - const AZStd::shared_ptr& physicsSetup = m_actor->GetPhysicsSetup(); + const AZStd::shared_ptr& physicsSetup = GetActor()->GetPhysicsSetup(); Physics::CharacterColliderConfiguration* colliderConfig = physicsSetup->GetColliderConfigByType(PhysicsSetup::HitDetection); EXPECT_NE(colliderConfig, nullptr) << "Collider config should be valid after we added a collider to it."; @@ -184,11 +194,11 @@ namespace EMotionFX const PhysicsSetup::ColliderConfigType m_configType = PhysicsSetup::ColliderConfigType::HitDetection; // Add collider to the given joint first. - const AZStd::shared_ptr& physicsSetup = m_actor->GetPhysicsSetup(); - EXPECT_TRUE(CommandColliderHelpers::AddCollider(m_actor->GetID(), m_jointName, m_configType, param.m_shapeType)); + const AZStd::shared_ptr& physicsSetup = GetActor()->GetPhysicsSetup(); + EXPECT_TRUE(CommandColliderHelpers::AddCollider(GetActor()->GetID(), m_jointName, m_configType, param.m_shapeType)); Physics::CharacterColliderConfiguration* characterColliderConfig = physicsSetup->GetColliderConfigByType(m_configType); ASSERT_TRUE(characterColliderConfig != nullptr); - Physics::CharacterColliderNodeConfiguration* nodeConfig = CommandColliderHelpers::GetCreateNodeConfig(m_actor.get(), m_jointName, *characterColliderConfig, result); + Physics::CharacterColliderNodeConfiguration* nodeConfig = CommandColliderHelpers::GetCreateNodeConfig(GetActor(), m_jointName, *characterColliderConfig, result); ASSERT_TRUE(nodeConfig != nullptr); EXPECT_EQ(nodeConfig->m_shapes.size(), 1); @@ -200,7 +210,8 @@ namespace EMotionFX // Create the adjust collider command and using the data from the test parameter. MCore::Command* orgCommand = CommandSystem::GetCommandManager()->FindCommand(CommandAdjustCollider::s_commandName); - CommandAdjustCollider* command = aznew CommandAdjustCollider(m_actor->GetID(), m_jointName, m_configType, /*colliderIndex=*/0, orgCommand); + CommandAdjustCollider* command = + aznew CommandAdjustCollider(GetActor()->GetID(), m_jointName, m_configType, /*colliderIndex=*/0, orgCommand); command->SetOldIsTrigger(colliderConfig->m_isTrigger); command->SetIsTrigger(param.m_isTrigger); command->SetOldPosition(colliderConfig->m_position); @@ -223,9 +234,9 @@ namespace EMotionFX } // Check execute. - const AZStd::string serializedBeforeExecute = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedBeforeExecute = SerializePhysicsSetup(GetActor()); EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(command, result)); - const AZStd::string serializedAfterExecute = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedAfterExecute = SerializePhysicsSetup(GetActor()); EXPECT_EQ(colliderConfig->m_isTrigger, param.m_isTrigger); EXPECT_EQ(colliderConfig->m_position, param.m_position); @@ -243,12 +254,12 @@ namespace EMotionFX // Check undo. EXPECT_TRUE(CommandSystem::GetCommandManager()->Undo(result)); - const AZStd::string serializedAfterUndo = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedAfterUndo = SerializePhysicsSetup(GetActor()); EXPECT_EQ(serializedAfterUndo, serializedBeforeExecute); // Check redo. EXPECT_TRUE(CommandSystem::GetCommandManager()->Redo(result)); - const AZStd::string serializedAfterRedo = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedAfterRedo = SerializePhysicsSetup(GetActor()); EXPECT_EQ(serializedAfterRedo, serializedAfterExecute); } diff --git a/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp index 31e1f75d29..0c3228567e 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp @@ -13,9 +13,11 @@ #include #include +#include +#include #include #include -#include +#include namespace EMotionFX { @@ -33,14 +35,12 @@ namespace EMotionFX ASSERT_EQ(GetActorManager().GetNumActors(), 0); // Load an Actor - const char* actorCmd{ "ImportActor -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" }; - { - AZStd::string result; - EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(actorCmd, result)) << result.c_str(); - } + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, "Jack"); // Ensure the Actor is correct - ASSERT_TRUE(GetActorManager().FindActorByName("rinActor")); + ASSERT_TRUE(GetActorManager().FindActorByName("Jack")); EXPECT_EQ(GetActorManager().GetNumActors(), 1); } } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/MotionExtractionBusTests.cpp b/Gems/EMotionFX/Code/Tests/MotionExtractionBusTests.cpp index 170f4d2d75..347d8f93a8 100644 --- a/Gems/EMotionFX/Code/Tests/MotionExtractionBusTests.cpp +++ b/Gems/EMotionFX/Code/Tests/MotionExtractionBusTests.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Tests/MultiThreadSchedulerTests.cpp b/Gems/EMotionFX/Code/Tests/MultiThreadSchedulerTests.cpp index 180da46746..02622ecd67 100644 --- a/Gems/EMotionFX/Code/Tests/MultiThreadSchedulerTests.cpp +++ b/Gems/EMotionFX/Code/Tests/MultiThreadSchedulerTests.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphActivateTests.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphActivateTests.cpp index 78cac409a6..dea332b40e 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphActivateTests.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphActivateTests.cpp @@ -19,11 +19,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include namespace EMotionFX @@ -78,7 +80,8 @@ namespace EMotionFX EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommandGroup(group, commandResult)) << commandResult.c_str(); // Create temp Actor - m_actor = ActorFactory::CreateAndInit(1, "tempActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 1, "tempActor"); // Cache some local poitners. m_animGraphPlugin = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::AnimGraphPlugin::CLASS_ID)); @@ -90,6 +93,7 @@ namespace EMotionFX void TearDown() override { + GetEMotionFX().GetActorManager()->UnregisterAllActors(); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); delete m_animGraph; UIFixture::TearDown(); @@ -104,7 +108,7 @@ namespace EMotionFX AZStd::string m_entryNodeName = "testEntry"; AnimGraph* m_animGraph = nullptr; EMStudio::AnimGraphPlugin* m_animGraphPlugin = nullptr; - AutoRegisteredActor m_actor; + AZ::Data::Asset m_actorAsset; }; TEST_F(PopulatedAnimGraphFixture, CanActivateValidGraph) diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphModelTests.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphModelTests.cpp index 4ffc9e0097..b9b96bb59c 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphModelTests.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/AnimGraphModelTests.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,7 @@ #include #include #include +#include #include namespace EMotionFX @@ -423,7 +423,10 @@ namespace EMotionFX using testing::Eq; using testing::Not; - AutoRegisteredActor actor = EMotionFX::ActorFactory::CreateAndInit(1); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 1); + auto motionSet = AZStd::make_unique(); { @@ -432,7 +435,7 @@ namespace EMotionFX } auto* animGraph = EMotionFX::GetAnimGraphManager().FindAnimGraphByID(0); - auto* actorInstance = EMotionFX::ActorInstance::Create(actor.get()); + auto* actorInstance = EMotionFX::ActorInstance::Create(actorAsset->GetActor()); auto* animGraphInstance = EMotionFX::AnimGraphInstance::Create(animGraph, actorInstance, motionSet.get()); actorInstance->SetAnimGraphInstance(animGraphInstance); diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp index d53ddcc924..c374938590 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp @@ -24,12 +24,11 @@ #include #include -#include #include #include +#include #include - namespace EMotionFX { @@ -58,8 +57,10 @@ namespace EMotionFX ASSERT_EQ(GetMotionManager().GetNumMotions(), 0) << "Expected exactly zero motions"; // Create Actor, AnimGraph, Motionset and Motion - AutoRegisteredActor actor = ActorFactory::CreateAndInit(2, "SampleActor"); - ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 2, "SampleActor"); + ActorInstance::Create(actorAsset->GetActor()); { AZStd::string result; ASSERT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(createAnimGraphCmd, result)) << result.c_str(); diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp index 4f43e7dae5..17f07b2180 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteColliders.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace EMotionFX @@ -79,7 +80,11 @@ namespace EMotionFX TEST_F(CopyPasteRagdollCollidersFixture, CanCopyCollider) #endif // AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS { - AutoRegisteredActor actor{ActorFactory::CreateAndInit(4)}; + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 4); + const Actor* actor = actorAsset->GetActor(); + const Physics::RagdollConfiguration& ragdollConfig = actor->GetPhysicsSetup()->GetRagdollConfig(); const Physics::CharacterColliderConfiguration& simulatedObjectConfig = actor->GetPhysicsSetup()->GetSimulatedObjectColliderConfig(); @@ -104,8 +109,7 @@ namespace EMotionFX { AZStd::string result; - EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand( - "Select -actorId " + AZStd::to_string(actor->GetID()), + EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand("Select -actorId " + AZStd::to_string(actor->GetID()), result)) << result.c_str(); } diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp index 8e4fba0dd6..3f475c7916 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Ragdoll/CanCopyPasteJointLimits.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -25,6 +24,7 @@ #include #include #include +#include #include namespace EMotionFX @@ -76,7 +76,9 @@ namespace EMotionFX return AZStd::make_unique(); }); - AutoRegisteredActor actor {ActorFactory::CreateAndInit(4)}; + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 4); + const Actor* actor = actorAsset->GetActor(); { AZStd::string result; diff --git a/Gems/EMotionFX/Code/Tests/RagdollCommandTests.cpp b/Gems/EMotionFX/Code/Tests/RagdollCommandTests.cpp index e9a4cc0c26..1004b0a1f6 100644 --- a/Gems/EMotionFX/Code/Tests/RagdollCommandTests.cpp +++ b/Gems/EMotionFX/Code/Tests/RagdollCommandTests.cpp @@ -99,28 +99,28 @@ namespace EMotionFX "l_hand", }; - CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_shldr"}, &commandGroup); + CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_shldr"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise( StrEq(), jointsToLeftShoulder ) ); - const AZStd::string serializedBeforeHandAdded = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedBeforeHandAdded = SerializePhysicsSetup(GetActor()); // Adding l_hand should add l_upArm and l_loArm as well commandGroup.RemoveAllCommands(); - CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup); + CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); - const AZStd::string serializedAfterHandAdded = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedAfterHandAdded = SerializePhysicsSetup(GetActor()); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise( StrEq(), jointsToLeftHand @@ -129,23 +129,23 @@ namespace EMotionFX EXPECT_TRUE(commandManager.Undo(result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise( StrEq(), jointsToLeftShoulder ) ); - EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedBeforeHandAdded)); + EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedBeforeHandAdded)); EXPECT_TRUE(commandManager.Redo(result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise( StrEq(), jointsToLeftHand ) ); - EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedAfterHandAdded)); + EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedAfterHandAdded)); } TEST_F(RagdollCommandTests, AddJointHigherInHierarchy) @@ -166,10 +166,10 @@ namespace EMotionFX "l_hand", }; - CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup); + CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise( StrEq(), jointsToLeftHand @@ -178,10 +178,10 @@ namespace EMotionFX // l_shldr should already be in the ragdoll, so adding it should do nothing commandGroup.RemoveAllCommands(); - CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_shldr"}, &commandGroup); + CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_shldr"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise( StrEq(), jointsToLeftHand @@ -190,11 +190,11 @@ namespace EMotionFX // Undo here undoes the addition of l_hand EXPECT_TRUE(commandManager.Undo(result)) << result.c_str(); - EXPECT_TRUE(GetRagdollJointNames(m_actor.get()).empty()); + EXPECT_TRUE(GetRagdollJointNames(GetActor()).empty()); EXPECT_TRUE(commandManager.Redo(result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise( StrEq(), jointsToLeftHand @@ -221,16 +221,16 @@ namespace EMotionFX }; // Add a joint to the ragdoll that does not make a chain all the way to the root - EXPECT_TRUE(commandManager.ExecuteCommand(aznew CommandAddRagdollJoint(m_actor->GetID(), "l_shldr"), result)) << result.c_str(); + EXPECT_TRUE(commandManager.ExecuteCommand(aznew CommandAddRagdollJoint(GetActor()->GetID(), "l_shldr"), result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise(StrEq(), AZStd::vector{"l_shldr"}) ); - CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup); + CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise(StrEq(), jointsToLeftHand) ); } @@ -250,17 +250,17 @@ namespace EMotionFX }; // Add joints from the root to the left hand - CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup); + CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); // Removing the left shoulder should remove the elbow, wrist, and hand // as well commandGroup.RemoveAllCommands(); - CommandRagdollHelpers::RemoveJointsFromRagdoll(m_actor->GetID(), {"l_shldr"}, &commandGroup); + CommandRagdollHelpers::RemoveJointsFromRagdoll(GetActor()->GetID(), {"l_shldr"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); EXPECT_THAT( - GetRagdollJointNames(m_actor.get()), + GetRagdollJointNames(GetActor()), testing::UnorderedPointwise(StrEq(), jointsToSpine3) ); } @@ -271,24 +271,24 @@ namespace EMotionFX CommandSystem::CommandManager commandManager; MCore::CommandGroup commandGroup; - CommandRagdollHelpers::AddJointsToRagdoll(m_actor->GetID(), {"l_hand"}, &commandGroup); + CommandRagdollHelpers::AddJointsToRagdoll(GetActor()->GetID(), {"l_hand"}, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)) << result.c_str(); - const AZStd::string serializedBeforeSphereAdded = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedBeforeSphereAdded = SerializePhysicsSetup(GetActor()); - CommandColliderHelpers::AddCollider(m_actor->GetID(), "l_hand", + CommandColliderHelpers::AddCollider(GetActor()->GetID(), "l_hand", PhysicsSetup::Ragdoll, azrtti_typeid()); - const AZStd::string serializedAfterSphereAdded = SerializePhysicsSetup(m_actor.get()); + const AZStd::string serializedAfterSphereAdded = SerializePhysicsSetup(GetActor()); EXPECT_THAT(serializedAfterSphereAdded, ::testing::Not(StrEq(serializedBeforeSphereAdded))); EXPECT_TRUE(commandManager.Undo(result)) << result.c_str(); - EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedBeforeSphereAdded)); + EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedBeforeSphereAdded)); EXPECT_TRUE(commandManager.Redo(result)) << result.c_str(); - EXPECT_THAT(SerializePhysicsSetup(m_actor.get()), StrEq(serializedAfterSphereAdded)); + EXPECT_THAT(SerializePhysicsSetup(GetActor()), StrEq(serializedAfterSphereAdded)); } } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/SimulatedObjectCommandTests.cpp b/Gems/EMotionFX/Code/Tests/SimulatedObjectCommandTests.cpp index 4bac70c13d..dab761f649 100644 --- a/Gems/EMotionFX/Code/Tests/SimulatedObjectCommandTests.cpp +++ b/Gems/EMotionFX/Code/Tests/SimulatedObjectCommandTests.cpp @@ -55,25 +55,25 @@ namespace EMotionFX CommandSystem::CommandManager commandManager; MCore::CommandGroup commandGroup; - const uint32 actorId = m_actor->GetID(); + const uint32 actorId = GetActor()->GetID(); const AZStd::vector jointNames = GetTestJointNames(); // 1. Add simulated object. - const AZStd::string serializedBeforeAdd = SerializeSimulatedObjectSetup(m_actor.get()); + const AZStd::string serializedBeforeAdd = SerializeSimulatedObjectSetup(GetActor()); CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup); CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup); CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - const AZStd::string serializedAfterAdd = SerializeSimulatedObjectSetup(m_actor.get()); - EXPECT_EQ(3, CountSimulatedObjects(m_actor.get())); + const AZStd::string serializedAfterAdd = SerializeSimulatedObjectSetup(GetActor()); + EXPECT_EQ(3, CountSimulatedObjects(GetActor())); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(0, CountSimulatedObjects(m_actor.get())); - EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(0, CountSimulatedObjects(GetActor())); + EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(GetActor())); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(3, CountSimulatedObjects(m_actor.get())); - EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(3, CountSimulatedObjects(GetActor())); + EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(GetActor())); // 2. Remove simulated object. commandGroup.RemoveAllCommands(); @@ -81,22 +81,22 @@ namespace EMotionFX CommandSimulatedObjectHelpers::RemoveSimulatedObject(actorId, 0, &commandGroup); CommandSimulatedObjectHelpers::RemoveSimulatedObject(actorId, 0, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - EXPECT_EQ(0, CountSimulatedObjects(m_actor.get())); - EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(0, CountSimulatedObjects(GetActor())); + EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(GetActor())); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(3, CountSimulatedObjects(m_actor.get())); - EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(3, CountSimulatedObjects(GetActor())); + EXPECT_EQ(serializedAfterAdd, SerializeSimulatedObjectSetup(GetActor())); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(0, CountSimulatedObjects(m_actor.get())); - EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(0, CountSimulatedObjects(GetActor())); + EXPECT_EQ(serializedBeforeAdd, SerializeSimulatedObjectSetup(GetActor())); // 3. Add simulated joints. // 3.1 Add a simulated object first to put in the simulated joints. commandGroup.RemoveAllCommands(); CommandSimulatedObjectHelpers::AddSimulatedObject(actorId); - const AZStd::string serialized3_1 = SerializeSimulatedObjectSetup(m_actor.get()); + const AZStd::string serialized3_1 = SerializeSimulatedObjectSetup(GetActor()); // 3.2 Add simulated joints. // Joint hierarchy as follow: @@ -105,7 +105,7 @@ namespace EMotionFX // --l_loLeg // --l_ankle // --l_ball - const Skeleton* skeleton = m_actor->GetSkeleton(); + const Skeleton* skeleton = GetActor()->GetSkeleton(); const size_t l_upLegIdx = skeleton->FindNodeByName("l_upLeg")->GetNodeIndex(); const size_t l_upLegRollIdx = skeleton->FindNodeByName("l_upLegRoll")->GetNodeIndex(); const size_t l_loLegIdx = skeleton->FindNodeByName("l_loLeg")->GetNodeIndex(); @@ -113,33 +113,33 @@ namespace EMotionFX const size_t l_ballIdx = skeleton->FindNodeByName("l_ball")->GetNodeIndex(); CommandSimulatedObjectHelpers::AddSimulatedJoints(actorId, {l_upLegIdx, l_upLegRollIdx, l_loLegIdx, l_ankleIdx, l_ballIdx}, 0, false, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - const AZStd::string serialized3_2 = SerializeSimulatedObjectSetup(m_actor.get()); - EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(2, CountChildJoints(m_actor.get(), 0, l_upLegIdx)); - EXPECT_EQ(0, CountChildJoints(m_actor.get(), 0, l_upLegRollIdx)); - EXPECT_EQ(1, CountChildJoints(m_actor.get(), 0, l_loLegIdx)); + const AZStd::string serialized3_2 = SerializeSimulatedObjectSetup(GetActor()); + EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(2, CountChildJoints(GetActor(), 0, l_upLegIdx)); + EXPECT_EQ(0, CountChildJoints(GetActor(), 0, l_upLegRollIdx)); + EXPECT_EQ(1, CountChildJoints(GetActor(), 0, l_loLegIdx)); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(GetActor())); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(GetActor())); // 4 Remove simulated joints. // 4.1 Test sparse chain. - EXPECT_EQ(1, CountRootJoints(m_actor.get(), 0)); + EXPECT_EQ(1, CountRootJoints(GetActor(), 0)); commandGroup.RemoveAllCommands(); CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, {l_loLegIdx}, 0, false, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - EXPECT_EQ(2, CountRootJoints(m_actor.get(), 0)); + EXPECT_EQ(2, CountRootJoints(GetActor(), 0)); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(1, CountRootJoints(m_actor.get(), 0)); + EXPECT_EQ(1, CountRootJoints(GetActor(), 0)); EXPECT_TRUE(commandManager.Redo(result)); - EXPECT_EQ(2, CountRootJoints(m_actor.get(), 0)); + EXPECT_EQ(2, CountRootJoints(GetActor(), 0)); EXPECT_TRUE(commandManager.Undo(result)); @@ -147,23 +147,23 @@ namespace EMotionFX commandGroup.RemoveAllCommands(); CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, { l_upLegIdx, l_upLegRollIdx, l_loLegIdx, l_ankleIdx, l_ballIdx }, 0, false, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(GetActor())); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(GetActor())); // 4.3 Test removing the root joint and children. commandGroup.RemoveAllCommands(); CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, { l_upLegIdx }, 0, true, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serialized3_1, SerializeSimulatedObjectSetup(GetActor())); EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(5, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(5, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serialized3_2, SerializeSimulatedObjectSetup(GetActor())); } TEST_F(SimulatedObjectCommandTests, SimulatedObjectCommands_UndoRemoveJointTest) @@ -172,35 +172,35 @@ namespace EMotionFX CommandSystem::CommandManager commandManager; MCore::CommandGroup commandGroup; - const uint32 actorId = m_actor->GetID(); + const uint32 actorId = GetActor()->GetID(); const AZStd::vector jointNames = GetTestJointNames(); // 1. Add simulated object CommandSimulatedObjectHelpers::AddSimulatedObject(actorId, AZStd::nullopt, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - const AZStd::string serializedBase = SerializeSimulatedObjectSetup(m_actor.get()); + const AZStd::string serializedBase = SerializeSimulatedObjectSetup(GetActor()); const size_t simulatedObjectIndex = 0; // 2. Add r_upLeg simulated joints - const Skeleton* skeleton = m_actor->GetSkeleton(); + const Skeleton* skeleton = GetActor()->GetSkeleton(); const size_t r_upLegIdx = skeleton->FindNodeByName("r_upLeg")->GetNodeIndex(); const size_t r_loLegIdx = skeleton->FindNodeByName("r_loLeg")->GetNodeIndex(); CommandSimulatedObjectHelpers::AddSimulatedJoints(actorId, { r_upLegIdx, r_loLegIdx }, 0, false); - EXPECT_EQ(2, CountSimulatedJoints(m_actor.get(), 0)); - const AZStd::string serializedUpLeg = SerializeSimulatedObjectSetup(m_actor.get()); + EXPECT_EQ(2, CountSimulatedJoints(GetActor(), 0)); + const AZStd::string serializedUpLeg = SerializeSimulatedObjectSetup(GetActor()); // 3. Remove the r_loLeg simulated joint AZStd::vector jointsToBeRemoved; commandGroup.RemoveAllCommands(); CommandSimulatedObjectHelpers::RemoveSimulatedJoints(actorId, { r_upLegIdx }, simulatedObjectIndex, true, &commandGroup); EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result)); - EXPECT_EQ(0, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serializedBase, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(0, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serializedBase, SerializeSimulatedObjectSetup(GetActor())); // 4. Undo // This recreates r_loLeg and r_loLeg but won't add all other children recursively as only these two joints got aded in step 3. EXPECT_TRUE(commandManager.Undo(result)); - EXPECT_EQ(2, CountSimulatedJoints(m_actor.get(), 0)); - EXPECT_EQ(serializedUpLeg, SerializeSimulatedObjectSetup(m_actor.get())); + EXPECT_EQ(2, CountSimulatedJoints(GetActor(), 0)); + EXPECT_EQ(serializedUpLeg, SerializeSimulatedObjectSetup(GetActor())); } } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/SimulatedObjectModelTests.cpp b/Gems/EMotionFX/Code/Tests/SimulatedObjectModelTests.cpp index 41269cec77..85da96412b 100644 --- a/Gems/EMotionFX/Code/Tests/SimulatedObjectModelTests.cpp +++ b/Gems/EMotionFX/Code/Tests/SimulatedObjectModelTests.cpp @@ -22,17 +22,21 @@ #include #include #include +#include namespace EMotionFX { using SimulatedObjectModelTestsFixture = UIFixture; TEST_F(SimulatedObjectModelTestsFixture, CanUndoAddSimulatedObjectAndSimulatedJointWithChildren) { - AutoRegisteredActor actor = ActorFactory::CreateAndInit(3, "simulatedObjectModelTestActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 3, "simulatedObjectModelTestActor"); + const Actor* actor = actorAsset->GetActor(); EMotionFX::SimulatedObjectWidget* simulatedObjectWidget = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMotionFX::SimulatedObjectWidget::CLASS_ID)); ASSERT_TRUE(simulatedObjectWidget) << "Simulated Object plugin not loaded"; - simulatedObjectWidget->ActorSelectionChanged(actor.get()); + simulatedObjectWidget->ActorSelectionChanged(actorAsset->GetActor()); SimulatedObjectModel* model = simulatedObjectWidget->GetSimulatedObjectModel(); diff --git a/Gems/EMotionFX/Code/Tests/SimulatedObjectSerializeTests.cpp b/Gems/EMotionFX/Code/Tests/SimulatedObjectSerializeTests.cpp index c261f63bc1..e5c2c5ce4f 100644 --- a/Gems/EMotionFX/Code/Tests/SimulatedObjectSerializeTests.cpp +++ b/Gems/EMotionFX/Code/Tests/SimulatedObjectSerializeTests.cpp @@ -20,7 +20,7 @@ namespace EMotionFX TEST_F(SimulatedObjectSerializeTests, SerializeTest) { - SimulatedObjectSetup* setup = m_actor->GetSimulatedObjectSetup().get(); + SimulatedObjectSetup* setup = GetActor()->GetSimulatedObjectSetup().get(); // Build some setup. SimulatedObject* object = setup->AddSimulatedObject(); @@ -29,7 +29,7 @@ namespace EMotionFX object->SetGravityFactor(3.0f); object->SetStiffnessFactor(4.0f); const AZStd::vector jointNames = { "l_upArm", "l_loArm", "l_hand" }; - Skeleton* skeleton = m_actor->GetSkeleton(); + Skeleton* skeleton = GetActor()->GetSkeleton(); for (const AZStd::string& name : jointNames) { size_t skeletonJointIndex; @@ -50,7 +50,7 @@ namespace EMotionFX object->GetSimulatedJoint(0)->SetPinned(true); // Serialize it and deserialize it. - const AZStd::string serialized = SerializeSimulatedObjectSetup(m_actor.get()); + const AZStd::string serialized = SerializeSimulatedObjectSetup(GetActor()); AZStd::unique_ptr loadedSetup(DeserializeSimulatedObjectSetup(serialized)); // Verify some of the contents of the deserialized version. diff --git a/Gems/EMotionFX/Code/Tests/SkeletalLODTests.cpp b/Gems/EMotionFX/Code/Tests/SkeletalLODTests.cpp index 1252eb36ae..54a81cb559 100644 --- a/Gems/EMotionFX/Code/Tests/SkeletalLODTests.cpp +++ b/Gems/EMotionFX/Code/Tests/SkeletalLODTests.cpp @@ -22,13 +22,13 @@ namespace EMotionFX void SetUp() { ActorFixture::SetUp(); - m_actor->AddLODLevel(); + GetActor()->AddLODLevel(); DisableJointsForLOD(m_disabledJointNames, 1); } void DisableJointsForLOD(const std::vector& jointNames, size_t lodLevel) { - const Skeleton* skeleton = m_actor->GetSkeleton(); + const Skeleton* skeleton = GetActor()->GetSkeleton(); for (const std::string& jointName : jointNames) { Node* joint = skeleton->FindNodeByName(jointName.c_str()); diff --git a/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.cpp b/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.cpp index 6375d48c6b..bb3c4f76e2 100644 --- a/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.cpp +++ b/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.cpp @@ -10,9 +10,10 @@ #include #include #include -#include #include #include +#include +#include namespace EMotionFX { diff --git a/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.h b/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.h index 3a041fcf34..5b75ddf590 100644 --- a/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.h +++ b/Gems/EMotionFX/Code/Tests/TestAssetCode/TestActorAssets.h @@ -10,6 +10,9 @@ #include #include +#include +#include +#include namespace EMotionFX { @@ -18,5 +21,14 @@ namespace EMotionFX public: static AZStd::string FileToBase64(const char* filePath); static AZ::Data::Asset GetAssetFromActor(const AZ::Data::AssetId& assetId, AZStd::unique_ptr&& actor); + + template + static AZ::Data::Asset CreateActorAssetAndRegister(const AZ::Data::AssetId& assetId, Args&&... args) + { + AZStd::unique_ptr actor = ActorFactory::CreateAndInit(AZStd::forward(args)...); + AZ::Data::Asset actorAsset = TestActorAssets::GetAssetFromActor(assetId, AZStd::move(actor)); + GetEMotionFX().GetActorManager()->RegisterActor(actorAsset); + return AZStd::move(actorAsset); + } }; } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/UI/CanAddJointAndChildren.cpp b/Gems/EMotionFX/Code/Tests/UI/CanAddJointAndChildren.cpp index 59506a9d43..32240ba409 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanAddJointAndChildren.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanAddJointAndChildren.cpp @@ -16,13 +16,13 @@ #include #include -#include #include #include #include #include #include +#include namespace EMotionFX { @@ -37,8 +37,11 @@ namespace EMotionFX RecordProperty("test_case_id", "C13048819"); // Create an actor - AutoRegisteredActor actor = ActorFactory::CreateAndInit(5, "SimpleActor"); - ActorInstance* actorInstance = ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 5, "SimpleActor"); + ActorInstance* actorInstance = ActorInstance::Create(actorAsset->GetActor()); + const Actor* actor = actorAsset->GetActor(); // Open simulated objects layout EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); diff --git a/Gems/EMotionFX/Code/Tests/UI/CanAddSimulatedObject.cpp b/Gems/EMotionFX/Code/Tests/UI/CanAddSimulatedObject.cpp index e1c4525a9e..0820895db8 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanAddSimulatedObject.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanAddSimulatedObject.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include #include +#include #include #include @@ -81,9 +81,9 @@ namespace EMotionFX inputDialog->accept(); // There is one and only one simulated objects - ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 1); + ASSERT_EQ(m_actorAsset->GetActor()->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 1); // Check it has the correct name - EXPECT_STREQ(m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(0)->GetName().c_str(), objectName); + EXPECT_STREQ(m_actorAsset->GetActor()->GetSimulatedObjectSetup()->GetSimulatedObject(0)->GetName().c_str(), objectName); } @@ -112,14 +112,16 @@ namespace EMotionFX }); ASSERT_NE(addCapsuleColliderAction, addSelectedColliderMenuActions.end()); - size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); + size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders( + m_actorAsset->GetActor(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); (*addCapsuleColliderAction)->trigger(); // Delete the context menu, otherwise there it will still be around during this frame as the Qt event loop has not been run. delete contextMenu; - const size_t numCapsuleCollidersAfterAdd = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); + const size_t numCapsuleCollidersAfterAdd = PhysicsSetupUtils::CountColliders( + m_actorAsset->GetActor(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); ASSERT_EQ(numCapsuleCollidersAfterAdd, numCapsuleColliders + 1); @@ -127,7 +129,7 @@ namespace EMotionFX } protected: - AutoRegisteredActor m_actor; + AZ::Data::Asset m_actorAsset; EMotionFX::SimulatedObjectWidget* m_simulatedObjectWidget = nullptr; EMotionFX::SkeletonOutlinerPlugin* m_skeletonOutliner = nullptr; @@ -144,7 +146,8 @@ namespace EMotionFX { RecordProperty("test_case_id", "C13048820"); - m_actor = ActorFactory::CreateAndInit(1, "CanAddSimulatedObjectActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 1, "CanAddSimulatedObjectActor"); CreateSimulateObject("New simulated object"); } @@ -153,9 +156,11 @@ namespace EMotionFX { RecordProperty("test_case_id", "C13048818"); - AutoRegisteredActor actor = ActorFactory::CreateAndInit(2, "CanAddSimulatedObjectWithJointsActor"); - - ActorInstance* actorInstance = ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 2, "CanAddSimulatedObjectWithJointsActor"); + Actor* actor = actorAsset->GetActor(); + ActorInstance* actorInstance = ActorInstance::Create(actor); EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); @@ -216,7 +221,9 @@ namespace EMotionFX { RecordProperty("test_case_id", "C13048820a"); - m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 5, "CanAddSimulatedObjectActor"); + Actor* actor = m_actorAsset->GetActor(); CreateSimulateObject("sim1"); @@ -261,8 +268,8 @@ namespace EMotionFX inputDialog->SetText("sim2"); inputDialog->accept(); - ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 2); - const auto simulatedObject = m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(1); + ASSERT_EQ(actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 2); + const auto simulatedObject = actor->GetSimulatedObjectSetup()->GetSimulatedObject(1); EXPECT_STREQ(simulatedObject->GetName().c_str(), "sim2"); } @@ -270,7 +277,9 @@ namespace EMotionFX { RecordProperty("test_case_id", "C13048816"); - m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 5, "CanAddSimulatedObjectActor"); + Actor* actor = m_actorAsset->GetActor(); CreateSimulateObject("sim1"); @@ -301,25 +310,25 @@ namespace EMotionFX QAction* addCapsuleColliderAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addCapsuleColliderAction, addSelectedColliderMenu, "Capsule")); - size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); + size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); EXPECT_EQ(numCapsuleColliders, 0); addCapsuleColliderAction->trigger(); // Check that a collider has been added. - size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); + size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); ASSERT_EQ(numCollidersAfterAddCapsule, numCapsuleColliders + 1) << "Capsule collider not added."; QAction* addSphereColliderAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addSphereColliderAction, addSelectedColliderMenu, "Sphere")); - const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); + const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); EXPECT_EQ(numSphereColliders, 0); addSphereColliderAction->trigger(); // Check that a second collider has been added. - const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); + const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); ASSERT_EQ(numCollidersAfterAddSphere, numSphereColliders + 1) << "Sphere collider not added."; } @@ -327,7 +336,9 @@ namespace EMotionFX { RecordProperty("test_case_id", "C13048821"); - m_actor = ActorFactory::CreateAndInit(1, "CanRemoveSimulatedObjectActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 1, "CanRemoveSimulatedObjectActor"); + Actor* actor = m_actorAsset->GetActor(); CreateSimulateObject("TestObject1"); @@ -350,14 +361,16 @@ namespace EMotionFX ASSERT_TRUE(UIFixture::GetActionFromContextMenu(removeObjectAction, contextMenu, "Remove object")); removeObjectAction->trigger(); - ASSERT_EQ(m_actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 0); + ASSERT_EQ(actor->GetSimulatedObjectSetup()->GetNumSimulatedObjects(), 0); } TEST_F(CanAddSimulatedObjectFixture, CanAddColliderToSimulatedObjectFromInspector) { RecordProperty("test_case_id", "C20385259"); - - m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); + + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 5, "CanAddSimulatedObjectActor"); + Actor* actor = m_actorAsset->GetActor(); CreateSimulateObject("sim1"); @@ -380,10 +393,12 @@ namespace EMotionFX // Send the left button click directly to the button QTest::mouseClick(addColliderButton, Qt::LeftButton); - const size_t numCapsuleColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); + const size_t numCapsuleColliders = + PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); EXPECT_EQ(numCapsuleColliders, 0); - const size_t numSphereColliders = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); + const size_t numSphereColliders = + PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); EXPECT_EQ(numSphereColliders, 0); QMenu* contextMenu = addColliderButton->findChild("EMFX.AddColliderButton.ContextMenu"); @@ -392,13 +407,15 @@ namespace EMotionFX QAction* addCapsuleAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addCapsuleAction, contextMenu, "Add capsule")); addCapsuleAction->trigger(); - const size_t numCollidersAfterAddCapsule = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); + const size_t numCollidersAfterAddCapsule = + PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Capsule); ASSERT_EQ(numCollidersAfterAddCapsule, numCapsuleColliders + 1) << "Capsule collider not added."; QAction* addSphereAction; ASSERT_TRUE(UIFixture::GetActionFromContextMenu(addSphereAction, contextMenu, "Add sphere")); addSphereAction->trigger(); - const size_t numCollidersAfterAddSphere = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); + const size_t numCollidersAfterAddSphere = + PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider, false, Physics::ShapeType::Sphere); ASSERT_EQ(numCollidersAfterAddSphere, numSphereColliders + 1) << "Sphere collider not added."; } @@ -406,7 +423,9 @@ namespace EMotionFX { RecordProperty("test_case_id", "C13048818"); - m_actor = ActorFactory::CreateAndInit(7, "CanAddSimulatedObjectActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 7, "CanAddSimulatedObjectActor"); + Actor* actor = m_actorAsset->GetActor(); CreateSimulateObject("ANY"); @@ -442,7 +461,7 @@ namespace EMotionFX messageBoxPopupHandler.WaitForPopupPressDialogButton(QDialogButtonBox::No); newSimulatedObjectAction->trigger(); - const EMotionFX::SimulatedObject* simulatedObject = m_actor->GetSimulatedObjectSetup()->GetSimulatedObject(0); + const EMotionFX::SimulatedObject* simulatedObject = actor->GetSimulatedObjectSetup()->GetSimulatedObject(0); EXPECT_EQ(simulatedObject->GetNumSimulatedRootJoints(), 1); EXPECT_EQ(simulatedObject->GetNumSimulatedJoints(), 3); } @@ -450,7 +469,9 @@ namespace EMotionFX { RecordProperty("test_case_id", "C13048817"); - m_actor = ActorFactory::CreateAndInit(5, "CanAddSimulatedObjectActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 5, "CanAddSimulatedObjectActor"); + Actor* actor = m_actorAsset->GetActor(); EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); @@ -470,7 +491,7 @@ namespace EMotionFX AddCapsuleColliderToJointIndex(3); AddCapsuleColliderToJointIndex(4); - const size_t numCollidersAfterAdd = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider); + const size_t numCollidersAfterAdd = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider); EXPECT_EQ(numCollidersAfterAdd, 2); m_indexList.clear(); @@ -498,7 +519,7 @@ namespace EMotionFX removeAction->trigger(); // Check that one of the colliders is now gone. - const size_t numCollidersAfterFirstRemove = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider); + const size_t numCollidersAfterFirstRemove = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider); ASSERT_EQ(numCollidersAfterFirstRemove, numCollidersAfterAdd - 1) << "RemoveCollider action in Simulated Object Inspector failed."; // Now do the same thing using the Simulated Object Inspector context menu. @@ -536,7 +557,7 @@ namespace EMotionFX delAction->trigger(); // Check that we have the number of colliders we started we expect. - const size_t numCollidersAfterSecondRemove = PhysicsSetupUtils::CountColliders(m_actor.get(), PhysicsSetup::SimulatedObjectCollider); + const size_t numCollidersAfterSecondRemove = PhysicsSetupUtils::CountColliders(actor, PhysicsSetup::SimulatedObjectCollider); ASSERT_EQ(numCollidersAfterSecondRemove, numCollidersAfterAdd - 2); } diff --git a/Gems/EMotionFX/Code/Tests/UI/CanAddToSimulatedObject.cpp b/Gems/EMotionFX/Code/Tests/UI/CanAddToSimulatedObject.cpp index e27d558664..a10ba352d2 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanAddToSimulatedObject.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanAddToSimulatedObject.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -52,9 +53,11 @@ namespace EMotionFX { RecordProperty("test_case_id", "C14603914"); - AutoRegisteredActor actor = ActorFactory::CreateAndInit(7, "CanAddToSimulatedObjectActor"); - - ActorInstance* actorInstance = ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 7, "CanAddToSimulatedObjectActor"); + Actor* actor = actorAsset->GetActor(); + ActorInstance* actorInstance = ActorInstance::Create(actor); // Change the Editor mode to Simulated Objects EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); @@ -165,9 +168,11 @@ namespace EMotionFX }); RecordProperty("test_case_id", "C13291807"); - AutoRegisteredActor actor = ActorFactory::CreateAndInit(7, "CanAddToSimulatedObjectActor"); - - ActorInstance* actorInstance = ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 7, "CanAddToSimulatedObjectActor"); + Actor* actor = actorAsset->GetActor(); + ActorInstance* actorInstance = ActorInstance::Create(actor); // Change the Editor mode to Physics EMStudio::GetMainWindow()->ApplicationModeChanged("Physics"); diff --git a/Gems/EMotionFX/Code/Tests/UI/CanChangeParametersInSimulatedObject.cpp b/Gems/EMotionFX/Code/Tests/UI/CanChangeParametersInSimulatedObject.cpp index 510bfb2d83..108a637412 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanChangeParametersInSimulatedObject.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanChangeParametersInSimulatedObject.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -37,9 +38,10 @@ namespace EMotionFX { RecordProperty("test_case_id", "C14519563"); - AutoRegisteredActor actor = ActorFactory::CreateAndInit(7, "CanAddToSimulatedObjectActor"); - - ActorInstance* actorInstance = ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 7, "CanAddToSimulatedObjectActor"); + ActorInstance* actorInstance = ActorInstance::Create(actorAsset->GetActor()); // Change the Editor mode to Simulated Objects EMStudio::GetMainWindow()->ApplicationModeChanged("SimulatedObjects"); diff --git a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp index 73a0f1c865..2af3329203 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp @@ -24,10 +24,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -141,8 +143,10 @@ namespace EMotionFX { if (EMotionFX::GetActorManager().GetNumActorInstances() == 0) { - AutoRegisteredActor actor = ActorFactory::CreateAndInit(2, "CanAddSimulatedObjectWithJointsActor"); - ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, 2, "CanAddSimulatedObjectWithJointsActor"); + ActorInstance::Create(actorAsset->GetActor()); EXPECT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to create actor set for reset test."; } @@ -152,15 +156,16 @@ namespace EMotionFX { if (EMotionFX::GetActorManager().GetNumActorInstances() == 0) { - AutoRegisteredActor actor = ActorFactory::CreateAndInit(2, "CanAddSimulatedObjectWithJointsActor"); - ActorInstance::Create(actor.get()); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = TestActorAssets::CreateActorAssetAndRegister( + actorAssetId, 2, "CanAddSimulatedObjectWithJointsActor"); + ActorInstance::Create(actorAsset->GetActor()); EXPECT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to create actor set for reset test."; - - actor->SetFileName(filename); + actorAsset->GetActor()->SetFileName(filename); AZStd::string stringFilename = filename; - ExporterLib::SaveActor(stringFilename, actor.get(), MCore::Endian::ENDIAN_LITTLE); + ExporterLib::SaveActor(stringFilename, actorAsset->GetActor(), MCore::Endian::ENDIAN_LITTLE); } } @@ -239,7 +244,6 @@ namespace EMotionFX // Load the actor we just saved, with replaceScene set to true to represent a load. LoadActor(actorFilename.toUtf8().data(), true); - ASSERT_EQ(EMotionFX::GetActorManager().GetNumActorInstances(), 1) << "Failed to load Actor."; // Do it again to verify that number of actors stays the same when replaceScene is true. @@ -696,7 +700,10 @@ namespace EMotionFX TestResetMenuItem(fileMenu); - TestActorMenus(fileMenu); + // Temporarily disable loading actor test. + // This is because the importer command now load actor asset instead of reading from disk. We do not want to add dependency to the asset processor + // in this test. + // TestActorMenus(fileMenu); TestSaveAllMenuItem(fileMenu); } diff --git a/Gems/EMotionFX/Code/Tests/UI/CanUseLayoutMenu.cpp b/Gems/EMotionFX/Code/Tests/UI/CanUseLayoutMenu.cpp index 6fbaf3a028..e615d3c9e0 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanUseLayoutMenu.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanUseLayoutMenu.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/Gems/EMotionFX/Code/Tests/UI/ClothColliderTests.cpp b/Gems/EMotionFX/Code/Tests/UI/ClothColliderTests.cpp index 6428a11e6d..d87c35a4fa 100644 --- a/Gems/EMotionFX/Code/Tests/UI/ClothColliderTests.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/ClothColliderTests.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace EMotionFX @@ -102,7 +103,9 @@ namespace EMotionFX const int lastIndex = 6; RecordProperty("test_case_id", "C18970351"); - AutoRegisteredActor actor = ActorFactory::CreateAndInit(numJoints, "RagdollEditTestsActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, numJoints, "RagdollEditTestsActor"); CreateSkeletonAndModelIndices(); EXPECT_EQ(m_indexList.size(), numJoints); diff --git a/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp b/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp index 6e5e14e9fc..def8bdab58 100644 --- a/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/LODSkinnedMeshTests.cpp @@ -80,11 +80,14 @@ namespace EMotionFX DataMembers m_data; }; - AZStd::unique_ptr CreateLODActor(int numLODs) + AZ::Data::Asset CreateLODActor(int numLODs) { - AZStd::unique_ptr actor = ActorFactory::CreateAndInit("LODSkinnedMeshTestsActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, "LODSkinnedMeshTestsActor"); // Modify the actor to have numLODs LOD levels. + Actor* actor = actorAsset->GetActor(); Mesh* lodMesh = actor->GetMesh(0, 0); StandardMaterial* dummyMat = StandardMaterial::Create("Dummy Material"); actor->AddMaterial(0, dummyMat); // owns the material @@ -97,7 +100,7 @@ namespace EMotionFX actor->AddMaterial(i, dummyMat->Clone()); } - return actor; + return AZStd::move(actorAsset); } class LODPropertyRowWidget @@ -112,9 +115,8 @@ namespace EMotionFX const int numLODs = GetParam(); RecordProperty("test_case_id", "C29202698"); - AutoRegisteredActor actor = CreateLODActor(numLODs); - - ActorInstance* actorInstance = ActorInstance::Create(actor.get()); + AZ::Data::Asset actorAsset = CreateLODActor(numLODs); + ActorInstance* actorInstance = ActorInstance::Create(actorAsset->GetActor()); // Change the Editor mode to Character EMStudio::GetMainWindow()->ApplicationModeChanged("Character"); @@ -166,8 +168,7 @@ namespace EMotionFX gameEntity->SetId(entityId); AZ::Data::AssetId actorAssetId("{85D3EF54-7400-43F8-8A40-F6BCBF534E54}"); - AZStd::unique_ptr actor = CreateLODActor(numLODs); - AZ::Data::Asset actorAsset = TestActorAssets::GetAssetFromActor(actorAssetId, AZStd::move(actor)); + AZ::Data::Asset actorAsset = CreateLODActor(numLODs); gameEntity->CreateComponent(); Integration::ActorComponent::Configuration actorConf; diff --git a/Gems/EMotionFX/Code/Tests/UI/RagdollEditTests.cpp b/Gems/EMotionFX/Code/Tests/UI/RagdollEditTests.cpp index 1c39cde5b6..d097e67d15 100644 --- a/Gems/EMotionFX/Code/Tests/UI/RagdollEditTests.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/RagdollEditTests.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -110,7 +111,9 @@ namespace EMotionFX const int numJoints = 6; RecordProperty("test_case_id", "C3122249"); - AutoRegisteredActor actor = ActorFactory::CreateAndInit(numJoints, "RagdollEditTestsActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, numJoints, "RagdollEditTestsActor"); CreateSkeletonAndModelIndices(); @@ -138,7 +141,9 @@ namespace EMotionFX const int numJoints = 8; RecordProperty("test_case_id", "C3122248"); - AutoRegisteredActor actor = ActorFactory::CreateAndInit(numJoints, "RagdollEditTestsActor"); + AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); + AZ::Data::Asset actorAsset = + TestActorAssets::CreateActorAssetAndRegister(actorAssetId, numJoints, "RagdollEditTestsActor"); CreateSkeletonAndModelIndices(); EXPECT_EQ(m_indexList.size(), numJoints); From 975589c0c4cb7bd1c3e544b72d26c8f502daa76d Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 10 Aug 2021 22:28:42 -0700 Subject: [PATCH 110/293] Add skeleton class for atom render plugin Signed-off-by: rhhong --- .../Source/AtomRender/AtomRenderPlugin.cpp | 27 +++++++ .../Source/AtomRender/AtomRenderPlugin.h | 72 +++++++++++++++++++ .../RenderPlugins/renderplugins_files.cmake | 2 + .../Integration/System/SystemComponent.cpp | 2 + 4 files changed, 103 insertions(+) create mode 100644 Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp create mode 100644 Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp new file mode 100644 index 0000000000..6b64afd50b --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp @@ -0,0 +1,27 @@ +/* + * 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 + +namespace EMStudio +{ + AtomRenderPlugin::AtomRenderPlugin() + { + + } + + AtomRenderPlugin::~AtomRenderPlugin() + { + + } + + bool AtomRenderPlugin::Init() + { + return true; + } +} diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h new file mode 100644 index 0000000000..59aabce3c3 --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace EMStudio +{ + class AtomRenderPlugin + : public DockWidgetPlugin + { + Q_OBJECT // AUTOMOC + + public: + enum + { + CLASS_ID = 0x32b0c04d + }; + AtomRenderPlugin(); + ~AtomRenderPlugin(); + + // Plugin information + const char* GetCompileDate() const override + { + return MCORE_DATE; + } + const char* GetName() const override + { + return "Atom Render Window"; + } + uint32 GetClassID() const override + { + return static_cast(AtomRenderPlugin::CLASS_ID); + } + const char* GetCreatorName() const override + { + return "O3DE"; + } + float GetVersion() const override + { + return 1.0f; + } + bool GetIsClosable() const override + { + return true; + } + bool GetIsFloatable() const override + { + return true; + } + bool GetIsVertical() const override + { + return false; + } + + bool Init(); + EMStudioPlugin* Clone() + { + return new AtomRenderPlugin(); + } + EMStudioPlugin::EPluginType GetPluginType() const override + { + return EMStudioPlugin::PLUGINTYPE_RENDERING; + } + }; +} diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake index 3bce07c3c4..339052823d 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake @@ -11,4 +11,6 @@ set(FILES Source/OpenGLRender/GLWidget.cpp Source/OpenGLRender/OpenGLRenderPlugin.h Source/OpenGLRender/OpenGLRenderPlugin.cpp + Source/AtomRender/AtomRenderPlugin.h + Source/AtomRender/AtomRenderPlugin.cpp ) diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index cf2f9beaa4..c3823f15ed 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -88,6 +88,7 @@ # include # include # include +# include # include # include # include @@ -794,6 +795,7 @@ namespace EMotionFX pluginManager->RegisterPlugin(new EMStudio::NodeGroupsPlugin()); pluginManager->RegisterPlugin(new EMStudio::AnimGraphPlugin()); pluginManager->RegisterPlugin(new EMStudio::OpenGLRenderPlugin()); + pluginManager->RegisterPlugin(new EMStudio::AtomRenderPlugin()); pluginManager->RegisterPlugin(new EMotionFX::HitDetectionJointInspectorPlugin()); pluginManager->RegisterPlugin(new EMotionFX::SkeletonOutlinerPlugin()); pluginManager->RegisterPlugin(new EMotionFX::RagdollNodeInspectorPlugin()); From a96b091d3fffead19d545d868e9cbf368cd1c8e5 Mon Sep 17 00:00:00 2001 From: rhhong Date: Wed, 11 Aug 2021 22:49:59 -0700 Subject: [PATCH 111/293] Add skeleton class for animviewportwidget. Signed-off-by: rhhong --- Gems/EMotionFX/Code/CMakeLists.txt | 2 ++ .../Source/AtomRender/AnimViewportWidget.cpp | 18 +++++++++++++++++ .../Source/AtomRender/AnimViewportWidget.h | 20 +++++++++++++++++++ .../Source/AtomRender/AtomRenderPlugin.cpp | 13 +++++++++++- .../Source/AtomRender/AtomRenderPlugin.h | 10 +++++++++- .../RenderPlugins/renderplugins_files.cmake | 2 ++ 6 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.cpp create mode 100644 Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.h diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index dace02b2ae..67d0ba6d85 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -109,6 +109,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzToolsFramework Legacy::Editor.Headers 3rdParty::OpenGLInterface + Gem::AtomToolsFramework.Static + Gem::AtomToolsFramework.Editor COMPILE_DEFINITIONS PUBLIC EMFX_EMSTUDIOLYEMBEDDED diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.cpp new file mode 100644 index 0000000000..df8edeb324 --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.cpp @@ -0,0 +1,18 @@ +/* + * 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 + +namespace EMStudio +{ + AnimViewportWidget::AnimViewportWidget(QWidget* parent) + : AtomToolsFramework::RenderViewportWidget(parent) + { + + } +} diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.h new file mode 100644 index 0000000000..59ea5c6680 --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +namespace EMStudio +{ + class AnimViewportWidget + : public AtomToolsFramework::RenderViewportWidget + { + public: + AnimViewportWidget(QWidget* parent = nullptr); + }; +} diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp index 6b64afd50b..6a95b83433 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp @@ -7,12 +7,13 @@ */ #include +#include namespace EMStudio { AtomRenderPlugin::AtomRenderPlugin() + : DockWidgetPlugin() { - } AtomRenderPlugin::~AtomRenderPlugin() @@ -22,6 +23,16 @@ namespace EMStudio bool AtomRenderPlugin::Init() { + m_innerWidget = new QWidget(); + m_dock->setWidget(m_innerWidget); + + QVBoxLayout* verticalLayout = new QVBoxLayout(m_innerWidget); + verticalLayout->setSizeConstraint(QLayout::SetNoConstraint); + verticalLayout->setSpacing(1); + verticalLayout->setMargin(0); + + m_animViewportWidget = new AnimViewportWidget(m_innerWidget); + return true; } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h index 59aabce3c3..d7605e276a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h @@ -8,7 +8,11 @@ #pragma once +#if !defined(Q_MOC_RUN) #include +#include +#include +#endif namespace EMStudio { @@ -59,7 +63,7 @@ namespace EMStudio return false; } - bool Init(); + bool Init() override; EMStudioPlugin* Clone() { return new AtomRenderPlugin(); @@ -68,5 +72,9 @@ namespace EMStudio { return EMStudioPlugin::PLUGINTYPE_RENDERING; } + + private: + QWidget* m_innerWidget; + AnimViewportWidget* m_animViewportWidget; }; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake index 339052823d..c184f708f2 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake @@ -13,4 +13,6 @@ set(FILES Source/OpenGLRender/OpenGLRenderPlugin.cpp Source/AtomRender/AtomRenderPlugin.h Source/AtomRender/AtomRenderPlugin.cpp + Source/AtomRender/AnimViewportWidget.h + Source/AtomRender/AnimViewportWidget.cpp ) From f2b449c4b97091525848910ca6df3195ed594c3a Mon Sep 17 00:00:00 2001 From: rhhong Date: Mon, 30 Aug 2021 17:57:45 -0700 Subject: [PATCH 112/293] Registering an empty atom render plugin in the emfxatom gem. Signed-off-by: rhhong --- .../EMotionFXAtom/Code/CMakeLists.txt | 7 ++ .../EMotionFXAtom/Code/Source/ActorModule.cpp | 11 ++- .../Source/Editor/EditorSystemComponent.cpp | 42 +++++++++++ .../Source/Editor/EditorSystemComponent.h | 35 ++++++++++ .../Tools/EMStudio}/AnimViewportWidget.cpp | 2 +- .../Code/Tools/EMStudio}/AnimViewportWidget.h | 0 .../Code/Tools/EMStudio}/AtomRenderPlugin.cpp | 2 +- .../Code/Tools/EMStudio}/AtomRenderPlugin.h | 4 +- .../Code/emotionfx_atom_editor_files.cmake | 6 ++ .../EMStudioSDK/Source/EMStudioManager.cpp | 44 +++--------- .../EMStudioSDK/Source/EMStudioManager.h | 70 +++++++++++-------- .../EMStudioSDK/Source/MainWindow.h | 6 +- .../RenderPlugins/renderplugins_files.cmake | 4 -- .../Code/Include/Integration/AnimationBus.h | 3 + .../Integration/System/SystemComponent.cpp | 10 +-- .../Integration/System/SystemComponent.h | 5 ++ 16 files changed, 173 insertions(+), 78 deletions(-) create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h rename Gems/{EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender => AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio}/AnimViewportWidget.cpp (81%) rename Gems/{EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender => AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio}/AnimViewportWidget.h (100%) rename Gems/{EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender => AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio}/AtomRenderPlugin.cpp (90%) rename Gems/{EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender => AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio}/AtomRenderPlugin.h (92%) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt index 5a08bab4fa..dc22c8ee93 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt @@ -54,11 +54,18 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) INCLUDE_DIRECTORIES PRIVATE Source + Tools BUILD_DEPENDENCIES PRIVATE AZ::AzCore Gem::EMotionFX_Atom.Static + Gem::EMotionFX.Editor.Static + Gem::AtomToolsFramework.Static + Gem::AtomToolsFramework.Editor RUNTIME_DEPENDENCIES Gem::EMotionFX.Editor + COMPILE_DEFINITIONS + PUBLIC + EMOTIONFXATOM_EDITOR ) endif() diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorModule.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorModule.cpp index 49c2e52c1a..93481c1da6 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorModule.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorModule.cpp @@ -11,6 +11,9 @@ #include #include #include +#ifdef EMOTIONFXATOM_EDITOR +#include +#endif namespace AZ { @@ -28,7 +31,10 @@ namespace AZ : Module() { m_descriptors.insert(m_descriptors.end(), { - ActorSystemComponent::CreateDescriptor() + ActorSystemComponent::CreateDescriptor(), +#ifdef EMOTIONFXATOM_EDITOR + EMotionFXAtom::EditorSystemComponent::CreateDescriptor(), +#endif }); } @@ -39,6 +45,9 @@ namespace AZ { return ComponentTypeList{ azrtti_typeid(), +#ifdef EMOTIONFXATOM_EDITOR + azrtti_typeid(), +#endif }; } }; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp new file mode 100644 index 0000000000..86a9c36c56 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include + +namespace AZ +{ + namespace EMotionFXAtom + { + void EditorSystemComponent::Reflect(ReflectContext* context) + { + if (SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class()->Version(0); + } + } + + void EditorSystemComponent::Activate() + { + EMotionFX::Integration::SystemNotificationBus::Handler::BusConnect(); + } + + void EditorSystemComponent::Deactivate() + { + EMotionFX::Integration::SystemNotificationBus::Handler::BusDisconnect(); + } + + void EditorSystemComponent::OnRegisterPlugin() + { + EMStudio::PluginManager* pluginManager = EMStudio::EMStudioManager::GetInstance()->GetPluginManager(); + pluginManager->RegisterPlugin(new EMStudio::AtomRenderPlugin()); + } + } +} // namespace AZ diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h new file mode 100644 index 0000000000..6121912481 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include + +namespace AZ +{ + namespace EMotionFXAtom + { + class EditorSystemComponent + : public Component + , private EMotionFX::Integration::SystemNotificationBus::Handler + { + public: + AZ_COMPONENT(EditorSystemComponent, "{1FAEC046-255D-4664-8F12-D16503C34431}"); + + static void Reflect(ReflectContext* context); + + protected: + // AZ::Component + void Activate() override; + void Deactivate() override; + + // SystemNotificationBus::OnRegisterPlugin + void OnRegisterPlugin() override; + }; + } // namespace EMotionFXAtom +} // namespace AZ diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp similarity index 81% rename from Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.cpp rename to Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index df8edeb324..2b961e6e7b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -6,7 +6,7 @@ * */ -#include +#include namespace EMStudio { diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h similarity index 100% rename from Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AnimViewportWidget.h rename to Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp similarity index 90% rename from Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp rename to Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index 6a95b83433..f7da1d19a9 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h similarity index 92% rename from Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h rename to Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index d7605e276a..910b5283cd 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/AtomRender/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -9,8 +9,8 @@ #pragma once #if !defined(Q_MOC_RUN) -#include -#include +#include +#include #include #endif diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake index 6401beb232..37e69739d0 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake @@ -8,4 +8,10 @@ set(FILES Source/ActorModule.cpp + Source/Editor/EditorSystemComponent.h + Source/Editor/EditorSystemComponent.cpp + Tools/EMStudio/AtomRenderPlugin.h + Tools/EMStudio/AtomRenderPlugin.cpp + Tools/EMStudio/AnimViewportWidget.h + Tools/EMStudio/AnimViewportWidget.cpp ) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp index 2321d7c71b..432a351edf 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp @@ -46,15 +46,10 @@ AZ_POP_DISABLE_WARNING namespace EMStudio { - //-------------------------------------------------------------------------- - // globals - //-------------------------------------------------------------------------- - EMStudioManager* gEMStudioMgr = nullptr; - - //-------------------------------------------------------------------------- // class EMStudioManager //-------------------------------------------------------------------------- + AZ_CLASS_ALLOCATOR_IMPL(EMStudioManager, AZ::SystemAllocator, 0) // constructor EMStudioManager::EMStudioManager(QApplication* app, [[maybe_unused]] int& argc, [[maybe_unused]] char* argv[]) @@ -105,6 +100,8 @@ namespace EMStudio // log some information LogInfo(); + + AZ::Interface::Register(this); } @@ -130,6 +127,8 @@ namespace EMStudio delete m_commandManager; AZ::AllocatorInstance::Destroy(); + + AZ::Interface::Unregister(this); } MainWindow* EMStudioManager::GetMainWindow() @@ -422,6 +421,12 @@ namespace EMStudio } + EMStudioManager* EMStudioManager::GetInstance() + { + return AZ::Interface().Get(); + } + + // function to add a gizmo to the manager MCommon::TransformationManipulator* EMStudioManager::AddTransformationManipulator(MCommon::TransformationManipulator* manipulator) { @@ -493,31 +498,4 @@ namespace EMStudio path.addText(textPos, font, text); painter.drawPath(path); } - - //-------------------------------------------------------------------------- - // class Initializer - //-------------------------------------------------------------------------- - // initialize EMotion Studio - bool Initializer::Init(QApplication* app, int& argc, char* argv[]) - { - // do nothing if we already have initialized - if (gEMStudioMgr) - { - return true; - } - - // create the new EMStudio object - gEMStudioMgr = new EMStudioManager(app, argc, argv); - - // return success - return true; - } - - - // the shutdown function - void Initializer::Shutdown() - { - delete gEMStudioMgr; - gEMStudioMgr = nullptr; - } } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h index 909f0231f3..8828253ea2 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h @@ -53,9 +53,10 @@ namespace EMStudio class EMSTUDIO_API EMStudioManager : private EMotionFX::SkeletonOutlinerNotificationBus::Handler { - MCORE_MEMORYOBJECTCATEGORY(EMStudioManager, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_EMSTUDIOSDK) - public: + AZ_RTTI(EMStudio::EMStudioManager, "{D45E95CF-0C7B-44F1-A9D4-99A1E12A5AB5}") + AZ_CLASS_ALLOCATOR_DECL + EMStudioManager(QApplication* app, int& argc, char* argv[]); ~EMStudioManager(); @@ -72,6 +73,9 @@ namespace EMStudio AZStd::string GetRecoverFolder() const; AZStd::string GetAutosavesFolder() const; + // Singleton pattern + static EMStudioManager* GetInstance(); + // text rendering helper function static void RenderText(QPainter& painter, const QString& text, const QColor& textColor, const QFont& font, const QFontMetrics& fontMetrics, Qt::Alignment textAlignment, const QRect& rect); @@ -153,31 +157,41 @@ namespace EMStudio EventProcessingCallback* m_eventProcessingCallback; }; - - /** - * - * - * - */ - class EMSTUDIO_API Initializer - { - public: - static bool MCORE_CDECL Init(QApplication* app, int& argc, char* argv[]); - static void MCORE_CDECL Shutdown(); - }; - - - // the global manager - extern EMSTUDIO_API EMStudioManager* gEMStudioMgr; - // shortcuts - MCORE_INLINE QApplication* GetApp() { return gEMStudioMgr->GetApp(); } - MCORE_INLINE EMStudioManager* GetManager() { return gEMStudioMgr; } - MCORE_INLINE bool HasMainWindow() { return gEMStudioMgr->HasMainWindow(); } - MCORE_INLINE MainWindow* GetMainWindow() { return gEMStudioMgr->GetMainWindow(); } - MCORE_INLINE PluginManager* GetPluginManager() { return gEMStudioMgr->GetPluginManager(); } - MCORE_INLINE LayoutManager* GetLayoutManager() { return gEMStudioMgr->GetLayoutManager(); } - MCORE_INLINE NotificationWindowManager* GetNotificationWindowManager() { return gEMStudioMgr->GetNotificationWindowManager(); } - MCORE_INLINE MotionEventPresetManager* GetEventPresetManager() { return gEMStudioMgr->GetEventPresetManger(); } - MCORE_INLINE CommandSystem::CommandManager* GetCommandManager() { return gEMStudioMgr->GetCommandManager(); } + MCORE_INLINE QApplication* GetApp() + { + return EMStudioManager::GetInstance()->GetApp(); + } + MCORE_INLINE EMStudioManager* GetManager() + { + return EMStudioManager::GetInstance(); + } + MCORE_INLINE bool HasMainWindow() + { + return EMStudioManager::GetInstance()->HasMainWindow(); + } + MCORE_INLINE MainWindow* GetMainWindow() + { + return EMStudioManager::GetInstance()->GetMainWindow(); + } + MCORE_INLINE PluginManager* GetPluginManager() + { + return EMStudioManager::GetInstance()->GetPluginManager(); + } + MCORE_INLINE LayoutManager* GetLayoutManager() + { + return EMStudioManager::GetInstance()->GetLayoutManager(); + } + MCORE_INLINE NotificationWindowManager* GetNotificationWindowManager() + { + return EMStudioManager::GetInstance()->GetNotificationWindowManager(); + } + MCORE_INLINE MotionEventPresetManager* GetEventPresetManager() + { + return EMStudioManager::GetInstance()->GetEventPresetManger(); + } + MCORE_INLINE CommandSystem::CommandManager* GetCommandManager() + { + return EMStudioManager::GetInstance()->GetCommandManager(); + } } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h index 585101f7d2..1aa8676352 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h @@ -10,9 +10,9 @@ #if !defined(Q_MOC_RUN) #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake index c184f708f2..3bce07c3c4 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/renderplugins_files.cmake @@ -11,8 +11,4 @@ set(FILES Source/OpenGLRender/GLWidget.cpp Source/OpenGLRender/OpenGLRenderPlugin.h Source/OpenGLRender/OpenGLRenderPlugin.cpp - Source/AtomRender/AtomRenderPlugin.h - Source/AtomRender/AtomRenderPlugin.cpp - Source/AtomRender/AnimViewportWidget.h - Source/AtomRender/AnimViewportWidget.cpp ) diff --git a/Gems/EMotionFX/Code/Include/Integration/AnimationBus.h b/Gems/EMotionFX/Code/Include/Integration/AnimationBus.h index 1b9eb55216..474ac1b6d5 100644 --- a/Gems/EMotionFX/Code/Include/Integration/AnimationBus.h +++ b/Gems/EMotionFX/Code/Include/Integration/AnimationBus.h @@ -46,6 +46,9 @@ namespace EMotionFX public: static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + + // Use this bus to register custom EMotionFX plugin. + virtual void OnRegisterPlugin() = 0; }; using SystemNotificationBus = AZ::EBus; diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index c3823f15ed..38af4232ba 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -70,7 +71,6 @@ # include # include # include -# include # include # include // EMStudio plugins @@ -88,7 +88,6 @@ # include # include # include -# include # include # include # include @@ -530,7 +529,7 @@ namespace EMotionFX if (EMStudio::GetManager()) { - EMStudio::Initializer::Shutdown(); + m_emstudioManager.reset(); MysticQt::Initializer::Shutdown(); } @@ -795,12 +794,13 @@ namespace EMotionFX pluginManager->RegisterPlugin(new EMStudio::NodeGroupsPlugin()); pluginManager->RegisterPlugin(new EMStudio::AnimGraphPlugin()); pluginManager->RegisterPlugin(new EMStudio::OpenGLRenderPlugin()); - pluginManager->RegisterPlugin(new EMStudio::AtomRenderPlugin()); pluginManager->RegisterPlugin(new EMotionFX::HitDetectionJointInspectorPlugin()); pluginManager->RegisterPlugin(new EMotionFX::SkeletonOutlinerPlugin()); pluginManager->RegisterPlugin(new EMotionFX::RagdollNodeInspectorPlugin()); pluginManager->RegisterPlugin(new EMotionFX::ClothJointInspectorPlugin()); pluginManager->RegisterPlugin(new EMotionFX::SimulatedObjectWidget()); + + SystemNotificationBus::Broadcast(&SystemNotificationBus::Events::OnRegisterPlugin); } ////////////////////////////////////////////////////////////////////////// @@ -816,7 +816,7 @@ namespace EMotionFX char** argv = nullptr; MysticQt::Initializer::Init("", editorAssetsPath.c_str()); - EMStudio::Initializer::Init(qApp, argc, argv); + m_emstudioManager = AZStd::make_unique(qApp, argc, argv); InitializeEMStudioPlugins(); diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h index 5e30820ca3..3ef626c947 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.h @@ -24,6 +24,7 @@ # include # include # include +# include #endif // EMOTIONFXANIMATION_EDITOR namespace AZ @@ -126,6 +127,10 @@ namespace EMotionFX AZStd::vector > m_assetHandlers; AZStd::unique_ptr m_eventHandler; AZStd::unique_ptr m_renderBackendManager; + +#if defined(EMOTIONFXANIMATION_EDITOR) + AZStd::unique_ptr m_emstudioManager; +#endif // EMOTIONFXANIMATION_EDITOR }; } } From af9448d4ea10c248ac73b0724d402ab18ee1bdbb Mon Sep 17 00:00:00 2001 From: rhhong Date: Mon, 30 Aug 2021 22:22:19 -0700 Subject: [PATCH 113/293] delete auto moc header Signed-off-by: rhhong --- .../EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index 910b5283cd..b3e47df91c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -19,8 +19,6 @@ namespace EMStudio class AtomRenderPlugin : public DockWidgetPlugin { - Q_OBJECT // AUTOMOC - public: enum { From c4a3162c8543eedc7c8ea20adca737e104269dbc Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 31 Aug 2021 12:23:05 -0700 Subject: [PATCH 114/293] CR feedback - code cleaning Signed-off-by: rhhong --- .../Source/Editor/EditorSystemComponent.cpp | 39 +++++++-------- .../Source/Editor/EditorSystemComponent.h | 33 ++++++------ .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 45 +++++++++++++++++ .../Code/Tools/EMStudio/AtomRenderPlugin.h | 50 ++++--------------- .../EMStudioSDK/Source/EMStudioManager.cpp | 46 ++++++++++++++++- .../EMStudioSDK/Source/EMStudioManager.h | 47 ++++------------- 6 files changed, 142 insertions(+), 118 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp index 86a9c36c56..64f7f2dd97 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp @@ -11,32 +11,29 @@ #include -namespace AZ +namespace AZ::EMotionFXAtom { - namespace EMotionFXAtom + void EditorSystemComponent::Reflect(ReflectContext* context) { - void EditorSystemComponent::Reflect(ReflectContext* context) + if (SerializeContext* serialize = azrtti_cast(context)) { - if (SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class()->Version(0); - } + serialize->Class()->Version(0); } + } - void EditorSystemComponent::Activate() - { - EMotionFX::Integration::SystemNotificationBus::Handler::BusConnect(); - } + void EditorSystemComponent::Activate() + { + EMotionFX::Integration::SystemNotificationBus::Handler::BusConnect(); + } - void EditorSystemComponent::Deactivate() - { - EMotionFX::Integration::SystemNotificationBus::Handler::BusDisconnect(); - } + void EditorSystemComponent::Deactivate() + { + EMotionFX::Integration::SystemNotificationBus::Handler::BusDisconnect(); + } - void EditorSystemComponent::OnRegisterPlugin() - { - EMStudio::PluginManager* pluginManager = EMStudio::EMStudioManager::GetInstance()->GetPluginManager(); - pluginManager->RegisterPlugin(new EMStudio::AtomRenderPlugin()); - } + void EditorSystemComponent::OnRegisterPlugin() + { + EMStudio::PluginManager* pluginManager = EMStudio::EMStudioManager::GetInstance()->GetPluginManager(); + pluginManager->RegisterPlugin(new EMStudio::AtomRenderPlugin()); } -} // namespace AZ +} // namespace AZ::EMotionFXAtom diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h index 6121912481..9da98bcf42 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h @@ -10,26 +10,23 @@ #include #include -namespace AZ +namespace AZ::EMotionFXAtom { - namespace EMotionFXAtom + class EditorSystemComponent + : public Component + , private EMotionFX::Integration::SystemNotificationBus::Handler { - class EditorSystemComponent - : public Component - , private EMotionFX::Integration::SystemNotificationBus::Handler - { - public: - AZ_COMPONENT(EditorSystemComponent, "{1FAEC046-255D-4664-8F12-D16503C34431}"); + public: + AZ_COMPONENT(EditorSystemComponent, "{1FAEC046-255D-4664-8F12-D16503C34431}"); - static void Reflect(ReflectContext* context); + static void Reflect(ReflectContext* context); - protected: - // AZ::Component - void Activate() override; - void Deactivate() override; + protected: + // AZ::Component + void Activate() override; + void Deactivate() override; - // SystemNotificationBus::OnRegisterPlugin - void OnRegisterPlugin() override; - }; - } // namespace EMotionFXAtom -} // namespace AZ + // SystemNotificationBus::OnRegisterPlugin + void OnRegisterPlugin() override; + }; +} // namespace AZ::EMotionFXAtom diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index f7da1d19a9..c7e2178366 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -21,6 +21,51 @@ namespace EMStudio } + const char* AtomRenderPlugin::GetName() const + { + return "Atom Render Window"; + } + + uint32 AtomRenderPlugin::GetClassID() const + { + return static_cast(AtomRenderPlugin::CLASS_ID); + } + + const char* AtomRenderPlugin::GetCreatorName() const + { + return "O3DE"; + } + + float AtomRenderPlugin::GetVersion() const + { + return 1.0f; + } + + bool AtomRenderPlugin::GetIsClosable() const + { + return true; + } + + bool AtomRenderPlugin::GetIsFloatable() const + { + return true; + } + + bool AtomRenderPlugin::GetIsVertical() const + { + return false; + } + + EMStudioPlugin* AtomRenderPlugin::Clone() + { + return new AtomRenderPlugin(); + } + + EMStudioPlugin::EPluginType AtomRenderPlugin::GetPluginType() const + { + return EMStudioPlugin::PLUGINTYPE_RENDERING; + } + bool AtomRenderPlugin::Init() { m_innerWidget = new QWidget(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index b3e47df91c..0fb1443a96 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -28,48 +28,16 @@ namespace EMStudio ~AtomRenderPlugin(); // Plugin information - const char* GetCompileDate() const override - { - return MCORE_DATE; - } - const char* GetName() const override - { - return "Atom Render Window"; - } - uint32 GetClassID() const override - { - return static_cast(AtomRenderPlugin::CLASS_ID); - } - const char* GetCreatorName() const override - { - return "O3DE"; - } - float GetVersion() const override - { - return 1.0f; - } - bool GetIsClosable() const override - { - return true; - } - bool GetIsFloatable() const override - { - return true; - } - bool GetIsVertical() const override - { - return false; - } - + const char* GetName() const override; + uint32 GetClassID() const override; + const char* GetCreatorName() const override; + float GetVersion() const override; + bool GetIsClosable() const override; + bool GetIsFloatable() const override; + bool GetIsVertical() const override; bool Init() override; - EMStudioPlugin* Clone() - { - return new AtomRenderPlugin(); - } - EMStudioPlugin::EPluginType GetPluginType() const override - { - return EMStudioPlugin::PLUGINTYPE_RENDERING; - } + EMStudioPlugin* Clone(); + EMStudioPlugin::EPluginType GetPluginType() const override; private: QWidget* m_innerWidget; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp index 432a351edf..b385de62be 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.cpp @@ -104,7 +104,6 @@ namespace EMStudio AZ::Interface::Register(this); } - // destructor EMStudioManager::~EMStudioManager() { @@ -498,4 +497,49 @@ namespace EMStudio path.addText(textPos, font, text); painter.drawPath(path); } + + // shortcuts + QApplication* GetApp() + { + return EMStudioManager::GetInstance()->GetApp(); + } + EMStudioManager* GetManager() + { + return EMStudioManager::GetInstance(); + } + + bool HasMainWindow() + { + return EMStudioManager::GetInstance()->HasMainWindow(); + } + + MainWindow* GetMainWindow() + { + return EMStudioManager::GetInstance()->GetMainWindow(); + } + + PluginManager* GetPluginManager() + { + return EMStudioManager::GetInstance()->GetPluginManager(); + } + + LayoutManager* GetLayoutManager() + { + return EMStudioManager::GetInstance()->GetLayoutManager(); + } + + NotificationWindowManager* GetNotificationWindowManager() + { + return EMStudioManager::GetInstance()->GetNotificationWindowManager(); + } + + MotionEventPresetManager* GetEventPresetManager() + { + return EMStudioManager::GetInstance()->GetEventPresetManger(); + } + + CommandSystem::CommandManager* GetCommandManager() + { + return EMStudioManager::GetInstance()->GetCommandManager(); + } } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h index 8828253ea2..e7a9397b22 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h @@ -157,41 +157,14 @@ namespace EMStudio EventProcessingCallback* m_eventProcessingCallback; }; - // shortcuts - MCORE_INLINE QApplication* GetApp() - { - return EMStudioManager::GetInstance()->GetApp(); - } - MCORE_INLINE EMStudioManager* GetManager() - { - return EMStudioManager::GetInstance(); - } - MCORE_INLINE bool HasMainWindow() - { - return EMStudioManager::GetInstance()->HasMainWindow(); - } - MCORE_INLINE MainWindow* GetMainWindow() - { - return EMStudioManager::GetInstance()->GetMainWindow(); - } - MCORE_INLINE PluginManager* GetPluginManager() - { - return EMStudioManager::GetInstance()->GetPluginManager(); - } - MCORE_INLINE LayoutManager* GetLayoutManager() - { - return EMStudioManager::GetInstance()->GetLayoutManager(); - } - MCORE_INLINE NotificationWindowManager* GetNotificationWindowManager() - { - return EMStudioManager::GetInstance()->GetNotificationWindowManager(); - } - MCORE_INLINE MotionEventPresetManager* GetEventPresetManager() - { - return EMStudioManager::GetInstance()->GetEventPresetManger(); - } - MCORE_INLINE CommandSystem::CommandManager* GetCommandManager() - { - return EMStudioManager::GetInstance()->GetCommandManager(); - } + // Shortcuts + QApplication* GetApp(); + EMStudioManager* GetManager(); + bool HasMainWindow(); + MainWindow* GetMainWindow(); + PluginManager* GetPluginManager(); + LayoutManager* GetLayoutManager(); + NotificationWindowManager* GetNotificationWindowManager(); + MotionEventPresetManager* GetEventPresetManager(); + CommandSystem::CommandManager* GetCommandManager(); } // namespace EMStudio From cda2bb9d4d080e874cecac5ce0a4345be946b8fd Mon Sep 17 00:00:00 2001 From: rhhong Date: Thu, 9 Sep 2021 21:36:52 -0700 Subject: [PATCH 115/293] Add anim viewport renderer Signed-off-by: rhhong --- .../EMotionFXAtom/Code/CMakeLists.txt | 3 + .../Tools/EMStudio/AnimViewportRenderer.cpp | 279 ++++++++++++++++++ .../Tools/EMStudio/AnimViewportRenderer.h | 79 +++++ .../Tools/EMStudio/AnimViewportWidget.cpp | 13 + .../Code/Tools/EMStudio/AnimViewportWidget.h | 5 + .../Code/emotionfx_atom_editor_files.cmake | 2 + 6 files changed, 381 insertions(+) create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt index dc22c8ee93..cc71e4f237 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt @@ -62,6 +62,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::EMotionFX.Editor.Static Gem::AtomToolsFramework.Static Gem::AtomToolsFramework.Editor + Gem::Atom_Component_DebugCamera.Static + Gem::Atom_Feature_Common.Static + Gem::AtomLyIntegration_CommonFeatures.Static RUNTIME_DEPENDENCIES Gem::EMotionFX.Editor COMPILE_DEFINITIONS diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp new file mode 100644 index 0000000000..96fae3cdaf --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#pragma optimize("", off) + +namespace EMStudio +{ + static constexpr float DepthNear = 0.01f; + + AnimViewportRenderer::AnimViewportRenderer(AZStd::shared_ptr windowContext) + : m_windowContext(windowContext) + { + // Create a new entity context + m_entityContext = AZStd::make_unique(); + m_entityContext->InitContext(); + + // Create the scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "Unable to retrieve scene system."); + AZ::Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene("AnimViewport"); + AZ_Assert(createSceneOutcome, "%s", createSceneOutcome.GetError().data()); + m_frameworkScene = createSceneOutcome.TakeValue(); + m_frameworkScene->SetSubsystem(m_entityContext.get()); + + // Create and register a scene with all available feature processors + // TODO: We don't need every procesors. + AZ::RPI::SceneDescriptor sceneDesc; + m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); + m_scene->EnableAllFeatureProcessors(); + + // Link our RPI::Scene to the AzFramework::Scene + m_frameworkScene->SetSubsystem(m_scene); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + AZStd::string defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset"; + AZ::Data::Asset pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath( + defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error); + m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *m_windowContext.get()); + pipelineAsset.Release(); + m_scene->AddRenderPipeline(m_renderPipeline); + + // As part of our initialization we need to create the BRDF texture generation pipeline + /* + AZ::RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = "BRDFTexturePipeline"; + pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline"; + pipelineDesc.m_executeOnce = true; + + AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(brdfTexturePipeline); + */ + + // Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be + // initialized properly + // with pipeline's pass information. + m_scene->Activate(); + AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + + AzFramework::EntityContextId entityContextId = m_entityContext->GetContextId(); + + // Configure camera + AzFramework::EntityContextRequestBus::EventResult( + m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity"); + AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity."); + + // Add debug camera and controller components + AZ::Debug::CameraComponentConfig cameraConfig(m_windowContext); + cameraConfig.m_fovY = AZ::Constants::HalfPi; + cameraConfig.m_depthNear = DepthNear; + m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid()); + m_cameraComponent->SetConfiguration(cameraConfig); + m_cameraEntity->CreateComponent(azrtti_typeid()); + m_cameraEntity->CreateComponent(azrtti_typeid()); + m_cameraEntity->Init(); + m_cameraEntity->Activate(); + + // Connect camera to pipeline's default view after camera entity activated + m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId()); + + // Get the FeatureProcessors + m_meshFeatureProcessor = m_scene->GetFeatureProcessor(); + // Helper function to load meshes + /* + const auto LoadMesh = [this](const char* modelPath) -> AZ::Render::MeshFeatureProcessorInterface::MeshHandle + { + AZ_Assert(m_meshFeatureProcessor, "Cannot find mesh feature processor on scene"); + + auto meshAsset = AZ::RPI::AssetUtils::GetAssetByProductPath(modelPath, AZ::RPI::AssetUtils::TraceLevel::Assert); + auto materialAsset = + AZ::RPI::AssetUtils::LoadAssetByProductPath("materials/defaultpbr.azmaterial", AZ::RPI::AssetUtils::TraceLevel::Assert); + auto material = AZ::RPI::Material::FindOrCreate(materialAsset); + AZ::Render::MeshFeatureProcessorInterface::MeshHandle meshHandle = + m_meshFeatureProcessor->AcquireMesh(AZ::Render::MeshHandleDescriptor{ meshAsset }, material); + + return meshHandle; + }; + LoadMesh("objects/shaderball_simple.azmodel"); + */ + + // Configure tone mapper + AzFramework::EntityContextRequestBus::EventResult( + m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity"); + AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity."); + + m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId); + m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId); + m_postProcessEntity->CreateComponent(azrtti_typeid()); + m_postProcessEntity->Activate(); + + // Init directional light processor + m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor(); + + // Init display mapper processor + m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor(); + + // Init Skybox + m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + m_skyboxFeatureProcessor->Enable(true); + m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap); + + // Create IBL + AzFramework::EntityContextRequestBus::EventResult( + m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity"); + AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity."); + + m_iblEntity->CreateComponent(AZ::Render::ImageBasedLightComponentTypeId); + m_iblEntity->CreateComponent(azrtti_typeid()); + m_iblEntity->Activate(); + + // Temp: Load light preset + AZ::Data::Asset lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath( + "lightingpresets/default.lightingpreset.azasset", AZ::RPI::AssetUtils::TraceLevel::Warning); + const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs(); + SetLightingPreset(preset); + + // Create model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); + AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); + + m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Activate(); + + // Create grid + AzFramework::EntityContextRequestBus::EventResult( + m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); + AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity."); + + AZ::Render::GridComponentConfig gridConfig; + gridConfig.m_gridSize = 4.0f; + gridConfig.m_axisColor = AZ::Color(0.5f, 0.5f, 0.5f, 1.0f); + gridConfig.m_primaryColor = AZ::Color(0.3f, 0.3f, 0.3f, 1.0f); + gridConfig.m_secondaryColor = AZ::Color(0.5f, 0.1f, 0.1f, 1.0f); + auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId); + gridComponent->SetConfiguration(gridConfig); + + m_gridEntity->CreateComponent(azrtti_typeid()); + m_gridEntity->Activate(); + + Reset(); + AZ::TickBus::Handler::BusConnect(); + } + + AnimViewportRenderer::~AnimViewportRenderer() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void AnimViewportRenderer::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + // m_renderPipeline->AddToRenderTickOnce(); + } + + void AnimViewportRenderer::Reset() + { + // Reset environment + AZ::Transform iblTransform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::Event(m_iblEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, iblTransform); + + const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity(); + AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); + + // Reset model + AZ::Transform modelTransform = AZ::Transform::CreateIdentity(); + modelTransform.SetTranslation(AZ::Vector3(1.0f, 2.0f, 0.5f)); + modelTransform.SetUniformScale(3.3f); + // modelTransform.SetUniformScale(50.0f); + AZ::TransformBus::Event(m_modelEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, modelTransform); + + auto modelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( + "objects/shaderball_simple.azmodel", AZ::RPI::AssetUtils::TraceLevel::Assert); + AZ::Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, modelAsset); + + Camera::Configuration cameraConfig; + Camera::CameraRequestBus::EventResult( + cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); + + // Reset the camera position + static constexpr float StartingDistanceMultiplier = 2.0f; + static constexpr float StartingRotationAngle = AZ::Constants::QuarterPi / 2.0f; + + AZ::Vector3 targetPosition = modelTransform.GetTranslation(); + const float distance = 1.0f * StartingDistanceMultiplier; + const AZ::Quaternion cameraRotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), StartingRotationAngle); + AZ::Vector3 cameraPosition(targetPosition.GetX(), targetPosition.GetY() - distance, targetPosition.GetZ()); + cameraPosition = cameraRotation.TransformVector(cameraPosition); + AZ::Transform cameraTransform = AZ::Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); + AZ::TransformBus::Event(m_cameraEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, cameraTransform); + + // Setup primary camera controls + AZ::Debug::CameraControllerRequestBus::Event( + m_cameraEntity->GetId(), &AZ::Debug::CameraControllerRequestBus::Events::Enable, azrtti_typeid()); + } + + void AnimViewportRenderer::SetLightingPreset(const AZ::Render::LightingPreset* preset) + { + if (!preset) + { + AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid lighting preset."); + return; + } + + AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor = + m_scene->GetFeatureProcessor(); + AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = + m_scene->GetFeatureProcessor(); + + AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = + postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId()) + ->GetOrCreateExposureControlSettingsInterface(); + + Camera::Configuration cameraConfig; + Camera::CameraRequestBus::EventResult( + cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); + + bool enableAlternateSkybox = false; + + AZStd::vector lightHandles; + preset->ApplyLightingPreset( + iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor, + cameraConfig, lightHandles, nullptr, AZ::RPI::MaterialPropertyIndex::Null, enableAlternateSkybox); + } +} // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h new file mode 100644 index 0000000000..9bf92aeff9 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace AZ +{ + class Entity; + class Component; + + namespace Render + { + class DisplayMapperFeatureProcessorInterface; + class DirectionalLightFeatureProcessorInterface; + class MeshFeatureProcessorInterface; + } + + namespace RPI + { + class WindowContext; + } +} + +namespace EMStudio +{ + //! + //! + class AnimViewportRenderer + : public AZ::TickBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(AnimViewportRenderer, AZ::SystemAllocator, 0); + + AnimViewportRenderer(AZStd::shared_ptr windowContext); + ~AnimViewportRenderer(); + + private: + // AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + void Reset(); + void SetLightingPreset(const AZ::Render::LightingPreset* preset); + + AZStd::shared_ptr m_windowContext; + AZStd::unique_ptr m_entityContext; + AZStd::shared_ptr m_frameworkScene; + AZ::RPI::ScenePtr m_scene; + AZ::RPI::RenderPipelinePtr m_renderPipeline; + AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = nullptr; + AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = nullptr; + AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = nullptr; + AZ::Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr; + + AZ::Entity* m_postProcessEntity = nullptr; + AZ::Entity* m_iblEntity = nullptr; + + AZ::Entity* m_cameraEntity = nullptr; + AZ::Component* m_cameraComponent = nullptr; + + AZ::Entity* m_modelEntity = nullptr; + AZ::Data::AssetId m_modelAssetId; + + AZ::Entity* m_gridEntity = nullptr; + }; +} diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 2b961e6e7b..39b45507da 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -6,13 +6,26 @@ * */ +#include + #include +#include namespace EMStudio { AnimViewportWidget::AnimViewportWidget(QWidget* parent) : AtomToolsFramework::RenderViewportWidget(parent) { + setObjectName(QString::fromUtf8("AtomViewportWidget")); + resize(869, 574); + QSizePolicy qSize(QSizePolicy::Preferred, QSizePolicy::Preferred); + qSize.setHorizontalStretch(0); + qSize.setVerticalStretch(0); + qSize.setHeightForWidth(sizePolicy().hasHeightForWidth()); + setSizePolicy(qSize); + setAutoFillBackground(false); + setStyleSheet(QString::fromUtf8("")); + m_renderer = AZStd::make_unique(GetViewportContext()->GetWindowContext()); } } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 59ea5c6680..26bb9838b3 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -11,10 +11,15 @@ namespace EMStudio { + class AnimViewportRenderer; + class AnimViewportWidget : public AtomToolsFramework::RenderViewportWidget { public: AnimViewportWidget(QWidget* parent = nullptr); + + private: + AZStd::unique_ptr m_renderer; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake index 37e69739d0..5c8728a8e9 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake @@ -14,4 +14,6 @@ set(FILES Tools/EMStudio/AtomRenderPlugin.cpp Tools/EMStudio/AnimViewportWidget.h Tools/EMStudio/AnimViewportWidget.cpp + Tools/EMStudio/AnimViewportRenderer.h + Tools/EMStudio/AnimViewportRenderer.cpp ) From d1853389789888e8661e2b6a95b357aec1b127e9 Mon Sep 17 00:00:00 2001 From: rhhong Date: Mon, 13 Sep 2021 21:17:06 -0700 Subject: [PATCH 116/293] Code clean Signed-off-by: rhhong --- .../Tools/EMStudio/AnimViewportRenderer.cpp | 83 ++++++++----------- .../Tools/EMStudio/AnimViewportRenderer.h | 11 +-- 2 files changed, 38 insertions(+), 56 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 96fae3cdaf..89050cc643 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -53,7 +53,7 @@ namespace EMStudio m_frameworkScene->SetSubsystem(m_entityContext.get()); // Create and register a scene with all available feature processors - // TODO: We don't need every procesors. + // TODO: We don't need every procesors, only register the processor we are going to use. AZ::RPI::SceneDescriptor sceneDesc; m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); @@ -69,21 +69,8 @@ namespace EMStudio pipelineAsset.Release(); m_scene->AddRenderPipeline(m_renderPipeline); - // As part of our initialization we need to create the BRDF texture generation pipeline - /* - AZ::RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = "BRDFTexturePipeline"; - pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline"; - pipelineDesc.m_executeOnce = true; - - AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - m_scene->AddRenderPipeline(brdfTexturePipeline); - */ - // Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be - // initialized properly - // with pipeline's pass information. + // initialized properly with pipeline's pass information. m_scene->Activate(); AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); @@ -110,23 +97,6 @@ namespace EMStudio // Get the FeatureProcessors m_meshFeatureProcessor = m_scene->GetFeatureProcessor(); - // Helper function to load meshes - /* - const auto LoadMesh = [this](const char* modelPath) -> AZ::Render::MeshFeatureProcessorInterface::MeshHandle - { - AZ_Assert(m_meshFeatureProcessor, "Cannot find mesh feature processor on scene"); - - auto meshAsset = AZ::RPI::AssetUtils::GetAssetByProductPath(modelPath, AZ::RPI::AssetUtils::TraceLevel::Assert); - auto materialAsset = - AZ::RPI::AssetUtils::LoadAssetByProductPath("materials/defaultpbr.azmaterial", AZ::RPI::AssetUtils::TraceLevel::Assert); - auto material = AZ::RPI::Material::FindOrCreate(materialAsset); - AZ::Render::MeshFeatureProcessorInterface::MeshHandle meshHandle = - m_meshFeatureProcessor->AcquireMesh(AZ::Render::MeshHandleDescriptor{ meshAsset }, material); - - return meshHandle; - }; - LoadMesh("objects/shaderball_simple.azmodel"); - */ // Configure tone mapper AzFramework::EntityContextRequestBus::EventResult( @@ -158,13 +128,14 @@ namespace EMStudio m_iblEntity->CreateComponent(azrtti_typeid()); m_iblEntity->Activate(); - // Temp: Load light preset + // Load light preset AZ::Data::Asset lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath( "lightingpresets/default.lightingpreset.azasset", AZ::RPI::AssetUtils::TraceLevel::Warning); const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs(); SetLightingPreset(preset); - // Create model + // Create a static model. + // TODO: Replace this with actor component. AzFramework::EntityContextRequestBus::EventResult( m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); @@ -191,17 +162,39 @@ namespace EMStudio m_gridEntity->Activate(); Reset(); - AZ::TickBus::Handler::BusConnect(); } AnimViewportRenderer::~AnimViewportRenderer() { - AZ::TickBus::Handler::BusDisconnect(); - } + const AzFramework::EntityContextId entityContextId = m_entityContext->GetContextId(); + // Destory all the entities we created. + auto DestoryEntity = [](AZ::Entity* entity, AzFramework::EntityContextId contextId) + { + AzFramework::EntityContextRequestBus::Event(contextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, entity); + entity = nullptr; + }; + DestoryEntity(m_iblEntity, entityContextId); + DestoryEntity(m_postProcessEntity, entityContextId); + DestoryEntity(m_cameraEntity, entityContextId); + DestoryEntity(m_modelEntity, entityContextId); + DestoryEntity(m_gridEntity, entityContextId); + m_entityContext->DestroyContext(); + + for (AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle& handle : m_lightHandles) + { + m_directionalLightFeatureProcessor->ReleaseLight(handle); + } + m_lightHandles.clear(); - void AnimViewportRenderer::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) - { - // m_renderPipeline->AddToRenderTickOnce(); + m_frameworkScene->UnsetSubsystem(m_scene); + + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "AtomViewportRenderer was unable to get the scene system during destruction."); + bool removeSuccess = sceneSystem->RemoveScene("AnimViewport"); + AZ_Assert(removeSuccess, "AtomViewportRenderer should be removed."); + + AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_scene = nullptr; } void AnimViewportRenderer::Reset() @@ -217,9 +210,6 @@ namespace EMStudio // Reset model AZ::Transform modelTransform = AZ::Transform::CreateIdentity(); - modelTransform.SetTranslation(AZ::Vector3(1.0f, 2.0f, 0.5f)); - modelTransform.SetUniformScale(3.3f); - // modelTransform.SetUniformScale(50.0f); AZ::TransformBus::Event(m_modelEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, modelTransform); auto modelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( @@ -252,7 +242,7 @@ namespace EMStudio { if (!preset) { - AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid lighting preset."); + AZ_Warning("AnimViewportRenderer", false, "Attempting to set invalid lighting preset."); return; } @@ -269,11 +259,8 @@ namespace EMStudio Camera::CameraRequestBus::EventResult( cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); - bool enableAlternateSkybox = false; - - AZStd::vector lightHandles; preset->ApplyLightingPreset( iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor, - cameraConfig, lightHandles, nullptr, AZ::RPI::MaterialPropertyIndex::Null, enableAlternateSkybox); + cameraConfig, m_lightHandles, nullptr, AZ::RPI::MaterialPropertyIndex::Null, false); } } // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index 9bf92aeff9..85538fd568 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace AZ @@ -37,10 +38,7 @@ namespace AZ namespace EMStudio { - //! - //! class AnimViewportRenderer - : public AZ::TickBus::Handler { public: AZ_CLASS_ALLOCATOR(AnimViewportRenderer, AZ::SystemAllocator, 0); @@ -49,8 +47,6 @@ namespace EMStudio ~AnimViewportRenderer(); private: - // AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; void Reset(); void SetLightingPreset(const AZ::Render::LightingPreset* preset); @@ -67,13 +63,12 @@ namespace EMStudio AZ::Entity* m_postProcessEntity = nullptr; AZ::Entity* m_iblEntity = nullptr; - AZ::Entity* m_cameraEntity = nullptr; AZ::Component* m_cameraComponent = nullptr; - AZ::Entity* m_modelEntity = nullptr; AZ::Data::AssetId m_modelAssetId; - AZ::Entity* m_gridEntity = nullptr; + + AZStd::vector m_lightHandles; }; } From b7900bf646a9c74b1ce1382d4dd4db0beaf6b411 Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 21 Sep 2021 09:51:27 -0700 Subject: [PATCH 117/293] render an actor Signed-off-by: rhhong --- .../Tools/EMStudio/AnimViewportRenderer.cpp | 22 ++++++++++++++++++ .../Tools/EMStudio/AnimViewportRenderer.h | 1 + .../Assets/Editor/Layouts/Character2.layout | Bin 0 -> 5388 bytes .../Include/Integration/ActorComponentBus.h | 6 ++++- 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Gems/EMotionFX/Assets/Editor/Layouts/Character2.layout diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 89050cc643..4db69cf8d9 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -145,6 +147,18 @@ namespace EMStudio m_modelEntity->CreateComponent(azrtti_typeid()); m_modelEntity->Activate(); + // Create an actor. + // TODO: Support multiple actors. + AzFramework::EntityContextRequestBus::EventResult( + m_actorEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); + AZ_Assert(m_actorEntity != nullptr, "Failed to create model entity."); + + static constexpr const char* const ActorComponentTypeId = "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"; + m_actorEntity->CreateComponent(ActorComponentTypeId); + m_actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + m_actorEntity->CreateComponent(azrtti_typeid()); + m_actorEntity->Activate(); + // Create grid AzFramework::EntityContextRequestBus::EventResult( m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); @@ -177,6 +191,7 @@ namespace EMStudio DestoryEntity(m_postProcessEntity, entityContextId); DestoryEntity(m_cameraEntity, entityContextId); DestoryEntity(m_modelEntity, entityContextId); + DestoryEntity(m_actorEntity, entityContextId); DestoryEntity(m_gridEntity, entityContextId); m_entityContext->DestroyContext(); @@ -217,6 +232,13 @@ namespace EMStudio AZ::Render::MeshComponentRequestBus::Event( m_modelEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, modelAsset); + // Reset the actor asset + AZ::TransformBus::Event(m_actorEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, modelTransform); + auto actorAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( + "objects/characters/jack/jack.actor", AZ::RPI::AssetUtils::TraceLevel::Assert); + EMotionFX::Integration::ActorComponentRequestBus::Event( + m_actorEntity->GetId(), &EMotionFX::Integration::ActorComponentRequestBus::Events::SetActorAsset, actorAsset); + Camera::Configuration cameraConfig; Camera::CameraRequestBus::EventResult( cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index 85538fd568..eb590f8d71 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -66,6 +66,7 @@ namespace EMStudio AZ::Entity* m_cameraEntity = nullptr; AZ::Component* m_cameraComponent = nullptr; AZ::Entity* m_modelEntity = nullptr; + AZ::Entity* m_actorEntity = nullptr; AZ::Data::AssetId m_modelAssetId; AZ::Entity* m_gridEntity = nullptr; diff --git a/Gems/EMotionFX/Assets/Editor/Layouts/Character2.layout b/Gems/EMotionFX/Assets/Editor/Layouts/Character2.layout new file mode 100644 index 0000000000000000000000000000000000000000..a97581727fce4261825b056591394bf56be2044d GIT binary patch literal 5388 zcmc&&U1%It6h7Ha(^?RV4cHgUDxxAp=HB@Sg`_HJOOh7bDuPhA$(k;jov_(dtkTd2 zt*w+65g`wvAc#VRs?p~@_$FdsguVz3DEOo(;!D=V@4GX1li8Y(hqQCToqOlbIp==o zyXV}Q>@%ZBMuuKEbnK{z^rBIQW+yA!t7u0nDdB#;N96Js7k^rs6T#5POIId;<2{A_ z;JY$MJu4j2kE>EYf6k}+S2Klc_pY3w{$Xp-)myz!v-usJ=YJTx`L{29^Cadf=hFVy zrTcz2INH5C>DTJp=bvSI*3GHydyM|&Z2s=uH>z#KVf~8SW1e4MSy-gM#iecL-rC!K z*R?Ot^7;Oo3yY7FEXWGPnfuzcM3aX1ZjssUY$_cgaN)bGa zB@?yEa5I^mo{{2sP}+|Jr9&^!j<3T4@?kV-PM@qCtu`lXtr;mQA3R5eq4Gm7@}(Fa zhFY!a_{phS11uEBgNu>~a6km1uY4&Y9}XtKByp$Vy$pisvwGj z0_tL@l}vSgJrwZ$pj51*F!J1ZK)G7SfrAf;0XGaB3`6olxn18;d+wt5-4{jr#xOA7 zUjJfXzf<{C+Pv#o!sTf>E;X5wL|RhEwShuv$*fG6yBYMaK%?@%e_9;TNO%|CO7Fwj z6*&DH;|ugIvVB>k+%{`%Yh!9JZ}H?2en7XOASF&i`cS>{gPA5WGo5M6cdOb2{4oBb z7?EQ#EC*yv0=$QOfMB1FB8+`e^bRRsN_&Ky4mP(EVNyzqxV*fIivSMh0C3qD03z@Z zi6<`Z1~BJhPGcN^BRxSu^};ttQQNGmOzP!?>NL>saL5bUpklg+ZRF7)%i(BMlL;hn^`BiU;d* z4F+#mYf#pA3e>%WcBHet$M>M|(!eykj}0@s|F9C6C=TVh%2NHpji`nUx%rvp$cHeu)bC%!qL1D$IHoP5Mg* z`!3OBXJd`_U<)_UWwM_7YE@|&?ivOsqe$qcPcrY #include #include - +#include namespace EMotionFX { @@ -96,6 +96,10 @@ namespace EMotionFX /// Returns skinning method used by the actor. virtual SkinningMethod GetSkinningMethod() const = 0; + // Use this to alter the actor asset. + virtual void SetActorAsset(AZ::Data::Asset actorAsset) = 0; + // virtual AZ::Data::Asset GetAsset() const = 0; + static const size_t s_invalidJointIndex = std::numeric_limits::max(); }; From c463721b52efbb216897d3b7d7d46f26bcad5cc7 Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 21 Sep 2021 09:51:52 -0700 Subject: [PATCH 118/293] move the function setactorasset Signed-off-by: rhhong --- .../Code/Source/Integration/Components/ActorComponent.h | 3 +-- .../Integration/Editor/Components/EditorActorComponent.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h index b376fa891d..15d9736f34 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h @@ -121,6 +121,7 @@ namespace EMotionFX void SetRenderCharacter(bool enable) override; bool GetRenderActorVisible() const override; SkinningMethod GetSkinningMethod() const override; + void SetActorAsset(AZ::Data::Asset actorAsset) override; ////////////////////////////////////////////////////////////////////////// // ActorComponentNotificationBus::Handler @@ -178,8 +179,6 @@ namespace EMotionFX void OnAssetReloaded(AZ::Data::Asset asset) override; bool IsPhysicsSceneSimulationFinishEventConnected() const; - - void SetActorAsset(AZ::Data::Asset actorAsset); AZ::Data::Asset GetActorAsset() const { return m_configuration.m_actorAsset; } private: diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h index e8f76bdd49..1d682b47d4 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h @@ -60,6 +60,7 @@ namespace EMotionFX bool GetRenderActorVisible() const override; size_t GetNumJoints() const override; SkinningMethod GetSkinningMethod() const override; + void SetActorAsset(AZ::Data::Asset actorAsset) override; // EditorActorComponentRequestBus overrides ... const AZ::Data::AssetId& GetActorAssetId() override; @@ -79,8 +80,6 @@ namespace EMotionFX void OnAssetReady(AZ::Data::Asset asset) override; void OnAssetReloaded(AZ::Data::Asset asset) override; - void SetActorAsset(AZ::Data::Asset actorAsset); - // BoundsRequestBus overrides ... AZ::Aabb GetWorldBounds() override; AZ::Aabb GetLocalBounds() override; From 82bfbd5c9819bf29a3d3e65ba5d378cd93169586 Mon Sep 17 00:00:00 2001 From: rhhong Date: Mon, 27 Sep 2021 16:27:32 -0700 Subject: [PATCH 119/293] Add ability to load actor from the ui Signed-off-by: rhhong --- .../Tools/EMStudio/AnimViewportRenderer.cpp | 149 +++++++++++------- .../Tools/EMStudio/AnimViewportRenderer.h | 17 +- .../Code/Tools/EMStudio/AnimViewportWidget.h | 2 + .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 43 ++++- .../Code/Tools/EMStudio/AtomRenderPlugin.h | 12 ++ .../Code/EMotionFX/Source/ActorManager.cpp | 6 + .../Code/EMotionFX/Source/ActorManager.h | 1 + 7 files changed, 170 insertions(+), 60 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 4db69cf8d9..f3294ddc09 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -9,8 +9,8 @@ #include #include -#include #include +#include #include #include #include @@ -32,12 +32,15 @@ #include #include +#include +#include #include -#pragma optimize("", off) + namespace EMStudio { static constexpr float DepthNear = 0.01f; + static constexpr const char* const s_actorComponentTypeId = "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"; AnimViewportRenderer::AnimViewportRenderer(AZStd::shared_ptr windowContext) : m_windowContext(windowContext) @@ -136,29 +139,6 @@ namespace EMStudio const AZ::Render::LightingPreset* preset = lightingPresetAsset->GetDataAs(); SetLightingPreset(preset); - // Create a static model. - // TODO: Replace this with actor component. - AzFramework::EntityContextRequestBus::EventResult( - m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); - AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); - - m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId); - m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_modelEntity->CreateComponent(azrtti_typeid()); - m_modelEntity->Activate(); - - // Create an actor. - // TODO: Support multiple actors. - AzFramework::EntityContextRequestBus::EventResult( - m_actorEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); - AZ_Assert(m_actorEntity != nullptr, "Failed to create model entity."); - - static constexpr const char* const ActorComponentTypeId = "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"; - m_actorEntity->CreateComponent(ActorComponentTypeId); - m_actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_actorEntity->CreateComponent(azrtti_typeid()); - m_actorEntity->Activate(); - // Create grid AzFramework::EntityContextRequestBus::EventResult( m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); @@ -175,24 +155,21 @@ namespace EMStudio m_gridEntity->CreateComponent(azrtti_typeid()); m_gridEntity->Activate(); - Reset(); + Reinit(); } AnimViewportRenderer::~AnimViewportRenderer() { - const AzFramework::EntityContextId entityContextId = m_entityContext->GetContextId(); - // Destory all the entities we created. - auto DestoryEntity = [](AZ::Entity* entity, AzFramework::EntityContextId contextId) + // Destroy all the entity we created. + m_entityContext->DestroyEntity(m_iblEntity); + m_entityContext->DestroyEntity(m_postProcessEntity); + m_entityContext->DestroyEntity(m_cameraEntity); + m_entityContext->DestroyEntity(m_gridEntity); + for (AZ::Entity* entity : m_actorEntities) { - AzFramework::EntityContextRequestBus::Event(contextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, entity); - entity = nullptr; - }; - DestoryEntity(m_iblEntity, entityContextId); - DestoryEntity(m_postProcessEntity, entityContextId); - DestoryEntity(m_cameraEntity, entityContextId); - DestoryEntity(m_modelEntity, entityContextId); - DestoryEntity(m_actorEntity, entityContextId); - DestoryEntity(m_gridEntity, entityContextId); + m_entityContext->DestroyEntity(entity); + } + m_actorEntities.clear(); m_entityContext->DestroyContext(); for (AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle& handle : m_lightHandles) @@ -212,7 +189,13 @@ namespace EMStudio m_scene = nullptr; } - void AnimViewportRenderer::Reset() + void AnimViewportRenderer::Reinit() + { + ReinitActorEntities(); + ResetEnvironment(); + } + + void AnimViewportRenderer::ResetEnvironment() { // Reset environment AZ::Transform iblTransform = AZ::Transform::CreateIdentity(); @@ -223,22 +206,6 @@ namespace EMStudio auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); - // Reset model - AZ::Transform modelTransform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::Event(m_modelEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, modelTransform); - - auto modelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( - "objects/shaderball_simple.azmodel", AZ::RPI::AssetUtils::TraceLevel::Assert); - AZ::Render::MeshComponentRequestBus::Event( - m_modelEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, modelAsset); - - // Reset the actor asset - AZ::TransformBus::Event(m_actorEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, modelTransform); - auto actorAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( - "objects/characters/jack/jack.actor", AZ::RPI::AssetUtils::TraceLevel::Assert); - EMotionFX::Integration::ActorComponentRequestBus::Event( - m_actorEntity->GetId(), &EMotionFX::Integration::ActorComponentRequestBus::Events::SetActorAsset, actorAsset); - Camera::Configuration cameraConfig; Camera::CameraRequestBus::EventResult( cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); @@ -247,7 +214,7 @@ namespace EMStudio static constexpr float StartingDistanceMultiplier = 2.0f; static constexpr float StartingRotationAngle = AZ::Constants::QuarterPi / 2.0f; - AZ::Vector3 targetPosition = modelTransform.GetTranslation(); + AZ::Vector3 targetPosition = iblTransform.GetTranslation(); const float distance = 1.0f * StartingDistanceMultiplier; const AZ::Quaternion cameraRotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), StartingRotationAngle); AZ::Vector3 cameraPosition(targetPosition.GetX(), targetPosition.GetY() - distance, targetPosition.GetZ()); @@ -260,6 +227,75 @@ namespace EMStudio m_cameraEntity->GetId(), &AZ::Debug::CameraControllerRequestBus::Events::Enable, azrtti_typeid()); } + void AnimViewportRenderer::ReinitActorEntities() + { + // 1. Destroy all the entities that does not point to any actorAsset anymore. + AZStd::set assetLookup; + AzFramework::EntityContext* entityContext = m_entityContext.get(); + const size_t numActors = EMotionFX::GetActorManager().GetNumActors(); + for (size_t i = 0; i < numActors; ++i) + { + assetLookup.emplace(EMotionFX::GetActorManager().GetActorAsset(i).GetId()); + } + m_actorEntities.erase( + AZStd::remove_if( + m_actorEntities.begin(), m_actorEntities.end(), + [&assetLookup, entityContext](AZ::Entity* entity) + { + EMotionFX::Integration::ActorComponent* actorComponent = + entity->FindComponent(); + if (assetLookup.find(actorComponent->GetActorAsset().GetId()) == assetLookup.end()) + { + entityContext->DestroyEntity(entity); + return true; + } + return false; + }), + m_actorEntities.end()); + + // 2. Create an entity for every actorAsset stored in actor manager. + for (size_t i = 0; i < numActors; ++i) + { + AZ::Data::Asset actorAsset = EMotionFX::GetActorManager().GetActorAsset(i); + if (!actorAsset->IsReady()) + { + continue; + } + + AZ::Entity* entity = FindActorEntity(actorAsset); + if (!entity) + { + m_actorEntities.emplace_back(CreateActorEntity(actorAsset)); + } + } + } + + AZ::Entity* AnimViewportRenderer::FindActorEntity(AZ::Data::Asset actorAsset) const + { + const auto foundEntity = AZStd::find_if( + begin(m_actorEntities), end(m_actorEntities), + [match = actorAsset](const AZ::Entity* entity) + { + EMotionFX::Integration::ActorComponent* actorComponent = entity->FindComponent(); + return actorComponent->GetActorAsset() == match; + }); + return foundEntity != end(m_actorEntities) ? (*foundEntity) : nullptr; + } + + AZ::Entity* AnimViewportRenderer::CreateActorEntity(AZ::Data::Asset actorAsset) + { + AZ::Entity* actorEntity = m_entityContext->CreateEntity(actorAsset->GetActor()->GetName()); + actorEntity->CreateComponent(s_actorComponentTypeId); + actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + actorEntity->CreateComponent(azrtti_typeid()); + actorEntity->Activate(); + + EMotionFX::Integration::ActorComponent* actorComponent = actorEntity->FindComponent(); + actorComponent->SetActorAsset(actorAsset); + + return actorEntity; + } + void AnimViewportRenderer::SetLightingPreset(const AZ::Render::LightingPreset* preset) { if (!preset) @@ -272,7 +308,6 @@ namespace EMStudio m_scene->GetFeatureProcessor(); AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); - AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId()) ->GetOrCreateExposureControlSettingsInterface(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index eb590f8d71..c131605caa 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -46,9 +47,21 @@ namespace EMStudio AnimViewportRenderer(AZStd::shared_ptr windowContext); ~AnimViewportRenderer(); + void Reinit(); + private: - void Reset(); + // This function reset the light, camera and other environment settings. + void ResetEnvironment(); + + // This function create in-editor entities for all the actor asset stored in the actor manager, + // and delete all the actor entities that no longer has an actor asset in the actor manager. + // Those entities are used in atom render viewport to visualize actors in animation editor. + void ReinitActorEntities(); + + AZ::Entity* CreateActorEntity(AZ::Data::Asset actorAsset); + + AZ::Entity* FindActorEntity(AZ::Data::Asset actorAsset) const; void SetLightingPreset(const AZ::Render::LightingPreset* preset); AZStd::shared_ptr m_windowContext; @@ -66,9 +79,9 @@ namespace EMStudio AZ::Entity* m_cameraEntity = nullptr; AZ::Component* m_cameraComponent = nullptr; AZ::Entity* m_modelEntity = nullptr; - AZ::Entity* m_actorEntity = nullptr; AZ::Data::AssetId m_modelAssetId; AZ::Entity* m_gridEntity = nullptr; + AZStd::vector m_actorEntities; AZStd::vector m_lightHandles; }; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 26bb9838b3..9e074c1d2c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -9,6 +9,7 @@ #include + namespace EMStudio { class AnimViewportRenderer; @@ -18,6 +19,7 @@ namespace EMStudio { public: AnimViewportWidget(QWidget* parent = nullptr); + AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get();} private: AZStd::unique_ptr m_renderer; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index c7e2178366..735c90d762 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -7,6 +7,11 @@ */ #include +#include + +#include +#include +#include #include namespace EMStudio @@ -66,6 +71,11 @@ namespace EMStudio return EMStudioPlugin::PLUGINTYPE_RENDERING; } + void AtomRenderPlugin::ReinitRenderer() + { + m_animViewportWidget->GetAnimViewportRenderer()->Reinit(); + } + bool AtomRenderPlugin::Init() { m_innerWidget = new QWidget(); @@ -75,9 +85,40 @@ namespace EMStudio verticalLayout->setSizeConstraint(QLayout::SetNoConstraint); verticalLayout->setSpacing(1); verticalLayout->setMargin(0); - m_animViewportWidget = new AnimViewportWidget(m_innerWidget); + // Register command callbacks. + m_createActorInstanceCallback = new CreateActorInstanceCallback(false); + EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("CreateActorInstance", m_createActorInstanceCallback); + + return true; + } + + // Command callbacks + bool ReinitAtomRenderPlugin() + { + EMStudioPlugin* plugin = EMStudio::GetPluginManager()->FindActivePlugin(static_cast(AtomRenderPlugin::CLASS_ID)); + if (!plugin) + { + AZ_Error("AtomRenderPlugin", false, "Cannot execute command callback. Atom render plugin does not exist."); + return false; + } + + AtomRenderPlugin* atomRenderPlugin = static_cast(plugin); + atomRenderPlugin->ReinitRenderer(); + return true; } + + bool AtomRenderPlugin::CreateActorInstanceCallback::Execute( + [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) + { + return ReinitAtomRenderPlugin(); + } + bool AtomRenderPlugin::CreateActorInstanceCallback::Undo( + [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) + { + return ReinitAtomRenderPlugin(); + } + } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index 0fb1443a96..9e5b3b6937 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -9,11 +9,18 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include + #include #include #endif +namespace AZ +{ + class Entity; +} + namespace EMStudio { class AtomRenderPlugin @@ -39,7 +46,12 @@ namespace EMStudio EMStudioPlugin* Clone(); EMStudioPlugin::EPluginType GetPluginType() const override; + void ReinitRenderer(); + private: + MCORE_DEFINECOMMANDCALLBACK(CreateActorInstanceCallback); + CreateActorInstanceCallback* m_createActorInstanceCallback; + QWidget* m_innerWidget; AnimViewportWidget* m_animViewportWidget; }; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp index 0779e55f85..0593575623 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp @@ -429,6 +429,12 @@ namespace EMotionFX } + ActorManager::ActorAssetData ActorManager::GetActorAsset(size_t nr) const + { + return m_actorAssets[nr]; + } + + const AZStd::vector& ActorManager::GetActorInstanceArray() const { return m_actorInstances; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h index e4ce0d6c94..e8bbf40661 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h @@ -80,6 +80,7 @@ namespace EMotionFX * @result A reference to the actor object that contains the array of Actor objects. */ Actor* GetActor(size_t nr) const; + ActorAssetData GetActorAsset(size_t nr) const; /** * Find the given actor by name. From 09f9e5c6c35a04327e35a663282df16f3082906e Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 28 Sep 2021 22:48:14 -0700 Subject: [PATCH 120/293] CR feedback Signed-off-by: rhhong --- .../Code/Tools/EMStudio/AnimViewportRenderer.cpp | 5 ++--- .../Code/Tools/EMStudio/AnimViewportRenderer.h | 6 +++--- .../Code/Tools/EMStudio/AnimViewportWidget.h | 2 +- .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 13 +++++++++++++ .../Code/Tools/EMStudio/AtomRenderPlugin.h | 2 ++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index f3294ddc09..c98a244d8f 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -40,7 +40,6 @@ namespace EMStudio { static constexpr float DepthNear = 0.01f; - static constexpr const char* const s_actorComponentTypeId = "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"; AnimViewportRenderer::AnimViewportRenderer(AZStd::shared_ptr windowContext) : m_windowContext(windowContext) @@ -229,7 +228,7 @@ namespace EMStudio void AnimViewportRenderer::ReinitActorEntities() { - // 1. Destroy all the entities that does not point to any actorAsset anymore. + // 1. Destroy all the entities that do not point to any actorAsset anymore. AZStd::set assetLookup; AzFramework::EntityContext* entityContext = m_entityContext.get(); const size_t numActors = EMotionFX::GetActorManager().GetNumActors(); @@ -285,7 +284,7 @@ namespace EMStudio AZ::Entity* AnimViewportRenderer::CreateActorEntity(AZ::Data::Asset actorAsset) { AZ::Entity* actorEntity = m_entityContext->CreateEntity(actorAsset->GetActor()->GetName()); - actorEntity->CreateComponent(s_actorComponentTypeId); + actorEntity->CreateComponent(azrtti_typeid()); actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); actorEntity->CreateComponent(azrtti_typeid()); actorEntity->Activate(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index c131605caa..8671068199 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -51,11 +51,11 @@ namespace EMStudio private: - // This function reset the light, camera and other environment settings. + // This function resets the light, camera and other environment settings. void ResetEnvironment(); - // This function create in-editor entities for all the actor asset stored in the actor manager, - // and delete all the actor entities that no longer has an actor asset in the actor manager. + // This function creates in-editor entities for all actor assets stored in the actor manager, + // and deletes all the actor entities that no longer has an actor asset in the actor manager. // Those entities are used in atom render viewport to visualize actors in animation editor. void ReinitActorEntities(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 9e074c1d2c..6d1d91ac0d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -19,7 +19,7 @@ namespace EMStudio { public: AnimViewportWidget(QWidget* parent = nullptr); - AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get();} + AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get(); } private: AZStd::unique_ptr m_renderer; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index 735c90d762..1f35212b8b 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -89,7 +89,9 @@ namespace EMStudio // Register command callbacks. m_createActorInstanceCallback = new CreateActorInstanceCallback(false); + m_removeActorInstanceCallback = new RemoveActorInstanceCallback(false); EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("CreateActorInstance", m_createActorInstanceCallback); + EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("RemoveActorInstance", m_removeActorInstanceCallback); return true; } @@ -121,4 +123,15 @@ namespace EMStudio return ReinitAtomRenderPlugin(); } + bool AtomRenderPlugin::RemoveActorInstanceCallback::Execute( + [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) + { + return ReinitAtomRenderPlugin(); + } + bool AtomRenderPlugin::RemoveActorInstanceCallback::Undo( + [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) + { + return ReinitAtomRenderPlugin(); + } + } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index 9e5b3b6937..475fd34180 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -50,7 +50,9 @@ namespace EMStudio private: MCORE_DEFINECOMMANDCALLBACK(CreateActorInstanceCallback); + MCORE_DEFINECOMMANDCALLBACK(RemoveActorInstanceCallback); CreateActorInstanceCallback* m_createActorInstanceCallback; + RemoveActorInstanceCallback* m_removeActorInstanceCallback; QWidget* m_innerWidget; AnimViewportWidget* m_animViewportWidget; From 47a2240fc3cd3d64c54ef93ca27e5eee99298ab8 Mon Sep 17 00:00:00 2001 From: rhhong Date: Fri, 1 Oct 2021 15:38:50 -0700 Subject: [PATCH 121/293] Using modular camera system to replace the camera entity. Signed-off-by: rhhong --- .../Tools/EMStudio/AnimViewportRenderer.cpp | 62 +++------ .../Tools/EMStudio/AnimViewportRenderer.h | 4 +- .../Tools/EMStudio/AnimViewportWidget.cpp | 122 +++++++++++++++++- .../Code/Tools/EMStudio/AnimViewportWidget.h | 8 +- .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 3 +- 5 files changed, 146 insertions(+), 53 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index c98a244d8f..c475ad8948 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -32,17 +32,19 @@ #include #include +#include #include #include -#include +#include +#include namespace EMStudio { static constexpr float DepthNear = 0.01f; - AnimViewportRenderer::AnimViewportRenderer(AZStd::shared_ptr windowContext) - : m_windowContext(windowContext) + AnimViewportRenderer::AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext) + : m_windowContext(viewportContext->GetWindowContext()) { // Create a new entity context m_entityContext = AZStd::make_unique(); @@ -72,33 +74,14 @@ namespace EMStudio m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *m_windowContext.get()); pipelineAsset.Release(); m_scene->AddRenderPipeline(m_renderPipeline); + m_renderPipeline->SetDefaultView(viewportContext->GetDefaultView()); // Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be // initialized properly with pipeline's pass information. m_scene->Activate(); AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); - AzFramework::EntityContextId entityContextId = m_entityContext->GetContextId(); - // Configure camera - AzFramework::EntityContextRequestBus::EventResult( - m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity"); - AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity."); - - // Add debug camera and controller components - AZ::Debug::CameraComponentConfig cameraConfig(m_windowContext); - cameraConfig.m_fovY = AZ::Constants::HalfPi; - cameraConfig.m_depthNear = DepthNear; - m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid()); - m_cameraComponent->SetConfiguration(cameraConfig); - m_cameraEntity->CreateComponent(azrtti_typeid()); - m_cameraEntity->CreateComponent(azrtti_typeid()); - m_cameraEntity->Init(); - m_cameraEntity->Activate(); - - // Connect camera to pipeline's default view after camera entity activated - m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId()); - // Get the FeatureProcessors m_meshFeatureProcessor = m_scene->GetFeatureProcessor(); @@ -162,7 +145,7 @@ namespace EMStudio // Destroy all the entity we created. m_entityContext->DestroyEntity(m_iblEntity); m_entityContext->DestroyEntity(m_postProcessEntity); - m_entityContext->DestroyEntity(m_cameraEntity); + //m_entityContext->DestroyEntity(m_cameraEntity); m_entityContext->DestroyEntity(m_gridEntity); for (AZ::Entity* entity : m_actorEntities) { @@ -204,26 +187,6 @@ namespace EMStudio AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); - - Camera::Configuration cameraConfig; - Camera::CameraRequestBus::EventResult( - cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); - - // Reset the camera position - static constexpr float StartingDistanceMultiplier = 2.0f; - static constexpr float StartingRotationAngle = AZ::Constants::QuarterPi / 2.0f; - - AZ::Vector3 targetPosition = iblTransform.GetTranslation(); - const float distance = 1.0f * StartingDistanceMultiplier; - const AZ::Quaternion cameraRotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), StartingRotationAngle); - AZ::Vector3 cameraPosition(targetPosition.GetX(), targetPosition.GetY() - distance, targetPosition.GetZ()); - cameraPosition = cameraRotation.TransformVector(cameraPosition); - AZ::Transform cameraTransform = AZ::Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); - AZ::TransformBus::Event(m_cameraEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, cameraTransform); - - // Setup primary camera controls - AZ::Debug::CameraControllerRequestBus::Event( - m_cameraEntity->GetId(), &AZ::Debug::CameraControllerRequestBus::Events::Enable, azrtti_typeid()); } void AnimViewportRenderer::ReinitActorEntities() @@ -292,6 +255,13 @@ namespace EMStudio EMotionFX::Integration::ActorComponent* actorComponent = actorEntity->FindComponent(); actorComponent->SetActorAsset(actorAsset); + // Since this entity belongs to the animation editor, we need to set the isOwnByRuntime flag to false. + actorComponent->GetActorInstance()->SetIsOwnedByRuntime(false); + // Selet the actor instance in the command manager after it has been created. + AZStd::string outResult; + EMStudioManager::GetInstance()->GetCommandManager()->ExecuteCommandInsideCommand( + AZStd::string::format("Select -actorInstanceID %i", actorComponent->GetActorInstance()->GetID()).c_str(), outResult); + return actorEntity; } @@ -312,8 +282,8 @@ namespace EMStudio ->GetOrCreateExposureControlSettingsInterface(); Camera::Configuration cameraConfig; - Camera::CameraRequestBus::EventResult( - cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); + cameraConfig.m_fovRadians = AZ::Constants::HalfPi; + cameraConfig.m_nearClipDistance = DepthNear; preset->ApplyLightingPreset( iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor, diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index 8671068199..dd420c175c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ namespace EMStudio public: AZ_CLASS_ALLOCATOR(AnimViewportRenderer, AZ::SystemAllocator, 0); - AnimViewportRenderer(AZStd::shared_ptr windowContext); + AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext); ~AnimViewportRenderer(); void Reinit(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 39b45507da..81678d477e 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -6,7 +6,11 @@ * */ +#include +#include +#include #include +#include #include #include @@ -17,7 +21,6 @@ namespace EMStudio : AtomToolsFramework::RenderViewportWidget(parent) { setObjectName(QString::fromUtf8("AtomViewportWidget")); - resize(869, 574); QSizePolicy qSize(QSizePolicy::Preferred, QSizePolicy::Preferred); qSize.setHorizontalStretch(0); qSize.setVerticalStretch(0); @@ -26,6 +29,119 @@ namespace EMStudio setAutoFillBackground(false); setStyleSheet(QString::fromUtf8("")); - m_renderer = AZStd::make_unique(GetViewportContext()->GetWindowContext()); + m_renderer = AZStd::make_unique(GetViewportContext()); + + SetupCameras(); + SetupCameraController(); + } + + template + AZStd::remove_cvref_t GetRegistry(const AZStd::string_view setting, T&& defaultValue) + { + AZStd::remove_cvref_t value = AZStd::forward(defaultValue); + if (const auto* registry = AZ::SettingsRegistry::Get()) + { + T potentialValue; + if (registry->Get(potentialValue, setting)) + { + value = AZStd::move(potentialValue); + } + } + + return value; + } + + // TODO: TranslateCameraInput should have a way to initiate with default channel id setup. + static AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds() + { + constexpr AZStd::string_view CameraTranslateForwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateForwardId"; + constexpr AZStd::string_view CameraTranslateBackwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateBackwardId"; + constexpr AZStd::string_view CameraTranslateLeftIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateLeftId"; + constexpr AZStd::string_view CameraTranslateRightIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateRightId"; + constexpr AZStd::string_view CameraTranslateUpIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpId"; + constexpr AZStd::string_view CameraTranslateDownIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpDownId"; + constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId"; + + AzFramework::TranslateCameraInputChannelIds translateCameraInputChannelIds; + translateCameraInputChannelIds.m_leftChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateLeftIdSetting, AZStd::string("keyboard_key_alphanumeric_A")).c_str()); + translateCameraInputChannelIds.m_rightChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateRightIdSetting, AZStd::string("keyboard_key_alphanumeric_D")).c_str()); + translateCameraInputChannelIds.m_forwardChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateForwardIdSetting, AZStd::string("keyboard_key_alphanumeric_W")).c_str()); + translateCameraInputChannelIds.m_backwardChannelId = AzFramework::InputChannelId( + GetRegistry(CameraTranslateBackwardIdSetting, AZStd::string("keyboard_key_alphanumeric_S")).c_str()); + translateCameraInputChannelIds.m_upChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateUpIdSetting, AZStd::string("keyboard_key_alphanumeric_E")).c_str()); + translateCameraInputChannelIds.m_downChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateDownIdSetting, AZStd::string("keyboard_key_alphanumeric_Q")).c_str()); + translateCameraInputChannelIds.m_boostChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateBoostIdSetting, AZStd::string("keyboard_key_modifier_shift_l")).c_str()); + + return translateCameraInputChannelIds; + } + + void AnimViewportWidget::SetupCameras() + { + constexpr AZStd::string_view CameraOrbitIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitId"; + constexpr AZStd::string_view CameraOrbitLookIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitLookId"; + + m_orbitRotateCamera = AZStd::make_shared( + AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str())); + + const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds(); + m_orbitTranslateCamera = + AZStd::make_shared(AzFramework::OrbitTranslation, translateCameraInputChannelIds); + m_orbitDollyScrollCamera = AZStd::make_shared(); + } + + void AnimViewportWidget::SetupCameraController() + { + auto controller = AZStd::make_shared(); + controller->SetCameraViewportContextBuilderCallback( + [viewportId = + GetViewportContext()->GetId()](AZStd::unique_ptr& cameraViewportContext) + { + cameraViewportContext = AZStd::make_unique(viewportId); + }); + + controller->SetCameraPriorityBuilderCallback( + [](AtomToolsFramework::CameraControllerPriorityFn& cameraControllerPriorityFn) + { + cameraControllerPriorityFn = AtomToolsFramework::DefaultCameraControllerPriority; + }); + + controller->SetCameraPropsBuilderCallback( + [](AzFramework::CameraProps& cameraProps) + { + cameraProps.m_rotateSmoothnessFn = [] + { + return 5.0f; + }; + + cameraProps.m_translateSmoothnessFn = [] + { + return 5.0f; + }; + + cameraProps.m_rotateSmoothingEnabledFn = [] + { + return true; + }; + + cameraProps.m_translateSmoothingEnabledFn = [] + { + return true; + }; + }); + + controller->SetCameraListBuilderCallback( + [this](AzFramework::Cameras& cameras) + { + cameras.AddCamera(m_orbitRotateCamera); + cameras.AddCamera(m_orbitTranslateCamera); + cameras.AddCamera(m_orbitDollyScrollCamera); + }); + GetControllerList()->Add(controller); } -} +} // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 6d1d91ac0d..64bf4cd5dd 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -8,7 +8,7 @@ #pragma once #include - +#include namespace EMStudio { @@ -22,6 +22,12 @@ namespace EMStudio AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get(); } private: + void SetupCameras(); + void SetupCameraController(); + AZStd::unique_ptr m_renderer; + AZStd::shared_ptr m_orbitRotateCamera; + AZStd::shared_ptr m_orbitTranslateCamera; + AZStd::shared_ptr m_orbitDollyScrollCamera; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index 1f35212b8b..948006e2b5 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -28,7 +28,7 @@ namespace EMStudio const char* AtomRenderPlugin::GetName() const { - return "Atom Render Window"; + return "Atom Render Window (Preview)"; } uint32 AtomRenderPlugin::GetClassID() const @@ -86,6 +86,7 @@ namespace EMStudio verticalLayout->setSpacing(1); verticalLayout->setMargin(0); m_animViewportWidget = new AnimViewportWidget(m_innerWidget); + verticalLayout->addWidget(m_animViewportWidget); // Register command callbacks. m_createActorInstanceCallback = new CreateActorInstanceCallback(false); From ffa637d115903758beecf05ce43ba21e5edbeb1c Mon Sep 17 00:00:00 2001 From: rhhong Date: Fri, 1 Oct 2021 16:04:49 -0700 Subject: [PATCH 122/293] Code cleanup Signed-off-by: rhhong --- .../EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index c475ad8948..a75095568f 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -145,7 +145,6 @@ namespace EMStudio // Destroy all the entity we created. m_entityContext->DestroyEntity(m_iblEntity); m_entityContext->DestroyEntity(m_postProcessEntity); - //m_entityContext->DestroyEntity(m_cameraEntity); m_entityContext->DestroyEntity(m_gridEntity); for (AZ::Entity* entity : m_actorEntities) { From 10febe2a4baa4309de50ffcebfc09ffacdfc7bc5 Mon Sep 17 00:00:00 2001 From: rhhong Date: Mon, 4 Oct 2021 18:52:11 -0700 Subject: [PATCH 123/293] Move some utility class and settings to a setting file. Signed-off-by: rhhong --- .../Tools/EMStudio/AnimViewportSettings.cpp | 73 +++++++++++++++++++ .../Tools/EMStudio/AnimViewportSettings.h | 37 ++++++++++ .../Tools/EMStudio/AnimViewportWidget.cpp | 63 ++-------------- .../Code/emotionfx_atom_editor_files.cmake | 2 + 4 files changed, 119 insertions(+), 56 deletions(-) create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp new file mode 100644 index 0000000000..99bfae91fd --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp @@ -0,0 +1,73 @@ +/* + * 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 + +namespace EMStudio::ViewportUtil +{ + constexpr AZStd::string_view CameraRotateSmoothnessSetting = "/Amazon/Preferences/Editor/Camera/RotateSmoothness"; + constexpr AZStd::string_view CameraTranslateSmoothnessSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothness"; + constexpr AZStd::string_view CameraTranslateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothing"; + constexpr AZStd::string_view CameraRotateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/RotateSmoothing"; + + constexpr AZStd::string_view CameraOrbitLookIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitLookId"; + constexpr AZStd::string_view CameraTranslateForwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateForwardId"; + constexpr AZStd::string_view CameraTranslateBackwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateBackwardId"; + constexpr AZStd::string_view CameraTranslateLeftIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateLeftId"; + constexpr AZStd::string_view CameraTranslateRightIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateRightId"; + constexpr AZStd::string_view CameraTranslateUpIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpId"; + constexpr AZStd::string_view CameraTranslateDownIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpDownId"; + constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId"; + + AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds() + { + AzFramework::TranslateCameraInputChannelIds translateCameraInputChannelIds; + translateCameraInputChannelIds.m_leftChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateLeftIdSetting, AZStd::string("keyboard_key_alphanumeric_A")).c_str()); + translateCameraInputChannelIds.m_rightChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateRightIdSetting, AZStd::string("keyboard_key_alphanumeric_D")).c_str()); + translateCameraInputChannelIds.m_forwardChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateForwardIdSetting, AZStd::string("keyboard_key_alphanumeric_W")).c_str()); + translateCameraInputChannelIds.m_backwardChannelId = AzFramework::InputChannelId( + GetRegistry(CameraTranslateBackwardIdSetting, AZStd::string("keyboard_key_alphanumeric_S")).c_str()); + translateCameraInputChannelIds.m_upChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateUpIdSetting, AZStd::string("keyboard_key_alphanumeric_E")).c_str()); + translateCameraInputChannelIds.m_downChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateDownIdSetting, AZStd::string("keyboard_key_alphanumeric_Q")).c_str()); + translateCameraInputChannelIds.m_boostChannelId = + AzFramework::InputChannelId(GetRegistry(CameraTranslateBoostIdSetting, AZStd::string("keyboard_key_modifier_shift_l")).c_str()); + + return translateCameraInputChannelIds; + } + + float CameraRotateSmoothness() + { + return aznumeric_cast(GetRegistry(CameraRotateSmoothnessSetting, 5.0)); + } + + float CameraTranslateSmoothness() + { + return aznumeric_cast(GetRegistry(CameraTranslateSmoothnessSetting, 5.0)); + } + + bool CameraRotateSmoothingEnabled() + { + return GetRegistry(CameraRotateSmoothingSetting, true); + } + + bool CameraTranslateSmoothingEnabled() + { + return GetRegistry(CameraTranslateSmoothingSetting, true); + } + + AzFramework::InputChannelId BuildRotateCameraInputId() + { + AzFramework::InputChannelId inputChannelId( + EMStudio::ViewportUtil::GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str()); + return inputChannelId; + } +} diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h new file mode 100644 index 0000000000..5fa14a8aae --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once +#include +#include + +namespace EMStudio::ViewportUtil +{ + template + AZStd::remove_cvref_t GetRegistry(const AZStd::string_view setting, T&& defaultValue) + { + AZStd::remove_cvref_t value = AZStd::forward(defaultValue); + if (const auto* registry = AZ::SettingsRegistry::Get()) + { + T potentialValue; + if (registry->Get(potentialValue, setting)) + { + value = AZStd::move(potentialValue); + } + } + + return value; + } + + float CameraRotateSmoothness(); + float CameraTranslateSmoothness(); + bool CameraRotateSmoothingEnabled(); + bool CameraTranslateSmoothingEnabled(); + + AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds(); + AzFramework::InputChannelId BuildRotateCameraInputId(); +} diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 81678d477e..2a5006767a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace EMStudio { @@ -35,61 +36,11 @@ namespace EMStudio SetupCameraController(); } - template - AZStd::remove_cvref_t GetRegistry(const AZStd::string_view setting, T&& defaultValue) - { - AZStd::remove_cvref_t value = AZStd::forward(defaultValue); - if (const auto* registry = AZ::SettingsRegistry::Get()) - { - T potentialValue; - if (registry->Get(potentialValue, setting)) - { - value = AZStd::move(potentialValue); - } - } - - return value; - } - - // TODO: TranslateCameraInput should have a way to initiate with default channel id setup. - static AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds() - { - constexpr AZStd::string_view CameraTranslateForwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateForwardId"; - constexpr AZStd::string_view CameraTranslateBackwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateBackwardId"; - constexpr AZStd::string_view CameraTranslateLeftIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateLeftId"; - constexpr AZStd::string_view CameraTranslateRightIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateRightId"; - constexpr AZStd::string_view CameraTranslateUpIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpId"; - constexpr AZStd::string_view CameraTranslateDownIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpDownId"; - constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId"; - - AzFramework::TranslateCameraInputChannelIds translateCameraInputChannelIds; - translateCameraInputChannelIds.m_leftChannelId = - AzFramework::InputChannelId(GetRegistry(CameraTranslateLeftIdSetting, AZStd::string("keyboard_key_alphanumeric_A")).c_str()); - translateCameraInputChannelIds.m_rightChannelId = - AzFramework::InputChannelId(GetRegistry(CameraTranslateRightIdSetting, AZStd::string("keyboard_key_alphanumeric_D")).c_str()); - translateCameraInputChannelIds.m_forwardChannelId = - AzFramework::InputChannelId(GetRegistry(CameraTranslateForwardIdSetting, AZStd::string("keyboard_key_alphanumeric_W")).c_str()); - translateCameraInputChannelIds.m_backwardChannelId = AzFramework::InputChannelId( - GetRegistry(CameraTranslateBackwardIdSetting, AZStd::string("keyboard_key_alphanumeric_S")).c_str()); - translateCameraInputChannelIds.m_upChannelId = - AzFramework::InputChannelId(GetRegistry(CameraTranslateUpIdSetting, AZStd::string("keyboard_key_alphanumeric_E")).c_str()); - translateCameraInputChannelIds.m_downChannelId = - AzFramework::InputChannelId(GetRegistry(CameraTranslateDownIdSetting, AZStd::string("keyboard_key_alphanumeric_Q")).c_str()); - translateCameraInputChannelIds.m_boostChannelId = - AzFramework::InputChannelId(GetRegistry(CameraTranslateBoostIdSetting, AZStd::string("keyboard_key_modifier_shift_l")).c_str()); - - return translateCameraInputChannelIds; - } - void AnimViewportWidget::SetupCameras() { - constexpr AZStd::string_view CameraOrbitIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitId"; - constexpr AZStd::string_view CameraOrbitLookIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitLookId"; - - m_orbitRotateCamera = AZStd::make_shared( - AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str())); + m_orbitRotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::BuildRotateCameraInputId()); - const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds(); + const auto translateCameraInputChannelIds = EMStudio::ViewportUtil::BuildTranslateCameraInputChannelIds(); m_orbitTranslateCamera = AZStd::make_shared(AzFramework::OrbitTranslation, translateCameraInputChannelIds); m_orbitDollyScrollCamera = AZStd::make_shared(); @@ -116,22 +67,22 @@ namespace EMStudio { cameraProps.m_rotateSmoothnessFn = [] { - return 5.0f; + return EMStudio::ViewportUtil::CameraRotateSmoothness(); }; cameraProps.m_translateSmoothnessFn = [] { - return 5.0f; + return EMStudio::ViewportUtil::CameraTranslateSmoothness(); }; cameraProps.m_rotateSmoothingEnabledFn = [] { - return true; + return EMStudio::ViewportUtil::CameraRotateSmoothingEnabled(); }; cameraProps.m_translateSmoothingEnabledFn = [] { - return true; + return EMStudio::ViewportUtil::CameraTranslateSmoothingEnabled(); }; }); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake index 5c8728a8e9..a88581099f 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake @@ -16,4 +16,6 @@ set(FILES Tools/EMStudio/AnimViewportWidget.cpp Tools/EMStudio/AnimViewportRenderer.h Tools/EMStudio/AnimViewportRenderer.cpp + Tools/EMStudio/AnimViewportSettings.h + Tools/EMStudio/AnimViewportSettings.cpp ) From 646369c1b5b27baab176838ba0e4904d55b4ddfa Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 5 Oct 2021 13:03:22 -0700 Subject: [PATCH 124/293] update camera naming and behavior after the merge in Signed-off-by: rhhong --- .../Tools/EMStudio/AnimViewportSettings.cpp | 4 +--- .../Tools/EMStudio/AnimViewportWidget.cpp | 19 ++++++++++++------- .../Code/Tools/EMStudio/AnimViewportWidget.h | 6 +++--- .../Source/RenderPlugin/RenderViewWidget.cpp | 4 ++-- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp index 99bfae91fd..347e077af3 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportSettings.cpp @@ -66,8 +66,6 @@ namespace EMStudio::ViewportUtil AzFramework::InputChannelId BuildRotateCameraInputId() { - AzFramework::InputChannelId inputChannelId( - EMStudio::ViewportUtil::GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str()); - return inputChannelId; + return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str()); } } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 2a5006767a..d3fd719d38 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -38,12 +38,17 @@ namespace EMStudio void AnimViewportWidget::SetupCameras() { - m_orbitRotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::BuildRotateCameraInputId()); + m_pivotRotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::BuildRotateCameraInputId()); const auto translateCameraInputChannelIds = EMStudio::ViewportUtil::BuildTranslateCameraInputChannelIds(); - m_orbitTranslateCamera = - AZStd::make_shared(AzFramework::OrbitTranslation, translateCameraInputChannelIds); - m_orbitDollyScrollCamera = AZStd::make_shared(); + m_pivotTranslateCamera = AZStd::make_shared( + translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot); + m_pivotTranslateCamera.get()->m_translateSpeedFn = [] + { + return 3.0f; + }; + + m_pivotDollyScrollCamera = AZStd::make_shared(); } void AnimViewportWidget::SetupCameraController() @@ -89,9 +94,9 @@ namespace EMStudio controller->SetCameraListBuilderCallback( [this](AzFramework::Cameras& cameras) { - cameras.AddCamera(m_orbitRotateCamera); - cameras.AddCamera(m_orbitTranslateCamera); - cameras.AddCamera(m_orbitDollyScrollCamera); + cameras.AddCamera(m_pivotRotateCamera); + cameras.AddCamera(m_pivotTranslateCamera); + cameras.AddCamera(m_pivotDollyScrollCamera); }); GetControllerList()->Add(controller); } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 64bf4cd5dd..70b4e1e667 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -26,8 +26,8 @@ namespace EMStudio void SetupCameraController(); AZStd::unique_ptr m_renderer; - AZStd::shared_ptr m_orbitRotateCamera; - AZStd::shared_ptr m_orbitTranslateCamera; - AZStd::shared_ptr m_orbitDollyScrollCamera; + AZStd::shared_ptr m_pivotRotateCamera; + AZStd::shared_ptr m_pivotTranslateCamera; + AZStd::shared_ptr m_pivotDollyScrollCamera; }; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp index 93a6dd3019..fe8fb61f02 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp @@ -155,12 +155,12 @@ namespace EMStudio cameraMenu->addAction("Reset Camera", [this]() { this->OnResetCamera(); }); QAction* showSelectedAction = cameraMenu->addAction("Show Selected", this, &RenderViewWidget::OnShowSelected); - showSelectedAction->setShortcut(Qt::Key_S); + showSelectedAction->setShortcut(QKeySequence(Qt::Key_S + Qt::SHIFT)); GetMainWindow()->GetShortcutManager()->RegisterKeyboardShortcut(showSelectedAction, RenderPlugin::s_renderWindowShortcutGroupName, true); addAction(showSelectedAction); QAction* showEntireSceneAction = cameraMenu->addAction("Show Entire Scene", this, &RenderViewWidget::OnShowEntireScene); - showEntireSceneAction->setShortcut(Qt::Key_A); + showEntireSceneAction->setShortcut(QKeySequence(Qt::Key_A + Qt::SHIFT)); GetMainWindow()->GetShortcutManager()->RegisterKeyboardShortcut(showEntireSceneAction, RenderPlugin::s_renderWindowShortcutGroupName, true); addAction(showEntireSceneAction); From 88970403157ee9df0952d5dbf9ef5dae1ddf8f91 Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 5 Oct 2021 18:08:02 -0700 Subject: [PATCH 125/293] Gems/EMotionFX/Assets/Editor/Layouts/Character2.layout Signed-off-by: rhhong --- .../Assets/Editor/Layouts/Character2.layout | Bin 5388 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Gems/EMotionFX/Assets/Editor/Layouts/Character2.layout diff --git a/Gems/EMotionFX/Assets/Editor/Layouts/Character2.layout b/Gems/EMotionFX/Assets/Editor/Layouts/Character2.layout deleted file mode 100644 index a97581727fce4261825b056591394bf56be2044d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5388 zcmc&&U1%It6h7Ha(^?RV4cHgUDxxAp=HB@Sg`_HJOOh7bDuPhA$(k;jov_(dtkTd2 zt*w+65g`wvAc#VRs?p~@_$FdsguVz3DEOo(;!D=V@4GX1li8Y(hqQCToqOlbIp==o zyXV}Q>@%ZBMuuKEbnK{z^rBIQW+yA!t7u0nDdB#;N96Js7k^rs6T#5POIId;<2{A_ z;JY$MJu4j2kE>EYf6k}+S2Klc_pY3w{$Xp-)myz!v-usJ=YJTx`L{29^Cadf=hFVy zrTcz2INH5C>DTJp=bvSI*3GHydyM|&Z2s=uH>z#KVf~8SW1e4MSy-gM#iecL-rC!K z*R?Ot^7;Oo3yY7FEXWGPnfuzcM3aX1ZjssUY$_cgaN)bGa zB@?yEa5I^mo{{2sP}+|Jr9&^!j<3T4@?kV-PM@qCtu`lXtr;mQA3R5eq4Gm7@}(Fa zhFY!a_{phS11uEBgNu>~a6km1uY4&Y9}XtKByp$Vy$pisvwGj z0_tL@l}vSgJrwZ$pj51*F!J1ZK)G7SfrAf;0XGaB3`6olxn18;d+wt5-4{jr#xOA7 zUjJfXzf<{C+Pv#o!sTf>E;X5wL|RhEwShuv$*fG6yBYMaK%?@%e_9;TNO%|CO7Fwj z6*&DH;|ugIvVB>k+%{`%Yh!9JZ}H?2en7XOASF&i`cS>{gPA5WGo5M6cdOb2{4oBb z7?EQ#EC*yv0=$QOfMB1FB8+`e^bRRsN_&Ky4mP(EVNyzqxV*fIivSMh0C3qD03z@Z zi6<`Z1~BJhPGcN^BRxSu^};ttQQNGmOzP!?>NL>saL5bUpklg+ZRF7)%i(BMlL;hn^`BiU;d* z4F+#mYf#pA3e>%WcBHet$M>M|(!eykj}0@s|F9C6C=TVh%2NHpji`nUx%rvp$cHeu)bC%!qL1D$IHoP5Mg* z`!3OBXJd`_U<)_UWwM_7YE@|&?ivOsqe$qcPcrY Date: Wed, 6 Oct 2021 22:28:18 -0700 Subject: [PATCH 126/293] CR feedback Signed-off-by: rhhong --- .../Source/Editor/EditorSystemComponent.cpp | 2 +- .../Source/Editor/EditorSystemComponent.h | 2 +- .../Tools/EMStudio/AnimViewportRenderer.cpp | 1 - .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 20 +++++++++++-------- .../Code/Tools/EMStudio/AtomRenderPlugin.h | 10 ++++++---- .../Code/EMotionFX/Source/ActorManager.cpp | 3 +-- .../Code/EMotionFX/Source/ActorManager.h | 1 - .../Source/NodeWindow/NodeWindowPlugin.h | 1 + .../Include/Integration/ActorComponentBus.h | 1 - .../Source/Integration/Assets/ActorAsset.h | 2 ++ 10 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp index 64f7f2dd97..edd2f074fe 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.cpp @@ -34,6 +34,6 @@ namespace AZ::EMotionFXAtom void EditorSystemComponent::OnRegisterPlugin() { EMStudio::PluginManager* pluginManager = EMStudio::EMStudioManager::GetInstance()->GetPluginManager(); - pluginManager->RegisterPlugin(new EMStudio::AtomRenderPlugin()); + pluginManager->RegisterPlugin(aznew EMStudio::AtomRenderPlugin()); } } // namespace AZ::EMotionFXAtom diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h index 9da98bcf42..80ff7b0b8d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/Editor/EditorSystemComponent.h @@ -22,7 +22,7 @@ namespace AZ::EMotionFXAtom static void Reflect(ReflectContext* context); protected: - // AZ::Component + // AZ::Component overrides void Activate() override; void Deactivate() override; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index a75095568f..08f85ab1be 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -59,7 +59,6 @@ namespace EMStudio m_frameworkScene->SetSubsystem(m_entityContext.get()); // Create and register a scene with all available feature processors - // TODO: We don't need every procesors, only register the processor we are going to use. AZ::RPI::SceneDescriptor sceneDesc; m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index 948006e2b5..90f6d54466 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -11,11 +11,14 @@ #include #include +#include #include #include namespace EMStudio { + AZ_CLASS_ALLOCATOR_IMPL(AtomRenderPlugin, EMotionFX::EditorAllocator, 0); + AtomRenderPlugin::AtomRenderPlugin() : DockWidgetPlugin() { @@ -74,6 +77,7 @@ namespace EMStudio void AtomRenderPlugin::ReinitRenderer() { m_animViewportWidget->GetAnimViewportRenderer()->Reinit(); + m_animViewportWidget->ResetCameraPosition(); } bool AtomRenderPlugin::Init() @@ -89,10 +93,10 @@ namespace EMStudio verticalLayout->addWidget(m_animViewportWidget); // Register command callbacks. - m_createActorInstanceCallback = new CreateActorInstanceCallback(false); - m_removeActorInstanceCallback = new RemoveActorInstanceCallback(false); - EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("CreateActorInstance", m_createActorInstanceCallback); - EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("RemoveActorInstance", m_removeActorInstanceCallback); + m_importActorCallback = new ImportActorCallback(false); + m_removeActorCallback = new RemoveActorCallback(false); + EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("ImportActor", m_importActorCallback); + EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("RemoveActor", m_removeActorCallback); return true; } @@ -113,23 +117,23 @@ namespace EMStudio return true; } - bool AtomRenderPlugin::CreateActorInstanceCallback::Execute( + bool AtomRenderPlugin::ImportActorCallback::Execute( [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) { return ReinitAtomRenderPlugin(); } - bool AtomRenderPlugin::CreateActorInstanceCallback::Undo( + bool AtomRenderPlugin::ImportActorCallback::Undo( [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) { return ReinitAtomRenderPlugin(); } - bool AtomRenderPlugin::RemoveActorInstanceCallback::Execute( + bool AtomRenderPlugin::RemoveActorCallback::Execute( [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) { return ReinitAtomRenderPlugin(); } - bool AtomRenderPlugin::RemoveActorInstanceCallback::Undo( + bool AtomRenderPlugin::RemoveActorCallback::Undo( [[maybe_unused]] MCore::Command* command, [[maybe_unused]] const MCore::CommandLine& commandLine) { return ReinitAtomRenderPlugin(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index 475fd34180..e890f9aa4b 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -27,6 +27,8 @@ namespace EMStudio : public DockWidgetPlugin { public: + AZ_CLASS_ALLOCATOR_DECL + enum { CLASS_ID = 0x32b0c04d @@ -49,10 +51,10 @@ namespace EMStudio void ReinitRenderer(); private: - MCORE_DEFINECOMMANDCALLBACK(CreateActorInstanceCallback); - MCORE_DEFINECOMMANDCALLBACK(RemoveActorInstanceCallback); - CreateActorInstanceCallback* m_createActorInstanceCallback; - RemoveActorInstanceCallback* m_removeActorInstanceCallback; + MCORE_DEFINECOMMANDCALLBACK(ImportActorCallback); + MCORE_DEFINECOMMANDCALLBACK(RemoveActorCallback); + ImportActorCallback* m_importActorCallback; + RemoveActorCallback* m_removeActorCallback; QWidget* m_innerWidget; AnimViewportWidget* m_animViewportWidget; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp index 0593575623..be3ac10d45 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp @@ -31,7 +31,6 @@ namespace EMotionFX SetScheduler(MultiThreadScheduler::Create()); // reserve memory - m_actorAssets.reserve(32); m_actorInstances.reserve(1024); m_rootActorInstances.reserve(1024); } @@ -429,7 +428,7 @@ namespace EMotionFX } - ActorManager::ActorAssetData ActorManager::GetActorAsset(size_t nr) const + ActorAssetData ActorManager::GetActorAsset(size_t nr) const { return m_actorAssets[nr]; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h index e8bbf40661..003153b36c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.h @@ -42,7 +42,6 @@ namespace EMotionFX friend class EMotionFXManager; public: - using ActorAssetData = AZ::Data::Asset; static ActorManager* Create(); /** diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h index 4c530fffdc..59c9f78719 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeWindow/NodeWindowPlugin.h @@ -90,6 +90,7 @@ namespace EMStudio AZStd::unique_ptr m_actorInfo; AZStd::unique_ptr m_nodeInfo; + // Use this flag to defer the reinit function to main thread. bool m_reinitRequested = false; }; } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h b/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h index 325191af81..4161b3c77d 100644 --- a/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h +++ b/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h @@ -98,7 +98,6 @@ namespace EMotionFX // Use this to alter the actor asset. virtual void SetActorAsset(AZ::Data::Asset actorAsset) = 0; - // virtual AZ::Data::Asset GetAsset() const = 0; static const size_t s_invalidJointIndex = std::numeric_limits::max(); }; diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h index c256fa5283..4b13603ed5 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.h @@ -80,6 +80,8 @@ namespace EMotionFX const char* GetBrowserIcon() const override; }; } // namespace Integration + + using ActorAssetData = AZ::Data::Asset; } // namespace EMotionFX namespace AZ From 265d3792f07b3f557a1739a8421a5aeaff5e6133 Mon Sep 17 00:00:00 2001 From: rhhong Date: Wed, 6 Oct 2021 22:36:19 -0700 Subject: [PATCH 127/293] fix broken build Signed-off-by: rhhong --- .../Code/Tools/EMStudio/AnimViewportRenderer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 08f85ab1be..ab54b1fa38 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -163,7 +163,10 @@ namespace EMStudio auto sceneSystem = AzFramework::SceneSystemInterface::Get(); AZ_Assert(sceneSystem, "AtomViewportRenderer was unable to get the scene system during destruction."); bool removeSuccess = sceneSystem->RemoveScene("AnimViewport"); - AZ_Assert(removeSuccess, "AtomViewportRenderer should be removed."); + if (!removeSuccess) + { + AZ_Assert(false, "AtomViewportRenderer should be removed."); + } AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); m_scene = nullptr; From a448caea7ceca018b045971d60329a3c784b9629 Mon Sep 17 00:00:00 2001 From: rhhong Date: Thu, 7 Oct 2021 08:55:52 -0700 Subject: [PATCH 128/293] fix broken build Signed-off-by: rhhong --- .../EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index 90f6d54466..b51a90587f 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -77,7 +77,6 @@ namespace EMStudio void AtomRenderPlugin::ReinitRenderer() { m_animViewportWidget->GetAnimViewportRenderer()->Reinit(); - m_animViewportWidget->ResetCameraPosition(); } bool AtomRenderPlugin::Init() From 4d2f65c4d88fbb1c57a74a06339dce83b8437dc9 Mon Sep 17 00:00:00 2001 From: rhhong Date: Thu, 7 Oct 2021 11:48:09 -0700 Subject: [PATCH 129/293] code review feedback 2 Signed-off-by: rhhong --- .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 3 +-- .../Code/Tools/EMStudio/AtomRenderPlugin.h | 11 +++++------ Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp | 4 ++-- .../EMStudioSDK/Source/EMStudioManager.h | 2 +- Gems/EMotionFX/Code/Tests/ActorFixture.cpp | 6 +++--- Gems/EMotionFX/Code/Tests/ActorFixture.h | 2 +- 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index b51a90587f..91a34e16cd 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -137,5 +137,4 @@ namespace EMStudio { return ReinitAtomRenderPlugin(); } - -} +}// namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index e890f9aa4b..1516b45e77 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -53,10 +53,9 @@ namespace EMStudio private: MCORE_DEFINECOMMANDCALLBACK(ImportActorCallback); MCORE_DEFINECOMMANDCALLBACK(RemoveActorCallback); - ImportActorCallback* m_importActorCallback; - RemoveActorCallback* m_removeActorCallback; - - QWidget* m_innerWidget; - AnimViewportWidget* m_animViewportWidget; + ImportActorCallback* m_importActorCallback = nullptr; + RemoveActorCallback* m_removeActorCallback = nullptr; + QWidget* m_innerWidget = nullptr; + AnimViewportWidget* m_animViewportWidget = nullptr; }; -} +}// namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp index be3ac10d45..184aac6e2c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorManager.cpp @@ -118,9 +118,9 @@ namespace EMotionFX if (FindActorIndex(actorAsset.GetId()) != InvalidIndex) { MCore::LogWarning( - "EMotionFX::ActorManager::RegisterActor() - The actor at location 0x%x has already been registered as actor, most likely " + "EMotionFX::ActorManager::RegisterActor() - The actor %s has already been registered as actor, most likely " "already by the LoadActor of the importer.", - actorAsset->GetActor()); + actorAsset->GetActor()->GetName()); UnlockActors(); return; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h index e7a9397b22..4c3139b77a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioManager.h @@ -154,7 +154,7 @@ namespace EMStudio void OnRemoveCommand(size_t historyIndex) override { MCORE_UNUSED(historyIndex); } void OnSetCurrentCommand(size_t index) override { MCORE_UNUSED(index); } }; - EventProcessingCallback* m_eventProcessingCallback; + EventProcessingCallback* m_eventProcessingCallback = nullptr; }; // Shortcuts diff --git a/Gems/EMotionFX/Code/Tests/ActorFixture.cpp b/Gems/EMotionFX/Code/Tests/ActorFixture.cpp index 31c3a0c721..33c26ca11e 100644 --- a/Gems/EMotionFX/Code/Tests/ActorFixture.cpp +++ b/Gems/EMotionFX/Code/Tests/ActorFixture.cpp @@ -28,7 +28,7 @@ namespace EMotionFX AZ::Data::AssetId actorAssetId("{5060227D-B6F4-422E-BF82-41AAC5F228A5}"); m_actorAsset = TestActorAssets::CreateActorAssetAndRegister(actorAssetId); - m_actorInstance = ActorInstance::Create(m_actorAsset->GetActor()); + m_actorInstance = ActorInstance::Create(GetActor()); } void ActorFixture::TearDown() @@ -76,7 +76,7 @@ namespace EMotionFX AZ::ObjectStream::FilterDescriptor loadFilter(nullptr, AZ::ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES); SimulatedObjectSetup* setup = AZ::Utils::LoadObjectFromBuffer(data.data(), data.size(), serializeContext, loadFilter); - setup->InitAfterLoad(m_actorAsset->GetActor()); + setup->InitAfterLoad(GetActor()); return setup; } @@ -87,7 +87,7 @@ namespace EMotionFX } - Actor* ActorFixture::GetActor() + Actor* ActorFixture::GetActor() const { return m_actorAsset->GetActor(); } diff --git a/Gems/EMotionFX/Code/Tests/ActorFixture.h b/Gems/EMotionFX/Code/Tests/ActorFixture.h index fad6a2c463..569d55cf47 100644 --- a/Gems/EMotionFX/Code/Tests/ActorFixture.h +++ b/Gems/EMotionFX/Code/Tests/ActorFixture.h @@ -30,7 +30,7 @@ namespace EMotionFX AZStd::vector GetTestJointNames() const; protected: - Actor* GetActor(); + Actor* GetActor() const; AZ::Data::Asset m_actorAsset; ActorInstance* m_actorInstance = nullptr; From 4b92aa34b7edde709ed7c5422043379eb6a42a43 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Thu, 7 Oct 2021 15:24:51 -0500 Subject: [PATCH 130/293] Updated with PR feedback. Created a common function to calculate the number of worker threads. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- .../AzCore/Jobs/JobManagerComponent.cpp | 7 +++--- .../AzCore/Task/TaskGraphSystemComponent.cpp | 11 +++----- .../AzCore/AzCore/Threading/ThreadUtils.cpp | 25 +++++++++++++++++++ .../AzCore/AzCore/Threading/ThreadUtils.h | 22 ++++++++++++++++ .../AzCore/AzCore/azcore_files.cmake | 2 ++ 5 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Threading/ThreadUtils.cpp create mode 100644 Code/Framework/AzCore/AzCore/Threading/ThreadUtils.h diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp index 59f9c5f6a2..6f5ccc93e4 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp @@ -20,6 +20,8 @@ #include +#include + AZ_CVAR(float, cl_jobThreadsConcurrencyRatio, 0.6f, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system multiplier on the number of hw threads the machine creates at initialization"); AZ_CVAR(uint32_t, cl_jobThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system number of hardware threads that are reserved for O3DE system threads"); AZ_CVAR(uint32_t, cl_jobThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system minimum number of worker threads to create after scaling the number of hw threads"); @@ -54,10 +56,7 @@ namespace AZ int numberOfWorkerThreads = m_numberOfWorkerThreads; if (numberOfWorkerThreads <= 0) // spawn default number of threads { - // calc number of job threads = cl_jobThreadsConcurrencyRatio * (number of hardware threads - cl_jobThreadsNumReserved), - // min = cl_jobThreadsMinNumber, - // max = number of hardware threads - cl_jobThreadsNumReserved - uint32_t scaledHardwareThreads = AZ::GetMax( cl_jobThreadsMinNumber, static_cast(AZStd::floor( 0.5f + AZ::GetClamp(cl_jobThreadsConcurrencyRatio, 0.0f, 1.0f) * static_cast(AZStd::thread::hardware_concurrency() - cl_jobThreadsNumReserved)))); + uint32_t scaledHardwareThreads = Threading::CalcNumWorkerThreads(cl_jobThreadsConcurrencyRatio, cl_jobThreadsMinNumber, cl_jobThreadsNumReserved); numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), scaledHardwareThreads); #if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS); diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp index 5ae0fb0394..56b56e96a1 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -12,11 +12,12 @@ #include #include #include +#include // Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system. AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)"); AZ_CVAR(float, cl_taskGraphThreadsConcurrencyRatio, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph calculate the number of worker threads to spawn by scaling the number of hw threads, value is clamped between 0.0f and 1.0f"); -AZ_CVAR(uint32_t, cl_taskGraphThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph number of hardware threads that are reserved for O3DE system threads"); +AZ_CVAR(uint32_t, cl_taskGraphThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph number of hardware threads that are reserved for O3DE system threads. Value is clamped between 0 and the number of logical cores in the system"); AZ_CVAR(uint32_t, cl_taskGraphThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph minimum number of worker threads to create after scaling the number of hw threads"); static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService"); @@ -29,13 +30,9 @@ namespace AZ if (Interface::Get() == nullptr) { - // calc number of worker threads = cl_taskGraphThreadsConcurrencyRatio * (number of hardware threads - cl_taskGraphThreadsNumReserved), - // min = cl_taskGraphThreadsMinNumber, - // max = number of hardware threads - cl_taskGraphThreadsNumReserved - uint32_t scaledHardwareThreads = AZ::GetMax( cl_taskGraphThreadsMinNumber, static_cast(AZStd::floor( 0.5f + AZ::GetClamp(cl_taskGraphThreadsConcurrencyRatio, 0.0f, 1.0f) * static_cast(AZStd::thread::hardware_concurrency() - cl_taskGraphThreadsNumReserved)))); - m_taskExecutor = aznew TaskExecutor(scaledHardwareThreads); + Interface::Register(this); // small window that another thread can try to use taskgraph between this line and the set instance. + m_taskExecutor = aznew TaskExecutor(Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved)); TaskExecutor::SetInstance(m_taskExecutor); - Interface::Register(this); } } diff --git a/Code/Framework/AzCore/AzCore/Threading/ThreadUtils.cpp b/Code/Framework/AzCore/AzCore/Threading/ThreadUtils.cpp new file mode 100644 index 0000000000..93eba9cc3f --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Threading/ThreadUtils.cpp @@ -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 + * + */ + +#include +#include +#include + +namespace AZ::Threading +{ + uint32_t CalcNumWorkerThreads(float workerThreadsRatio, uint32_t minNumWorkerThreads, uint32_t reservedNumThreads) + { + const uint32_t maxHardwareThreads = AZStd::thread::hardware_concurrency(); + const uint32_t numReservedThreads = AZ::GetMin(reservedNumThreads, maxHardwareThreads); // protect against num reserved being bigger than the number of hw threads + const uint32_t maxWorkerThreads = maxHardwareThreads - numReservedThreads; + const float requestedWorkerThreads = AZ::GetClamp(workerThreadsRatio, 0.0f, 1.0f) * static_cast(maxWorkerThreads); + const uint32_t requestedWorkerThreadsRounded = AZStd::lround(requestedWorkerThreads); + const uint32_t numWorkerThreads = AZ::GetMax(minNumWorkerThreads, requestedWorkerThreadsRounded); + return numWorkerThreads; + } +}; diff --git a/Code/Framework/AzCore/AzCore/Threading/ThreadUtils.h b/Code/Framework/AzCore/AzCore/Threading/ThreadUtils.h new file mode 100644 index 0000000000..505d900289 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Threading/ThreadUtils.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AZ::Threading +{ + //! Calculates the number of worker threads a system should use based on the number of hardware threads a device has. + //! result = max (minNumWorkerThreads, workerThreadsRatio * (num_hardware_threads - reservedNumThreads)) + //! @param workerThreadsRatio scale applied to the calculated maximum number of threads available after reserved threads have been accounted for. Clamped between 0 and 1. + //! @param minNumWorkerThreads minimum value that will be returned. Value is unclamped and can be more than num_hardware_threads. + //! @param reservedNumThreads number of hardware threads to reserve for O3DE system threads. Value clamped to num_hardware_threads. + //! @return number of worker threads for the calling system to allocate + uint32_t CalcNumWorkerThreads(float workerThreadsRatio, uint32_t minNumWorkerThreads, uint32_t reservedNumThreads); +}; diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 14579cbf33..010c748402 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -639,6 +639,8 @@ set(FILES Threading/ThreadSafeDeque.inl Threading/ThreadSafeObject.h Threading/ThreadSafeObject.inl + Threading/ThreadUtils.h + Threading/ThreadUtils.cpp Time/ITime.h Time/TimeSystemComponent.cpp Time/TimeSystemComponent.h From 38efd581738e7a8789734f6122cff1a3e2c93496 Mon Sep 17 00:00:00 2001 From: rhhong Date: Thu, 7 Oct 2021 14:54:30 -0700 Subject: [PATCH 131/293] Fix merging issue with camera input Signed-off-by: rhhong --- .../Code/Tools/EMStudio/AnimViewportWidget.cpp | 16 ++++++++-------- .../Code/Tools/EMStudio/AnimViewportWidget.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index d3fd719d38..6a6c9df901 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -38,17 +38,17 @@ namespace EMStudio void AnimViewportWidget::SetupCameras() { - m_pivotRotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::BuildRotateCameraInputId()); + m_rotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::BuildRotateCameraInputId()); const auto translateCameraInputChannelIds = EMStudio::ViewportUtil::BuildTranslateCameraInputChannelIds(); - m_pivotTranslateCamera = AZStd::make_shared( - translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot); - m_pivotTranslateCamera.get()->m_translateSpeedFn = [] + m_translateCamera = AZStd::make_shared( + translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook); + m_translateCamera.get()->m_translateSpeedFn = [] { return 3.0f; }; - m_pivotDollyScrollCamera = AZStd::make_shared(); + m_orbitDollyScrollCamera = AZStd::make_shared(); } void AnimViewportWidget::SetupCameraController() @@ -94,9 +94,9 @@ namespace EMStudio controller->SetCameraListBuilderCallback( [this](AzFramework::Cameras& cameras) { - cameras.AddCamera(m_pivotRotateCamera); - cameras.AddCamera(m_pivotTranslateCamera); - cameras.AddCamera(m_pivotDollyScrollCamera); + cameras.AddCamera(m_rotateCamera); + cameras.AddCamera(m_translateCamera); + cameras.AddCamera(m_orbitDollyScrollCamera); }); GetControllerList()->Add(controller); } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 70b4e1e667..7c2e085f84 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -26,8 +26,8 @@ namespace EMStudio void SetupCameraController(); AZStd::unique_ptr m_renderer; - AZStd::shared_ptr m_pivotRotateCamera; - AZStd::shared_ptr m_pivotTranslateCamera; - AZStd::shared_ptr m_pivotDollyScrollCamera; + AZStd::shared_ptr m_rotateCamera; + AZStd::shared_ptr m_translateCamera; + AZStd::shared_ptr m_orbitDollyScrollCamera; }; } From 437a4d2d63c2af67ba9148b09341e9a0c950bec0 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 7 Oct 2021 17:38:54 -0500 Subject: [PATCH 132/293] Updated engine template unit tests. Signed-off-by: Chris Galvan --- .../o3de/tests/unit_test_engine_template.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/o3de/tests/unit_test_engine_template.py b/scripts/o3de/tests/unit_test_engine_template.py index 16ac24d74c..ed1c8258d3 100755 --- a/scripts/o3de/tests/unit_test_engine_template.py +++ b/scripts/o3de/tests/unit_test_engine_template.py @@ -31,17 +31,17 @@ TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE = """ #include #include -namespace ${Name} +namespace ${SanitizedCppName} { - class ${Name}Requests + class ${SanitizedCppName}Requests { public: - AZ_RTTI(${Name}Requests, "{${Random_Uuid}}"); - virtual ~${Name}Requests() = default; + AZ_RTTI(${SanitizedCppName}Requests, "{${Random_Uuid}}"); + virtual ~${SanitizedCppName}Requests() = default; // Put your public methods here }; - class ${Name}BusTraits + class ${SanitizedCppName}BusTraits : public AZ::EBusTraits { public: @@ -52,31 +52,31 @@ namespace ${Name} ////////////////////////////////////////////////////////////////////////// }; - using ${Name}RequestBus = AZ::EBus<${Name}Requests, ${Name}BusTraits>; - using ${Name}Interface = AZ::Interface<${Name}Requests>; + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests, ${SanitizedCppName}BusTraits>; + using ${SanitizedCppName}Interface = AZ::Interface<${SanitizedCppName}Requests>; -} // namespace ${Name} +} // namespace ${SanitizedCppName} """ TEST_TEMPLATED_CONTENT_WITH_LICENSE = CPP_LICENSE_TEXT + TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITHOUT_LICENSE = string.Template( - TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'Name': "TestTemplate"}) + TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'SanitizedCppName': "TestTemplate"}) TEST_CONCRETE_TESTTEMPLATE_CONTENT_WITH_LICENSE = string.Template( - TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'Name': "TestTemplate"}) + TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'SanitizedCppName': "TestTemplate"}) TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITHOUT_LICENSE = string.Template( - TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'Name': "TestProject"}) + TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'SanitizedCppName': "TestProject"}) TEST_CONCRETE_TESTPROJECT_TEMPLATE_CONTENT_WITH_LICENSE = string.Template( - TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'Name': "TestProject"}) + TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'SanitizedCppName': "TestProject"}) TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITHOUT_LICENSE = string.Template( - TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'Name': "TestGem"}) + TEST_TEMPLATED_CONTENT_WITHOUT_LICENSE).safe_substitute({'SanitizedCppName': "TestGem"}) TEST_CONCRETE_TESTGEM_TEMPLATE_CONTENT_WITH_LICENSE = string.Template( - TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'Name': "TestGem"}) + TEST_TEMPLATED_CONTENT_WITH_LICENSE).safe_substitute({'SanitizedCppName': "TestGem"}) TEST_TEMPLATE_JSON_CONTENTS = """\ { From e64b9d3536ccdbb9bcbbda8228522c940c91784b Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:23:13 -0700 Subject: [PATCH 133/293] ATOM-16320 Remove PVRTC and ETC compressor (#4557) Signed-off-by: Qing Tao --- .../AzToolsFramework/Tests/LogLines.cpp | 2 +- .../ImageProcessingAtom/Code/CMakeLists.txt | 3 - .../Atom/ImageProcessing/PixelFormats.h | 12 +- .../Source/BuilderSettings/PresetSettings.cpp | 7 - .../Code/Source/Compressors/Compressor.cpp | 22 - .../Code/Source/Compressors/ETC2.cpp | 233 --------- .../Code/Source/Compressors/ETC2.h | 31 -- .../Code/Source/Compressors/PVRTC.cpp | 338 ------------- .../Code/Source/Compressors/PVRTC.h | 30 -- .../Code/Source/Editor/PresetInfoPopup.cpp | 1 - .../Code/Source/ImageLoader/DdsLoader.cpp | 443 +----------------- .../Code/Source/ImageLoader/ImageLoaders.h | 5 - .../Source/Platform/Mac/platform_mac.cmake | 5 - .../Code/Source/Processing/DDSHeader.h | 14 +- .../Source/Processing/PixelFormatInfo.cpp | 58 --- .../Code/Source/Processing/PixelFormatInfo.h | 8 - .../Code/Source/Processing/Utils.cpp | 42 -- .../Code/Tests/ImageProcessing_Test.cpp | 142 +----- .../Code/imageprocessing_files.cmake | 4 - .../Code/Source/Editor/AtlasBuilderWorker.cpp | 4 +- .../Linux/BuiltInPackages_linux.cmake | 2 - .../Platform/Mac/BuiltInPackages_mac.cmake | 2 - .../Windows/BuiltInPackages_windows.cmake | 2 - 23 files changed, 12 insertions(+), 1398 deletions(-) delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.cpp delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.h delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.cpp delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.h diff --git a/Code/Framework/AzToolsFramework/Tests/LogLines.cpp b/Code/Framework/AzToolsFramework/Tests/LogLines.cpp index 5af6513720..1c69e855ee 100644 --- a/Code/Framework/AzToolsFramework/Tests/LogLines.cpp +++ b/Code/Framework/AzToolsFramework/Tests/LogLines.cpp @@ -25,7 +25,7 @@ namespace UnitTest R"X(Executing RC.EXE: '"E:\lyengine\dev\windows\bin\profile\rc.exe" "E:/Directory/File.tga")X", R"X(Executing RC.EXE with working directory : '')X", R"X(ResourceCompiler 64 - bit DEBUG)X", - R"X(Platform support : PC, PowerVR, etc2Comp)X", + R"X(Platform support : PC, PowerVR)X", R"X(Version 1.1.8.6 Nov 5 2018 13 : 28 : 28)X" }; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt index 1463124e27..836f173632 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt @@ -63,13 +63,10 @@ ly_add_target( 3rdParty::Qt::Widgets 3rdParty::Qt::Gui 3rdParty::astc-encoder - 3rdParty::etc2comp - 3rdParty::PVRTexTool 3rdParty::squish-ccr 3rdParty::tiff 3rdParty::ISPCTexComp 3rdParty::ilmbase - Legacy::CryCommon AZ::AzFramework AZ::AzToolsFramework AZ::AzQtComponents diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/PixelFormats.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/PixelFormats.h index fbde69abb2..4da996dbde 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/PixelFormats.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Include/Atom/ImageProcessing/PixelFormats.h @@ -39,16 +39,7 @@ namespace ImageProcessingAtom ePixelFormat_ASTC_10x8, ePixelFormat_ASTC_10x10, ePixelFormat_ASTC_12x10, - ePixelFormat_ASTC_12x12, - //Formats supported by PowerVR GPU. Mainly for ios devices. - ePixelFormat_PVRTC2, //2bpp - ePixelFormat_PVRTC4, //4bpp - //formats for opengl and opengles 3.0 (android devices) - ePixelFormat_EAC_R11, //one channel unsigned data - ePixelFormat_EAC_RG11, //two channel unsigned data - ePixelFormat_ETC2, //Compresses RGB888 data, it taks 4x4 groups of pixel data and compresses each into a 64-bit - ePixelFormat_ETC2a1, //Compresses RGB888A1 data, it taks 4x4 groups of pixel data and compresses each into a 64-bit - ePixelFormat_ETC2a, //Compresses RGBA8888 data with full alpha support + ePixelFormat_ASTC_12x12, // Standardized Compressed DXGI Formats (DX10+) // Data in these compressed formats is hardware decodable on all DX10 chips, and manageable with the DX10-API. @@ -88,7 +79,6 @@ namespace ImageProcessingAtom }; bool IsASTCFormat(EPixelFormat fmt); - bool IsETCFormat(EPixelFormat fmt); } // namespace ImageProcessingAtom namespace AZ diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp index 7ffabc45a9..3812b86026 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.cpp @@ -109,13 +109,6 @@ namespace ImageProcessingAtom ->Value("ASTC_10x10", EPixelFormat::ePixelFormat_ASTC_10x10) ->Value("ASTC_12x10", EPixelFormat::ePixelFormat_ASTC_12x10) ->Value("ASTC_12x12", EPixelFormat::ePixelFormat_ASTC_12x12) - ->Value("PVRTC2", EPixelFormat::ePixelFormat_PVRTC2) - ->Value("PVRTC4", EPixelFormat::ePixelFormat_PVRTC4) - ->Value("EAC_R11", EPixelFormat::ePixelFormat_EAC_R11) - ->Value("EAC_RG11", EPixelFormat::ePixelFormat_EAC_RG11) - ->Value("ETC2", EPixelFormat::ePixelFormat_ETC2) - ->Value("ETC2a1", EPixelFormat::ePixelFormat_ETC2a1) - ->Value("ETC2a", EPixelFormat::ePixelFormat_ETC2a) ->Value("BC1", EPixelFormat::ePixelFormat_BC1) ->Value("BC1a", EPixelFormat::ePixelFormat_BC1a) ->Value("BC3", EPixelFormat::ePixelFormat_BC3) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/Compressor.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/Compressor.cpp index 1dd18faaf3..ac5340eaab 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/Compressor.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/Compressor.cpp @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include namespace ImageProcessingAtom @@ -42,26 +40,6 @@ namespace ImageProcessingAtom } } - // Both ETC2Compressor and PVRTCCompressor can process ETC formats - // According to Mobile team, Etc2Com is faster than PVRTexLib, so we check with ETC2Compressor before PVRTCCompressor - // Note: with the test I have done, I found out it cost similar time for both Etc2Com and PVRTexLib to compress - // a 2048x2048 test texture to EAC_R11 and EAC_RG11. It was around 7 minutes for EAC_R11 and 14 minutes for EAC_RG11 - if (ETC2Compressor::IsCompressedPixelFormatSupported(fmt)) - { - if (isCompressing || (!isCompressing && ETC2Compressor::DoesSupportDecompress(fmt))) - { - return ICompressorPtr(new ETC2Compressor()); - } - } - - if (PVRTCCompressor::IsCompressedPixelFormatSupported(fmt)) - { - if (isCompressing || (!isCompressing && PVRTCCompressor::DoesSupportDecompress(fmt))) - { - return ICompressorPtr(new PVRTCCompressor()); - } - } - return nullptr; } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.cpp deleted file mode 100644 index 73108d5502..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace ImageProcessingAtom -{ - //limited to 1 thread because AP requires so. We may change to n when AP allocate n thread to a job in the furture - static const int MAX_COMP_JOBS = 1; - static const int MIN_COMP_JOBS = 1; - static const float ETC_LOW_EFFORT_LEVEL = 25.0f; - static const float ETC_MED_EFFORT_LEVEL = 40.0f; - static const float ETC_HIGH_EFFORT_LEVEL = 80.0f; - - //Grab the Etc2Comp specific pixel format enum - static Etc::Image::Format FindEtc2PixelFormat(EPixelFormat fmt) - { - switch (fmt) - { - case ePixelFormat_EAC_RG11: - return Etc::Image::Format::RG11; - case ePixelFormat_EAC_R11: - return Etc::Image::Format::R11; - case ePixelFormat_ETC2: - return Etc::Image::Format::RGB8; - case ePixelFormat_ETC2a1: - return Etc::Image::Format::RGB8A1; - case ePixelFormat_ETC2a: - return Etc::Image::Format::RGBA8; - default: - return Etc::Image::Format::FORMATS; - } - } - - //Get the errmetric required for the compression - static Etc::ErrorMetric FindErrMetric(Etc::Image::Format fmt) - { - switch (fmt) - { - case Etc::Image::Format::RG11: - return Etc::ErrorMetric::NORMALXYZ; - case Etc::Image::Format::R11: - return Etc::ErrorMetric::NUMERIC; - case Etc::Image::Format::RGB8: - return Etc::ErrorMetric::RGBX; - case Etc::Image::Format::RGBA8: - case Etc::Image::Format::RGB8A1: - return Etc::ErrorMetric::RGBA; - default: - return Etc::ErrorMetric::ERROR_METRICS; - } - } - - //Convert to sRGB format - static Etc::Image::Format FindGammaEtc2PixelFormat(Etc::Image::Format fmt) - { - switch (fmt) - { - case Etc::Image::Format::RGB8: - return Etc::Image::Format::SRGB8; - case Etc::Image::Format::RGBA8: - return Etc::Image::Format::SRGBA8; - case Etc::Image::Format::RGB8A1: - return Etc::Image::Format::SRGB8A1; - default: - return Etc::Image::Format::FORMATS; - } - } - - bool ETC2Compressor::IsCompressedPixelFormatSupported(EPixelFormat fmt) - { - return (FindEtc2PixelFormat(fmt) != Etc::Image::Format::FORMATS); - } - - bool ETC2Compressor::IsUncompressedPixelFormatSupported(EPixelFormat fmt) - { - //for uncompress format - if (fmt == ePixelFormat_R8G8B8A8) - { - return true; - } - return false; - } - - EPixelFormat ETC2Compressor::GetSuggestedUncompressedFormat([[maybe_unused]] EPixelFormat compressedfmt, [[maybe_unused]] EPixelFormat uncompressedfmt) const - { - return ePixelFormat_R8G8B8A8; - } - - bool ETC2Compressor::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst) - { - return false; - } - - ColorSpace ETC2Compressor::GetSupportedColorSpace([[maybe_unused]] EPixelFormat compressFormat) const - { - return ColorSpace::autoSelect; - } - - const char* ETC2Compressor::GetName() const - { - return "ETC2Compressor"; - } - - IImageObjectPtr ETC2Compressor::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, - const CompressOption* compressOption) const - { - //validate input - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); - - //src format need to be uncompressed and dst format need to compressed. - if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - //determinate compression quality - ICompressor::EQuality quality = ICompressor::eQuality_Normal; - //get setting from compression option - if (compressOption) - { - quality = compressOption->compressQuality; - } - - float qualityEffort = 0.0f; - switch (quality) - { - case eQuality_Preview: - case eQuality_Fast: - { - qualityEffort = ETC_LOW_EFFORT_LEVEL; - break; - } - case eQuality_Normal: - { - qualityEffort = ETC_MED_EFFORT_LEVEL; - break; - } - default: - { - qualityEffort = ETC_HIGH_EFFORT_LEVEL; - } - } - - Etc::Image::Format dstEtc2Format = FindEtc2PixelFormat(fmtDst); - if (srcImage->GetImageFlags() & EIF_SRGBRead) - { - dstEtc2Format = FindGammaEtc2PixelFormat(dstEtc2Format); - } - - //use to read pixel data from src image - IPixelOperationPtr pixelOp = CreatePixelOperation(fmtSrc); - //get count of bytes per pixel for images - AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(fmtSrc)->bitsPerBlock / 8; - - const AZ::u32 mipCount = dstImage->GetMipCount(); - for (AZ::u32 mip = 0; mip < mipCount; ++mip) - { - const AZ::u32 width = srcImage->GetWidth(mip); - const AZ::u32 height = srcImage->GetHeight(mip); - - // Prepare source data - AZ::u8* srcMem; - AZ::u32 srcPitch; - srcImage->GetImagePointer(mip, srcMem, srcPitch); - const AZ::u32 pixelCount = srcImage->GetPixelCount(mip); - - Etc::ColorFloatRGBA* rgbaPixels = new Etc::ColorFloatRGBA[pixelCount]; - Etc::ColorFloatRGBA* rgbaPixelPtr = rgbaPixels; - float r, g, b, a; - for (AZ::u32 pixelIdx = 0; pixelIdx < pixelCount; pixelIdx++, srcMem += pixelBytes, rgbaPixelPtr++) - { - pixelOp->GetRGBA(srcMem, r, g, b, a); - rgbaPixelPtr->fA = a; - rgbaPixelPtr->fR = r; - rgbaPixelPtr->fG = g; - rgbaPixelPtr->fB = b; - } - - //Call into etc2Comp lib to compress. https://medium.com/@duhroach/building-a-blazing-fast-etc2-compressor-307f3e9aad99 - Etc::ErrorMetric errMetric = FindErrMetric(dstEtc2Format); - unsigned char* paucEncodingBits; - unsigned int uiEncodingBitsBytes; - unsigned int uiExtendedWidth; - unsigned int uiExtendedHeight; - int iEncodingTime_ms; - - Etc::Encode(reinterpret_cast(rgbaPixels), - width, height, - dstEtc2Format, - errMetric, - qualityEffort, - MIN_COMP_JOBS, - MAX_COMP_JOBS, - &paucEncodingBits, &uiEncodingBitsBytes, - &uiExtendedWidth, &uiExtendedHeight, - &iEncodingTime_ms); - - AZ::u8* dstMem; - AZ::u32 dstPitch; - dstImage->GetImagePointer(mip, dstMem, dstPitch); - - memcpy(dstMem, paucEncodingBits, uiEncodingBitsBytes); - delete[] rgbaPixels; - } - - return dstImage; - } - - IImageObjectPtr ETC2Compressor::DecompressImage(IImageObjectPtr srcImage, [[maybe_unused]] EPixelFormat fmtDst) const - { - //etc2Comp doesn't support decompression - //Since PVRTexLib support ETC formats too. It may take over the decompression. - return nullptr; - } -} // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.h deleted file mode 100644 index 9ab5a164a5..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/ETC2.h +++ /dev/null @@ -1,31 +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 - * - */ - -#pragma once - -#include - -namespace ImageProcessingAtom -{ - class ETC2Compressor - : public ICompressor - { - public: - static bool IsCompressedPixelFormatSupported(EPixelFormat fmt); - static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt); - static bool DoesSupportDecompress(EPixelFormat fmtDst); - - IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption* compressOption) const override; - IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) const override; - - EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) const override; - ColorSpace GetSupportedColorSpace(EPixelFormat compressFormat) const final; - const char* GetName() const final; - - }; -} // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.cpp deleted file mode 100644 index f3a630e8c1..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - - -namespace ImageProcessingAtom -{ - // Note: PVRTexLib supports ETC formats, PVRTC formats and BC formats - // We haven't tested the performace to compress BC formats compare to CTSquisher - // For PVRTC formats, we only added PVRTC 1 support for now - // The compression for ePVRTPF_EAC_R11 and ePVRTPF_EAC_RG11 are very slow. It takes 7 and 14 minutes for a 2048x2048 texture. - EPVRTPixelFormat FindPvrPixelFormat(EPixelFormat fmt) - { - switch (fmt) - { - case ePixelFormat_PVRTC2: - return ePVRTPF_PVRTCI_2bpp_RGBA; - case ePixelFormat_PVRTC4: - return ePVRTPF_PVRTCI_4bpp_RGBA; - case ePixelFormat_EAC_R11: - return ePVRTPF_EAC_R11; - case ePixelFormat_EAC_RG11: - return ePVRTPF_EAC_RG11; - case ePixelFormat_ETC2: - return ePVRTPF_ETC2_RGB; - case ePixelFormat_ETC2a1: - return ePVRTPF_ETC2_RGB_A1; - case ePixelFormat_ETC2a: - return ePVRTPF_ETC2_RGBA; - default: - return ePVRTPF_NumCompressedPFs; - } - } - - bool PVRTCCompressor::IsCompressedPixelFormatSupported(EPixelFormat fmt) - { - return (FindPvrPixelFormat(fmt) != ePVRTPF_NumCompressedPFs); - } - - bool PVRTCCompressor::IsUncompressedPixelFormatSupported(EPixelFormat fmt) - { - //for uncompress format - if (fmt == ePixelFormat_R8G8B8A8) - { - return true; - } - return false; - } - - EPixelFormat PVRTCCompressor::GetSuggestedUncompressedFormat([[maybe_unused]] EPixelFormat compressedfmt, [[maybe_unused]] EPixelFormat uncompressedfmt) const - { - return ePixelFormat_R8G8B8A8; - } - - ColorSpace PVRTCCompressor::GetSupportedColorSpace([[maybe_unused]] EPixelFormat compressFormat) const - { - return ColorSpace::autoSelect; - } - - const char* PVRTCCompressor::GetName() const - { - return "PVRTCCompressor"; - } - - bool PVRTCCompressor::DoesSupportDecompress([[maybe_unused]] EPixelFormat fmtDst) - { - return true; - } - - IImageObjectPtr PVRTCCompressor::CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, - const CompressOption* compressOption) const - { - //validate input - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); - - //src format need to be uncompressed and dst format need to compressed. - if (!IsUncompressedPixelFormatSupported(fmtSrc) || !IsCompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - //determinate compression quality - pvrtexture::ECompressorQuality internalQuality = pvrtexture::eETCFast; - ICompressor::EQuality quality = ICompressor::eQuality_Normal; - AZ::Vector3 uniformWeights = AZ::Vector3(0.3333f, 0.3334f, 0.3333f); - AZ::Vector3 weights = uniformWeights; - bool isUniform = true; - //get setting from compression option - if (compressOption) - { - quality = compressOption->compressQuality; - weights = compressOption->rgbWeight; - isUniform = (weights == uniformWeights); - } - - if (IsETCFormat(fmtDst)) - { - if ((quality <= eQuality_Normal) && isUniform) - { - internalQuality = pvrtexture::eETCFast; - } - else if (quality <= eQuality_Normal) - { - internalQuality = pvrtexture::eETCNormal; - } - else if (isUniform) - { - internalQuality = pvrtexture::eETCSlow; - } - else - { - internalQuality = pvrtexture::eETCSlow; - } - } - else - { - if (quality == eQuality_Preview) - { - internalQuality = pvrtexture::ePVRTCFastest; - } - else if (quality == eQuality_Fast) - { - internalQuality = pvrtexture::ePVRTCFast; - } - else if (quality == eQuality_Normal) - { - internalQuality = pvrtexture::ePVRTCNormal; - } - else - { - internalQuality = pvrtexture::ePVRTCHigh; - } - } - - // setup color space - EPVRTColourSpace cspace = ePVRTCSpacelRGB; - if (srcImage->GetImageFlags() & EIF_SRGBRead) - { - cspace = ePVRTCSpacesRGB; - } - - //setup src texture for compression - const pvrtexture::PixelType srcPixelType('r', 'g', 'b', 'a', 8, 8, 8, 8); - const AZ::u32 dstMips = dstImage->GetMipCount(); - for (AZ::u32 mip = 0; mip < dstMips; ++mip) - { - const AZ::u32 width = srcImage->GetWidth(mip); - const AZ::u32 height = srcImage->GetHeight(mip); - - // Prepare source data - AZ::u8* srcMem; - uint32 srcPitch; - srcImage->GetImagePointer(mip, srcMem, srcPitch); - - const pvrtexture::CPVRTextureHeader srcHeader( - srcPixelType.PixelTypeID, // AZ::u64 u64PixelFormat, - width, // uint32 u32Height=1, - height, // uint32 u32Width=1, - 1, // uint32 u32Depth=1, - 1, // uint32 u32NumMipMaps=1, - 1, // uint32 u32NumArrayMembers=1, - 1, // uint32 u32NumFaces=1, - cspace, // EPVRTColourSpace eColourSpace=ePVRTCSpacelRGB, - ePVRTVarTypeUnsignedByteNorm, // EPVRTVariableType eChannelType=ePVRTVarTypeUnsignedByteNorm, - false); // bool bPreMultiplied=false); - - pvrtexture::CPVRTexture compressTexture(srcHeader, srcMem); - - //compressing - bool isSuccess = false; -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - try -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - { - isSuccess = pvrtexture::Transcode( - compressTexture, - pvrtexture::PixelType(FindPvrPixelFormat(fmtDst)), - ePVRTVarTypeUnsignedByteNorm, - cspace, - internalQuality); - } -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - catch (...) - { - AZ_Error("Image Processing", false, "Unknown exception in PVRTexLib"); - return nullptr; - } -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - - if (!isSuccess) - { - AZ_Error("Image Processing", false, "Failed to compress image with PVRTexLib."); - return nullptr; - } - - // Getting compressed data - const void* const compressedData = compressTexture.getDataPtr(); - if (!compressedData) - { - AZ_Error("Image Processing", false, "Failed to obtain compressed image data by using PVRTexLib"); - return nullptr; - } - - const AZ::u32 compressedDataSize = compressTexture.getDataSize(); - if (dstImage->GetMipBufSize(mip) != compressedDataSize) - { - AZ_Error("Image Processing", false, "Compressed image data size mismatch while using PVRTexLib"); - return nullptr; - } - - //save compressed data to dst image - AZ::u8* dstMem; - AZ::u32 dstPitch; - dstImage->GetImagePointer(mip, dstMem, dstPitch); - memcpy(dstMem, compressedData, compressedDataSize); - } - - return dstImage; - } - - IImageObjectPtr PVRTCCompressor::DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) const - { - //validate input - EPixelFormat fmtSrc = srcImage->GetPixelFormat(); //compressed - - if (!IsCompressedPixelFormatSupported(fmtSrc) || !IsUncompressedPixelFormatSupported(fmtDst)) - { - return nullptr; - } - - EPVRTColourSpace colorSpace = ePVRTCSpacelRGB; - if (srcImage->GetImageFlags() & EIF_SRGBRead) - { - colorSpace = ePVRTCSpacesRGB; - } - - IImageObjectPtr dstImage(srcImage->AllocateImage(fmtDst)); - - const AZ::u32 mipCount = dstImage->GetMipCount(); - for (AZ::u32 mip = 0; mip < mipCount; ++mip) - { - const AZ::u32 width = srcImage->GetWidth(mip); - const AZ::u32 height = srcImage->GetHeight(mip); - - // Preparing source compressed data - const pvrtexture::CPVRTextureHeader compressedHeader( - FindPvrPixelFormat(fmtSrc), // AZ::u64 u64PixelFormat, - width, // uint32 u32Height=1, - height, // uint32 u32Width=1, - 1, // uint32 u32Depth=1, - 1, // uint32 u32NumMipMaps=1, - 1, // uint32 u32NumArrayMembers=1, - 1, // uint32 u32NumFaces=1, - colorSpace, // EPVRTColourSpace eColourSpace=ePVRTCSpacelRGB, - ePVRTVarTypeUnsignedByteNorm, // EPVRTVariableType eChannelType=ePVRTVarTypeUnsignedByteNorm, - false); // bool bPreMultiplied=false); - - const AZ::u32 compressedDataSize = compressedHeader.getDataSize(); - if (srcImage->GetMipBufSize(mip) != compressedDataSize) - { - AZ_Error("Image Processing", false, "Decompressed image data size mismatch while using PVRTexLib"); - return nullptr; - } - - AZ::u8* srcMem; - AZ::u32 srcPitch; - srcImage->GetImagePointer(mip, srcMem, srcPitch); - pvrtexture::CPVRTexture cTexture(compressedHeader, srcMem); - - // Decompress - bool bOk = false; -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - try - { -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - bOk = pvrtexture::Transcode( - cTexture, - pvrtexture::PVRStandard8PixelType, - ePVRTVarTypeUnsignedByteNorm, - colorSpace, - pvrtexture::ePVRTCHigh); - -#if AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - } - catch (...) - { - AZ_Error("Image Processing", false, "Unknown exception in PVRTexLib when decompressing"); - return nullptr; - } -#endif // AZ_TRAIT_IMAGEPROCESSING_SUPPORT_TRY_CATCH - - if (!bOk) - { - AZ_Error("Image Processing", false, "Failed to decompress an image by using PVRTexLib"); - return nullptr; - } - - // Getting decompressed data - const void* const pDecompressedData = cTexture.getDataPtr(); - if (!pDecompressedData) - { - AZ_Error("Image Processing", false, "Failed to obtain decompressed image data by using PVRTexLib"); - return nullptr; - } - - const AZ::u32 decompressedDataSize = cTexture.getDataSize(); - if (dstImage->GetMipBufSize(mip) != decompressedDataSize) - { - AZ_Error("Image Processing", false, "Decompressed image data size mismatch while using PVRTexLib"); - return nullptr; - } - - //save decompressed image to dst image - AZ::u8* dstMem; - AZ::u32 dstPitch; - dstImage->GetImagePointer(mip, dstMem, dstPitch); - memcpy(dstMem, pDecompressedData, decompressedDataSize); - } - - return dstImage; - } -} //namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.h deleted file mode 100644 index cedd6d6643..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Compressors/PVRTC.h +++ /dev/null @@ -1,30 +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 - * - */ - -#pragma once - -#include - -namespace ImageProcessingAtom -{ - class PVRTCCompressor - : public ICompressor - { - public: - static bool IsCompressedPixelFormatSupported(EPixelFormat fmt); - static bool IsUncompressedPixelFormatSupported(EPixelFormat fmt); - static bool DoesSupportDecompress(EPixelFormat fmtDst); - - IImageObjectPtr CompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst, const CompressOption* compressOption) const override; - IImageObjectPtr DecompressImage(IImageObjectPtr srcImage, EPixelFormat fmtDst) const override; - - EPixelFormat GetSuggestedUncompressedFormat(EPixelFormat compressedfmt, EPixelFormat uncompressedfmt) const override; - ColorSpace GetSupportedColorSpace(EPixelFormat compressFormat) const final; - const char* GetName() const final; - }; -} // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp index daaac5176b..2d5c89e8f5 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp @@ -82,7 +82,6 @@ namespace ImageProcessingAtomEditor presetInfoText += "\n"; presetInfoText += QString("Suppress Engine Reduce: %1\n").arg(presetSettings->m_suppressEngineReduce ? "True" : "False"); presetInfoText += QString("Discard Alpha: %1\n").arg(presetSettings->m_discardAlpha ? "True" : "False"); - presetInfoText += QString("Is Power Of 2: %1\n").arg(presetSettings->m_isPowerOf2 ? "True" : "False"); presetInfoText += QString("Is Color Chart: %1\n").arg(presetSettings->m_isColorChart ? "True" : "False"); presetInfoText += QString("High Pass Mip: %1\n").arg(presetSettings->m_highPassMip); presetInfoText += QString("Gloss From Normal: %1\n").arg(presetSettings->m_glossFromNormals); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/DdsLoader.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/DdsLoader.cpp index 20367227bd..d7f36398e3 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/DdsLoader.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/DdsLoader.cpp @@ -24,201 +24,6 @@ namespace ImageProcessingAtom { namespace DdsLoader { - IImageObject* CreateImageFromHeaderLegacy(DDS_HEADER_LEGACY& header, DDS_HEADER_DXT10& exthead) - { - EPixelFormat eFormat = ePixelFormat_Unknown; - AZ::u32 dwWidth, dwMips, dwHeight; - AZ::u32 imageFlags = header.dwReserved1; - AZ::Color colMinARGB, colMaxARGB; - - dwWidth = header.dwWidth; - dwHeight = header.dwHeight; - dwMips = 1; - if (header.dwHeaderFlags & DDS_HEADER_FLAGS_MIPMAP) - { - dwMips = header.dwMipMapCount; - } - if ((header.dwSurfaceFlags & DDS_SURFACE_FLAGS_CUBEMAP) && (header.dwCubemapFlags & DDS_CUBEMAP_ALLFACES)) - { - AZ_Assert(header.dwReserved1 & EIF_Cubemap, "Image flag should have cubemap flag"); - dwHeight *= 6; - } - - colMinARGB = AZ::Color(header.cMinColor[0], header.cMinColor[1], header.cMinColor[2], header.cMinColor[3]); - colMaxARGB = AZ::Color(header.cMaxColor[0], header.cMaxColor[1], header.cMaxColor[2], header.cMaxColor[3]); - - //get pixel format - { - // DX10 formats - if (header.ddspf.dwFourCC == FOURCC_DX10) - { - AZ::u32 dxgiFormat = exthead.dxgiFormat; - - //remove the SRGB from dxgi format and add sRGB to image flag - if (dxgiFormat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC1_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC1_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC2_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC2_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC3_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC3_UNORM; - } - else if (dxgiFormat == DXGI_FORMAT_BC7_UNORM_SRGB) - { - dxgiFormat = DXGI_FORMAT_BC7_UNORM; - } - - //add rgb flag if the dxgiformat was changed (which means it was sRGB format) above - if (dxgiFormat != exthead.dxgiFormat) - { - AZ_Assert(imageFlags & EIF_SRGBRead, "Image flags should have SRGBRead flag"); - imageFlags |= EIF_SRGBRead; - } - - //check all the pixel formats and find matching one - if (dxgiFormat != DXGI_FORMAT_UNKNOWN) - { - int i = 0; - for (; i < ePixelFormat_Count; i++) - { - const PixelFormatInfo* info = CPixelFormats::GetInstance().GetPixelFormatInfo((EPixelFormat)i); - if (static_cast(info->d3d10Format) == dxgiFormat) - { - eFormat = (EPixelFormat)i; - break; - } - } - if (i == ePixelFormat_Count) - { - AZ_Error("Image Processing", false, "Unhandled d3d10 format: %d", dxgiFormat); - return nullptr; - } - } - } - else - { - //for non-dx10 formats, use fourCC to find out its pixel formats - //go through all pixel formats and find a match with the fourcc - for (AZ::u32 formatIdx = 0; formatIdx < ePixelFormat_Count; formatIdx++) - { - const PixelFormatInfo* info = CPixelFormats::GetInstance().GetPixelFormatInfo((EPixelFormat)formatIdx); - if (header.ddspf.dwFourCC == info->fourCC) - { - eFormat = (EPixelFormat)formatIdx; - break; - } - } - - //legacy formats. This section is only used for load dds files converted by RC.exe - //our save to dds file function won't use any of these fourcc - if (eFormat == ePixelFormat_Unknown) - { - if (header.ddspf.dwFourCC == FOURCC_DXT1) - { - eFormat = ePixelFormat_BC1; - } - else if (header.ddspf.dwFourCC == FOURCC_DXT5) - { - eFormat = ePixelFormat_BC3; - } - else if (header.ddspf.dwFourCC == FOURCC_3DCP) - { - eFormat = ePixelFormat_BC4; - } - else if (header.ddspf.dwFourCC == FOURCC_3DC) - { - eFormat = ePixelFormat_BC5; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_R32F) - { - eFormat = ePixelFormat_R32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_G32R32F) - { - eFormat = ePixelFormat_R32G32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A32B32G32R32F) - { - eFormat = ePixelFormat_R32G32B32A32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_R16F) - { - eFormat = ePixelFormat_R16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_G16R16F) - { - eFormat = ePixelFormat_R16G16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A16B16G16R16F) - { - eFormat = ePixelFormat_R16G16B16A16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A16B16G16R16) - { - eFormat = ePixelFormat_R16G16B16A16; - } - else if ((header.ddspf.dwFlags == DDS_RGBA || header.ddspf.dwFlags == DDS_RGB) - && header.ddspf.dwRGBBitCount == 32) - { - if (header.ddspf.dwRBitMask == 0x00ff0000) - { - eFormat = ePixelFormat_B8G8R8A8; - } - else - { - eFormat = ePixelFormat_R8G8B8A8; - } - } - else if (header.ddspf.dwFlags == DDS_LUMINANCEA && header.ddspf.dwRGBBitCount == 8) - { - eFormat = ePixelFormat_R8G8; - } - else if (header.ddspf.dwFlags == DDS_LUMINANCE && header.ddspf.dwRGBBitCount == 8) - { - eFormat = ePixelFormat_A8; - } - else if ((header.ddspf.dwFlags == DDS_A || header.ddspf.dwFlags == DDS_A_ONLY || header.ddspf.dwFlags == (DDS_A | DDS_A_ONLY)) && header.ddspf.dwRGBBitCount == 8) - { - eFormat = ePixelFormat_A8; - } - } - } - } - - if (eFormat == ePixelFormat_Unknown) - { - AZ_Error("Image Processing", false, "Unhandled dds pixel format fourCC: %d, flags: %d", - header.ddspf.dwFourCC, header.ddspf.dwFlags); - return nullptr; - } - - IImageObject* newImage = IImageObject::CreateImage(dwWidth, dwHeight, dwMips, eFormat); - - if (dwMips != newImage->GetMipCount()) - { - AZ_Error("Image Processing", false, "Mipcount from image data doesn't match image size and pixelformat"); - delete newImage; - return nullptr; - } - - //set properties - newImage->SetImageFlags(imageFlags); - newImage->SetAverageBrightness(header.fAvgBrightness); - newImage->SetColorRange(colMinARGB, colMaxARGB); - newImage->SetNumPersistentMips(header.bNumPersistentMips); - - return newImage; - } - - bool IsExtensionSupported(const char* extension) { QString ext = QString(extension).toLower(); @@ -226,215 +31,6 @@ namespace ImageProcessingAtom return ext == "dds"; } - IImageObject* LoadImageFromFileLegacy(const AZStd::string& filename) - { - AZ::IO::SystemFile file; - file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY); - - AZ::IO::SystemFileStream fileLoadStream(&file, true); - if (!fileLoadStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to open file %s", __FUNCTION__, filename.c_str()); - return nullptr; - } - - AZStd::string ext = ""; - AzFramework::StringFunc::Path::GetExtension(filename.c_str(), ext, false); - bool isAlphaImage = (ext == "a"); - - IImageObject* imageObj = LoadImageFromFileStreamLegacy(fileLoadStream); - - //load mips from seperated files if it's splitted - if (imageObj && imageObj->HasImageFlags(EIF_Splitted)) - { - AZStd::string baseName; - if (isAlphaImage) - { - baseName = filename.substr(0, filename.size() - 2); - } - else - { - baseName = filename; - } - - AZ::u32 externalMipCount = 0; - if (imageObj->GetNumPersistentMips() < imageObj->GetMipCount()) - { - externalMipCount = imageObj->GetMipCount() - imageObj->GetNumPersistentMips(); - } - //load other mips from files with number extensions - for (AZ::u32 mipIdx = 1; mipIdx <= externalMipCount; mipIdx++) - { - AZ::u32 mip = externalMipCount - mipIdx; - AZStd::string mipFileName = AZStd::string::format("%s.%d%s", baseName.c_str(), mipIdx, isAlphaImage ? "a" : ""); - - AZ::IO::SystemFile mipFile; - mipFile.Open(mipFileName.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY); - - AZ::IO::SystemFileStream mipFileLoadStream(&mipFile, true); - - if (!mipFileLoadStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to open mip file %s", __FUNCTION__, mipFileName.c_str()); - break; - } - - AZ::u32 pitch; - AZ::u8* mem; - imageObj->GetImagePointer(mip, mem, pitch); - AZ::u32 bufSize = imageObj->GetMipBufSize(mip); - mipFileLoadStream.Read(bufSize, mem); - } - } - - return imageObj; - } - - IImageObject* LoadImageFromFileStreamLegacy(AZ::IO::SystemFileStream& fileLoadStream) - { - if (fileLoadStream.GetLength() - fileLoadStream.GetCurPos() < sizeof(DDS_FILE_DESC_LEGACY)) - { - AZ_Error("Image Processing", false, "%s: Trying to load a none-DDS file", __FUNCTION__); - return nullptr; - } - - DDS_FILE_DESC_LEGACY desc; - DDS_HEADER_DXT10 exthead; - - AZ::IO::SizeType startPos = fileLoadStream.GetCurPos(); - fileLoadStream.Read(sizeof(desc.dwMagic), &desc.dwMagic); - - if (desc.dwMagic != FOURCC_DDS) - { - desc.dwMagic = FOURCC_DDS; - //the old cry .a file doesn't have "DDS " in the beginning of the file. - //so reset to previous position - fileLoadStream.Seek(startPos, AZ::IO::GenericStream::ST_SEEK_BEGIN); - } - - fileLoadStream.Read(sizeof(desc.header), &desc.header); - - if (!desc.IsValid()) - { - AZ_Error("Image Processing", false, "%s: Trying to load a none-DDS file", __FUNCTION__); - return nullptr; - } - - if (desc.header.IsDX10Ext()) - { - fileLoadStream.Read(sizeof(exthead), &exthead); - } - - IImageObject* outImage = CreateImageFromHeaderLegacy(desc.header, exthead); - - if (outImage == nullptr) - { - return nullptr; - } - - //load mip data - AZ::u32 mipStart = 0; - //There are at least three lowest mips are in the file if it was splitted. This is to load splitted dds file exported by legacy rc.exe - int numPersistentMips = outImage->GetNumPersistentMips(); - if (numPersistentMips == 0 && outImage->HasImageFlags(EIF_Splitted)) - { - outImage->SetNumPersistentMips(3); - } - - if (outImage->HasImageFlags(EIF_Splitted) - && outImage->GetMipCount() > outImage->GetNumPersistentMips()) - { - mipStart = outImage->GetMipCount() - outImage->GetNumPersistentMips(); - } - - AZ::u32 faces = 1; - if (outImage->HasImageFlags(EIF_Cubemap)) - { - faces = 6; - } - - for (AZ::u32 face = 0; face < faces; face++) - { - for (AZ::u32 mip = mipStart; mip < outImage->GetMipCount(); ++mip) - { - AZ::u32 pitch; - AZ::u8* mem; - outImage->GetImagePointer(mip, mem, pitch); - AZ::u32 faceBufSize = outImage->GetMipBufSize(mip) / faces; - fileLoadStream.Read(faceBufSize, mem + faceBufSize * face); - } - } - - return outImage; - } - - IImageObject* LoadAttachedImageFromDdsFileLegacy(const AZStd::string& filename, IImageObjectPtr originImage) - { - if (originImage == nullptr) - { - return nullptr; - } - - AZ_Assert(originImage->HasImageFlags(EIF_AttachedAlpha), - "this function should only be called for origin image loaded from same file with attached alpha flag"); - - AZ::IO::SystemFile file; - file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY); - - AZ::IO::SystemFileStream fileLoadStream(&file, true); - if (!fileLoadStream.IsOpen()) - { - AZ_Warning("Image Processing", false, "%s: failed to open file %s", __FUNCTION__, filename.c_str()); - return nullptr; - } - - DDS_FILE_DESC_LEGACY desc; - DDS_HEADER_DXT10 exthead; - - fileLoadStream.Read(sizeof(desc), &desc); - if (desc.dwMagic != FOURCC_DDS) - { - AZ_Error("Image Processing", false, "%s:Trying to load a none-DDS file", __FUNCTION__); - return nullptr; - } - - if (desc.header.IsDX10Ext()) - { - fileLoadStream.Read(sizeof(exthead), &exthead); - } - - //skip size for originImage's mip data - for (AZ::u32 mip = 0; mip < originImage->GetMipCount(); ++mip) - { - AZ::u32 bufSize = originImage->GetMipBufSize(mip); - fileLoadStream.Seek(bufSize, AZ::IO::GenericStream::ST_SEEK_CUR); - } - - IImageObject* alphaImage = nullptr; - - AZ::u32 marker = 0; - fileLoadStream.Read(4, &marker); - if (marker == FOURCC_CExt) // marker for the start of O3DE Extended data - { - fileLoadStream.Read(4, &marker); - if (FOURCC_AttC == marker) // Attached Channel chunk - { - AZ::u32 size = 0; - fileLoadStream.Read(4, &size); - - alphaImage = LoadImageFromFileStreamLegacy(fileLoadStream); - fileLoadStream.Read(4, &marker); - } - - if (FOURCC_CEnd == marker) // marker for the end of O3DE Extended data - { - fileLoadStream.Read(4, &marker); - } - } - - return alphaImage; - } - // Create an image object from standard dds header IImageObject* CreateImageFromHeader(DDS_HEADER& header, DDS_HEADER_DXT10& exthead) { @@ -526,45 +122,14 @@ namespace ImageProcessingAtom { format = ePixelFormat_BC1; } - else if (header.ddspf.dwFourCC == FOURCC_DXT5) + else if (header.ddspf.dwFourCC == FOURCC_DXT5 || header.ddspf.dwFourCC == FOURCC_DXT4) { format = ePixelFormat_BC3; } - else if (header.ddspf.dwFourCC == FOURCC_3DCP) - { - format = ePixelFormat_BC4; - } - else if (header.ddspf.dwFourCC == FOURCC_3DC) - { - format = ePixelFormat_BC5; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_R32F) - { - format = ePixelFormat_R32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_G32R32F) - { - format = ePixelFormat_R32G32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A32B32G32R32F) - { - format = ePixelFormat_R32G32B32A32F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_R16F) - { - format = ePixelFormat_R16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_G16R16F) - { - format = ePixelFormat_R16G16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A16B16G16R16F) - { - format = ePixelFormat_R16G16B16A16F; - } - else if (header.ddspf.dwFourCC == DDS_FOURCC_A16B16G16R16) + else { - format = ePixelFormat_R16G16B16A16; + AZ_Error("Image Processing", false, "unsupported fourCC format: 0x%x", header.ddspf.dwFourCC); + return nullptr; } } else diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/ImageLoaders.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/ImageLoaders.h index 587c9b551b..b860e82631 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/ImageLoaders.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageLoader/ImageLoaders.h @@ -44,11 +44,6 @@ namespace ImageProcessingAtom { bool IsExtensionSupported(const char* extension); IImageObject* LoadImageFromFile(const AZStd::string& filename); - - // These functions are for loading legacy O3DE dds files - IImageObject* LoadImageFromFileLegacy(const AZStd::string& filename); - IImageObject* LoadImageFromFileStreamLegacy(AZ::IO::SystemFileStream& fileLoadStream); - IImageObject* LoadAttachedImageFromDdsFileLegacy(const AZStd::string& filename, IImageObjectPtr originImage); };// namespace DdsLoader // Load .exr files to an image object diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Platform/Mac/platform_mac.cmake b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Platform/Mac/platform_mac.cmake index 7008b352a8..7a325ca97e 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Platform/Mac/platform_mac.cmake +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Platform/Mac/platform_mac.cmake @@ -5,8 +5,3 @@ # SPDX-License-Identifier: Apache-2.0 OR MIT # # - -set(LY_COMPILE_OPTIONS - PRIVATE - -fexceptions #ImageLoader/ExrLoader.cpp and PVRTC.cpp uses exceptions -) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h index 785424a9b1..0f953897c9 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h @@ -237,14 +237,8 @@ namespace ImageProcessingAtom const static AZ::u32 FOURCC_CEnd = IMAGE_BUIDER_MAKEFOURCC('C', 'E', 'n', 'd'); // O3DE extension end const static AZ::u32 FOURCC_AttC = IMAGE_BUIDER_MAKEFOURCC('A', 't', 't', 'C'); // Chunk Attached Channel - //Fourcc for pixel formats which aren't supported by dx10, such as astc formats, etc formats, pvrtc formats + //Fourcc for pixel formats which aren't supported by dx10, such as astc formats //They are used for dwFourCC of dds header's DDS_PIXELFORMAT to identify non-dx10 pixel formats - const static AZ::u32 FOURCC_EAC_R11 = IMAGE_BUIDER_MAKEFOURCC('E', 'A', 'R', ' '); - const static AZ::u32 FOURCC_EAC_RG11 = IMAGE_BUIDER_MAKEFOURCC('E', 'A', 'R', 'G'); - const static AZ::u32 FOURCC_ETC2 = IMAGE_BUIDER_MAKEFOURCC('E', 'T', '2', ' '); - const static AZ::u32 FOURCC_ETC2A = IMAGE_BUIDER_MAKEFOURCC('E', 'T', '2', 'A'); - const static AZ::u32 FOURCC_PVRTC2 = IMAGE_BUIDER_MAKEFOURCC('P', 'V', 'R', '2'); - const static AZ::u32 FOURCC_PVRTC4 = IMAGE_BUIDER_MAKEFOURCC('P', 'V', 'R', '4'); const static AZ::u32 FOURCC_ASTC_4x4 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '4', '4'); const static AZ::u32 FOURCC_ASTC_5x4 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '5', '4'); const static AZ::u32 FOURCC_ASTC_5x5 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', '5', '5'); @@ -260,10 +254,10 @@ namespace ImageProcessingAtom const static AZ::u32 FOURCC_ASTC_12x10 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'C', 'A'); const static AZ::u32 FOURCC_ASTC_12x12 = IMAGE_BUIDER_MAKEFOURCC('A', 'S', 'C', 'C'); - //legacy formats names. they are only used for load rc.exe's dds formats + //legacy formats names. they are only used for load old dds formats. const static AZ::u32 FOURCC_DXT1 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '1'); + const static AZ::u32 FOURCC_DXT2 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '2'); const static AZ::u32 FOURCC_DXT3 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '3'); + const static AZ::u32 FOURCC_DXT4 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '4'); const static AZ::u32 FOURCC_DXT5 = IMAGE_BUIDER_MAKEFOURCC('D', 'X', 'T', '5'); - const static AZ::u32 FOURCC_3DCP = IMAGE_BUIDER_MAKEFOURCC('A', 'T', 'I', '1'); - const static AZ::u32 FOURCC_3DC = IMAGE_BUIDER_MAKEFOURCC('A', 'T', 'I', '2'); } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.cpp index 94fce9bc1f..8a741d6637 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.cpp @@ -52,19 +52,6 @@ namespace ImageProcessingAtom return false; } - bool IsETCFormat(EPixelFormat fmt) - { - if (fmt == ePixelFormat_ETC2 - || fmt == ePixelFormat_ETC2a - || fmt == ePixelFormat_ETC2a1 - || fmt == ePixelFormat_EAC_R11 - || fmt == ePixelFormat_EAC_RG11) - { - return true; - } - return false; - } - PixelFormatInfo::PixelFormatInfo( uint32_t a_bitsPerPixel, uint32_t a_Channels, @@ -96,7 +83,6 @@ namespace ImageProcessingAtom , fourCC(a_fourCC) , eSampleType(a_eSampleType) , szName(a_szName) - , szLegacyName(a_szName) , szDescription(a_szDescription) , bCompressed(a_bCompressed) , bSelectable(a_bSelectable) @@ -122,15 +108,6 @@ namespace ImageProcessingAtom CPixelFormats::CPixelFormats() { InitPixelFormats(); - - m_removedLegacyFormats["DXT1"] = ePixelFormat_BC1; - m_removedLegacyFormats["DXT1a"] = ePixelFormat_BC1a; - m_removedLegacyFormats["DXT3"] = ePixelFormat_BC3; - m_removedLegacyFormats["DXT3t"] = ePixelFormat_BC3t; - m_removedLegacyFormats["DXT5"] = ePixelFormat_BC3; - m_removedLegacyFormats["DXT5t"] = ePixelFormat_BC3t; - m_removedLegacyFormats["3DCp"] = ePixelFormat_BC4; - m_removedLegacyFormats["3DC"] = ePixelFormat_BC5; } void CPixelFormats::InitPixelFormat(EPixelFormat format, const PixelFormatInfo& formatInfo) @@ -176,13 +153,6 @@ namespace ImageProcessingAtom InitPixelFormat(ePixelFormat_ASTC_10x10, PixelFormatInfo(0, 4, true, "?", 16, 16, 10, 10, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_10x10, ESampleType::eSampleType_Compressed, "ASTC_10x10", "ASTC 10x10 compressed texture format", true, false)); InitPixelFormat(ePixelFormat_ASTC_12x10, PixelFormatInfo(0, 4, true, "?", 16, 16, 12, 10, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_12x10, ESampleType::eSampleType_Compressed, "ASTC_12x10", "ASTC 12x10 compressed texture format", true, false)); InitPixelFormat(ePixelFormat_ASTC_12x12, PixelFormatInfo(0, 4, true, "?", 16, 16, 12, 12, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ASTC_12x12, ESampleType::eSampleType_Compressed, "ASTC_12x12", "ASTC 12x12 compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_PVRTC2, PixelFormatInfo(2, 4, true, "2", 16, 16, 8, 4, 64, true, DXGI_FORMAT_UNKNOWN, FOURCC_PVRTC2, ESampleType::eSampleType_Compressed, "PVRTC2", "POWERVR 2 bpp compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_PVRTC4, PixelFormatInfo(4, 4, true, "2", 8, 8, 4, 4, 64, true, DXGI_FORMAT_UNKNOWN, FOURCC_PVRTC4, ESampleType::eSampleType_Compressed, "PVRTC4", "POWERVR 4 bpp compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_EAC_R11, PixelFormatInfo(4, 1, true, "4", 4, 4, 4, 4, 64, false, DXGI_FORMAT_UNKNOWN, FOURCC_EAC_R11, ESampleType::eSampleType_Compressed, "EAC_R11", "EAC 4 bpp single channel texture format", true, false)); - InitPixelFormat(ePixelFormat_EAC_RG11, PixelFormatInfo(8, 2, false, "0", 4, 4, 4, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_EAC_RG11, ESampleType::eSampleType_Compressed, "EAC_RG11", "EAC 8 bpp dual channel texture format", true, false)); - InitPixelFormat(ePixelFormat_ETC2, PixelFormatInfo(4, 3, false, "0", 4, 4, 4, 4, 64, false, DXGI_FORMAT_UNKNOWN, FOURCC_ETC2, ESampleType::eSampleType_Compressed, "ETC2", "ETC2 RGB 4 bpp compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ETC2a, PixelFormatInfo(8, 4, true, "4", 4, 4, 4, 4, 128, false, DXGI_FORMAT_UNKNOWN, FOURCC_ETC2A, ESampleType::eSampleType_Compressed, "ETC2a", "ETC2 RGBA 8 bpp compressed texture format", true, false)); - InitPixelFormat(ePixelFormat_ETC2a1, PixelFormatInfo(4, 4, true, "1", 4, 4, 4, 4, 64, false, DXGI_FORMAT_UNKNOWN, FOURCC_ETC2A, ESampleType::eSampleType_Compressed, "ETC2a1", "ETC2 RGBA1 8 bpp compressed texture format", true, false)); // Standardized Compressed DXGI Formats (DX10+) // Data in these compressed formats is hardware decodable on all DX10 chips, and manageable with the DX10-API. @@ -216,17 +186,6 @@ namespace ImageProcessingAtom InitPixelFormat(ePixelFormat_R32, PixelFormatInfo(32, 1, false, "0", 1, 1, 1, 1, 32, false, DXGI_FORMAT_FORCE_UINT, FOURCC_DX10, ESampleType::eSampleType_Uint32, "R32", "32-bit red only", false, false)); - //Set legacy name it can be used for convertion - m_pixelFormatInfo[ePixelFormat_R8G8B8A8].szLegacyName = "A8R8G8B8"; - m_pixelFormatInfo[ePixelFormat_R8G8B8X8].szLegacyName = "X8R8G8B8"; - m_pixelFormatInfo[ePixelFormat_R8G8].szLegacyName = "G8R8"; - m_pixelFormatInfo[ePixelFormat_R16G16B16A16].szLegacyName = "A16B16G16R16"; - m_pixelFormatInfo[ePixelFormat_R16G16].szLegacyName = "G16R16"; - m_pixelFormatInfo[ePixelFormat_R32G32B32A32F].szLegacyName = "A32B32G32R32F"; - m_pixelFormatInfo[ePixelFormat_R32G32F].szLegacyName = "G32R32F"; - m_pixelFormatInfo[ePixelFormat_R16G16B16A16F].szLegacyName = "A16B16G16R16F"; - m_pixelFormatInfo[ePixelFormat_R16G16F].szLegacyName = "G16R16F"; - //validate all pixel formats are proper initialized for (int i = 0; i < ePixelFormat_Count; ++i) { @@ -249,23 +208,6 @@ namespace ImageProcessingAtom return ePixelFormat_Unknown; } - EPixelFormat CPixelFormats::FindPixelFormatByLegacyName(const char* name) - { - if (m_removedLegacyFormats.find(name) != m_removedLegacyFormats.end()) - { - return m_removedLegacyFormats[name]; - } - - for (int i = 0; i < ePixelFormat_Count; ++i) - { - if (azstricmp(m_pixelFormatInfo[i].szLegacyName, name) == 0) - { - return (EPixelFormat)i; - } - } - return ePixelFormat_Unknown; - } - const PixelFormatInfo* CPixelFormats::GetPixelFormatInfo(EPixelFormat format) { AZ_Assert((format >= 0) && (format < ePixelFormat_Count), "Unsupport pixel format: %d", format); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h index ec1ec1bfaf..92c4bdd99e 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h @@ -119,7 +119,6 @@ namespace ImageProcessingAtom bool bSquarePow2; // whether the pixel format requires image size be square and power of 2. DXGI_FORMAT d3d10Format; // the mapping d3d10 pixel format ESampleType eSampleType; // the data type used to present pixel - const char* szLegacyName; // name used for cryEngine const char* szName; // name for showing in editors const char* szDescription; // description for showing in editors bool bCompressed; // if it's a compressed format @@ -173,10 +172,6 @@ namespace ImageProcessingAtom bool IsFormatSigned(EPixelFormat fmt); bool IsFormatFloatingPoint(EPixelFormat fmt, bool bFullPrecision); - //find the pixel format for name used by Cry's RC.ini - //returns ePixelFormat_Unknown if the name was not found in registed format list - EPixelFormat FindPixelFormatByLegacyName(const char* name); - //find pixel format by its name EPixelFormat FindPixelFormatByName(const char* name); @@ -208,9 +203,6 @@ namespace ImageProcessingAtom //pixel format name to pixel format enum AZStd::map m_pixelFormatNameMap; - - // some formats from cryEngine were removed. using this name-pixelFormat mapping to look for new format - AZStd::map m_removedLegacyFormats; }; template diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp index d282e9b02b..29ba8c3351 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp @@ -102,32 +102,6 @@ namespace ImageProcessingAtom case AZ::RHI::Format::ASTC_12x12_UNORM: return ePixelFormat_ASTC_12x12; - case AZ::RHI::Format::PVRTC2_UNORM_SRGB: - isSRGB = true; - case AZ::RHI::Format::PVRTC2_UNORM: - return ePixelFormat_PVRTC2; - case AZ::RHI::Format::PVRTC4_UNORM_SRGB: - isSRGB = true; - case AZ::RHI::Format::PVRTC4_UNORM: - return ePixelFormat_PVRTC4; - - case AZ::RHI::Format::EAC_R11_UNORM: - return ePixelFormat_EAC_R11; - case AZ::RHI::Format::EAC_RG11_UNORM: - return ePixelFormat_EAC_RG11; - case AZ::RHI::Format::ETC2_UNORM_SRGB: - isSRGB = true; - case AZ::RHI::Format::ETC2_UNORM: - return ePixelFormat_ETC2; - case AZ::RHI::Format::ETC2A_UNORM_SRGB: - isSRGB = true; - case AZ::RHI::Format::ETC2A_UNORM: - return ePixelFormat_ETC2a; - case AZ::RHI::Format::ETC2A1_UNORM_SRGB: - isSRGB = true; - case AZ::RHI::Format::ETC2A1_UNORM: - return ePixelFormat_ETC2a1; - case AZ::RHI::Format::BC1_UNORM_SRGB: isSRGB = true; case AZ::RHI::Format::BC1_UNORM: @@ -225,22 +199,6 @@ namespace ImageProcessingAtom case ePixelFormat_ASTC_12x12: return isSrgb ? RHI::Format::ASTC_12x12_UNORM_SRGB : RHI::Format::ASTC_12x12_UNORM; - case ePixelFormat_PVRTC2: - return isSrgb ? RHI::Format::PVRTC2_UNORM_SRGB : RHI::Format::PVRTC2_UNORM; - case ePixelFormat_PVRTC4: - return isSrgb ? RHI::Format::PVRTC4_UNORM_SRGB : RHI::Format::PVRTC4_UNORM; - - case ePixelFormat_EAC_R11: - return RHI::Format::EAC_R11_UNORM; - case ePixelFormat_EAC_RG11: - return RHI::Format::EAC_RG11_UNORM; - case ePixelFormat_ETC2: - return isSrgb ? RHI::Format::ETC2_UNORM_SRGB : RHI::Format::ETC2_UNORM; - case ePixelFormat_ETC2a: - return isSrgb ? RHI::Format::ETC2A_UNORM_SRGB : RHI::Format::ETC2A_UNORM; - case ePixelFormat_ETC2a1: - return isSrgb ? RHI::Format::ETC2A1_UNORM_SRGB : RHI::Format::ETC2A1_UNORM; - case ePixelFormat_BC1: case ePixelFormat_BC1a: return isSrgb ? RHI::Format::BC1_UNORM_SRGB : RHI::Format::BC1_UNORM; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index c72e1dc309..9e4aa83908 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -426,60 +426,6 @@ namespace UnitTest return isDifferent; } - - bool CompareDDSImage(const QString& imagePath1, const QString& imagePath2, QString& output) - { - IImageObjectPtr image1, alphaImage1, image2, alphaImage2; - - - image1 = IImageObjectPtr(DdsLoader::LoadImageFromFileLegacy(imagePath1.toUtf8().constData())); - if (image1 && image1->HasImageFlags(EIF_AttachedAlpha)) - { - if (image1->HasImageFlags(EIF_Splitted)) - { - alphaImage1 = IImageObjectPtr(DdsLoader::LoadImageFromFileLegacy(QString(imagePath1 + ".a").toUtf8().constData())); - } - else - { - alphaImage1 = IImageObjectPtr(DdsLoader::LoadAttachedImageFromDdsFileLegacy(imagePath1.toUtf8().constData(), image1)); - } - } - - image2 = IImageObjectPtr(DdsLoader::LoadImageFromFileLegacy(imagePath2.toUtf8().constData())); - if (image2 && image2->HasImageFlags(EIF_AttachedAlpha)) - { - if (image2->HasImageFlags(EIF_Splitted)) - { - alphaImage2 = IImageObjectPtr(DdsLoader::LoadImageFromFileLegacy(QString(imagePath2 + ".a").toUtf8().constData())); - } - else - { - alphaImage2 = IImageObjectPtr(DdsLoader::LoadAttachedImageFromDdsFileLegacy(imagePath2.toUtf8().constData(), image2)); - } - } - - if (!image1 && !image2) - { - output += "Cannot load both image file! "; - return false; - } - bool isDifferent = false; - - isDifferent = GetComparisonResult(image1, image2, output); - - - QFileInfo fi(imagePath1); - AZStd::string imageName = fi.baseName().toUtf8().constData(); - SaveImageToFile(image1, imageName + "_new"); - SaveImageToFile(image2, imageName + "_old"); - - if (alphaImage1 || alphaImage2) - { - isDifferent |= GetComparisonResult(alphaImage1, alphaImage2, output); - } - - return isDifferent; - } }; // test CPixelFormats related functions @@ -487,34 +433,6 @@ namespace UnitTest { CPixelFormats& pixelFormats = CPixelFormats::GetInstance(); - //verify names which was used for legacy rc.ini - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC7t") == ePixelFormat_BC7t); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("ETC2A") == ePixelFormat_ETC2a); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("PVRTC4") == ePixelFormat_PVRTC4); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC1") == ePixelFormat_BC1); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("ETC2") == ePixelFormat_ETC2); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC1a") == ePixelFormat_BC1a); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC3") == ePixelFormat_BC3); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC7") == ePixelFormat_BC7); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC5s") == ePixelFormat_BC5s); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("EAC_RG11") == ePixelFormat_EAC_RG11); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC4") == ePixelFormat_BC4); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("EAC_R11") == ePixelFormat_EAC_R11); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("A8R8G8B8") == ePixelFormat_R8G8B8A8); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("BC6UH") == ePixelFormat_BC6UH); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("R9G9B9E5") == ePixelFormat_R9G9B9E5); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("X8R8G8B8") == ePixelFormat_R8G8B8X8); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("A16B16G16R16F") == ePixelFormat_R16G16B16A16F); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("G8R8") == ePixelFormat_R8G8); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("G16R16") == ePixelFormat_R16G16); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("G16R16F") == ePixelFormat_R16G16F); - - //some legacy format need to be mapping to new format. - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("DXT1") == ePixelFormat_BC1); - ASSERT_TRUE(pixelFormats.FindPixelFormatByLegacyName("DXT5") == ePixelFormat_BC3); - - //calculate mipmap count. no cubemap support at this moment - //for all the non-compressed textures, if there minimum required texture size is 1x1 for (uint32 i = 0; i < ePixelFormat_Count; i++) { @@ -543,13 +461,6 @@ namespace UnitTest } //check function IsImageSizeValid && EvaluateImageDataSize function - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 2, 1, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 4, 4, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 16, 16, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 16, 32, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 34, 34, false) == false); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_PVRTC4, 256, 256, false) == true); - ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 2, 1, false) == false); ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 16, 16, false) == true); ASSERT_TRUE(pixelFormats.IsImageSizeValid(ePixelFormat_BC1, 16, 32, false) == true); @@ -834,9 +745,7 @@ namespace UnitTest if (formatInfo->bCompressed) { // skip ASTC formats which are tested in TestConvertASTCCompressor - if (!IsASTCFormat(pixelFormat) - && pixelFormat != ePixelFormat_PVRTC2 && pixelFormat != ePixelFormat_PVRTC4 - && !IsETCFormat(pixelFormat)) // skip ETC since it's very slow + if (!IsASTCFormat(pixelFormat)) { compressedFormats.push_back(pixelFormat); } @@ -1112,55 +1021,6 @@ namespace UnitTest } } - TEST_F(ImageProcessingTest, DISABLED_CompareOutputImage) - { - AZStd::string curretTextureFolder = "../TestAssets/TextureAssets/assets_new/textures"; - AZStd::string oldTextureFolder = "../TestAssets/TextureAssets/assets_old/textures"; - bool outputOnlyDifferent = false; - QDirIterator it(curretTextureFolder.c_str(), QStringList() << "*.dds", QDir::Files, QDirIterator::Subdirectories); - QFile f("../texture_comparison_output.csv"); - f.open(QIODevice::ReadWrite | QIODevice::Truncate); - // Write a header for csv file - f.write("Texture Name, Path, Mip new/old, MipDiff, Format new/old, Flag new/old, MemSize new/old, MemDiff, Error, AlphaMip new/old, AlphaMipDiff, AlphaFormat new/old, AlphaFlag new/old, AlphaMemSize new/old, AlphaMemDiff, AlphaError\r\n"); - int i = 0; - while (it.hasNext()) - { - i++; - it.next(); - - QString fileName = it.fileName(); - QString newFilePath = it.filePath(); - QString sharedPath = QString(newFilePath).remove(curretTextureFolder.c_str()); - QString oldFilePath = QString(oldTextureFolder.c_str()) + sharedPath; - QString output; - if (QFile::exists(oldFilePath)) - { - bool isDifferent = CompareDDSImage(newFilePath, oldFilePath, output); - if (outputOnlyDifferent && !isDifferent) - { - continue; - } - else - { - f.write(fileName.toUtf8().constData()); - f.write(","); - f.write(sharedPath.toUtf8().constData()); - f.write(output.toUtf8().constData()); - } - } - else - { - f.write(fileName.toUtf8().constData()); - f.write(","); - f.write(sharedPath.toUtf8().constData()); - output += ",No old file for comparison!"; - f.write(output.toUtf8().constData()); - } - f.write("\r\n"); - } - f.close(); - } - TEST_F(ImageProcessingTest, TextureSettingReflect_SerializingModernDataInAndOut_WritesAndParsesFileAccurately) { AZStd::string filepath = "test.xml"; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake index ba9e9f29b7..aad400518d 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake @@ -120,10 +120,6 @@ set(FILES Source/Compressors/Compressor.cpp Source/Compressors/CTSquisher.h Source/Compressors/CTSquisher.cpp - Source/Compressors/PVRTC.cpp - Source/Compressors/PVRTC.h - Source/Compressors/ETC2.cpp - Source/Compressors/ETC2.h Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4f.cpp Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4s.cpp Source/Compressors/CryTextureSquisher/ColorBlockRGBA4x4c.cpp diff --git a/Gems/TextureAtlas/Code/Source/Editor/AtlasBuilderWorker.cpp b/Gems/TextureAtlas/Code/Source/Editor/AtlasBuilderWorker.cpp index abcdce99b9..f6e6a1254c 100644 --- a/Gems/TextureAtlas/Code/Source/Editor/AtlasBuilderWorker.cpp +++ b/Gems/TextureAtlas/Code/Source/Editor/AtlasBuilderWorker.cpp @@ -757,9 +757,7 @@ namespace TextureAtlasBuilder if (input.m_presetName.empty()) { - // Default to the TextureAtlas preset which is currently set to use compression for all platforms except for iOS. - // Currently the only fully supported compression for iOS is PVRTC which requires the texture to be square and a power of 2. - // Due to this limitation, we default to using no compression for iOS until ASTC is fully supported + // Default to the TextureAtlas preset which is currently set to use compression const AZStd::string defaultPresetName = "UserInterface_Compressed"; input.m_presetName = defaultPresetName; } diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index fb02a80088..8e4a3ef828 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -20,7 +20,6 @@ ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) -ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-linux TARGETS AWSGameLiftServerSDK PACKAGE_HASH a8149a95bd100384af6ade97e2b21a56173740d921e6c3da8188cd51554d39af) @@ -29,7 +28,6 @@ ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-linux ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev6-linux TARGETS AWSNativeSDK PACKAGE_HASH 490291e4c8057975c3ab86feb971b8a38871c58bac5e5d86abdd1aeb7141eec4) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-linux TARGETS Lua PACKAGE_HASH 1adc812abe3dd0dbb2ca9756f81d8f0e0ba45779ac85bf1d8455b25c531a38b0) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-linux TARGETS PhysX PACKAGE_HASH a110249cbef4f266b0002c4ee9a71f59f373040cefbe6b82f1e1510c811edde6) -ly_associate_package(PACKAGE_NAME etc2comp-9cd0f9cae0-rev1-linux TARGETS etc2comp PACKAGE_HASH 9283aa5db5bb7fb90a0ddb7a9f3895317c8ebe8044943124bbb3673a41407430) ly_associate_package(PACKAGE_NAME mcpp-2.7.2_az.2-rev1-linux TARGETS mcpp PACKAGE_HASH df7a998d0bc3fedf44b5bdebaf69ddad6033355b71a590e8642445ec77bc6c41) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-linux TARGETS mikkelsen PACKAGE_HASH 5973b1e71a64633588eecdb5b5c06ca0081f7be97230f6ef64365cbda315b9c8) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-linux TARGETS googletest PACKAGE_HASH 7b7ad330f369450c316a4c4592d17fbb4c14c731c95bd8f37757203e8c2bbc1b) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index e80956530a..631c42784a 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -21,7 +21,6 @@ ly_associate_package(PACKAGE_NAME azslc-1.7.23-rev1-multiplatform ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) -ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-mac TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 3f77367dbb0342136ec4ebbd44bc1fedf7198089a0f83c5631248530769b2be6) @@ -31,7 +30,6 @@ ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-mac ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev5-mac TARGETS AWSNativeSDK PACKAGE_HASH ffb890bd9cf23afb429b9214ad9bac1bf04696f07a0ebb93c42058c482ab2f01) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev6-mac TARGETS Lua PACKAGE_HASH b9079fd35634774c9269028447562c6b712dbc83b9c64975c095fd423ff04c08) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-mac TARGETS PhysX PACKAGE_HASH 5e092a11d5c0a50c4dd99bb681a04b566a4f6f29aa08443d9bffc8dc12c27c8e) -ly_associate_package(PACKAGE_NAME etc2comp-9cd0f9cae0-rev1-mac TARGETS etc2comp PACKAGE_HASH 1966ab101c89db7ecf30984917e0a48c0d02ee0e4d65b798743842b9469c0818) ly_associate_package(PACKAGE_NAME mcpp-2.7.2_az.2-rev1-mac TARGETS mcpp PACKAGE_HASH be9558905c9c49179ef3d7d84f0a5472415acdf7fe2d76eb060d9431723ddf2e) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-mac TARGETS mikkelsen PACKAGE_HASH 83af99ca8bee123684ad254263add556f0cf49486c0b3e32e6d303535714e505) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-mac TARGETS googletest PACKAGE_HASH cbf020d5ef976c5db8b6e894c6c63151ade85ed98e7c502729dd20172acae5a8) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 7e112c405e..428e5e9526 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -21,7 +21,6 @@ ly_associate_package(PACKAGE_NAME azslc-1.7.23-rev1-multiplatform ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) -ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-windows TARGETS AWSGameLiftServerSDK PACKAGE_HASH a0586b006e4def65cc25f388de17dc475e417dc1e6f9d96749777c88aa8271b0) @@ -32,7 +31,6 @@ ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-windows ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-windows TARGETS AWSNativeSDK PACKAGE_HASH a900e80f7259e43aed5c847afee2599ada37f29db70505481397675bcbb6c76c) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-windows TARGETS Lua PACKAGE_HASH 136faccf1f73891e3fa3b95f908523187792e56f5b92c63c6a6d7e72d1158d40) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-windows TARGETS PhysX PACKAGE_HASH 0c5ffbd9fa588e5cf7643721a7cfe74d0fe448bf82252d39b3a96d06dfca2298) -ly_associate_package(PACKAGE_NAME etc2comp-9cd0f9cae0-rev1-windows TARGETS etc2comp PACKAGE_HASH fc9ae937b2ec0d42d5e7d0e9e8c80e5e4d257673fb33bc9b7d6db76002117123) ly_associate_package(PACKAGE_NAME mcpp-2.7.2_az.2-rev1-windows TARGETS mcpp PACKAGE_HASH 794789aba639bfe2f4e8fcb4424d679933dd6290e523084aa0a4e287ac44acb2) ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-windows TARGETS mikkelsen PACKAGE_HASH 872c4d245a1c86139aa929f2b465b63ea4ea55b04ced50309135dd4597457a4e) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-windows TARGETS googletest PACKAGE_HASH 7e8f03ae8a01563124e3daa06386f25a2b311c10bb95bff05cae6c41eff83837) From f43b3b9fbefa56b0500da096b900809c0dedeb23 Mon Sep 17 00:00:00 2001 From: Mikhail Naumov Date: Thu, 7 Oct 2021 20:35:23 -0500 Subject: [PATCH 134/293] Fixing crash creating new level when simulate mode is on Signed-off-by: Mikhail Naumov --- Code/Editor/CryEdit.cpp | 10 ++++++++++ .../AzFramework/Spawnable/RootSpawnableInterface.h | 4 ++++ .../AzFramework/Spawnable/SpawnableSystemComponent.cpp | 9 +++++++-- .../AzFramework/Spawnable/SpawnableSystemComponent.h | 1 + 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 4aa3d22114..d2a448bd34 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -57,6 +57,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include // AzToolsFramework #include @@ -3019,6 +3020,15 @@ CCryEditApp::ECreateLevelResult CCryEditApp::CreateLevel(const QString& levelNam bool bIsDocModified = GetIEditor()->GetDocument()->IsModified(); OnSwitchPhysics(); GetIEditor()->GetDocument()->SetModifiedFlag(bIsDocModified); + + if (usePrefabSystemForLevels) + { + auto* rootSpawnableInterface = AzFramework::RootSpawnableInterface::Get(); + if (rootSpawnableInterface) + { + rootSpawnableInterface->ProcessSpawnableQueue(); + } + } } const QScopedValueRollback rollback(m_creatingNewLevel); diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/RootSpawnableInterface.h b/Code/Framework/AzFramework/AzFramework/Spawnable/RootSpawnableInterface.h index bb1f137ba2..72a3031e3e 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/RootSpawnableInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/RootSpawnableInterface.h @@ -61,6 +61,10 @@ namespace AzFramework //! be deleted and the spawnable asset to be released. This call is automatically done when //! AssignRootSpawnable is called while a root spawnable is assigned. virtual void ReleaseRootSpawnable() = 0; + //! Force processing all SpawnableEntitiesManager requests immediately + //! This is useful when loading a different level while SpawnableEntitiesManager still has + //! pending requests + virtual void ProcessSpawnableQueue() = 0; }; using RootSpawnableInterface = AZ::Interface; diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp index f6130c9e31..af41fdd6ba 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp @@ -45,8 +45,7 @@ namespace AzFramework void SpawnableSystemComponent::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) { - m_entitiesManager.ProcessQueue( - SpawnableEntitiesManager::CommandQueuePriority::High | SpawnableEntitiesManager::CommandQueuePriority::Regular); + ProcessSpawnableQueue(); RootSpawnableNotificationBus::ExecuteQueuedEvents(); } @@ -121,6 +120,12 @@ namespace AzFramework m_rootSpawnableId = AZ::Data::AssetId(); } + void SpawnableSystemComponent::ProcessSpawnableQueue() + { + m_entitiesManager.ProcessQueue( + SpawnableEntitiesManager::CommandQueuePriority::High | SpawnableEntitiesManager::CommandQueuePriority::Regular); + } + void SpawnableSystemComponent::OnRootSpawnableAssigned([[maybe_unused]] AZ::Data::Asset rootSpawnable, [[maybe_unused]] uint32_t generation) { diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.h index 5b5fb1b7ee..74e255d624 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.h @@ -75,6 +75,7 @@ namespace AzFramework uint64_t AssignRootSpawnable(AZ::Data::Asset rootSpawnable) override; void ReleaseRootSpawnable() override; + void ProcessSpawnableQueue() override; // // RootSpawnbleNotificationBus From c90e1da475db44d2cd9be82a5cef7d832dabdc6e Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 7 Oct 2021 21:05:10 -0500 Subject: [PATCH 135/293] =?UTF-8?q?=E2=80=A2=20Moved=20everything=20relate?= =?UTF-8?q?d=20to=20the=20subject=20being=20captured=20by=20the=20preview?= =?UTF-8?q?=20renderer=20into=20a=20preview=20render=20content=20class=20w?= =?UTF-8?q?hich=20will=20become=20an=20interface=20in=20the=20next=20itera?= =?UTF-8?q?tion=20=E2=80=A2=20Extracted=20all=20of=20the=20thumbnail=20spe?= =?UTF-8?q?cific=20code=20from=20the=20common=20preview=20render=20class?= =?UTF-8?q?=20as=20a=20step=20towards=20separating=20it=20from=20the=20thu?= =?UTF-8?q?mbnail=20system=20completely=20=E2=80=A2=20Created=20a=20captur?= =?UTF-8?q?e=20request=20structure=20that=20stores=20all=20of=20the=20info?= =?UTF-8?q?=20related=20to=20the=20content=20being=20captured=20and=20call?= =?UTF-8?q?backs=20for=20success=20and=20failure=20=E2=80=A2=20Request=20t?= =?UTF-8?q?o=20capture=20any=20kind=20of=20content=20can=20be=20added=20to?= =?UTF-8?q?=20the=20renderer=20using=20this=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../PreviewerFeatureProcessorProviderBus.h | 4 +- .../Rendering/CommonPreviewContent.cpp | 170 ++++++++++++++ .../Rendering/CommonPreviewContent.h | 79 +++++++ .../Rendering/CommonPreviewRenderer.cpp | 221 +++++------------- .../Rendering/CommonPreviewRenderer.h | 67 ++---- .../CommonPreviewRendererCaptureState.cpp | 2 +- .../CommonPreviewRendererIdleState.cpp | 2 +- ...egration_commonfeatures_editor_files.cmake | 2 + 8 files changed, 340 insertions(+), 207 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h index ef0e586348..bae49db89d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h @@ -16,14 +16,14 @@ namespace AZ { namespace Thumbnails { - //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation + //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for preview image generation //! Duplicates will be ignored //! You can check minimal feature processors that are already registered in CommonPreviewRenderer.cpp class PreviewerFeatureProcessorProviderRequests : public AZ::EBusTraits { public: - //! Get a list of custom feature processors to register with thumbnail renderer + //! Get a list of custom feature processors to register with preview image renderer virtual void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp new file mode 100644 index 0000000000..12caac1e90 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + CommonPreviewContent::CommonPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId) + : m_scene(scene) + , m_view(view) + , m_entityContextId(entityContextId) + { + // Connect camera to pipeline's default view after camera entity activated + Matrix4x4 viewToClipMatrix; + MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); + m_view->SetViewToClipMatrix(viewToClipMatrix); + + // Create preview model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); + m_modelEntity->CreateComponent(Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Init(); + m_modelEntity->Activate(); + + m_defaultModelAsset.Create(DefaultModelAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + + m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, false); + m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, false); + m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, false); + } + + CommonPreviewContent::~CommonPreviewContent() + { + if (m_modelEntity) + { + AzFramework::EntityContextRequestBus::Event( + m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + } + } + + void CommonPreviewContent::Load() + { + m_modelAsset.QueueLoad(); + m_materialAsset.QueueLoad(); + m_lightingPresetAsset.QueueLoad(); + } + + bool CommonPreviewContent::IsReady() const + { + return m_modelAsset.IsReady() && m_materialAsset.IsReady() && m_lightingPresetAsset.IsReady(); + } + + bool CommonPreviewContent::IsError() const + { + return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); + } + + void CommonPreviewContent::ReportErrors() + { + AZ_Warning( + "CommonPreviewContent", m_modelAsset.IsReady(), "Asset failed to load in time: %s", + m_modelAsset.ToString().c_str()); + AZ_Warning( + "CommonPreviewContent", m_materialAsset.IsReady(), "Asset failed to load in time: %s", + m_materialAsset.ToString().c_str()); + AZ_Warning( + "CommonPreviewContent", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", + m_lightingPresetAsset.ToString().c_str()); + } + + void CommonPreviewContent::UpdateScene() + { + UpdateModel(); + UpdateLighting(); + UpdateCamera(); + } + + void CommonPreviewContent::UpdateModel() + { + Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, + m_materialAsset.GetId()); + } + + void CommonPreviewContent::UpdateLighting() + { + auto preset = m_lightingPresetAsset->GetDataAs(); + if (preset) + { + auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); + auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); + auto directionalLightFeatureProcessor = + m_scene->GetFeatureProcessor(); + auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + skyboxFeatureProcessor->Enable(true); + skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); + + Camera::Configuration cameraConfig; + cameraConfig.m_fovRadians = FieldOfView; + cameraConfig.m_nearClipDistance = NearDist; + cameraConfig.m_farClipDistance = FarDist; + cameraConfig.m_frustumWidth = 100.0f; + cameraConfig.m_frustumHeight = 100.0f; + + AZStd::vector lightHandles; + + preset->ApplyLightingPreset( + iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, + cameraConfig, lightHandles); + } + } + + void CommonPreviewContent::UpdateCamera() + { + // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it + Vector3 center = {}; + float radius = {}; + m_modelAsset->GetAabb().GetAsSphere(center, radius); + + const auto distance = radius + NearDist; + const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); + const auto cameraPosition = center - cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); + const auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); + m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); + } + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h new file mode 100644 index 0000000000..6c8f0c5565 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + //! Provides custom rendering of material and model thumbnails + class CommonPreviewContent + { + public: + AZ_CLASS_ALLOCATOR(CommonPreviewContent, AZ::SystemAllocator, 0); + + CommonPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId); + ~CommonPreviewContent(); + + void Load(); + bool IsReady() const; + bool IsError() const; + void ReportErrors(); + void UpdateScene(); + + private: + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = Constants::HalfPi; + static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; + + RPI::ScenePtr m_scene; + RPI::ViewPtr m_view; + AZ::Uuid m_entityContextId; + Entity* m_modelEntity = nullptr; + + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + Data::Asset m_lightingPresetAsset; + + //! Model asset about to be rendered + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + Data::Asset m_modelAsset; + + //! Material asset about to be rendered + static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; + const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); + Data::Asset m_defaultMaterialAsset; + Data::Asset m_materialAsset; + }; + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp index b24de64b42..37a9bab378 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp @@ -6,33 +6,17 @@ * */ -#include -#include -#include #include -#include #include #include #include #include #include #include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include #include @@ -51,8 +35,7 @@ namespace AZ { CommonPreviewRenderer::CommonPreviewRenderer() { - // CommonPreviewRenderer supports both models and materials, but we connect on materialAssetType - // since MaterialOrModelThumbnail dispatches event on materialAssetType address too + // CommonPreviewRenderer supports both models and materials AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); @@ -72,7 +55,7 @@ namespace AZ // Bind m_frameworkScene to the entity context's AzFramework::Scene auto sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation."); + AZ_Assert(sceneSystem, "Failed to get scene system implementation."); Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(m_sceneName); AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); @@ -104,23 +87,9 @@ namespace AZ m_view->SetViewToClipMatrix(viewToClipMatrix); m_renderPipeline->SetDefaultView(m_view); - // Create preview model - AzFramework::EntityContextRequestBus::EventResult( - m_modelEntity, m_entityContext->GetContextId(), &AzFramework::EntityContextRequestBus::Events::CreateEntity, - "ThumbnailPreviewModel"); - m_modelEntity->CreateComponent(Render::MeshComponentTypeId); - m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); - m_modelEntity->CreateComponent(azrtti_typeid()); - m_modelEntity->Init(); - m_modelEntity->Activate(); - - m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); - m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); - m_defaultModelAsset.Create(DefaultModelAssetId, true); - - m_steps[CommonPreviewRenderer::State::IdleState] = AZStd::make_shared(this); - m_steps[CommonPreviewRenderer::State::LoadState] = AZStd::make_shared(this); - m_steps[CommonPreviewRenderer::State::CaptureState] = AZStd::make_shared(this); + m_states[CommonPreviewRenderer::State::IdleState] = AZStd::make_shared(this); + m_states[CommonPreviewRenderer::State::LoadState] = AZStd::make_shared(this); + m_states[CommonPreviewRenderer::State::CaptureState] = AZStd::make_shared(this); SetState(CommonPreviewRenderer::State::IdleState); } @@ -131,13 +100,8 @@ namespace AZ PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); SetState(CommonPreviewRenderer::State::None); - - if (m_modelEntity) - { - AzFramework::EntityContextRequestBus::Event( - m_entityContext->GetContextId(), &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); - m_modelEntity = nullptr; - } + m_currentCaptureRequest = {}; + m_captureRequestQueue = {}; m_scene->Deactivate(); m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); @@ -146,18 +110,23 @@ namespace AZ m_frameworkScene->UnsetSubsystem(m_entityContext.get()); } + void CommonPreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) + { + m_captureRequestQueue.push(captureRequest); + } + void CommonPreviewRenderer::SetState(State state) { - auto stepItr = m_steps.find(m_currentState); - if (stepItr != m_steps.end()) + auto stepItr = m_states.find(m_currentState); + if (stepItr != m_states.end()) { stepItr->second->Stop(); } m_currentState = state; - stepItr = m_steps.find(m_currentState); - if (stepItr != m_steps.end()) + stepItr = m_states.find(m_currentState); + if (stepItr != m_states.end()) { stepItr->second->Start(); } @@ -168,54 +137,43 @@ namespace AZ return m_currentState; } - void CommonPreviewRenderer::SelectThumbnail() + void CommonPreviewRenderer::SelectCaptureRequest() { - if (!m_thumbnailInfoQueue.empty()) + if (!m_captureRequestQueue.empty()) { - // pop the next thumbnailkey to be rendered from the queue - m_currentThubnailInfo = m_thumbnailInfoQueue.front(); - m_thumbnailInfoQueue.pop(); + // pop the next request to be rendered from the queue + m_currentCaptureRequest = m_captureRequestQueue.front(); + m_captureRequestQueue.pop(); SetState(CommonPreviewRenderer::State::LoadState); } } - void CommonPreviewRenderer::CancelThumbnail() + void CommonPreviewRenderer::CancelCaptureRequest() { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_currentThubnailInfo.m_key, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + m_currentCaptureRequest.m_captureFailedCallback(); SetState(CommonPreviewRenderer::State::IdleState); } - void CommonPreviewRenderer::CompleteThumbnail() + void CommonPreviewRenderer::CompleteCaptureRequest() { SetState(CommonPreviewRenderer::State::IdleState); } void CommonPreviewRenderer::LoadAssets() { - // Determine if thumbnailkey contains a material asset or set a default material - const Data::AssetId materialAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::MaterialAsset::RTTI_Type()); - m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, true); - - // Determine if thumbnailkey contains a model asset or set a default model - const Data::AssetId modelAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::ModelAsset::RTTI_Type()); - m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, true); - - // Determine if thumbnailkey contains a lighting preset asset or set a default lighting preset - const Data::AssetId lightingPresetAssetId = GetAssetId(m_currentThubnailInfo.m_key, RPI::AnyAsset::RTTI_Type()); - m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, true); + m_currentCaptureRequest.m_content->Load(); } void CommonPreviewRenderer::UpdateLoadAssets() { - if (m_materialAsset.IsReady() && m_modelAsset.IsReady() && m_lightingPresetAsset.IsReady()) + if (m_currentCaptureRequest.m_content->IsReady()) { SetState(CommonPreviewRenderer::State::CaptureState); return; } - if (m_materialAsset.IsError() || m_modelAsset.IsError() || m_lightingPresetAsset.IsError()) + if (m_currentCaptureRequest.m_content->IsError()) { CancelLoadAssets(); return; @@ -224,107 +182,35 @@ namespace AZ void CommonPreviewRenderer::CancelLoadAssets() { - AZ_Warning( - "CommonPreviewRenderer", m_materialAsset.IsReady(), "Asset failed to load in time: %s", - m_materialAsset.ToString().c_str()); - AZ_Warning( - "CommonPreviewRenderer", m_modelAsset.IsReady(), "Asset failed to load in time: %s", - m_modelAsset.ToString().c_str()); - AZ_Warning( - "CommonPreviewRenderer", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", - m_lightingPresetAsset.ToString().c_str()); - CancelThumbnail(); + m_currentCaptureRequest.m_content->ReportErrors(); + CancelCaptureRequest(); } void CommonPreviewRenderer::UpdateScene() { - UpdateModel(); - UpdateLighting(); - UpdateCamera(); - } - - void CommonPreviewRenderer::UpdateModel() - { - Render::MaterialComponentRequestBus::Event( - m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, - m_materialAsset.GetId()); - - Render::MeshComponentRequestBus::Event( - m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); - } - - void CommonPreviewRenderer::UpdateLighting() - { - auto preset = m_lightingPresetAsset->GetDataAs(); - if (preset) - { - auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); - auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); - auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); - auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); - auto directionalLightFeatureProcessor = - m_scene->GetFeatureProcessor(); - auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); - skyboxFeatureProcessor->Enable(true); - skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); - - Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = FieldOfView; - cameraConfig.m_nearClipDistance = NearDist; - cameraConfig.m_farClipDistance = FarDist; - cameraConfig.m_frustumWidth = 100.0f; - cameraConfig.m_frustumHeight = 100.0f; - - AZStd::vector lightHandles; - - preset->ApplyLightingPreset( - iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, - cameraConfig, lightHandles); - } - } - - void CommonPreviewRenderer::UpdateCamera() - { - // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it - Vector3 center = {}; - float radius = {}; - m_modelAsset->GetAabb().GetAsSphere(center, radius); - - const auto distance = radius + NearDist; - const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); - const auto cameraPosition = center - cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); - const auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); - m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); + m_currentCaptureRequest.m_content->UpdateScene(); } - RPI::AttachmentReadback::CallbackFunction CommonPreviewRenderer::GetCaptureCallback() + bool CommonPreviewRenderer::StartCapture() { - return [this](const RPI::AttachmentReadback::ReadbackResult& result) + auto captureCallback = + [currentCaptureRequest = m_currentCaptureRequest](const RPI::AttachmentReadback::ReadbackResult& result) { if (result.m_dataBuffer) { - QImage image( + currentCaptureRequest.m_captureCompleteCallback(QImage( result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, - result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888); - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_currentThubnailInfo.m_key, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, QPixmap::fromImage(image)); + result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888)); } else { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_currentThubnailInfo.m_key, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + currentCaptureRequest.m_captureFailedCallback(); } }; - } - bool CommonPreviewRenderer::StartCapture() - { if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) { - renderToTexturePass->ResizeOutput(m_currentThubnailInfo.m_size, m_currentThubnailInfo.m_size); + renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size); } m_renderPipeline->AddToRenderTickOnce(); @@ -332,7 +218,7 @@ namespace AZ bool startedCapture = false; Render::FrameCaptureRequestBus::BroadcastResult( startedCapture, &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, - AZStd::string("Output"), GetCaptureCallback(), RPI::PassAttachmentReadbackOption::Output); + AZStd::string("Output"), captureCallback, RPI::PassAttachmentReadbackOption::Output); return startedCapture; } @@ -341,11 +227,6 @@ namespace AZ m_renderPipeline->RemoveFromRenderTick(); } - bool CommonPreviewRenderer::Installed() const - { - return true; - } - void CommonPreviewRenderer::OnSystemTick() { AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); @@ -372,10 +253,32 @@ namespace AZ "AZ::Render::PostProcessFeatureProcessor", "AZ::Render::SkyBoxFeatureProcessor" }); } - + void CommonPreviewRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) { - m_thumbnailInfoQueue.push({ thumbnailKey, thumbnailSize }); + AddCaptureRequest( + { thumbnailSize, + AZStd::make_shared( + m_scene, m_view, m_entityContext->GetContextId(), + GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type()), + GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type()), + GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type())), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QImage& image) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, + QPixmap::fromImage(image)); + } }); + } + + bool CommonPreviewRenderer::Installed() const + { + return true; } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h index 259063cfdf..124a6987cc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h @@ -10,13 +10,11 @@ #include #include -#include -#include -#include #include #include #include #include +#include #include namespace AzFramework @@ -46,11 +44,21 @@ namespace AZ , public PreviewerFeatureProcessorProviderBus::Handler { public: - AZ_CLASS_ALLOCATOR(CommonPreviewRenderer, AZ::SystemAllocator, 0) + AZ_CLASS_ALLOCATOR(CommonPreviewRenderer, AZ::SystemAllocator, 0); CommonPreviewRenderer(); ~CommonPreviewRenderer(); + struct CaptureRequest + { + int m_size = 512; + AZStd::shared_ptr m_content; + AZStd::function m_captureFailedCallback; + AZStd::function m_captureCompleteCallback; + }; + + void AddCaptureRequest(const CaptureRequest& captureRequest); + enum class State : AZ::s8 { None, @@ -62,39 +70,34 @@ namespace AZ void SetState(State state); State GetState() const; - void SelectThumbnail(); - void CancelThumbnail(); - void CompleteThumbnail(); + void SelectCaptureRequest(); + void CancelCaptureRequest(); + void CompleteCaptureRequest(); void LoadAssets(); void UpdateLoadAssets(); void CancelLoadAssets(); void UpdateScene(); - void UpdateModel(); - void UpdateLighting(); - void UpdateCamera(); - RPI::AttachmentReadback::CallbackFunction GetCaptureCallback(); bool StartCapture(); void EndCapture(); private: - //! ThumbnailerRendererRequestsBus::Handler interface overrides... - void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; - bool Installed() const override; - //! SystemTickBus::Handler interface overrides... void OnSystemTick() override; //! Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + //! ThumbnailerRendererRequestsBus::Handler interface overrides... + void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; + bool Installed() const override; + static constexpr float AspectRatio = 1.0f; static constexpr float NearDist = 0.001f; static constexpr float FarDist = 100.0f; static constexpr float FieldOfView = Constants::HalfPi; - static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; RPI::ScenePtr m_scene; AZStd::string m_sceneName = "Material Thumbnail Scene"; @@ -105,36 +108,12 @@ namespace AZ AZStd::vector m_passHierarchy; AZStd::unique_ptr m_entityContext; - //! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function. - struct ThumbnailInfo - { - AzToolsFramework::Thumbnailer::SharedThumbnailKey m_key; - int m_size = 512; - }; - AZStd::queue m_thumbnailInfoQueue; - ThumbnailInfo m_currentThubnailInfo; + //! Incoming requests are appended to this queue and processed one at a time in OnTick function. + AZStd::queue m_captureRequestQueue; + CaptureRequest m_currentCaptureRequest; - AZStd::unordered_map> m_steps; + AZStd::unordered_map> m_states; State m_currentState = CommonPreviewRenderer::State::None; - - static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); - Data::Asset m_defaultLightingPresetAsset; - Data::Asset m_lightingPresetAsset; - - //! Model asset about to be rendered - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); - Data::Asset m_defaultModelAsset; - Data::Asset m_modelAsset; - - //! Material asset about to be rendered - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); - Data::Asset m_defaultMaterialAsset; - Data::Asset m_materialAsset; - - Entity* m_modelEntity = nullptr; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp index e77b9709ac..fc74e9f43b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp @@ -50,7 +50,7 @@ namespace AZ void CommonPreviewRendererCaptureState::OnCaptureFinished( [[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) { - m_renderer->CompleteThumbnail(); + m_renderer->CompleteCaptureRequest(); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp index b272faef30..12a38fc93f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp @@ -32,7 +32,7 @@ namespace AZ void CommonPreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { - m_renderer->SelectThumbnail(); + m_renderer->SelectCaptureRequest(); } } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index e96f199f5e..f135bc1132 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -102,6 +102,8 @@ set(FILES Source/Thumbnails/Preview/CommonPreviewer.ui Source/Thumbnails/Preview/CommonPreviewerFactory.cpp Source/Thumbnails/Preview/CommonPreviewerFactory.h + Source/Thumbnails/Rendering/CommonPreviewContent.cpp + Source/Thumbnails/Rendering/CommonPreviewContent.h Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp Source/Thumbnails/Rendering/CommonPreviewRenderer.h Source/Thumbnails/Rendering/CommonPreviewRendererState.h From ab5547fdf7f694f2783647846f1b3fe2265fe569 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 8 Oct 2021 02:46:00 -0500 Subject: [PATCH 136/293] =?UTF-8?q?=E2=80=A2=20Created=20interface=20for?= =?UTF-8?q?=20preview=20rendering=20content=20=E2=80=A2=20moved=20all=20th?= =?UTF-8?q?umbnail=20classes=20and=20registration=20back=20to=20the=20comm?= =?UTF-8?q?on=20feature=20editor=20component=20=E2=80=A2=20added=20lightin?= =?UTF-8?q?g=20preset=20thumbnail=20as=20a=20quick=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../EditorCommonFeaturesSystemComponent.cpp | 58 ++++++++- .../EditorCommonFeaturesSystemComponent.h | 13 +- .../EditorMaterialSystemComponent.cpp | 36 ------ .../Material/EditorMaterialSystemComponent.h | 10 -- .../Source/Mesh/EditorMeshSystemComponent.cpp | 41 +------ .../Source/Mesh/EditorMeshSystemComponent.h | 10 -- ....cpp => CommonThumbnailPreviewContent.cpp} | 38 +++--- .../CommonThumbnailPreviewContent.h | 82 +++++++++++++ .../Thumbnails/CommonThumbnailRenderer.cpp | 71 +++++++++++ .../Thumbnails/CommonThumbnailRenderer.h | 46 +++++++ .../Thumbnails/LightingPresetThumbnail.cpp | 115 ++++++++++++++++++ .../LightingPresetThumbnail.h} | 23 ++-- .../MaterialThumbnail.cpp | 22 ++-- .../MaterialThumbnail.h | 12 +- .../ModelThumbnail.cpp} | 51 ++++---- .../Code/Source/Thumbnails/ModelThumbnail.h | 67 ++++++++++ .../Preview/CommonPreviewerFactory.cpp | 29 ++++- .../Rendering/CommonPreviewContent.h | 62 ++-------- .../Rendering/CommonPreviewRenderer.cpp | 56 +++------ .../Rendering/CommonPreviewRenderer.h | 32 ++--- ...egration_commonfeatures_editor_files.cmake | 15 ++- 21 files changed, 576 insertions(+), 313 deletions(-) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/{Rendering/CommonPreviewContent.cpp => CommonThumbnailPreviewContent.cpp} (81%) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.cpp rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Mesh/MeshThumbnail.h => Thumbnails/LightingPresetThumbnail.h} (72%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Material => Thumbnails}/MaterialThumbnail.cpp (80%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Material => Thumbnails}/MaterialThumbnail.h (83%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Mesh/MeshThumbnail.cpp => Thumbnails/ModelThumbnail.cpp} (59%) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 0355351654..c04702ff90 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -9,12 +9,18 @@ #include #include -#include #include #include +#include +#include #include #include #include +#include + +#include +#include +#include #include @@ -68,7 +74,7 @@ namespace AZ void EditorCommonFeaturesSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - AZ_UNUSED(required); + required.push_back(AZ_CRC_CE("ThumbnailerService")); } void EditorCommonFeaturesSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) @@ -98,8 +104,7 @@ namespace AZ AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect(); m_skinnedMeshDebugDisplay.reset(); - m_previewerFactory.reset(); - m_renderer.reset(); + TeardownThumbnails(); } void EditorCommonFeaturesSystemComponent::OnNewLevelCreated() @@ -194,8 +199,7 @@ namespace AZ void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) { AZ::TickBus::QueueFunction([this](){ - m_renderer = AZStd::make_unique(); - m_previewerFactory = AZStd::make_unique(); + SetupThumbnails(); }); } @@ -207,7 +211,49 @@ namespace AZ void EditorCommonFeaturesSystemComponent::OnApplicationAboutToStop() { + TeardownThumbnails(); + } + + void EditorCommonFeaturesSystemComponent::SetupThumbnails() + { + using namespace AzToolsFramework::Thumbnailer; + using namespace LyIntegration; + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache), + ThumbnailContext::DefaultContext); + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::ModelThumbnailCache), + ThumbnailContext::DefaultContext); + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::LightingPresetThumbnailCache), + ThumbnailContext::DefaultContext); + + m_renderer = AZStd::make_unique(); + m_previewerFactory = AZStd::make_unique(); + } + + void EditorCommonFeaturesSystemComponent::TeardownThumbnails() + { + using namespace AzToolsFramework::Thumbnailer; + using namespace LyIntegration; + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName, + ThumbnailContext::DefaultContext); + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::ModelThumbnailCache::ProviderName, + ThumbnailContext::DefaultContext); + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::LightingPresetThumbnailCache::ProviderName, + ThumbnailContext::DefaultContext); + m_renderer.reset(); + m_previewerFactory.reset(); } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index 90dc5fcf2e..ed6b3eb426 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include namespace AZ { @@ -54,18 +54,23 @@ namespace AZ void OnNewLevelCreated() override; // SliceEditorEntityOwnershipServiceBus overrides ... - void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; + void OnSliceInstantiated( + const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override; // AzFramework::AssetCatalogEventBus::Handler overrides ... void OnCatalogLoaded(const char* catalogFile) override; // AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler overrides... - const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; + const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory( + const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; // AzFramework::ApplicationLifecycleEvents overrides... void OnApplicationAboutToStop() override; + void SetupThumbnails(); + void TeardownThumbnails(); + private: AZStd::unique_ptr m_skinnedMeshDebugDisplay; @@ -73,7 +78,7 @@ namespace AZ AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" }; float m_envProbeHeight{ 200.0f }; - AZStd::unique_ptr m_renderer; + AZStd::unique_ptr m_renderer; AZStd::unique_ptr m_previewerFactory; }; } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index a6b595940f..9efa8eb333 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -16,11 +16,9 @@ #include #include #include -#include #include #include #include -#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class @@ -72,11 +70,6 @@ namespace AZ incompatible.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e)); } - void EditorMaterialSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.push_back(AZ_CRC("ThumbnailerService", 0x65422b97)); - } - void EditorMaterialSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { AZ_UNUSED(dependent); @@ -90,24 +83,20 @@ namespace AZ void EditorMaterialSystemComponent::Activate() { EditorMaterialSystemComponentRequestBus::Handler::BusConnect(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); - SetupThumbnails(); m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); } void EditorMaterialSystemComponent::Deactivate() { EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); - TeardownThumbnails(); m_materialBrowserInteractions.reset(); if (m_openMaterialEditorAction) @@ -154,11 +143,6 @@ namespace AZ } } - void EditorMaterialSystemComponent::OnApplicationAboutToStop() - { - TeardownThumbnails(); - } - void EditorMaterialSystemComponent::OnPopulateToolMenuItems() { if (!m_openMaterialEditorAction) @@ -201,26 +185,6 @@ namespace AZ "Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions); } - void EditorMaterialSystemComponent::SetupThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache), - ThumbnailContext::DefaultContext); - } - - void EditorMaterialSystemComponent::TeardownThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); - } - AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails( const char* fullSourceFileName) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h index 7fa43ea309..60e489f55e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h @@ -8,10 +8,8 @@ #pragma once #include -#include #include #include -#include #include #include @@ -26,7 +24,6 @@ namespace AZ class EditorMaterialSystemComponent : public AZ::Component , private EditorMaterialSystemComponentRequestBus::Handler - , private AzFramework::ApplicationLifecycleEvents::Bus::Handler , private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler , private AzToolsFramework::EditorMenuNotificationBus::Handler , private AzToolsFramework::EditorEvents::Bus::Handler @@ -38,7 +35,6 @@ namespace AZ static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); - static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); protected: @@ -52,9 +48,6 @@ namespace AZ void OpenMaterialEditor(const AZStd::string& sourcePath) override; void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; - // AzFramework::ApplicationLifecycleEvents overrides... - void OnApplicationAboutToStop() override; - //! AssetBrowserInteractionNotificationBus::Handler overrides... AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override; @@ -65,9 +58,6 @@ namespace AZ // AztoolsFramework::EditorEvents::Bus::Handler overrides... void NotifyRegisterViews() override; - void SetupThumbnails(); - void TeardownThumbnails(); - QAction* m_openMaterialEditorAction = nullptr; AZStd::unique_ptr m_materialBrowserInteractions; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp index 8b2f6c8a11..c6a7ff1f50 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp @@ -6,13 +6,10 @@ * */ -#include #include #include -#include -#include -#include -#include +#include +#include namespace AZ { @@ -47,11 +44,6 @@ namespace AZ incompatible.push_back(AZ_CRC_CE("EditorMeshSystem")); } - void EditorMeshSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.push_back(AZ_CRC_CE("ThumbnailerService")); - } - void EditorMeshSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { AZ_UNUSED(dependent); @@ -59,39 +51,10 @@ namespace AZ void EditorMeshSystemComponent::Activate() { - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); - SetupThumbnails(); } void EditorMeshSystemComponent::Deactivate() { - TeardownThumbnails(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); - } - - void EditorMeshSystemComponent::OnApplicationAboutToStop() - { - TeardownThumbnails(); - } - - void EditorMeshSystemComponent::SetupThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, - MAKE_TCACHE(Thumbnails::MeshThumbnailCache), - ThumbnailContext::DefaultContext); - } - - void EditorMeshSystemComponent::TeardownThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::UnregisterThumbnailProvider, - Thumbnails::MeshThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h index 64d72bc33d..a784785830 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h @@ -8,7 +8,6 @@ #pragma once #include -#include namespace AZ { @@ -17,7 +16,6 @@ namespace AZ //! System component that sets up necessary logic related to EditorMeshComponent. class EditorMeshSystemComponent : public AZ::Component - , private AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: AZ_COMPONENT(EditorMeshSystemComponent, "{4D332E3D-C4FC-410B-A915-8E234CBDD4EC}"); @@ -26,20 +24,12 @@ namespace AZ static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); - static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); protected: // AZ::Component interface overrides... void Activate() override; void Deactivate() override; - - private: - // AzFramework::ApplicationLifecycleEvents overrides... - void OnApplicationAboutToStop() override; - - void SetupThumbnails(); - void TeardownThumbnails(); }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.cpp similarity index 81% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.cpp index 12caac1e90..f8c508a493 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace AZ { @@ -31,7 +31,7 @@ namespace AZ { namespace Thumbnails { - CommonPreviewContent::CommonPreviewContent( + CommonThumbnailPreviewContent::CommonThumbnailPreviewContent( RPI::ScenePtr scene, RPI::ViewPtr view, AZ::Uuid entityContextId, @@ -65,7 +65,7 @@ namespace AZ m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, false); } - CommonPreviewContent::~CommonPreviewContent() + CommonThumbnailPreviewContent::~CommonThumbnailPreviewContent() { if (m_modelEntity) { @@ -75,44 +75,46 @@ namespace AZ } } - void CommonPreviewContent::Load() + void CommonThumbnailPreviewContent::Load() { m_modelAsset.QueueLoad(); m_materialAsset.QueueLoad(); m_lightingPresetAsset.QueueLoad(); } - bool CommonPreviewContent::IsReady() const + bool CommonThumbnailPreviewContent::IsReady() const { - return m_modelAsset.IsReady() && m_materialAsset.IsReady() && m_lightingPresetAsset.IsReady(); + return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) && + (!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) && + (!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady()); } - bool CommonPreviewContent::IsError() const + bool CommonThumbnailPreviewContent::IsError() const { return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); } - void CommonPreviewContent::ReportErrors() + void CommonThumbnailPreviewContent::ReportErrors() { AZ_Warning( - "CommonPreviewContent", m_modelAsset.IsReady(), "Asset failed to load in time: %s", - m_modelAsset.ToString().c_str()); + "CommonThumbnailPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), + "Asset failed to load in time: %s", m_modelAsset.ToString().c_str()); AZ_Warning( - "CommonPreviewContent", m_materialAsset.IsReady(), "Asset failed to load in time: %s", - m_materialAsset.ToString().c_str()); + "CommonThumbnailPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), + "Asset failed to load in time: %s", m_materialAsset.ToString().c_str()); AZ_Warning( - "CommonPreviewContent", m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", - m_lightingPresetAsset.ToString().c_str()); + "CommonThumbnailPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(), + "Asset failed to load in time: %s", m_lightingPresetAsset.ToString().c_str()); } - void CommonPreviewContent::UpdateScene() + void CommonThumbnailPreviewContent::UpdateScene() { UpdateModel(); UpdateLighting(); UpdateCamera(); } - void CommonPreviewContent::UpdateModel() + void CommonThumbnailPreviewContent::UpdateModel() { Render::MeshComponentRequestBus::Event( m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); @@ -122,7 +124,7 @@ namespace AZ m_materialAsset.GetId()); } - void CommonPreviewContent::UpdateLighting() + void CommonThumbnailPreviewContent::UpdateLighting() { auto preset = m_lightingPresetAsset->GetDataAs(); if (preset) @@ -152,7 +154,7 @@ namespace AZ } } - void CommonPreviewContent::UpdateCamera() + void CommonThumbnailPreviewContent::UpdateCamera() { // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it Vector3 center = {}; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h new file mode 100644 index 0000000000..59556e03d1 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + //! Provides custom rendering of material and model previews + class CommonThumbnailPreviewContent final + : public CommonPreviewContent + { + public: + AZ_CLASS_ALLOCATOR(CommonThumbnailPreviewContent, AZ::SystemAllocator, 0); + + CommonThumbnailPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId); + + ~CommonThumbnailPreviewContent() override; + + void Load() override; + bool IsReady() const override; + bool IsError() const override; + void ReportErrors() override; + void UpdateScene() override; + + private: + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = Constants::HalfPi; + static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; + + RPI::ScenePtr m_scene; + RPI::ViewPtr m_view; + AZ::Uuid m_entityContextId; + Entity* m_modelEntity = nullptr; + + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + Data::Asset m_lightingPresetAsset; + + //! Model asset about to be rendered + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + Data::Asset m_modelAsset; + + //! Material asset about to be rendered + static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; + const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); + Data::Asset m_defaultMaterialAsset; + Data::Asset m_materialAsset; + }; + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.cpp new file mode 100644 index 0000000000..63b36b9e14 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + CommonThumbnailRenderer::CommonThumbnailRenderer() + { + // CommonThumbnailRenderer supports both models and materials + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::AnyAsset::RTTI_Type()); + SystemTickBus::Handler::BusConnect(); + } + + CommonThumbnailRenderer::~CommonThumbnailRenderer() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); + SystemTickBus::Handler::BusDisconnect(); + } + + void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) + { + m_previewRenderer.AddCaptureRequest( + { thumbnailSize, + AZStd::make_shared( + m_previewRenderer.GetScene(), + m_previewRenderer.GetView(), + m_previewRenderer.GetEntityContextId(), + GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type()), + GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type()), + GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type())), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QImage& image) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, + QPixmap::fromImage(image)); + } }); + } + + bool CommonThumbnailRenderer::Installed() const + { + return true; + } + + void CommonThumbnailRenderer::OnSystemTick() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); + } + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h new file mode 100644 index 0000000000..fb683c1aff --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h @@ -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 + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + //! Provides custom rendering of material and model thumbnails + class CommonThumbnailRenderer + : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler + , public SystemTickBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0); + + CommonThumbnailRenderer(); + ~CommonThumbnailRenderer(); + + private: + //! ThumbnailerRendererRequestsBus::Handler interface overrides... + void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; + bool Installed() const override; + + //! SystemTickBus::Handler interface overrides... + void OnSystemTick() override; + + CommonPreviewRenderer m_previewRenderer; + }; + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.cpp new file mode 100644 index 0000000000..8fe4b1998d --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + static constexpr const int LightingPresetThumbnailSize = 512; // 512 is the default size in render to texture pass + + ////////////////////////////////////////////////////////////////////////// + // LightingPresetThumbnail + ////////////////////////////////////////////////////////////////////////// + LightingPresetThumbnail::LightingPresetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + : Thumbnail(key) + { + m_assetId = GetAssetId(key, RPI::AnyAsset::RTTI_Type()); + if (!m_assetId.IsValid()) + { + AZ_Error("LightingPresetThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); + m_state = State::Failed; + return; + } + + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + } + + void LightingPresetThumbnail::LoadThread() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( + RPI::AnyAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, + LightingPresetThumbnailSize); + // wait for response from thumbnail renderer + m_renderWait.acquire(); + } + + LightingPresetThumbnail::~LightingPresetThumbnail() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + } + + void LightingPresetThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + { + m_pixmap = thumbnailImage; + m_renderWait.release(); + } + + void LightingPresetThumbnail::ThumbnailFailedToRender() + { + m_state = State::Failed; + m_renderWait.release(); + } + + void LightingPresetThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) + { + if (m_assetId == assetId && m_state == State::Ready) + { + m_state = State::Unloaded; + Load(); + } + } + + ////////////////////////////////////////////////////////////////////////// + // LightingPresetThumbnailCache + ////////////////////////////////////////////////////////////////////////// + LightingPresetThumbnailCache::LightingPresetThumbnailCache() + : ThumbnailCache() + { + } + + LightingPresetThumbnailCache::~LightingPresetThumbnailCache() = default; + + int LightingPresetThumbnailCache::GetPriority() const + { + // Thumbnails override default source thumbnails, so carry higher priority + return 1; + } + + const char* LightingPresetThumbnailCache::GetProviderName() const + { + return ProviderName; + } + + bool LightingPresetThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const + { + const auto assetId = Thumbnails::GetAssetId(key, RPI::AnyAsset::RTTI_Type()); + if (assetId.IsValid()) + { + AZ::Data::AssetInfo assetInfo; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId); + return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset"); + } + + return false; + } + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ + +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.h similarity index 72% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.h index 2975b6950c..efbfe5b7d5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.h @@ -21,18 +21,16 @@ namespace AZ { namespace Thumbnails { - /** - * Custom material or model thumbnail that detects when an asset changes and updates the thumbnail - */ - class MeshThumbnail + //! Custom thumbnail that detects when an asset changes and updates the thumbnail + class LightingPresetThumbnail : public AzToolsFramework::Thumbnailer::Thumbnail , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler , private AzFramework::AssetCatalogEventBus::Handler { Q_OBJECT public: - MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~MeshThumbnail() override; + LightingPresetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + ~LightingPresetThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... void ThumbnailRendered(QPixmap& thumbnailImage) override; @@ -49,20 +47,17 @@ namespace AZ Data::AssetId m_assetId; }; - /** - * Cache configuration for large material thumbnails - */ - class MeshThumbnailCache - : public AzToolsFramework::Thumbnailer::ThumbnailCache + //! Cache configuration for large thumbnails + class LightingPresetThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache { public: - MeshThumbnailCache(); - ~MeshThumbnailCache() override; + LightingPresetThumbnailCache(); + ~LightingPresetThumbnailCache() override; int GetPriority() const override; const char* GetProviderName() const override; - static constexpr const char* ProviderName = "Mesh Thumbnails"; + static constexpr const char* ProviderName = "LightingPreset Thumbnails"; protected: bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.cpp similarity index 80% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.cpp index 0723859ff5..69bcffde06 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.cpp @@ -6,10 +6,11 @@ * */ +#include #include #include -#include -#include +#include +#include namespace AZ { @@ -40,9 +41,7 @@ namespace AZ void MaterialThumbnail::LoadThread() { AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::MaterialAsset::RTTI_Type(), - &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, - m_key, + RPI::MaterialAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, MaterialThumbnailSize); // wait for response from thumbnail renderer m_renderWait.acquire(); @@ -68,8 +67,7 @@ namespace AZ void MaterialThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) { - if (m_assetId == assetId && - m_state == State::Ready) + if (m_assetId == assetId && m_state == State::Ready) { m_state = State::Unloaded; Load(); @@ -88,7 +86,7 @@ namespace AZ int MaterialThumbnailCache::GetPriority() const { - // Material thumbnails override default source thumbnails, so carry higher priority + // Thumbnails override default source thumbnails, so carry higher priority return 1; } @@ -99,14 +97,10 @@ namespace AZ bool MaterialThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const { - return - GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid() && - // in case it's a source scene file, it will contain both material and model products - // model thumbnails are handled by MeshThumbnail - !GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid(); + return GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid(); } } // namespace Thumbnails } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.h similarity index 83% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.h index d323a04a1f..9a580d07ce 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.h @@ -13,7 +13,6 @@ #include #include #include -#include #endif namespace AZ @@ -22,9 +21,7 @@ namespace AZ { namespace Thumbnails { - /** - * Custom material or model thumbnail that detects when an asset changes and updates the thumbnail - */ + //! Custom thumbnail that detects when an asset changes and updates the thumbnail class MaterialThumbnail : public AzToolsFramework::Thumbnailer::Thumbnail , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler @@ -50,11 +47,8 @@ namespace AZ Data::AssetId m_assetId; }; - /** - * Cache configuration for large material thumbnails - */ - class MaterialThumbnailCache - : public AzToolsFramework::Thumbnailer::ThumbnailCache + //! Cache configuration for large thumbnails + class MaterialThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache { public: MaterialThumbnailCache(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.cpp similarity index 59% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.cpp index 658d420a16..bc47ec04b8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.cpp @@ -6,11 +6,11 @@ * */ -#include #include +#include #include -#include -#include +#include +#include namespace AZ { @@ -18,18 +18,18 @@ namespace AZ { namespace Thumbnails { - static constexpr const int MeshThumbnailSize = 512; // 512 is the default size in render to texture pass + static constexpr const int ModelThumbnailSize = 512; // 512 is the default size in render to texture pass ////////////////////////////////////////////////////////////////////////// - // MeshThumbnail + // ModelThumbnail ////////////////////////////////////////////////////////////////////////// - MeshThumbnail::MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + ModelThumbnail::ModelThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) : Thumbnail(key) { m_assetId = GetAssetId(key, RPI::ModelAsset::RTTI_Type()); if (!m_assetId.IsValid()) { - AZ_Error("MeshThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); + AZ_Error("ModelThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); m_state = State::Failed; return; } @@ -38,39 +38,36 @@ namespace AZ AzFramework::AssetCatalogEventBus::Handler::BusConnect(); } - void MeshThumbnail::LoadThread() + void ModelThumbnail::LoadThread() { AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::ModelAsset::RTTI_Type(), - &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, - m_key, - MeshThumbnailSize); + RPI::ModelAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, + ModelThumbnailSize); // wait for response from thumbnail renderer m_renderWait.acquire(); } - MeshThumbnail::~MeshThumbnail() + ModelThumbnail::~ModelThumbnail() { AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } - void MeshThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void ModelThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); } - void MeshThumbnail::ThumbnailFailedToRender() + void ModelThumbnail::ThumbnailFailedToRender() { m_state = State::Failed; m_renderWait.release(); } - void MeshThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) + void ModelThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) { - if (m_assetId == assetId && - m_state == State::Ready) + if (m_assetId == assetId && m_state == State::Ready) { m_state = State::Unloaded; Load(); @@ -78,27 +75,27 @@ namespace AZ } ////////////////////////////////////////////////////////////////////////// - // MeshThumbnailCache + // ModelThumbnailCache ////////////////////////////////////////////////////////////////////////// - MeshThumbnailCache::MeshThumbnailCache() - : ThumbnailCache() + ModelThumbnailCache::ModelThumbnailCache() + : ThumbnailCache() { } - MeshThumbnailCache::~MeshThumbnailCache() = default; + ModelThumbnailCache::~ModelThumbnailCache() = default; - int MeshThumbnailCache::GetPriority() const + int ModelThumbnailCache::GetPriority() const { - // Material thumbnails override default source thumbnails, so carry higher priority + // Thumbnails override default source thumbnails, so carry higher priority return 1; } - const char* MeshThumbnailCache::GetProviderName() const + const char* ModelThumbnailCache::GetProviderName() const { return ProviderName; } - bool MeshThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const + bool ModelThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const { return GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid(); } @@ -106,4 +103,4 @@ namespace AZ } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.h new file mode 100644 index 0000000000..2925abe36e --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#endif + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + //! Custom thumbnail that detects when an asset changes and updates the thumbnail + class ModelThumbnail + : public AzToolsFramework::Thumbnailer::Thumbnail + , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler + , private AzFramework::AssetCatalogEventBus::Handler + { + Q_OBJECT + public: + ModelThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + ~ModelThumbnail() override; + + //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... + void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailFailedToRender() override; + + protected: + void LoadThread() override; + + private: + // AzFramework::AssetCatalogEventBus::Handler interface overrides... + void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; + + AZStd::binary_semaphore m_renderWait; + Data::AssetId m_assetId; + }; + + //! Cache configuration for large thumbnails + class ModelThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache + { + public: + ModelThumbnailCache(); + ~ModelThumbnailCache() override; + + int GetPriority() const override; + const char* GetProviderName() const override; + + static constexpr const char* ProviderName = "Model Thumbnails"; + + protected: + bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; + }; + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp index 856d38d6cb..5b7ef4bfa6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp @@ -6,9 +6,11 @@ * */ -#include +#include #include #include +#include +#include #include #include #include @@ -24,9 +26,28 @@ namespace AZ bool CommonPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const { - return - Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::MaterialAsset::RTTI_Type()).IsValid() || - Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::ModelAsset::RTTI_Type()).IsValid(); + AZ::Data::AssetId assetId = Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::ModelAsset::RTTI_Type()); + if (assetId.IsValid()) + { + return true; + } + + assetId = Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::MaterialAsset::RTTI_Type()); + if (assetId.IsValid()) + { + return true; + } + + assetId = Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::AnyAsset::RTTI_Type()); + if (assetId.IsValid()) + { + AZ::Data::AssetInfo assetInfo; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId); + return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset"); + } + + return false; } const QString& CommonPreviewerFactory::GetName() const diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h index 6c8f0c5565..891c7f2d01 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h @@ -8,11 +8,7 @@ #pragma once -#include -#include -#include -#include -#include +#include namespace AZ { @@ -20,59 +16,19 @@ namespace AZ { namespace Thumbnails { - //! Provides custom rendering of material and model thumbnails + //! Provides custom rendering of preeview images class CommonPreviewContent { public: AZ_CLASS_ALLOCATOR(CommonPreviewContent, AZ::SystemAllocator, 0); - CommonPreviewContent( - RPI::ScenePtr scene, - RPI::ViewPtr view, - AZ::Uuid entityContextId, - const Data::AssetId& modelAssetId, - const Data::AssetId& materialAssetId, - const Data::AssetId& lightingPresetAssetId); - ~CommonPreviewContent(); - - void Load(); - bool IsReady() const; - bool IsError() const; - void ReportErrors(); - void UpdateScene(); - - private: - void UpdateModel(); - void UpdateLighting(); - void UpdateCamera(); - - static constexpr float AspectRatio = 1.0f; - static constexpr float NearDist = 0.001f; - static constexpr float FarDist = 100.0f; - static constexpr float FieldOfView = Constants::HalfPi; - static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; - - RPI::ScenePtr m_scene; - RPI::ViewPtr m_view; - AZ::Uuid m_entityContextId; - Entity* m_modelEntity = nullptr; - - static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); - Data::Asset m_defaultLightingPresetAsset; - Data::Asset m_lightingPresetAsset; - - //! Model asset about to be rendered - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); - Data::Asset m_defaultModelAsset; - Data::Asset m_modelAsset; - - //! Material asset about to be rendered - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); - Data::Asset m_defaultMaterialAsset; - Data::Asset m_materialAsset; + CommonPreviewContent() = default; + virtual ~CommonPreviewContent() = default; + virtual void Load() = 0; + virtual bool IsReady() const = 0; + virtual bool IsError() const = 0; + virtual void ReportErrors() = 0; + virtual void UpdateScene() = 0; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp index 37a9bab378..d21387c925 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp @@ -19,13 +19,10 @@ #include #include #include -#include -#include #include #include #include #include -#include namespace AZ { @@ -35,11 +32,7 @@ namespace AZ { CommonPreviewRenderer::CommonPreviewRenderer() { - // CommonPreviewRenderer supports both models and materials - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); - SystemTickBus::Handler::BusConnect(); m_entityContext = AZStd::make_unique(); m_entityContext->InitContext(); @@ -95,8 +88,6 @@ namespace AZ CommonPreviewRenderer::~CommonPreviewRenderer() { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); - SystemTickBus::Handler::BusDisconnect(); PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); SetState(CommonPreviewRenderer::State::None); @@ -110,6 +101,21 @@ namespace AZ m_frameworkScene->UnsetSubsystem(m_entityContext.get()); } + RPI::ScenePtr CommonPreviewRenderer::GetScene() const + { + return m_scene; + } + + RPI::ViewPtr CommonPreviewRenderer::GetView() const + { + return m_view; + } + + AZ::Uuid CommonPreviewRenderer::GetEntityContextId() const + { + return m_entityContext->GetContextId(); + } + void CommonPreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) { m_captureRequestQueue.push(captureRequest); @@ -227,11 +233,6 @@ namespace AZ m_renderPipeline->RemoveFromRenderTick(); } - void CommonPreviewRenderer::OnSystemTick() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); - } - void CommonPreviewRenderer::GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const { featureProcessors.insert({ @@ -253,33 +254,6 @@ namespace AZ "AZ::Render::PostProcessFeatureProcessor", "AZ::Render::SkyBoxFeatureProcessor" }); } - - void CommonPreviewRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) - { - AddCaptureRequest( - { thumbnailSize, - AZStd::make_shared( - m_scene, m_view, m_entityContext->GetContextId(), - GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type()), - GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type()), - GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type())), - [thumbnailKey]() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - }, - [thumbnailKey](const QImage& image) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, - QPixmap::fromImage(image)); - } }); - } - - bool CommonPreviewRenderer::Installed() const - { - return true; - } } // namespace Thumbnails } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h index 124a6987cc..dd0c3c4898 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h @@ -12,22 +12,15 @@ #include #include #include -#include -#include #include -#include +#include namespace AzFramework { class Scene; } -// Disables warning messages triggered by the Qt library -// 4251: class needs to have dll-interface to be used by clients of class -// 4800: forcing value to bool 'true' or 'false' (performance warning) -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING +class QImage; namespace AZ { @@ -35,13 +28,9 @@ namespace AZ { namespace Thumbnails { - class CommonPreviewRendererState; - //! Provides custom rendering of material and model thumbnails - class CommonPreviewRenderer - : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler - , public SystemTickBus::Handler - , public PreviewerFeatureProcessorProviderBus::Handler + class CommonPreviewRenderer final + : public PreviewerFeatureProcessorProviderBus::Handler { public: AZ_CLASS_ALLOCATOR(CommonPreviewRenderer, AZ::SystemAllocator, 0); @@ -49,7 +38,7 @@ namespace AZ CommonPreviewRenderer(); ~CommonPreviewRenderer(); - struct CaptureRequest + struct CaptureRequest final { int m_size = 512; AZStd::shared_ptr m_content; @@ -57,6 +46,10 @@ namespace AZ AZStd::function m_captureCompleteCallback; }; + RPI::ScenePtr GetScene() const; + RPI::ViewPtr GetView() const; + AZ::Uuid GetEntityContextId() const; + void AddCaptureRequest(const CaptureRequest& captureRequest); enum class State : AZ::s8 @@ -84,16 +77,9 @@ namespace AZ void EndCapture(); private: - //! SystemTickBus::Handler interface overrides... - void OnSystemTick() override; - //! Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; - //! ThumbnailerRendererRequestsBus::Handler interface overrides... - void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; - bool Installed() const override; - static constexpr float AspectRatio = 1.0f; static constexpr float NearDist = 0.001f; static constexpr float FarDist = 100.0f; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index f135bc1132..3b6212e0eb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -45,8 +45,6 @@ set(FILES Source/Material/EditorMaterialSystemComponent.h Source/Material/MaterialBrowserInteractions.h Source/Material/MaterialBrowserInteractions.cpp - Source/Material/MaterialThumbnail.cpp - Source/Material/MaterialThumbnail.h Source/Mesh/EditorMeshComponent.h Source/Mesh/EditorMeshComponent.cpp Source/Mesh/EditorMeshStats.h @@ -55,8 +53,6 @@ set(FILES Source/Mesh/EditorMeshSystemComponent.h Source/Mesh/EditorMeshStatsSerializer.cpp Source/Mesh/EditorMeshStatsSerializer.h - Source/Mesh/MeshThumbnail.h - Source/Mesh/MeshThumbnail.cpp Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp Source/PostProcess/EditorPostFxLayerComponent.cpp @@ -102,7 +98,6 @@ set(FILES Source/Thumbnails/Preview/CommonPreviewer.ui Source/Thumbnails/Preview/CommonPreviewerFactory.cpp Source/Thumbnails/Preview/CommonPreviewerFactory.h - Source/Thumbnails/Rendering/CommonPreviewContent.cpp Source/Thumbnails/Rendering/CommonPreviewContent.h Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp Source/Thumbnails/Rendering/CommonPreviewRenderer.h @@ -113,6 +108,16 @@ set(FILES Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h + Source/Thumbnails/CommonThumbnailPreviewContent.cpp + Source/Thumbnails/CommonThumbnailPreviewContent.h + Source/Thumbnails/CommonThumbnailRenderer.cpp + Source/Thumbnails/CommonThumbnailRenderer.h + Source/Thumbnails/MaterialThumbnail.cpp + Source/Thumbnails/MaterialThumbnail.h + Source/Thumbnails/ModelThumbnail.cpp + Source/Thumbnails/ModelThumbnail.h + Source/Thumbnails/LightingPresetThumbnail.cpp + Source/Thumbnails/LightingPresetThumbnail.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp From 569318e9e1b18e7b796da209d23a0b8de40feeca Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 8 Oct 2021 02:56:24 -0500 Subject: [PATCH 137/293] Moved preview renderer files to atom tools framework Signed-off-by: Guthrie Adams --- .../Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h} | 0 .../Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h} | 0 .../Code/Source/PreviewRenderer/PreviewRenderer.cpp} | 0 .../Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp} | 0 .../Code/Source/PreviewRenderer/PreviewRendererCaptureState.h} | 0 .../Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp} | 0 .../Code/Source/PreviewRenderer/PreviewRendererIdleState.h} | 0 .../Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp} | 0 .../Code/Source/PreviewRenderer/PreviewRendererLoadState.h} | 0 .../Code/Source/PreviewRenderer/PreviewRendererState.h} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h => Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h => Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h} (100%) rename Gems/{AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h => Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h} (100%) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewContent.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonPreviewRendererState.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h From 76b4dafbb3e848ad0f7f48b392ec97bbf0974ff9 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 8 Oct 2021 04:33:45 -0500 Subject: [PATCH 138/293] Everything compiling again after moving preview renderer to atom tools framework Signed-off-by: Guthrie Adams --- .../AtomToolsFramework/Code/CMakeLists.txt | 1 + .../PreviewRenderer/PreviewContent.h | 34 +- .../PreviewRenderer/PreviewRenderer.h | 157 ++++--- .../PreviewRenderer/PreviewRendererState.h | 35 ++ .../PreviewerFeatureProcessorProviderBus.h | 25 ++ .../Viewport/RenderViewportWidget.h | 4 +- .../PreviewRenderer/PreviewRenderer.cpp | 417 +++++++++--------- .../PreviewRendererCaptureState.cpp | 74 ++-- .../PreviewRendererCaptureState.h | 47 +- .../PreviewRendererIdleState.cpp | 44 +- .../PreviewRendererIdleState.h | 39 +- .../PreviewRendererLoadState.cpp | 64 ++- .../PreviewRendererLoadState.h | 41 +- .../PreviewRenderer/PreviewRendererState.h | 37 -- .../Code/atomtoolsframework_files.cmake | 11 + .../PreviewerFeatureProcessorProviderBus.h | 33 -- .../CommonThumbnailPreviewContent.h | 4 +- .../Thumbnails/CommonThumbnailRenderer.h | 4 +- .../Thumbnails/Preview/CommonPreviewer.cpp | 8 +- ...egration_commonfeatures_editor_files.cmake | 11 - 20 files changed, 511 insertions(+), 579 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h delete mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index add499f080..ea5b65be7c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -36,6 +36,7 @@ ly_add_target( Gem::Atom_RPI.Edit Gem::Atom_RPI.Public Gem::Atom_RHI.Reflect + Gem::Atom_Feature_Common.Static Gem::Atom_Bootstrap.Headers ) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h index 891c7f2d01..17445835ba 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h @@ -10,26 +10,20 @@ #include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + //! Provides custom rendering of previefw images + class PreviewContent { - namespace Thumbnails - { - //! Provides custom rendering of preeview images - class CommonPreviewContent - { - public: - AZ_CLASS_ALLOCATOR(CommonPreviewContent, AZ::SystemAllocator, 0); + public: + AZ_CLASS_ALLOCATOR(PreviewContent, AZ::SystemAllocator, 0); - CommonPreviewContent() = default; - virtual ~CommonPreviewContent() = default; - virtual void Load() = 0; - virtual bool IsReady() const = 0; - virtual bool IsError() const = 0; - virtual void ReportErrors() = 0; - virtual void UpdateScene() = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + PreviewContent() = default; + virtual ~PreviewContent() = default; + virtual void Load() = 0; + virtual bool IsReady() const = 0; + virtual bool IsError() const = 0; + virtual void ReportErrors() = 0; + virtual void UpdateScene() = 0; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h index dd0c3c4898..b772bfcaf2 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h @@ -10,10 +10,10 @@ #include #include -#include +#include +#include +#include #include -#include -#include namespace AzFramework { @@ -22,85 +22,78 @@ namespace AzFramework class QImage; -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + //! Provides custom rendering of preview images + class PreviewRenderer final : public PreviewerFeatureProcessorProviderBus::Handler { - namespace Thumbnails + public: + AZ_CLASS_ALLOCATOR(PreviewRenderer, AZ::SystemAllocator, 0); + + PreviewRenderer(); + ~PreviewRenderer(); + + struct CaptureRequest final + { + int m_size = 512; + AZStd::shared_ptr m_content; + AZStd::function m_captureFailedCallback; + AZStd::function m_captureCompleteCallback; + }; + + AZ::RPI::ScenePtr GetScene() const; + AZ::RPI::ViewPtr GetView() const; + AZ::Uuid GetEntityContextId() const; + + void AddCaptureRequest(const CaptureRequest& captureRequest); + + enum class State : AZ::s8 { - //! Provides custom rendering of material and model thumbnails - class CommonPreviewRenderer final - : public PreviewerFeatureProcessorProviderBus::Handler - { - public: - AZ_CLASS_ALLOCATOR(CommonPreviewRenderer, AZ::SystemAllocator, 0); - - CommonPreviewRenderer(); - ~CommonPreviewRenderer(); - - struct CaptureRequest final - { - int m_size = 512; - AZStd::shared_ptr m_content; - AZStd::function m_captureFailedCallback; - AZStd::function m_captureCompleteCallback; - }; - - RPI::ScenePtr GetScene() const; - RPI::ViewPtr GetView() const; - AZ::Uuid GetEntityContextId() const; - - void AddCaptureRequest(const CaptureRequest& captureRequest); - - enum class State : AZ::s8 - { - None, - IdleState, - LoadState, - CaptureState - }; - - void SetState(State state); - State GetState() const; - - void SelectCaptureRequest(); - void CancelCaptureRequest(); - void CompleteCaptureRequest(); - - void LoadAssets(); - void UpdateLoadAssets(); - void CancelLoadAssets(); - - void UpdateScene(); - - bool StartCapture(); - void EndCapture(); - - private: - //! Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... - void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; - - static constexpr float AspectRatio = 1.0f; - static constexpr float NearDist = 0.001f; - static constexpr float FarDist = 100.0f; - static constexpr float FieldOfView = Constants::HalfPi; - - RPI::ScenePtr m_scene; - AZStd::string m_sceneName = "Material Thumbnail Scene"; - AZStd::string m_pipelineName = "Material Thumbnail Pipeline"; - AZStd::shared_ptr m_frameworkScene; - RPI::RenderPipelinePtr m_renderPipeline; - RPI::ViewPtr m_view; - AZStd::vector m_passHierarchy; - AZStd::unique_ptr m_entityContext; - - //! Incoming requests are appended to this queue and processed one at a time in OnTick function. - AZStd::queue m_captureRequestQueue; - CaptureRequest m_currentCaptureRequest; - - AZStd::unordered_map> m_states; - State m_currentState = CommonPreviewRenderer::State::None; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + None, + IdleState, + LoadState, + CaptureState + }; + + void SetState(State state); + State GetState() const; + + void SelectCaptureRequest(); + void CancelCaptureRequest(); + void CompleteCaptureRequest(); + + void LoadAssets(); + void UpdateLoadAssets(); + void CancelLoadAssets(); + + void UpdateScene(); + + bool StartCapture(); + void EndCapture(); + + private: + //! AZ::Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... + void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = AZ::Constants::HalfPi; + + AZ::RPI::ScenePtr m_scene; + AZStd::string m_sceneName = "Preview Renderer Scene"; + AZStd::string m_pipelineName = "Preview Renderer Pipeline"; + AZStd::shared_ptr m_frameworkScene; + AZ::RPI::RenderPipelinePtr m_renderPipeline; + AZ::RPI::ViewPtr m_view; + AZStd::vector m_passHierarchy; + AZStd::unique_ptr m_entityContext; + + //! Incoming requests are appended to this queue and processed one at a time in OnTick function. + AZStd::queue m_captureRequestQueue; + CaptureRequest m_currentCaptureRequest; + + AZStd::unordered_map> m_states; + State m_currentState = PreviewRenderer::State::None; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h new file mode 100644 index 0000000000..264c37a122 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +namespace AtomToolsFramework +{ + class PreviewRenderer; + + //! PreviewRendererState decouples PreviewRenderer logic into easy-to-understand and debug pieces + class PreviewRendererState + { + public: + explicit PreviewRendererState(PreviewRenderer* renderer) + : m_renderer(renderer) + { + } + + virtual ~PreviewRendererState() = default; + + //! Start is called when state begins execution + virtual void Start() = 0; + + //! Stop is called when state ends execution + virtual void Stop() = 0; + + protected: + PreviewRenderer* m_renderer = {}; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h new file mode 100644 index 0000000000..fe1980b39b --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h @@ -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 + * + */ +#pragma once + +#include +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for preview image generation + class PreviewerFeatureProcessorProviderRequests : public AZ::EBusTraits + { + public: + //! Get a list of custom feature processors to register with preview image renderer + virtual void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; + }; + + using PreviewerFeatureProcessorProviderBus = AZ::EBus; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index 623d759c9f..22d9dcfc6b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -25,7 +25,7 @@ namespace AtomToolsFramework { //! The RenderViewportWidget class is a Qt wrapper around an Atom viewport. - //! RenderViewportWidget renders to an internal window using RPI::ViewportContext + //! RenderViewportWidget renders to an internal window using AZ::RPI::ViewportContext //! and delegates input via its internal ViewportControllerList. //! @see AZ::RPI::ViewportContext for Atom's API for setting up class RenderViewportWidget @@ -39,7 +39,7 @@ namespace AtomToolsFramework public: //! Creates a RenderViewportWidget. //! Requires the Atom RPI to be initialized in order - //! to internally construct an RPI::ViewportContext. + //! to internally construct an AZ::RPI::ViewportContext. //! If initializeViewportContext is set to false, nothing will be displayed on-screen until InitiliazeViewportContext is called. explicit RenderViewportWidget(QWidget* parent = nullptr, bool shouldInitializeViewportContext = true); ~RenderViewportWidget(); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index d21387c925..dfefd0203e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -15,245 +15,238 @@ #include #include #include +#include #include #include #include #include -#include -#include -#include -#include +#include +#include +#include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + PreviewRenderer::PreviewRenderer() { - namespace Thumbnails + PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); + + m_entityContext = AZStd::make_unique(); + m_entityContext->InitContext(); + + // Create and register a scene with all required feature processors + AZStd::unordered_set featureProcessors; + PreviewerFeatureProcessorProviderBus::Broadcast( + &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); + + AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); + m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); + + // Bind m_frameworkScene to the entity context's AzFramework::Scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "Failed to get scene system implementation."); + + AZ::Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(m_sceneName); + AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); + + m_frameworkScene = createSceneOutcome.TakeValue(); + m_frameworkScene->SetSubsystem(m_scene); + m_frameworkScene->SetSubsystem(m_entityContext.get()); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + AZ::RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = m_pipelineName; + pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; + + // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue + // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost + pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; + m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(m_renderPipeline); + m_scene->Activate(); + AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + m_passHierarchy.push_back(m_pipelineName); + m_passHierarchy.push_back("CopyToSwapChain"); + + // Connect camera to pipeline's default view after camera entity activated + AZ::Matrix4x4 viewToClipMatrix; + AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); + m_view = AZ::RPI::View::CreateView(AZ::Name("MainCamera"), AZ::RPI::View::UsageCamera); + m_view->SetViewToClipMatrix(viewToClipMatrix); + m_renderPipeline->SetDefaultView(m_view); + + m_states[PreviewRenderer::State::IdleState] = AZStd::make_shared(this); + m_states[PreviewRenderer::State::LoadState] = AZStd::make_shared(this); + m_states[PreviewRenderer::State::CaptureState] = AZStd::make_shared(this); + SetState(PreviewRenderer::State::IdleState); + } + + PreviewRenderer::~PreviewRenderer() + { + PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); + + SetState(PreviewRenderer::State::None); + m_currentCaptureRequest = {}; + m_captureRequestQueue = {}; + + m_scene->Deactivate(); + m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); + AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_frameworkScene->UnsetSubsystem(m_scene); + m_frameworkScene->UnsetSubsystem(m_entityContext.get()); + } + + AZ::RPI::ScenePtr PreviewRenderer::GetScene() const + { + return m_scene; + } + + AZ::RPI::ViewPtr PreviewRenderer::GetView() const + { + return m_view; + } + + AZ::Uuid PreviewRenderer::GetEntityContextId() const + { + return m_entityContext->GetContextId(); + } + + void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) + { + m_captureRequestQueue.push(captureRequest); + } + + void PreviewRenderer::SetState(State state) + { + auto stepItr = m_states.find(m_currentState); + if (stepItr != m_states.end()) { - CommonPreviewRenderer::CommonPreviewRenderer() - { - PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); - - m_entityContext = AZStd::make_unique(); - m_entityContext->InitContext(); - - // Create and register a scene with all required feature processors - AZStd::unordered_set featureProcessors; - PreviewerFeatureProcessorProviderBus::Broadcast( - &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); - - RPI::SceneDescriptor sceneDesc; - sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); - m_scene = RPI::Scene::CreateScene(sceneDesc); - - // Bind m_frameworkScene to the entity context's AzFramework::Scene - auto sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "Failed to get scene system implementation."); - - Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(m_sceneName); - AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); - - m_frameworkScene = createSceneOutcome.TakeValue(); - m_frameworkScene->SetSubsystem(m_scene); - m_frameworkScene->SetSubsystem(m_entityContext.get()); - - // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene - RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = m_pipelineName; - pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; - - // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue - // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost - pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; - m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - m_scene->AddRenderPipeline(m_renderPipeline); - m_scene->Activate(); - RPI::RPISystemInterface::Get()->RegisterScene(m_scene); - m_passHierarchy.push_back(m_pipelineName); - m_passHierarchy.push_back("CopyToSwapChain"); - - // Connect camera to pipeline's default view after camera entity activated - Matrix4x4 viewToClipMatrix; - MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); - m_view = RPI::View::CreateView(Name("MainCamera"), RPI::View::UsageCamera); - m_view->SetViewToClipMatrix(viewToClipMatrix); - m_renderPipeline->SetDefaultView(m_view); - - m_states[CommonPreviewRenderer::State::IdleState] = AZStd::make_shared(this); - m_states[CommonPreviewRenderer::State::LoadState] = AZStd::make_shared(this); - m_states[CommonPreviewRenderer::State::CaptureState] = AZStd::make_shared(this); - SetState(CommonPreviewRenderer::State::IdleState); - } + stepItr->second->Stop(); + } - CommonPreviewRenderer::~CommonPreviewRenderer() - { - PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); + m_currentState = state; - SetState(CommonPreviewRenderer::State::None); - m_currentCaptureRequest = {}; - m_captureRequestQueue = {}; + stepItr = m_states.find(m_currentState); + if (stepItr != m_states.end()) + { + stepItr->second->Start(); + } + } - m_scene->Deactivate(); - m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); - RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); - m_frameworkScene->UnsetSubsystem(m_scene); - m_frameworkScene->UnsetSubsystem(m_entityContext.get()); - } + PreviewRenderer::State PreviewRenderer::GetState() const + { + return m_currentState; + } - RPI::ScenePtr CommonPreviewRenderer::GetScene() const - { - return m_scene; - } + void PreviewRenderer::SelectCaptureRequest() + { + if (!m_captureRequestQueue.empty()) + { + // pop the next request to be rendered from the queue + m_currentCaptureRequest = m_captureRequestQueue.front(); + m_captureRequestQueue.pop(); - RPI::ViewPtr CommonPreviewRenderer::GetView() const - { - return m_view; - } + SetState(PreviewRenderer::State::LoadState); + } + } - AZ::Uuid CommonPreviewRenderer::GetEntityContextId() const - { - return m_entityContext->GetContextId(); - } + void PreviewRenderer::CancelCaptureRequest() + { + m_currentCaptureRequest.m_captureFailedCallback(); + SetState(PreviewRenderer::State::IdleState); + } - void CommonPreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) - { - m_captureRequestQueue.push(captureRequest); - } + void PreviewRenderer::CompleteCaptureRequest() + { + SetState(PreviewRenderer::State::IdleState); + } - void CommonPreviewRenderer::SetState(State state) - { - auto stepItr = m_states.find(m_currentState); - if (stepItr != m_states.end()) - { - stepItr->second->Stop(); - } - - m_currentState = state; - - stepItr = m_states.find(m_currentState); - if (stepItr != m_states.end()) - { - stepItr->second->Start(); - } - } + void PreviewRenderer::LoadAssets() + { + m_currentCaptureRequest.m_content->Load(); + } - CommonPreviewRenderer::State CommonPreviewRenderer::GetState() const - { - return m_currentState; - } + void PreviewRenderer::UpdateLoadAssets() + { + if (m_currentCaptureRequest.m_content->IsReady()) + { + SetState(PreviewRenderer::State::CaptureState); + return; + } - void CommonPreviewRenderer::SelectCaptureRequest() - { - if (!m_captureRequestQueue.empty()) - { - // pop the next request to be rendered from the queue - m_currentCaptureRequest = m_captureRequestQueue.front(); - m_captureRequestQueue.pop(); - - SetState(CommonPreviewRenderer::State::LoadState); - } - } + if (m_currentCaptureRequest.m_content->IsError()) + { + CancelLoadAssets(); + return; + } + } - void CommonPreviewRenderer::CancelCaptureRequest() - { - m_currentCaptureRequest.m_captureFailedCallback(); - SetState(CommonPreviewRenderer::State::IdleState); - } + void PreviewRenderer::CancelLoadAssets() + { + m_currentCaptureRequest.m_content->ReportErrors(); + CancelCaptureRequest(); + } - void CommonPreviewRenderer::CompleteCaptureRequest() - { - SetState(CommonPreviewRenderer::State::IdleState); - } + void PreviewRenderer::UpdateScene() + { + m_currentCaptureRequest.m_content->UpdateScene(); + } - void CommonPreviewRenderer::LoadAssets() + bool PreviewRenderer::StartCapture() + { + auto captureCallback = [currentCaptureRequest = m_currentCaptureRequest](const AZ::RPI::AttachmentReadback::ReadbackResult& result) + { + if (result.m_dataBuffer) { - m_currentCaptureRequest.m_content->Load(); + currentCaptureRequest.m_captureCompleteCallback(QImage( + result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, + QImage::Format_RGBA8888)); } - - void CommonPreviewRenderer::UpdateLoadAssets() + else { - if (m_currentCaptureRequest.m_content->IsReady()) - { - SetState(CommonPreviewRenderer::State::CaptureState); - return; - } - - if (m_currentCaptureRequest.m_content->IsError()) - { - CancelLoadAssets(); - return; - } + currentCaptureRequest.m_captureFailedCallback(); } + }; - void CommonPreviewRenderer::CancelLoadAssets() - { - m_currentCaptureRequest.m_content->ReportErrors(); - CancelCaptureRequest(); - } + if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) + { + renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size); + } - void CommonPreviewRenderer::UpdateScene() - { - m_currentCaptureRequest.m_content->UpdateScene(); - } + m_renderPipeline->AddToRenderTickOnce(); - bool CommonPreviewRenderer::StartCapture() - { - auto captureCallback = - [currentCaptureRequest = m_currentCaptureRequest](const RPI::AttachmentReadback::ReadbackResult& result) - { - if (result.m_dataBuffer) - { - currentCaptureRequest.m_captureCompleteCallback(QImage( - result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, - result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888)); - } - else - { - currentCaptureRequest.m_captureFailedCallback(); - } - }; - - if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) - { - renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size); - } - - m_renderPipeline->AddToRenderTickOnce(); - - bool startedCapture = false; - Render::FrameCaptureRequestBus::BroadcastResult( - startedCapture, &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, - AZStd::string("Output"), captureCallback, RPI::PassAttachmentReadbackOption::Output); - return startedCapture; - } + bool startedCapture = false; + AZ::Render::FrameCaptureRequestBus::BroadcastResult( + startedCapture, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, + AZStd::string("Output"), captureCallback, AZ::RPI::PassAttachmentReadbackOption::Output); + return startedCapture; + } - void CommonPreviewRenderer::EndCapture() - { - m_renderPipeline->RemoveFromRenderTick(); - } + void PreviewRenderer::EndCapture() + { + m_renderPipeline->RemoveFromRenderTick(); + } - void CommonPreviewRenderer::GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const - { - featureProcessors.insert({ - "AZ::Render::TransformServiceFeatureProcessor", - "AZ::Render::MeshFeatureProcessor", - "AZ::Render::SimplePointLightFeatureProcessor", - "AZ::Render::SimpleSpotLightFeatureProcessor", - "AZ::Render::PointLightFeatureProcessor", - // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow - // flickering [ATOM-13568] - // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. - // Possibly re-enable with [GFX TODO][ATOM-13639] - // "AZ::Render::DirectionalLightFeatureProcessor", - "AZ::Render::DiskLightFeatureProcessor", - "AZ::Render::CapsuleLightFeatureProcessor", - "AZ::Render::QuadLightFeatureProcessor", - "AZ::Render::DecalTextureArrayFeatureProcessor", - "AZ::Render::ImageBasedLightFeatureProcessor", - "AZ::Render::PostProcessFeatureProcessor", - "AZ::Render::SkyBoxFeatureProcessor" }); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + void PreviewRenderer::GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const + { + featureProcessors.insert({ + "AZ::Render::TransformServiceFeatureProcessor", + "AZ::Render::MeshFeatureProcessor", + "AZ::Render::SimplePointLightFeatureProcessor", + "AZ::Render::SimpleSpotLightFeatureProcessor", + "AZ::Render::PointLightFeatureProcessor", + // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow + // flickering [ATOM-13568] + // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. + // Possibly re-enable with [GFX TODO][ATOM-13639] + // "AZ::Render::DirectionalLightFeatureProcessor", + "AZ::Render::DiskLightFeatureProcessor", + "AZ::Render::CapsuleLightFeatureProcessor", + "AZ::Render::QuadLightFeatureProcessor", + "AZ::Render::DecalTextureArrayFeatureProcessor", + "AZ::Render::ImageBasedLightFeatureProcessor", + "AZ::Render::PostProcessFeatureProcessor", + "AZ::Render::SkyBoxFeatureProcessor" }); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp index fc74e9f43b..f3414bc29f 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp @@ -6,52 +6,46 @@ * */ -#include -#include +#include +#include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + PreviewRendererCaptureState::PreviewRendererCaptureState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) { - namespace Thumbnails - { - CommonPreviewRendererCaptureState::CommonPreviewRendererCaptureState(CommonPreviewRenderer* renderer) - : CommonPreviewRendererState(renderer) - { - } + } - void CommonPreviewRendererCaptureState::Start() - { - m_ticksToCapture = 1; - m_renderer->UpdateScene(); - TickBus::Handler::BusConnect(); - } + void PreviewRendererCaptureState::Start() + { + m_ticksToCapture = 1; + m_renderer->UpdateScene(); + AZ::TickBus::Handler::BusConnect(); + } - void CommonPreviewRendererCaptureState::Stop() - { - m_renderer->EndCapture(); - TickBus::Handler::BusDisconnect(); - Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); - } + void PreviewRendererCaptureState::Stop() + { + m_renderer->EndCapture(); + AZ::TickBus::Handler::BusDisconnect(); + AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); + } - void CommonPreviewRendererCaptureState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) + void PreviewRendererCaptureState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + if (m_ticksToCapture-- <= 0) + { + // Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick. + if (m_renderer->StartCapture()) { - if (m_ticksToCapture-- <= 0) - { - // Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick. - if (m_renderer->StartCapture()) - { - Render::FrameCaptureNotificationBus::Handler::BusConnect(); - TickBus::Handler::BusDisconnect(); - } - } + AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusDisconnect(); } + } + } - void CommonPreviewRendererCaptureState::OnCaptureFinished( - [[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) - { - m_renderer->CompleteCaptureRequest(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + void PreviewRendererCaptureState::OnCaptureFinished( + [[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) + { + m_renderer->CompleteCaptureRequest(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h index c19f12d9bb..190cb919df 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h @@ -9,38 +9,31 @@ #pragma once #include +#include #include -#include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + //! PreviewRendererCaptureState renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished + class PreviewRendererCaptureState final + : public PreviewRendererState + , public AZ::TickBus::Handler + , public AZ::Render::FrameCaptureNotificationBus::Handler { - namespace Thumbnails - { - //! CommonPreviewRendererCaptureState renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished - class CommonPreviewRendererCaptureState - : public CommonPreviewRendererState - , private TickBus::Handler - , private Render::FrameCaptureNotificationBus::Handler - { - public: - CommonPreviewRendererCaptureState(CommonPreviewRenderer* renderer); + public: + PreviewRendererCaptureState(PreviewRenderer* renderer); - void Start() override; - void Stop() override; + void Start() override; + void Stop() override; - private: - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - //! Render::FrameCaptureNotificationBus::Handler overrides... - void OnCaptureFinished(Render::FrameCaptureResult result, const AZStd::string& info) override; - - //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials - int m_ticksToCapture = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + //! AZ::Render::FrameCaptureNotificationBus::Handler overrides... + void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override; + //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials + int m_ticksToCapture = 0; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp index 12a38fc93f..db91bedce1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp @@ -6,34 +6,28 @@ * */ -#include -#include +#include +#include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + PreviewRendererIdleState::PreviewRendererIdleState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) { - namespace Thumbnails - { - CommonPreviewRendererIdleState::CommonPreviewRendererIdleState(CommonPreviewRenderer* renderer) - : CommonPreviewRendererState(renderer) - { - } + } - void CommonPreviewRendererIdleState::Start() - { - TickBus::Handler::BusConnect(); - } + void PreviewRendererIdleState::Start() + { + AZ::TickBus::Handler::BusConnect(); + } - void CommonPreviewRendererIdleState::Stop() - { - TickBus::Handler::BusDisconnect(); - } + void PreviewRendererIdleState::Stop() + { + AZ::TickBus::Handler::BusDisconnect(); + } - void CommonPreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) - { - m_renderer->SelectCaptureRequest(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + void PreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + m_renderer->SelectCaptureRequest(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h index 3278149b98..9e5380e734 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h @@ -8,31 +8,24 @@ #pragma once -#include +#include +#include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + //! PreviewRendererIdleState checks whether there are any new thumbnails that need to be rendered every tick + class PreviewRendererIdleState final + : public PreviewRendererState + , public AZ::TickBus::Handler { - namespace Thumbnails - { - //! CommonPreviewRendererIdleState checks whether there are any new thumbnails that need to be rendered every tick - class CommonPreviewRendererIdleState - : public CommonPreviewRendererState - , private TickBus::Handler - { - public: - CommonPreviewRendererIdleState(CommonPreviewRenderer* renderer); + public: + PreviewRendererIdleState(PreviewRenderer* renderer); - void Start() override; - void Stop() override; - - private: - - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + void Start() override; + void Stop() override; + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp index dcac673de2..b5d219636e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp @@ -6,44 +6,38 @@ * */ -#include -#include +#include +#include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + PreviewRendererLoadState::PreviewRendererLoadState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) { - namespace Thumbnails - { - CommonPreviewRendererLoadState::CommonPreviewRendererLoadState(CommonPreviewRenderer* renderer) - : CommonPreviewRendererState(renderer) - { - } + } - void CommonPreviewRendererLoadState::Start() - { - m_renderer->LoadAssets(); - m_timeRemainingS = TimeOutS; - TickBus::Handler::BusConnect(); - } + void PreviewRendererLoadState::Start() + { + m_renderer->LoadAssets(); + m_timeRemainingS = TimeOutS; + AZ::TickBus::Handler::BusConnect(); + } - void CommonPreviewRendererLoadState::Stop() - { - TickBus::Handler::BusDisconnect(); - } + void PreviewRendererLoadState::Stop() + { + AZ::TickBus::Handler::BusDisconnect(); + } - void CommonPreviewRendererLoadState::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) - { - m_timeRemainingS -= deltaTime; - if (m_timeRemainingS > 0.0f) - { - m_renderer->UpdateLoadAssets(); - } - else - { - m_renderer->CancelLoadAssets(); - } - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + void PreviewRendererLoadState::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + m_timeRemainingS -= deltaTime; + if (m_timeRemainingS > 0.0f) + { + m_renderer->UpdateLoadAssets(); + } + else + { + m_renderer->CancelLoadAssets(); + } + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h index 438fd774ca..623d6cbdfc 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h @@ -9,33 +9,26 @@ #pragma once #include -#include +#include -namespace AZ +namespace AtomToolsFramework { - namespace LyIntegration + //! PreviewRendererLoadState pauses further rendering until all assets used for rendering a thumbnail have been loaded + class PreviewRendererLoadState final + : public PreviewRendererState + , public AZ::TickBus::Handler { - namespace Thumbnails - { - //! CommonPreviewRendererLoadState pauses further rendering until all assets used for rendering a thumbnail have been loaded - class CommonPreviewRendererLoadState - : public CommonPreviewRendererState - , private TickBus::Handler - { - public: - CommonPreviewRendererLoadState(CommonPreviewRenderer* renderer); + public: + PreviewRendererLoadState(PreviewRenderer* renderer); - void Start() override; - void Stop() override; + void Start() override; + void Stop() override; - private: - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - static constexpr float TimeOutS = 5.0f; - float m_timeRemainingS = TimeOutS; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + static constexpr float TimeOutS = 5.0f; + float m_timeRemainingS = TimeOutS; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h deleted file mode 100644 index 9dbf50ab0e..0000000000 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h +++ /dev/null @@ -1,37 +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 - * - */ - -#pragma once - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class CommonPreviewRenderer; - - //! CommonPreviewRendererState decouples CommonPreviewRenderer logic into easy-to-understand and debug pieces - class CommonPreviewRendererState - { - public: - explicit CommonPreviewRendererState(CommonPreviewRenderer* renderer) : m_renderer(renderer) {} - virtual ~CommonPreviewRendererState() = default; - - //! Start is called when state begins execution - virtual void Start() {} - //! Stop is called when state ends execution - virtual void Stop() {} - - protected: - CommonPreviewRenderer* m_renderer; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index 3d4bb82eec..df0dba2678 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -58,4 +58,15 @@ set(FILES Source/Window/AtomToolsMainWindow.cpp Source/Window/AtomToolsMainWindowSystemComponent.cpp Source/Window/AtomToolsMainWindowSystemComponent.h + Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h + Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h + Source/PreviewRenderer/PreviewRenderer.cpp + Source/PreviewRenderer/PreviewRendererIdleState.cpp + Source/PreviewRenderer/PreviewRendererIdleState.h + Source/PreviewRenderer/PreviewRendererLoadState.cpp + Source/PreviewRenderer/PreviewRendererLoadState.h + Source/PreviewRenderer/PreviewRendererCaptureState.cpp + Source/PreviewRenderer/PreviewRendererCaptureState.h ) \ No newline at end of file diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h deleted file mode 100644 index bae49db89d..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h +++ /dev/null @@ -1,33 +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 - * - */ -#pragma once - -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for preview image generation - //! Duplicates will be ignored - //! You can check minimal feature processors that are already registered in CommonPreviewRenderer.cpp - class PreviewerFeatureProcessorProviderRequests - : public AZ::EBusTraits - { - public: - //! Get a list of custom feature processors to register with preview image renderer - virtual void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; - }; - - using PreviewerFeatureProcessorProviderBus = AZ::EBus; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h index 59556e03d1..8520d6053a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace AZ { @@ -23,7 +23,7 @@ namespace AZ { //! Provides custom rendering of material and model previews class CommonThumbnailPreviewContent final - : public CommonPreviewContent + : public AtomToolsFramework::PreviewContent { public: AZ_CLASS_ALLOCATOR(CommonThumbnailPreviewContent, AZ::SystemAllocator, 0); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h index fb683c1aff..0497521d44 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h @@ -8,10 +8,10 @@ #pragma once +#include #include #include #include -#include #include namespace AZ @@ -39,7 +39,7 @@ namespace AZ //! SystemTickBus::Handler interface overrides... void OnSystemTick() override; - CommonPreviewRenderer m_previewRenderer; + AtomToolsFramework::PreviewRenderer m_previewRenderer; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp index 9730c7d4a9..a8692b5eb4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp @@ -14,14 +14,14 @@ #include #include -#include -#include +#include +#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include +#include #include #include AZ_POP_DISABLE_WARNING @@ -73,4 +73,4 @@ namespace AZ } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 3b6212e0eb..db42b663c8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -9,7 +9,6 @@ set(FILES Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h - Include/AtomLyIntegration/CommonFeatures/Thumbnails/PreviewerFeatureProcessorProviderBus.h Source/Module.cpp Source/Animation/EditorAttachmentComponent.h Source/Animation/EditorAttachmentComponent.cpp @@ -98,16 +97,6 @@ set(FILES Source/Thumbnails/Preview/CommonPreviewer.ui Source/Thumbnails/Preview/CommonPreviewerFactory.cpp Source/Thumbnails/Preview/CommonPreviewerFactory.h - Source/Thumbnails/Rendering/CommonPreviewContent.h - Source/Thumbnails/Rendering/CommonPreviewRenderer.cpp - Source/Thumbnails/Rendering/CommonPreviewRenderer.h - Source/Thumbnails/Rendering/CommonPreviewRendererState.h - Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.cpp - Source/Thumbnails/Rendering/CommonPreviewRendererIdleState.h - Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.cpp - Source/Thumbnails/Rendering/CommonPreviewRendererLoadState.h - Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.cpp - Source/Thumbnails/Rendering/CommonPreviewRendererCaptureState.h Source/Thumbnails/CommonThumbnailPreviewContent.cpp Source/Thumbnails/CommonThumbnailPreviewContent.h Source/Thumbnails/CommonThumbnailRenderer.cpp From 2fb4a9d2c391b20dfc92b1aaac0b330dff0579f9 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Fri, 8 Oct 2021 13:13:52 +0100 Subject: [PATCH 139/293] Add xfail to test that failed in an unrelated development build (#4569) Signed-off-by: hultonha --- AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index 4c5716d365..b148ffdcdb 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -25,6 +25,7 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") class TestAtomEditorComponentsMain(object): """Holds tests for Atom components.""" + @pytest.mark.xfail(reason="This test is being marked xfail as it failed during an unrelated development run. See LYN-7530 for more details.") def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform): """ Please review the hydra script run by this test for more specific test info. From 591854c384f10ffe1e2461378bcb4134e6bdb0c6 Mon Sep 17 00:00:00 2001 From: FiniteStateGit <31811688+FiniteStateGit@users.noreply.github.com> Date: Fri, 8 Oct 2021 06:05:24 -0700 Subject: [PATCH 140/293] Edit help menu lua documentation link (#4520) --- Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp b/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp index c88ea59bdb..33d8373487 100644 --- a/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp +++ b/Code/Tools/Standalone/Source/LUA/LUAEditorMainWindow.cpp @@ -395,7 +395,7 @@ namespace LUAEditor void LUAEditorMainWindow::OnLuaDocumentation() { - QDesktopServices::openUrl(QUrl("http://docs.aws.amazon.com/lumberyard/latest/developerguide/lua-scripting-intro.html")); + QDesktopServices::openUrl(QUrl("https://o3de.org/docs/user-guide/scripting/lua/")); } void LUAEditorMainWindow::OnMenuCloseCurrentWindow() From dcadfe6e1f0138d8e1bb210c6c6f9f8352591787 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Fri, 8 Oct 2021 09:20:17 -0500 Subject: [PATCH 141/293] Feature json assetloading assethints (#4554) * capture assets using SerializedAssetTracker in LoadInstanceFromPrefabDom() assign assets using asset hints where the asset ID is not valid switch up SerializedAssetTracker to store pointers instead of copies of Asset<> Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * PoC for the AssetFixUp strategy Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * clean up of PoC Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> --- .../AzCore/Asset/AssetJsonSerializer.cpp | 17 +++++++++- .../AzCore/AzCore/Asset/AssetJsonSerializer.h | 7 +++- .../Prefab/PrefabDomUtils.cpp | 32 +++++++++++++++++-- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.cpp index 3a83aa5d1c..3fa3b39ca5 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.cpp @@ -173,6 +173,7 @@ namespace AZ if (assetTracker) { + assetTracker->FixUpAsset(*instance); assetTracker->AddAsset(*instance); } @@ -185,7 +186,20 @@ namespace AZ return context.Report(result, message); } - void SerializedAssetTracker::AddAsset(Asset& asset) + void SerializedAssetTracker::SetAssetFixUp(AssetFixUp assetFixUpCallback) + { + m_assetFixUpCallback = AZStd::move(assetFixUpCallback); + } + + void SerializedAssetTracker::FixUpAsset(Asset& asset) + { + if (m_assetFixUpCallback) + { + m_assetFixUpCallback(asset); + } + } + + void SerializedAssetTracker::AddAsset(Asset asset) { m_serializedAssets.emplace_back(asset); } @@ -199,5 +213,6 @@ namespace AZ { return m_serializedAssets; } + } // namespace Data } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.h b/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.h index 879952c82d..e1b8cda00d 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetJsonSerializer.h @@ -39,13 +39,18 @@ namespace AZ { public: AZ_RTTI(SerializedAssetTracker, "{1E067091-8C0A-44B1-A455-6E97663F6963}"); + using AssetFixUp = AZStd::function& asset)>; - void AddAsset(Asset& asset); + void SetAssetFixUp(AssetFixUp assetFixUpCallback); + void FixUpAsset(Asset& asset); + + void AddAsset(Asset asset); AZStd::vector>& GetTrackedAssets(); const AZStd::vector>& GetTrackedAssets() const; private: AZStd::vector> m_serializedAssets; + AssetFixUp m_assetFixUpCallback; }; } // namespace Data } // namespace AZ diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp index f60759f77e..ea0fa55256 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp @@ -224,6 +224,7 @@ namespace AzToolsFramework return false; } + AZ::Data::SerializedAssetTracker* assetTracker = settings.m_metadata.Find(); referencedAssets = AZStd::move(assetTracker->GetTrackedAssets()); @@ -245,6 +246,30 @@ namespace AzToolsFramework entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random); } + // some assets may come in from the JSON serialzier with no AssetID, but have an asset hint + // this attempts to fix up the assets using the assetHint field + auto fixUpInvalidAssets = [](AZ::Data::Asset& asset) + { + if (!asset.GetId().IsValid() && !asset.GetHint().empty()) + { + AZ::Data::AssetId assetId; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetId, + &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, + asset.GetHint().c_str(), + AZ::Data::s_invalidAssetType, + false); + + if (assetId.IsValid()) + { + asset.Create(assetId, true); + } + } + }; + + auto tracker = AZ::Data::SerializedAssetTracker{}; + tracker.SetAssetFixUp(fixUpInvalidAssets); + AZ::JsonDeserializerSettings settings; // The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is // specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta @@ -252,16 +277,17 @@ namespace AzToolsFramework settings.m_metadata.Add(static_cast(&entityIdMapper)); settings.m_metadata.Add(&entityIdMapper); settings.m_metadata.Create(newlyAddedEntities); + settings.m_metadata.Add(tracker); AZStd::string scratchBuffer; auto issueReportingCallback = [&scratchBuffer]( - AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, - AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode + AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, + AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode { return Internal::JsonIssueReporter(scratchBuffer, message, result, path); }; settings.m_reporting = AZStd::move(issueReportingCallback); - + AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings); AZ::Data::AssetManager::Instance().ResumeAssetRelease(); From 06953bb81f57ade284f1bc4daaa03ab93c8b9b7c Mon Sep 17 00:00:00 2001 From: nggieber Date: Fri, 8 Oct 2021 08:14:28 -0700 Subject: [PATCH 142/293] More PR changes Signed-off-by: nggieber --- scripts/o3de/o3de/manifest.py | 41 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 32bab05de8..5d34c4bcf9 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -421,31 +421,34 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa return list(filter(filter_project_and_gem_templates_out, get_all_templates())) -def get_json_file_path(object_typename: str = None, +def get_json_file_path(object_typename: str, object_path: str or pathlib.Path = None) -> pathlib.Path: if not object_typename: - logger.error(f'Missing object typename.') + logger.error('Missing object typename.') + return None if not object_path: - logger.error(f'{object_typename} Path {object_path} has not been registered.') return None object_path = pathlib.Path(object_path).resolve() return object_path / f'{object_typename}.json' -def get_json_data_file(object_typename: str = None, - object_json: str or pathlib.Path = None, +def get_json_data_file(object_json: pathlib.Path, + object_typename: str = None, object_validator = callable) -> dict or None: if not object_typename: - logger.error(f'Missing object typename.') + logger.error('Missing object typename.') + + if not object_json: + logger.error(f'No object_json provided for {object_typename}') if not object_json.is_file(): logger.error(f'{object_typename} json {object_json} is not present.') return None if not object_validator: - logger.error(f'Missing object validator.') + logger.error('Missing object validator.') if not object_validator(object_json): logger.error(f'{object_typename} json {object_json} is not valid.') @@ -463,10 +466,14 @@ def get_json_data_file(object_typename: str = None, def get_json_data(object_typename: str = None, object_path: str or pathlib.Path = None, - object_validator = callable) -> dict or None: + object_validator = callable, + object_name: str = None) -> dict or None: object_json = get_json_file_path(object_typename, object_path) - return get_json_data_file(object_typename, object_json, object_validator) + if not object_json and object_name: + logger.error(f'{object_name} has not been registered.') + + return get_json_data_file(object_json, object_typename, object_validator) def get_engine_json_data(engine_name: str = None, @@ -478,7 +485,7 @@ def get_engine_json_data(engine_name: str = None, if engine_name and not engine_path: engine_path = get_registered(engine_name=engine_name) - return get_json_data('engine', engine_path, validation.valid_o3de_engine_json) + return get_json_data('engine', engine_path, validation.valid_o3de_engine_json, engine_name) def get_project_json_data(project_name: str = None, @@ -490,7 +497,7 @@ def get_project_json_data(project_name: str = None, if project_name and not project_path: project_path = get_registered(project_name=project_name) - return get_json_data('project', project_path, validation.valid_o3de_project_json) + return get_json_data('project', project_path, validation.valid_o3de_project_json, project_name) def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None, @@ -502,7 +509,7 @@ def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None if gem_name and not gem_path: gem_path = get_registered(gem_name=gem_name, project_path=project_path) - return get_json_data('gem', gem_path, validation.valid_o3de_gem_json) + return get_json_data('gem', gem_path, validation.valid_o3de_gem_json, gem_name) def get_template_json_data(template_name: str = None, template_path: str or pathlib.Path = None, @@ -514,7 +521,7 @@ def get_template_json_data(template_name: str = None, template_path: str or path if template_name and not template_path: template_path = get_registered(template_name=template_name, project_path=project_path) - return get_json_data('template', template_path, validation.valid_o3de_template_json) + return get_json_data('template', template_path, validation.valid_o3de_template_json, template_name) def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None, @@ -526,18 +533,18 @@ def get_restricted_json_data(restricted_name: str = None, restricted_path: str o if restricted_name and not restricted_path: restricted_path = get_registered(restricted_name=restricted_name, project_path=project_path) - return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json) + return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json, restricted_name) -def get_repo_json_data(repo_uri: str = None) -> dict or None: +def get_repo_json_data(repo_uri: str) -> dict or None: if not repo_uri: logger.error('Must specify a Repo Uri.') return None repo_json = get_repo_path(repo_uri=repo_uri) - get_json_data_file("Repo", repo_json, validation.valid_o3de_repo_json) + return get_json_data_file(repo_json, "Repo", validation.valid_o3de_repo_json) -def get_repo_path(repo_uri: str = None, cache_folder: str = None) -> pathlib.Path: +def get_repo_path(repo_uri: str, cache_folder: str = None) -> pathlib.Path: if not cache_folder: cache_folder = get_o3de_cache_folder() From c562f0a80719b7ddc73544d5f6fd0cd03d5a23f8 Mon Sep 17 00:00:00 2001 From: greerdv Date: Fri, 8 Oct 2021 16:56:53 +0100 Subject: [PATCH 143/293] small improvements to triangle mesh rigid body warning Signed-off-by: greerdv --- .../Components/Widgets/CardNotification.cpp | 3 +++ .../Code/Source/EditorColliderComponent.cpp | 17 +++++++++++++---- .../Code/Source/EditorRigidBodyComponent.cpp | 12 ++++++++++-- .../Code/Source/EditorRigidBodyComponent.h | 2 ++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp index d9451949ea..d2144457c8 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp @@ -33,6 +33,9 @@ namespace AzQtComponents titleLabel->setObjectName("Title"); titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); titleLabel->setWordWrap(true); + titleLabel->setTextFormat(Qt::RichText); + titleLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + titleLabel->setOpenExternalLinks(true); QHBoxLayout* headerLayout = new QHBoxLayout(headerFrame); headerLayout->setSizeConstraint(QLayout::SetMinimumSize); diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 7c07ca207c..7cc69caeb7 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -791,6 +792,7 @@ namespace PhysX if (shapes.empty()) { m_componentWarnings.clear(); + AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree); return; @@ -824,9 +826,16 @@ namespace PhysX } m_componentWarnings.push_back(AZStd::string::format( - "The Physics Asset \"%s\" is a Triangle Mesh, it is not compatible with a Dynamic Rigidbody, either:\n" - "Change the PhysicsAsset to Convex Mesh or set the Rigidbody to kinematic.", + "The asset \"%s\" contains one or more triangle meshes, which are not compatible with non-kinematic dynamic " + "rigid bodies. To make the collider compatible, you can export the asset as a primitive or convex mesh, use mesh " + "decomposition when exporting the asset, or set the rigid body to kinematic. Learn more about " + "colliders.", assetPath.c_str())); + + // make sure the entity inspector scrolls so the warning is visible by marking this component as having + // new content + AzToolsFramework::EntityPropertyEditorRequestBus::Broadcast( + &AzToolsFramework::EntityPropertyEditorRequests::SetNewComponentId, GetId()); } else { @@ -839,8 +848,8 @@ namespace PhysX } AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( - &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree); - + &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, + m_componentWarnings.empty() ? AzToolsFramework::Refresh_EntireTree : AzToolsFramework::Refresh_EntireTree_NewContent); } void EditorColliderComponent::OnAssetReloaded(AZ::Data::Asset asset) diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp index 447c2755c6..24b2586c9e 100644 --- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp @@ -103,7 +103,6 @@ namespace PhysX } } // namespace Internal - void EditorRigidBodyConfiguration::Reflect(AZ::ReflectContext* context) { auto serializeContext = azrtti_cast(context); @@ -310,6 +309,15 @@ namespace PhysX } } + void EditorRigidBodyComponent::OnConfigurationChanged() + { + CreateEditorWorldRigidBody(); + + // required in case the kinematic setting has changed + PhysX::EditorColliderValidationRequestBus::Event( + GetEntityId(), &PhysX::EditorColliderValidationRequestBus::Events::ValidateRigidBodyMeshGeometryType); + } + void EditorRigidBodyComponent::Reflect(AZ::ReflectContext* context) { EditorRigidBodyConfiguration::Reflect(context); @@ -336,7 +344,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/rigid-body-physics/") ->DataElement(0, &EditorRigidBodyComponent::m_config, "Configuration", "Configuration for rigid body physics.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorRigidBodyComponent::CreateEditorWorldRigidBody) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorRigidBodyComponent::OnConfigurationChanged) ; } } diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h index 5d63ec9705..ed147ad8cb 100644 --- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h +++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h @@ -120,6 +120,8 @@ namespace PhysX void InitPhysicsTickHandler(); void PrePhysicsTick(); + void OnConfigurationChanged(); + Debug::DebugDisplayDataChangedEvent::Handler m_debugDisplayDataChangeHandler; EditorRigidBodyConfiguration m_config; From e256df3f05c778d7ddad16471b18aa87fb504a54 Mon Sep 17 00:00:00 2001 From: brianherrera Date: Fri, 8 Oct 2021 10:05:50 -0700 Subject: [PATCH 144/293] Add retry config to boto3 clients This change makes the inc_build_util script more resilient against transient network issues and issues encountered during node boot-up. Signed-off-by: brianherrera --- .../build/bootstrap/incremental_build_util.py | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/scripts/build/bootstrap/incremental_build_util.py b/scripts/build/bootstrap/incremental_build_util.py index 101e31b5db..5c77559085 100644 --- a/scripts/build/bootstrap/incremental_build_util.py +++ b/scripts/build/bootstrap/incremental_build_util.py @@ -18,6 +18,8 @@ from contextlib import contextmanager import threading import _thread +from botocore.config import Config + DEFAULT_REGION = 'us-west-2' DEFAULT_DISK_SIZE = 300 DEFAULT_DISK_TYPE = 'gp2' @@ -173,10 +175,27 @@ def get_region_name(): def get_ec2_client(region): - client = boto3.client('ec2', region_name=region) + client_config = Config( + region_name=region, + retries={ + 'mode': 'standard' + } + ) + client = boto3.client('ec2', config=client_config) return client +def get_ec2_resource(region): + resource_config = Config( + region_name=region, + retries={ + 'mode': 'standard' + } + ) + resource = boto3.resource('ec2', config=resource_config) + return resource + + def get_ec2_instance_id(): try: instance_id = urllib.request.urlopen('http://169.254.169.254/latest/meta-data/instance-id').read() @@ -395,14 +414,11 @@ def detach_volume_from_ec2_instance(volume, ec2_instance_id, force, timeout_dura def mount_ebs(snapshot_hint, repository_name, project, pipeline, branch, platform, build_type, disk_size, disk_type): - session = boto3.session.Session() - region = session.region_name - if region is None: - region = DEFAULT_REGION + region = get_region_name() ec2_client = get_ec2_client(region) ec2_instance_id = get_ec2_instance_id() ec2_availability_zone = get_availability_zone() - ec2_resource = boto3.resource('ec2', region_name=region) + ec2_resource = get_ec2_resource(region) ec2_instance = ec2_resource.Instance(ec2_instance_id) for volume in ec2_instance.volumes.all(): @@ -469,7 +485,7 @@ def mount_ebs(snapshot_hint, repository_name, project, pipeline, branch, platfor def unmount_ebs(): region = get_region_name() ec2_instance_id = get_ec2_instance_id() - ec2_resource = boto3.resource('ec2', region_name=region) + ec2_resource = get_ec2_resource(region) ec2_instance = ec2_resource.Instance(ec2_instance_id) if os.path.isfile('envinject.properties'): From a5cd1b55e4c19b133f6c55fd858c27298cb9c282 Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Fri, 8 Oct 2021 10:37:50 -0700 Subject: [PATCH 145/293] Make the access log bucket optional in the AWSCore CDK application (#4553) * Make the access log bucket optional in the AWSCore CDK application Signed-off-by: Junbo Liang --- Gems/AWSCore/cdk/README.md | 10 +++++ Gems/AWSCore/cdk/app.py | 5 ++- Gems/AWSCore/cdk/core/core_stack.py | 37 ++++++++++--------- .../cdk/example/example_resources_stack.py | 18 +++++---- .../Windows/deploy_cdk_applications.cmd | 2 +- 5 files changed, 44 insertions(+), 28 deletions(-) diff --git a/Gems/AWSCore/cdk/README.md b/Gems/AWSCore/cdk/README.md index e4c0335c9c..d50ca40279 100644 --- a/Gems/AWSCore/cdk/README.md +++ b/Gems/AWSCore/cdk/README.md @@ -64,6 +64,16 @@ To add additional dependencies, for example other CDK libraries, just add them to your `setup.py` file and rerun the `pip install -r requirements.txt` command. +## Optional Features +Server access logging is enabled by default. To disable the feature, use the following commands to synthesize and deploy this CDK application. + +``` +$ cdk synth -c disable_access_log=true --all +$ cdk deploy -c disable_access_log=true --all +``` + +See https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerLogs.html for more information about server access logging. + ## Useful commands * `cdk ls` list all stacks in the app diff --git a/Gems/AWSCore/cdk/app.py b/Gems/AWSCore/cdk/app.py index 16773b5f69..9a401033ef 100755 --- a/Gems/AWSCore/cdk/app.py +++ b/Gems/AWSCore/cdk/app.py @@ -57,8 +57,9 @@ example_stack = ExampleResources( tags={Constants.O3DE_PROJECT_TAG_NAME: PROJECT_NAME, Constants.O3DE_FEATURE_TAG_NAME: FEATURE_NAME}, env=env ) -# -# Add the common stack as a dependency of the feature stack + +# Add the core stack as a dependency of the feature stack since the feature stack +# requires the core stack outputs for deployment. example_stack.add_dependency(core_construct.common_stack) app.synth() diff --git a/Gems/AWSCore/cdk/core/core_stack.py b/Gems/AWSCore/cdk/core/core_stack.py index fc1b4cf8d8..c124cb72ab 100755 --- a/Gems/AWSCore/cdk/core/core_stack.py +++ b/Gems/AWSCore/cdk/core/core_stack.py @@ -60,17 +60,6 @@ class CoreStack(core.Stack): type='TAG_FILTERS_1_0') ) - # Create an S3 bucket for Amazon S3 server access logging - # See https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html - self._server_access_logs_bucket = s3.Bucket( - self, - f'{self._project_name}-{self._feature_name}-Access-Log-Bucket', - block_public_access=s3.BlockPublicAccess.BLOCK_ALL, - encryption=s3.BucketEncryption.S3_MANAGED, - access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE - ) - self._server_access_logs_bucket.grant_read(self._admin_group) - # Define exports # Export resource group self._resource_group_output = core.CfnOutput( @@ -94,10 +83,22 @@ class CoreStack(core.Stack): export_name=f"{self._project_name}:AdminGroup", value=self._admin_group.group_arn) - # Export access log bucket name - self._server_access_logs_bucket_output = core.CfnOutput( - self, - id=f'ServerAccessLogsBucketOutput', - description='Name of the S3 bucket for storing server access logs generated by the sample CDK application(s)', - export_name=f"{self._project_name}:ServerAccessLogsBucket", - value=self._server_access_logs_bucket.bucket_name) + # Create an S3 bucket for Amazon S3 server access logging + # See https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html + if self.node.try_get_context('disable_access_log') != 'true': + self._server_access_logs_bucket = s3.Bucket( + self, + f'{self._project_name}-{self._feature_name}-Access-Log-Bucket', + block_public_access=s3.BlockPublicAccess.BLOCK_ALL, + encryption=s3.BucketEncryption.S3_MANAGED, + access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE + ) + self._server_access_logs_bucket.grant_read(self._admin_group) + + # Export access log bucket name + self._server_access_logs_bucket_output = core.CfnOutput( + self, + id=f'ServerAccessLogsBucketOutput', + description='Name of the S3 bucket for storing server access logs generated by the sample CDK application(s)', + export_name=f"{self._project_name}:ServerAccessLogsBucket", + value=self._server_access_logs_bucket.bucket_name) diff --git a/Gems/AWSCore/cdk/example/example_resources_stack.py b/Gems/AWSCore/cdk/example/example_resources_stack.py index 23bc78d8fc..ac229cb313 100755 --- a/Gems/AWSCore/cdk/example/example_resources_stack.py +++ b/Gems/AWSCore/cdk/example/example_resources_stack.py @@ -118,19 +118,23 @@ class ExampleResources(core.Stack): # https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html # 3. Enable Amazon S3 server access logging # https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerLogs.html - server_access_logs_bucket = s3.Bucket.from_bucket_name( - self, - f'{self._project_name}-{self._feature_name}-ImportedAccessLogsBucket', - core.Fn.import_value(f"{self._project_name}:ServerAccessLogsBucket") - ) + server_access_logs_bucket = None + if self.node.try_get_context('disable_access_log') != 'true': + server_access_logs_bucket = s3.Bucket.from_bucket_name( + self, + f'{self._project_name}-{self._feature_name}-ImportedAccessLogsBucket', + core.Fn.import_value(f"{self._project_name}:ServerAccessLogsBucket") + ) example_bucket = s3.Bucket( self, f'{self._project_name}-{self._feature_name}-Example-S3bucket', block_public_access=s3.BlockPublicAccess.BLOCK_ALL, encryption=s3.BucketEncryption.S3_MANAGED, - server_access_logs_bucket=server_access_logs_bucket, - server_access_logs_prefix=f'{self._project_name}-{self._feature_name}-{self.region}-AccessLogs' + server_access_logs_bucket= + server_access_logs_bucket if server_access_logs_bucket else None, + server_access_logs_prefix= + f'{self._project_name}-{self._feature_name}-{self.region}-AccessLogs' if server_access_logs_bucket else None ) s3_deployment.BucketDeployment( diff --git a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd index 2845707923..54a2485360 100644 --- a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd +++ b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd @@ -57,7 +57,7 @@ IF ERRORLEVEL 1 ( exit /b 1 ) -CALL :DeployCDKApplication AWSCore --all +CALL :DeployCDKApplication AWSCore --all "-c disable_access_log=true" IF ERRORLEVEL 1 ( exit /b 1 ) From 960edf857da0fce5f57ab7f0049b56fcf394c439 Mon Sep 17 00:00:00 2001 From: Pip Potter <61438964+lmbr-pip@users.noreply.github.com> Date: Fri, 8 Oct 2021 11:20:09 -0700 Subject: [PATCH 146/293] LYN-4831: AWCore code cleanup pass, fixing issues with ResolvePath (#4538) Signed-off-by: rppotter --- .../Code/Include/Private/AWSCoreModule.h | 2 +- .../Configuration/AWSCoreConfiguration.h | 2 +- .../Credential/AWSDefaultCredentialHandler.h | 2 +- .../AWSCoreAttributionConsentDialog.h | 7 ++-- .../Attribution/AWSCoreAttributionConstant.h | 2 +- .../Private/Editor/UI/AWSCoreEditorMenu.h | 2 +- .../AWSResourceMappingManager.h | 2 +- .../Public/Framework/AWSApiClientJobConfig.h | 9 ++---- .../Code/Include/Public/Framework/AWSApiJob.h | 7 ++-- .../Public/Framework/AWSApiJobConfig.h | 7 ++-- .../Public/Framework/AWSApiRequestJob.h | 6 ++-- .../Public/Framework/HttpClientComponent.h | 4 +-- .../Include/Public/Framework/HttpRequestJob.h | 2 +- .../Public/Framework/JsonObjectHandler.h | 8 ++--- .../Include/Public/Framework/JsonWriter.h | 4 +-- .../Include/Public/Framework/RequestBuilder.h | 2 +- .../Public/Framework/ServiceClientJobConfig.h | 7 ++-- .../Public/Framework/ServiceRequestJob.h | 8 ++--- .../Framework/ServiceRequestJobConfig.h | 3 -- .../Source/AWSCoreEditorSystemComponent.cpp | 4 +-- .../AWSCoreAttributionConsentDialog.cpp | 3 +- .../Attribution/AWSCoreAttributionManager.cpp | 32 +++++++++++-------- .../Source/Editor/UI/AWSCoreEditorMenu.cpp | 4 +-- .../Code/Source/Framework/AWSApiJob.cpp | 4 --- .../Source/Framework/MultipartFormData.cpp | 2 +- .../Code/Source/Framework/RequestBuilder.cpp | 4 +++ .../AWSResourceMappingManager.cpp | 3 +- .../AWSScriptBehaviorDynamoDB.cpp | 2 +- .../Code/Tests/AWSCoreSystemComponentTest.cpp | 2 +- .../AWSCVarCredentialHandlerTest.cpp | 2 +- .../Tests/Credential/AWSCredentialBusTest.cpp | 16 +++++----- .../AWSDefaultCredentialHandlerTest.cpp | 2 +- .../Framework/AWSApiClientJobConfigTest.cpp | 5 +++ .../Framework/ServiceClientJobConfigTest.cpp | 2 +- .../AWSResourceMappingManagerTest.cpp | 4 +-- .../AWSResourceMappingUtilsTest.cpp | 6 ++-- .../AWSScriptBehaviorDynamoDBTest.cpp | 2 +- .../AWSScriptBehaviorLambdaTest.cpp | 2 +- .../ScriptCanvas/AWSScriptBehaviorS3Test.cpp | 2 +- .../Code/Tests/TestFramework/AWSCoreFixture.h | 4 +-- 40 files changed, 91 insertions(+), 102 deletions(-) diff --git a/Gems/AWSCore/Code/Include/Private/AWSCoreModule.h b/Gems/AWSCore/Code/Include/Private/AWSCoreModule.h index ae5b424e69..f03579a0dd 100644 --- a/Gems/AWSCore/Code/Include/Private/AWSCoreModule.h +++ b/Gems/AWSCore/Code/Include/Private/AWSCoreModule.h @@ -24,7 +24,7 @@ namespace AWSCore /** * Add required SystemComponents to the SystemEntity. */ - virtual AZ::ComponentTypeList GetRequiredSystemComponents() const override; + AZ::ComponentTypeList GetRequiredSystemComponents() const override; }; } diff --git a/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h b/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h index 9834f9ca38..dd9f22f04d 100644 --- a/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h +++ b/Gems/AWSCore/Code/Include/Private/Configuration/AWSCoreConfiguration.h @@ -42,7 +42,7 @@ namespace AWSCore AWSCoreConfiguration(); - ~AWSCoreConfiguration() = default; + ~AWSCoreConfiguration() override = default; void ActivateConfig(); void DeactivateConfig(); diff --git a/Gems/AWSCore/Code/Include/Private/Credential/AWSDefaultCredentialHandler.h b/Gems/AWSCore/Code/Include/Private/Credential/AWSDefaultCredentialHandler.h index 7f021f5748..068addfc24 100644 --- a/Gems/AWSCore/Code/Include/Private/Credential/AWSDefaultCredentialHandler.h +++ b/Gems/AWSCore/Code/Include/Private/Credential/AWSDefaultCredentialHandler.h @@ -23,7 +23,7 @@ namespace AWSCore { public: AWSDefaultCredentialHandler(); - ~AWSDefaultCredentialHandler() = default; + ~AWSDefaultCredentialHandler() override = default; //! Activate handler and its credentials provider, make sure activation //! invoked after AWSNativeSDK init to avoid memory leak diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConsentDialog.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConsentDialog.h index c2194ccfb4..8a3445c742 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConsentDialog.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConsentDialog.h @@ -15,13 +15,12 @@ namespace AWSCore { //! Defines AWSCoreAttributionConsent QT dialog as QT message box. - class AWSCoreAttributionConsentDialog : - public QMessageBox + class AWSCoreAttributionConsentDialog + : public QMessageBox { public: AZ_CLASS_ALLOCATOR(AWSCoreAttributionConsentDialog, AZ::SystemAllocator, 0); AWSCoreAttributionConsentDialog(); - virtual ~AWSCoreAttributionConsentDialog() = default; - + ~AWSCoreAttributionConsentDialog() override = default; }; } // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h index e8a034e8e9..49c533cef5 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h @@ -18,4 +18,4 @@ namespace AWSCore static constexpr char AwsAttributionAttributeKeyActiveAWSGems[] = "aws_gems"; static constexpr char AwsAttributionAttributeKeyTimestamp[] = "timestamp"; -} // namespace AWSCOre +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h index 39e96517a7..62f91d36ef 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h @@ -34,7 +34,7 @@ namespace AWSCore "Failed to launch Resource Mapping Tool, please check logs for details."; AWSCoreEditorMenu(const QString& text); - ~AWSCoreEditorMenu(); + ~AWSCoreEditorMenu() override; private: QAction* AddExternalLinkAction(const AZStd::string& name, const AZStd::string& url, const AZStd::string& icon = ""); diff --git a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h index fbc37622bf..27ff275630 100644 --- a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h +++ b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingManager.h @@ -71,7 +71,7 @@ namespace AWSCore }; AWSResourceMappingManager(); - ~AWSResourceMappingManager() = default; + ~AWSResourceMappingManager() override = default; void ActivateManager(); void DeactivateManager(); diff --git a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiClientJobConfig.h b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiClientJobConfig.h index e991b2af7e..d14509550e 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiClientJobConfig.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiClientJobConfig.h @@ -64,9 +64,6 @@ namespace AWSCore /// Initialize an AwsApiClientJobConfig object. /// - /// \param DefaultConfigType - the type of the config object from which - /// default values will be taken. - /// /// \param defaultConfig - the config object that provides values when /// no override has been set in this object. The default is nullptr, which /// will cause a default value to be used. @@ -83,10 +80,10 @@ namespace AWSCore } } - virtual ~AwsApiClientJobConfig() = default; + ~AwsApiClientJobConfig() override = default; /// Gets a client initialized used currently applied settings. If - /// any settings change after first use, code must call + /// any settings change after first use, code must call /// ApplySettings before those changes will take effect. std::shared_ptr GetClient() override { @@ -112,7 +109,7 @@ namespace AWSCore } else { - // If no explict credenitals are provided then AWS C++ SDK will perform standard search + // If no explicit credentials are provided then AWS C++ SDK will perform standard search return std::make_shared(Aws::Auth::AWSCredentials(), GetClientConfiguration()); } } diff --git a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJob.h b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJob.h index 00949011cb..93fc75feed 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJob.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJob.h @@ -14,14 +14,12 @@ namespace AWSCore { - - /// Base class for all AWS jobs. Primarily exists so that + /// Base class for all AWS jobs. Primarily exists so that /// AwsApiJob::s_config can be used for settings that apply to /// all AWS jobs. class AwsApiJob : public AZ::Job { - public: // To use a different allocator, extend this class and use this macro. AZ_CLASS_ALLOCATOR(AwsApiJob, AZ::SystemAllocator, 0); @@ -33,11 +31,10 @@ namespace AWSCore protected: AwsApiJob(bool isAutoDelete, IConfig* config = GetDefaultConfig()); - virtual ~AwsApiJob(); + ~AwsApiJob() override = default; /// Used for error messages. static const char* COMPONENT_DISPLAY_NAME; - }; } // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h index 0f25c648d0..516b42c0dd 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiJobConfig.h @@ -96,9 +96,6 @@ namespace AWSCore /// Initialize an AwsApiClientJobConfig object. /// - /// \param DefaultConfigType - the type of the config object from which - /// default values will be taken. - /// /// \param defaultConfig - the config object that provides values when /// no override has been set in this object. The default is nullptr, which /// will cause a default value to be used. @@ -146,7 +143,7 @@ namespace AWSCore #endif Override caFile; - /// Applys settings changes made after first use. + /// Applies settings changes made after first use. virtual void ApplySettings(); ////////////////////////////////////////////////////////////////////////// @@ -217,7 +214,7 @@ namespace AWSCore : protected AWSCoreNotificationsBus::Handler { public: - ~AwsApiJobConfigHolder() + ~AwsApiJobConfigHolder() override { AWSCoreNotificationsBus::Handler::BusDisconnect(); } diff --git a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiRequestJob.h b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiRequestJob.h index c189e94f22..80ac6657ed 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/AWSApiRequestJob.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/AWSApiRequestJob.h @@ -145,10 +145,10 @@ namespace AWSCore AWS_API_REQUEST_TRAITS_TEMPLATE_DEFINITION_HELPER typename AWS_API_REQUEST_TRAITS_TEMPLATE_INSTANCE_HELPER::AsyncFunctionType AWS_API_REQUEST_TRAITS_TEMPLATE_INSTANCE_HELPER::AsyncFunction = _AsyncFunction; - /// Macro that simplifies the declaration of an AwsRequstJob that has a result. + /// Macro that simplifies the declaration of an AwsRequestJob that has a result. #define AWS_API_REQUEST_JOB(SERVICE, REQUEST) AWSCore::AwsApiRequestJob -/// Macro that simplifies the declaration of an AwsRequstJob that has no result. +/// Macro that simplifies the declaration of an AwsRequestJob that has no result. #define AWS_API_REQUEST_JOB_NO_RESULT(SERVICE, REQUEST) AWSCore::AwsApiRequestJob /// An Az::Job that that executes a specific AWS request. @@ -257,7 +257,7 @@ namespace AWSCore /// of request data until your running on the job's worker thread, /// instead of setting the request data before calling Start. /// - /// \param true if the request should be made. + /// \return true if the request should be made. virtual bool PrepareRequest() { return true; diff --git a/Gems/AWSCore/Code/Include/Public/Framework/HttpClientComponent.h b/Gems/AWSCore/Code/Include/Public/Framework/HttpClientComponent.h index f936e7f107..48b59cc56a 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/HttpClientComponent.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/HttpClientComponent.h @@ -39,7 +39,7 @@ namespace AWSCore : public AZ::ComponentBus { public: - virtual ~HttpClientComponentNotifications() {} + ~HttpClientComponentNotifications() override = default; virtual void OnHttpRequestSuccess(int responseCode, AZStd::string responseBody) {} virtual void OnHttpRequestFailure(int responseCode) {} }; @@ -55,7 +55,7 @@ namespace AWSCore { public: AZ_COMPONENT(HttpClientComponent, "{23ECDBDF-129A-4670-B9B4-1E0B541ACD61}"); - virtual ~HttpClientComponent() = default; + ~HttpClientComponent() override = default; void Init() override; void Activate() override; diff --git a/Gems/AWSCore/Code/Include/Public/Framework/HttpRequestJob.h b/Gems/AWSCore/Code/Include/Public/Framework/HttpRequestJob.h index 60bb0ffd34..b277340be9 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/HttpRequestJob.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/HttpRequestJob.h @@ -178,7 +178,7 @@ namespace AWSCore }; /// Override to process the response to the HTTP request before callbacks are fired. - /// WARNING: This gets called on the job's thread, so observe thread safety precations. + /// WARNING: This gets called on the job's thread, so observe thread safety precautions. virtual void ProcessResponse(const std::shared_ptr& response) { AZ_UNUSED(response); diff --git a/Gems/AWSCore/Code/Include/Public/Framework/JsonObjectHandler.h b/Gems/AWSCore/Code/Include/Public/Framework/JsonObjectHandler.h index 57eabe3593..e86db54bbf 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/JsonObjectHandler.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/JsonObjectHandler.h @@ -29,24 +29,24 @@ namespace AWSCore Ch Peek() const { int c = m_is.peek(); - return c == std::char_traits::eof() ? '\0' : (Ch)c; + return c == std::char_traits::eof() ? '\0' : static_cast(c); } Ch Take() { int c = m_is.get(); - return c == std::char_traits::eof() ? '\0' : (Ch)c; + return c == std::char_traits::eof() ? '\0' : static_cast(c); } size_t Tell() const { - return (size_t)m_is.tellg(); + return static_cast(m_is.tellg()); } Ch* PutBegin() { AZ_Assert(false, "Not Implemented"); - return 0; + return nullptr; } void Put(Ch) diff --git a/Gems/AWSCore/Code/Include/Public/Framework/JsonWriter.h b/Gems/AWSCore/Code/Include/Public/Framework/JsonWriter.h index 8b3f4d55b2..261907b7ec 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/JsonWriter.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/JsonWriter.h @@ -161,7 +161,7 @@ namespace AWSCore } /// Write JSON format content directly to the writer's output stream. - /// This can be used to efficently output static content. + /// This can be used to efficiently output static content. bool WriteJson(const Ch* json) { if (json) @@ -182,7 +182,7 @@ namespace AWSCore } /// Write an object. The object can implement a WriteJson function - /// or you can provide an GobalWriteJson template function + /// or you can provide an GlobalWriteJson template function /// specialization. template bool Object(const ObjectType& obj) diff --git a/Gems/AWSCore/Code/Include/Public/Framework/RequestBuilder.h b/Gems/AWSCore/Code/Include/Public/Framework/RequestBuilder.h index 1e4b7c34c2..c12e8b1d5c 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/RequestBuilder.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/RequestBuilder.h @@ -36,7 +36,7 @@ namespace AWSCore class RequestBuilder { public: - RequestBuilder() = default; + RequestBuilder(); /// Converts the provided object to JSON and sends it as the /// body of the request. The object can implement the following diff --git a/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h b/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h index 9082498e96..89141bb492 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h @@ -20,7 +20,7 @@ namespace AWSCore { public: - virtual const AZStd::string GetServiceUrl() = 0; + virtual AZStd::string GetServiceUrl() = 0; }; /// Encapsulates what code needs to know about a service in order to @@ -81,9 +81,6 @@ namespace AWSCore /// Initialize an ServiceClientJobConfig object. /// - /// \param DefaultConfigType - the type of the config object from which - /// default values will be taken. - /// /// \param defaultConfig - the config object that provides values when /// no override has been set in this object. The default is nullptr, which /// will cause a default value to be used. @@ -102,7 +99,7 @@ namespace AWSCore /// This implementation assumes the caller will cache this value as /// needed. See it's use in ServiceRequestJobConfig. - const AZStd::string GetServiceUrl() override + AZStd::string GetServiceUrl() override { if (endpointOverride.has_value()) { diff --git a/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJob.h b/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJob.h index cd0686c2d0..c24387a7ba 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJob.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJob.h @@ -119,7 +119,7 @@ namespace AWSCore Error error; /// Determines if the AWS credentials, as supplied by the credentialsProvider from - /// the ServiceReqestJobConfig object (which defaults to the user's credentials), + /// the ServiceRequestJobConfig object (which defaults to the user's credentials), /// are used to sign the request. The default is true. Override this and return false /// if calling a public API and want to avoid the overhead of signing requests. bool UseAWSCredentials() { @@ -565,13 +565,11 @@ namespace AWSCore } AZStd::string requestContent; - AZStd::string responseContent; - - std::istreambuf_iterator eos; std::shared_ptr requestStream = response->GetOriginatingRequest().GetContentBody(); if (requestStream) { + std::istreambuf_iterator eos; requestStream->clear(); requestStream->seekg(0); requestContent = AZStd::string{ std::istreambuf_iterator(*requestStream.get()),eos }; @@ -584,7 +582,7 @@ namespace AWSCore Aws::IOStream& responseStream = response->GetResponseBody(); responseStream.clear(); responseStream.seekg(0); - responseContent = AZStd::string{ std::istreambuf_iterator(responseStream),responseEos }; + AZStd::string responseContent = AZStd::string{ std::istreambuf_iterator(responseStream), responseEos }; responseContent = EscapePercentCharsInString(responseContent); responseStream.seekg(0); diff --git a/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJobConfig.h b/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJobConfig.h index 10b14ed5af..6c4e884f49 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJobConfig.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/ServiceRequestJobConfig.h @@ -44,9 +44,6 @@ namespace AWSCore /// Initialize an ServiceRequestJobConfig object. /// - /// \param DefaultConfigType - the type of the config object from which - /// default values will be taken. - /// /// \param defaultConfig - the config object that provides values when /// no override has been set in this object. The default is nullptr, which /// will cause a default value to be used. diff --git a/Gems/AWSCore/Code/Source/AWSCoreEditorSystemComponent.cpp b/Gems/AWSCore/Code/Source/AWSCoreEditorSystemComponent.cpp index f4420cb40a..a522f71084 100644 --- a/Gems/AWSCore/Code/Source/AWSCoreEditorSystemComponent.cpp +++ b/Gems/AWSCore/Code/Source/AWSCoreEditorSystemComponent.cpp @@ -79,7 +79,7 @@ namespace AWSCore QMenuBar* menuBar = mainWindow->menuBar(); QList actionList = menuBar->actions(); QAction* insertPivot = nullptr; - for (QList::iterator itr = actionList.begin(); itr != actionList.end(); itr++) + for (QList::iterator itr = actionList.begin(); itr != actionList.end(); ++itr) { if (QString::compare((*itr)->text(), EDITOR_HELP_MENU_TEXT) == 0) { @@ -88,7 +88,7 @@ namespace AWSCore } } - auto menu = m_awsCoreEditorManager->GetAWSCoreEditorMenu(); + const auto menu = m_awsCoreEditorManager->GetAWSCoreEditorMenu(); if (insertPivot) { menuBar->insertMenu(insertPivot, menu); diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionConsentDialog.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionConsentDialog.cpp index 85912616c2..7ec9f9ea4f 100644 --- a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionConsentDialog.cpp +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionConsentDialog.cpp @@ -35,8 +35,7 @@ namespace AWSCore this->setDefaultButton(QMessageBox::Save); this->button(QMessageBox::Cancel)->hide(); this->setIcon(QMessageBox::Information); - QGridLayout* layout = (QGridLayout*)this->layout(); - if (layout) + if (QGridLayout* layout = static_cast(this->layout())) { layout->setVerticalSpacing(20); layout->setHorizontalSpacing(10); diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp index 712c083e7a..3b9352d250 100644 --- a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp @@ -68,19 +68,19 @@ namespace AWSCore AZ_Assert(fileIO, "File IO is not initialized."); // Resolve path to editor_aws_preferences.setreg - AZStd::string editorAWSPreferencesFilePath = + const AZStd::string editorAWSPreferencesFilePath = AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName); - AZStd::array resolvedPathAWSPreference{}; - if (!fileIO->ResolvePath(editorAWSPreferencesFilePath.c_str(), resolvedPathAWSPreference.data(), resolvedPathAWSPreference.size())) + AZ::IO::FixedMaxPath resolvedPathAWSPreference; + if (!fileIO->ResolvePath(resolvedPathAWSPreference, AZ::IO::PathView(editorAWSPreferencesFilePath))) { - AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.data()); + AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.c_str()); return; } - if (fileIO->Exists(resolvedPathAWSPreference.data())) + if (fileIO->Exists(resolvedPathAWSPreference.c_str())) { m_settingsRegistry->MergeSettingsFile( - resolvedPathAWSPreference.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + resolvedPathAWSPreference.String(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); } } @@ -136,8 +136,8 @@ namespace AWSCore return true; } - AZStd::chrono::seconds lastSendTimeStamp = AZStd::chrono::seconds(lastSendTimeStampSeconds); - AZStd::chrono::seconds secondsSinceLastSend = + const AZStd::chrono::seconds lastSendTimeStamp = AZStd::chrono::seconds(lastSendTimeStampSeconds); + const AZStd::chrono::seconds secondsSinceLastSend = AZStd::chrono::duration_cast(AZStd::chrono::system_clock::now().time_since_epoch()) - lastSendTimeStamp; if (static_cast(secondsSinceLastSend.count()) >= delayInSeconds) { @@ -154,7 +154,7 @@ namespace AWSCore if (credentialResult.result) { std::shared_ptr provider = credentialResult.result; - auto creds = provider->GetAWSCredentials(); + const auto creds = provider->GetAWSCredentials(); if (!creds.IsEmpty()) { return true; @@ -200,9 +200,13 @@ namespace AWSCore AZ_Assert(fileIO, "File IO is not initialized."); // Resolve path to editor_aws_preferences.setreg - AZStd::string editorPreferencesFilePath = AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName); - AZStd::array resolvedPath {}; - fileIO->ResolvePath(editorPreferencesFilePath.c_str(), resolvedPath.data(), resolvedPath.size()); + const AZStd::string editorPreferencesFilePath = AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName); + AZ::IO::FixedMaxPath resolvedPathAWSPreference; + if (!fileIO->ResolvePath(resolvedPathAWSPreference, AZ::IO::PathView(editorPreferencesFilePath))) + { + AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", editorPreferencesFilePath.c_str()); + return; + } AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings; dumperSettings.m_prettifyOutput = true; @@ -215,14 +219,14 @@ namespace AWSCore { AZ_Warning( "AWSAttributionManager", false, R"(Unable to save changes to the Editor AWS Preferences registry file at "%s"\n)", - resolvedPath.data()); + resolvedPathAWSPreference.c_str()); return; } bool saved {}; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; - if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode)) + if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPathAWSPreference.c_str(), configurationMode)) { saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size(); } diff --git a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp index d55510930e..6391dd94ee 100644 --- a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp +++ b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp @@ -54,7 +54,7 @@ namespace AWSCore { if (m_resourceMappingToolWatcher->IsProcessRunning()) { - m_resourceMappingToolWatcher->TerminateProcess(AZ::u32(-1)); + m_resourceMappingToolWatcher->TerminateProcess(static_cast(-1)); } m_resourceMappingToolWatcher.reset(); } @@ -214,7 +214,7 @@ namespace AWSCore QMenu* AWSCoreEditorMenu::SetAWSFeatureSubMenu(const AZStd::string& menuText) { auto actionList = this->actions(); - for (QList::iterator itr = actionList.begin(); itr != actionList.end(); itr++) + for (QList::iterator itr = actionList.begin(); itr != actionList.end(); ++itr) { if (QString::compare((*itr)->text(), menuText.c_str()) == 0) { diff --git a/Gems/AWSCore/Code/Source/Framework/AWSApiJob.cpp b/Gems/AWSCore/Code/Source/Framework/AWSApiJob.cpp index f203506edd..34581e00ff 100644 --- a/Gems/AWSCore/Code/Source/Framework/AWSApiJob.cpp +++ b/Gems/AWSCore/Code/Source/Framework/AWSApiJob.cpp @@ -22,10 +22,6 @@ namespace AWSCore { } - AwsApiJob::~AwsApiJob() - { - } - AwsApiJob::Config* AwsApiJob::GetDefaultConfig() { static AwsApiJobConfigHolder s_configHolder{}; diff --git a/Gems/AWSCore/Code/Source/Framework/MultipartFormData.cpp b/Gems/AWSCore/Code/Source/Framework/MultipartFormData.cpp index ff4668a62b..47059ac156 100644 --- a/Gems/AWSCore/Code/Source/Framework/MultipartFormData.cpp +++ b/Gems/AWSCore/Code/Source/Framework/MultipartFormData.cpp @@ -49,7 +49,7 @@ namespace AWSCore { m_fileFields.emplace_back(FileField{ std::move(fieldName), std::move(fileName) , AZStd::vector{} }); m_fileFields.back().m_fileData.reserve(length); - m_fileFields.back().m_fileData.assign((const char*)bytes, (const char*)bytes + length); + m_fileFields.back().m_fileData.assign(static_cast(bytes), static_cast(bytes) + length); } void MultipartFormData::SetCustomBoundary(AZStd::string boundary) diff --git a/Gems/AWSCore/Code/Source/Framework/RequestBuilder.cpp b/Gems/AWSCore/Code/Source/Framework/RequestBuilder.cpp index 16a5163fc7..d32ec9d039 100644 --- a/Gems/AWSCore/Code/Source/Framework/RequestBuilder.cpp +++ b/Gems/AWSCore/Code/Source/Framework/RequestBuilder.cpp @@ -10,6 +10,10 @@ namespace AWSCore { + RequestBuilder::RequestBuilder() + : m_httpMethod(Aws::Http::HttpMethod::HTTP_GET) + { + } bool RequestBuilder::SetPathParameterUnescaped(const char* key, const char* value) { diff --git a/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp b/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp index c3d87bff86..faec07b19e 100644 --- a/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp +++ b/Gems/AWSCore/Code/Source/ResourceMapping/AWSResourceMappingManager.cpp @@ -26,7 +26,6 @@ namespace AWSCore : m_status(Status::NotLoaded) , m_defaultAccountId("") , m_defaultRegion("") - , m_resourceMappings() { } @@ -164,7 +163,7 @@ namespace AWSCore m_defaultRegion = jsonDocument.FindMember(ResourceMappingRegionKeyName)->value.GetString(); auto resourceMappings = jsonDocument.FindMember(ResourceMappingResourcesKeyName)->value.GetObject(); - for (auto mappingIter = resourceMappings.MemberBegin(); mappingIter != resourceMappings.MemberEnd(); mappingIter++) + for (auto mappingIter = resourceMappings.MemberBegin(); mappingIter != resourceMappings.MemberEnd(); ++mappingIter) { auto mappingValue = mappingIter->value.GetObject(); if (mappingValue.MemberCount() != 0) diff --git a/Gems/AWSCore/Code/Source/ScriptCanvas/AWSScriptBehaviorDynamoDB.cpp b/Gems/AWSCore/Code/Source/ScriptCanvas/AWSScriptBehaviorDynamoDB.cpp index 4467cc5db7..4183997d4a 100644 --- a/Gems/AWSCore/Code/Source/ScriptCanvas/AWSScriptBehaviorDynamoDB.cpp +++ b/Gems/AWSCore/Code/Source/ScriptCanvas/AWSScriptBehaviorDynamoDB.cpp @@ -71,7 +71,7 @@ namespace AWSCore [](DynamoDBGetItemRequestJob* job) // OnSuccess handler { auto item = job->result.GetItem(); - if (item.size() > 0) + if (!item.empty()) { DynamoDBAttributeValueMap result; for (const auto& itermPair : item) diff --git a/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp b/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp index f9fff631f4..648648e945 100644 --- a/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp +++ b/Gems/AWSCore/Code/Tests/AWSCoreSystemComponentTest.cpp @@ -40,7 +40,7 @@ public: AWSCoreNotificationsBus::Handler::BusConnect(); } - ~AWSCoreNotificationsBusMock() + ~AWSCoreNotificationsBusMock() override { AWSCoreNotificationsBus::Handler::BusDisconnect(); } diff --git a/Gems/AWSCore/Code/Tests/Credential/AWSCVarCredentialHandlerTest.cpp b/Gems/AWSCore/Code/Tests/Credential/AWSCVarCredentialHandlerTest.cpp index 73120d4adc..244c945af9 100644 --- a/Gems/AWSCore/Code/Tests/Credential/AWSCVarCredentialHandlerTest.cpp +++ b/Gems/AWSCore/Code/Tests/Credential/AWSCVarCredentialHandlerTest.cpp @@ -18,7 +18,7 @@ class AWSCVarCredentialHandlerTest { public: AWSCVarCredentialHandlerTest() = default; - virtual ~AWSCVarCredentialHandlerTest() = default; + ~AWSCVarCredentialHandlerTest() override = default; void SetUp() override { diff --git a/Gems/AWSCore/Code/Tests/Credential/AWSCredentialBusTest.cpp b/Gems/AWSCore/Code/Tests/Credential/AWSCredentialBusTest.cpp index 238b5c819c..82c8c84b81 100644 --- a/Gems/AWSCore/Code/Tests/Credential/AWSCredentialBusTest.cpp +++ b/Gems/AWSCore/Code/Tests/Credential/AWSCredentialBusTest.cpp @@ -36,14 +36,14 @@ public: m_credentialsProvider.reset(); } - int GetCredentialHandlerOrder() const + int GetCredentialHandlerOrder() const override { return 1; } - std::shared_ptr GetCredentialsProvider() + std::shared_ptr GetCredentialsProvider() override { - m_handlerCounter++; + ++m_handlerCounter; return m_credentialsProvider; } @@ -72,14 +72,14 @@ public: m_credentialsProvider.reset(); } - int GetCredentialHandlerOrder() const + int GetCredentialHandlerOrder() const override { return 2; } - std::shared_ptr GetCredentialsProvider() + std::shared_ptr GetCredentialsProvider() override { - m_handlerCounter++; + ++m_handlerCounter; return m_credentialsProvider; } @@ -115,10 +115,10 @@ public: TEST_F(AWSCredentialBusTest, GetCredentialsProvider_CallFromMultithread_GetExpectedCredentialsProviderAndNumberOfCalls) { - int testThreadNumber = 10; + constexpr int testThreadNumber = 10; AZStd::atomic actualEbusCalls = 0; AZStd::vector testThreadPool; - for (int index = 0; index < testThreadNumber; index++) + for (int index = 0; index < testThreadNumber; ++index) { testThreadPool.emplace_back(AZStd::thread([&]() { AWSCredentialResult result; diff --git a/Gems/AWSCore/Code/Tests/Credential/AWSDefaultCredentialHandlerTest.cpp b/Gems/AWSCore/Code/Tests/Credential/AWSDefaultCredentialHandlerTest.cpp index b3e2ec5738..af03afb337 100644 --- a/Gems/AWSCore/Code/Tests/Credential/AWSDefaultCredentialHandlerTest.cpp +++ b/Gems/AWSCore/Code/Tests/Credential/AWSDefaultCredentialHandlerTest.cpp @@ -49,7 +49,7 @@ class AWSDefaultCredentialHandlerTest { public: AWSDefaultCredentialHandlerTest() = default; - virtual ~AWSDefaultCredentialHandlerTest() = default; + ~AWSDefaultCredentialHandlerTest() override = default; void SetUp() override { diff --git a/Gems/AWSCore/Code/Tests/Framework/AWSApiClientJobConfigTest.cpp b/Gems/AWSCore/Code/Tests/Framework/AWSApiClientJobConfigTest.cpp index b49cdc6a71..db433062ad 100644 --- a/Gems/AWSCore/Code/Tests/Framework/AWSApiClientJobConfigTest.cpp +++ b/Gems/AWSCore/Code/Tests/Framework/AWSApiClientJobConfigTest.cpp @@ -23,6 +23,11 @@ class AWSApiClientJobConfigTest , public AWSCredentialRequestBus::Handler { public: + AWSApiClientJobConfigTest() + : m_credentialHandlerCounter(0) + { + } + void SetUp() override { AWSNativeSDKInit::InitializationManager::InitAwsApi(); diff --git a/Gems/AWSCore/Code/Tests/Framework/ServiceClientJobConfigTest.cpp b/Gems/AWSCore/Code/Tests/Framework/ServiceClientJobConfigTest.cpp index 7a45ffb739..9bc43482cd 100644 --- a/Gems/AWSCore/Code/Tests/Framework/ServiceClientJobConfigTest.cpp +++ b/Gems/AWSCore/Code/Tests/Framework/ServiceClientJobConfigTest.cpp @@ -84,7 +84,7 @@ class ServiceClientJobConfigTest void ReloadConfigFile(bool reloadConfigFileName = false) override { AZ_UNUSED(reloadConfigFileName); - }; + } }; TEST_F(ServiceClientJobConfigTest, GetServiceUrl_CreateServiceWithServiceNameOnly_GetExpectedFeatureServiceUrl) diff --git a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp index d438a99f83..fb03dea4c0 100644 --- a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp +++ b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp @@ -217,7 +217,7 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE); m_resourceMappingManager->ActivateManager(); - int testThreadNumber = 10; + constexpr int testThreadNumber = 10; AZStd::atomic actualEbusCalls = 0; AZStd::vector testThreadPool; for (int index = 0; index < testThreadNumber; index++) @@ -226,7 +226,7 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi AZStd::string actualAccountId; AWSResourceMappingRequestBus::BroadcastResult(actualAccountId, &AWSResourceMappingRequests::GetDefaultAccountId); EXPECT_FALSE(actualAccountId.empty()); - actualEbusCalls++; + ++actualEbusCalls; })); } diff --git a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingUtilsTest.cpp b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingUtilsTest.cpp index 9c23615917..f1a90aa2ae 100644 --- a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingUtilsTest.cpp +++ b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingUtilsTest.cpp @@ -44,19 +44,19 @@ TEST_F(AWSResourceMappingUtilsTest, FormatRESTApiUrl_PassingInvalidRESTApiId_Ret { auto actualUrl = AWSResourceMappingUtils::FormatRESTApiUrl("", TEST_VALID_RESTAPI_REGION, TEST_VALID_RESTAPI_STAGE); - EXPECT_TRUE(actualUrl == ""); + EXPECT_TRUE(actualUrl.empty()); } TEST_F(AWSResourceMappingUtilsTest, FormatRESTApiUrl_PassingInvalidRESTApiRegion_ReturnEmptyResult) { auto actualUrl = AWSResourceMappingUtils::FormatRESTApiUrl(TEST_VALID_RESTAPI_ID, "", TEST_VALID_RESTAPI_STAGE); - EXPECT_TRUE(actualUrl == ""); + EXPECT_TRUE(actualUrl.empty()); } TEST_F(AWSResourceMappingUtilsTest, FormatRESTApiUrl_PassingInvalidRESTApiStage_ReturnEmptyResult) { auto actualUrl = AWSResourceMappingUtils::FormatRESTApiUrl(TEST_VALID_RESTAPI_ID, TEST_VALID_RESTAPI_REGION, ""); - EXPECT_TRUE(actualUrl == ""); + EXPECT_TRUE(actualUrl.empty()); } diff --git a/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorDynamoDBTest.cpp b/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorDynamoDBTest.cpp index 52b91c306d..e42e270bc2 100644 --- a/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorDynamoDBTest.cpp +++ b/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorDynamoDBTest.cpp @@ -23,7 +23,7 @@ public: AWSScriptBehaviorDynamoDBNotificationBus::Handler::BusConnect(); } - ~AWSScriptBehaviorDynamoDBNotificationBusHandlerMock() + ~AWSScriptBehaviorDynamoDBNotificationBusHandlerMock() override { AWSScriptBehaviorDynamoDBNotificationBus::Handler::BusDisconnect(); } diff --git a/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorLambdaTest.cpp b/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorLambdaTest.cpp index 299f4a95d6..42ccd6eddc 100644 --- a/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorLambdaTest.cpp +++ b/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorLambdaTest.cpp @@ -22,7 +22,7 @@ public: AWSScriptBehaviorLambdaNotificationBus::Handler::BusConnect(); } - ~AWSScriptBehaviorLambdaNotificationBusHandlerMock() + ~AWSScriptBehaviorLambdaNotificationBusHandlerMock() override { AWSScriptBehaviorLambdaNotificationBus::Handler::BusDisconnect(); } diff --git a/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorS3Test.cpp b/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorS3Test.cpp index 118174576c..34a0166e32 100644 --- a/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorS3Test.cpp +++ b/Gems/AWSCore/Code/Tests/ScriptCanvas/AWSScriptBehaviorS3Test.cpp @@ -24,7 +24,7 @@ public: AWSScriptBehaviorS3NotificationBus::Handler::BusConnect(); } - ~AWSScriptBehaviorS3NotificationBusHandlerMock() + ~AWSScriptBehaviorS3NotificationBusHandlerMock() override { AWSScriptBehaviorS3NotificationBus::Handler::BusDisconnect(); } diff --git a/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h b/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h index a5c2bf6475..1d14484387 100644 --- a/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h +++ b/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h @@ -107,8 +107,8 @@ class AWSCoreFixture : public UnitTest::ScopedAllocatorSetupFixture { public: - AWSCoreFixture() {} - virtual ~AWSCoreFixture() = default; + AWSCoreFixture() = default; + ~AWSCoreFixture() override = default; void SetUp() override { From 73f8537030aaa5efd126c991e28e61c803fc560e Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 8 Oct 2021 11:41:46 -0700 Subject: [PATCH 147/293] Fix Issue saving new assets in Asset Editor on Linux (#4537) * Add helper function to apply a selected file filter from a file dialog to the result filename if needed * Add platform traits to restrict the use of the helper function on platforms that need to apply it * Fix building of file filters of multiple extensions for a file type Signed-off-by: Steve Pham --- .../Components/Widgets/FileDialog.cpp | 92 ++++++++++++++++++- .../Components/Widgets/FileDialog.h | 6 ++ .../Platform/Linux/platform_linux_files.cmake | 2 + .../Platform/Mac/platform_mac_files.cmake | 2 + .../Windows/platform_windows_files.cmake | 2 + .../AzQtComponents/Tests/FileDialogTests.cpp | 65 +++++++++++++ .../azqtcomponents_testing_files.cmake | 1 + Code/Framework/AzQtComponents/CMakeLists.txt | 5 + .../AzQtComponents_Traits_Linux.h | 11 +++ .../AzQtComponents_Traits_Platform.h | 10 ++ .../AzQtComponents_Traits_Mac.h | 11 +++ .../AzQtComponents_Traits_Platform.h | 10 ++ .../AzQtComponents_Traits_Platform.h | 10 ++ .../AzQtComponents_Traits_Windows.h | 11 +++ .../AssetEditor/AssetEditorWidget.cpp | 2 +- 15 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Tests/FileDialogTests.cpp create mode 100644 Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Linux.h create mode 100644 Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Platform.h create mode 100644 Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Mac.h create mode 100644 Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Platform.h create mode 100644 Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Platform.h create mode 100644 Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Windows.h diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.cpp index d2d773ff93..3061ceedd5 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.cpp @@ -6,10 +6,11 @@ * */ +#include #include #include -#include +#include namespace AzQtComponents { @@ -24,7 +25,12 @@ namespace AzQtComponents // Trigger Qt's save filename dialog // If filePath isn't empty, it means we are prompting again because the filename was invalid, // so pass it instead of the directory so the filename is pre-filled in for the user - filePath = QFileDialog::getSaveFileName(parent, caption, (filePath.isEmpty()) ? dir : filePath, filter, selectedFilter, options); + QString localSelectedFilter; + filePath = QFileDialog::getSaveFileName(parent, caption, (filePath.isEmpty()) ? dir : filePath, filter, &localSelectedFilter, options); + if (selectedFilter) + { + *selectedFilter = localSelectedFilter; + } if (!filePath.isEmpty()) { @@ -32,15 +38,39 @@ namespace AzQtComponents QString fileName = fileInfo.fileName(); // Check if the filename has any invalid characters - QRegExp validFileNameRegex("^[a-zA-Z0-9_\\-./]*$"); - shouldPromptAgain = !validFileNameRegex.exactMatch(fileName); + QRegularExpression validFileNameRegex("^[a-zA-Z0-9_\\-./]*$"); + QRegularExpressionMatch validFileNameMatch = validFileNameRegex.match(fileName); // If the filename had invalid characters, then show a warning message and then we will re-prompt the save filename dialog - if (shouldPromptAgain) + if (!validFileNameMatch.hasMatch()) { QMessageBox::warning(parent, QObject::tr("Invalid filename"), QObject::tr("O3DE assets are restricted to alphanumeric characters, hyphens (-), underscores (_), and dots (.)\n\n%1").arg(fileName)); + shouldPromptAgain = true; + continue; + } + else + { + shouldPromptAgain = false; + } +#if AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION + // If a filter was selected, then make sure that the resulting filename ends with that extension. On systems that use the default QFileDialog, + // the extension is not guaranteed to be set in the resulting filename + if (FileDialog::ApplyMissingExtension(localSelectedFilter, filePath)) + { + // If an extension had to be applied, then the file dialog did not handle the case of overwriting existing files. + // We need to check that condition before we proceed + QFileInfo updatedFilePath(filePath); + + if (updatedFilePath.exists()) + { + QMessageBox::StandardButton overwriteSelection = QMessageBox::question(parent, + QObject::tr("File exists"), + QObject::tr("%1 exists. Do you want to overwrite the existing file?").arg(updatedFilePath.fileName())); + shouldPromptAgain = (overwriteSelection == QMessageBox::No); + } } +#endif // AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION } else { @@ -51,4 +81,56 @@ namespace AzQtComponents return filePath; } + + bool FileDialog::ApplyMissingExtension(const QString& selectedFilter, QString& filePath) + { + if (selectedFilter.isEmpty()) + { + return false; + } + + // According to the QT documentation for QFileDialog, the selected filter will come in the form + // ( .. ) + // + // For example: + // "Images (*.gif *.png *.jpg)" + // + // Extract the contents of the (s) inside the parenthesis and split them based on a whitespace or comma + const QRegularExpression filterContent(".*\\((?[^\\)]+)\\)"); + QRegularExpressionMatch filterContentMatch = filterContent.match(selectedFilter); + if (!filterContentMatch.hasMatch()) + { + return false; + } + QString filterExtensionsString = filterContentMatch.captured("filters"); + QStringList filterExtensionsFull = filterExtensionsString.split(" ", Qt::SkipEmptyParts); + if (filterExtensionsFull.length() <= 0) + { + return false; + } + + // If there are multiple suffixes in the selected filter, then default to the first one if a suffix needs to be appended + QString defaultSuffix = filterExtensionsFull[0].mid(1); + + // Iterate through the filter patterns to see if the current filename matches + QFileInfo fileInfo(filePath); + bool extensionNeeded = true; + for (const QString& filterExtensionFull : filterExtensionsFull) + { + QString wildcardExpression = QRegularExpression::wildcardToRegularExpression(filterExtensionFull); + QRegularExpression filterPattern(wildcardExpression, AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY); + QRegularExpressionMatch filterPatternMatch = filterPattern.match(fileInfo.fileName()); + if (filterPatternMatch.hasMatch()) + { + // The filename matches one of the filter patterns already, the extension does not need to be added to the filename + extensionNeeded = false; + } + } + if (extensionNeeded) + { + // If the current (if any) suffix does not match, automatically add the default suffix for the selected filter + filePath.append(defaultSuffix); + } + return extensionNeeded; + } } // namespace AzQtComponents diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.h index 6b63404949..9f27431400 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/FileDialog.h @@ -24,6 +24,12 @@ namespace AzQtComponents static QString GetSaveFileName(QWidget* parent = nullptr, const QString& caption = QString(), const QString& dir = QString(), const QString& filter = QString(), QString* selectedFilter = nullptr, QFileDialog::Options options = QFileDialog::Options()); + + //! Helper method that parses a selected filter from Qt's QFileDialog::getSaveFileName and applies the + //! selected filter's extension to the filePath if it doesnt already have the extension. This is needed + //! on platforms that do not have a default file dialog (These platforms uses Qt's custom file dialog which will + //! not apply the filter's extension automatically on user entered filenames) + static bool ApplyMissingExtension(const QString& selectedFilter, QString& filePath); }; } // namespace AzQtComponents diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake index 7f204e5022..ec71d7b508 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake @@ -12,4 +12,6 @@ set(FILES ../../Utilities/QtWindowUtilities_linux.cpp ../../Utilities/ScreenGrabber_linux.cpp ../../../Platform/Linux/AzQtComponents/Components/StyledDockWidget_Linux.cpp + ../../../Platform/Linux/AzQtComponents/AzQtComponents_Traits_Linux.h + ../../../Platform/Linux/AzQtComponents/AzQtComponents_Traits_Platform.h ) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake index 50084d7a1e..18f9479289 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake @@ -12,4 +12,6 @@ set(FILES ../../Utilities/QtWindowUtilities_mac.mm ../../Utilities/ScreenGrabber_mac.mm ../../../Platform/Mac/AzQtComponents/Components/StyledDockWidget_Mac.cpp + ../../../Platform/Mac/AzQtComponents/AzQtComponents_Traits_Mac.h + ../../../Platform/Mac/AzQtComponents/AzQtComponents_Traits_Platform.h ) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake index 37d1d0f390..ca4145ef35 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake @@ -17,4 +17,6 @@ set(FILES ../../Components/TitleBarOverdrawScreenHandler_win.h ../../Components/TitleBarOverdrawScreenHandler_win.cpp ../../../Platform/Windows/AzQtComponents/Components/StyledDockWidget_Windows.cpp + ../../../Platform/Windows/AzQtComponents/AzQtComponents_Traits_Windows.h + ../../../Platform/Windows/AzQtComponents/AzQtComponents_Traits_Platform.h ) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Tests/FileDialogTests.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Tests/FileDialogTests.cpp new file mode 100644 index 0000000000..e3dc4b4f0d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Tests/FileDialogTests.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +TEST(AzQtComponents, ApplyMissingExtension_UpdateMissingExtension_Success) +{ + const QString textFiler{"Text Files (*.txt)"}; + QString testPath{"testFile"}; + bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath); + EXPECT_TRUE(result); + EXPECT_STRCASEEQ("testFile.txt", testPath.toUtf8().constData()); +} + +TEST(AzQtComponents, ApplyMissingExtension_NoUpdateExistingExtension_Success) +{ + const QString textFiler{"Text Files (*.txt)"}; + QString testPath{"testFile.txt"}; + bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath); + EXPECT_FALSE(result); + EXPECT_STRCASEEQ("testFile.txt", testPath.toUtf8().constData()); +} + +TEST(AzQtComponents, ApplyMissingExtension_UpdateMissingExtensionMultipleExtensionFilter_Success) +{ + const QString textFiler{"Image Files (*.jpg *.bmp *.png)"}; + QString testPath{"testFile"}; + bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath); + EXPECT_TRUE(result); + EXPECT_STRCASEEQ("testFile.jpg", testPath.toUtf8().constData()); +} + +TEST(AzQtComponents, ApplyMissingExtension_NoUpdateMissingExtensionMultipleExtensionFilter_Success) +{ + const QString textFiler{"Image Files (*.jpg *.bmp *.png)"}; + QString testPath{"testFile.png"}; + bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath); + EXPECT_FALSE(result); + EXPECT_STRCASEEQ("testFile.png", testPath.toUtf8().constData()); +} + +TEST(AzQtComponents, ApplyMissingExtension_NoUpdateMissingExtensionEmptyFilter_Success) +{ + const QString textFiler{""}; + QString testPath{"testFile"}; + bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath); + EXPECT_FALSE(result); + EXPECT_STRCASEEQ("testFile", testPath.toUtf8().constData()); +} + +TEST(AzQtComponents, ApplyMissingExtension_NoUpdateMissingExtensionInvalidFilter_Success) +{ + const QString textFiler{"Bad Filter!!"}; + QString testPath{"testFile"}; + bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath); + EXPECT_FALSE(result); + EXPECT_STRCASEEQ("testFile", testPath.toUtf8().constData()); +} diff --git a/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_testing_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_testing_files.cmake index 2611063305..b4ab487c79 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_testing_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_testing_files.cmake @@ -9,6 +9,7 @@ set(FILES Tests/AzQtComponentTests.cpp Tests/ColorControllerTests.cpp + Tests/FileDialogTests.cpp Tests/FloatToStringConversionTests.cpp Tests/HexParsingTests.cpp Tests/StyleSheetCacheTests.cpp diff --git a/Code/Framework/AzQtComponents/CMakeLists.txt b/Code/Framework/AzQtComponents/CMakeLists.txt index dd217a7be2..a24b68bcd7 100644 --- a/Code/Framework/AzQtComponents/CMakeLists.txt +++ b/Code/Framework/AzQtComponents/CMakeLists.txt @@ -10,6 +10,8 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) return() endif() +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) + ly_add_target( NAME AzQtComponents SHARED NAMESPACE AZ @@ -26,6 +28,7 @@ ly_add_target( AzQtComponents PUBLIC . + ${pal_dir} COMPILE_DEFINITIONS PRIVATE AZ_QT_COMPONENTS_EXPORT_SYMBOLS @@ -53,6 +56,7 @@ ly_add_target( . AzQtComponents AzQtComponents/Gallery + ${pal_dir} BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Svg @@ -86,6 +90,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) PRIVATE Tests AzQtComponents + ${pal_dir} BUILD_DEPENDENCIES PRIVATE AZ::AzQtComponents diff --git a/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Linux.h b/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Linux.h new file mode 100644 index 0000000000..685ac4dfed --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Linux.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION 1 +#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY QRegularExpression::NoPatternOption diff --git a/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Platform.h b/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Platform.h new file mode 100644 index 0000000000..101fe3a494 --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/AzQtComponents_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Mac.h b/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Mac.h new file mode 100644 index 0000000000..1cb91ec09e --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Mac.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION 0 +#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY QRegularExpression::NoPatternOption diff --git a/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Platform.h b/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Platform.h new file mode 100644 index 0000000000..9b285476c1 --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/AzQtComponents_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Platform.h b/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Platform.h new file mode 100644 index 0000000000..2c3efc5e6c --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include diff --git a/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Windows.h b/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Windows.h new file mode 100644 index 0000000000..edba0043b4 --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/AzQtComponents_Traits_Windows.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION 0 +#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY QRegularExpression::CaseInsensitiveOption diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp index 8856989911..a159882f72 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp @@ -410,7 +410,7 @@ namespace AzToolsFramework filter.append(ext); if (i < n - 1) { - filter.append(", "); + filter.append(" "); } } filter.append(")"); From b7c2401056ba31bd7cea0b5609bc08195479dd51 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 8 Oct 2021 15:14:22 -0500 Subject: [PATCH 148/293] Added a ThreadDispatch Policy to the EBus code (#4405) * Added a ThreadDispatch Policy to the EBus code The ThreadDispatch Policy can be configured by authors of an EBusTraits to invoke a callback function after an EBus has finished it's dispatching mechanism on a specific thread. It takes into account recursive calls as well and will only invoke the PostDispatch callback after all callstack entries for the current thread are cleared. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Clang build fix The Traits type is dependent on the template parameter, therefore the compiler needs to be told that the ThreadDispatchPolicy is a type and not a value. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed DispatchLockGuard cxall in the TerrainWorldRendererComponent.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added EBusTrait for configuring the DispatchLockGuard Removed the ThreadPolicy trait, now that the DispatchLockGuard for the EBus Context can be configured. Used the DispatchLockGuard template along with the IsInDispatchThisThread function to determine when an EBus has finished dispatching on thread and released it's Context Mutex. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Tweaked comment format for the IsInDispatch function Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed explicit GetContext call from ThreadDispatchTestBus. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Clang EBus Test fix for DispatchLockGuard trait Due to the clang compiler evalating constants within templates at the time of declaration, the LocklessDispatch value supplied to the template was always false resulting in the LocklessDispatch feature always locking. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/EBus/BusImpl.h | 26 ++- Code/Framework/AzCore/AzCore/EBus/EBus.h | 35 +++- Code/Framework/AzCore/Tests/EBus.cpp | 201 +++++++++++++++++++- 3 files changed, 243 insertions(+), 19 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/EBus/BusImpl.h b/Code/Framework/AzCore/AzCore/EBus/BusImpl.h index 8e655c0525..e2b1c2e92b 100644 --- a/Code/Framework/AzCore/AzCore/EBus/BusImpl.h +++ b/Code/Framework/AzCore/AzCore/EBus/BusImpl.h @@ -160,8 +160,8 @@ namespace AZ /** * Locking primitive that is used when executing events in the event queue. */ - using EventQueueMutexType = typename AZStd::Utils::if_c::value, // if EventQueueMutexType==NullMutex use MutexType otherwise EventQueueMutexType - MutexType, typename Traits::EventQueueMutexType>::type; + using EventQueueMutexType = AZStd::conditional_t::value, // if EventQueueMutexType==NullMutex use MutexType otherwise EventQueueMutexType + MutexType, typename Traits::EventQueueMutexType>; /** * Pointer to an address on the bus. @@ -180,14 +180,22 @@ namespace AZ * `::ExecuteQueuedEvents()`. * By default, the event queue is disabled. */ - static const bool EnableEventQueue = Traits::EnableEventQueue; - static const bool EventQueueingActiveByDefault = Traits::EventQueueingActiveByDefault; - static const bool EnableQueuedReferences = Traits::EnableQueuedReferences; + static constexpr bool EnableEventQueue = Traits::EnableEventQueue; + static constexpr bool EventQueueingActiveByDefault = Traits::EventQueueingActiveByDefault; + static constexpr bool EnableQueuedReferences = Traits::EnableQueuedReferences; /** * True if the EBus supports more than one address. Otherwise, false. */ - static const bool HasId = Traits::AddressPolicy != EBusAddressPolicy::Single; + static constexpr bool HasId = Traits::AddressPolicy != EBusAddressPolicy::Single; + + /** + * Template Lock Guard class that wraps around the Mutex + * The EBus uses for Dispatching Events. + * This is not the EBus Context Mutex if LocklessDispatch is true + */ + template + using DispatchLockGuard = typename Traits::template DispatchLockGuard; }; /** @@ -460,7 +468,7 @@ namespace AZ using BusPtr = typename Traits::BusPtr; /** - * Helper to queue an event by BusIdType only when function queueing is enabled + * Helper to queue an event by BusIdType only when function queueing is enabled * @param id Address ID. Handlers that are connected to this ID will receive the event. * @param func Function pointer of the event to dispatch. * @param args Function arguments that are passed to each handler. @@ -581,7 +589,7 @@ namespace AZ , public EBusBroadcaster , public EBusEventer , public EBusEventEnumerator - , public AZStd::Utils::if_c, EBusNullQueue>::type + , public AZStd::conditional_t, EBusNullQueue> { }; @@ -599,7 +607,7 @@ namespace AZ : public EventDispatcher , public EBusBroadcaster , public EBusBroadcastEnumerator - , public AZStd::Utils::if_c, EBusNullQueue>::type + , public AZStd::conditional_t, EBusNullQueue> { }; diff --git a/Code/Framework/AzCore/AzCore/EBus/EBus.h b/Code/Framework/AzCore/AzCore/EBus/EBus.h index da8c880963..a3dc10b103 100644 --- a/Code/Framework/AzCore/AzCore/EBus/EBus.h +++ b/Code/Framework/AzCore/AzCore/EBus/EBus.h @@ -236,6 +236,17 @@ namespace AZ * code before or after an event. */ using EventProcessingPolicy = EBusEventProcessingPolicy; + + /** + * Template Lock Guard class that wraps around the Mutex + * The EBus Context uses the LockGuard when dispatching + * (either AZStd::scoped_lock or NullLockGuard) + * The IsLocklessDispatch bool is there to defer evaluation of the LocklessDispatch constant + * Otherwise the value above in EBusTraits.h is always used and not the value + * that the derived trait class sets. + */ + template + using DispatchLockGuard = AZStd::conditional_t, AZStd::scoped_lock>; }; namespace Internal @@ -496,6 +507,14 @@ namespace AZ */ static const bool HasId = Traits::AddressPolicy != EBusAddressPolicy::Single; + /** + * Template Lock Guard class that wraps around the Mutex + * The EBus uses for Dispatching Events. + * This is not EBus Context Mutex when LocklessDispatch is set + */ + template + using DispatchLockGuard = typename ImplTraits::template DispatchLockGuard; + ////////////////////////////////////////////////////////////////////////// // Check to help identify common mistakes /// @cond EXCLUDE_DOCS @@ -620,11 +639,11 @@ namespace AZ using ContextMutexType = AZStd::conditional_t, AZStd::shared_mutex, MutexType>; /** - * The scoped lock guard to use (either AZStd::scoped_lock or NullLockGuard + * The scoped lock guard to use * during broadcast/event dispatch. * @see EBusTraits::LocklessDispatch */ - using DispatchLockGuard = AZStd::conditional_t, AZStd::scoped_lock>; + using DispatchLockGuard = DispatchLockGuard; /** * The scoped lock guard to use during connection. Some specialized policies execute handler methods which @@ -704,6 +723,11 @@ namespace AZ static Context& GetOrCreateContext(bool trackCallstack=true); static bool IsInDispatch(Context* context = GetContext(false)); + + /** + * Returns whether the EBus context is in the middle of a dispatch on the current thread + */ + static bool IsInDispatchThisThread(Context* context = GetContext(false)); /// @cond EXCLUDE_DOCS struct RouterCallstackEntry : public CallstackEntry @@ -1208,6 +1232,13 @@ AZ_POP_DISABLE_WARNING return context != nullptr && context->m_dispatches > 0; } + template + bool EBus::IsInDispatchThisThread(Context* context) + { + return context != nullptr && context->s_callstack != nullptr + && context->s_callstack->m_prev != nullptr; + } + //========================================================================= template EBus::RouterCallstackEntry::RouterCallstackEntry(Iterator it, const BusIdType* busId, bool isQueued, bool isReverse) diff --git a/Code/Framework/AzCore/Tests/EBus.cpp b/Code/Framework/AzCore/Tests/EBus.cpp index 10216a0485..9acf0f8a05 100644 --- a/Code/Framework/AzCore/Tests/EBus.cpp +++ b/Code/Framework/AzCore/Tests/EBus.cpp @@ -2088,7 +2088,7 @@ namespace UnitTest DisconnectNextHandlerByIdImpl multiHandler2; multiHandler2.BusConnect(DisconnectNextHandlerByIdImpl::firstBusAddress); multiHandler2.BusConnect(DisconnectNextHandlerByIdImpl::secondBusAddress); - + // Set the first handler m_nextHandler field to point to the second handler multiHandler1.m_nextHandler = &multiHandler2; @@ -2807,7 +2807,7 @@ namespace UnitTest AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(m_val % m_maxSleep)); } } - + void DoConnect() override { MyEventGroupBus::Handler::BusConnect(m_id); @@ -2854,7 +2854,7 @@ namespace UnitTest } MyEventGroupBus::Event(id, &MyEventGroupBus::Events::Calculate, i, i * 2, i << 4); - + LocklessConnectorBus::Event(id, &LocklessConnectorBus::Events::DoDisconnect); bool failed = (AZStd::find_if(&sentinel[0], end, [](char s) { return s != 0; }) != end); @@ -2891,7 +2891,7 @@ namespace UnitTest { MyEventGroupImpl() { - + } ~MyEventGroupImpl() override @@ -3614,7 +3614,7 @@ namespace UnitTest { AZStd::this_thread::yield(); } - + EXPECT_GE(AZStd::chrono::system_clock::now(), endTime); }; AZStd::thread connectThread([&connectHandler, &waitHandler]() @@ -3813,7 +3813,7 @@ namespace UnitTest struct LastHandlerDisconnectHandler : public LastHandlerDisconnectBus::Handler { - void OnEvent() override + void OnEvent() override { ++m_numOnEvents; BusDisconnect(); @@ -3854,7 +3854,7 @@ namespace UnitTest struct DisconnectAssertHandler : public DisconnectAssertBus::Handler { - + }; TEST_F(EBus, HandlerDestroyedWithoutDisconnect_Asserts) @@ -3995,6 +3995,191 @@ namespace UnitTest idTestRequest.Disconnect(); } + + // IsInDispatchThisThread + struct IsInThreadDispatchRequests + : AZ::EBusTraits + { + using MutexType = AZStd::recursive_mutex; + }; + + using IsInThreadDispatchBus = AZ::EBus; + + class IsInThreadDispatchHandler + : public IsInThreadDispatchBus::Handler + {}; + + TEST_F(EBus, InvokingIsInThisThread_ReturnsSuccess_OnlyIfThreadIsInDispatch) + { + IsInThreadDispatchHandler handler; + handler.BusConnect(); + + auto ThreadDispatcher = [](IsInThreadDispatchRequests*) + { + EXPECT_TRUE(IsInThreadDispatchBus::IsInDispatchThisThread()); + auto PerThreadBusDispatch = []() + { + EXPECT_FALSE(IsInThreadDispatchBus::IsInDispatchThisThread()); + }; + AZStd::array threads{ AZStd::thread(PerThreadBusDispatch), AZStd::thread(PerThreadBusDispatch) }; + for (AZStd::thread& thread : threads) + { + thread.join(); + } + }; + + static constexpr size_t ThreadDispatcherIterations = 4; + for (size_t iteration = 0; iteration < ThreadDispatcherIterations; ++iteration) + { + EXPECT_FALSE(IsInThreadDispatchBus::IsInDispatchThisThread()); + IsInThreadDispatchBus::Broadcast(ThreadDispatcher); + EXPECT_FALSE(IsInThreadDispatchBus::IsInDispatchThisThread()); + } + } + + // Thread Dispatch Policy + struct ThreadDispatchTestBusTraits + : AZ::EBusTraits + { + using MutexType = AZStd::recursive_mutex; + + struct PostThreadDispatchTestInvoker + { + ~PostThreadDispatchTestInvoker(); + }; + + template + struct ThreadDispatchTestLockGuard + { + ThreadDispatchTestLockGuard(DispatchMutex& contextMutex) + : m_lock{ contextMutex } + {} + ThreadDispatchTestLockGuard(DispatchMutex& contextMutex, AZStd::adopt_lock_t adopt_lock) + : m_lock{ contextMutex, adopt_lock } + {} + ThreadDispatchTestLockGuard(const ThreadDispatchTestLockGuard&) = delete; + ThreadDispatchTestLockGuard& operator=(const ThreadDispatchTestLockGuard&) = delete; + private: + PostThreadDispatchTestInvoker m_threadPolicyInvoker; + using LockType = AZStd::conditional_t, AZStd::scoped_lock>; + LockType m_lock; + }; + + template + using DispatchLockGuard = ThreadDispatchTestLockGuard; + + static inline AZStd::atomic s_threadPostDispatchCalls; + }; + + class ThreadDispatchTestRequests + { + public: + virtual void FirstCall() = 0; + virtual void SecondCall() = 0; + virtual void ThirdCall() = 0; + }; + + using ThreadDispatchTestBus = AZ::EBus; + + ThreadDispatchTestBusTraits::PostThreadDispatchTestInvoker::~PostThreadDispatchTestInvoker() + { + if (!ThreadDispatchTestBus::IsInDispatchThisThread()) + { + ++s_threadPostDispatchCalls; + } + } + + class ThreadDispatchTestHandler + : public ThreadDispatchTestBus::Handler + { + public: + void Connect() + { + ThreadDispatchTestBus::Handler::BusConnect(); + } + void Disconnect() + { + ThreadDispatchTestBus::Handler::BusDisconnect(); + } + + void FirstCall() override + { + ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::SecondCall); + } + void SecondCall() override + { + ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::ThirdCall); + } + void ThirdCall() override + { + } + }; + + template + class EBusParamFixture + : public ScopedAllocatorSetupFixture + , public ::testing::WithParamInterface + {}; + + struct ThreadDispatchParams + { + size_t m_threadCount{}; + size_t m_handlerCount{}; + }; + + using ThreadDispatchParamFixture = EBusParamFixture; + + INSTANTIATE_TEST_CASE_P( + ThreadDispatch, + ThreadDispatchParamFixture, + ::testing::Values( + ThreadDispatchParams{ 1, 1 }, + ThreadDispatchParams{ 2, 1 }, + ThreadDispatchParams{ 1, 2 }, + ThreadDispatchParams{ 2, 2 }, + ThreadDispatchParams{ 16, 8 } + ) + ); + + TEST_P(ThreadDispatchParamFixture, CustomDispatchLockGuard_InvokesPostDispatchFunction_AfterThreadHasFinishedDispatch) + { + ThreadDispatchTestBusTraits::s_threadPostDispatchCalls = 0; + ThreadDispatchParams threadDispatchParams = GetParam(); + AZStd::vector testThreads; + AZStd::vector testHandlers(threadDispatchParams.m_handlerCount); + for (ThreadDispatchTestHandler& testHandler : testHandlers) + { + testHandler.Connect(); + } + + static constexpr size_t DispatchThreadCalls = 3; + const size_t totalThreadDispatchCalls = threadDispatchParams.m_threadCount * DispatchThreadCalls; + + auto DispatchThreadWorker = []() + { + ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::FirstCall); + ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::SecondCall); + ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::ThirdCall); + }; + + for (size_t threadIndex = 0; threadIndex < threadDispatchParams.m_threadCount; ++threadIndex) + { + testThreads.emplace_back(DispatchThreadWorker); + } + + for (AZStd::thread& thread : testThreads) + { + thread.join(); + } + + for (ThreadDispatchTestHandler& testHandler : testHandlers) + { + testHandler.Disconnect(); + } + + EXPECT_EQ(totalThreadDispatchCalls, ThreadDispatchTestBusTraits::s_threadPostDispatchCalls); + ThreadDispatchTestBusTraits::s_threadPostDispatchCalls = 0; + } } // namespace UnitTest #if defined(HAVE_BENCHMARK) @@ -4370,7 +4555,7 @@ namespace Benchmark Bus::ExecuteQueuedEvents(); } s_benchmarkEBusEnv.Disconnect(state); - + } BUS_BENCHMARK_REGISTER_ALL(BM_EBus_ExecuteBroadcast); From de41653d26e87eed74f1d8d71009a2d44715b40c Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Fri, 8 Oct 2021 13:36:46 -0700 Subject: [PATCH 149/293] remove LY_PROJECTS check in Atom test registrations so that the targets build in project centric builds (#4581) Signed-off-by: jromnoa --- AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt index 0d6fe4c8fa..ff3cd5c465 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt @@ -6,12 +6,7 @@ # # -################################################################################ -# Atom Renderer: Automated Tests -# Runs EditorPythonBindings (hydra) scripts inside the Editor to verify test results for the Atom renderer. -################################################################################ - -if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS) +if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_pytest( NAME AutomatedTesting::Atom_TestSuite_Main TEST_SUITE main From cef41261004e1b76171882115a38be4872e4b7fe Mon Sep 17 00:00:00 2001 From: smurly Date: Fri, 8 Oct 2021 13:49:51 -0700 Subject: [PATCH 150/293] Mesh component parallel test automation P0 (#4562) * Mesh component P0 automation for parallel testing Signed-off-by: Scott Murray * Remove unused imports Signed-off-by: Scott Murray * Decorating test classes with test_case_id to corresponding testrail cases Signed-off-by: Scott Murray --- .../Atom/TestSuite_Main_Optimized.py | 14 ++ .../hydra_AtomEditorComponents_MeshAdded.py | 171 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index f5ac411a01..90436fbe27 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -14,36 +14,50 @@ from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite @pytest.mark.parametrize("launcher_platform", ['windows_editor']) class TestAutomation(EditorTestSuite): + @pytest.mark.test_case_id("C32078118") class AtomEditorComponents_DecalAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module + @pytest.mark.test_case_id("C32078119") class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module + @pytest.mark.test_case_id("C32078120") class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module + @pytest.mark.test_case_id("C32078121") class AtomEditorComponents_ExposureControlAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module + @pytest.mark.test_case_id("C32078115") class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module + @pytest.mark.test_case_id("C32078125") class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module + @pytest.mark.test_case_id("C32078131") class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest): from Atom.tests import ( hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module) + @pytest.mark.test_case_id("C32078117") class AtomEditorComponents_LightAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module + @pytest.mark.test_case_id("C36525660") class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module + @pytest.mark.test_case_id("C32078128") class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module + @pytest.mark.test_case_id("C32078124") + class AtomEditorComponents_MeshAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py new file mode 100644 index 0000000000..fbf5c987d1 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py @@ -0,0 +1,171 @@ +""" +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: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + mesh_entity_creation = ( + "Mesh Entity successfully created", + "Mesh Entity failed to be created") + mesh_component_added = ( + "Entity has a Mesh component", + "Entity failed to find Mesh component") + mesh_asset_specified = ( + "Mesh asset set", + "Mesh asset not set") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_Mesh_AddedToEntity(): + """ + Summary: + Tests the Mesh component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a Mesh entity with no components. + 2) Add a Mesh component to Mesh entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Specify the Mesh component asset + 6) Enter/Exit game mode. + 7) Test IsHidden. + 8) Test IsVisible. + 9) Delete Mesh entity. + 10) UNDO deletion. + 11) REDO deletion. + 12) Look for errors. + + :return: None + """ + + import os + + import azlmbr.legacy.general as general + + from editor_python_test_tools.asset_utils import Asset + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + helper.init_idle() + helper.open_level("", "Base") + + # Test steps begin. + # 1. Create a Mesh entity with no components. + mesh_name = "Mesh" + mesh_entity = EditorEntity.create_editor_entity(mesh_name) + Report.critical_result(Tests.mesh_entity_creation, mesh_entity.exists()) + + # 2. Add a Mesh component to Mesh entity. + mesh_component = mesh_entity.add_component(mesh_name) + Report.critical_result( + Tests.mesh_component_added, + mesh_entity.has_component(mesh_name)) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not mesh_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, mesh_entity.exists()) + + # 5. Set Mesh component asset property + mesh_property_asset = 'Controller|Configuration|Mesh Asset' + model_path = os.path.join('Objects', 'shaderball', 'shaderball_default_1m.azmodel') + model = Asset.find_asset_by_path(model_path) + mesh_component.set_component_property_value(mesh_property_asset, model.id) + Report.result(Tests.mesh_asset_specified, + mesh_component.get_component_property_value(mesh_property_asset) == model.id) + + # 6. Enter/Exit game mode. + helper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + helper.exit_game_mode(Tests.exit_game_mode) + + # 7. Test IsHidden. + mesh_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, mesh_entity.is_hidden() is True) + + # 8. Test IsVisible. + mesh_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, mesh_entity.is_visible() is True) + + # 9. Delete Mesh entity. + mesh_entity.delete() + Report.result(Tests.entity_deleted, not mesh_entity.exists()) + + # 10. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, mesh_entity.exists()) + + # 11. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not mesh_entity.exists()) + + # 12. Look for errors or asserts. + helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_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(AtomEditorComponents_Mesh_AddedToEntity) From 4c3d7a7e04de0d9573557bd5a3ba93c3c48c8473 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 8 Oct 2021 16:02:57 -0500 Subject: [PATCH 151/293] Reorganized thumbnail and preview are files into common folder Signed-off-by: Guthrie Adams --- .../EditorCommonFeaturesSystemComponent.cpp | 6 +- .../EditorCommonFeaturesSystemComponent.h | 4 +- .../Source/Previewer/CommonPreviewContent.cpp | 165 +++++++++++++++++ .../Source/Previewer/CommonPreviewContent.h | 78 ++++++++ .../Preview => Previewer}/CommonPreviewer.cpp | 14 +- .../Preview => Previewer}/CommonPreviewer.h | 0 .../Preview => Previewer}/CommonPreviewer.ui | 0 .../CommonPreviewerFactory.cpp | 6 +- .../CommonPreviewerFactory.h | 0 .../CommonThumbnailRenderer.cpp | 8 +- .../CommonThumbnailRenderer.h | 0 .../LightingPresetThumbnail.cpp | 6 +- .../LightingPresetThumbnail.h | 0 .../MaterialThumbnail.cpp | 6 +- .../MaterialThumbnail.h | 0 .../ModelThumbnail.cpp | 6 +- .../ModelThumbnail.h | 0 .../ThumbnailUtils.cpp | 2 +- .../ThumbnailUtils.h | 0 .../CommonThumbnailPreviewContent.cpp | 172 ------------------ .../CommonThumbnailPreviewContent.h | 82 --------- ...egration_commonfeatures_editor_files.cmake | 34 ++-- 22 files changed, 288 insertions(+), 301 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails/Preview => Previewer}/CommonPreviewer.cpp (92%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails/Preview => Previewer}/CommonPreviewer.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails/Preview => Previewer}/CommonPreviewer.ui (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails/Preview => Previewer}/CommonPreviewerFactory.cpp (92%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails/Preview => Previewer}/CommonPreviewerFactory.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/CommonThumbnailRenderer.cpp (93%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/CommonThumbnailRenderer.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/LightingPresetThumbnail.cpp (96%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/LightingPresetThumbnail.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/MaterialThumbnail.cpp (96%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/MaterialThumbnail.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/ModelThumbnail.cpp (96%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/ModelThumbnail.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/ThumbnailUtils.cpp (98%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Thumbnails => Previewer}/ThumbnailUtils.h (100%) delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.cpp delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index c04702ff90..19a7eda24b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -18,9 +18,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index ed6b3eb426..b9a4151955 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -13,8 +13,8 @@ #include #include #include -#include -#include +#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp new file mode 100644 index 0000000000..6890fabb01 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + CommonPreviewContent::CommonPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId) + : m_scene(scene) + , m_view(view) + , m_entityContextId(entityContextId) + { + // Create preview model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); + m_modelEntity->CreateComponent(Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Init(); + m_modelEntity->Activate(); + + m_defaultModelAsset.Create(DefaultModelAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + + m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, false); + m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, false); + m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, false); + } + + CommonPreviewContent::~CommonPreviewContent() + { + if (m_modelEntity) + { + AzFramework::EntityContextRequestBus::Event( + m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + } + } + + void CommonPreviewContent::Load() + { + m_modelAsset.QueueLoad(); + m_materialAsset.QueueLoad(); + m_lightingPresetAsset.QueueLoad(); + } + + bool CommonPreviewContent::IsReady() const + { + return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) && + (!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) && + (!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady()); + } + + bool CommonPreviewContent::IsError() const + { + return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); + } + + void CommonPreviewContent::ReportErrors() + { + AZ_Warning( + "CommonPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), "Asset failed to load in time: %s", + m_modelAsset.ToString().c_str()); + AZ_Warning( + "CommonPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), "Asset failed to load in time: %s", + m_materialAsset.ToString().c_str()); + AZ_Warning( + "CommonPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(), + "Asset failed to load in time: %s", m_lightingPresetAsset.ToString().c_str()); + } + + void CommonPreviewContent::UpdateScene() + { + UpdateModel(); + UpdateLighting(); + UpdateCamera(); + } + + void CommonPreviewContent::UpdateModel() + { + Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, m_materialAsset.GetId()); + } + + void CommonPreviewContent::UpdateLighting() + { + auto preset = m_lightingPresetAsset->GetDataAs(); + if (preset) + { + auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); + auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); + auto directionalLightFeatureProcessor = m_scene->GetFeatureProcessor(); + auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + skyboxFeatureProcessor->Enable(true); + skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); + + Camera::Configuration cameraConfig; + cameraConfig.m_fovRadians = FieldOfView; + cameraConfig.m_nearClipDistance = NearDist; + cameraConfig.m_farClipDistance = FarDist; + cameraConfig.m_frustumWidth = 100.0f; + cameraConfig.m_frustumHeight = 100.0f; + + AZStd::vector lightHandles; + + preset->ApplyLightingPreset( + iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, + cameraConfig, lightHandles); + } + } + + void CommonPreviewContent::UpdateCamera() + { + // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it + Vector3 center = {}; + float radius = {}; + if (m_modelAsset.IsReady()) + { + m_modelAsset->GetAabb().GetAsSphere(center, radius); + } + + const auto distance = radius + NearDist; + const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); + const auto cameraPosition = center - cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); + const auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); + m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); + } + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h new file mode 100644 index 0000000000..482dde2986 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + //! Provides custom rendering of material and model previews + class CommonPreviewContent final : public AtomToolsFramework::PreviewContent + { + public: + AZ_CLASS_ALLOCATOR(CommonPreviewContent, AZ::SystemAllocator, 0); + + CommonPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId); + + ~CommonPreviewContent() override; + + void Load() override; + bool IsReady() const override; + bool IsError() const override; + void ReportErrors() override; + void UpdateScene() override; + + private: + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = Constants::HalfPi; + static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; + + RPI::ScenePtr m_scene; + RPI::ViewPtr m_view; + AZ::Uuid m_entityContextId; + Entity* m_modelEntity = nullptr; + + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + Data::Asset m_lightingPresetAsset; + + //! Model asset about to be rendered + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + Data::Asset m_modelAsset; + + //! Material asset about to be rendered + static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; + const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); + Data::Asset m_defaultMaterialAsset; + Data::Asset m_materialAsset; + }; + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp similarity index 92% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp index a8692b5eb4..2b5ea7843a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp @@ -7,21 +7,19 @@ */ #include - +#include #include #include -#include -#include #include - -#include -#include +#include +#include +#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include +#include #include #include AZ_POP_DISABLE_WARNING @@ -73,4 +71,4 @@ namespace AZ } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.ui similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.ui diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp similarity index 92% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp index 5b7ef4bfa6..3a6fd2a424 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp @@ -11,9 +11,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp similarity index 93% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp index 63b36b9e14..e9eba7a08d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp @@ -8,9 +8,9 @@ #include #include -#include -#include -#include +#include +#include +#include namespace AZ { @@ -37,7 +37,7 @@ namespace AZ { m_previewRenderer.AddCaptureRequest( { thumbnailSize, - AZStd::make_shared( + AZStd::make_shared( m_previewRenderer.GetScene(), m_previewRenderer.GetView(), m_previewRenderer.GetEntityContextId(), diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailRenderer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp similarity index 96% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp index 8fe4b1998d..566a8d7b58 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include namespace AZ { @@ -112,4 +112,4 @@ namespace AZ } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/LightingPresetThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp similarity index 96% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp index 69bcffde06..b6a93aa59c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include namespace AZ { @@ -103,4 +103,4 @@ namespace AZ } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/MaterialThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp similarity index 96% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp index bc47ec04b8..6fe490e9dc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include namespace AZ { @@ -103,4 +103,4 @@ namespace AZ } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ModelThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp similarity index 98% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp index c8f67138ef..8293b33763 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.cpp deleted file mode 100644 index f8c508a493..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - CommonThumbnailPreviewContent::CommonThumbnailPreviewContent( - RPI::ScenePtr scene, - RPI::ViewPtr view, - AZ::Uuid entityContextId, - const Data::AssetId& modelAssetId, - const Data::AssetId& materialAssetId, - const Data::AssetId& lightingPresetAssetId) - : m_scene(scene) - , m_view(view) - , m_entityContextId(entityContextId) - { - // Connect camera to pipeline's default view after camera entity activated - Matrix4x4 viewToClipMatrix; - MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); - m_view->SetViewToClipMatrix(viewToClipMatrix); - - // Create preview model - AzFramework::EntityContextRequestBus::EventResult( - m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); - m_modelEntity->CreateComponent(Render::MeshComponentTypeId); - m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); - m_modelEntity->CreateComponent(azrtti_typeid()); - m_modelEntity->Init(); - m_modelEntity->Activate(); - - m_defaultModelAsset.Create(DefaultModelAssetId, true); - m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); - m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); - - m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, false); - m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, false); - m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, false); - } - - CommonThumbnailPreviewContent::~CommonThumbnailPreviewContent() - { - if (m_modelEntity) - { - AzFramework::EntityContextRequestBus::Event( - m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); - m_modelEntity = nullptr; - } - } - - void CommonThumbnailPreviewContent::Load() - { - m_modelAsset.QueueLoad(); - m_materialAsset.QueueLoad(); - m_lightingPresetAsset.QueueLoad(); - } - - bool CommonThumbnailPreviewContent::IsReady() const - { - return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) && - (!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) && - (!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady()); - } - - bool CommonThumbnailPreviewContent::IsError() const - { - return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); - } - - void CommonThumbnailPreviewContent::ReportErrors() - { - AZ_Warning( - "CommonThumbnailPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), - "Asset failed to load in time: %s", m_modelAsset.ToString().c_str()); - AZ_Warning( - "CommonThumbnailPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), - "Asset failed to load in time: %s", m_materialAsset.ToString().c_str()); - AZ_Warning( - "CommonThumbnailPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(), - "Asset failed to load in time: %s", m_lightingPresetAsset.ToString().c_str()); - } - - void CommonThumbnailPreviewContent::UpdateScene() - { - UpdateModel(); - UpdateLighting(); - UpdateCamera(); - } - - void CommonThumbnailPreviewContent::UpdateModel() - { - Render::MeshComponentRequestBus::Event( - m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); - - Render::MaterialComponentRequestBus::Event( - m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, - m_materialAsset.GetId()); - } - - void CommonThumbnailPreviewContent::UpdateLighting() - { - auto preset = m_lightingPresetAsset->GetDataAs(); - if (preset) - { - auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); - auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); - auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); - auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); - auto directionalLightFeatureProcessor = - m_scene->GetFeatureProcessor(); - auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); - skyboxFeatureProcessor->Enable(true); - skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); - - Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = FieldOfView; - cameraConfig.m_nearClipDistance = NearDist; - cameraConfig.m_farClipDistance = FarDist; - cameraConfig.m_frustumWidth = 100.0f; - cameraConfig.m_frustumHeight = 100.0f; - - AZStd::vector lightHandles; - - preset->ApplyLightingPreset( - iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, - cameraConfig, lightHandles); - } - } - - void CommonThumbnailPreviewContent::UpdateCamera() - { - // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it - Vector3 center = {}; - float radius = {}; - m_modelAsset->GetAabb().GetAsSphere(center, radius); - - const auto distance = radius + NearDist; - const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); - const auto cameraPosition = center - cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); - const auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); - m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h deleted file mode 100644 index 8520d6053a..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/CommonThumbnailPreviewContent.h +++ /dev/null @@ -1,82 +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 - * - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! Provides custom rendering of material and model previews - class CommonThumbnailPreviewContent final - : public AtomToolsFramework::PreviewContent - { - public: - AZ_CLASS_ALLOCATOR(CommonThumbnailPreviewContent, AZ::SystemAllocator, 0); - - CommonThumbnailPreviewContent( - RPI::ScenePtr scene, - RPI::ViewPtr view, - AZ::Uuid entityContextId, - const Data::AssetId& modelAssetId, - const Data::AssetId& materialAssetId, - const Data::AssetId& lightingPresetAssetId); - - ~CommonThumbnailPreviewContent() override; - - void Load() override; - bool IsReady() const override; - bool IsError() const override; - void ReportErrors() override; - void UpdateScene() override; - - private: - void UpdateModel(); - void UpdateLighting(); - void UpdateCamera(); - - static constexpr float AspectRatio = 1.0f; - static constexpr float NearDist = 0.001f; - static constexpr float FarDist = 100.0f; - static constexpr float FieldOfView = Constants::HalfPi; - static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; - - RPI::ScenePtr m_scene; - RPI::ViewPtr m_view; - AZ::Uuid m_entityContextId; - Entity* m_modelEntity = nullptr; - - static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); - Data::Asset m_defaultLightingPresetAsset; - Data::Asset m_lightingPresetAsset; - - //! Model asset about to be rendered - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); - Data::Asset m_defaultModelAsset; - Data::Asset m_modelAsset; - - //! Material asset about to be rendered - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); - Data::Asset m_defaultMaterialAsset; - Data::Asset m_materialAsset; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index db42b663c8..32f1bd882e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -90,23 +90,23 @@ set(FILES Source/SkyBox/EditorHDRiSkyboxComponent.h Source/SkyBox/EditorPhysicalSkyComponent.cpp Source/SkyBox/EditorPhysicalSkyComponent.h - Source/Thumbnails/ThumbnailUtils.h - Source/Thumbnails/ThumbnailUtils.cpp - Source/Thumbnails/Preview/CommonPreviewer.cpp - Source/Thumbnails/Preview/CommonPreviewer.h - Source/Thumbnails/Preview/CommonPreviewer.ui - Source/Thumbnails/Preview/CommonPreviewerFactory.cpp - Source/Thumbnails/Preview/CommonPreviewerFactory.h - Source/Thumbnails/CommonThumbnailPreviewContent.cpp - Source/Thumbnails/CommonThumbnailPreviewContent.h - Source/Thumbnails/CommonThumbnailRenderer.cpp - Source/Thumbnails/CommonThumbnailRenderer.h - Source/Thumbnails/MaterialThumbnail.cpp - Source/Thumbnails/MaterialThumbnail.h - Source/Thumbnails/ModelThumbnail.cpp - Source/Thumbnails/ModelThumbnail.h - Source/Thumbnails/LightingPresetThumbnail.cpp - Source/Thumbnails/LightingPresetThumbnail.h + Source/Previewer/ThumbnailUtils.h + Source/Previewer/ThumbnailUtils.cpp + Source/Previewer/CommonPreviewer.cpp + Source/Previewer/CommonPreviewer.h + Source/Previewer/CommonPreviewer.ui + Source/Previewer/CommonPreviewerFactory.cpp + Source/Previewer/CommonPreviewerFactory.h + Source/Previewer/CommonPreviewContent.cpp + Source/Previewer/CommonPreviewContent.h + Source/Previewer/CommonThumbnailRenderer.cpp + Source/Previewer/CommonThumbnailRenderer.h + Source/Previewer/MaterialThumbnail.cpp + Source/Previewer/MaterialThumbnail.h + Source/Previewer/ModelThumbnail.cpp + Source/Previewer/ModelThumbnail.h + Source/Previewer/LightingPresetThumbnail.cpp + Source/Previewer/LightingPresetThumbnail.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp From d3f6898ad6e617d5f40e7f45bc7098a1ce098569 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Fri, 8 Oct 2021 15:01:20 -0700 Subject: [PATCH 152/293] Fixes test_MaterialEditorLaunch_AllRHIOptionsSucceed() test by searching for RHI log lines (#4511) * double test timeout from 60 seconds to 120 seconds in attempt to fix it for nightly GPU runs Signed-off-by: jromnoa * add a file to launch with the test to ensure we get a full viewport load completed Signed-off-by: jromnoa * fix import error Signed-off-by: jromnoa * remove python error checks Signed-off-by: jromnoa * add new log line specific to each RHI to check for Signed-off-by: jromnoa * remove the new test script as it is no longer needed with our improved log lines check - the viewport logs don't show up in AR for some reason Signed-off-by: jromnoa --- .../Gem/PythonTests/Atom/TestSuite_Main_GPU.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index 3403d8e9b1..220623af8b 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -220,20 +220,18 @@ class TestPerformanceBenchmarkSuite(object): @pytest.mark.system class TestMaterialEditor(object): - @pytest.mark.parametrize("cfg_args", ["-rhi=dx12", "-rhi=Vulkan"]) + @pytest.mark.parametrize("cfg_args,expected_lines", [ + pytest.param("-rhi=dx12", ["Registering dx12 RHI"]), + pytest.param("-rhi=Vulkan", ["Registering vulkan RHI"]) + ]) @pytest.mark.parametrize("exe_file_name", ["MaterialEditor"]) def test_MaterialEditorLaunch_AllRHIOptionsSucceed( - self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args): + self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args, + expected_lines): """ Tests each valid RHI option (Null RHI excluded) can be launched with the MaterialEditor. - Checks for the "Finished loading viewport configurations." success message post launch. + Checks for the specific expected_lines messaging for each RHI type. """ - expected_lines = ["Finished loading viewport configurations."] - unexpected_lines = [ - # "Trace::Assert", - # "Trace::Error", - "Traceback (most recent call last):", - ] hydra.launch_and_validate_results( request, @@ -243,7 +241,7 @@ class TestMaterialEditor(object): run_python="--runpython", timeout=60, expected_lines=expected_lines, - unexpected_lines=unexpected_lines, + unexpected_lines=[], halt_on_unexpected=False, null_renderer=False, cfg_args=[cfg_args], From 2034cd3053d6d8af08135ded0cdb38c06381c15f Mon Sep 17 00:00:00 2001 From: sweeneys Date: Fri, 8 Oct 2021 15:36:52 -0700 Subject: [PATCH 153/293] Platform manager and sanity tests for Linux Signed-off-by: sweeneys --- Tools/LyTestTools/ly_test_tools/__init__.py | 6 +- .../managers/abstract_resource_locator.py | 2 +- .../_internal/managers/platforms/linux.py | 3 - .../environment/process_utils.py | 14 ++ .../launchers/platforms/linux/launcher.py | 28 ++- .../ly_test_tools/o3de/asset_processor.py | 172 +++++++++--------- .../o3de/asset_processor_utils.py | 19 +- Tools/LyTestTools/tests/integ/sanity_tests.py | 3 +- .../tests/unit/test_asset_processor.py | 14 +- 9 files changed, 150 insertions(+), 111 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/__init__.py b/Tools/LyTestTools/ly_test_tools/__init__.py index 58340342ab..972e97d488 100755 --- a/Tools/LyTestTools/ly_test_tools/__init__.py +++ b/Tools/LyTestTools/ly_test_tools/__init__.py @@ -16,7 +16,7 @@ ALL_PLATFORM_OPTIONS = ['android', 'ios', 'linux', 'mac', 'windows'] ALL_LAUNCHER_OPTIONS = ['android', 'base', 'linux', 'mac', 'windows', 'windows_editor', 'windows_dedicated', 'windows_generic'] ANDROID = False IOS = False # Not implemented - see SPEC-2505 -LINUX = sys.platform.startswith('linux') # Not implemented - see SPEC-2501 +LINUX = sys.platform.startswith('linux') MAC = sys.platform.startswith('darwin') WINDOWS = sys.platform.startswith('win') @@ -54,9 +54,11 @@ elif LINUX: HOST_OS_PLATFORM = 'linux' HOST_OS_EDITOR = 'linux_editor' HOST_OS_DEDICATED_SERVER = 'linux_dedicated' - from ly_test_tools.launchers.platforms.linux.launcher import (LinuxLauncher, LinuxEditor, DedicatedLinuxLauncher) + HOST_OS_GENERIC_EXECUTABLE = 'linux_generic' + from ly_test_tools.launchers.platforms.linux.launcher import (LinuxLauncher, LinuxEditor, DedicatedLinuxLauncher, LinuxGenericLauncher) LAUNCHERS['linux'] = LinuxLauncher LAUNCHERS['linux_editor'] = LinuxEditor LAUNCHERS['linux_dedicated'] = DedicatedLinuxLauncher + LAUNCHERS['linux_generic'] = LinuxGenericLauncher else: logger.warning(f'WARNING: LyTestTools only supports Windows, Mac, and Linux. Unexpectedly detected HOST_OS_PLATFORM: "{HOST_OS_PLATFORM}".') diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py index 77d58e3a48..fccc94bdcc 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py @@ -265,7 +265,7 @@ class AbstractResourceLocator(object): Return path to AssetProcessor's log file using the project bin dir :return: path to 'AP_Gui.log' file in folder """ - return os.path.join(self.ap_log_dir(), 'AP_Gui.log') + return os.path.join(self.ap_log_dir(), 'AP_GUI.log') def project_cache(self): """ diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py index cdbd379183..fea60cc9cb 100644 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py @@ -23,9 +23,6 @@ class _LinuxResourceManager(AbstractResourceLocator): """ Override for locating resources in a Linux operating system running LyTestTools. """ - def __init__(self, build_directory: str, project: str): - pass - def platform_config_file(self): """ :return: path to the platform config file diff --git a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py index 1c0be299a8..79fc4f420a 100755 --- a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py +++ b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py @@ -465,3 +465,17 @@ def close_windows_process(pid, timeout=20, raise_on_missing=False): # Wait for asyncronous termination waiter.wait_for(lambda: pid not in psutil.pids(), timeout=timeout, exc=TimeoutError(f"Process {pid} never terminated")) + + +def get_display_env(): + """ + Fetches environment variables with an appropriate display (monitor) configured, + useful for subprocess calls to UI applications + :return: A dictionary containing environment variables (per os.environ) + """ + env = os.environ.copy() + if not ly_test_tools.WINDOWS: + if 'DISPLAY' not in env.keys(): + # assume Display 1 is available in another session + env['DISPLAY'] = ':1' + return env diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py index 210519d197..afee522daf 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py @@ -13,6 +13,7 @@ import subprocess import ly_test_tools.environment.waiter import ly_test_tools.launchers.exceptions +import ly_test_tools.environment.process_utils as process_utils from ly_test_tools.launchers.platforms.base import Launcher from ly_test_tools.launchers.exceptions import TeardownError, ProcessNotStartedError @@ -68,7 +69,7 @@ class LinuxLauncher(Launcher): """ command = [self.binary_path()] + self.args self._tmpout = TemporaryFile() - self._proc = subprocess.Popen(command, stdout=self._tmpout, stderr=self._tmpout, universal_newlines=True) + self._proc = subprocess.Popen(command, stdout=self._tmpout, stderr=self._tmpout, universal_newlines=True, env=process_utils.get_display_env()) log.debug(f"Started Linux Launcher with command: {command}") def get_output(self, encoding="utf-8"): @@ -222,3 +223,28 @@ class LinuxEditor(LinuxLauncher): """ assert self.workspace.project is not None return os.path.join(self.workspace.paths.build_directory(), "Editor") + + +class LinuxGenericLauncher(LinuxLauncher): + + def __init__(self, build, exe_file_name, args=None): + super(LinuxLauncher, self).__init__(build, args) + self.exe_file_name = exe_file_name + self.expected_executable_path = os.path.join( + self.workspace.paths.build_directory(), f"{self.exe_file_name}") + + if not os.path.exists(self.expected_executable_path): + raise ProcessNotStartedError( + f"Unable to locate executable '{self.exe_file_name}' " + f"in path: '{self.expected_executable_path}'") + + def binary_path(self): + """ + Return full path to the executable file for this build's configuration and project + Relies on the build_directory() in self.workspace.paths to be accurate + + :return: full path to the given exe file + """ + assert self.workspace.project is not None, ( + 'Project cannot be NoneType - please specify a project name string.') + return self.expected_executable_path diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py index 57454930eb..0623715350 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py @@ -7,21 +7,22 @@ SPDX-License-Identifier: Apache-2.0 OR MIT A class to control functionality of Lumberyard's asset processor. The class manages a workspace's asset processor and asset configurations. """ -import os -import datetime import logging -import subprocess -import socket -import time -import tempfile +import os +import psutil import shutil +import socket import stat +import subprocess +import tempfile +import time + from typing import List, Tuple -import psutil import ly_test_tools -import ly_test_tools.environment.waiter as waiter import ly_test_tools.environment.file_system as file_system +import ly_test_tools.environment.process_utils as process_utils +import ly_test_tools.environment.waiter as waiter import ly_test_tools.o3de.pipeline_utils as utils from ly_test_tools.o3de.ap_log_parser import APLogParser @@ -177,24 +178,26 @@ class AssetProcessor(object): """ Read the a port chosen by AP from the log """ - start_time = time.time() - read_port_timeout = 10 - while (time.time() - start_time) < read_port_timeout: + port = None + + def _get_port_from_log(): + nonlocal port if not os.path.exists(self._workspace.paths.ap_gui_log()): - logger.debug(f"Log at {self._workspace.paths.ap_gui_log()} doesn't exist, sleeping") - else: - log = APLogParser(self._workspace.paths.ap_gui_log()) - if len(log.runs): - try: - port = log.runs[-1][port_type] - if port: - logger.info(f"Read port type {port_type} : {port}") - return port - except Exception: # intentionally broad - pass - time.sleep(1) - logger.warning(f"Failed to read port type {port_type}") - return 0 + return False + + log = APLogParser(self._workspace.paths.ap_gui_log()) + if len(log.runs): + try: + port = log.runs[-1][port_type] + logger.debug(f"Read port type {port_type} : {port}") + return True + except Exception as ex: # intentionally broad + logger.debug("Failed to read port from file", exc_info=ex) + return False + + err = AssetProcessorError(f"Failed to read port type {port_type} from {self._workspace.paths.ap_gui_log()}") + waiter.wait_for(_get_port_from_log, timeout=10, exc=err) + return port def set_control_connection(self, connection): self._control_connection = connection @@ -206,13 +209,8 @@ class AssetProcessor(object): """ if not self._control_connection: control_timeout = 60 - try: - return self.connect_socket("Control Connection", self.read_control_port, - set_port_method=self.set_control_connection, timeout=control_timeout) - except AssetProcessorError as e: - # We dont want a failure of our test socket connection to fail the entire test automatically. - logger.error(f"Failed to connect control socket with error {e}") - pass + return self.connect_socket("Control Connection", self.read_control_port, + set_port_method=self.set_control_connection, timeout=control_timeout) return True, None def using_temp_workspace(self): @@ -227,34 +225,40 @@ class AssetProcessor(object): :param set_port_method: If set, method to call with the established connection :param timeout: Max seconds to attempt connection for """ - - connection_timeout = timeout connect_port = read_port_method() - logger.debug(f"Waiting for connection to AP {port_name}: {host}:{connect_port}, " - f"{connection_timeout} seconds remaining") - start_time = time.time() - while (time.time() - start_time) < connection_timeout: + logger.debug(f"Attempting to for connect to AP {port_name}: {host}:{connect_port} for {timeout} seconds") + + def _attempt_connection(): + nonlocal connect_port + if self._ap_proc.poll() is not None: + raise AssetProcessorError(f"Asset processor exited early with errorcode: {self._ap_proc.returncode}") + connection_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - connection_socket.settimeout(10.0) + connection_socket.settimeout(timeout) try: connection_socket.connect((host, connect_port)) logger.debug(f"Connection to AP {port_name} was successful") if set_port_method is not None: set_port_method(connection_socket) - return True, None - except Exception: # Purposefully broad - # Short delay to prevent immediate failure due to slower starting applications such as debug builds - time.sleep(0.01) + return True + except Exception as ex: # Purposefully broad + logger.debug(f"Failed to connect to {host}:{connect_port}", exc_info=ex) if not connect_port or not self.using_temp_workspace(): # If we're not using a temp workspace with a fresh log it's possible we're reading a port from # a previous run and the log just hasn't written yet, we need to keep checking the log for a new # port to use - new_connect_port = read_port_method() - if new_connect_port != connect_port: - logger.debug( - f"Read new connect port for {port_name}: {host}:{new_connect_port}") - connect_port = new_connect_port - raise AssetProcessorError(f"Could not connect to AP {port_name}") + try: + new_connect_port = read_port_method() + if new_connect_port != connect_port: + logger.debug(f"Found new connect port for {port_name}: {host}:{new_connect_port}") + connect_port = new_connect_port + except Exception as read_exception: # Purposefully broad + logger.debug(f"Failed to read port data", exc_info=read_exception) + return False + + err = AssetProcessorError(f"Could not connect to AP {port_name} on {host}:{connect_port}") + waiter.wait_for(_attempt_connection, timeout=timeout, exc=err) + return True, None def stop(self, timeout=60): """ @@ -436,15 +440,14 @@ class AssetProcessor(object): extra_params=None, add_gem_scan_folders=None, add_config_scan_folders=None, decode=True, expect_failure=False, quitonidle=False, connect_to_ap=False, accept_input=True, run_until_idle=True, scan_folder_pattern=None): - ap_path = self._workspace.paths.asset_processor() + ap_path = os.path.abspath(self._workspace.paths.asset_processor()) + ap_exe_path = os.path.dirname(ap_path) extra_gui_params = [] if quitonidle: extra_gui_params.append("--quitonidle") if accept_input: extra_gui_params.append("--acceptInput") - ap_exe_path = os.path.dirname(self._workspace.paths.asset_processor()) - logger.info("Starting asset processor") if self.process_exists(): logger.error("Asset processor already started. Stop first") @@ -483,20 +486,30 @@ class AssetProcessor(object): logger.warning(f"Cannot capture output when leaving AP connection open.") logger.info(f"Launching AP with command: {command}") - self._ap_proc = subprocess.Popen(command, cwd=ap_exe_path) - - if accept_input and not quitonidle: - self.connect_control() - - if connect_to_ap: - self.connect_listen() - - if quitonidle: - waiter.wait_for(lambda: not self.process_exists(), timeout=timeout) - elif run_until_idle and accept_input: - if not self.wait_for_idle(): - return False, None - return True, None + try: + self._ap_proc = subprocess.Popen(command, cwd=ap_exe_path, env=process_utils.get_display_env()) + + if accept_input: + self.connect_control() + + if connect_to_ap: + self.connect_listen() + + if quitonidle: + waiter.wait_for(lambda: not self.process_exists(), timeout=timeout, + exc=AssetProcessorError(f"Failed to quit on idle within {timeout} seconds")) + elif run_until_idle and accept_input: + if not self.wait_for_idle(): + return False, None + return True, None + except BaseException as be: # purposefully broad + logger.exception("Exception while starting Asset Processor", be) + # clean up to avoid leaking open AP process to future tests + try: + self._ap_proc.kill() + except Exception as ex: + logger.exception("Ignoring exception while trying to terminate Asset Processor", ex) + raise # raise whatever prompted us to clean up def connect_listen(self, timeout=DEFAULT_TIMEOUT_SECONDS): # Wait for the AP we launched to be ready to accept a connection @@ -574,21 +587,17 @@ class AssetProcessor(object): expect_failure=False): """ In case of a timeout, the asset processor and associated processes are killed and the function returns False. - + :param timeout: seconds to wait before aborting :param capture_output = Capture output which will be returned in the second of the return pair :param decode: decode byte strings from captured output to utf-8 :param expect_failure: asset processing is expected to fail, so don't error on a failure, and assert on no failure. """ logger.info(f"Launching AP with command: {command}") - start = datetime.datetime.now() - try: - duration = datetime.timedelta(seconds=timeout) - except TypeError: - logger.warning("Cannot set timeout value of '{}' seconds, defaulting to {} hours".format( - timeout, DEFAULT_TIMEOUT_HOURS)) - duration = datetime.timedelta(hours=DEFAULT_TIMEOUT_HOURS) - timeout = duration.total_seconds() + start = time.time() + if type(timeout) not in [int, float] or timeout < 1: + logger.warning(f"Invalid timeout {timeout} - defaulting to {DEFAULT_TIMEOUT_SECONDS} seconds") + timeout = DEFAULT_TIMEOUT_SECONDS run_result = subprocess.run(command, close_fds=True, timeout=timeout, capture_output=capture_output) output_list = None @@ -609,8 +618,7 @@ class AssetProcessor(object): elif expect_failure: logger.error(f"{command} was expected to fail, but instead ran without failure.") return True, output_list - logger.info( - f"{command} completed successfully in {(datetime.datetime.now() - start).seconds} seconds") + logger.info(f"{command} completed successfully in {time.time() - start} seconds") return True, output_list def set_failure_log_folder(self, log_root): @@ -743,14 +751,14 @@ class AssetProcessor(object): :return: Absolute path of added scan folder """ if os.path.isabs(folder_name): - if not folder_name in self._override_scan_folders: + if folder_name not in self._override_scan_folders: self._override_scan_folders.append(folder_name) logger.info(f'Adding override scan folder {folder_name}') return folder_name else: if not self._temp_asset_root: - logger.warning(f"Can't create scan folder, no temporary asset workspace has been created") - return + logger.warning(f"Can not create scan folder, no temporary asset workspace has been created") + return "" scan_folder = os.path.join(self._temp_asset_root if self._temp_asset_root else self._workspace.paths.engine_root(), folder_name) if not os.path.isdir(scan_folder): @@ -802,9 +810,9 @@ class AssetProcessor(object): if not use_current_root: self.create_temp_asset_root() test_asset_root = os.path.join(self._temp_asset_root, self._workspace.project if relative_asset_root is None - else relative_asset_root) + else relative_asset_root) test_folder = os.path.join(test_asset_root, function_name if existing_function_name is None - else existing_function_name) + else existing_function_name) if not os.path.isdir(test_folder): os.makedirs(test_folder) if add_scan_folder: diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py index 34ea5f4eb8..f30ed2f233 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py @@ -9,8 +9,7 @@ import logging import os import subprocess -import ly_test_tools -from ly_test_tools.environment.process_utils import kill_processes_named as kill_processes_named +import ly_test_tools.environment.process_utils as process_utils logger = logging.getLogger(__name__) @@ -23,7 +22,7 @@ def start_asset_processor(bin_dir): :return: A subprocess.Popen object for the AssetProcessor process. """ os.chdir(bin_dir) - asset_processor = subprocess.Popen(['AssetProcessor.exe']) + asset_processor = subprocess.Popen(['AssetProcessor'], env=process_utils.get_display_env()) return_code = asset_processor.poll() if return_code is not None and return_code != 0: @@ -40,11 +39,9 @@ def kill_asset_processor(): :return: None """ - - kill_processes_named('AssetProcessor_tmp', ignore_extensions=True) - kill_processes_named('AssetProcessor', ignore_extensions=True) - kill_processes_named('AssetProcessorBatch', ignore_extensions=True) - kill_processes_named('AssetBuilder', ignore_extensions=True) - kill_processes_named('rc', ignore_extensions=True) - kill_processes_named('Lua Editor', ignore_extensions=True) - + process_utils.kill_processes_named('AssetProcessor_tmp', ignore_extensions=True) + process_utils.kill_processes_named('AssetProcessor', ignore_extensions=True) + process_utils.kill_processes_named('AssetProcessorBatch', ignore_extensions=True) + process_utils.kill_processes_named('AssetBuilder', ignore_extensions=True) + process_utils.kill_processes_named('rc', ignore_extensions=True) + process_utils.kill_processes_named('Lua Editor', ignore_extensions=True) diff --git a/Tools/LyTestTools/tests/integ/sanity_tests.py b/Tools/LyTestTools/tests/integ/sanity_tests.py index e27398c477..ed77d7b8db 100755 --- a/Tools/LyTestTools/tests/integ/sanity_tests.py +++ b/Tools/LyTestTools/tests/integ/sanity_tests.py @@ -58,12 +58,11 @@ class TestAutomatedTestingProject(object): # Call the game client executable with launcher.start(): # Wait for the process to exist - waiter.wait_for(lambda: process_utils.process_exists(f"{project}.GameLauncher.exe", ignore_extensions=True)) + waiter.wait_for(lambda: process_utils.process_exists(f"{project}.GameLauncher", ignore_extensions=True)) finally: # Clean up processes after the test is finished process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True) - @pytest.mark.skipif(not ly_test_tools.WINDOWS, reason="Editor currently only functions on Windows") def test_StartEditor_Sanity(self, project): """ The `test_StartEditor_Sanity` test function is similar to the previous example with minor adjustments. A diff --git a/Tools/LyTestTools/tests/unit/test_asset_processor.py b/Tools/LyTestTools/tests/unit/test_asset_processor.py index f487cc8537..aabbf2f2f5 100755 --- a/Tools/LyTestTools/tests/unit/test_asset_processor.py +++ b/Tools/LyTestTools/tests/unit/test_asset_processor.py @@ -58,10 +58,8 @@ class TestAssetProcessor(object): under_test.start(connect_to_ap=True) assert under_test._ap_proc is not None - mock_popen.assert_called_once_with([mock_ap_path, '--zeroAnalysisMode', - f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"', - '--logDir', under_test.log_root(), - '--acceptInput', '--platforms', 'bar'], cwd=os.path.dirname(mock_ap_path)) + mock_popen.assert_called_once() + assert '--zeroAnalysisMode' in mock_popen.call_args[0][0] mock_connect.assert_called() @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') @@ -114,7 +112,7 @@ class TestAssetProcessor(object): assert result mock_run.assert_called_once_with([apb_path, - f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"', + f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"', '--logDir', under_test.log_root()], close_fds=True, capture_output=False, timeout=1) @@ -150,10 +148,8 @@ class TestAssetProcessor(object): result, _ = under_test.batch_process(None, False) assert not result - mock_run.assert_called_once_with([apb_path, - f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"', - '--logDir', under_test.log_root()], - close_fds=True, capture_output=False, timeout=28800.0) + mock_run.assert_called_once() + assert f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"' in mock_run.call_args[0][0] @mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager') From e4d3ab118c02071d5533ea90525cb8b43589ea62 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 8 Oct 2021 17:59:57 -0500 Subject: [PATCH 154/293] Console changes: Added a new SettingsRegistry root key for executing (#4567) console commands. The new key is "/O3DE/Autoexec/ConsoleCommands" and the only difference with the "/Amazon/AzCore/Runtime/ConosleCommands" key is that it isn't excluded by the SettingsRegistryBuilder. Due to not being excluded by the SettingsRegistryBuilder this key can be used to forward console commands to the aggregate `bootstrap.game...setreg` files. For GameLauncher specific console commands it is recommend to be put them in .setreg file that uses the "game" specialization, such as "autoexec.game.setreg". Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Console/Console.cpp | 32 +++++++++++++------ .../AzCore/AzCore/Console/IConsole.h | 3 +- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Console/Console.cpp b/Code/Framework/AzCore/AzCore/Console/Console.cpp index a1b8a1759d..9f207d9afd 100644 --- a/Code/Framework/AzCore/AzCore/Console/Console.cpp +++ b/Code/Framework/AzCore/AzCore/Console/Console.cpp @@ -476,15 +476,16 @@ namespace AZ // Responsible for using the Json Serialization Issue Callback system // to determine when a JSON Patch or JSON Merge Patch modifies a value - // at a path underneath the IConsole::ConsoleRootCommandKey JSON pointer + // at a path underneath the IConsole::ConsoleRuntimeCommandKey JSON pointer JsonSerializationResult::ResultCode operator()(AZStd::string_view message, JsonSerializationResult::ResultCode result, AZStd::string_view path) { - AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator }; + constexpr AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRuntimeCommandKey, AZ::IO::PosixPathSeparator }; + constexpr AZ::IO::PathView consoleAutoexecCommandKey{ IConsole::ConsoleAutoexecCommandKey, AZ::IO::PosixPathSeparator }; AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; if (result.GetTask() == JsonSerializationResult::Tasks::Merge && result.GetProcessing() == JsonSerializationResult::Processing::Completed - && inputKey.IsRelativeTo(consoleRootCommandKey)) + && (inputKey.IsRelativeTo(consoleRootCommandKey) || inputKey.IsRelativeTo(consoleAutoexecCommandKey))) { if (auto type = m_settingsRegistry.GetType(path); type != SettingsRegistryInterface::Type::NoType) { @@ -510,12 +511,24 @@ namespace AZ { using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; - AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator }; + constexpr AZ::IO::PathView consoleRuntimeCommandKey{ IConsole::ConsoleRuntimeCommandKey, AZ::IO::PosixPathSeparator }; + constexpr AZ::IO::PathView consoleAutoexecCommandKey{ IConsole::ConsoleAutoexecCommandKey, AZ::IO::PosixPathSeparator }; AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; - // The ConsoleRootComamndKey is not a command itself so strictly children keys are being examined - if (inputKey.IsRelativeTo(consoleRootCommandKey) && inputKey != consoleRootCommandKey) + + // Abuses the IsRelativeToFuncton function of the path class to extract the console + // command from the settings registry objects + FixedValueString command; + if (inputKey != consoleRuntimeCommandKey && inputKey.IsRelativeTo(consoleRuntimeCommandKey)) + { + command = inputKey.LexicallyRelative(consoleRuntimeCommandKey).Native(); + } + else if (inputKey != consoleAutoexecCommandKey && inputKey.IsRelativeTo(consoleAutoexecCommandKey)) + { + command = inputKey.LexicallyRelative(consoleAutoexecCommandKey).Native(); + } + + if (!command.empty()) { - FixedValueString command = inputKey.LexicallyRelative(consoleRootCommandKey).Native(); ConsoleCommandContainer commandArgs; // Argument string which stores the value from the Settings Registry long enough // to pass into the PerformCommand. The ConsoleCommandContainer stores string_views @@ -603,9 +616,10 @@ namespace AZ void Console::RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry) { - // Make sure the there is a JSON object at the path of AZ::IConsole::ConsoleRootCommandKey + // Make sure the there is a JSON object at the ConsoleRuntimeCommandKey or ConsoleAutoexecKey // So that JSON Patch is able to add values underneath that object (JSON Patch doesn't create intermediate objects) - settingsRegistry.MergeSettings(R"({ "Amazon": { "AzCore": { "Runtime": { "ConsoleCommands": {} } }}})", + settingsRegistry.MergeSettings(R"({ "Amazon": { "AzCore": { "Runtime": { "ConsoleCommands": {} } } })" + R"(,"O3DE": { "Autoexec": { "ConsoleCommands": {} } } })", SettingsRegistryInterface::Format::JsonMergePatch); m_consoleCommandKeyHandler = settingsRegistry.RegisterNotifier(ConsoleCommandKeyNotificationHandler{ settingsRegistry, *this }); diff --git a/Code/Framework/AzCore/AzCore/Console/IConsole.h b/Code/Framework/AzCore/AzCore/Console/IConsole.h index dafc284ce3..73d17ac65a 100644 --- a/Code/Framework/AzCore/AzCore/Console/IConsole.h +++ b/Code/Framework/AzCore/AzCore/Console/IConsole.h @@ -31,7 +31,8 @@ namespace AZ using FunctorVisitor = AZStd::function; - inline static constexpr AZStd::string_view ConsoleRootCommandKey = "/Amazon/AzCore/Runtime/ConsoleCommands"; + inline static constexpr AZStd::string_view ConsoleRuntimeCommandKey = "/Amazon/AzCore/Runtime/ConsoleCommands"; + inline static constexpr AZStd::string_view ConsoleAutoexecCommandKey = "/O3DE/Autoexec/ConsoleCommands"; IConsole() = default; virtual ~IConsole() = default; From 70053f055a7dbbdd336d7027ca938ba2492f3e4f Mon Sep 17 00:00:00 2001 From: nggieber Date: Fri, 8 Oct 2021 16:52:58 -0700 Subject: [PATCH 155/293] More python PR feedback Signed-off-by: nggieber --- scripts/o3de/o3de/manifest.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 5d34c4bcf9..c5f6315474 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -423,11 +423,8 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa def get_json_file_path(object_typename: str, object_path: str or pathlib.Path = None) -> pathlib.Path: - if not object_typename: - logger.error('Missing object typename.') - return None - - if not object_path: + if not object_typename or not object_path: + logger.error('Must specify an object typename and object path.') return None object_path = pathlib.Path(object_path).resolve() @@ -439,9 +436,11 @@ def get_json_data_file(object_json: pathlib.Path, object_validator = callable) -> dict or None: if not object_typename: logger.error('Missing object typename.') + return None if not object_json: - logger.error(f'No object_json provided for {object_typename}') + logger.error(f'No object json provided for {object_typename}') + return None if not object_json.is_file(): logger.error(f'{object_typename} json {object_json} is not present.') @@ -449,6 +448,7 @@ def get_json_data_file(object_json: pathlib.Path, if not object_validator: logger.error('Missing object validator.') + return None if not object_validator(object_json): logger.error(f'{object_typename} json {object_json} is not valid.') @@ -472,6 +472,7 @@ def get_json_data(object_typename: str = None, if not object_json and object_name: logger.error(f'{object_name} has not been registered.') + return None return get_json_data_file(object_json, object_typename, object_validator) From 7b1dd01d1d648b2e449dba283d051bcae2414483 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 8 Oct 2021 20:09:22 -0500 Subject: [PATCH 156/293] Implemented a deferred LoadLevel queue for the SpawnableLevelSystem (#4561) * Moved the SettingsRegistryTests.cpp and SettingsRegistryMergeUtilsTests.cpp to the Settings folder Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Implemented a deferred level load queue, that allows the SpawnableLevelSystem to re-run the last LoadLevel command that occured before it was constructed. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added SettingsRegistryVisitorUtils to reduce Array and Object visitor boilerplate. The VisitArray and VisitObject functions allows iteration over each element of array and object respectively via a callback. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed the queuing logic for levels that attempt to load before the SpawnableLevelSystem is available Only the last level name that could not load is stored off and deferred until the SpawnableLevelsystem is created. Made the FieldVisitor AggregateTypes constructor protected and added a comment specifying the expected values. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Bring in the SettingsRegistry::Visitor::Visit functions into scope to fix MSVC compilation errors. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed the list of supported SettingsRegistry types to visit to an enum to constrain the values to Array and/or Object. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Settings/SettingsRegistry.h | 4 +- .../Settings/SettingsRegistryVisitorUtils.cpp | 136 ++++++++++++ .../Settings/SettingsRegistryVisitorUtils.h | 83 ++++++++ .../AzCore/AzCore/azcore_files.cmake | 2 + .../SettingsRegistryMergeUtilsTests.cpp | 0 .../{ => Settings}/SettingsRegistryTests.cpp | 0 .../SettingsRegistryVisitorUtilsTests.cpp | 196 ++++++++++++++++++ .../AzCore/Tests/azcoretests_files.cmake | 5 +- .../LevelSystem/SpawnableLevelSystem.cpp | 35 +++- Registry/setregbuilder.assetprocessor.setreg | 3 +- 10 files changed, 456 insertions(+), 8 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp create mode 100644 Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h rename Code/Framework/AzCore/Tests/{ => Settings}/SettingsRegistryMergeUtilsTests.cpp (100%) rename Code/Framework/AzCore/Tests/{ => Settings}/SettingsRegistryTests.cpp (100%) create mode 100644 Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h index 3dc1be87c5..40022bdc04 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h @@ -204,14 +204,14 @@ namespace AZ [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent(const PreMergeEventCallback& callback) = 0; //! Register a function that will be called before a file is merged. //! @callback The function to call before a file is merged. - [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent (PreMergeEventCallback&& callback) = 0; + [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent(PreMergeEventCallback&& callback) = 0; //! Register a function that will be called after a file is merged. //! @callback The function to call after a file is merged. [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent(const PostMergeEventCallback& callback) = 0; //! Register a function that will be called after a file is merged. //! @callback The function to call after a file is merged. - [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent (PostMergeEventCallback&& callback) = 0; + [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent(PostMergeEventCallback&& callback) = 0; //! Gets the boolean value at the provided path. //! @param result The target to write the result to. diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp new file mode 100644 index 0000000000..9456616024 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp @@ -0,0 +1,136 @@ +/* + * 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 + + +namespace AZ::SettingsRegistryVisitorUtils +{ + // Field Visitor implementation + FieldVisitor::FieldVisitor() = default; + FieldVisitor::FieldVisitor(VisitFieldType visitFieldType) + : m_visitFieldType{ visitFieldType } + { + } + + auto FieldVisitor::Traverse(AZStd::string_view path, AZStd::string_view valueName, + VisitAction action, Type type) -> VisitResponse + { + // A default response skip prevents visiting grand children(depth 2 or lower) + VisitResponse visitResponse = VisitResponse::Skip; + if (action == VisitAction::Begin) + { + // Invoke FieldVisitor override if the root path has been set + if (m_rootPath.has_value()) + { + Visit(path, valueName, type); + } + // To make sure only the direct children are visited(depth 1) + // set the root path once and set the VisitReponsoe + // to Continue to recurse into is fields + if (!m_rootPath.has_value()) + { + bool visitableFieldType{}; + switch (m_visitFieldType) + { + case VisitFieldType::Array: + visitableFieldType = type == Type::Array; + break; + case VisitFieldType::Object: + visitableFieldType = type == Type::Object; + break; + case VisitFieldType::ArrayOrObject: + visitableFieldType = type == Type::Array || type ==Type::Object; + break; + default: + AZ_Error("FieldVisitor", false, "The field visitation type value is invalid"); + break; + } + + if (visitableFieldType) + { + m_rootPath = path; + visitResponse = VisitResponse::Continue; + } + } + } + else if (action == VisitAction::Value) + { + // Invoke FieldVisitor override if the root path has been set + if (m_rootPath.has_value()) + { + Visit(path, valueName, type); + } + } + else if (action == VisitAction::End) + { + // Reset m_rootPath back to null when the root path has finished being visited + if (m_rootPath.has_value() && *m_rootPath == path) + { + m_rootPath = AZStd::nullopt; + } + } + + + return visitResponse; + } + + // Array Visitor implementation + ArrayVisitor::ArrayVisitor() + : FieldVisitor(VisitFieldType::Array) + { + } + + // Object Visitor implementation + ObjectVisitor::ObjectVisitor() + : FieldVisitor(VisitFieldType::Object) + { + } + + // Generic VisitField Callback implemention + template + bool VisitFieldCallback(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path) + { + struct VisitFieldVisitor + : BaseVisitor + { + using BaseVisitor::Visit; + VisitFieldVisitor(const VisitorCallback& visitCallback) + : m_visitCallback{ visitCallback } + {} + + void Visit(AZStd::string_view path, AZStd::string_view fieldIndex, typename BaseVisitor::Type type) override + { + m_visitCallback(path, fieldIndex, type); + } + + const VisitorCallback& m_visitCallback; + }; + + VisitFieldVisitor visitor{ visitCallback }; + return settingsRegistry.Visit(visitor, path); + } + + // VisitField implementation + bool VisitField(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path) + { + return VisitFieldCallback(settingsRegistry, visitCallback, path); + } + + // VisitArray implementation + bool VisitArray(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path) + { + return VisitFieldCallback(settingsRegistry, visitCallback, path); + } + + // VisitObject implementation + bool VisitObject(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path) + { + return VisitFieldCallback(settingsRegistry, visitCallback, path); + } +} diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h new file mode 100644 index 0000000000..a45712521f --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + + +namespace AZ::SettingsRegistryVisitorUtils +{ + //! Interface for visiting the fields of an array or object + //! To access the values, use the SettingsRegistryInterface Get/GetObject methods + struct FieldVisitor + : public AZ::SettingsRegistryInterface::Visitor + { + using VisitResponse = AZ::SettingsRegistryInterface::VisitResponse; + using VisitAction = AZ::SettingsRegistryInterface::VisitAction; + using Type = AZ::SettingsRegistryInterface::Type; + + FieldVisitor(); + + // Bring the base class visitor functions into scope + using AZ::SettingsRegistryInterface::Visitor::Visit; + virtual void Visit(AZStd::string_view path, AZStd::string_view arrayIndex, Type type) = 0; + + protected: + // VisitFieldType is used for filtering the type of referenced by the root path + enum class VisitFieldType + { + Array, + Object, + ArrayOrObject + }; + FieldVisitor(const VisitFieldType visitFieldType); + private: + VisitResponse Traverse(AZStd::string_view path, AZStd::string_view valueName, + VisitAction action, Type type) override; + + VisitFieldType m_visitFieldType{ VisitFieldType::ArrayOrObject }; + AZStd::optional m_rootPath; + }; + + //! Interface for visiting the fields of an array + //! To access the values, use the SettingsRegistryInterface Get/GetObject methods + struct ArrayVisitor + : public FieldVisitor + { + ArrayVisitor(); + }; + + //! Interface for visiting the fields of an object + //! To access the values, use the SettingsRegistryInterface Get/GetObject methods + struct ObjectVisitor + : public FieldVisitor + { + ObjectVisitor(); + }; + + //! Signature of callback funcition invoked when visiting an element of an array or object + using VisitorCallback = AZStd::function; + + //! Invokes the visitor callback for each element of either the array or object at @path + //! If @path is not an array or object, then no elements are visited + //! This function will not recurse into children of elements + //! @visitCallback functor that is invoked for each array or object element found + bool VisitField(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path); + //! Invokes the visitor callback for each element of the array at @path + //! If @path is not an array, then no elements are visited + //! This function will not recurse into children of elements + //! @visitCallback functor that is invoked for each array element found + bool VisitArray(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path); + //! Invokes the visitor callback for each element of the object at @path + //! If @path is not an object, then no elements are visited + //! This function will not recurse into children of elements + //! @visitCallback functor that is invoked for each object element found + bool VisitObject(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path); +} diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 010c748402..6675958247 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -566,6 +566,8 @@ set(FILES Settings/SettingsRegistryMergeUtils.h Settings/SettingsRegistryScriptUtils.cpp Settings/SettingsRegistryScriptUtils.h + Settings/SettingsRegistryVisitorUtils.cpp + Settings/SettingsRegistryVisitorUtils.h State/HSM.cpp State/HSM.h Statistics/NamedRunningStatistic.h diff --git a/Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryMergeUtilsTests.cpp similarity index 100% rename from Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp rename to Code/Framework/AzCore/Tests/Settings/SettingsRegistryMergeUtilsTests.cpp diff --git a/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryTests.cpp similarity index 100% rename from Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp rename to Code/Framework/AzCore/Tests/Settings/SettingsRegistryTests.cpp diff --git a/Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp new file mode 100644 index 0000000000..15f346ee93 --- /dev/null +++ b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + + +#include +#include +#include +#include +#include +#include + +namespace SettingsRegistryVisitorUtilsTests +{ + struct VisitCallbackParams + { + AZStd::string_view m_inputJsonDocument; + using VisitFieldFunction = bool(*)(AZ::SettingsRegistryInterface&, + const AZ::SettingsRegistryVisitorUtils::VisitorCallback&, + AZStd::string_view); + + static inline constexpr size_t MaxFieldCount = 10; + using ObjectFields = AZStd::fixed_vector, MaxFieldCount>; + using ArrayFields = AZStd::fixed_vector; + ObjectFields m_objectFields; + ArrayFields m_arrayFields; + }; + + template + class SettingsRegistryVisitorUtilsParamFixture + : public UnitTest::ScopedAllocatorSetupFixture + , public ::testing::WithParamInterface + { + public: + + void SetUp() override + { + m_registry = AZStd::make_unique(); + } + + void TearDown() override + { + m_registry.reset(); + } + + AZStd::unique_ptr m_registry; + }; + + using SettingsRegistryVisitCallbackFixture = SettingsRegistryVisitorUtilsParamFixture; + + TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitFieldsOfArrayType_ReturnsFields) + { + const VisitCallbackParams& visitParams = GetParam(); + + ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch)); + + AZStd::fixed_vector testArrayFields; + auto visitorCallback = [this, &testArrayFields](AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type) + { + AZStd::string fieldValue; + EXPECT_TRUE(m_registry->Get(fieldValue, path)); + testArrayFields.emplace_back(AZStd::move(fieldValue)); + }; + + AZ::SettingsRegistryVisitorUtils::VisitField(*m_registry, visitorCallback, "/Test/Array"); + + const AZStd::fixed_vector expectedFields{ + visitParams.m_arrayFields.begin(), visitParams.m_arrayFields.end() }; + EXPECT_THAT(testArrayFields, ::testing::ContainerEq(expectedFields)); + } + + TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitFieldsOfObjectType_ReturnsFields) + { + const VisitCallbackParams& visitParams = GetParam(); + + ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch)); + + AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> testObjectFields; + auto visitorCallback = [this, &testObjectFields](AZStd::string_view path, AZStd::string_view fieldName, AZ::SettingsRegistryInterface::Type) + { + AZStd::string fieldValue; + EXPECT_TRUE(m_registry->Get(fieldValue, path)); + testObjectFields.emplace_back(fieldName, AZStd::move(fieldValue)); + }; + + AZ::SettingsRegistryVisitorUtils::VisitField(*m_registry, visitorCallback, "/Test/Object"); + + const AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> expectedFields{ + visitParams.m_objectFields.begin(), visitParams.m_objectFields.end() }; + EXPECT_THAT(testObjectFields, ::testing::ContainerEq(expectedFields)); + } + + TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitArrayOfArrayType_ReturnsFields) + { + const VisitCallbackParams& visitParams = GetParam(); + + ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch)); + + AZStd::fixed_vector testArrayFields; + auto visitorCallback = [this, &testArrayFields](AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type) + { + AZStd::string fieldValue; + EXPECT_TRUE(m_registry->Get(fieldValue, path)); + testArrayFields.emplace_back(AZStd::move(fieldValue)); + }; + + AZ::SettingsRegistryVisitorUtils::VisitArray(*m_registry, visitorCallback, "/Test/Array"); + + const AZStd::fixed_vector expectedArrayFields{ + visitParams.m_arrayFields.begin(), visitParams.m_arrayFields.end() }; + EXPECT_THAT(testArrayFields, ::testing::ContainerEq(expectedArrayFields)); + } + + TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitArrayOfObjectType_ReturnsEmpty) + { + const VisitCallbackParams& visitParams = GetParam(); + + ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch)); + + AZStd::fixed_vector testArrayFields; + auto visitorCallback = [this, &testArrayFields](AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type) + { + AZStd::string fieldValue; + EXPECT_TRUE(m_registry->Get(fieldValue, path)); + testArrayFields.emplace_back(AZStd::move(fieldValue)); + }; + + AZ::SettingsRegistryVisitorUtils::VisitArray(*m_registry, visitorCallback, "/Test/Object"); + + EXPECT_TRUE(testArrayFields.empty()); + } + + TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitObjectOfArrayType_ReturnsEmpty) + { + const VisitCallbackParams& visitParams = GetParam(); + + ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch)); + + AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> testObjectFields; + auto visitorCallback = [this, &testObjectFields](AZStd::string_view path, AZStd::string_view fieldName, AZ::SettingsRegistryInterface::Type) + { + AZStd::string fieldValue; + EXPECT_TRUE(m_registry->Get(fieldValue, path)); + testObjectFields.emplace_back(fieldName, AZStd::move(fieldValue)); + }; + + AZ::SettingsRegistryVisitorUtils::VisitObject(*m_registry, visitorCallback, "/Test/Array"); + + EXPECT_TRUE(testObjectFields.empty()); + } + + TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitObjectOfObjectType_ReturnsFields) + { + const VisitCallbackParams& visitParams = GetParam(); + + ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch)); + + AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> testObjectFields; + auto visitorCallback = [this, &testObjectFields](AZStd::string_view path, AZStd::string_view fieldName, AZ::SettingsRegistryInterface::Type) + { + AZStd::string fieldValue; + EXPECT_TRUE(m_registry->Get(fieldValue, path)); + testObjectFields.emplace_back(fieldName, AZStd::move(fieldValue)); + }; + + AZ::SettingsRegistryVisitorUtils::VisitObject(*m_registry, visitorCallback, "/Test/Object"); + + const AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> expectedObjectFields{ + visitParams.m_objectFields.begin(), visitParams.m_objectFields.end() }; + EXPECT_THAT(testObjectFields, ::testing::ContainerEq(expectedObjectFields)); + } + + + INSTANTIATE_TEST_CASE_P( + VisitField, + SettingsRegistryVisitCallbackFixture, + ::testing::Values( + VisitCallbackParams + { + R"({)" "\n" + R"( "Test":)" "\n" + R"( {)" "\n" + R"( "Array": [ "Hello", "World" ],)" "\n" + R"( "Object": { "Foo": "Hello", "Bar": "World"})" "\n" + R"( })" "\n" + R"(})" "\n", + VisitCallbackParams::ObjectFields{{"Foo", "Hello"}, {"Bar", "World"}}, + VisitCallbackParams::ArrayFields{"Hello", "World"} + } + ) + ); +} diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index e155594aa0..d738711a4f 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -75,11 +75,12 @@ set(FILES Name/NameJsonSerializerTests.cpp Name/NameTests.cpp RTTI/TypeSafeIntegralTests.cpp - SettingsRegistryTests.cpp - SettingsRegistryMergeUtilsTests.cpp Settings/CommandLineTests.cpp + Settings/SettingsRegistryTests.cpp Settings/SettingsRegistryConsoleUtilsTests.cpp + Settings/SettingsRegistryMergeUtilsTests.cpp Settings/SettingsRegistryScriptUtilsTests.cpp + Settings/SettingsRegistryVisitorUtilsTests.cpp Streamer/BlockCacheTests.cpp Streamer/DedicatedCacheTests.cpp Streamer/FullDecompressorTests.cpp diff --git a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index a82c4a6914..b2b67c3b75 100644 --- a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -22,22 +22,33 @@ #include #include #include +#include #include #include namespace LegacyLevelSystem { + constexpr AZStd::string_view DeferredLoadLevelKey = "/O3DE/Runtime/SpawnableLevelSystem/DeferredLoadLevel"; //------------------------------------------------------------------------ static void LoadLevel(const AZ::ConsoleCommandContainer& arguments) { AZ_Error("SpawnableLevelSystem", !arguments.empty(), "LoadLevel requires a level file name to be provided."); AZ_Error("SpawnableLevelSystem", arguments.size() == 1, "LoadLevel requires a single level file name to be provided."); - if (!arguments.empty() && gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor()) + if (!arguments.empty() && gEnv && gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor()) { gEnv->pSystem->GetILevelSystem()->LoadLevel(arguments[0].data()); } + else if (!arguments.empty()) + { + // The SpawnableLevelSystem isn't available yet. + // Defer the level load until later by storing it in the SettingsRegistry + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Set(DeferredLoadLevelKey, arguments.front()); + } + } } //------------------------------------------------------------------------ @@ -45,7 +56,7 @@ namespace LegacyLevelSystem { AZ_Warning("SpawnableLevelSystem", !arguments.empty(), "UnloadLevel doesn't use any arguments."); - if (gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor()) + if (gEnv && gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor()) { gEnv->pSystem->GetILevelSystem()->UnloadLevel(); } @@ -73,6 +84,24 @@ namespace LegacyLevelSystem } AzFramework::RootSpawnableNotificationBus::Handler::BusConnect(); + + // If there were LoadLevel command invocations before the creation of the level system + // then those invocations were queued. + // load the last level in the queue, since only one level can be loaded at a time + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (AZ::SettingsRegistryInterface::FixedValueString deferredLevelName; + settingsRegistry->Get(deferredLevelName, DeferredLoadLevelKey) && !deferredLevelName.empty()) + { + // since this is the constructor any derived classes vtables aren't setup yet + // call this class LoadLevel function + AZ_TracePrintf("SpawnableLevelSystem", "The Level System is now available." + " Loading level %s which could not be loaded earlier\n", deferredLevelName.c_str()); + SpawnableLevelSystem::LoadLevel(deferredLevelName.c_str()); + // Delete the key with the deferred level name + settingsRegistry->Remove(DeferredLoadLevelKey); + } + } } //------------------------------------------------------------------------ @@ -173,7 +202,7 @@ namespace LegacyLevelSystem } // Make sure a spawnable level exists that matches levelname - AZStd::string validLevelName = ""; + AZStd::string validLevelName; AZ::Data::AssetId rootSpawnableAssetId; AZ::Data::AssetCatalogRequestBus::BroadcastResult( rootSpawnableAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, levelName, nullptr, false); diff --git a/Registry/setregbuilder.assetprocessor.setreg b/Registry/setregbuilder.assetprocessor.setreg index 25b51470bf..00e6e2f7f8 100644 --- a/Registry/setregbuilder.assetprocessor.setreg +++ b/Registry/setregbuilder.assetprocessor.setreg @@ -20,7 +20,8 @@ "Excludes": [ "/Amazon/AzCore/Runtime", - "/Amazon/AzCore/Bootstrap/project_path" + "/Amazon/AzCore/Bootstrap/project_path", + "/O3DE/Runtime", ] } } From 2c6cfdd7dc73a57a1ed1714c8c3a5dacdc1e9258 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 9 Oct 2021 18:17:50 -0500 Subject: [PATCH 157/293] Implemented support for semi-live previews of materials in the material property inspector. Changed thumbnailer bus to use const pixmap Changed capture request call back to use const pixmap instead of image Replaced scene and pipeline members with constructor parameters Added material preview renderer to editor material system component with new requests and notifications Changed material property inspector details group to persistent heading so the preview image widget would not get destroyed during refreshes. But this was also a backlog task. Changed common preview render camera to use lookat Moved default asset caching to thumbnail renderer Signed-off-by: Guthrie Adams --- .../Thumbnails/ThumbnailerBus.h | 2 +- .../Code/Source/Thumbnail/ImageThumbnail.cpp | 2 +- .../Code/Source/Thumbnail/ImageThumbnail.h | 2 +- .../PreviewRenderer/PreviewRenderer.h | 12 +- .../PreviewRenderer/PreviewRenderer.cpp | 25 +-- ...orMaterialSystemComponentNotificationBus.h | 35 ++++ .../EditorMaterialSystemComponentRequestBus.h | 8 +- .../EditorCommonFeaturesSystemComponent.cpp | 2 +- .../EditorMaterialComponentInspector.cpp | 177 +++++++++--------- .../EditorMaterialComponentInspector.h | 19 +- .../Material/EditorMaterialComponentSlot.cpp | 3 + .../EditorMaterialSystemComponent.cpp | 69 ++++++- .../Material/EditorMaterialSystemComponent.h | 30 ++- .../Source/Previewer/CommonPreviewContent.cpp | 75 ++++---- .../Source/Previewer/CommonPreviewContent.h | 21 +-- .../Previewer/CommonThumbnailRenderer.cpp | 41 ++-- .../Previewer/CommonThumbnailRenderer.h | 18 +- .../Previewer/LightingPresetThumbnail.cpp | 2 +- .../Previewer/LightingPresetThumbnail.h | 2 +- .../Source/Previewer/MaterialThumbnail.cpp | 2 +- .../Code/Source/Previewer/MaterialThumbnail.h | 2 +- .../Code/Source/Previewer/ModelThumbnail.cpp | 2 +- .../Code/Source/Previewer/ModelThumbnail.h | 2 +- .../Code/Source/Previewer/ThumbnailUtils.cpp | 13 +- .../Code/Source/Previewer/ThumbnailUtils.h | 5 +- ...egration_commonfeatures_editor_files.cmake | 1 + 26 files changed, 367 insertions(+), 205 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h index 6f074da878..acd8ba3966 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h @@ -90,7 +90,7 @@ namespace AzToolsFramework typedef SharedThumbnailKey BusIdType; //! notify product thumbnail that the data is ready - virtual void ThumbnailRendered(QPixmap& thumbnailImage) = 0; + virtual void ThumbnailRendered(const QPixmap& thumbnailImage) = 0; //! notify product thumbnail that the thumbnail failed to render virtual void ThumbnailFailedToRender() = 0; }; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp index 084e38a2db..cdd63dca18 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp @@ -67,7 +67,7 @@ namespace ImageProcessingAtom m_renderWait.acquire(); } - void ImageThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void ImageThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h index 45fd178285..eadbfca945 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h @@ -34,7 +34,7 @@ namespace ImageProcessingAtom ~ImageThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailRendered(const QPixmap& thumbnailImage) override; void ThumbnailFailedToRender() override; protected: diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h index b772bfcaf2..acedc77751 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h @@ -20,7 +20,7 @@ namespace AzFramework class Scene; } -class QImage; +class QPixmap; namespace AtomToolsFramework { @@ -30,7 +30,7 @@ namespace AtomToolsFramework public: AZ_CLASS_ALLOCATOR(PreviewRenderer, AZ::SystemAllocator, 0); - PreviewRenderer(); + PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName); ~PreviewRenderer(); struct CaptureRequest final @@ -38,15 +38,15 @@ namespace AtomToolsFramework int m_size = 512; AZStd::shared_ptr m_content; AZStd::function m_captureFailedCallback; - AZStd::function m_captureCompleteCallback; + AZStd::function m_captureCompleteCallback; }; + void AddCaptureRequest(const CaptureRequest& captureRequest); + AZ::RPI::ScenePtr GetScene() const; AZ::RPI::ViewPtr GetView() const; AZ::Uuid GetEntityContextId() const; - void AddCaptureRequest(const CaptureRequest& captureRequest); - enum class State : AZ::s8 { None, @@ -81,8 +81,6 @@ namespace AtomToolsFramework static constexpr float FieldOfView = AZ::Constants::HalfPi; AZ::RPI::ScenePtr m_scene; - AZStd::string m_sceneName = "Preview Renderer Scene"; - AZStd::string m_pipelineName = "Preview Renderer Pipeline"; AZStd::shared_ptr m_frameworkScene; AZ::RPI::RenderPipelinePtr m_renderPipeline; AZ::RPI::ViewPtr m_view; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index dfefd0203e..06969abee4 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -24,9 +24,12 @@ #include #include +#include +#include + namespace AtomToolsFramework { - PreviewRenderer::PreviewRenderer() + PreviewRenderer::PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName) { PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); @@ -46,7 +49,7 @@ namespace AtomToolsFramework auto sceneSystem = AzFramework::SceneSystemInterface::Get(); AZ_Assert(sceneSystem, "Failed to get scene system implementation."); - AZ::Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(m_sceneName); + AZ::Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(sceneName); AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); m_frameworkScene = createSceneOutcome.TakeValue(); @@ -56,7 +59,7 @@ namespace AtomToolsFramework // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene AZ::RPI::RenderPipelineDescriptor pipelineDesc; pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = m_pipelineName; + pipelineDesc.m_name = pipelineName; pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue @@ -66,7 +69,7 @@ namespace AtomToolsFramework m_scene->AddRenderPipeline(m_renderPipeline); m_scene->Activate(); AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); - m_passHierarchy.push_back(m_pipelineName); + m_passHierarchy.push_back(pipelineName); m_passHierarchy.push_back("CopyToSwapChain"); // Connect camera to pipeline's default view after camera entity activated @@ -97,6 +100,11 @@ namespace AtomToolsFramework m_frameworkScene->UnsetSubsystem(m_entityContext.get()); } + void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) + { + m_captureRequestQueue.push(captureRequest); + } + AZ::RPI::ScenePtr PreviewRenderer::GetScene() const { return m_scene; @@ -112,11 +120,6 @@ namespace AtomToolsFramework return m_entityContext->GetContextId(); } - void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) - { - m_captureRequestQueue.push(captureRequest); - } - void PreviewRenderer::SetState(State state) { auto stepItr = m_states.find(m_currentState); @@ -199,9 +202,9 @@ namespace AtomToolsFramework { if (result.m_dataBuffer) { - currentCaptureRequest.m_captureCompleteCallback(QImage( + currentCaptureRequest.m_captureCompleteCallback(QPixmap::fromImage(QImage( result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, - QImage::Format_RGBA8888)); + QImage::Format_RGBA8888))); } else { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h new file mode 100644 index 0000000000..4e655c7835 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include + +class QPixmap; + +namespace AZ +{ + namespace Render + { + //! EditorMaterialSystemComponentNotifications provides an interface to communicate with EditorMaterialSystemComponent + class EditorMaterialSystemComponentNotifications : public AZ::EBusTraits + { + public: + // Only a single handler is allowed + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + + //! Notify that a material preview image is ready + virtual void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) = 0; + }; + using EditorMaterialSystemComponentNotificationBus = AZ::EBus; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h index 47fad038b6..059e6dec8e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -17,8 +18,7 @@ namespace AZ namespace Render { //! EditorMaterialSystemComponentRequests provides an interface to communicate with MaterialEditor - class EditorMaterialSystemComponentRequests - : public AZ::EBusTraits + class EditorMaterialSystemComponentRequests : public AZ::EBusTraits { public: // Only a single handler is allowed @@ -31,6 +31,10 @@ namespace AZ //! Open material instance editor virtual void OpenMaterialInspector( const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0; + + //! Generate a material preview image + virtual void RenderMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0; }; using EditorMaterialSystemComponentRequestBus = AZ::EBus; } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 19a7eda24b..34cd9f59d0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -98,9 +98,9 @@ namespace AZ void EditorCommonFeaturesSystemComponent::Deactivate() { - AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect(); m_skinnedMeshDebugDisplay.reset(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 665adcd568..7562049031 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -23,10 +23,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -49,29 +45,18 @@ namespace AZ MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent) : AtomToolsFramework::InspectorWidget(parent) { - // Create the menu button - QToolButton* menuButton = new QToolButton(this); - menuButton->setAutoRaise(true); - menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg")); - menuButton->setVisible(true); - QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); }); - AddHeading(menuButton); - - m_messageLabel = new QLabel(this); - m_messageLabel->setWordWrap(true); - m_messageLabel->setVisible(true); - m_messageLabel->setAlignment(Qt::AlignCenter); - m_messageLabel->setText(tr("Material not available")); - AddHeading(m_messageLabel); - + CreateHeading(); + AZ::TickBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); } MaterialPropertyInspector::~MaterialPropertyInspector() { AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); - AZ::EntitySystemBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); + AZ::EntitySystemBus::Handler::BusDisconnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); MaterialComponentNotificationBus::Handler::BusDisconnect(); } @@ -140,7 +125,7 @@ namespace AZ } Populate(); - m_messageLabel->setVisible(false); + LoadOverridesFromEntity(); return true; } @@ -152,8 +137,9 @@ namespace AZ m_dirtyPropertyFlags.set(); m_editorFunctors = {}; m_internalEditNotification = {}; - m_messageLabel->setVisible(true); - m_messageLabel->setText(tr("Material not available")); + m_updateUI = {}; + m_updatePreview = {}; + UpdateHeading(); } bool MaterialPropertyInspector::IsLoaded() const @@ -168,49 +154,62 @@ namespace AZ m_dirtyPropertyFlags.set(); m_internalEditNotification = {}; - AZ::TickBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorWidget::Reset(); } - void MaterialPropertyInspector::AddDetailsGroup() + void MaterialPropertyInspector::CreateHeading() { - const AZStd::string& groupName = "Details"; - const AZStd::string& groupDisplayName = "Details"; - const AZStd::string& groupDescription = ""; - - auto propertyGroupContainer = new QWidget(this); - propertyGroupContainer->setLayout(new QHBoxLayout()); + // Create the menu button + QToolButton* menuButton = new QToolButton(this); + menuButton->setAutoRaise(true); + menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg")); + menuButton->setVisible(true); + QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); }); + AddHeading(menuButton); - AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey = - MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, m_editData.m_materialAssetId); - auto thumbnailWidget = new AzToolsFramework::Thumbnailer::ThumbnailWidget(this); - thumbnailWidget->setFixedSize(QSize(120, 120)); - thumbnailWidget->setVisible(true); - thumbnailWidget->SetThumbnailKey(thumbnailKey, AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext); - propertyGroupContainer->layout()->addWidget(thumbnailWidget); + m_overviewImage = new QLabel(this); + m_overviewImage->setFixedSize(QSize(120, 120)); + m_overviewImage->setVisible(false); - auto materialInfoWidget = new QLabel(this); + m_overviewText = new QLabel(this); QSizePolicy sizePolicy1(QSizePolicy::Ignored, QSizePolicy::Preferred); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth(materialInfoWidget->sizePolicy().hasHeightForWidth()); - materialInfoWidget->setSizePolicy(sizePolicy1); - materialInfoWidget->setMinimumSize(QSize(0, 0)); - materialInfoWidget->setMaximumSize(QSize(16777215, 16777215)); - materialInfoWidget->setTextFormat(Qt::AutoText); - materialInfoWidget->setScaledContents(false); - materialInfoWidget->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - materialInfoWidget->setWordWrap(true); + sizePolicy1.setHeightForWidth(m_overviewText->sizePolicy().hasHeightForWidth()); + m_overviewText->setSizePolicy(sizePolicy1); + m_overviewText->setMinimumSize(QSize(0, 0)); + m_overviewText->setMaximumSize(QSize(16777215, 16777215)); + m_overviewText->setTextFormat(Qt::AutoText); + m_overviewText->setScaledContents(false); + m_overviewText->setWordWrap(true); + m_overviewText->setVisible(true); + + auto overviewContainer = new QWidget(this); + overviewContainer->setLayout(new QHBoxLayout()); + overviewContainer->layout()->addWidget(m_overviewImage); + overviewContainer->layout()->addWidget(m_overviewText); + AddHeading(overviewContainer); + } + + void MaterialPropertyInspector::UpdateHeading() + { + if (!IsLoaded()) + { + m_overviewText->setText(tr("Material not available")); + m_overviewText->setAlignment(Qt::AlignCenter); + m_overviewImage->setVisible(false); + return; + } QFileInfo materialFileInfo(AZ::RPI::AssetUtils::GetProductPathByAssetId(m_editData.m_materialAsset.GetId()).c_str()); QFileInfo materialSourceFileInfo(m_editData.m_materialSourcePath.c_str()); QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str()); - QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str()); + QFileInfo materialParentSourceFileInfo( + AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str()); AZStd::string entityName; - AZ::ComponentApplicationBus::BroadcastResult( - entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId); + AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId); AZStd::string slotName; MaterialComponentRequestBus::EventResult( @@ -226,7 +225,8 @@ namespace AZ } if (!materialTypeSourceFileInfo.fileName().isEmpty()) { - materialInfo += tr("Material Type %1").arg(materialTypeSourceFileInfo.fileName()); + materialInfo += + tr("Material Type %1").arg(materialTypeSourceFileInfo.fileName()); } if (!materialSourceFileInfo.fileName().isEmpty()) { @@ -234,14 +234,15 @@ namespace AZ } if (!materialParentSourceFileInfo.fileName().isEmpty()) { - materialInfo += tr("Material Parent %1").arg(materialParentSourceFileInfo.fileName()); + materialInfo += + tr("Material Parent %1").arg(materialParentSourceFileInfo.fileName()); } materialInfo += tr(""); - materialInfoWidget->setText(materialInfo); - - propertyGroupContainer->layout()->addWidget(materialInfoWidget); - AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer); + m_overviewText->setText(materialInfo); + m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); + m_overviewImage->setVisible(true); + m_updatePreview = true; } void MaterialPropertyInspector::AddUvNamesGroup() @@ -282,13 +283,8 @@ namespace AZ AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } - void MaterialPropertyInspector::Populate() + void MaterialPropertyInspector::AddPropertiesGroup() { - AddGroupsBegin(); - - AddDetailsGroup(); - AddUvNamesGroup(); - // Copy all of the properties from the material asset to the source data that will be exported for (const auto& groupDefinition : m_editData.m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder()) { @@ -327,10 +323,14 @@ namespace AZ [this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0); AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } + } + void MaterialPropertyInspector::Populate() + { + AddGroupsBegin(); + AddUvNamesGroup(); + AddPropertiesGroup(); AddGroupsEnd(); - - LoadOverridesFromEntity(); } void MaterialPropertyInspector::LoadOverridesFromEntity() @@ -375,6 +375,7 @@ namespace AZ m_dirtyPropertyFlags.set(); RunEditorMaterialFunctors(); RebuildAll(); + UpdateHeading(); } void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges) @@ -398,6 +399,8 @@ namespace AZ MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited); m_internalEditNotification = false; } + + m_updatePreview = true; } void MaterialPropertyInspector::RunEditorMaterialFunctors() @@ -607,7 +610,8 @@ namespace AZ MaterialComponentRequestBus::Event( m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId, MaterialPropertyOverrideMap()); - QueueUpdateUI(); + m_updateUI = true; + m_updatePreview = true; }); action->setEnabled(IsLoaded()); @@ -702,10 +706,7 @@ namespace AZ void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId) { - if (m_entityId == entityId) - { - QueueUpdateUI(); - } + m_updateUI |= (m_entityId == entityId); } void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId) @@ -719,25 +720,39 @@ namespace AZ void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) { AZ_UNUSED(name); - if (m_entityId == entityId) - { - QueueUpdateUI(); - } + m_updateUI |= (m_entityId == entityId); } void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time) { AZ_UNUSED(time); AZ_UNUSED(deltaTime); - UpdateUI(); - AZ::TickBus::Handler::BusDisconnect(); + if (m_updateUI) + { + m_updateUI = false; + UpdateUI(); + } + + if (m_updatePreview) + { + m_updatePreview = false; + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_materialAssignmentId); + } } void MaterialPropertyInspector::OnMaterialsEdited() { - if (!m_internalEditNotification) + m_updateUI |= !m_internalEditNotification; + m_updatePreview = true; + } + + void MaterialPropertyInspector::OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) + { + if (m_overviewImage && m_entityId == entityId && m_materialAssignmentId == materialAssignmentId) { - QueueUpdateUI(); + m_overviewImage->setPixmap(pixmap); } } @@ -761,14 +776,6 @@ namespace AZ LoadMaterial(m_entityId, m_materialAssignmentId); } } - - void MaterialPropertyInspector::QueueUpdateUI() - { - if (!AZ::TickBus::Handler::BusIsConnected()) - { - AZ::TickBus::Handler::BusConnect(); - } - } } // namespace EditorMaterialComponentInspector } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h index 048c1e19cb..6199fba179 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h @@ -9,6 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include #include #include @@ -39,6 +40,7 @@ namespace AZ , public AZ::EntitySystemBus::Handler , public AZ::TickBus::Handler , public MaterialComponentNotificationBus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler { Q_OBJECT public: @@ -89,11 +91,19 @@ namespace AZ //! MaterialComponentNotificationBus::Handler overrides... void OnMaterialsEdited() override; + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, + const AZ::Render::MaterialAssignmentId& materialAssignmentId, + const QPixmap& pixmap) override; + void UpdateUI(); - void QueueUpdateUI(); - void AddDetailsGroup(); + void CreateHeading(); + void UpdateHeading(); + void AddUvNamesGroup(); + void AddPropertiesGroup(); void LoadOverridesFromEntity(); void SaveOverridesToEntity(bool commitChanges); @@ -115,7 +125,10 @@ namespace AZ AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {}; AZStd::unordered_map m_groups = {}; bool m_internalEditNotification = {}; - QLabel* m_messageLabel = {}; + bool m_updateUI = {}; + bool m_updatePreview = {}; + QLabel* m_overviewText = {}; + QLabel* m_overviewImage = {}; }; } // namespace EditorMaterialComponentInspector } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index f5d38f48c4..21d045a072 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -315,6 +315,9 @@ namespace AZ AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast( &AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId); + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id); + MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited); AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index 9efa8eb333..e18cc0b907 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -6,7 +6,10 @@ * */ +#include #include +#include +#include #include #include #include @@ -19,6 +22,7 @@ #include #include #include +#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class @@ -28,6 +32,8 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") #include #include #include +#include +#include #include AZ_POP_DISABLE_WARNING @@ -86,17 +92,20 @@ namespace AZ AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); - - m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); } void EditorMaterialSystemComponent::Deactivate() { + AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + m_previewRenderer.reset(); m_materialBrowserInteractions.reset(); if (m_openMaterialEditorAction) @@ -143,6 +152,47 @@ namespace AZ } } + void EditorMaterialSystemComponent::RenderMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) + { + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + + if (m_previewRenderer) + { + AZ::Data::AssetId materialAssetId = {}; + MaterialComponentRequestBus::EventResult( + materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, materialAssignmentId); + if (!materialAssetId.IsValid()) + { + MaterialComponentRequestBus::EventResult( + materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, materialAssignmentId); + } + + AZ::Render::MaterialPropertyOverrideMap propertyOverrides; + AZ::Render::MaterialComponentRequestBus::EventResult( + propertyOverrides, entityId, &AZ::Render::MaterialComponentRequestBus::Events::GetPropertyOverrides, + materialAssignmentId); + + m_previewRenderer->AddCaptureRequest( + { 128, + AZStd::make_shared( + m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), + AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId, + AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides), + []() + { + // failed + }, + [entityId, materialAssignmentId](const QPixmap& pixmap) + { + AZ::Render::EditorMaterialSystemComponentNotificationBus::Broadcast( + &AZ::Render::EditorMaterialSystemComponentNotificationBus::Events::OnRenderMaterialPreviewComplete, entityId, + materialAssignmentId, pixmap); + } }); + } + } + void EditorMaterialSystemComponent::OnPopulateToolMenuItems() { if (!m_openMaterialEditorAction) @@ -185,6 +235,21 @@ namespace AZ "Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions); } + void EditorMaterialSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) + { + AZ::TickBus::QueueFunction([this](){ + m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "EditorMaterialSystemComponent Preview Scene", "EditorMaterialSystemComponent Preview Pipeline")); + }); + } + + void EditorMaterialSystemComponent::OnApplicationAboutToStop() + { + m_previewRenderer.reset(); + m_materialBrowserInteractions.reset(); + } + AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails( const char* fullSourceFileName) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h index 60e489f55e..f2ccbdc435 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h @@ -7,13 +7,14 @@ */ #pragma once +#include +#include +#include #include +#include #include #include #include - -#include - #include namespace AZ @@ -21,12 +22,14 @@ namespace AZ namespace Render { //! System component that manages launching and maintaining connections with the material editor. - class EditorMaterialSystemComponent + class EditorMaterialSystemComponent final : public AZ::Component - , private EditorMaterialSystemComponentRequestBus::Handler - , private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler - , private AzToolsFramework::EditorMenuNotificationBus::Handler - , private AzToolsFramework::EditorEvents::Bus::Handler + , public EditorMaterialSystemComponentRequestBus::Handler + , public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler + , public AzToolsFramework::EditorMenuNotificationBus::Handler + , public AzToolsFramework::EditorEvents::Bus::Handler + , public AzFramework::AssetCatalogEventBus::Handler + , public AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}"); @@ -47,6 +50,8 @@ namespace AZ //! EditorMaterialSystemComponentRequestBus::Handler overrides... void OpenMaterialEditor(const AZStd::string& sourcePath) override; void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; + void RenderMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; //! AssetBrowserInteractionNotificationBus::Handler overrides... AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override; @@ -58,9 +63,16 @@ namespace AZ // AztoolsFramework::EditorEvents::Bus::Handler overrides... void NotifyRegisterViews() override; - QAction* m_openMaterialEditorAction = nullptr; + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + + // AzFramework::ApplicationLifecycleEvents overrides... + void OnApplicationAboutToStop() override; + + QAction* m_openMaterialEditorAction = nullptr; AZStd::unique_ptr m_materialBrowserInteractions; + AZStd::unique_ptr m_previewRenderer; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp index 6890fabb01..966877317c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp @@ -35,10 +35,12 @@ namespace AZ AZ::Uuid entityContextId, const Data::AssetId& modelAssetId, const Data::AssetId& materialAssetId, - const Data::AssetId& lightingPresetAssetId) + const Data::AssetId& lightingPresetAssetId, + const Render::MaterialPropertyOverrideMap& materialPropertyOverrides) : m_scene(scene) , m_view(view) , m_entityContextId(entityContextId) + , m_materialPropertyOverrides(materialPropertyOverrides) { // Create preview model AzFramework::EntityContextRequestBus::EventResult( @@ -49,13 +51,9 @@ namespace AZ m_modelEntity->Init(); m_modelEntity->Activate(); - m_defaultModelAsset.Create(DefaultModelAssetId, true); - m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); - m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); - - m_modelAsset.Create(modelAssetId.IsValid() ? modelAssetId : DefaultModelAssetId, false); - m_materialAsset.Create(materialAssetId.IsValid() ? materialAssetId : DefaultMaterialAssetId, false); - m_lightingPresetAsset.Create(lightingPresetAssetId.IsValid() ? lightingPresetAssetId : DefaultLightingPresetAssetId, false); + m_modelAsset.Create(modelAssetId); + m_materialAsset.Create(materialAssetId); + m_lightingPresetAsset.Create(lightingPresetAssetId); } CommonPreviewContent::~CommonPreviewContent() @@ -113,35 +111,44 @@ namespace AZ m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); Render::MaterialComponentRequestBus::Event( - m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, m_materialAsset.GetId()); + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetMaterialOverride, + Render::DefaultMaterialAssignmentId, m_materialAsset.GetId()); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetPropertyOverrides, + Render::DefaultMaterialAssignmentId, m_materialPropertyOverrides); } void CommonPreviewContent::UpdateLighting() { - auto preset = m_lightingPresetAsset->GetDataAs(); - if (preset) + if (m_lightingPresetAsset.IsReady()) { - auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); - auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); - auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); - auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); - auto directionalLightFeatureProcessor = m_scene->GetFeatureProcessor(); - auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); - skyboxFeatureProcessor->Enable(true); - skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); - - Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = FieldOfView; - cameraConfig.m_nearClipDistance = NearDist; - cameraConfig.m_farClipDistance = FarDist; - cameraConfig.m_frustumWidth = 100.0f; - cameraConfig.m_frustumHeight = 100.0f; - - AZStd::vector lightHandles; - - preset->ApplyLightingPreset( - iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, - cameraConfig, lightHandles); + auto preset = m_lightingPresetAsset->GetDataAs(); + if (preset) + { + auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); + auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); + auto directionalLightFeatureProcessor = + m_scene->GetFeatureProcessor(); + auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + skyboxFeatureProcessor->Enable(true); + skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); + + Camera::Configuration cameraConfig; + cameraConfig.m_fovRadians = FieldOfView; + cameraConfig.m_nearClipDistance = NearDist; + cameraConfig.m_farClipDistance = FarDist; + cameraConfig.m_frustumWidth = 100.0f; + cameraConfig.m_frustumHeight = 100.0f; + + AZStd::vector lightHandles; + + preset->ApplyLightingPreset( + iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, + cameraConfig, lightHandles); + } } } @@ -157,8 +164,8 @@ namespace AZ const auto distance = radius + NearDist; const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); - const auto cameraPosition = center - cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); - const auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); + const auto cameraPosition = center + cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); + const auto cameraTransform = Transform::CreateLookAt(cameraPosition, center); m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); } } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h index 482dde2986..a6bb2f6c4e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h @@ -8,8 +8,8 @@ #pragma once +#include #include -#include #include #include #include @@ -31,7 +31,8 @@ namespace AZ AZ::Uuid entityContextId, const Data::AssetId& modelAssetId, const Data::AssetId& materialAssetId, - const Data::AssetId& lightingPresetAssetId); + const Data::AssetId& lightingPresetAssetId, + const Render::MaterialPropertyOverrideMap& materialPropertyOverrides); ~CommonPreviewContent() override; @@ -57,22 +58,10 @@ namespace AZ AZ::Uuid m_entityContextId; Entity* m_modelEntity = nullptr; - static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); - Data::Asset m_defaultLightingPresetAsset; - Data::Asset m_lightingPresetAsset; - - //! Model asset about to be rendered - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); - Data::Asset m_defaultModelAsset; Data::Asset m_modelAsset; - - //! Material asset about to be rendered - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - const Data::AssetId DefaultMaterialAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultMaterialPath); - Data::Asset m_defaultMaterialAsset; Data::Asset m_materialAsset; + Data::Asset m_lightingPresetAsset; + Render::MaterialPropertyOverrideMap m_materialPropertyOverrides; }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp index e9eba7a08d..f29762b563 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp @@ -20,6 +20,13 @@ namespace AZ { CommonThumbnailRenderer::CommonThumbnailRenderer() { + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "CommonThumbnailRenderer Preview Scene", "CommonThumbnailRenderer Preview Pipeline")); + + m_defaultModelAsset.Create(DefaultModelAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + // CommonThumbnailRenderer supports both models and materials AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); @@ -35,26 +42,24 @@ namespace AZ void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) { - m_previewRenderer.AddCaptureRequest( + m_previewRenderer->AddCaptureRequest( { thumbnailSize, AZStd::make_shared( - m_previewRenderer.GetScene(), - m_previewRenderer.GetView(), - m_previewRenderer.GetEntityContextId(), - GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type()), - GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type()), - GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type())), - [thumbnailKey]() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - }, - [thumbnailKey](const QImage& image) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, - QPixmap::fromImage(image)); - } }); + m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), + GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId), + GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId), + GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId), + Render::MaterialPropertyOverrideMap()), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QPixmap& pixmap) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap); + } }); } bool CommonThumbnailRenderer::Installed() const diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h index 0497521d44..a57c3dae8e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h @@ -8,6 +8,10 @@ #pragma once +#include +#include +#include +#include #include #include #include @@ -39,7 +43,19 @@ namespace AZ //! SystemTickBus::Handler interface overrides... void OnSystemTick() override; - AtomToolsFramework::PreviewRenderer m_previewRenderer; + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + + static constexpr const char* DefaultMaterialPath = ""; + const Data::AssetId DefaultMaterialAssetId; + Data::Asset m_defaultMaterialAsset; + + AZStd::unique_ptr m_previewRenderer; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp index 566a8d7b58..6a9c2ca2ca 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp @@ -53,7 +53,7 @@ namespace AZ AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } - void LightingPresetThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void LightingPresetThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h index efbfe5b7d5..437a372c3c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h @@ -33,7 +33,7 @@ namespace AZ ~LightingPresetThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailRendered(const QPixmap& thumbnailImage) override; void ThumbnailFailedToRender() override; protected: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp index b6a93aa59c..b9a3412d0e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp @@ -53,7 +53,7 @@ namespace AZ AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } - void MaterialThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void MaterialThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h index 9a580d07ce..1349336245 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h @@ -33,7 +33,7 @@ namespace AZ ~MaterialThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailRendered(const QPixmap& thumbnailImage) override; void ThumbnailFailedToRender() override; protected: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp index 6fe490e9dc..e3eb7a3af6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp @@ -53,7 +53,7 @@ namespace AZ AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } - void ModelThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void ModelThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h index 2925abe36e..5d9449e988 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h @@ -33,7 +33,7 @@ namespace AZ ~ModelThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailRendered(const QPixmap& thumbnailImage) override; void ThumbnailFailedToRender() override; protected: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp index 8293b33763..6d3d07faef 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp @@ -19,10 +19,11 @@ namespace AZ { namespace Thumbnails { - Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType) + Data::AssetId GetAssetId( + AzToolsFramework::Thumbnailer::SharedThumbnailKey key, + const Data::AssetType& assetType, + const Data::AssetId& defaultAssetId) { - static const Data::AssetId invalidAssetId; - // if it's a source thumbnail key, find first product with a matching asset type auto sourceKey = azrtti_cast(key.data()); if (sourceKey) @@ -32,7 +33,7 @@ namespace AZ AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, sourceKey->GetSourceUuid(), productsAssetInfo); if (!foundIt) { - return invalidAssetId; + return defaultAssetId; } auto assetInfoIt = AZStd::find_if(productsAssetInfo.begin(), productsAssetInfo.end(), [&assetType](const Data::AssetInfo& assetInfo) @@ -41,7 +42,7 @@ namespace AZ }); if (assetInfoIt == productsAssetInfo.end()) { - return invalidAssetId; + return defaultAssetId; } return assetInfoIt->m_assetId; @@ -53,7 +54,7 @@ namespace AZ { return productKey->GetAssetId(); } - return invalidAssetId; + return defaultAssetId; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h index e4efcd6b49..a88a25c2b7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h @@ -21,7 +21,10 @@ namespace AZ namespace Thumbnails { //! Get assetId by assetType that belongs to either source or product thumbnail key - Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType); + Data::AssetId GetAssetId( + AzToolsFramework::Thumbnailer::SharedThumbnailKey key, + const Data::AssetType& assetType, + const Data::AssetId& defaultAssetId = {}); //! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word wrap needed QString WordWrap(const QString& string, int maxLength); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 32f1bd882e..7c7765d3af 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -7,6 +7,7 @@ # set(FILES + Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h Source/Module.cpp From afa8bb92264c2928ea40420267714c83c3d3b723 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 9 Oct 2021 21:10:08 -0700 Subject: [PATCH 158/293] chore: update intersect and improve documentation Signed-off-by: Michael Pollind --- .../AzCore/AzCore/Math/IntersectSegment.cpp | 33 +- .../AzCore/AzCore/Math/IntersectSegment.h | 672 ++++++++++-------- .../AzCore/AzCore/Math/IntersectSegment.inl | 102 +++ .../AzCore/AzCore/azcore_files.cmake | 1 + 4 files changed, 497 insertions(+), 311 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp index a7a0d5197e..2a00412689 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp @@ -157,7 +157,7 @@ Intersect::IntersectSegmentTriangle( // TestSegmentAABBOrigin // [10/21/2009] //========================================================================= -int +bool AZ::Intersect::TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends) { const Vector3 EPSILON(0.001f); // \todo this is slow load move to a const @@ -168,7 +168,7 @@ AZ::Intersect::TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& hal // Try world coordinate axes as separating axes if (!absMidpoint.IsLessEqualThan(absHalfMidpoint)) { - return 0; + return false; } // Add in an epsilon term to counteract arithmetic errors when segment is @@ -188,11 +188,11 @@ AZ::Intersect::TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& hal Vector3 ead(ey * adz + ez * ady, ex * adz + ez * adx, ex * ady + ey * adx); if (!absMDCross.IsLessEqualThan(ead)) { - return 0; + return false; } // No separating axis found; segment must be overlapping AABB - return 1; + return true; } @@ -200,7 +200,7 @@ AZ::Intersect::TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& hal // IntersectRayAABB // [10/21/2009] //========================================================================= -int +RayAABBIsectTypes AZ::Intersect::IntersectRayAABB( const Vector3& rayStart, const Vector3& dir, const Vector3& dirRCP, const Aabb& aabb, float& tStart, float& tEnd, Vector3& startNormal /*, Vector3& inter*/) @@ -352,11 +352,14 @@ AZ::Intersect::IntersectRayAABB( return ISECT_RAY_AABB_ISECT; } + + + //========================================================================= // IntersectRayAABB2 // [2/18/2011] //========================================================================= -int +RayAABBIsectTypes AZ::Intersect::IntersectRayAABB2(const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, float& start, float& end) { float tmin, tmax, tymin, tymax, tzmin, tzmax; @@ -1166,7 +1169,7 @@ int AZ::Intersect::IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayD // IntersectSegmentCylinder // [10/21/2009] //========================================================================= -int +CylinderIsectTypes AZ::Intersect::IntersectSegmentCylinder( const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t) { @@ -1225,7 +1228,7 @@ AZ::Intersect::IntersectSegmentCylinder( return RR_ISECT_RAY_CYL_NONE; // No real roots; no intersection } t = (-b - Sqrt(discr)) / a; - int result = RR_ISECT_RAY_CYL_PQ; // default along the PQ segment + CylinderIsectTypes result = RR_ISECT_RAY_CYL_PQ; // default along the PQ segment if (md + t * nd < 0.0f) { @@ -1294,7 +1297,7 @@ AZ::Intersect::IntersectSegmentCylinder( // IntersectSegmentCapsule // [10/21/2009] //========================================================================= -int +CapsuleIsectTypes AZ::Intersect::IntersectSegmentCapsule(const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t) { int result = IntersectSegmentCylinder(sa, dir, p, q, r, t); @@ -1361,7 +1364,7 @@ AZ::Intersect::IntersectSegmentCapsule(const Vector3& sa, const Vector3& dir, co // IntersectSegmentPolyhedron // [10/21/2009] //========================================================================= -int +bool AZ::Intersect::IntersectSegmentPolyhedron( const Vector3& sa, const Vector3& sBA, const Plane p[], int numPlanes, float& tfirst, float& tlast, int& iFirstPlane, int& iLastPlane) @@ -1388,7 +1391,7 @@ AZ::Intersect::IntersectSegmentPolyhedron( // If so, return "no intersection" if segment lies outside plane if (dist < 0.0f) { - return 0; + return false; } } else @@ -1417,7 +1420,7 @@ AZ::Intersect::IntersectSegmentPolyhedron( // Exit with "no intersection" if intersection becomes empty if (tfirst > tlast) { - return 0; + return false; } } } @@ -1425,11 +1428,11 @@ AZ::Intersect::IntersectSegmentPolyhedron( //DBG_Assert(iFirstPlane!=-1&&iLastPlane!=-1,("We have some bad border case to have only one plane, fix this function!")); if (iFirstPlane == -1 && iLastPlane == -1) { - return 0; + return false; } // A nonzero logical intersection, so the segment intersects the polyhedron - return 1; + return true; } //========================================================================= @@ -1442,7 +1445,7 @@ AZ::Intersect::ClosestSegmentSegment( const Vector3& segment2Start, const Vector3& segment2End, float& segment1Proportion, float& segment2Proportion, Vector3& closestPointSegment1, Vector3& closestPointSegment2, - float epsilon /*= 1e-4f*/ ) + float epsilon) { const Vector3 segment1 = segment1End - segment1Start; const Vector3 segment2 = segment2End - segment2Start; diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h index df3d5e10fb..7be35c5ae6 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h @@ -5,257 +5,262 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#ifndef AZCORE_MATH_SEGMENT_INTERSECTION_H -#define AZCORE_MATH_SEGMENT_INTERSECTION_H +#pragma once -#include #include #include #include - -/// \file isect_segment.h +#include namespace AZ { namespace Intersect { - //! LineToPointDistanceTime computes the time of the shortest distance from point 'p' to segment (s1,s2). - //! To calculate the point of intersection: - //! P = s1 + u (s2 - s1) - //! @param s1 segment start point - //! @param s2 segment end point - //! @param p point to find the closest time to. - //! @return time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] - inline float LineToPointDistanceTime(const Vector3& s1, const Vector3& s21, const Vector3& p) - { - // so u = (p.x - s1.x)*(s2.x - s1.x) + (p.y - s1.y)*(s2.y - s1.y) + (p.z-s1.z)*(s2.z-s1.z) / |s2-s1|^2 - return s21.Dot(p - s1) / s21.Dot(s21); - } - - //! LineToPointDistance computes the closest point to 'p' from a segment (s1,s2). - //! @param s1 segment start point - //! @param s2 segment end point - //! @param p point to find the closest time to. - //! @param u time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] - //! @return the closest point - inline Vector3 LineToPointDistance(const Vector3& s1, const Vector3& s2, const Vector3& p, float& u) - { - const Vector3 s21 = s2 - s1; - // we assume seg1 and seg2 are NOT coincident - AZ_MATH_ASSERT(!s21.IsClose(Vector3(0.0f), 1e-4f), "OK we agreed that we will pass valid segments! (s1 != s2)"); - - u = LineToPointDistanceTime(s1, s21, p); - - return s1 + u * s21; - } - - //! Given segment pq and triangle abc (CCW), returns whether segment intersects - //! triangle and if so, also returns the barycentric coordinates (u,v,w) - //! of the intersection point. - //! @param p segment start point - //! @param q segment end point - //! @param a triangle point 1 - //! @param b triangle point 2 - //! @param c triangle point 3 - //! @param normal at the intersection point. - //! @param t time of intersection along the segment [0.0 (p), 1.0 (q)] - //! @return 1 if the segment intersects the triangle otherwise 0 + /** + * LineToPointDistanceTime computes the time of the shortest distance from point 'p' to segment (s1,s2). + * To calculate the point of intersection: + * P = s1 + u (s2 - s1) + * @param s1 segment start point + * @param s2 segment end point + * @param p point to find the closest time to. + * @return time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] + */ + float LineToPointDistanceTime(const Vector3& s1, const Vector3& s21, const Vector3& p); + + /** + * LineToPointDistance computes the closest point to 'p' from a segment (s1,s2). + * @param s1 segment start point + * @param s2 segment end point + * @param p point to find the closest time to. + * @param u time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] + * @return the closest point + */ + Vector3 LineToPointDistance(const Vector3& s1, const Vector3& s2, const Vector3& p, float& u); + + /** + * Given segment pq and triangle abc (CCW), returns whether segment intersects + * triangle and if so, also returns the barycentric coordinates (u,v,w) + * of the intersection point. + * + * @param p segment start point + * @param q segment end point + * @param a triangle point 1 + * @param b triangle point 2 + * @param c triangle point 3 + * @param normal at the intersection point. + * @param t time of intersection along the segment [0.0 (p), 1.0 (q)] + * @return true if the segments intersects the triangle otherwise false + */ int IntersectSegmentTriangleCCW( - const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, - /*float &u, float &v, float &w,*/ Vector3& normal, float& t); - - //! Same as \ref IntersectSegmentTriangleCCW without respecting the triangle (a,b,c) vertex order (double sided). + const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, Vector3& normal, float& t); + + /** + * Same as \ref IntersectSegmentTriangleCCW without respecting the triangle (a,b,c) vertex order (double sided). + * + * @param p segment start point + * @param q segment end point + * @param a triangle point 1 + * @param b triangle point 2 + * @param c triangle point 3 + * @param normal at the intersection point; + * @param t time of intersection along the segment [0.0 (p), 1.0 (q)] + * @return true if the segments intersects the triangle otherwise false + */ int IntersectSegmentTriangle( - const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, - /*float &u, float &v, float &w,*/ Vector3& normal, float& t); + const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, Vector3& normal, float& t); //! Ray aabb intersection result types. - enum RayAABBIsectTypes + enum RayAABBIsectTypes : AZ::s32 { - ISECT_RAY_AABB_NONE = 0, ///< no intersection - ISECT_RAY_AABB_SA_INSIDE, ///< the ray starts inside the aabb - ISECT_RAY_AABB_ISECT, ///< intersects along the PQ segment + ISECT_RAY_AABB_NONE = 0, ///< no intersection + ISECT_RAY_AABB_SA_INSIDE, ///< the ray starts inside the aabb + ISECT_RAY_AABB_ISECT, ///< intersects along the PQ segment }; - //! Intersect ray R(t) = rayStart + t*d against AABB a. When intersecting, - //! return intersection distance tmin and point q of intersection. - //! @param rayStart ray starting point - //! @param dir ray direction and length (dir = rayEnd - rayStart) - //! @param dirRCP 1/dir (reciprocal direction - we cache this result very often so we don't need to compute it multiple times, otherwise just use dir.GetReciprocal()) - //! @param aabb Axis aligned bounding box to intersect against - //! @param tStart time on ray of the first intersection [0,1] or 0 if the ray starts inside the aabb - check the return value - //! @param tEnd time of the of the second intersection [0,1] (it can be > 1 if intersects after the rayEnd) - //! @param startNormal normal at the start point. - //! @return \ref RayAABBIsectTypes - int IntersectRayAABB( - const Vector3& rayStart, const Vector3& dir, const Vector3& dirRCP, const Aabb& aabb, - float& tStart, float& tEnd, Vector3& startNormal /*, Vector3& inter*/); - - //! Intersect ray against AABB. - //! @param rayStart ray starting point. - //! @param dir ray reciprocal direction. - //! @param aabb Axis aligned bounding box to intersect against. - //! @param start length on ray of the first intersection. - //! @param end length of the of the second intersection. - //! @return \ref RayAABBIsectTypes In this faster version than IntersectRayAABB we return only ISECT_RAY_AABB_NONE and ISECT_RAY_AABB_ISECT. - //! You can check yourself for that case. - int IntersectRayAABB2( - const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, - float& start, float& end); - - //! Clip a ray to an aabb. return true if ray was clipped. The ray - //! can be inside so don't use the result if the ray intersect the box. - inline int ClipRayWithAabb( - const Aabb& aabb, Vector3& rayStart, Vector3& rayEnd, float& tClipStart, float& tClipEnd) - { - Vector3 startNormal; - float tStart, tEnd; - Vector3 dirLen = rayEnd - rayStart; - if (IntersectRayAABB(rayStart, dirLen, dirLen.GetReciprocal(), aabb, tStart, tEnd, startNormal) != ISECT_RAY_AABB_NONE) - { - // clip the ray with the box - if (tStart > 0.0f) - { - rayStart = rayStart + tStart * dirLen; - tClipStart = tStart; - } - if (tEnd < 1.0f) - { - rayEnd = rayStart + tEnd * dirLen; - tClipEnd = tEnd; - } - - return 1; - } - - return 0; - } - - //! Test segment and aabb where the segment is defined by midpoint - //! midPoint = (p1-p0) * 0.5f and half vector halfVector = p1 - midPoint. - //! the aabb is at the origin and defined by half extents only. - //! @return 1 if the intersect, otherwise 0. - int TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends); - - //! Test if segment specified by points p0 and p1 intersects AABB. \ref TestSegmentAABBOrigin - //! @return 1 if the segment and AABB intersect, otherwise 0. - inline int TestSegmentAABB(const Vector3& p0, const Vector3& p1, const Aabb& aabb) - { - Vector3 e = aabb.GetExtents(); - Vector3 d = p1 - p0; - Vector3 m = p0 + p1 - aabb.GetMin() - aabb.GetMax(); - - return TestSegmentAABBOrigin(m, d, e); - } + /** + * Intersect ray R(t) = rayStart + t*d against AABB a. When intersecting, + * return intersection distance tmin and point q of intersection. + * @param rayStart ray starting point + * @param dir ray direction and length (dir = rayEnd - rayStart) + * @param dirRCP 1/dir (reciprocal direction - we cache this result very often so we don't need to compute it multiple times, + * otherwise just use dir.GetReciprocal()) + * @param aabb Axis aligned bounding box to intersect against + * @param tStart time on ray of the first intersection [0,1] or 0 if the ray starts inside the aabb - check the return value + * @param tEnd time of the of the second intersection [0,1] (it can be > 1 if intersects after the rayEnd) + * @param startNormal normal at the start point. + * @return \ref RayAABBIsectTypes + */ + RayAABBIsectTypes IntersectRayAABB( + const Vector3& rayStart, + const Vector3& dir, + const Vector3& dirRCP, + const Aabb& aabb, + float& tStart, + float& tEnd, + Vector3& startNormal /*, Vector3& inter*/); + + /** + * Intersect ray against AABB. + * + * @param rayStart ray starting point. + * @param dir ray reciprocal direction. + * @param aabb Axis aligned bounding box to intersect against. + * @param start length on ray of the first intersection. + * @param end length of the of the second intersection. + * @return \ref RayAABBIsectTypes In this faster version than IntersectRayAABB we return only ISECT_RAY_AABB_NONE and ISECT_RAY_AABB_ISECT. You can check yourself for that case. + */ + RayAABBIsectTypes IntersectRayAABB2(const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, float& start, float& end); + + /** + * Clip a ray to an aabb. return true if ray was clipped. The ray + * can be inside so don't use the result if the ray intersect the box. + * + * @param aabb bounds + * @param rayStart the start of the ray + * @param rayEnd the end of the ray + * @param tClipStart[out] The proportion where the ray enterts the aabb + * @param tClipEnd[out] The proportion where the ray exits the aabb + * @return true ray was clipped else false + */ + bool ClipRayWithAabb(const Aabb& aabb, Vector3& rayStart, Vector3& rayEnd, float& tClipStart, float& tClipEnd); + + /** + * Test segment and aabb where the segment is defined by midpoint + * midPoint = (p1-p0) * 0.5f and half vector halfVector = p1 - midPoint. + * the aabb is at the origin and defined by half extents only. + * + * @param midPoint midpoint of a line segment + * @param halfVector half vector of an aabb + * @param aabbExtends the extends of a bounded box + * @return 1 if the intersect, otherwise 0. + */ + bool TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends); + + /** + * Test if segment specified by points p0 and p1 intersects AABB. \ref TestSegmentAABBOrigin + * + * @param p0 point 1 + * @param p1 point 2 + * @param aabb bounded box + * @return true if the segment and AABB intersect, otherwise false. + */ + bool TestSegmentAABB(const Vector3& p0, const Vector3& p1, const Aabb& aabb); //! Ray sphere intersection result types. - enum SphereIsectTypes + enum SphereIsectTypes : AZ::s32 { ISECT_RAY_SPHERE_SA_INSIDE = -1, // the ray starts inside the cylinder - ISECT_RAY_SPHERE_NONE, // no intersection - ISECT_RAY_SPHERE_ISECT, // along the PQ segment + ISECT_RAY_SPHERE_NONE, // no intersection + ISECT_RAY_SPHERE_ISECT, // along the PQ segment }; - //! IntersectRaySphereOrigin - //! return time t>=0 but not limited, so if you check a segment make sure - //! t <= segmentLen - //! @param rayStart ray start point - //! @param rayDirNormalized ray direction normalized. - //! @param shereRadius sphere radius - //! @param time of closest intersection [0,+INF] in relation to the normalized direction. - //! @return \ref SphereIsectTypes - AZ_INLINE int IntersectRaySphereOrigin( - const Vector3& rayStart, const Vector3& rayDirNormalized, - const float sphereRadius, float& t) - { - Vector3 m = rayStart; - float b = m.Dot(rayDirNormalized); - float c = m.Dot(m) - sphereRadius * sphereRadius; - - // Exit if r's origin outside s (c > 0)and r pointing away from s (b > 0) - if (c > 0.0f && b > 0.0f) - { - return ISECT_RAY_SPHERE_NONE; - } - float discr = b * b - c; - // A negative discriminant corresponds to ray missing sphere - if (discr < 0.0f) - { - return ISECT_RAY_SPHERE_NONE; - } - - // Ray now found to intersect sphere, compute smallest t value of intersection - t = -b - Sqrt(discr); - - // If t is negative, ray started inside sphere so clamp t to zero - if (t < 0.0f) - { - // t = 0.0f; - return ISECT_RAY_SPHERE_SA_INSIDE; // no hit if inside - } - //q = p + t * d; - return ISECT_RAY_SPHERE_ISECT; - } - - //! Intersect ray (rayStart,rayDirNormalized) and sphere (sphereCenter,sphereRadius) \ref IntersectRaySphereOrigin - inline int IntersectRaySphere( - const Vector3& rayStart, const Vector3& rayDirNormalized, const Vector3& sphereCenter, const float sphereRadius, float& t) - { - return IntersectRaySphereOrigin(rayStart - sphereCenter, rayDirNormalized, sphereRadius, t); - } - - //! @param rayOrigin The origin of the ray to test. - //! @param rayDir The direction of the ray to test. It has to be unit length. - //! @param diskCenter Center point of the disk - //! @param diskRadius Radius of the disk - //! @param diskNormal A normal perpendicular to the disk - //! @param[out] t If returning 1 (indicating a hit), this contains distance from rayOrigin along the normalized rayDir that the hit occured at. - //! @return The number of intersecting points. + /** + * IntersectRaySphereOrigin + * return time t>=0 but not limited, so if you check a segment make sure + * t <= segmentLen + * @param rayStart ray start point + * @param rayDirNormalized ray direction normalized. + * @param shereRadius sphere radius + * @param time of closest intersection [0,+INF] in relation to the normalized direction. + * @return \ref SphereIsectTypes + **/ + SphereIsectTypes IntersectRaySphereOrigin( + const Vector3& rayStart, const Vector3& rayDirNormalized, const float sphereRadius, float& t); + + /** + * Intersect ray (rayStart,rayDirNormalized) and sphere (sphereCenter,sphereRadius) \ref IntersectRaySphereOrigin + * + * @param rayStart + * @param rayDirNormalized + * @param sphereCenter + * @param sphereRadius + * @param t + * @return int + */ + SphereIsectTypes IntersectRaySphere( + const Vector3& rayStart, const Vector3& rayDirNormalized, const Vector3& sphereCenter, const float sphereRadius, float& t); + + /** + * @param rayOrigin The origin of the ray to test. + * @param rayDir The direction of the ray to test. It has to be unit length. + * @param diskCenter Center point of the disk + * @param diskRadius Radius of the disk + * @param diskNormal A normal perpendicular to the disk + * @param[out] t If returning 1 (indicating a hit), this contains distance from rayOrigin along the normalized rayDir + * that the hit occured at. + * @return The number of intersecting points. + **/ int IntersectRayDisk( - const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& diskCenter, const float diskRadius, const AZ::Vector3& diskNormal, float& t); + const Vector3& rayOrigin, + const Vector3& rayDir, + const Vector3& diskCenter, + const float diskRadius, + const AZ::Vector3& diskNormal, + float& t); - //! If there is only one intersecting point, the coefficient is stored in \ref t1. - //! @param rayOrigin The origin of the ray to test. - //! @param rayDir The direction of the ray to test. It has to be unit length. - //! @param cylinderEnd1 The center of the circle on one end of the cylinder. - //! @param cylinderDir The direction pointing from \ref cylinderEnd1 to the other end of the cylinder. It has to be unit length. - //! @param cylinderHeight The distance between two centers of the circles on two ends of the cylinder respectively. - //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t1 * rayDir". - //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t2 * rayDir". - //! @return The number of intersecting points. + /** + * If there is only one intersecting point, the coefficient is stored in \ref t1. + * @param rayOrigin The origin of the ray to test. + * @param rayDir The direction of the ray to test. It has to be unit length. + * @param cylinderEnd1 The center of the circle on one end of the cylinder. + * @param cylinderDir The direction pointing from \ref cylinderEnd1 to the other end of the cylinder. It has to be unit + * length. + * @param cylinderHeight The distance between two centers of the circles on two ends of the cylinder respectively. + * @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + * as "rayOrigin + t1 * rayDir". + * @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + * as "rayOrigin + t2 * rayDir". + * @return The number of intersecting points. + **/ int IntersectRayCappedCylinder( - const Vector3& rayOrigin, const Vector3& rayDir, - const Vector3& cylinderEnd1, const Vector3& cylinderDir, float cylinderHeight, float cylinderRadius, - float& t1, float& t2); - - //! If there is only one intersecting point, the coefficient is stored in \ref t1. - //! @param rayOrigin The origin of the ray to test. - //! @param rayDir The direction of the ray to test. It has to be unit length. - //! @param coneApex The apex of the cone. - //! @param coneDir The unit-length direction from the apex to the base. - //! @param coneHeight The height of the cone, from the apex to the base. - //! @param coneBaseRadius The radius of the cone base circle. - //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t1 * rayDir". - //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t2 * rayDir". - //! @return The number of intersecting points. + const Vector3& rayOrigin, + const Vector3& rayDir, + const Vector3& cylinderEnd1, + const Vector3& cylinderDir, + float cylinderHeight, + float cylinderRadius, + float& t1, + float& t2); + + /** + * If there is only one intersecting point, the coefficient is stored in \ref t1. + * @param rayOrigin The origin of the ray to test. + * @param rayDir The direction of the ray to test. It has to be unit length. + * @param coneApex The apex of the cone. + * @param coneDir The unit-length direction from the apex to the base. + * @param coneHeight The height of the cone, from the apex to the base. + * @param coneBaseRadius The radius of the cone base circle. + * @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + * as "rayOrigin + t1 * rayDir". + * @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + * as "rayOrigin + t2 * rayDir". + * @return The number of intersecting points. + **/ int IntersectRayCone( - const Vector3& rayOrigin, const Vector3& rayDir, - const Vector3& coneApex, const Vector3& coneDir, float coneHeight, float coneBaseRadius, - float& t1, float& t2); - - //! Test intersection between a ray and a plane in 3D. - //! @param rayOrigin The origin of the ray to test intersection with. - //! @param rayDir The direction of the ray to test intersection with. - //! @param planePos A point on the plane to test intersection with. - //! @param planeNormal The normal of the plane to test intersection with. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". - //! @return The number of intersection point. + const Vector3& rayOrigin, + const Vector3& rayDir, + const Vector3& coneApex, + const Vector3& coneDir, + float coneHeight, + float coneBaseRadius, + float& t1, + float& t2); + + /** + * Test intersection between a ray and a plane in 3D. + * @param rayOrigin The origin of the ray to test intersection with. + * @param rayDir The direction of the ray to test intersection with. + * @param planePos A point on the plane to test intersection with. + * @param planeNormal The normal of the plane to test intersection with. + * @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + *+ t * rayDirection". + * @return The number of intersection point. + **/ int IntersectRayPlane( - const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& planePos, - const Vector3& planeNormal, float& t); + const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& planePos, const Vector3& planeNormal, float& t); //! Test intersection between a ray and a two-sided quadrilateral defined by four points in 3D. - //! The four points that define the quadrilateral could be passed in with either counter clock-wise + //! The four points that define the quadrilateral could be passed in with either counter clock-wise //! winding or clock-wise winding. //! @param rayOrigin The origin of the ray to test intersection with. //! @param rayDir The direction of the ray to test intersection with. @@ -263,105 +268,180 @@ namespace AZ //! @param vertexB One of the four points that define the quadrilateral. //! @param vertexC One of the four points that define the quadrilateral. //! @param vertexD One of the four points that define the quadrilateral. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". + //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + + //! t * rayDirection". //! @return The number of intersection point. int IntersectRayQuad( - const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& vertexA, - const Vector3& vertexB, const Vector3& vertexC, const Vector3& vertexD, float& t); + const Vector3& rayOrigin, + const Vector3& rayDir, + const Vector3& vertexA, + const Vector3& vertexB, + const Vector3& vertexC, + const Vector3& vertexD, + float& t); - //! Test intersection between a ray and an oriented box in 3D. - //! @param rayOrigin The origin of the ray to test intersection with. - //! @param rayDir The direction of the ray to test intersection with. - //! @param boxCenter The position of the center of the box. - //! @param boxAxis1 An axis along one dimension of the oriented box. - //! @param boxAxis2 An axis along one dimension of the oriented box. - //! @param boxAxis3 An axis along one dimension of the oriented box. - //! @param boxHalfExtent1 The half extent of the box on the dimension of \ref boxAxis1. - //! @param boxHalfExtent2 The half extent of the box on the dimension of \ref boxAxis2. - //! @param boxHalfExtent3 The half extent of the box on the dimension of \ref boxAxis3. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". - //! @return 1 if there is an intersection, 0 otherwise. + /** Test intersection between a ray and an oriented box in 3D. + * @param rayOrigin The origin of the ray to test intersection with. + * @param rayDir The direction of the ray to test intersection with. + * @param boxCenter The position of the center of the box. + * @param boxAxis1 An axis along one dimension of the oriented box. + * @param boxAxis2 An axis along one dimension of the oriented box. + * @param boxAxis3 An axis along one dimension of the oriented box. + * @param boxHalfExtent1 The half extent of the box on the dimension of \ref boxAxis1. + * @param boxHalfExtent2 The half extent of the box on the dimension of \ref boxAxis2. + * @param boxHalfExtent3 The half extent of the box on the dimension of \ref boxAxis3. + * @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + + * t * rayDirection". + * @return 1 if there is an intersection, 0 otherwise. + **/ int IntersectRayBox( - const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& boxCenter, const Vector3& boxAxis1, - const Vector3& boxAxis2, const Vector3& boxAxis3, float boxHalfExtent1, float boxHalfExtent2, float boxHalfExtent3, + const Vector3& rayOrigin, + const Vector3& rayDir, + const Vector3& boxCenter, + const Vector3& boxAxis1, + const Vector3& boxAxis2, + const Vector3& boxAxis3, + float boxHalfExtent1, + float boxHalfExtent2, + float boxHalfExtent3, float& t); - //! Test intersection between a ray and an OBB. - //! @param rayOrigin The origin of the ray to test intersection with. - //! @param rayDir The direction of the ray to test intersection with. - //! @param obb The OBB to test for intersection with the ray. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". - //! @return 1 if there is an intersection, 0 otherwise. + /** + * Test intersection between a ray and an OBB. + * @param rayOrigin The origin of the ray to test intersection with. + * @param rayDir The direction of the ray to test intersection with. + * @param obb The OBB to test for intersection with the ray. + * @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * + * rayDirection". + * @return 1 if there is an intersection, 0 otherwise. + */ int IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t); //! Ray cylinder intersection types. - enum CylinderIsectTypes + enum CylinderIsectTypes : AZ::s32 { RR_ISECT_RAY_CYL_SA_INSIDE = -1, // the ray starts inside the cylinder - RR_ISECT_RAY_CYL_NONE, // no intersection - RR_ISECT_RAY_CYL_PQ, // along the PQ segment - RR_ISECT_RAY_CYL_P_SIDE, // on the P side - RR_ISECT_RAY_CYL_Q_SIDE, // on the Q side + RR_ISECT_RAY_CYL_NONE, // no intersection + RR_ISECT_RAY_CYL_PQ, // along the PQ segment + RR_ISECT_RAY_CYL_P_SIDE, // on the P side + RR_ISECT_RAY_CYL_Q_SIDE, // on the Q side }; - //! Intersect segment S(t)=sa+t(dir), 0<=t<=1 against cylinder specified by p, q and r. - int IntersectSegmentCylinder( - const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, - const float r, float& t); + /** + * Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder + * Intersect segment S(t)=sa+t(dir), 0<=t<=1 against cylinder specified by p, q and r. + * + * @param sa point + * @param dir magnitude along sa + * @param p center point of side 1 cylinder + * @param q center point of side 2 cylinder + * @param r radius of cylinder + * @param t[out] proporition along line semgnet + * @return CylinderIsectTypes + */ + CylinderIsectTypes IntersectSegmentCylinder( + const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); //! Capsule ray intersect types. enum CapsuleIsectTypes { ISECT_RAY_CAPSULE_SA_INSIDE = -1, // the ray starts inside the cylinder ISECT_RAY_CAPSULE_NONE, // no intersection - ISECT_RAY_CAPSULE_PQ, // along the PQ segment - ISECT_RAY_CAPSULE_P_SIDE, // on the P side - ISECT_RAY_CAPSULE_Q_SIDE, // on the Q side + ISECT_RAY_CAPSULE_PQ, // along the PQ segment + ISECT_RAY_CAPSULE_P_SIDE, // on the P side + ISECT_RAY_CAPSULE_Q_SIDE, // on the Q side }; - //! This is a quick implementation of segment capsule based on segment cylinder \ref IntersectSegmentCylinder - //! segment sphere intersection. We can optimize it a lot once we fix the ray - //! cylinder intersection. - int IntersectSegmentCapsule( - const Vector3& sa, const Vector3& dir, const Vector3& p, - const Vector3& q, const float r, float& t); - - //! Intersect segment S(t)=A+t(B-A), 0<=t<=1 against convex polyhedron specified - //! by the n halfspaces defined by the planes p[]. On exit tfirst and tlast - //! define the intersection, if any. - int IntersectSegmentPolyhedron( - const Vector3& sa, const Vector3& sBA, const Plane p[], int numPlanes, - float& tfirst, float& tlast, int& iFirstPlane, int& iLastPlane); - - //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between - //! two segments segment1Start<->segment1End and segment2Start<->segment2End. Also calculate the values of segment1Proportion and segment2Proportion where - //! closestPointSegment1 = segment1Start + (segment1Proportion * (segment1End - segment1Start)) - //! closestPointSegment2 = segment2Start + (segment2Proportion * (segment2End - segment2Start)) - //! If segments are parallel returns a solution. + /** + * This is a quick implementation of segment capsule based on segment cylinder \ref IntersectSegmentCylinder + * segment sphere intersection. We can optimize it a lot once we fix the ray + * cylinder intersection. + */ + CapsuleIsectTypes IntersectSegmentCapsule( + const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); + + /** + * Intersect segment S(t)=A+t(B-A), 0<=t<=1 against convex polyhedron specified + * by the n halfspaces defined by the planes p[]. On exit tfirst and tlast + * define the intersection, if any. + */ + bool IntersectSegmentPolyhedron( + const Vector3& sa, + const Vector3& sBA, + const Plane p[], + int numPlanes, + float& tfirst, + float& tlast, + int& iFirstPlane, + int& iLastPlane); + + /** + * Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between + * two segments segment1Start<->segment1End and segment2Start<->segment2End. Also calculate the values of segment1Proportion and + * segment2Proportion where closestPointSegment1 = segment1Start + (segment1Proportion * (segment1End - segment1Start)) + * closestPointSegment2 = segment2Start + (segment2Proportion * (segment2End - segment2Start)) + * If segments are parallel returns a solution. + * @param segment1Start start of segment 1. + * @param segment1End end of segment 1. + * @param segment2Start start of segment 2. + * @param segment2End end of segment 2. + * @param segment1Proportion[out] the proporition along segment 1 [0..1] + * @param segment2Proportion[out] the proporition along segment 2 [0..1] + * @param closestPointSegment1[out] closest point on segment 1. + * @param closestPointSegment2[out] closest point on segment 2. + * @param epsilon the minimum square distance where a line segment can be treated as a single point. + */ void ClosestSegmentSegment( - const Vector3& segment1Start, const Vector3& segment1End, - const Vector3& segment2Start, const Vector3& segment2End, - float& segment1Proportion, float& segment2Proportion, - Vector3& closestPointSegment1, Vector3& closestPointSegment2, + const Vector3& segment1Start, + const Vector3& segment1End, + const Vector3& segment2Start, + const Vector3& segment2End, + float& segment1Proportion, + float& segment2Proportion, + Vector3& closestPointSegment1, + Vector3& closestPointSegment2, float epsilon = 1e-4f); - //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between - //! two segments segment1Start<->segment1End and segment2Start<->segment2End. - //! If segments are parallel returns a solution. + /** + * Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between + * two segments segment1Start<->segment1End and segment2Start<->segment2End. + * If segments are parallel returns a solution. + * + * @param segment1Start start of segment 1. + * @param segment1End end of segment 1. + * @param segment2Start start of segment 2. + * @param segment2End end of segment 2. + * @param closestPointSegment1[out] closest point on segment 1. + * @param closestPointSegment2[out] closest point on segment 2. + * @param epsilon the minimum square distance where a line segment can be treated as a single point. + */ void ClosestSegmentSegment( - const Vector3& segment1Start, const Vector3& segment1End, - const Vector3& segment2Start, const Vector3& segment2End, - Vector3& closestPointSegment1, Vector3& closestPointSegment2, + const Vector3& segment1Start, + const Vector3& segment1End, + const Vector3& segment2Start, + const Vector3& segment2End, + Vector3& closestPointSegment1, + Vector3& closestPointSegment2, float epsilon = 1e-4f); - //! Calculate the point (closestPointOnSegment) that is the closest point on - //! segment segmentStart/segmentEnd to point. Also calculate the value of proportion where - //! closestPointOnSegment = segmentStart + (proportion * (segmentEnd - segmentStart)) + /** + * Calculate the point (closestPointOnSegment) that is the closest point on + * segment segmentStart/segmentEnd to point. Also calculate the value of proportion where + * closestPointOnSegment = segmentStart + (proportion * (segmentEnd - segmentStart)) + * + * @param point the point to test + * @param segmentStart the start of the segment + * @param segmentEnd the end of the segment + * @param proportion[out] the proportion of the segment L(t) = (end - start) * t + * @param closestPointOnSegment[out] the point along the line segment + */ void ClosestPointSegment( - const Vector3& point, const Vector3& segmentStart, const Vector3& segmentEnd, - float& proportion, Vector3& closestPointOnSegment); - } -} - -#endif // AZCORE_MATH_SEGMENT_INTERSECTION_H -#pragma once + const Vector3& point, + const Vector3& segmentStart, + const Vector3& segmentEnd, + float& proportion, + Vector3& closestPointOnSegment); + } // namespace Intersect +} // namespace AZ + +#include diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl new file mode 100644 index 0000000000..b9f5139923 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl @@ -0,0 +1,102 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +namespace AZ +{ + namespace Intersect + { + AZ_MATH_INLINE bool ClipRayWithAabb(const Aabb& aabb, Vector3& rayStart, Vector3& rayEnd, float& tClipStart, float& tClipEnd) + { + Vector3 startNormal; + float tStart, tEnd; + Vector3 dirLen = rayEnd - rayStart; + if (IntersectRayAABB(rayStart, dirLen, dirLen.GetReciprocal(), aabb, tStart, tEnd, startNormal) != ISECT_RAY_AABB_NONE) + { + // clip the ray with the box + if (tStart > 0.0f) + { + rayStart = rayStart + tStart * dirLen; + tClipStart = tStart; + } + if (tEnd < 1.0f) + { + rayEnd = rayStart + tEnd * dirLen; + tClipEnd = tEnd; + } + + return true; + } + + return false; + } + + AZ_MATH_INLINE SphereIsectTypes + IntersectRaySphereOrigin(const Vector3& rayStart, const Vector3& rayDirNormalized, const float sphereRadius, float& t) + { + Vector3 m = rayStart; + float b = m.Dot(rayDirNormalized); + float c = m.Dot(m) - sphereRadius * sphereRadius; + + // Exit if r's origin outside s (c > 0)and r pointing away from s (b > 0) + if (c > 0.0f && b > 0.0f) + { + return ISECT_RAY_SPHERE_NONE; + } + float discr = b * b - c; + // A negative discriminant corresponds to ray missing sphere + if (discr < 0.0f) + { + return ISECT_RAY_SPHERE_NONE; + } + + // Ray now found to intersect sphere, compute smallest t value of intersection + t = -b - Sqrt(discr); + + // If t is negative, ray started inside sphere so clamp t to zero + if (t < 0.0f) + { + // t = 0.0f; + return ISECT_RAY_SPHERE_SA_INSIDE; // no hit if inside + } + // q = p + t * d; + return ISECT_RAY_SPHERE_ISECT; + } + + AZ_MATH_INLINE SphereIsectTypes IntersectRaySphere(const Vector3& rayStart, const Vector3& rayDirNormalized, const Vector3& sphereCenter, const float sphereRadius, float& t) + { + return IntersectRaySphereOrigin(rayStart - sphereCenter, rayDirNormalized, sphereRadius, t); + } + + AZ_MATH_INLINE Vector3 LineToPointDistance(const Vector3& s1, const Vector3& s2, const Vector3& p, float& u) + { + const Vector3 s21 = s2 - s1; + // we assume seg1 and seg2 are NOT coincident + AZ_MATH_ASSERT(!s21.IsClose(Vector3(0.0f), 1e-4f), "OK we agreed that we will pass valid segments! (s1 != s2)"); + + u = LineToPointDistanceTime(s1, s21, p); + + return s1 + u * s21; + } + + AZ_MATH_INLINE float LineToPointDistanceTime(const Vector3& s1, const Vector3& s21, const Vector3& p) + { + // so u = (p.x - s1.x)*(s2.x - s1.x) + (p.y - s1.y)*(s2.y - s1.y) + (p.z-s1.z)*(s2.z-s1.z) / |s2-s1|^2 + return s21.Dot(p - s1) / s21.Dot(s21); + } + + AZ_MATH_INLINE bool TestSegmentAABB(const Vector3& p0, const Vector3& p1, const Aabb& aabb) + { + Vector3 e = aabb.GetExtents(); + Vector3 d = p1 - p0; + Vector3 m = p0 + p1 - aabb.GetMin() - aabb.GetMax(); + + return TestSegmentAABBOrigin(m, d, e); + } + } // namespace Intersect +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 6675958247..4d95ddf098 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -282,6 +282,7 @@ set(FILES Math/Internal/VertexContainer.inl Math/InterpolationSample.h Math/IntersectPoint.h + Math/IntersectSegment.inl Math/IntersectSegment.cpp Math/IntersectSegment.h Math/MathIntrinsics.h From 78f4e0d0de41687ff05bb0db33715edf1b316523 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 9 Oct 2021 23:57:04 -0500 Subject: [PATCH 159/293] Combined common thumbnail classes Signed-off-by: Guthrie Adams --- .../EditorCommonFeaturesSystemComponent.cpp | 30 +---- .../Code/Source/Previewer/CommonPreviewer.cpp | 10 +- .../Code/Source/Previewer/CommonPreviewer.h | 14 +-- .../Previewer/CommonPreviewerFactory.cpp | 25 +--- .../Source/Previewer/CommonPreviewerFactory.h | 4 +- .../Code/Source/Previewer/CommonThumbnail.cpp | 113 +++++++++++++++++ .../{ModelThumbnail.h => CommonThumbnail.h} | 15 +-- .../Previewer/CommonThumbnailRenderer.cpp | 10 +- ...nailUtils.cpp => CommonThumbnailUtils.cpp} | 37 +++++- ...humbnailUtils.h => CommonThumbnailUtils.h} | 7 +- .../Previewer/LightingPresetThumbnail.cpp | 115 ------------------ .../Previewer/LightingPresetThumbnail.h | 67 ---------- .../Source/Previewer/MaterialThumbnail.cpp | 106 ---------------- .../Code/Source/Previewer/MaterialThumbnail.h | 67 ---------- .../Code/Source/Previewer/ModelThumbnail.cpp | 106 ---------------- ...egration_commonfeatures_editor_files.cmake | 12 +- 16 files changed, 192 insertions(+), 546 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.cpp rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/{ModelThumbnail.h => CommonThumbnail.h} (80%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/{ThumbnailUtils.cpp => CommonThumbnailUtils.cpp} (64%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/{ThumbnailUtils.h => CommonThumbnailUtils.h} (83%) delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h delete mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 34cd9f59d0..47dd5ce571 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -6,9 +6,6 @@ * */ -#include -#include - #include #include #include @@ -17,10 +14,9 @@ #include #include #include - -#include -#include -#include +#include +#include +#include #include @@ -220,15 +216,7 @@ namespace AZ using namespace LyIntegration; ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache), - ThumbnailContext::DefaultContext); - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::ModelThumbnailCache), - ThumbnailContext::DefaultContext); - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::LightingPresetThumbnailCache), + &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::CommonThumbnailCache), ThumbnailContext::DefaultContext); m_renderer = AZStd::make_unique(); @@ -241,15 +229,7 @@ namespace AZ using namespace LyIntegration; ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::ModelThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::LightingPresetThumbnailCache::ProviderName, + &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::CommonThumbnailCache::ProviderName, ThumbnailContext::DefaultContext); m_renderer.reset(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp index 2b5ea7843a..9ecc41e0f2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp @@ -13,15 +13,15 @@ #include #include #include -#include +#include // Disables warning messages triggered by the Qt library -// 4251: class needs to have dll-interface to be used by clients of class +// 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") #include -#include #include +#include AZ_POP_DISABLE_WARNING namespace AZ @@ -41,6 +41,10 @@ namespace AZ { } + void CommonPreviewer::Clear() const + { + } + void CommonPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) { using namespace AzToolsFramework::AssetBrowser; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h index 1dfa8788e0..6d2108d826 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h @@ -5,16 +5,17 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #if !defined(Q_MOC_RUN) -#include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include #include +#include AZ_POP_DISABLE_WARNING #endif @@ -30,8 +31,8 @@ namespace AzToolsFramework class ProductAssetBrowserEntry; class SourceAssetBrowserEntry; class AssetBrowserEntry; - } -} + } // namespace AssetBrowser +} // namespace AzToolsFramework class QResizeEvent; @@ -39,8 +40,7 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewer final - : public AzToolsFramework::AssetBrowser::Previewer + class CommonPreviewer final : public AzToolsFramework::AssetBrowser::Previewer { Q_OBJECT public: @@ -50,7 +50,7 @@ namespace AZ ~CommonPreviewer(); // AzToolsFramework::AssetBrowser::Previewer overrides... - void Clear() const override {} + void Clear() const override; void Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) override; const QString& GetName() const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp index 3a6fd2a424..f947cfd8ba 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace AZ { @@ -26,28 +26,7 @@ namespace AZ bool CommonPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const { - AZ::Data::AssetId assetId = Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::ModelAsset::RTTI_Type()); - if (assetId.IsValid()) - { - return true; - } - - assetId = Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::MaterialAsset::RTTI_Type()); - if (assetId.IsValid()) - { - return true; - } - - assetId = Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::AnyAsset::RTTI_Type()); - if (assetId.IsValid()) - { - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId); - return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset"); - } - - return false; + return Thumbnails::IsSupportedThumbnail(entry->GetThumbnailKey()); } const QString& CommonPreviewerFactory::GetName() const diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h index 1f9cc9d5df..cec4ccc21f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -18,8 +19,7 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewerFactory final - : public AzToolsFramework::AssetBrowser::PreviewerFactory + class CommonPreviewerFactory final : public AzToolsFramework::AssetBrowser::PreviewerFactory { public: AZ_CLASS_ALLOCATOR(CommonPreviewerFactory, AZ::SystemAllocator, 0); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.cpp new file mode 100644 index 0000000000..298d062b7d --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + static constexpr const int CommonThumbnailSize = 256; + + ////////////////////////////////////////////////////////////////////////// + // CommonThumbnail + ////////////////////////////////////////////////////////////////////////// + CommonThumbnail::CommonThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + : Thumbnail(key) + { + for (const AZ::Uuid& typeId : GetSupportedThumbnailAssetTypes()) + { + const AZ::Data::AssetId& assetId = GetAssetId(key, typeId); + if (assetId.IsValid()) + { + m_assetId = assetId; + m_typeId = typeId; + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + return; + } + } + + AZ_Error("CommonThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); + m_state = State::Failed; + } + + void CommonThumbnail::LoadThread() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( + m_typeId, &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, + CommonThumbnailSize); + // wait for response from thumbnail renderer + m_renderWait.acquire(); + } + + CommonThumbnail::~CommonThumbnail() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + } + + void CommonThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) + { + m_pixmap = thumbnailImage; + m_renderWait.release(); + } + + void CommonThumbnail::ThumbnailFailedToRender() + { + m_state = State::Failed; + m_renderWait.release(); + } + + void CommonThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) + { + if (m_assetId == assetId && m_state == State::Ready) + { + m_state = State::Unloaded; + Load(); + } + } + + ////////////////////////////////////////////////////////////////////////// + // CommonThumbnailCache + ////////////////////////////////////////////////////////////////////////// + CommonThumbnailCache::CommonThumbnailCache() + : ThumbnailCache() + { + } + + CommonThumbnailCache::~CommonThumbnailCache() = default; + + int CommonThumbnailCache::GetPriority() const + { + // Thumbnails override default source thumbnails, so carry higher priority + return 1; + } + + const char* CommonThumbnailCache::GetProviderName() const + { + return ProviderName; + } + + bool CommonThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const + { + return Thumbnails::IsSupportedThumbnail(key); + } + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ + +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.h similarity index 80% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.h index 5d9449e988..195452ca21 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.h @@ -22,15 +22,15 @@ namespace AZ namespace Thumbnails { //! Custom thumbnail that detects when an asset changes and updates the thumbnail - class ModelThumbnail + class CommonThumbnail : public AzToolsFramework::Thumbnailer::Thumbnail , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler , private AzFramework::AssetCatalogEventBus::Handler { Q_OBJECT public: - ModelThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~ModelThumbnail() override; + CommonThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + ~CommonThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... void ThumbnailRendered(const QPixmap& thumbnailImage) override; @@ -45,19 +45,20 @@ namespace AZ AZStd::binary_semaphore m_renderWait; Data::AssetId m_assetId; + AZ::Uuid m_typeId; }; //! Cache configuration for large thumbnails - class ModelThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache + class CommonThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache { public: - ModelThumbnailCache(); - ~ModelThumbnailCache() override; + CommonThumbnailCache(); + ~CommonThumbnailCache() override; int GetPriority() const override; const char* GetProviderName() const override; - static constexpr const char* ProviderName = "Model Thumbnails"; + static constexpr const char* ProviderName = "Common Thumbnails"; protected: bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp index f29762b563..0eb6a9b4a3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace AZ { @@ -27,10 +27,10 @@ namespace AZ m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); - // CommonThumbnailRenderer supports both models and materials - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::AnyAsset::RTTI_Type()); + for (const AZ::Uuid& typeId : GetSupportedThumbnailAssetTypes()) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(typeId); + } SystemTickBus::Handler::BusConnect(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.cpp similarity index 64% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.cpp index 6d3d07faef..013bc4261b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.cpp @@ -9,9 +9,10 @@ #include #include #include +#include #include #include -#include +#include namespace AZ { @@ -30,12 +31,15 @@ namespace AZ { bool foundIt = false; AZStd::vector productsAssetInfo; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, sourceKey->GetSourceUuid(), productsAssetInfo); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, + sourceKey->GetSourceUuid(), productsAssetInfo); if (!foundIt) { return defaultAssetId; } - auto assetInfoIt = AZStd::find_if(productsAssetInfo.begin(), productsAssetInfo.end(), + auto assetInfoIt = AZStd::find_if( + productsAssetInfo.begin(), productsAssetInfo.end(), [&assetType](const Data::AssetInfo& assetInfo) { return assetInfo.m_assetType == assetType; @@ -57,7 +61,6 @@ namespace AZ return defaultAssetId; } - QString WordWrap(const QString& string, int maxLength) { QString result; @@ -82,6 +85,32 @@ namespace AZ } return result; } + + AZStd::unordered_set GetSupportedThumbnailAssetTypes() + { + return { RPI::AnyAsset::RTTI_Type(), RPI::MaterialAsset::RTTI_Type(), RPI::ModelAsset::RTTI_Type() }; + } + + bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + { + for (const AZ::Uuid& typeId : GetSupportedThumbnailAssetTypes()) + { + const AZ::Data::AssetId& assetId = GetAssetId(key, typeId); + if (assetId.IsValid()) + { + if (typeId == RPI::AnyAsset::RTTI_Type()) + { + AZ::Data::AssetInfo assetInfo; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId); + return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset"); + } + return true; + } + } + + return false; + } } // namespace Thumbnails } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.h similarity index 83% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.h index a88a25c2b7..be2432bc7b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ThumbnailUtils.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.h @@ -26,8 +26,13 @@ namespace AZ const Data::AssetType& assetType, const Data::AssetId& defaultAssetId = {}); - //! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word wrap needed + //! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word + //! wrap needed QString WordWrap(const QString& string, int maxLength); + + AZStd::unordered_set GetSupportedThumbnailAssetTypes(); + + bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); } // namespace Thumbnails } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp deleted file mode 100644 index 6a9c2ca2ca..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - static constexpr const int LightingPresetThumbnailSize = 512; // 512 is the default size in render to texture pass - - ////////////////////////////////////////////////////////////////////////// - // LightingPresetThumbnail - ////////////////////////////////////////////////////////////////////////// - LightingPresetThumbnail::LightingPresetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) - { - m_assetId = GetAssetId(key, RPI::AnyAsset::RTTI_Type()); - if (!m_assetId.IsValid()) - { - AZ_Error("LightingPresetThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; - return; - } - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } - - void LightingPresetThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::AnyAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, - LightingPresetThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } - - LightingPresetThumbnail::~LightingPresetThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } - - void LightingPresetThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } - - void LightingPresetThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } - - void LightingPresetThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } - - ////////////////////////////////////////////////////////////////////////// - // LightingPresetThumbnailCache - ////////////////////////////////////////////////////////////////////////// - LightingPresetThumbnailCache::LightingPresetThumbnailCache() - : ThumbnailCache() - { - } - - LightingPresetThumbnailCache::~LightingPresetThumbnailCache() = default; - - int LightingPresetThumbnailCache::GetPriority() const - { - // Thumbnails override default source thumbnails, so carry higher priority - return 1; - } - - const char* LightingPresetThumbnailCache::GetProviderName() const - { - return ProviderName; - } - - bool LightingPresetThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - const auto assetId = Thumbnails::GetAssetId(key, RPI::AnyAsset::RTTI_Type()); - if (assetId.IsValid()) - { - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId); - return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset"); - } - - return false; - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - -#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h deleted file mode 100644 index 437a372c3c..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/LightingPresetThumbnail.h +++ /dev/null @@ -1,67 +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 - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#endif - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! Custom thumbnail that detects when an asset changes and updates the thumbnail - class LightingPresetThumbnail - : public AzToolsFramework::Thumbnailer::Thumbnail - , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler - { - Q_OBJECT - public: - LightingPresetThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~LightingPresetThumbnail() override; - - //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(const QPixmap& thumbnailImage) override; - void ThumbnailFailedToRender() override; - - protected: - void LoadThread() override; - - private: - // AzFramework::AssetCatalogEventBus::Handler interface overrides... - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; - - AZStd::binary_semaphore m_renderWait; - Data::AssetId m_assetId; - }; - - //! Cache configuration for large thumbnails - class LightingPresetThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache - { - public: - LightingPresetThumbnailCache(); - ~LightingPresetThumbnailCache() override; - - int GetPriority() const override; - const char* GetProviderName() const override; - - static constexpr const char* ProviderName = "LightingPreset Thumbnails"; - - protected: - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp deleted file mode 100644 index b9a3412d0e..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - static constexpr const int MaterialThumbnailSize = 512; // 512 is the default size in render to texture pass - - ////////////////////////////////////////////////////////////////////////// - // MaterialThumbnail - ////////////////////////////////////////////////////////////////////////// - MaterialThumbnail::MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) - { - m_assetId = GetAssetId(key, RPI::MaterialAsset::RTTI_Type()); - if (!m_assetId.IsValid()) - { - AZ_Error("MaterialThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; - return; - } - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } - - void MaterialThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::MaterialAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, - MaterialThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } - - MaterialThumbnail::~MaterialThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } - - void MaterialThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } - - void MaterialThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } - - void MaterialThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } - - ////////////////////////////////////////////////////////////////////////// - // MaterialThumbnailCache - ////////////////////////////////////////////////////////////////////////// - MaterialThumbnailCache::MaterialThumbnailCache() - : ThumbnailCache() - { - } - - MaterialThumbnailCache::~MaterialThumbnailCache() = default; - - int MaterialThumbnailCache::GetPriority() const - { - // Thumbnails override default source thumbnails, so carry higher priority - return 1; - } - - const char* MaterialThumbnailCache::GetProviderName() const - { - return ProviderName; - } - - bool MaterialThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - return GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - -#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h deleted file mode 100644 index 1349336245..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/MaterialThumbnail.h +++ /dev/null @@ -1,67 +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 - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#endif - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! Custom thumbnail that detects when an asset changes and updates the thumbnail - class MaterialThumbnail - : public AzToolsFramework::Thumbnailer::Thumbnail - , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler - { - Q_OBJECT - public: - MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~MaterialThumbnail() override; - - //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(const QPixmap& thumbnailImage) override; - void ThumbnailFailedToRender() override; - - protected: - void LoadThread() override; - - private: - // AzFramework::AssetCatalogEventBus::Handler interface overrides... - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; - - AZStd::binary_semaphore m_renderWait; - Data::AssetId m_assetId; - }; - - //! Cache configuration for large thumbnails - class MaterialThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache - { - public: - MaterialThumbnailCache(); - ~MaterialThumbnailCache() override; - - int GetPriority() const override; - const char* GetProviderName() const override; - - static constexpr const char* ProviderName = "Material Thumbnails"; - - protected: - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp deleted file mode 100644 index e3eb7a3af6..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/ModelThumbnail.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - static constexpr const int ModelThumbnailSize = 512; // 512 is the default size in render to texture pass - - ////////////////////////////////////////////////////////////////////////// - // ModelThumbnail - ////////////////////////////////////////////////////////////////////////// - ModelThumbnail::ModelThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) - { - m_assetId = GetAssetId(key, RPI::ModelAsset::RTTI_Type()); - if (!m_assetId.IsValid()) - { - AZ_Error("ModelThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; - return; - } - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } - - void ModelThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::ModelAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, - ModelThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } - - ModelThumbnail::~ModelThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } - - void ModelThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } - - void ModelThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } - - void ModelThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } - - ////////////////////////////////////////////////////////////////////////// - // ModelThumbnailCache - ////////////////////////////////////////////////////////////////////////// - ModelThumbnailCache::ModelThumbnailCache() - : ThumbnailCache() - { - } - - ModelThumbnailCache::~ModelThumbnailCache() = default; - - int ModelThumbnailCache::GetPriority() const - { - // Thumbnails override default source thumbnails, so carry higher priority - return 1; - } - - const char* ModelThumbnailCache::GetProviderName() const - { - return ProviderName; - } - - bool ModelThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - return GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - -#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 7c7765d3af..00d3f09978 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -91,8 +91,6 @@ set(FILES Source/SkyBox/EditorHDRiSkyboxComponent.h Source/SkyBox/EditorPhysicalSkyComponent.cpp Source/SkyBox/EditorPhysicalSkyComponent.h - Source/Previewer/ThumbnailUtils.h - Source/Previewer/ThumbnailUtils.cpp Source/Previewer/CommonPreviewer.cpp Source/Previewer/CommonPreviewer.h Source/Previewer/CommonPreviewer.ui @@ -100,14 +98,12 @@ set(FILES Source/Previewer/CommonPreviewerFactory.h Source/Previewer/CommonPreviewContent.cpp Source/Previewer/CommonPreviewContent.h + Source/Previewer/CommonThumbnail.cpp + Source/Previewer/CommonThumbnail.h Source/Previewer/CommonThumbnailRenderer.cpp Source/Previewer/CommonThumbnailRenderer.h - Source/Previewer/MaterialThumbnail.cpp - Source/Previewer/MaterialThumbnail.h - Source/Previewer/ModelThumbnail.cpp - Source/Previewer/ModelThumbnail.h - Source/Previewer/LightingPresetThumbnail.cpp - Source/Previewer/LightingPresetThumbnail.h + Source/Previewer/CommonThumbnailUtils.cpp + Source/Previewer/CommonThumbnailUtils.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp From 7f4aae70891b7e95734c681475b0cb3e5e7346e0 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 10 Oct 2021 00:32:14 -0500 Subject: [PATCH 160/293] renaming Previewer folder to SharedPreview Signed-off-by: Guthrie Adams --- .../Source/{Previewer => SharedPreview}/CommonPreviewContent.cpp | 0 .../Source/{Previewer => SharedPreview}/CommonPreviewContent.h | 0 .../Code/Source/{Previewer => SharedPreview}/CommonPreviewer.cpp | 0 .../Code/Source/{Previewer => SharedPreview}/CommonPreviewer.h | 0 .../Code/Source/{Previewer => SharedPreview}/CommonPreviewer.ui | 0 .../{Previewer => SharedPreview}/CommonPreviewerFactory.cpp | 0 .../Source/{Previewer => SharedPreview}/CommonPreviewerFactory.h | 0 .../Code/Source/{Previewer => SharedPreview}/CommonThumbnail.cpp | 0 .../Code/Source/{Previewer => SharedPreview}/CommonThumbnail.h | 0 .../{Previewer => SharedPreview}/CommonThumbnailRenderer.cpp | 0 .../Source/{Previewer => SharedPreview}/CommonThumbnailRenderer.h | 0 .../Source/{Previewer => SharedPreview}/CommonThumbnailUtils.cpp | 0 .../Source/{Previewer => SharedPreview}/CommonThumbnailUtils.h | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonPreviewContent.cpp (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonPreviewContent.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonPreviewer.cpp (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonPreviewer.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonPreviewer.ui (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonPreviewerFactory.cpp (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonPreviewerFactory.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonThumbnail.cpp (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonThumbnail.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonThumbnailRenderer.cpp (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonThumbnailRenderer.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonThumbnailUtils.cpp (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{Previewer => SharedPreview}/CommonThumbnailUtils.h (100%) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewContent.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.ui b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.ui similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewer.ui rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.ui diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonPreviewerFactory.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailRenderer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Previewer/CommonThumbnailUtils.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.h From 3ee45d54bb06f553b03d0f87cc4258df352cd933 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 10 Oct 2021 00:37:13 -0500 Subject: [PATCH 161/293] rename Common*.* Shared*.* Signed-off-by: Guthrie Adams --- .../{CommonPreviewContent.cpp => SharedPreviewContent.cpp} | 0 .../{CommonPreviewContent.h => SharedPreviewContent.h} | 0 .../SharedPreview/{CommonPreviewer.cpp => SharedPreviewer.cpp} | 0 .../Source/SharedPreview/{CommonPreviewer.h => SharedPreviewer.h} | 0 .../SharedPreview/{CommonPreviewer.ui => SharedPreviewer.ui} | 0 .../{CommonPreviewerFactory.cpp => SharedPreviewerFactory.cpp} | 0 .../{CommonPreviewerFactory.h => SharedPreviewerFactory.h} | 0 .../SharedPreview/{CommonThumbnail.cpp => SharedThumbnail.cpp} | 0 .../Source/SharedPreview/{CommonThumbnail.h => SharedThumbnail.h} | 0 .../{CommonThumbnailRenderer.cpp => SharedThumbnailRenderer.cpp} | 0 .../{CommonThumbnailRenderer.h => SharedThumbnailRenderer.h} | 0 .../{CommonThumbnailUtils.cpp => SharedThumbnailUtils.cpp} | 0 .../{CommonThumbnailUtils.h => SharedThumbnailUtils.h} | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonPreviewContent.cpp => SharedPreviewContent.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonPreviewContent.h => SharedPreviewContent.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonPreviewer.cpp => SharedPreviewer.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonPreviewer.h => SharedPreviewer.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonPreviewer.ui => SharedPreviewer.ui} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonPreviewerFactory.cpp => SharedPreviewerFactory.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonPreviewerFactory.h => SharedPreviewerFactory.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonThumbnail.cpp => SharedThumbnail.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonThumbnail.h => SharedThumbnail.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonThumbnailRenderer.cpp => SharedThumbnailRenderer.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonThumbnailRenderer.h => SharedThumbnailRenderer.h} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonThumbnailUtils.cpp => SharedThumbnailUtils.cpp} (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{CommonThumbnailUtils.h => SharedThumbnailUtils.h} (100%) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewContent.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.ui b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewer.ui rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonPreviewerFactory.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnail.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailRenderer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/CommonThumbnailUtils.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h From 9f92bd2d331a8f3e0223111e78d12c106b2c558d Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 10 Oct 2021 01:45:13 -0500 Subject: [PATCH 162/293] Compile again after renaming and moving files Cleaned up namespaces Renamed a couple of functions and added comments Signed-off-by: Guthrie Adams --- .../PreviewRenderer/PreviewContent.h | 2 +- .../PreviewRenderer/PreviewRenderer.h | 12 +- .../PreviewRenderer/PreviewRenderer.cpp | 14 +- .../PreviewRendererCaptureState.cpp | 2 +- .../PreviewRendererIdleState.cpp | 2 +- .../PreviewRendererLoadState.cpp | 6 +- .../EditorCommonFeaturesSystemComponent.cpp | 10 +- .../EditorCommonFeaturesSystemComponent.h | 8 +- .../EditorMaterialSystemComponent.cpp | 4 +- .../SharedPreview/SharedPreviewContent.cpp | 28 ++-- .../SharedPreview/SharedPreviewContent.h | 12 +- .../Source/SharedPreview/SharedPreviewer.cpp | 26 ++-- .../Source/SharedPreview/SharedPreviewer.h | 14 +- .../Source/SharedPreview/SharedPreviewer.ui | 4 +- .../SharedPreview/SharedPreviewerFactory.cpp | 16 +- .../SharedPreview/SharedPreviewerFactory.h | 10 +- .../Source/SharedPreview/SharedThumbnail.cpp | 146 +++++++++--------- .../Source/SharedPreview/SharedThumbnail.h | 69 ++++----- .../SharedPreview/SharedThumbnailRenderer.cpp | 99 ++++++------ .../SharedPreview/SharedThumbnailRenderer.h | 68 ++++---- .../SharedPreview/SharedThumbnailUtils.cpp | 14 +- .../SharedPreview/SharedThumbnailUtils.h | 10 +- ...egration_commonfeatures_editor_files.cmake | 26 ++-- 23 files changed, 296 insertions(+), 306 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h index 17445835ba..bdc7afe0b1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h @@ -24,6 +24,6 @@ namespace AtomToolsFramework virtual bool IsReady() const = 0; virtual bool IsError() const = 0; virtual void ReportErrors() = 0; - virtual void UpdateScene() = 0; + virtual void Update() = 0; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h index acedc77751..d4fdd3ca1e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h @@ -24,7 +24,7 @@ class QPixmap; namespace AtomToolsFramework { - //! Provides custom rendering of preview images + //! Processes requests for setting up content that gets rendered to a texture and captured to an image class PreviewRenderer final : public PreviewerFeatureProcessorProviderBus::Handler { public: @@ -58,15 +58,15 @@ namespace AtomToolsFramework void SetState(State state); State GetState() const; - void SelectCaptureRequest(); + void ProcessCaptureRequests(); void CancelCaptureRequest(); void CompleteCaptureRequest(); - void LoadAssets(); - void UpdateLoadAssets(); - void CancelLoadAssets(); + void LoadContent(); + void UpdateLoadContent(); + void CancelLoadContent(); - void UpdateScene(); + void PoseContent(); bool StartCapture(); void EndCapture(); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 06969abee4..69a8d357c9 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -142,7 +142,7 @@ namespace AtomToolsFramework return m_currentState; } - void PreviewRenderer::SelectCaptureRequest() + void PreviewRenderer::ProcessCaptureRequests() { if (!m_captureRequestQueue.empty()) { @@ -165,12 +165,12 @@ namespace AtomToolsFramework SetState(PreviewRenderer::State::IdleState); } - void PreviewRenderer::LoadAssets() + void PreviewRenderer::LoadContent() { m_currentCaptureRequest.m_content->Load(); } - void PreviewRenderer::UpdateLoadAssets() + void PreviewRenderer::UpdateLoadContent() { if (m_currentCaptureRequest.m_content->IsReady()) { @@ -180,20 +180,20 @@ namespace AtomToolsFramework if (m_currentCaptureRequest.m_content->IsError()) { - CancelLoadAssets(); + CancelLoadContent(); return; } } - void PreviewRenderer::CancelLoadAssets() + void PreviewRenderer::CancelLoadContent() { m_currentCaptureRequest.m_content->ReportErrors(); CancelCaptureRequest(); } - void PreviewRenderer::UpdateScene() + void PreviewRenderer::PoseContent() { - m_currentCaptureRequest.m_content->UpdateScene(); + m_currentCaptureRequest.m_content->Update(); } bool PreviewRenderer::StartCapture() diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp index f3414bc29f..9cf228b707 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp @@ -19,7 +19,7 @@ namespace AtomToolsFramework void PreviewRendererCaptureState::Start() { m_ticksToCapture = 1; - m_renderer->UpdateScene(); + m_renderer->PoseContent(); AZ::TickBus::Handler::BusConnect(); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp index db91bedce1..800aa03113 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp @@ -28,6 +28,6 @@ namespace AtomToolsFramework void PreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - m_renderer->SelectCaptureRequest(); + m_renderer->ProcessCaptureRequests(); } } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp index b5d219636e..bb858989f7 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp @@ -18,7 +18,7 @@ namespace AtomToolsFramework void PreviewRendererLoadState::Start() { - m_renderer->LoadAssets(); + m_renderer->LoadContent(); m_timeRemainingS = TimeOutS; AZ::TickBus::Handler::BusConnect(); } @@ -33,11 +33,11 @@ namespace AtomToolsFramework m_timeRemainingS -= deltaTime; if (m_timeRemainingS > 0.0f) { - m_renderer->UpdateLoadAssets(); + m_renderer->UpdateLoadContent(); } else { - m_renderer->CancelLoadAssets(); + m_renderer->CancelLoadContent(); } } } // namespace AtomToolsFramework diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 47dd5ce571..1718dde5d4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -216,11 +216,11 @@ namespace AZ using namespace LyIntegration; ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::CommonThumbnailCache), + &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SharedThumbnailCache), ThumbnailContext::DefaultContext); - m_renderer = AZStd::make_unique(); - m_previewerFactory = AZStd::make_unique(); + m_renderer = AZStd::make_unique(); + m_previewerFactory = AZStd::make_unique(); } void EditorCommonFeaturesSystemComponent::TeardownThumbnails() @@ -229,7 +229,7 @@ namespace AZ using namespace LyIntegration; ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::CommonThumbnailCache::ProviderName, + &ThumbnailerRequests::UnregisterThumbnailProvider, SharedThumbnailCache::ProviderName, ThumbnailContext::DefaultContext); m_renderer.reset(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index b9a4151955..8021770873 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -13,8 +13,8 @@ #include #include #include -#include -#include +#include +#include namespace AZ { @@ -78,8 +78,8 @@ namespace AZ AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" }; float m_envProbeHeight{ 200.0f }; - AZStd::unique_ptr m_renderer; - AZStd::unique_ptr m_previewerFactory; + AZStd::unique_ptr m_renderer; + AZStd::unique_ptr m_previewerFactory; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index e18cc0b907..96a8e3e8d4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class @@ -176,7 +176,7 @@ namespace AZ m_previewRenderer->AddCaptureRequest( { 128, - AZStd::make_shared( + AZStd::make_shared( m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId, AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides), diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp index 966877317c..21020f64b1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp @@ -23,13 +23,13 @@ #include #include #include -#include +#include namespace AZ { namespace LyIntegration { - CommonPreviewContent::CommonPreviewContent( + SharedPreviewContent::SharedPreviewContent( RPI::ScenePtr scene, RPI::ViewPtr view, AZ::Uuid entityContextId, @@ -56,7 +56,7 @@ namespace AZ m_lightingPresetAsset.Create(lightingPresetAssetId); } - CommonPreviewContent::~CommonPreviewContent() + SharedPreviewContent::~SharedPreviewContent() { if (m_modelEntity) { @@ -66,46 +66,46 @@ namespace AZ } } - void CommonPreviewContent::Load() + void SharedPreviewContent::Load() { m_modelAsset.QueueLoad(); m_materialAsset.QueueLoad(); m_lightingPresetAsset.QueueLoad(); } - bool CommonPreviewContent::IsReady() const + bool SharedPreviewContent::IsReady() const { return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) && (!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) && (!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady()); } - bool CommonPreviewContent::IsError() const + bool SharedPreviewContent::IsError() const { return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); } - void CommonPreviewContent::ReportErrors() + void SharedPreviewContent::ReportErrors() { AZ_Warning( - "CommonPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), "Asset failed to load in time: %s", + "SharedPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), "Asset failed to load in time: %s", m_modelAsset.ToString().c_str()); AZ_Warning( - "CommonPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), "Asset failed to load in time: %s", + "SharedPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), "Asset failed to load in time: %s", m_materialAsset.ToString().c_str()); AZ_Warning( - "CommonPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(), + "SharedPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(), "Asset failed to load in time: %s", m_lightingPresetAsset.ToString().c_str()); } - void CommonPreviewContent::UpdateScene() + void SharedPreviewContent::Update() { UpdateModel(); UpdateLighting(); UpdateCamera(); } - void CommonPreviewContent::UpdateModel() + void SharedPreviewContent::UpdateModel() { Render::MeshComponentRequestBus::Event( m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); @@ -119,7 +119,7 @@ namespace AZ Render::DefaultMaterialAssignmentId, m_materialPropertyOverrides); } - void CommonPreviewContent::UpdateLighting() + void SharedPreviewContent::UpdateLighting() { if (m_lightingPresetAsset.IsReady()) { @@ -152,7 +152,7 @@ namespace AZ } } - void CommonPreviewContent::UpdateCamera() + void SharedPreviewContent::UpdateCamera() { // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it Vector3 center = {}; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h index a6bb2f6c4e..7308aa19bc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h @@ -19,13 +19,13 @@ namespace AZ { namespace LyIntegration { - //! Provides custom rendering of material and model previews - class CommonPreviewContent final : public AtomToolsFramework::PreviewContent + //! Creates a simple scene used for most previews and thumbnails + class SharedPreviewContent final : public AtomToolsFramework::PreviewContent { public: - AZ_CLASS_ALLOCATOR(CommonPreviewContent, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(SharedPreviewContent, AZ::SystemAllocator, 0); - CommonPreviewContent( + SharedPreviewContent( RPI::ScenePtr scene, RPI::ViewPtr view, AZ::Uuid entityContextId, @@ -34,13 +34,13 @@ namespace AZ const Data::AssetId& lightingPresetAssetId, const Render::MaterialPropertyOverrideMap& materialPropertyOverrides); - ~CommonPreviewContent() override; + ~SharedPreviewContent() override; void Load() override; bool IsReady() const override; bool IsError() const override; void ReportErrors() override; - void UpdateScene() override; + void Update() override; private: void UpdateModel(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp index 9ecc41e0f2..73080b5c05 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp @@ -12,14 +12,14 @@ #include #include #include -#include -#include +#include +#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include +#include #include #include AZ_POP_DISABLE_WARNING @@ -30,22 +30,22 @@ namespace AZ { static constexpr int CharWidth = 6; - CommonPreviewer::CommonPreviewer(QWidget* parent) + SharedPreviewer::SharedPreviewer(QWidget* parent) : Previewer(parent) - , m_ui(new Ui::CommonPreviewerClass()) + , m_ui(new Ui::SharedPreviewerClass()) { m_ui->setupUi(this); } - CommonPreviewer::~CommonPreviewer() + SharedPreviewer::~SharedPreviewer() { } - void CommonPreviewer::Clear() const + void SharedPreviewer::Clear() const { } - void CommonPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) + void SharedPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) { using namespace AzToolsFramework::AssetBrowser; using namespace AzToolsFramework::Thumbnailer; @@ -56,23 +56,23 @@ namespace AZ UpdateFileInfo(); } - const QString& CommonPreviewer::GetName() const + const QString& SharedPreviewer::GetName() const { return m_name; } - void CommonPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event) + void SharedPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event) { m_ui->m_previewWidget->setMaximumHeight(m_ui->m_previewWidget->width()); UpdateFileInfo(); } - void CommonPreviewer::UpdateFileInfo() const + void SharedPreviewer::UpdateFileInfo() const { - m_ui->m_fileInfoLabel->setText(Thumbnails::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth)); + m_ui->m_fileInfoLabel->setText(SharedPreviewUtils::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth)); } } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h index 6d2108d826..ab6f793982 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h @@ -21,7 +21,7 @@ AZ_POP_DISABLE_WARNING namespace Ui { - class CommonPreviewerClass; + class SharedPreviewerClass; } namespace AzToolsFramework @@ -40,14 +40,14 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewer final : public AzToolsFramework::AssetBrowser::Previewer + class SharedPreviewer final : public AzToolsFramework::AssetBrowser::Previewer { Q_OBJECT public: - AZ_CLASS_ALLOCATOR(CommonPreviewer, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(SharedPreviewer, AZ::SystemAllocator, 0); - explicit CommonPreviewer(QWidget* parent = nullptr); - ~CommonPreviewer(); + explicit SharedPreviewer(QWidget* parent = nullptr); + ~SharedPreviewer(); // AzToolsFramework::AssetBrowser::Previewer overrides... void Clear() const override; @@ -60,9 +60,9 @@ namespace AZ private: void UpdateFileInfo() const; - QScopedPointer m_ui; + QScopedPointer m_ui; QString m_fileInfo; - QString m_name = "CommonPreviewer"; + QString m_name = "SharedPreviewer"; }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui index f97dde0a1f..139231d607 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui @@ -1,7 +1,7 @@ - CommonPreviewerClass - + SharedPreviewerClass + 0 diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp index f947cfd8ba..95593402f3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp @@ -11,25 +11,25 @@ #include #include #include -#include -#include -#include +#include +#include +#include namespace AZ { namespace LyIntegration { - AzToolsFramework::AssetBrowser::Previewer* CommonPreviewerFactory::CreatePreviewer(QWidget* parent) const + AzToolsFramework::AssetBrowser::Previewer* SharedPreviewerFactory::CreatePreviewer(QWidget* parent) const { - return new CommonPreviewer(parent); + return new SharedPreviewer(parent); } - bool CommonPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const + bool SharedPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const { - return Thumbnails::IsSupportedThumbnail(entry->GetThumbnailKey()); + return SharedPreviewUtils::IsSupportedAssetType(entry->GetThumbnailKey()); } - const QString& CommonPreviewerFactory::GetName() const + const QString& SharedPreviewerFactory::GetName() const { return m_name; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h index cec4ccc21f..e3021cb8ab 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h @@ -19,13 +19,13 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewerFactory final : public AzToolsFramework::AssetBrowser::PreviewerFactory + class SharedPreviewerFactory final : public AzToolsFramework::AssetBrowser::PreviewerFactory { public: - AZ_CLASS_ALLOCATOR(CommonPreviewerFactory, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(SharedPreviewerFactory, AZ::SystemAllocator, 0); - CommonPreviewerFactory() = default; - ~CommonPreviewerFactory() = default; + SharedPreviewerFactory() = default; + ~SharedPreviewerFactory() = default; // AzToolsFramework::AssetBrowser::PreviewerFactory overrides... AzToolsFramework::AssetBrowser::Previewer* CreatePreviewer(QWidget* parent = nullptr) const override; @@ -33,7 +33,7 @@ namespace AZ const QString& GetName() const override; private: - QString m_name = "CommonPreviewer"; + QString m_name = "SharedPreviewer"; }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp index 298d062b7d..dcc5244d8c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp @@ -10,104 +10,100 @@ #include #include #include -#include -#include +#include +#include #include namespace AZ { namespace LyIntegration { - namespace Thumbnails - { - static constexpr const int CommonThumbnailSize = 256; + static constexpr const int SharedThumbnailSize = 256; - ////////////////////////////////////////////////////////////////////////// - // CommonThumbnail - ////////////////////////////////////////////////////////////////////////// - CommonThumbnail::CommonThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) + ////////////////////////////////////////////////////////////////////////// + // SharedThumbnail + ////////////////////////////////////////////////////////////////////////// + SharedThumbnail::SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + : Thumbnail(key) + { + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) { - for (const AZ::Uuid& typeId : GetSupportedThumbnailAssetTypes()) + const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId); + if (assetId.IsValid()) { - const AZ::Data::AssetId& assetId = GetAssetId(key, typeId); - if (assetId.IsValid()) - { - m_assetId = assetId; - m_typeId = typeId; - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - return; - } + m_assetId = assetId; + m_typeId = typeId; + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + return; } - - AZ_Error("CommonThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; } - void CommonThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - m_typeId, &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, - CommonThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } + AZ_Error("SharedThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); + m_state = State::Failed; + } - CommonThumbnail::~CommonThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } + void SharedThumbnail::LoadThread() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( + m_typeId, &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, SharedThumbnailSize); + // wait for response from thumbnail renderer + m_renderWait.acquire(); + } - void CommonThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } + SharedThumbnail::~SharedThumbnail() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + } - void CommonThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } + void SharedThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) + { + m_pixmap = thumbnailImage; + m_renderWait.release(); + } - void CommonThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } + void SharedThumbnail::ThumbnailFailedToRender() + { + m_state = State::Failed; + m_renderWait.release(); + } - ////////////////////////////////////////////////////////////////////////// - // CommonThumbnailCache - ////////////////////////////////////////////////////////////////////////// - CommonThumbnailCache::CommonThumbnailCache() - : ThumbnailCache() + void SharedThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) + { + if (m_assetId == assetId && m_state == State::Ready) { + m_state = State::Unloaded; + Load(); } + } - CommonThumbnailCache::~CommonThumbnailCache() = default; + ////////////////////////////////////////////////////////////////////////// + // SharedThumbnailCache + ////////////////////////////////////////////////////////////////////////// + SharedThumbnailCache::SharedThumbnailCache() + : ThumbnailCache() + { + } - int CommonThumbnailCache::GetPriority() const - { - // Thumbnails override default source thumbnails, so carry higher priority - return 1; - } + SharedThumbnailCache::~SharedThumbnailCache() = default; - const char* CommonThumbnailCache::GetProviderName() const - { - return ProviderName; - } + int SharedThumbnailCache::GetPriority() const + { + // Thumbnails override default source thumbnails, so carry higher priority + return 1; + } - bool CommonThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - return Thumbnails::IsSupportedThumbnail(key); - } - } // namespace Thumbnails + const char* SharedThumbnailCache::GetProviderName() const + { + return ProviderName; + } + + bool SharedThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const + { + return SharedPreviewUtils::IsSupportedAssetType(key); + } } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h index 195452ca21..d65e94a7a3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h @@ -19,50 +19,47 @@ namespace AZ { namespace LyIntegration { - namespace Thumbnails + //! Custom thumbnail that detects when an asset changes and updates the thumbnail + class SharedThumbnail final + : public AzToolsFramework::Thumbnailer::Thumbnail + , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler + , private AzFramework::AssetCatalogEventBus::Handler { - //! Custom thumbnail that detects when an asset changes and updates the thumbnail - class CommonThumbnail - : public AzToolsFramework::Thumbnailer::Thumbnail - , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler - { - Q_OBJECT - public: - CommonThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~CommonThumbnail() override; + Q_OBJECT + public: + SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + ~SharedThumbnail() override; - //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(const QPixmap& thumbnailImage) override; - void ThumbnailFailedToRender() override; + //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... + void ThumbnailRendered(const QPixmap& thumbnailImage) override; + void ThumbnailFailedToRender() override; - protected: - void LoadThread() override; + protected: + void LoadThread() override; - private: - // AzFramework::AssetCatalogEventBus::Handler interface overrides... - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; + private: + // AzFramework::AssetCatalogEventBus::Handler interface overrides... + void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; - AZStd::binary_semaphore m_renderWait; - Data::AssetId m_assetId; - AZ::Uuid m_typeId; - }; + AZStd::binary_semaphore m_renderWait; + Data::AssetId m_assetId; + AZ::Uuid m_typeId; + }; - //! Cache configuration for large thumbnails - class CommonThumbnailCache : public AzToolsFramework::Thumbnailer::ThumbnailCache - { - public: - CommonThumbnailCache(); - ~CommonThumbnailCache() override; + //! Cache configuration for large thumbnails + class SharedThumbnailCache final : public AzToolsFramework::Thumbnailer::ThumbnailCache + { + public: + SharedThumbnailCache(); + ~SharedThumbnailCache() override; - int GetPriority() const override; - const char* GetProviderName() const override; + int GetPriority() const override; + const char* GetProviderName() const override; - static constexpr const char* ProviderName = "Common Thumbnails"; + static constexpr const char* ProviderName = "Common Feature Shared Thumbnail= Provider"; - protected: - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; - }; - } // namespace Thumbnails + protected: + bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; + }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp index 0eb6a9b4a3..28b2290d23 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp @@ -8,69 +8,66 @@ #include #include -#include -#include -#include +#include +#include +#include namespace AZ { namespace LyIntegration { - namespace Thumbnails + SharedThumbnailRenderer::SharedThumbnailRenderer() { - CommonThumbnailRenderer::CommonThumbnailRenderer() - { - m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( - "CommonThumbnailRenderer Preview Scene", "CommonThumbnailRenderer Preview Pipeline")); - - m_defaultModelAsset.Create(DefaultModelAssetId, true); - m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); - m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "SharedThumbnailRenderer Preview Scene", "SharedThumbnailRenderer Preview Pipeline")); - for (const AZ::Uuid& typeId : GetSupportedThumbnailAssetTypes()) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(typeId); - } - SystemTickBus::Handler::BusConnect(); - } + m_defaultModelAsset.Create(DefaultModelAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); - CommonThumbnailRenderer::~CommonThumbnailRenderer() + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); - SystemTickBus::Handler::BusDisconnect(); + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(typeId); } + SystemTickBus::Handler::BusConnect(); + } - void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) - { - m_previewRenderer->AddCaptureRequest( - { thumbnailSize, - AZStd::make_shared( - m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), - GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId), - GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId), - GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId), - Render::MaterialPropertyOverrideMap()), - [thumbnailKey]() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - }, - [thumbnailKey](const QPixmap& pixmap) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap); - } }); - } + SharedThumbnailRenderer::~SharedThumbnailRenderer() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); + SystemTickBus::Handler::BusDisconnect(); + } - bool CommonThumbnailRenderer::Installed() const - { - return true; - } + void SharedThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) + { + m_previewRenderer->AddCaptureRequest( + { thumbnailSize, + AZStd::make_shared( + m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId), + Render::MaterialPropertyOverrideMap()), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QPixmap& pixmap) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap); + } }); + } - void CommonThumbnailRenderer::OnSystemTick() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); - } - } // namespace Thumbnails + bool SharedThumbnailRenderer::Installed() const + { + return true; + } + + void SharedThumbnailRenderer::OnSystemTick() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); + } } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h index a57c3dae8e..bcefbd6f4e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h @@ -22,41 +22,39 @@ namespace AZ { namespace LyIntegration { - namespace Thumbnails + //! Provides custom rendering thumbnails of supported asset types + class SharedThumbnailRenderer final + : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler + , public SystemTickBus::Handler { - //! Provides custom rendering of material and model thumbnails - class CommonThumbnailRenderer - : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler - , public SystemTickBus::Handler - { - public: - AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0); - - CommonThumbnailRenderer(); - ~CommonThumbnailRenderer(); - - private: - //! ThumbnailerRendererRequestsBus::Handler interface overrides... - void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; - bool Installed() const override; - - //! SystemTickBus::Handler interface overrides... - void OnSystemTick() override; - - static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); - Data::Asset m_defaultLightingPresetAsset; - - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); - Data::Asset m_defaultModelAsset; - - static constexpr const char* DefaultMaterialPath = ""; - const Data::AssetId DefaultMaterialAssetId; - Data::Asset m_defaultMaterialAsset; - - AZStd::unique_ptr m_previewRenderer; - }; - } // namespace Thumbnails + public: + AZ_CLASS_ALLOCATOR(SharedThumbnailRenderer, AZ::SystemAllocator, 0); + + SharedThumbnailRenderer(); + ~SharedThumbnailRenderer(); + + private: + //! ThumbnailerRendererRequestsBus::Handler interface overrides... + void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; + bool Installed() const override; + + //! SystemTickBus::Handler interface overrides... + void OnSystemTick() override; + + // Default assets to be kept loaded and used for rendering if not overridden + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + + static constexpr const char* DefaultMaterialPath = ""; + const Data::AssetId DefaultMaterialAssetId; + Data::Asset m_defaultMaterialAsset; + + AZStd::unique_ptr m_previewRenderer; + }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp index 013bc4261b..398e50e10a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp @@ -9,16 +9,16 @@ #include #include #include -#include #include #include #include +#include namespace AZ { namespace LyIntegration { - namespace Thumbnails + namespace SharedPreviewUtils { Data::AssetId GetAssetId( AzToolsFramework::Thumbnailer::SharedThumbnailKey key, @@ -86,16 +86,16 @@ namespace AZ return result; } - AZStd::unordered_set GetSupportedThumbnailAssetTypes() + AZStd::unordered_set GetSupportedAssetTypes() { return { RPI::AnyAsset::RTTI_Type(), RPI::MaterialAsset::RTTI_Type(), RPI::ModelAsset::RTTI_Type() }; } - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) { - for (const AZ::Uuid& typeId : GetSupportedThumbnailAssetTypes()) + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) { - const AZ::Data::AssetId& assetId = GetAssetId(key, typeId); + const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId); if (assetId.IsValid()) { if (typeId == RPI::AnyAsset::RTTI_Type()) @@ -111,6 +111,6 @@ namespace AZ return false; } - } // namespace Thumbnails + } // namespace SharedPreviewUtils } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h index be2432bc7b..51b8981e41 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h @@ -18,7 +18,7 @@ namespace AZ { namespace LyIntegration { - namespace Thumbnails + namespace SharedPreviewUtils { //! Get assetId by assetType that belongs to either source or product thumbnail key Data::AssetId GetAssetId( @@ -30,9 +30,11 @@ namespace AZ //! wrap needed QString WordWrap(const QString& string, int maxLength); - AZStd::unordered_set GetSupportedThumbnailAssetTypes(); + //! Get the set of all asset types supported by the shared preview + AZStd::unordered_set GetSupportedAssetTypes(); - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - } // namespace Thumbnails + //! Determine if a thumbnail key has an asset the shared preview + bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + } // namespace SharedPreviewUtils } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 00d3f09978..6babd43db7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -91,19 +91,19 @@ set(FILES Source/SkyBox/EditorHDRiSkyboxComponent.h Source/SkyBox/EditorPhysicalSkyComponent.cpp Source/SkyBox/EditorPhysicalSkyComponent.h - Source/Previewer/CommonPreviewer.cpp - Source/Previewer/CommonPreviewer.h - Source/Previewer/CommonPreviewer.ui - Source/Previewer/CommonPreviewerFactory.cpp - Source/Previewer/CommonPreviewerFactory.h - Source/Previewer/CommonPreviewContent.cpp - Source/Previewer/CommonPreviewContent.h - Source/Previewer/CommonThumbnail.cpp - Source/Previewer/CommonThumbnail.h - Source/Previewer/CommonThumbnailRenderer.cpp - Source/Previewer/CommonThumbnailRenderer.h - Source/Previewer/CommonThumbnailUtils.cpp - Source/Previewer/CommonThumbnailUtils.h + Source/SharedPreview/SharedPreviewer.cpp + Source/SharedPreview/SharedPreviewer.h + Source/SharedPreview/SharedPreviewer.ui + Source/SharedPreview/SharedPreviewerFactory.cpp + Source/SharedPreview/SharedPreviewerFactory.h + Source/SharedPreview/SharedPreviewContent.cpp + Source/SharedPreview/SharedPreviewContent.h + Source/SharedPreview/SharedThumbnail.cpp + Source/SharedPreview/SharedThumbnail.h + Source/SharedPreview/SharedThumbnailRenderer.cpp + Source/SharedPreview/SharedThumbnailRenderer.h + Source/SharedPreview/SharedThumbnailUtils.cpp + Source/SharedPreview/SharedThumbnailUtils.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp From 8aea92af29bf06ad455ab7a96715e848df4c3b5c Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 10 Oct 2021 02:10:15 -0500 Subject: [PATCH 163/293] renamed SharedThumbnailUtils to SharedPreviewUtils Signed-off-by: Guthrie Adams --- .../{SharedThumbnailUtils.cpp => SharedPreviewUtils.cpp} | 2 +- .../{SharedThumbnailUtils.h => SharedPreviewUtils.h} | 2 +- .../Code/Source/SharedPreview/SharedPreviewer.cpp | 4 ++-- .../Code/Source/SharedPreview/SharedPreviewerFactory.cpp | 6 +----- .../Code/Source/SharedPreview/SharedThumbnail.cpp | 7 ++----- .../Code/Source/SharedPreview/SharedThumbnailRenderer.cpp | 2 +- .../atomlyintegration_commonfeatures_editor_files.cmake | 4 ++-- 7 files changed, 10 insertions(+), 17 deletions(-) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{SharedThumbnailUtils.cpp => SharedPreviewUtils.cpp} (98%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/{SharedThumbnailUtils.h => SharedPreviewUtils.h} (93%) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp similarity index 98% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp index 398e50e10a..c2988cf53d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h similarity index 93% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h index 51b8981e41..6c5d83d22a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailUtils.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h @@ -33,7 +33,7 @@ namespace AZ //! Get the set of all asset types supported by the shared preview AZStd::unordered_set GetSupportedAssetTypes(); - //! Determine if a thumbnail key has an asset the shared preview + //! Determine if a thumbnail key has an asset supported by the shared preview bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); } // namespace SharedPreviewUtils } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp index 73080b5c05..942af55721 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp @@ -12,16 +12,16 @@ #include #include #include +#include #include -#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include #include #include +#include AZ_POP_DISABLE_WARNING namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp index 95593402f3..14d6e5b5f0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp @@ -6,14 +6,10 @@ * */ -#include -#include -#include -#include #include +#include #include #include -#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp index dcc5244d8c..ebfad39229 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp @@ -6,13 +6,10 @@ * */ -#include -#include -#include #include -#include -#include #include +#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp index 28b2290d23..c20cef548f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp @@ -9,8 +9,8 @@ #include #include #include +#include #include -#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 6babd43db7..2714b65a56 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -98,12 +98,12 @@ set(FILES Source/SharedPreview/SharedPreviewerFactory.h Source/SharedPreview/SharedPreviewContent.cpp Source/SharedPreview/SharedPreviewContent.h + Source/SharedPreview/SharedPreviewUtils.cpp + Source/SharedPreview/SharedPreviewUtils.h Source/SharedPreview/SharedThumbnail.cpp Source/SharedPreview/SharedThumbnail.h Source/SharedPreview/SharedThumbnailRenderer.cpp Source/SharedPreview/SharedThumbnailRenderer.h - Source/SharedPreview/SharedThumbnailUtils.cpp - Source/SharedPreview/SharedThumbnailUtils.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp From c3ff1e0cd3e6a3c9145a9972d2090d802d8bdba2 Mon Sep 17 00:00:00 2001 From: greerdv Date: Mon, 11 Oct 2021 11:15:55 +0100 Subject: [PATCH 164/293] feedback from PR Signed-off-by: greerdv --- Gems/PhysX/Code/Source/EditorColliderComponent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 7cc69caeb7..f8d0adf156 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -826,9 +826,9 @@ namespace PhysX } m_componentWarnings.push_back(AZStd::string::format( - "The asset \"%s\" contains one or more triangle meshes, which are not compatible with non-kinematic dynamic " - "rigid bodies. To make the collider compatible, you can export the asset as a primitive or convex mesh, use mesh " - "decomposition when exporting the asset, or set the rigid body to kinematic. Learn more about " + "The physics asset \"%s\" was exported using triangle mesh geometry, which is not compatible with non-kinematic " + "dynamic rigid bodies. To make the collider compatible, you can export the asset using primitive or convex mesh " + "geometry, use mesh decomposition when exporting the asset, or set the rigid body to kinematic. Learn more about " "colliders.", assetPath.c_str())); From b91d503a824a18b14ad8e724cd11cb805aec7e44 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Mon, 11 Oct 2021 12:55:24 +0200 Subject: [PATCH 165/293] Add AZStd::lerp math function, based on C++20 (#3468) * Add AZStd::lerp math function, based on c++20 Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Add unit test for AZStd::lerp, based on libc++ ones Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * written a reduced set of lerp tests, but now the license is correct Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Update Code/Framework/AzCore/AzCore/std/math.h Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Update Code/Framework/AzCore/Tests/AZStd/Math.cpp Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * fix the github suggestion merge Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Copy some AZ::Lerp tests to std::lerp test suite + clang-format Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Cleanup lerp test cases Remove comments that suggested very heavy tests that required things like `for every t1..` Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix unit test compilation issues Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * fix whitespace issue Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Use `TypeParam` in TYPED_TEST Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove unneeded new-lines Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * remove unused infinity Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/std/math.h | 45 ++++++++++++++++++ Code/Framework/AzCore/Tests/AZStd/Math.cpp | 46 +++++++++++++++++++ .../AzCore/Tests/azcoretests_files.cmake | 1 + 3 files changed, 92 insertions(+) create mode 100644 Code/Framework/AzCore/Tests/AZStd/Math.cpp diff --git a/Code/Framework/AzCore/AzCore/std/math.h b/Code/Framework/AzCore/AzCore/std/math.h index 03f12e6e08..042dcca657 100644 --- a/Code/Framework/AzCore/AzCore/std/math.h +++ b/Code/Framework/AzCore/AzCore/std/math.h @@ -30,4 +30,49 @@ namespace AZStd using std::sqrt; using std::tan; using std::trunc; + +} // namespace AZStd + +// from c++20 standard +namespace AZStd::Internal +{ + template + constexpr T lerp(T a, T b, T t) noexcept + { + if ((a <= 0 && b >= 0) || (a >= 0 && b <= 0)) + { + return t * b + (1 - t) * a; + } + if (t == 1) + { + return b; + } + const T x = a + t * (b - a); + if ((t > 1) == (b > a)) + { + return b < x ? x : b; + } + else + { + return x < b ? x : b; + } + } +} // namespace AZStd::Internal + +namespace AZStd +{ + constexpr float lerp(float a, float b, float t) noexcept + { + return Internal::lerp(a, b, t); + } + + constexpr double lerp(double a, double b, double t) noexcept + { + return Internal::lerp(a, b, t); + } + + constexpr long double lerp(long double a, long double b, long double t) noexcept + { + return Internal::lerp(a, b, t); + } } // namespace AZStd diff --git a/Code/Framework/AzCore/Tests/AZStd/Math.cpp b/Code/Framework/AzCore/Tests/AZStd/Math.cpp new file mode 100644 index 0000000000..5379c9946b --- /dev/null +++ b/Code/Framework/AzCore/Tests/AZStd/Math.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 +#include + +namespace UnitTest +{ + template + class StdMathTest : public ::testing::Test + { + }; + + using MathTestConfigs = ::testing::Types; + TYPED_TEST_CASE(StdMathTest, MathTestConfigs); + + TYPED_TEST(StdMathTest, LerpOperations) + { + using AZStd::lerp; + using ::testing::Eq; + using T = TypeParam; + + constexpr T maxNumber = AZStd::numeric_limits::max(); + constexpr T eps = AZStd::numeric_limits::epsilon(); + constexpr T a{ 42 }; + + // exactness: lerp(a,b,0)==a && lerp(a,b,1)==b + EXPECT_THAT(lerp(eps, maxNumber, T(0)), Eq(eps)); + EXPECT_THAT(lerp(eps, maxNumber, T(1)), Eq(maxNumber)); + + // consistency: lerp(a,a,t)==a + EXPECT_THAT(lerp(a, a, T(0.5)), Eq(a)); + EXPECT_THAT(lerp(eps, eps, T(0.5)), Eq(eps)); + + // a few generic tests taken from MathUtilTests.cpp + EXPECT_EQ(T(2.5), lerp(T(2), T(4), T(0.25))); + EXPECT_EQ(T(6.0), lerp(T(2), T(4), T(2.0))); + EXPECT_EQ(T(3.5), lerp(T(2), T(4), T(0.75))); + EXPECT_EQ(T(0.0), lerp(T(2), T(4), T(-1.0))); + } +} // namespace UnitTest diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index d738711a4f..6ba9944f7d 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -195,6 +195,7 @@ set(FILES AZStd/LockFreeQueues.cpp AZStd/LockFreeStacks.cpp AZStd/LockTests.cpp + AZStd/Math.cpp AZStd/Numeric.cpp AZStd/Ordered.cpp AZStd/Optional.cpp From f84bd9829a82e2b131ae913fcf134cc35fe32ad3 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Mon, 11 Oct 2021 13:01:14 +0100 Subject: [PATCH 166/293] remove some flackyness in physx automated tests (#4547) Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- .../PythonTests/Physics/TestSuite_Periodic.py | 4 - ...egion_SplineRegionWithModifiedTransform.py | 2 +- .../ForceRegion_ZeroPointForceDoesNothing.py | 2 +- .../Physics/tests/joints/JointsHelper.py | 11 +- .../joints/Joints_FixedLeadFollowerCollide.py | 92 ----- .../RigidBody_KinematicModeWorks.py | 30 +- .../Joints_FixedLeadFollowerCollide.ly | 3 - .../filelist.xml | 6 - .../Joints_FixedLeadFollowerCollide/level.pak | 3 - .../leveldata/Environment.xml | 14 - .../leveldata/TerrainTexture.xml | 7 - .../leveldata/TimeOfDay.xml | 356 ------------------ .../leveldata/VegetationMap.dat | 3 - .../Joints_FixedLeadFollowerCollide/tags.txt | 12 - .../terraintexture.pak | 3 - .../Joints_HingeNoLimitsConstrained.ly | 4 +- .../RigidBody_KinematicModeWorks.ly | 4 +- 17 files changed, 30 insertions(+), 526 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak diff --git a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py index da89316993..e5dd9adbb9 100755 --- a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py @@ -525,10 +525,6 @@ class TestAutomation(TestAutomationBase): from .tests.joints import Joints_BallNoLimitsConstrained as test_module self._run_test(request, workspace, editor, test_module) - def test_Joints_FixedLeadFollowerCollide(self, request, workspace, editor, launcher_platform): - from .tests.joints import Joints_FixedLeadFollowerCollide as test_module - self._run_test(request, workspace, editor, test_module) - def test_Joints_GlobalFrameConstrained(self, request, workspace, editor, launcher_platform): from .tests.joints import Joints_GlobalFrameConstrained as test_module self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py index abc58779a2..e949d2d8f9 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py @@ -82,7 +82,7 @@ def ForceRegion_SplineRegionWithModifiedTransform(): import azlmbr.bus as bus # region Constants - TIMEOUT = 5.0 + TIMEOUT = 10.0 MIN_TRIGGER_DISTANCE = 2.0 # endregion diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py index 91190f83e5..6582628ff9 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py @@ -77,7 +77,7 @@ def ForceRegion_ZeroPointForceDoesNothing(): helper.init_idle() - TIMEOUT_SECONDS = 3.0 + TIMEOUT_SECONDS = 5.0 X_Y_Z_TOLERANCE = 1.5 REGION_HEIGHT = 3.0 TERRAIN_HEIGHT = 32.0 diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py index 6226f42534..a85e460659 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py @@ -45,8 +45,13 @@ class JointEntity: # Entity class that sets a flag when an instance receives collision events. class JointEntityCollisionAware(JointEntity): def on_collision_begin(self, args): - if not self.collided: - self.collided = True + self.collided = True + + def on_collision_persist(self, args): + self.collided = True + + def on_collision_end(self, args): + self.collided = True def __init__(self, name): self.id = general.find_game_entity(name) @@ -58,3 +63,5 @@ class JointEntityCollisionAware(JointEntity): self.handler = azlmbr.physics.CollisionNotificationBusHandler() self.handler.connect(self.id) self.handler.add_callback("OnCollisionBegin", self.on_collision_begin) + self.handler.add_callback("OnCollisionPresist", self.on_collision_persist) + self.handler.add_callback("OnCollisionEnd", self.on_collision_end) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py deleted file mode 100644 index e142941c5a..0000000000 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py +++ /dev/null @@ -1,92 +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 -""" - -# Test case ID : C18243582 -# Test Case Title : Check that fixed joint allows lead-follower collision - - -# fmt: off -class Tests: - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - lead_found = ("Found lead", "Did not find lead") - follower_found = ("Found follower", "Did not find follower") - check_collision_happened = ("Lead and follower collided", "Lead and follower did not collide") -# fmt: on - - -def Joints_FixedLeadFollowerCollide(): - """ - Summary: Check that fixed joint allows lead-follower collision - - Level Description: - lead - Starts above follower entity - follower - Starts below lead entity. Constrained to lead entity with fixed joint. Starts with initial velocity of (5, 0, 0) in positive X direction. - - Expected Behavior: - The follower entity moves in the positive X direction and the lead entity is dragged along towards the positive X direction. - The x position of the lead entity is incremented from its original. - The lead and follower entities are kept apart at a distance of approximately 1.0 due to collision. - - Test Steps: - 1) Open Level - 2) Enter Game Mode - 3) Create and Validate Entities - 4) Wait for several seconds - 5) Check to see if lead and follower behaved as expected. - 6) Exit Game Mode - 7) Close Editor - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - - :return: None - """ - import os - import sys - from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper - - import azlmbr.legacy.general as general - import azlmbr.bus - - from JointsHelper import JointEntityCollisionAware - - # Helper Entity class - self.collided flag is set when instance receives collision event. - class Entity(JointEntityCollisionAware): - def criticalEntityFound(self): # Override function to use local Test dictionary - Report.critical_result(Tests.__dict__[self.name + "_found"], self.id.isValid()) - - # Main Script - helper.init_idle() - - # 1) Open Level - helper.open_level("Physics", "Joints_FixedLeadFollowerCollide") - - # 2) Enter Game Mode - helper.enter_game_mode(Tests.enter_game_mode) - - # 3) Create and Validate Entities - lead = Entity("lead") - follower = Entity("follower") - - # 4) Wait for several seconds - general.idle_wait(2.0) # wait for lead and follower to move - - # 5) Check to see if lead entity and follower collided - Report.critical_result(Tests.check_collision_happened, lead.collided and follower.collided) - - # 6) Exit Game Mode - helper.exit_game_mode(Tests.exit_game_mode) - - - -if __name__ == "__main__": - from editor_python_test_tools.utils import Report - Report.start_test(Joints_FixedLeadFollowerCollide) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py index 1c53854bab..05671389c2 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py @@ -80,6 +80,20 @@ def RigidBody_KinematicModeWorks(): ramp_id = general.find_game_entity("Ramp") Report.result(Tests.find_ramp, ramp_id.IsValid()) + # 2.1) setup collision handler + class RampTouched: + value = False + + def on_collision_begin(args): + other_id = args[0] + if other_id.Equal(ramp_id): + Report.info("Box touched ramp") + RampTouched.value = True + + handler = azlmbr.physics.CollisionNotificationBusHandler() + handler.connect(box_id) + handler.add_callback("OnCollisionBegin", on_collision_begin) + # 3) Check for kinematic ramp and not kinematic box box_kinematic = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsKinematic", box_id) Report.result(Tests.box_is_not_kinematic, not box_kinematic) @@ -98,21 +112,7 @@ def RigidBody_KinematicModeWorks(): ramp_pos_start = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", ramp_id) Report.info("Ramp's initial position: {}".format(ramp_pos_start)) - # 6) Check to see that the box hits the ramp - class RampTouched: - value = False - - def on_collision_begin(args): - other_id = args[0] - if other_id.Equal(ramp_id): - Report.info("Box touched ramp") - RampTouched.value = True - - handler = azlmbr.physics.CollisionNotificationBusHandler() - handler.connect(box_id) - handler.add_callback("OnCollisionBegin", on_collision_begin) - - # 6.5) Wait for the box to touch the ramp or timeout + # 6) Wait for the box to touch the ramp or timeout helper.wait_for_condition(lambda: RampTouched.value, TIME_OUT) Report.result(Tests.box_touched_ramp, RampTouched.value) diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly deleted file mode 100644 index 0c3ac9e668..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3093fee5317ba6fb353a435c09f43f13c5e722421aae62a297f699c202d6129e -size 6699 diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml deleted file mode 100644 index d0960f8154..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak deleted file mode 100644 index 532be2c1bd..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b1daa050e732ff0594601bbfca8ac9ed05972c2f9fa3e43dbc8645e802ed2730 -size 7959 diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml deleted file mode 100644 index 4ba36f66ae..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml deleted file mode 100644 index f43df05b22..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml deleted file mode 100644 index 456d609b8a..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml +++ /dev/null @@ -1,356 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat deleted file mode 100644 index dce5631cd0..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e6a5435c928079b27796f6b202bbc2623e7e454244ddc099a3cadf33b7cb9e9 -size 63 diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt deleted file mode 100644 index 0d6c1880e7..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt +++ /dev/null @@ -1,12 +0,0 @@ -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 -0,0,0,0,0,0 diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak deleted file mode 100644 index fe3604a050..0000000000 --- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85 -size 22 diff --git a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly index 3d17ae7ccc..86dd941423 100644 --- a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly +++ b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:012caffa9354f6253d2e626ba183b44eb02a74eba286fde0430227ef024411e2 -size 8961 +oid sha256:817bd8dd22e185136418b60fba5b3552993687515d3d5ae96791f2c3be907b92 +size 7233 diff --git a/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly b/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly index 92e6788bf0..d6052ffa7c 100644 --- a/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly +++ b/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:619bcf0c2a2b08f4ffe05e60858c479828fe39d5530f4e488b9c0ec8a585ccb7 -size 7735 +oid sha256:cb97ada674d123c67d7a32eb65e81fa66472cf51f748054c4a4297649f2a0f40 +size 5568 From 9baf76beab35c190eee3044e2d57b4b70421e5a3 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 11 Oct 2021 13:28:33 +0100 Subject: [PATCH 167/293] Add missing header for non-unity builds on Linux. Signed-off-by: John --- Code/Editor/MainWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index 05477bb0c7..ed72cd9170 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -98,6 +98,7 @@ AZ_POP_DISABLE_WARNING #include "ActionManager.h" #include +#include #include using namespace AZ; From 6c8441713d91a0237fe002a687b43847d92c8ab0 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 11 Oct 2021 14:02:56 +0100 Subject: [PATCH 168/293] Fix another missing header for Linux non-unity. Signed-off-by: John --- Code/Editor/GameExporter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Editor/GameExporter.cpp b/Code/Editor/GameExporter.cpp index 9315505e08..0324629877 100644 --- a/Code/Editor/GameExporter.cpp +++ b/Code/Editor/GameExporter.cpp @@ -28,6 +28,7 @@ #include "Objects/EntityObject.h" #include +#include ////////////////////////////////////////////////////////////////////////// #define MUSIC_LEVEL_LIBRARY_FILE "Music.xml" From e26d1f9ec564d3eed9412d6e65d6345daada6bd9 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 11 Oct 2021 14:17:46 +0100 Subject: [PATCH 169/293] Linux non-unity header fix (again). Signed-off-by: John --- Code/Editor/Viewport.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Editor/Viewport.cpp b/Code/Editor/Viewport.cpp index 5b4f4a4df3..44c41fef2f 100644 --- a/Code/Editor/Viewport.cpp +++ b/Code/Editor/Viewport.cpp @@ -18,6 +18,7 @@ #include #include +#include #include // Editor From 3ef24d3a05400dbf6a1ba8d964f9cc1c37d7968a Mon Sep 17 00:00:00 2001 From: John Date: Mon, 11 Oct 2021 14:28:27 +0100 Subject: [PATCH 170/293] Header fix. Signed-off-by: John --- Code/Editor/Viewport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Editor/Viewport.cpp b/Code/Editor/Viewport.cpp index 44c41fef2f..c8f2e268d9 100644 --- a/Code/Editor/Viewport.cpp +++ b/Code/Editor/Viewport.cpp @@ -18,8 +18,8 @@ #include #include -#include #include +#include // Editor #include "ViewManager.h" From 1c3b293cd36da71dd5c34fc71521d9a81446b885 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 11 Oct 2021 07:28:34 -0700 Subject: [PATCH 171/293] fix comments replace /** with //! Signed-off-by: Michael Pollind --- .../AzCore/AzCore/Math/IntersectSegment.h | 454 ++++++++---------- .../AzCore/AzCore/Math/IntersectSegment.inl | 1 - 2 files changed, 204 insertions(+), 251 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h index 7be35c5ae6..ecb0d7acc9 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h @@ -16,56 +16,47 @@ namespace AZ { namespace Intersect { - /** - * LineToPointDistanceTime computes the time of the shortest distance from point 'p' to segment (s1,s2). - * To calculate the point of intersection: - * P = s1 + u (s2 - s1) - * @param s1 segment start point - * @param s2 segment end point - * @param p point to find the closest time to. - * @return time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] - */ + //! LineToPointDistanceTime computes the time of the shortest distance from point 'p' to segment (s1,s2). + //! To calculate the point of intersection: + //! P = s1 + u (s2 - s1) + //! @param s1 segment start point + //! @param s2 segment end point + //! @param p point to find the closest time to. + //! @return time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] float LineToPointDistanceTime(const Vector3& s1, const Vector3& s21, const Vector3& p); - /** - * LineToPointDistance computes the closest point to 'p' from a segment (s1,s2). - * @param s1 segment start point - * @param s2 segment end point - * @param p point to find the closest time to. - * @param u time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] - * @return the closest point - */ + //! LineToPointDistance computes the closest point to 'p' from a segment (s1,s2). + //! @param s1 segment start point + //! @param s2 segment end point + //! @param p point to find the closest time to. + //! @param u time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] + //! @return the closest point Vector3 LineToPointDistance(const Vector3& s1, const Vector3& s2, const Vector3& p, float& u); - /** - * Given segment pq and triangle abc (CCW), returns whether segment intersects - * triangle and if so, also returns the barycentric coordinates (u,v,w) - * of the intersection point. - * - * @param p segment start point - * @param q segment end point - * @param a triangle point 1 - * @param b triangle point 2 - * @param c triangle point 3 - * @param normal at the intersection point. - * @param t time of intersection along the segment [0.0 (p), 1.0 (q)] - * @return true if the segments intersects the triangle otherwise false - */ + //! Given segment pq and triangle abc (CCW), returns whether segment intersects + //! triangle and if so, also returns the barycentric coordinates (u,v,w) + //! of the intersection point. + //! + //! @param p segment start point + //! @param q segment end point + //! @param a triangle point 1 + //! @param b triangle point 2 + //! @param c triangle point 3 + //! @param normal at the intersection point. + //! @param t time of intersection along the segment [0.0 (p), 1.0 (q)] + //! @return true if the segments intersects the triangle otherwise false int IntersectSegmentTriangleCCW( const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, Vector3& normal, float& t); - /** - * Same as \ref IntersectSegmentTriangleCCW without respecting the triangle (a,b,c) vertex order (double sided). - * - * @param p segment start point - * @param q segment end point - * @param a triangle point 1 - * @param b triangle point 2 - * @param c triangle point 3 - * @param normal at the intersection point; - * @param t time of intersection along the segment [0.0 (p), 1.0 (q)] - * @return true if the segments intersects the triangle otherwise false - */ + //! Same as \ref IntersectSegmentTriangleCCW without respecting the triangle (a,b,c) vertex order (double sided). + //! //! @param p segment start point + //! @param q segment end point + //! @param a triangle point 1 + //! @param b triangle point 2 + //! @param c triangle point 3 + //! @param normal at the intersection point; + //! @param t time of intersection along the segment [0.0 (p), 1.0 (q)] + //! @return true if the segments intersects the triangle otherwise false int IntersectSegmentTriangle( const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, Vector3& normal, float& t); @@ -77,19 +68,17 @@ namespace AZ ISECT_RAY_AABB_ISECT, ///< intersects along the PQ segment }; - /** - * Intersect ray R(t) = rayStart + t*d against AABB a. When intersecting, - * return intersection distance tmin and point q of intersection. - * @param rayStart ray starting point - * @param dir ray direction and length (dir = rayEnd - rayStart) - * @param dirRCP 1/dir (reciprocal direction - we cache this result very often so we don't need to compute it multiple times, - * otherwise just use dir.GetReciprocal()) - * @param aabb Axis aligned bounding box to intersect against - * @param tStart time on ray of the first intersection [0,1] or 0 if the ray starts inside the aabb - check the return value - * @param tEnd time of the of the second intersection [0,1] (it can be > 1 if intersects after the rayEnd) - * @param startNormal normal at the start point. - * @return \ref RayAABBIsectTypes - */ + //! Intersect ray R(t) = rayStart + t*d against AABB a. When intersecting, + //! return intersection distance tmin and point q of intersection. + //! @param rayStart ray starting point + //! @param dir ray direction and length (dir = rayEnd - rayStart) + //! @param dirRCP 1/dir (reciprocal direction - we cache this result very often so we don't need to compute it multiple times, + //! otherwise just use dir.GetReciprocal()) + //! @param aabb Axis aligned bounding box to intersect against + //! @param tStart time on ray of the first intersection [0,1] or 0 if the ray starts inside the aabb - check the return value + //! @param tEnd time of the of the second intersection [0,1] (it can be > 1 if intersects after the rayEnd) + //! @param startNormal normal at the start point. + //! @return \ref RayAABBIsectTypes RayAABBIsectTypes IntersectRayAABB( const Vector3& rayStart, const Vector3& dir, @@ -99,51 +88,43 @@ namespace AZ float& tEnd, Vector3& startNormal /*, Vector3& inter*/); - /** - * Intersect ray against AABB. - * - * @param rayStart ray starting point. - * @param dir ray reciprocal direction. - * @param aabb Axis aligned bounding box to intersect against. - * @param start length on ray of the first intersection. - * @param end length of the of the second intersection. - * @return \ref RayAABBIsectTypes In this faster version than IntersectRayAABB we return only ISECT_RAY_AABB_NONE and ISECT_RAY_AABB_ISECT. You can check yourself for that case. - */ + //! Intersect ray against AABB. + //! + //! @param rayStart ray starting point. + //! @param dir ray reciprocal direction. + //! @param aabb Axis aligned bounding box to intersect against. + //! @param start length on ray of the first intersection. + //! @param end length of the of the second intersection. + //! @return \ref RayAABBIsectTypes In this faster version than IntersectRayAABB we return only ISECT_RAY_AABB_NONE and ISECT_RAY_AABB_ISECT. You can check yourself for that case. RayAABBIsectTypes IntersectRayAABB2(const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, float& start, float& end); - /** - * Clip a ray to an aabb. return true if ray was clipped. The ray - * can be inside so don't use the result if the ray intersect the box. - * - * @param aabb bounds - * @param rayStart the start of the ray - * @param rayEnd the end of the ray - * @param tClipStart[out] The proportion where the ray enterts the aabb - * @param tClipEnd[out] The proportion where the ray exits the aabb - * @return true ray was clipped else false - */ + //! Clip a ray to an aabb. return true if ray was clipped. The ray + //! can be inside so don't use the result if the ray intersect the box. + //! + //! @param aabb bounds + //! @param rayStart the start of the ray + //! @param rayEnd the end of the ray + //! @param tClipStart[out] The proportion where the ray enterts the aabb + //! @param tClipEnd[out] The proportion where the ray exits the aabb + //! @return true ray was clipped else false bool ClipRayWithAabb(const Aabb& aabb, Vector3& rayStart, Vector3& rayEnd, float& tClipStart, float& tClipEnd); - /** - * Test segment and aabb where the segment is defined by midpoint - * midPoint = (p1-p0) * 0.5f and half vector halfVector = p1 - midPoint. - * the aabb is at the origin and defined by half extents only. - * - * @param midPoint midpoint of a line segment - * @param halfVector half vector of an aabb - * @param aabbExtends the extends of a bounded box - * @return 1 if the intersect, otherwise 0. - */ + //! Test segment and aabb where the segment is defined by midpoint + //! midPoint = (p1-p0) * 0.5f and half vector halfVector = p1 - midPoint. + //! the aabb is at the origin and defined by half extents only. + //! + //! @param midPoint midpoint of a line segment + //! @param halfVector half vector of an aabb + //! @param aabbExtends the extends of a bounded box + //! @return 1 if the intersect, otherwise 0. bool TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends); - /** - * Test if segment specified by points p0 and p1 intersects AABB. \ref TestSegmentAABBOrigin - * - * @param p0 point 1 - * @param p1 point 2 - * @param aabb bounded box - * @return true if the segment and AABB intersect, otherwise false. - */ + //! Test if segment specified by points p0 and p1 intersects AABB. \ref TestSegmentAABBOrigin + //! + //! @param p0 point 1 + //! @param p1 point 2 + //! @param aabb bounded box + //! @return true if the segment and AABB intersect, otherwise false. bool TestSegmentAABB(const Vector3& p0, const Vector3& p1, const Aabb& aabb); //! Ray sphere intersection result types. @@ -154,42 +135,36 @@ namespace AZ ISECT_RAY_SPHERE_ISECT, // along the PQ segment }; - /** - * IntersectRaySphereOrigin - * return time t>=0 but not limited, so if you check a segment make sure - * t <= segmentLen - * @param rayStart ray start point - * @param rayDirNormalized ray direction normalized. - * @param shereRadius sphere radius - * @param time of closest intersection [0,+INF] in relation to the normalized direction. - * @return \ref SphereIsectTypes - **/ + //! IntersectRaySphereOrigin + //! return time t>=0 but not limited, so if you check a segment make sure + //! t <= segmentLen + //! @param rayStart ray start point + //! @param rayDirNormalized ray direction normalized. + //! @param shereRadius sphere radius + //! @param time of closest intersection [0,+INF] in relation to the normalized direction. + //! @return \ref SphereIsectTypes SphereIsectTypes IntersectRaySphereOrigin( const Vector3& rayStart, const Vector3& rayDirNormalized, const float sphereRadius, float& t); - /** - * Intersect ray (rayStart,rayDirNormalized) and sphere (sphereCenter,sphereRadius) \ref IntersectRaySphereOrigin - * - * @param rayStart - * @param rayDirNormalized - * @param sphereCenter - * @param sphereRadius - * @param t - * @return int - */ + //! Intersect ray (rayStart,rayDirNormalized) and sphere (sphereCenter,sphereRadius) \ref IntersectRaySphereOrigin + //! + //! @param rayStart + //! @param rayDirNormalized + //! @param sphereCenter + //! @param sphereRadius + //! @param t + //! @return SphereIsectTypes SphereIsectTypes IntersectRaySphere( const Vector3& rayStart, const Vector3& rayDirNormalized, const Vector3& sphereCenter, const float sphereRadius, float& t); - /** - * @param rayOrigin The origin of the ray to test. - * @param rayDir The direction of the ray to test. It has to be unit length. - * @param diskCenter Center point of the disk - * @param diskRadius Radius of the disk - * @param diskNormal A normal perpendicular to the disk - * @param[out] t If returning 1 (indicating a hit), this contains distance from rayOrigin along the normalized rayDir - * that the hit occured at. - * @return The number of intersecting points. - **/ + //! @param rayOrigin The origin of the ray to test. + //! @param rayDir The direction of the ray to test. It has to be unit length. + //! @param diskCenter Center point of the disk + //! @param diskRadius Radius of the disk + //! @param diskNormal A normal perpendicular to the disk + //! @param[out] t If returning 1 (indicating a hit), this contains distance from rayOrigin along the normalized rayDir + //! that the hit occured at. + //! @return The number of intersecting points. int IntersectRayDisk( const Vector3& rayOrigin, const Vector3& rayDir, @@ -198,20 +173,18 @@ namespace AZ const AZ::Vector3& diskNormal, float& t); - /** - * If there is only one intersecting point, the coefficient is stored in \ref t1. - * @param rayOrigin The origin of the ray to test. - * @param rayDir The direction of the ray to test. It has to be unit length. - * @param cylinderEnd1 The center of the circle on one end of the cylinder. - * @param cylinderDir The direction pointing from \ref cylinderEnd1 to the other end of the cylinder. It has to be unit - * length. - * @param cylinderHeight The distance between two centers of the circles on two ends of the cylinder respectively. - * @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - * as "rayOrigin + t1 * rayDir". - * @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - * as "rayOrigin + t2 * rayDir". - * @return The number of intersecting points. - **/ + //! If there is only one intersecting point, the coefficient is stored in \ref t1. + //! @param rayOrigin The origin of the ray to test. + //! @param rayDir The direction of the ray to test. It has to be unit length. + //! @param cylinderEnd1 The center of the circle on one end of the cylinder. + //! @param cylinderDir The direction pointing from \ref cylinderEnd1 to the other end of the cylinder. It has to be unit + //! length. + //! @param cylinderHeight The distance between two centers of the circles on two ends of the cylinder respectively. + //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + //! as "rayOrigin + t1 * rayDir". + //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + //! as "rayOrigin + t2 * rayDir". + //! @return The number of intersecting points. int IntersectRayCappedCylinder( const Vector3& rayOrigin, const Vector3& rayDir, @@ -222,20 +195,18 @@ namespace AZ float& t1, float& t2); - /** - * If there is only one intersecting point, the coefficient is stored in \ref t1. - * @param rayOrigin The origin of the ray to test. - * @param rayDir The direction of the ray to test. It has to be unit length. - * @param coneApex The apex of the cone. - * @param coneDir The unit-length direction from the apex to the base. - * @param coneHeight The height of the cone, from the apex to the base. - * @param coneBaseRadius The radius of the cone base circle. - * @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - * as "rayOrigin + t1 * rayDir". - * @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - * as "rayOrigin + t2 * rayDir". - * @return The number of intersecting points. - **/ + //! If there is only one intersecting point, the coefficient is stored in \ref t1. + //! @param rayOrigin The origin of the ray to test. + //! @param rayDir The direction of the ray to test. It has to be unit length. + //! @param coneApex The apex of the cone. + //! @param coneDir The unit-length direction from the apex to the base. + //! @param coneHeight The height of the cone, from the apex to the base. + //! @param coneBaseRadius The radius of the cone base circle. + //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + //! as "rayOrigin + t1 * rayDir". + //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated + //! as "rayOrigin + t2 * rayDir". + //! @return The number of intersecting points. int IntersectRayCone( const Vector3& rayOrigin, const Vector3& rayDir, @@ -246,16 +217,13 @@ namespace AZ float& t1, float& t2); - /** - * Test intersection between a ray and a plane in 3D. - * @param rayOrigin The origin of the ray to test intersection with. - * @param rayDir The direction of the ray to test intersection with. - * @param planePos A point on the plane to test intersection with. - * @param planeNormal The normal of the plane to test intersection with. - * @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin - *+ t * rayDirection". - * @return The number of intersection point. - **/ + //! Test intersection between a ray and a plane in 3D. + //! @param rayOrigin The origin of the ray to test intersection with. + //! @param rayDir The direction of the ray to test intersection with. + //! @param planePos A point on the plane to test intersection with. + //! @param planeNormal The normal of the plane to test intersection with. + //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". + //! @return The number of intersection point. int IntersectRayPlane( const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& planePos, const Vector3& planeNormal, float& t); @@ -268,8 +236,7 @@ namespace AZ //! @param vertexB One of the four points that define the quadrilateral. //! @param vertexC One of the four points that define the quadrilateral. //! @param vertexD One of the four points that define the quadrilateral. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + - //! t * rayDirection". + //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". //! @return The number of intersection point. int IntersectRayQuad( const Vector3& rayOrigin, @@ -280,20 +247,19 @@ namespace AZ const Vector3& vertexD, float& t); - /** Test intersection between a ray and an oriented box in 3D. - * @param rayOrigin The origin of the ray to test intersection with. - * @param rayDir The direction of the ray to test intersection with. - * @param boxCenter The position of the center of the box. - * @param boxAxis1 An axis along one dimension of the oriented box. - * @param boxAxis2 An axis along one dimension of the oriented box. - * @param boxAxis3 An axis along one dimension of the oriented box. - * @param boxHalfExtent1 The half extent of the box on the dimension of \ref boxAxis1. - * @param boxHalfExtent2 The half extent of the box on the dimension of \ref boxAxis2. - * @param boxHalfExtent3 The half extent of the box on the dimension of \ref boxAxis3. - * @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + - * t * rayDirection". - * @return 1 if there is an intersection, 0 otherwise. - **/ + //! Test intersection between a ray and an oriented box in 3D. + //! + //! @param rayOrigin The origin of the ray to test intersection with. + //! @param rayDir The direction of the ray to test intersection with. + //! @param boxCenter The position of the center of the box. + //! @param boxAxis1 An axis along one dimension of the oriented box. + //! @param boxAxis2 An axis along one dimension of the oriented box. + //! @param boxAxis3 An axis along one dimension of the oriented box. + //! @param boxHalfExtent1 The half extent of the box on the dimension of \ref boxAxis1. + //! @param boxHalfExtent2 The half extent of the box on the dimension of \ref boxAxis2. + //! @param boxHalfExtent3 The half extent of the box on the dimension of \ref boxAxis3. + //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". + //! @return 1 if there is an intersection, 0 otherwise. int IntersectRayBox( const Vector3& rayOrigin, const Vector3& rayDir, @@ -306,15 +272,14 @@ namespace AZ float boxHalfExtent3, float& t); - /** - * Test intersection between a ray and an OBB. - * @param rayOrigin The origin of the ray to test intersection with. - * @param rayDir The direction of the ray to test intersection with. - * @param obb The OBB to test for intersection with the ray. - * @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * - * rayDirection". - * @return 1 if there is an intersection, 0 otherwise. - */ + //! Test intersection between a ray and an OBB. + //! + //! @param rayOrigin The origin of the ray to test intersection with. + //! @param rayDir The direction of the ray to test intersection with. + //! @param obb The OBB to test for intersection with the ray. + //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * + //! rayDirection". + //! @return 1 if there is an intersection, 0 otherwise. int IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t); //! Ray cylinder intersection types. @@ -327,18 +292,16 @@ namespace AZ RR_ISECT_RAY_CYL_Q_SIDE, // on the Q side }; - /** - * Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder - * Intersect segment S(t)=sa+t(dir), 0<=t<=1 against cylinder specified by p, q and r. - * - * @param sa point - * @param dir magnitude along sa - * @param p center point of side 1 cylinder - * @param q center point of side 2 cylinder - * @param r radius of cylinder - * @param t[out] proporition along line semgnet - * @return CylinderIsectTypes - */ + //! Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder + //! Intersect segment S(t)=sa+t(dir), 0<=t<=1 against cylinder specified by p, q and r. + //! + //! @param sa point + //! @param dir magnitude along sa + //! @param p center point of side 1 cylinder + //! @param q center point of side 2 cylinder + //! @param r radius of cylinder + //! @param t[out] proporition along line semgnet + //! @return CylinderIsectTypes CylinderIsectTypes IntersectSegmentCylinder( const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); @@ -352,19 +315,16 @@ namespace AZ ISECT_RAY_CAPSULE_Q_SIDE, // on the Q side }; - /** - * This is a quick implementation of segment capsule based on segment cylinder \ref IntersectSegmentCylinder - * segment sphere intersection. We can optimize it a lot once we fix the ray - * cylinder intersection. - */ + //! This is a quick implementation of segment capsule based on segment cylinder \ref IntersectSegmentCylinder + //! segment sphere intersection. We can optimize it a lot once we fix the ray + //! cylinder intersection. + //! CapsuleIsectTypes IntersectSegmentCapsule( const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); - /** - * Intersect segment S(t)=A+t(B-A), 0<=t<=1 against convex polyhedron specified - * by the n halfspaces defined by the planes p[]. On exit tfirst and tlast - * define the intersection, if any. - */ + //! Intersect segment S(t)=A+t(B-A), 0<=t<=1 against convex polyhedron specified + //! by the n halfspaces defined by the planes p[]. On exit tfirst and tlast + //! define the intersection, if any. bool IntersectSegmentPolyhedron( const Vector3& sa, const Vector3& sBA, @@ -375,22 +335,20 @@ namespace AZ int& iFirstPlane, int& iLastPlane); - /** - * Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between - * two segments segment1Start<->segment1End and segment2Start<->segment2End. Also calculate the values of segment1Proportion and - * segment2Proportion where closestPointSegment1 = segment1Start + (segment1Proportion * (segment1End - segment1Start)) - * closestPointSegment2 = segment2Start + (segment2Proportion * (segment2End - segment2Start)) - * If segments are parallel returns a solution. - * @param segment1Start start of segment 1. - * @param segment1End end of segment 1. - * @param segment2Start start of segment 2. - * @param segment2End end of segment 2. - * @param segment1Proportion[out] the proporition along segment 1 [0..1] - * @param segment2Proportion[out] the proporition along segment 2 [0..1] - * @param closestPointSegment1[out] closest point on segment 1. - * @param closestPointSegment2[out] closest point on segment 2. - * @param epsilon the minimum square distance where a line segment can be treated as a single point. - */ + //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between + //! two segments segment1Start<->segment1End and segment2Start<->segment2End. Also calculate the values of segment1Proportion and + //! segment2Proportion where closestPointSegment1 = segment1Start + (segment1Proportion * (segment1End - segment1Start)) + //! closestPointSegment2 = segment2Start + (segment2Proportion * (segment2End - segment2Start)) + //! If segments are parallel returns a solution. + //! @param segment1Start start of segment 1. + //! @param segment1End end of segment 1. + //! @param segment2Start start of segment 2. + //! @param segment2End end of segment 2. + //! @param segment1Proportion[out] the proporition along segment 1 [0..1] + //! @param segment2Proportion[out] the proporition along segment 2 [0..1] + //! @param closestPointSegment1[out] closest point on segment 1. + //! @param closestPointSegment2[out] closest point on segment 2. + //! @param epsilon the minimum square distance where a line segment can be treated as a single point. void ClosestSegmentSegment( const Vector3& segment1Start, const Vector3& segment1End, @@ -402,19 +360,17 @@ namespace AZ Vector3& closestPointSegment2, float epsilon = 1e-4f); - /** - * Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between - * two segments segment1Start<->segment1End and segment2Start<->segment2End. - * If segments are parallel returns a solution. - * - * @param segment1Start start of segment 1. - * @param segment1End end of segment 1. - * @param segment2Start start of segment 2. - * @param segment2End end of segment 2. - * @param closestPointSegment1[out] closest point on segment 1. - * @param closestPointSegment2[out] closest point on segment 2. - * @param epsilon the minimum square distance where a line segment can be treated as a single point. - */ + //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between + //! two segments segment1Start<->segment1End and segment2Start<->segment2End. + //! If segments are parallel returns a solution. + //! + //! @param segment1Start start of segment 1. + //! @param segment1End end of segment 1. + //! @param segment2Start start of segment 2. + //! @param segment2End end of segment 2. + //! @param closestPointSegment1[out] closest point on segment 1. + //! @param closestPointSegment2[out] closest point on segment 2. + //! @param epsilon the minimum square distance where a line segment can be treated as a single point. void ClosestSegmentSegment( const Vector3& segment1Start, const Vector3& segment1End, @@ -424,17 +380,15 @@ namespace AZ Vector3& closestPointSegment2, float epsilon = 1e-4f); - /** - * Calculate the point (closestPointOnSegment) that is the closest point on - * segment segmentStart/segmentEnd to point. Also calculate the value of proportion where - * closestPointOnSegment = segmentStart + (proportion * (segmentEnd - segmentStart)) - * - * @param point the point to test - * @param segmentStart the start of the segment - * @param segmentEnd the end of the segment - * @param proportion[out] the proportion of the segment L(t) = (end - start) * t - * @param closestPointOnSegment[out] the point along the line segment - */ + //! Calculate the point (closestPointOnSegment) that is the closest point on + //! segment segmentStart/segmentEnd to point. Also calculate the value of proportion where + //! closestPointOnSegment = segmentStart + (proportion * (segmentEnd - segmentStart)) + //! + //! @param point the point to test + //! @param segmentStart the start of the segment + //! @param segmentEnd the end of the segment + //! @param proportion[out] the proportion of the segment L(t) = (end - start) * t + //! @param closestPointOnSegment[out] the point along the line segment void ClosestPointSegment( const Vector3& point, const Vector3& segmentStart, diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl index b9f5139923..b570b6a182 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.inl @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#pragma once namespace AZ { From 2d7dfe5047bef70e3dcf4fcf77a8fab080eb3516 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Mon, 11 Oct 2021 08:36:07 -0600 Subject: [PATCH 172/293] Increase the max time in the iOS run loop from DBL_EPSILON to one millisecond to address issue where the virtual keyboard is sluggish. (#4580) Signed-off-by: bosnichd --- .../Platform/iOS/AzFramework/Application/Application_iOS.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Application/Application_iOS.mm b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Application/Application_iOS.mm index 41bba124c7..36d920085b 100644 --- a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Application/Application_iOS.mm +++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Application/Application_iOS.mm @@ -112,9 +112,10 @@ namespace AzFramework void ApplicationIos::PumpSystemEventLoopUntilEmpty() { SInt32 result; + const CFTimeInterval MaxSecondsInRunLoop = 0.001; // One millisecond do { - result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, DBL_EPSILON, TRUE); + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, MaxSecondsInRunLoop, TRUE); } while (result == kCFRunLoopRunHandledSource); } From 3b89f7e1cd0c259642d6b70de5b96a4a734267f9 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Mon, 11 Oct 2021 09:55:28 -0500 Subject: [PATCH 173/293] {lyn7283} added test for assetHint Json Serialzier callback logic (#4586) * {lyn7283} adding unit test for the assetHint Json Serialzier callback logic AssetTracker_Callback_Works will regress the functionality Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * clean up of the jsonRegistrationContext Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> --- .../AzCore/Tests/AssetJsonSerializerTests.cpp | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp b/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp index e04c5190f9..e3a2c5c23b 100644 --- a/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp +++ b/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp @@ -64,6 +64,91 @@ namespace JsonSerializationTests }; + class TestSerializedAssetTracker + : public BaseJsonSerializerFixture + { + public: + void SetUp() override + { + BaseJsonSerializerFixture::SetUp(); + + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + // Set up the Job Manager with 1 thread so that the Asset Manager is able to load assets. + AZ::JobManagerDesc jobDesc; + AZ::JobManagerThreadDesc threadDesc; + jobDesc.m_workerThreads.push_back(threadDesc); + m_jobManager = aznew AZ::JobManager(jobDesc); + m_jobContext = aznew AZ::JobContext(*m_jobManager); + AZ::JobContext::SetGlobalContext(m_jobContext); + + AZ::Data::AssetManager::Descriptor descriptor; + AZ::Data::AssetManager::Create(descriptor); + AZ::Data::AssetManager::Instance().RegisterHandler(&m_assetHandler, azrtti_typeid()); + + m_serializeContext->RegisterGenericType>(); + m_jsonRegistrationContext->Serializer()->HandlesType(); + } + + void TearDown() override + { + m_jsonRegistrationContext->EnableRemoveReflection(); + m_jsonRegistrationContext->Serializer()->HandlesType(); + m_jsonRegistrationContext->DisableRemoveReflection(); + + AZ::Data::AssetManager::Instance().UnregisterHandler(&m_assetHandler); + AZ::Data::AssetManager::Destroy(); + + AZ::JobContext::SetGlobalContext(nullptr); + delete m_jobContext; + delete m_jobManager; + + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + + BaseJsonSerializerFixture::TearDown(); + } + + private: + TestAssetHandler m_assetHandler; + AZ::JobManager* m_jobManager{ nullptr }; + AZ::JobContext* m_jobContext{ nullptr }; + }; + + TEST_F(TestSerializedAssetTracker, AssetTracker_Callback_Works) + { + auto assetCallback = [](AZ::Data::Asset& asset) + { + if (!asset.GetId().IsValid() && !asset.GetHint().empty()) + { + if (asset.GetHint() == "test/path/foo.asset") + { + asset.SetHint("passed"); + } + } + }; + auto tracker = AZ::Data::SerializedAssetTracker{}; + tracker.SetAssetFixUp(assetCallback); + + AZ::JsonDeserializerSettings settings; + settings.m_metadata.Add(tracker); + settings.m_registrationContext = this->m_jsonRegistrationContext.get(); + settings.m_serializeContext = this->m_serializeContext.get(); + + AZStd::string_view assetHintOnlyTestAsset = R"( + { + "assetHint" : "test/path/foo.asset" + })"; + rapidjson::Document jsonDom; + jsonDom.Parse(assetHintOnlyTestAsset.data()); + + AZ::Data::Asset instance; + auto result = AZ::JsonSerialization::Load(instance, jsonDom, settings); + EXPECT_NE(result.GetProcessing(), AZ::JsonSerializationResult::Processing::Halted); + EXPECT_STREQ(instance.GetHint().c_str(), "passed"); + } + class AssetSerializerTestDescription final : public JsonSerializerConformityTestDescriptor> { From 5c859cb13493e0c4e42984099c342a7fb9c0b104 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Mon, 11 Oct 2021 16:23:24 +0100 Subject: [PATCH 174/293] Fix camera drift issues (#4576) * remove some unused code in RenderViewportWidget and make viewing devicePixelRatioF easier Signed-off-by: hultonha * updates to how cursor positions are calculate to handle the viewport widget moving Signed-off-by: hultonha * remove optional for previous position Signed-off-by: hultonha * add test to capture error with moving the widget Signed-off-by: hultonha * minor comment updates before publishing PR Signed-off-by: hultonha --- .../test_ModularViewportCameraController.cpp | 48 +++++++++++++++++++ .../Input/QtEventToAzInputManager.cpp | 20 ++++---- .../Input/QtEventToAzInputManager.h | 6 +-- .../Viewport/RenderViewportWidget.h | 15 +++--- .../Source/Viewport/RenderViewportWidget.cpp | 11 ++--- 5 files changed, 71 insertions(+), 29 deletions(-) diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index 157291cfc2..ea3653f663 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -69,6 +69,7 @@ namespace UnitTest m_rootWidget = AZStd::make_unique(); m_rootWidget->setFixedSize(WidgetSize); + m_rootWidget->move(0, 0); // explicitly set the widget to be in the upper left corner m_controllerList = AZStd::make_shared(); m_controllerList->RegisterViewportContext(TestViewportId); @@ -344,4 +345,51 @@ namespace UnitTest // Clean-up HaltCollaborators(); } + + // test to verify deltas and cursor positions are handled correctly when the widget is moved + TEST_F(ModularViewportCameraControllerFixture, CameraDoesNotStutterAfterWidgetIsMoved) + { + // Given + PrepareCollaborators(); + SandboxEditor::SetCameraCaptureCursorForLook(true); + + const float deltaTime = 1.0f / 60.0f; + + // When + // move cursor to the center of the screen + auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2); + MouseMove(m_rootWidget.get(), start, QPoint(0, 0)); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + + // move camera right + const auto mouseDelta = QPoint(200, 0); + MousePressAndMove(m_rootWidget.get(), start, mouseDelta, Qt::MouseButton::RightButton); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + + QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::RightButton, Qt::NoModifier, start + mouseDelta); + + // update the position of the widget + const auto offset = QPoint(500, 500); + m_rootWidget->move(offset); + + // move cursor back to widget center + MouseMove(m_rootWidget.get(), start, QPoint(0, 0)); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + + // move camera left + MousePressAndMove(m_rootWidget.get(), start, -mouseDelta, Qt::MouseButton::RightButton); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + + // Then + // ensure the camera rotation has returned to the identity + const AZ::Quaternion cameraRotation = m_cameraViewportContextView->GetCameraTransform().GetRotation(); + const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromQuaternion(cameraRotation)); + + using ::testing::FloatNear; + EXPECT_THAT(eulerAngles.GetX(), FloatNear(0.0f, 0.001f)); + EXPECT_THAT(eulerAngles.GetZ(), FloatNear(0.0f, 0.001f)); + + // Clean-up + HaltCollaborators(); + } } // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp index 5fcf7e11d3..18acccf049 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp @@ -261,10 +261,10 @@ namespace AzToolsFramework // ensures cursor positions are refreshed correctly with context menu focus changes) if (eventType == QEvent::FocusIn) { - const auto widgetCursorPosition = m_sourceWidget->mapFromGlobal(QCursor::pos()); - if (m_sourceWidget->geometry().contains(widgetCursorPosition)) + const auto globalCursorPosition = QCursor::pos(); + if (m_sourceWidget->geometry().contains(globalCursorPosition)) { - HandleMouseMoveEvent(widgetCursorPosition); + HandleMouseMoveEvent(globalCursorPosition); } } } @@ -290,7 +290,7 @@ namespace AzToolsFramework else if (eventType == QEvent::Type::MouseMove) { auto mouseEvent = static_cast(event); - HandleMouseMoveEvent(mouseEvent->pos()); + HandleMouseMoveEvent(mouseEvent->globalPos()); } // Map wheel events to the mouse Z movement channel. else if (eventType == QEvent::Type::Wheel) @@ -370,11 +370,12 @@ namespace AzToolsFramework return QPoint{ denormalizedX, denormalizedY }; } - void QtEventToAzInputMapper::HandleMouseMoveEvent(const QPoint& cursorPosition) + void QtEventToAzInputMapper::HandleMouseMoveEvent(const QPoint& globalCursorPosition) { - const QPoint cursorDelta = cursorPosition - m_previousCursorPosition; + const QPoint cursorDelta = globalCursorPosition - m_previousGlobalCursorPosition; - m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(cursorPosition); + m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = + WidgetPositionToNormalizedPosition(m_sourceWidget->mapFromGlobal(globalCursorPosition)); m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = WidgetPositionToNormalizedPosition(cursorDelta); ProcessPendingMouseEvents(cursorDelta); @@ -382,12 +383,11 @@ namespace AzToolsFramework if (m_capturingCursor) { // Reset our cursor position to the previous point - const QPoint screenCursorPosition = m_sourceWidget->mapToGlobal(m_previousCursorPosition); - AzQtComponents::SetCursorPos(screenCursorPosition); + AzQtComponents::SetCursorPos(m_previousGlobalCursorPosition); } else { - m_previousCursorPosition = cursorPosition; + m_previousGlobalCursorPosition = globalCursorPosition; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h index aaf3fb6295..5add24ad84 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h @@ -129,7 +129,7 @@ namespace AzToolsFramework // Handle mouse click events. void HandleMouseButtonEvent(QMouseEvent* mouseEvent); // Handle mouse move events. - void HandleMouseMoveEvent(const QPoint& cursorPosition); + void HandleMouseMoveEvent(const QPoint& globalCursorPosition); // Handles key press / release events (or ShortcutOverride events for keys listed in m_highPriorityKeys). void HandleKeyEvent(QKeyEvent* keyEvent); // Handles mouse wheel events. @@ -156,8 +156,8 @@ namespace AzToolsFramework AZStd::unordered_set m_highPriorityKeys; // A lookup table for AZ input channel ID -> physical input channel on our mouse or keyboard device. AZStd::unordered_map m_channels; - // Where the position of the mouse cursor was at the last cursor event. - QPoint m_previousCursorPosition; + // Where the mouse cursor was at the last cursor event. + QPoint m_previousGlobalCursorPosition; // The source widget to map events from, used to calculate the relative mouse position within the widget bounds. QWidget* m_sourceWidget; // Flags whether or not Qt events should currently be processed. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index 623d759c9f..b407aa2b4c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -90,7 +90,7 @@ namespace AtomToolsFramework //! Input processing is enabled by default. void SetInputProcessingEnabled(bool enabled); - // AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler ... + // AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler overrides ... AzFramework::CameraState GetCameraState() override; AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) override; AZStd::optional ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override; @@ -98,12 +98,12 @@ namespace AtomToolsFramework const AzFramework::ScreenPoint& screenPosition) override; float DeviceScalingFactor() override; - // AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler ... + // AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler overrides ... void BeginCursorCapture() override; void EndCursorCapture() override; bool IsMouseOver() const override; - // AzFramework::WindowRequestBus::Handler ... + // AzFramework::WindowRequestBus::Handler overrides ... void SetWindowTitle(const AZStd::string& title) override; AzFramework::WindowSize GetClientAreaSize() const override; void ResizeClientArea(AzFramework::WindowSize clientAreaSize) override; @@ -116,18 +116,17 @@ namespace AtomToolsFramework uint32_t GetDisplayRefreshRate() const override; protected: - // AzFramework::InputChannelEventListener ... + // AzFramework::InputChannelEventListener overrides ... bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; - // AZ::TickBus::Handler ... + // AZ::TickBus::Handler overrides ... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - // QWidget ... + // QWidget overrides ... void resizeEvent(QResizeEvent *event) override; bool event(QEvent* event) override; void enterEvent(QEvent* event) override; void leaveEvent(QEvent* event) override; - void mouseMoveEvent(QMouseEvent* event) override; private: void SendWindowResizeEvent(); @@ -143,8 +142,6 @@ namespace AtomToolsFramework AZ::RPI::AuxGeomDrawPtr m_auxGeom; // Tracks whether the cursor is currently over our viewport, used for mouse input event book-keeping. bool m_mouseOver = false; - // The last recorded mouse position, in local viewport screen coordinates. - QPointF m_mousePosition; // Captures the time between our render events to give controllers a time delta. QElapsedTimer m_renderTimer; // The time of the last recorded tick event from the system tick bus. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 7192afebf7..83926ecc79 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -214,20 +214,17 @@ namespace AtomToolsFramework m_mouseOver = false; } - void RenderViewportWidget::mouseMoveEvent(QMouseEvent* event) - { - m_mousePosition = event->localPos(); - } - void RenderViewportWidget::SendWindowResizeEvent() { // Scale the size by the DPI of the platform to // get the proper size in pixels. + const auto pixelRatio = devicePixelRatioF(); const QSize uiWindowSize = size(); - const QSize windowSize = uiWindowSize * devicePixelRatioF(); + const QSize windowSize = uiWindowSize * pixelRatio; const AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); - AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height()); + AzFramework::WindowNotificationBus::Event( + windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height()); } AZ::Name RenderViewportWidget::GetCurrentContextName() const From 189aa5f3acc225a66763cece9bd5efc8dea37228 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Mon, 11 Oct 2021 08:50:05 -0700 Subject: [PATCH 175/293] Disable the creation of the UserSettings.xml file in Xcb tests (#4593) Signed-off-by: Chris Burel --- .../Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp index 3abbcdc564..2b1f21ede7 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -196,6 +197,7 @@ namespace AzFramework Application application; application.Start({}, {}); + AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); const InputChannel* inputChannel = InputChannelRequests::FindInputChannel(InputDeviceKeyboard::Key::AlphanumericA); ASSERT_TRUE(inputChannel); @@ -420,6 +422,7 @@ namespace AzFramework Application application; application.Start({}, {}); + AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); for (int i = 0; i < 4; ++i) { From 091b729183fbcf7e0041aeb0b28cc8724d38e321 Mon Sep 17 00:00:00 2001 From: Tobias Alexander Franke Date: Mon, 11 Oct 2021 18:48:28 +0200 Subject: [PATCH 176/293] Do not run SSAO pass when disabled (#3826) * Define fallback slots when shader is disabled * Disable SSAO parent pass depending on the settings * Move SSAO modulation pass into SsaoParent pass so it can be disabled with the rest of SSAO * Enable SSAO by default Co-authored-by: Tobias Alexander Franke --- .../Common/Assets/Passes/OpaqueParent.pass | 29 ++------------- .../Common/Assets/Passes/SsaoCompute.pass | 8 +++- .../Common/Assets/Passes/SsaoParent.pass | 37 ++++++++++++++++++- .../Code/Source/PostProcessing/SsaoPasses.cpp | 27 +++++++++++++- 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass index f45f5c8b07..752d565234 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/OpaqueParent.pass @@ -472,36 +472,15 @@ "Pass": "Parent", "Attachment": "DepthLinear" } - } - ] - }, - { - "Name": "ModulateWithSsao", - "TemplateName": "ModulateTextureTemplate", - "Enabled": true, - "Connections": [ - { - "LocalSlot": "Input", - "AttachmentRef": { - "Pass": "Ssao", - "Attachment": "Output" - } }, { - "LocalSlot": "InputOutput", + "LocalSlot": "Modulate", "AttachmentRef": { "Pass": "SubsurfaceScatteringPass", "Attachment": "Output" } } - ], - "PassData": { - "$type": "ComputePassData", - "ShaderAsset": { - "FilePath": "Shaders/PostProcessing/ModulateTexture.shader" - }, - "Make Fullscreen Pass": true - } + ] }, { "Name": "DiffuseSpecularMergePass", @@ -510,8 +489,8 @@ { "LocalSlot": "InputDiffuse", "AttachmentRef": { - "Pass": "ModulateWithSsao", - "Attachment": "InputOutput" + "Pass": "Ssao", + "Attachment": "Output" } }, { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass b/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass index 034b4359b4..3c4a8c76f1 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass @@ -51,7 +51,13 @@ }, "Make Fullscreen Pass": true, "PipelineViewTag": "MainCamera" - } + }, + "FallbackConnections": [ + { + "Input": "LinearDepth", + "Output": "Output" + } + ] } } } diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SsaoParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/SsaoParent.pass index b94ca4ab38..111518706f 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/SsaoParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/SsaoParent.pass @@ -12,6 +12,11 @@ "SlotType": "Input", "ScopeAttachmentUsage": "Shader" }, + { + "Name": "Modulate", + "SlotType": "Input", + "ScopeAttachmentUsage": "Shader" + }, { "Name": "Output", "SlotType": "Output", @@ -22,8 +27,8 @@ { "LocalSlot": "Output", "AttachmentRef": { - "Pass": "Upsample", - "Attachment": "Output" + "Pass": "ModulateWithSsao", + "Attachment": "InputOutput" } } ], @@ -103,6 +108,34 @@ } } ] + }, + { + "Name": "ModulateWithSsao", + "TemplateName": "ModulateTextureTemplate", + "Enabled": true, + "Connections": [ + { + "LocalSlot": "Input", + "AttachmentRef": { + "Pass": "Upsample", + "Attachment": "Output" + } + }, + { + "LocalSlot": "InputOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "Modulate" + } + } + ], + "PassData": { + "$type": "ComputePassData", + "ShaderAsset": { + "FilePath": "Shaders/PostProcessing/ModulateTexture.shader" + }, + "Make Fullscreen Pass": true + } } ] } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp index 5e6d4b2ad9..15f7f52338 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SsaoPasses.cpp @@ -34,7 +34,32 @@ namespace AZ bool SsaoParentPass::IsEnabled() const { - return ParentPass::IsEnabled(); + if (!ParentPass::IsEnabled()) + { + return false; + } + const RPI::Scene* scene = GetScene(); + if (!scene) + { + return false; + } + PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor(); + const RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView(); + if (!fp) + { + return true; + } + PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view); + if (!postProcessSettings) + { + return true; + } + const SsaoSettings* ssaoSettings = postProcessSettings->GetSsaoSettings(); + if (!ssaoSettings) + { + return true; + } + return ssaoSettings->GetEnabled(); } void SsaoParentPass::InitializeInternal() From c759bc9cd02e5a05fc418728ef5d023f4c79ef91 Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Mon, 11 Oct 2021 10:52:00 -0700 Subject: [PATCH 177/293] Update the Jenkins script to disable access log during AWSI deployment (#4579) Signed-off-by: Junbo Liang --- scripts/build/Platform/Windows/deploy_cdk_applications.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd index 54a2485360..006e0158c0 100644 --- a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd +++ b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd @@ -57,7 +57,7 @@ IF ERRORLEVEL 1 ( exit /b 1 ) -CALL :DeployCDKApplication AWSCore --all "-c disable_access_log=true" +CALL :DeployCDKApplication AWSCore "-c disable_access_log=true --all" IF ERRORLEVEL 1 ( exit /b 1 ) From 45def7440986934ed8cea07db62306506c262ad8 Mon Sep 17 00:00:00 2001 From: sweeneys Date: Mon, 11 Oct 2021 11:11:40 -0700 Subject: [PATCH 178/293] Fix extension ignoring between Windows and Linux Signed-off-by: sweeneys --- .../environment/process_utils.py | 88 ++++++++++++------- Tools/LyTestTools/tests/integ/sanity_tests.py | 4 +- .../tests/unit/test_process_utils.py | 51 +++++++++-- 3 files changed, 101 insertions(+), 42 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py index 79fc4f420a..f8245495fa 100755 --- a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py +++ b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py @@ -31,45 +31,59 @@ def kill_processes_named(names, ignore_extensions=False): Kills all processes with a given name :param names: string process name, or list of strings of process name - :param ignore_extensions: ignore trailing file extension + :param ignore_extensions: ignore trailing file extensions. By default 'abc.exe' will not match 'abc'. Note that + enabling this will cause 'abc.exe' to match 'abc', 'abc.bat', and 'abc.sh', though 'abc.GameLauncher.exe' + will not match 'abc.DedicatedServer' """ if not names: return - names = [names] if isinstance(names, str) else names + name_set = set() + if isinstance(names, str): + name_set.add(names) + else: + name_set.update(names) if ignore_extensions: - names = [_remove_extension(name) for name in names] + # both exact matches and extensionless + stripped_names = set() + for name in name_set: + stripped_names.add(_remove_extension(name)) + name_set.update(stripped_names) # remove any blank names, which may empty the list - names = list(filter(lambda x: not x.isspace(), names)) - if not names: + name_set = set(filter(lambda x: not x.isspace(), name_set)) + if not name_set: return - logger.info(f"Killing all processes named {names}") - process_list_to_kill = [] + logger.info(f"Killing all processes named {name_set}") + process_set_to_kill = set() for process in _safe_get_processes(['name', 'pid']): try: proc_name = process.name() except psutil.AccessDenied: - logger.info(f"Process {process} permissions error during kill_processes_named()", exc_info=True) + logger.warning(f"Process {process} permissions error during kill_processes_named()", exc_info=True) continue except psutil.ProcessLookupError: - logger.debug(f"Process {process} could not be killed during kill_processes_named() and was likely already stopped", exc_info=True) + logger.debug(f"Process {process} could not be killed during kill_processes_named() and was likely already " + f"stopped", exc_info=True) continue except psutil.NoSuchProcess: logger.debug(f"Process '{process}' was active when list of processes was requested but it was not found " f"during kill_processes_named()", exc_info=True) continue - if ignore_extensions: - proc_name = _remove_extension(proc_name) + if proc_name in name_set: + logger.debug(f"Found process with name {proc_name}.") + process_set_to_kill.add(process) - if proc_name in names: - logger.debug(f"Found process with name {proc_name}. Attempting to kill...") - process_list_to_kill.append(process) + if ignore_extensions: + extensionless_name = _remove_extension(proc_name) + if extensionless_name in name_set: + process_set_to_kill.add(process) - _safe_kill_process_list(process_list_to_kill) + if process_set_to_kill: + _safe_kill_processes(process_set_to_kill) def kill_processes_started_from(path): @@ -90,7 +104,7 @@ def kill_processes_started_from(path): if process_path.lower().startswith(path.lower()): process_list.append(process) - _safe_kill_process_list(process_list) + _safe_kill_processes(process_list) else: logger.warning(f"Path:'{path}' not found") @@ -118,7 +132,7 @@ def kill_processes_with_name_not_started_from(name, path): logger.info("%s -> %s" % (os.path.dirname(process_path.lower()), path)) proccesses_to_kill.append(process) - _safe_kill_process_list(proccesses_to_kill) + _safe_kill_processes(proccesses_to_kill) else: logger.warning(f"Path:'{path}' not found") @@ -151,10 +165,12 @@ def process_exists(name, ignore_extensions=False): :return: A boolean determining whether the process is alive or not """ name = name.lower() - if ignore_extensions: - name = _remove_extension(name) if name.isspace(): return False + + if ignore_extensions: + name_extensionless = _remove_extension(name) + for process in _safe_get_processes(["name"]): try: proc_name = process.name().lower() @@ -165,10 +181,17 @@ def process_exists(name, ignore_extensions=False): except psutil.AccessDenied as e: logger.info(f"Permissions issue on {process} during process_exists check", exc_info=True) continue - if ignore_extensions: - proc_name = _remove_extension(proc_name) - if proc_name == name: + + if proc_name == name: # abc.exe matches abc.exe return True + if ignore_extensions: + proc_name_extensionless = _remove_extension(proc_name) + if proc_name_extensionless == name: # abc matches abc.exe + return True + if proc_name == name_extensionless: # abc.exe matches abc + return True + # don't check proc_name_extensionless against name_extensionless: abc.exe and abc.exe are already tested, + # however xyz.Gamelauncher should not match xyz.DedicatedServer return False @@ -341,17 +364,14 @@ def _safe_kill_process(proc): except Exception: # purposefully broad logger.warning("Unexpected exception while terminating process", exc_info=True) -def _safe_kill_process_list(proc_list): + +def _safe_kill_processes(processes): """ Kills a given process without raising an error - :param proc_list: The process list to kill + :param processes: An iterable of processes to kill """ - - def on_terminate(proc): - print(f"process '{proc.name()}' with id '{proc.pid}' terminated with exit code {proc.returncode}") - - for proc in proc_list: + for proc in processes: try: logger.info(f"Terminating process '{proc.name()}' with id '{proc.pid}'") proc.kill() @@ -360,12 +380,14 @@ def _safe_kill_process_list(proc_list): except psutil.NoSuchProcess: logger.debug("Termination request ignored, process was already terminated during iteration", exc_info=True) except Exception: # purposefully broad - logger.warning("Unexpected exception while terminating process", exc_info=True) + logger.warning("Unexpected exception ignored while terminating process", exc_info=True) + def on_terminate(proc): + logger.info(f"process '{proc.name()}' with id '{proc.pid}' terminated with exit code {proc.returncode}") try: - psutil.wait_procs(proc_list, timeout=30, callback=on_terminate) + psutil.wait_procs(processes, timeout=30, callback=on_terminate) except Exception: # purposefully broad - logger.warning("Unexpected exception while waiting for process to terminate", exc_info=True) + logger.warning("Unexpected exception while waiting for processes to terminate", exc_info=True) def _terminate_and_confirm_dead(proc): @@ -383,7 +405,7 @@ def _terminate_and_confirm_dead(proc): def _remove_extension(filename): """ - Returns a file name without its extension + Returns a file name without its extension, if any is present :param filename: The name of a file :return: The name of the file without the extension diff --git a/Tools/LyTestTools/tests/integ/sanity_tests.py b/Tools/LyTestTools/tests/integ/sanity_tests.py index ed77d7b8db..2e46d822c7 100755 --- a/Tools/LyTestTools/tests/integ/sanity_tests.py +++ b/Tools/LyTestTools/tests/integ/sanity_tests.py @@ -58,7 +58,7 @@ class TestAutomatedTestingProject(object): # Call the game client executable with launcher.start(): # Wait for the process to exist - waiter.wait_for(lambda: process_utils.process_exists(f"{project}.GameLauncher", ignore_extensions=True)) + waiter.wait_for(lambda: process_utils.process_exists(f"{project}.GameLauncher.exe", ignore_extensions=True)) finally: # Clean up processes after the test is finished process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True) @@ -85,7 +85,7 @@ class TestAutomatedTestingProject(object): # Call the Editor executable with editor.start(): # Wait for the process to exist - waiter.wait_for(lambda: process_utils.process_exists("Editor", ignore_extensions=True)) + waiter.wait_for(lambda: process_utils.process_exists("Editor.exe", ignore_extensions=True)) finally: # Clean up processes after the test is finished process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True) diff --git a/Tools/LyTestTools/tests/unit/test_process_utils.py b/Tools/LyTestTools/tests/unit/test_process_utils.py index de40fb8e34..bd6a79fb09 100755 --- a/Tools/LyTestTools/tests/unit/test_process_utils.py +++ b/Tools/LyTestTools/tests/unit/test_process_utils.py @@ -223,7 +223,7 @@ class TestCloseWindowsProcess(unittest.TestCase): mock_enum.assert_called_once() -class Test(unittest.TestCase): +class TestProcessMatching(unittest.TestCase): @mock.patch("ly_test_tools.environment.process_utils._safe_get_processes") def test_ProcExists_HasExtension_Found(self, mock_get_proc): @@ -261,18 +261,55 @@ class Test(unittest.TestCase): self.assertTrue(result) proc_mock.name.assert_called() - @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock) + @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes') @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes') - def test_KillProcNamed_MockKill_SilentSuccess(self, mock_get_proc): + def test_KillProcNamed_ExactMatch_Killed(self, mock_get_proc, mock_kill_proc): + name = "dummy.exe" + proc_mock = mock.MagicMock() + proc_mock.name.return_value = name + mock_get_proc.return_value = [proc_mock] + + process_utils.kill_processes_named("dummy.exe", ignore_extensions=False) + mock_kill_proc.assert_called() + proc_mock.name.assert_called() + + @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes') + @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes') + def test_KillProcNamed_NearMatch_Ignore(self, mock_get_proc, mock_kill_proc): + name = "dummy.exe" + proc_mock = mock.MagicMock() + proc_mock.name.return_value = name + mock_get_proc.return_value = [proc_mock] + + process_utils.kill_processes_named("dummy", ignore_extensions=False) + mock_kill_proc.assert_not_called() + proc_mock.name.assert_called() + + @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes') + @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes') + def test_KillProcNamed_NearMatchIgnoreExtension_Kill(self, mock_get_proc, mock_kill_proc): name = "dummy.exe" proc_mock = mock.MagicMock() proc_mock.name.return_value = name mock_get_proc.return_value = [proc_mock] process_utils.kill_processes_named("dummy", ignore_extensions=True) + mock_kill_proc.assert_called() + proc_mock.name.assert_called() + + @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes') + @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes') + def test_KillProcNamed_ExactMatchIgnoreExtension_Killed(self, mock_get_proc, mock_kill_proc): + name = "dummy.exe" + proc_mock = mock.MagicMock() + proc_mock.name.return_value = name + mock_get_proc.return_value = [proc_mock] + + process_utils.kill_processes_named("dummy.exe", ignore_extensions=True) + mock_kill_proc.assert_called() proc_mock.name.assert_called() - @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock) + @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes', mock.MagicMock) @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes') @mock.patch('os.path.exists') def test_KillProcFrom_MockKill_SilentSuccess(self, mock_path, mock_get_proc): @@ -293,7 +330,7 @@ class Test(unittest.TestCase): mock_kill.assert_called() - @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock) + @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes', mock.MagicMock) @mock.patch('psutil.Process') def test_KillProcPid_NoProc_SilentPass(self, mock_psutil): mock_proc = mock.MagicMock() @@ -302,7 +339,7 @@ class Test(unittest.TestCase): process_utils.kill_process_with_pid(1) - @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock) + @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes', mock.MagicMock) @mock.patch('psutil.Process') def test_KillProcPidRaiseOnMissing_NoProc_Raises(self, mock_psutil): mock_proc = mock.MagicMock() @@ -339,7 +376,7 @@ class Test(unittest.TestCase): mock_wait_procs.side_effect = psutil.PermissionError() proc_mock = mock.MagicMock() - process_utils._safe_kill_process_list(proc_mock) + process_utils._safe_kill_processes(proc_mock) mock_wait_procs.assert_called() mock_log_warn.assert_called() From ef3470b0a91c1f0f11becc6dcad487d07addb2b1 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 11 Oct 2021 12:04:44 -0700 Subject: [PATCH 179/293] Dependency confirmation screen and URL display fix Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Resources/ProjectManager.qss | 23 +++- .../Source/CreateProjectCtrl.cpp | 6 +- .../Source/GemCatalog/GemCatalogScreen.cpp | 27 +++-- .../Source/GemCatalog/GemCatalogScreen.h | 9 +- .../GemCatalog/GemDependenciesDialog.cpp | 80 ++++++++++++++ .../Source/GemCatalog/GemDependenciesDialog.h | 27 +++++ .../Source/GemCatalog/GemItemDelegate.cpp | 102 +++++++++++++++--- .../Source/GemCatalog/GemItemDelegate.h | 3 + .../Source/GemCatalog/GemListView.cpp | 21 ---- .../Source/GemCatalog/GemModel.cpp | 14 +++ .../Source/GemCatalog/GemModel.h | 1 + .../GemCatalog/GemRequirementDelegate.cpp | 47 ++++++-- .../GemCatalog/GemRequirementDelegate.h | 3 + .../GemCatalog/GemRequirementDialog.cpp | 29 ++--- .../Source/GemCatalog/GemRequirementDialog.h | 12 +-- .../GemRequirementFilterProxyModel.cpp | 21 +--- .../GemRequirementFilterProxyModel.h | 5 +- .../GemCatalog/GemRequirementListView.cpp | 1 - .../Tools/ProjectManager/Source/TagWidget.cpp | 79 ++++---------- Code/Tools/ProjectManager/Source/TagWidget.h | 6 -- .../Source/UpdateProjectCtrl.cpp | 6 +- .../project_manager_files.cmake | 2 + 22 files changed, 341 insertions(+), 183 deletions(-) create mode 100644 Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.cpp create mode 100644 Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.h diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index f91a597481..5f7826dbac 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -496,13 +496,34 @@ QProgressBar::chunk { background-color: #333333; } -/************** Filter tag widget **************/ +#GemDependenciesDialog QLabel { + margin-bottom:10px; +} + +#GemDependenciesDialog QCheckBox { + background-color: #333333; + border-radius: 3px; + spacing:3px; + margin-right:5px; + padding:4px; + margin-top:5px; +} + +/************** Filter Tag widget **************/ #FilterTagWidgetTextLabel { color: #94D2FF; font-size: 10px; } +#TagWidget { + background-color: #333333; + padding:3px; + font-size:12px; + border-radius: 3px; + margin-right: 3px; +} + /************** Gems SubWidget **************/ #gemSubWidgetTitleLabel { diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index f098518fd3..84b931cb30 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -238,9 +238,13 @@ namespace O3DE::ProjectManager PythonBindingsInterface::Get()->AddProject(projectInfo.m_path); #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED - if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path)) + const GemCatalogScreen::EnableDisableGemsResult gemResult = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path); + if (gemResult == GemCatalogScreen::EnableDisableGemsResult::Failed) { QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template.")); + } + if (gemResult != GemCatalogScreen::EnableDisableGemsResult::Success) + { return; } #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index a41a81b448..945878768d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -134,7 +135,7 @@ namespace O3DE::ProjectManager } } - bool GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath) + GemCatalogScreen::EnableDisableGemsResult GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath) { IPythonBindings* pythonBindings = PythonBindingsInterface::Get(); QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); @@ -142,13 +143,23 @@ namespace O3DE::ProjectManager if (m_gemModel->DoGemsToBeAddedHaveRequirements()) { - GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, toBeAdded, this); - confirmRequirementsDialog->exec(); + GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, this); + if(confirmRequirementsDialog->exec() == QDialog::Rejected) + { + return EnableDisableGemsResult::Cancel; + } + } - if (confirmRequirementsDialog->GetButtonResult() != QDialogButtonBox::ApplyRole) + if (m_gemModel->HasDependentGemsToRemove()) + { + GemDependenciesDialog* dependenciesDialog = new GemDependenciesDialog(m_gemModel, this); + if(dependenciesDialog->exec() == QDialog::Rejected) { - return false; + return EnableDisableGemsResult::Cancel; } + + toBeAdded = m_gemModel->GatherGemsToBeAdded(); + toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); } for (const QModelIndex& modelIndex : toBeAdded) @@ -160,7 +171,7 @@ namespace O3DE::ProjectManager QMessageBox::critical(nullptr, "Operation failed", QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); - return false; + return EnableDisableGemsResult::Failed; } } @@ -173,11 +184,11 @@ namespace O3DE::ProjectManager QMessageBox::critical(nullptr, "Operation failed", QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); - return false; + return EnableDisableGemsResult::Failed; } } - return true; + return EnableDisableGemsResult::Success; } ProjectManagerScreen GemCatalogScreen::GetScreenEnum() diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 5b48b2f90e..72e8d44f65 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -29,7 +29,14 @@ namespace O3DE::ProjectManager ProjectManagerScreen GetScreenEnum() override; void ReinitForProject(const QString& projectPath); - bool EnableDisableGemsForProject(const QString& projectPath); + + enum class EnableDisableGemsResult + { + Failed = 0, + Success, + Cancel + }; + EnableDisableGemsResult EnableDisableGemsForProject(const QString& projectPath); GemModel* GetGemModel() const { return m_gemModel; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.cpp new file mode 100644 index 0000000000..98aebd8fab --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + GemDependenciesDialog::GemDependenciesDialog(GemModel* gemModel, QWidget *parent) + : QDialog(parent) + { + setWindowTitle(tr("Dependent Gems")); + setObjectName("GemDependenciesDialog"); + setAttribute(Qt::WA_DeleteOnClose); + setModal(true); + + QVBoxLayout* layout = new QVBoxLayout(); + // layout margin/alignment cannot be set with qss + layout->setMargin(15); + layout->setAlignment(Qt::AlignTop); + setLayout(layout); + + // message + QLabel* instructionLabel = new QLabel( + tr("The following gem dependencies are no longer needed and will be deactivated.

" + "To keep these Gems enabled, select the checkbox next to it.")); + layout->addWidget(instructionLabel); + + // checkboxes + FlowLayout* flowLayout = new FlowLayout(); + QVector gemsToRemove = gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true); + for (const QModelIndex& gem : gemsToRemove) + { + if (GemModel::WasPreviouslyAddedDependency(gem)) + { + QCheckBox* checkBox = new QCheckBox(GemModel::GetName(gem)); + connect(checkBox, &QCheckBox::stateChanged, this, + [=](int state) + { + GemModel::SetIsAdded(*gemModel, gem, /*isAdded=*/state == Qt::Checked); + }); + flowLayout->addWidget(checkBox); + } + } + layout->addLayout(flowLayout); + + layout->addSpacing(10); + layout->addStretch(1); + + // buttons + QDialogButtonBox* dialogButtons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); + connect(dialogButtons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(dialogButtons, &QDialogButtonBox::rejected, this, + [=]() + { + // de-select any Gems the user selected because they're canceling + for (const QModelIndex& gem : gemsToRemove) + { + if (GemModel::WasPreviouslyAddedDependency(gem) && GemModel::IsAdded(gem)) + { + GemModel::SetIsAdded(*gemModel, gem, /*isAdded=*/false); + } + } + + reject(); + }); + layout->addWidget(dialogButtons); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.h new file mode 100644 index 0000000000..df8ca6f8a2 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + QT_FORWARD_DECLARE_CLASS(GemModel) + + class GemDependenciesDialog + : public QDialog + { + Q_OBJECT // AUTOMOC + public: + explicit GemDependenciesDialog(GemModel* gemModel, QWidget *parent = nullptr); + ~GemDependenciesDialog() = default; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index dc24c13009..2c7f17db32 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,9 @@ #include #include #include +#include +#include +#include namespace O3DE::ProjectManager { @@ -104,22 +108,11 @@ namespace O3DE::ProjectManager painter->drawText(gemCreatorRect, Qt::TextSingleLine, gemCreator); // Gem summary - - // In case there are feature tags displayed at the bottom, decrease the size of the summary text field. const QStringList featureTags = GemModel::GetFeatures(modelIndex); - const int featureTagAreaHeight = 30; - const int summaryHeight = contentRect.height() - (!featureTags.empty() * featureTagAreaHeight); - - const int additionalSummarySpacing = s_itemMargins.right() * 3; - const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing, - summaryHeight); - const QRect summaryRect = QRect(/*topLeft=*/QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize); - - painter->setFont(standardFont); - painter->setPen(m_textColor); - + const bool hasTags = !featureTags.isEmpty(); const QString summary = GemModel::GetSummary(modelIndex); - painter->drawText(summaryRect, Qt::AlignLeft | Qt::TextWordWrap, summary); + const QRect summaryRect = CalcSummaryRect(contentRect, hasTags); + DrawText(summary, painter, summaryRect, standardFont); DrawButton(painter, contentRect, modelIndex); DrawPlatformIcons(painter, contentRect, modelIndex); @@ -128,6 +121,17 @@ namespace O3DE::ProjectManager painter->restore(); } + QRect GemItemDelegate::CalcSummaryRect(const QRect& contentRect, bool hasTags) const + { + const int featureTagAreaHeight = 30; + const int summaryHeight = contentRect.height() - (hasTags * featureTagAreaHeight); + + const int additionalSummarySpacing = s_itemMargins.right() * 3; + const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing, + summaryHeight); + return QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize); + } + QSize GemItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const { QStyleOptionViewItem options(option); @@ -154,7 +158,7 @@ namespace O3DE::ProjectManager return true; } } - else if (event->type() == QEvent::MouseButtonPress ) + else if (event->type() == QEvent::MouseButtonPress) { QMouseEvent* mouseEvent = static_cast(event); @@ -168,6 +172,21 @@ namespace O3DE::ProjectManager GemModel::SetIsAdded(*model, modelIndex, !isAdded); return true; } + + // we must manually handle html links because we aren't using QLabels + const QStringList featureTags = GemModel::GetFeatures(modelIndex); + const bool hasTags = !featureTags.isEmpty(); + const QRect summaryRect = CalcSummaryRect(contentRect, hasTags); + if (summaryRect.contains(mouseEvent->pos())) + { + const QString html = GemModel::GetSummary(modelIndex); + QString anchor = anchorAt(html, mouseEvent->pos(), summaryRect); + if (!anchor.isEmpty()) + { + QDesktopServices::openUrl(QUrl(anchor)); + return true; + } + } } return QStyledItemDelegate::editorEvent(event, model, option, modelIndex); @@ -321,6 +340,44 @@ namespace O3DE::ProjectManager } } + AZStd::unique_ptr GetTextDocument(const QString& text, int width) + { + // using unique_ptr as a workaround for QTextDocument having a private copy constructor + auto doc = AZStd::make_unique(); + QTextOption textOption(doc->defaultTextOption()); + textOption.setWrapMode(QTextOption::WordWrap); + doc->setDefaultTextOption(textOption); + doc->setHtml(text); + doc->setTextWidth(width); + return doc; + } + + void GemItemDelegate::DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const + { + painter->save(); + + if (text.contains('<')) + { + painter->translate(rect.topLeft()); + + // use QTextDocument because drawText does not support rich text or html + QAbstractTextDocumentLayout::PaintContext paintContext; + paintContext.clip = QRect(0, 0, rect.width(), rect.height()); + paintContext.palette.setColor(QPalette::Text, painter->pen().color()); + + AZStd::unique_ptr textDocument = GetTextDocument(text, rect.width()); + textDocument->documentLayout()->draw(painter, paintContext); + } + else + { + painter->setFont(standardFont); + painter->setPen(m_textColor); + painter->drawText(rect, Qt::AlignLeft | Qt::TextWordWrap, text); + } + + painter->restore(); + } + void GemItemDelegate::DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const { painter->save(); @@ -355,4 +412,19 @@ namespace O3DE::ProjectManager painter->restore(); } + + QString GemItemDelegate::anchorAt(const QString& html, const QPoint& position, const QRect& rect) + { + if (!html.isEmpty()) + { + AZStd::unique_ptr doc = GetTextDocument(html, rect.width()); + QAbstractTextDocumentLayout* layout = doc->documentLayout(); + if (layout) + { + return layout->anchorAt(position - rect.topLeft()); + } + } + + return QString(); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h index d842f63ae7..52b5a4f58e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h @@ -30,6 +30,7 @@ namespace O3DE::ProjectManager void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; + virtual QString anchorAt(const QString& html, const QPoint& position, const QRect& rect); // Colors const QColor m_textColor = QColor("#FFFFFF"); @@ -71,9 +72,11 @@ namespace O3DE::ProjectManager void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const; QRect CalcButtonRect(const QRect& contentRect) const; + QRect CalcSummaryRect(const QRect& contentRect, bool hasTags) const; void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; void DrawFeatureTags(QPainter* painter, const QRect& contentRect, const QStringList& featureTags, const QFont& standardFont, const QRect& summaryRect) const; + void DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const; QAbstractItemModel* m_model = nullptr; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp index afdb9697c9..f5b54a364b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp @@ -8,27 +8,9 @@ #include #include -#include -#include namespace O3DE::ProjectManager { - class GemListViewProxyStyle : public QProxyStyle - { - public: - using QProxyStyle::QProxyStyle; - int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override - { - if (hint == QStyle::SH_ToolTip_WakeUpDelay || hint == QStyle::SH_ToolTip_FallAsleepDelay) - { - // no delay - return 0; - } - - return QProxyStyle::styleHint(hint, option, widget, returnData); - } - }; - GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent) : QListView(parent) { @@ -38,8 +20,5 @@ namespace O3DE::ProjectManager setModel(model); setSelectionModel(selectionModel); setItemDelegate(new GemItemDelegate(model, this)); - - // use a custom proxy style so we get immediate tooltips for gem radio buttons - setStyle(new GemListViewProxyStyle(this->style())); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 0941541793..c8911de360 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -391,6 +391,20 @@ namespace O3DE::ProjectManager return false; } + bool GemModel::HasDependentGemsToRemove() const + { + for (int row = 0; row < rowCount(); ++row) + { + const QModelIndex modelIndex = index(row, 0); + if (GemModel::NeedsToBeRemoved(modelIndex, /*includeDependencies=*/true) && + GemModel::WasPreviouslyAddedDependency(modelIndex)) + { + return true; + } + } + return false; + } + QVector GemModel::GatherGemDependencies(const QModelIndex& modelIndex) const { QVector result; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 0591094c11..ef2d1a903d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -66,6 +66,7 @@ namespace O3DE::ProjectManager static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex); bool DoGemsToBeAddedHaveRequirements() const; + bool HasDependentGemsToRemove() const; QVector GatherGemDependencies(const QModelIndex& modelIndex) const; QVector GatherDependentGems(const QModelIndex& modelIndex, bool addedOnly = false) const; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp index 0ca5ca836f..f4a7148d46 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include namespace O3DE::ProjectManager { @@ -38,7 +40,6 @@ namespace O3DE::ProjectManager standardFont.setPixelSize(static_cast(s_fontSize)); QFontMetrics standardFontMetrics(standardFont); - painter->save(); painter->setClipping(true); painter->setClipRect(fullRect); painter->setFont(options.font); @@ -65,25 +66,51 @@ namespace O3DE::ProjectManager painter->drawText(gemNameRect, Qt::TextSingleLine, gemName); // Gem requirement - const QSize requirementSize = QSize(contentRect.width() - s_summaryStartX - s_itemMargins.right(), contentRect.height()); - const QRect requirementRect = QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), requirementSize); - - painter->setFont(standardFont); - painter->setPen(m_textColor); - + const QRect requirementRect = CalcRequirementRect(contentRect); const QString requirement = GemModel::GetRequirement(modelIndex); - painter->drawText(requirementRect, Qt::AlignLeft | Qt::TextWordWrap, requirement); + DrawText(requirement, painter, requirementRect, standardFont); painter->restore(); } + QRect GemRequirementDelegate::CalcRequirementRect(const QRect& contentRect) const + { + const QSize requirementSize = QSize(contentRect.width() - s_summaryStartX - s_itemMargins.right(), contentRect.height()); + return QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), requirementSize); + } + bool GemRequirementDelegate::editorEvent( [[maybe_unused]] QEvent* event, [[maybe_unused]] QAbstractItemModel* model, [[maybe_unused]] const QStyleOptionViewItem& option, [[maybe_unused]] const QModelIndex& modelIndex) { - // Do nothing here - return false; + if (!modelIndex.isValid()) + { + return false; + } + + if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* mouseEvent = static_cast(event); + + QRect fullRect, itemRect, contentRect; + CalcRects(option, fullRect, itemRect, contentRect); + + const QRect requirementsRect = CalcRequirementRect(contentRect); + if (requirementsRect.contains(mouseEvent->pos())) + { + const QString html = GemModel::GetRequirement(modelIndex); + QString anchor = anchorAt(html, mouseEvent->pos(), requirementsRect); + if (!anchor.isEmpty()) + { + QDesktopServices::openUrl(QUrl(anchor)); + return true; + } + } + } + + return QStyledItemDelegate::editorEvent(event, model, option, modelIndex); } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h index a23b999ca0..e9001df7fa 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h @@ -29,5 +29,8 @@ namespace O3DE::ProjectManager const QColor m_backgroundColor = QColor("#444444"); // Outside of the actual gem item const QColor m_itemBackgroundColor = QColor("#393939"); // Background color of the gem item + + private: + QRect CalcRequirementRect(const QRect& contentRect) const; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp index 4740d29344..23bb776c29 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp @@ -19,11 +19,12 @@ namespace O3DE::ProjectManager { - GemRequirementDialog::GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, QWidget* parent) + GemRequirementDialog::GemRequirementDialog(GemModel* model, QWidget* parent) : QDialog(parent) { setWindowTitle(tr("Manual setup is required")); setModal(true); + setAttribute(Qt::WA_DeleteOnClose); QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); @@ -51,7 +52,7 @@ namespace O3DE::ProjectManager vLayout->addSpacing(20); - GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, gemsToAdd, this); + GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, this); GemRequirementListView* m_gemListView = new GemRequirementListView(proxModel, proxModel->GetSelectionModel(), this); vLayout->addWidget(m_gemListView); @@ -62,27 +63,9 @@ namespace O3DE::ProjectManager QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); cancelButton->setProperty("secondary", true); - QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::ApplyRole); + QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::AcceptRole); - connect(cancelButton, &QPushButton::clicked, this, &GemRequirementDialog::CancelButtonPressed); - connect(continueButton, &QPushButton::clicked, this, &GemRequirementDialog::ContinueButtonPressed); + connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject); + connect(continueButton, &QPushButton::clicked, this, &QDialog::accept); } - - QDialogButtonBox::ButtonRole GemRequirementDialog::GetButtonResult() - { - return m_buttonResult; - } - - void GemRequirementDialog::CancelButtonPressed() - { - m_buttonResult = QDialogButtonBox::RejectRole; - close(); - } - - void GemRequirementDialog::ContinueButtonPressed() - { - m_buttonResult = QDialogButtonBox::ApplyRole; - close(); - } - } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h index 22f6977332..af8b1e2cc9 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h @@ -10,8 +10,6 @@ #if !defined(Q_MOC_RUN) #include - -#include #endif namespace O3DE::ProjectManager @@ -23,15 +21,7 @@ namespace O3DE::ProjectManager { Q_OBJECT // AUTOMOC public: - explicit GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, QWidget *parent = nullptr); + explicit GemRequirementDialog(GemModel* model, QWidget *parent = nullptr); ~GemRequirementDialog() = default; - - QDialogButtonBox::ButtonRole GetButtonResult(); - - private: - void CancelButtonPressed(); - void ContinueButtonPressed(); - - QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp index 50639b7936..e89de82c6c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp @@ -13,10 +13,8 @@ namespace O3DE::ProjectManager { - GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, QObject* parent) + GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, QObject* parent) : QSortFilterProxyModel(parent) - , m_sourceModel(sourceModel) - , m_addedGems(addedGems) { setSourceModel(sourceModel); m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent); @@ -26,22 +24,7 @@ namespace O3DE::ProjectManager { // Do not use sourceParent->child because an invalid parent does not produce valid children (which our index function does) QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); - if (!sourceIndex.isValid()) - { - return false; - } - - if (!m_addedGems.contains(sourceIndex)) - { - return false; - } - - if (!m_sourceModel->HasRequirement(sourceIndex)) - { - return false; - } - - return true; + return GemModel::IsAdded(sourceIndex) && GemModel::HasRequirement(sourceIndex); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h index a40eed9fb4..7df75f7d94 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h @@ -25,16 +25,13 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, QObject* parent = nullptr); + GemRequirementFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr); AzQtComponents::SelectionProxyModel* GetSelectionModel() const { return m_selectionProxyModel; } bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; private: - GemModel* m_sourceModel = nullptr; AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr; - - QVector m_addedGems; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp index daed5764ff..fd7d22cbfc 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp @@ -8,7 +8,6 @@ #include #include -#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/TagWidget.cpp b/Code/Tools/ProjectManager/Source/TagWidget.cpp index 8f433f420f..ace9d72d8f 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.cpp +++ b/Code/Tools/ProjectManager/Source/TagWidget.cpp @@ -8,87 +8,44 @@ #include #include +#include namespace O3DE::ProjectManager { TagWidget::TagWidget(const QString& text, QWidget* parent) : QLabel(text, parent) { - setFixedHeight(24); - setMargin(5); - setStyleSheet("font-size: 12px; background-color: #333333; border-radius: 3px;"); + setObjectName("TagWidget"); } TagContainerWidget::TagContainerWidget(QWidget* parent) : QWidget(parent) { - m_layout = new QVBoxLayout(); - m_layout->setAlignment(Qt::AlignTop); - m_layout->setMargin(0); - setLayout(m_layout); + setObjectName("TagWidgetContainer"); + setLayout(new FlowLayout(this)); + + // layout margins cannot be set via qss + constexpr int verticalMargin = 10; + constexpr int horizontalMargin = 0; + layout()->setContentsMargins(horizontalMargin, verticalMargin, horizontalMargin, verticalMargin); + + setAttribute(Qt::WA_StyledBackground, true); } void TagContainerWidget::Update(const QStringList& tags) { - QWidget* parentWidget = qobject_cast(parent()); - int width = 200; - if (parentWidget) - { - width = parentWidget->width(); - } + FlowLayout* flowLayout = static_cast(layout()); - if (m_widget) + // remove old tags + QLayoutItem* layoutItem = nullptr; + while ((layoutItem = layout()->takeAt(0)) != nullptr) { - // Hide the old widget and request deletion. - m_widget->hide(); - m_widget->deleteLater(); + layoutItem->widget()->deleteLater(); } - QVBoxLayout* vLayout = new QVBoxLayout(); - m_widget = new QWidget(this); - m_widget->setLayout(vLayout); - m_layout->addWidget(m_widget); - - vLayout->setAlignment(Qt::AlignTop); - vLayout->setMargin(0); - - QHBoxLayout* hLayout = nullptr; - int usedSpaceInRow = 0; - const int numTags = tags.count(); - - for (int i = 0; i < numTags; ++i) + foreach (const QString& tag, tags) { - // Create the new tag widget. - TagWidget* tagWidget = new TagWidget(tags[i]); - const int tagWidgetWidth = tagWidget->minimumSizeHint().width(); - - // Calculate the width we're currently using in the current row. Does the new tag still fit in the current row? - const bool isRowFull = width - usedSpaceInRow - tagWidgetWidth < 0; - if (isRowFull || i == 0) - { - // Add a spacer widget after the last tag widget in a row to push the tag widgets to the left. - if (i > 0) - { - QWidget* spacerWidget = new QWidget(); - spacerWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - hLayout->addWidget(spacerWidget); - } - - // Add a new row for the current tag widget. - hLayout = new QHBoxLayout(); - hLayout->setAlignment(Qt::AlignLeft); - hLayout->setMargin(0); - vLayout->addLayout(hLayout); - - // Reset the used space in the row. - usedSpaceInRow = 0; - } - - // Calculate the width of the tag widgets including the spacing between them of the current row. - usedSpaceInRow += tagWidgetWidth + hLayout->spacing(); - - // Add the tag widget to the current row. - hLayout->addWidget(tagWidget); + flowLayout->addWidget(new TagWidget(tag)); } } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/TagWidget.h b/Code/Tools/ProjectManager/Source/TagWidget.h index 16eca28fc1..0dad7468eb 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.h +++ b/Code/Tools/ProjectManager/Source/TagWidget.h @@ -14,8 +14,6 @@ #include #endif -QT_FORWARD_DECLARE_CLASS(QVBoxLayout) - namespace O3DE::ProjectManager { // Single tag @@ -40,9 +38,5 @@ namespace O3DE::ProjectManager ~TagContainerWidget() = default; void Update(const QStringList& tags); - - private: - QVBoxLayout* m_layout = nullptr; - QWidget* m_widget = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 08ad7f24d9..e952ada57a 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -137,9 +137,13 @@ namespace O3DE::ProjectManager else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen) { // Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project. - if (!m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path)) + const GemCatalogScreen::EnableDisableGemsResult result = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path); + if (result == GemCatalogScreen::EnableDisableGemsResult::Failed) { QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for project.")); + } + if (result != GemCatalogScreen::EnableDisableGemsResult::Success) + { return; } diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 544fa2537b..fd8389ca4f 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -92,6 +92,8 @@ set(FILES Source/GemCatalog/GemListHeaderWidget.cpp Source/GemCatalog/GemModel.h Source/GemCatalog/GemModel.cpp + Source/GemCatalog/GemDependenciesDialog.h + Source/GemCatalog/GemDependenciesDialog.cpp Source/GemCatalog/GemRequirementDialog.h Source/GemCatalog/GemRequirementDialog.cpp Source/GemCatalog/GemRequirementDelegate.h From 56de6064d2fa7755b9c34335d9a14f1afd934c08 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 11 Oct 2021 12:07:04 -0700 Subject: [PATCH 180/293] Hopefully final pass on PR comments Signed-off-by: nggieber --- scripts/o3de/o3de/manifest.py | 43 ++++++++++++----------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index c5f6315474..b665727a4e 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -422,7 +422,7 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa return list(filter(filter_project_and_gem_templates_out, get_all_templates())) def get_json_file_path(object_typename: str, - object_path: str or pathlib.Path = None) -> pathlib.Path: + object_path: str or pathlib.Path) -> pathlib.Path: if not object_typename or not object_path: logger.error('Must specify an object typename and object path.') return None @@ -432,26 +432,18 @@ def get_json_file_path(object_typename: str, def get_json_data_file(object_json: pathlib.Path, - object_typename: str = None, - object_validator = callable) -> dict or None: + object_typename: str, + object_validator: callable) -> dict or None: if not object_typename: logger.error('Missing object typename.') return None - if not object_json: - logger.error(f'No object json provided for {object_typename}') + if not object_json or not object_json.is_file(): + logger.error(f'Invalid {object_typename} json {object_json} supplied or file missing.') return None - if not object_json.is_file(): - logger.error(f'{object_typename} json {object_json} is not present.') - return None - - if not object_validator: - logger.error('Missing object validator.') - return None - - if not object_validator(object_json): - logger.error(f'{object_typename} json {object_json} is not valid.') + if not object_validator or not object_validator(object_json): + logger.error(f'{object_typename} json {object_json} is not valid or could not be validated.') return None with object_json.open('r') as f: @@ -464,16 +456,11 @@ def get_json_data_file(object_json: pathlib.Path, return None -def get_json_data(object_typename: str = None, - object_path: str or pathlib.Path = None, - object_validator = callable, - object_name: str = None) -> dict or None: +def get_json_data(object_typename: str, + object_path: str or pathlib.Path, + object_validator: callable) -> dict or None: object_json = get_json_file_path(object_typename, object_path) - if not object_json and object_name: - logger.error(f'{object_name} has not been registered.') - return None - return get_json_data_file(object_json, object_typename, object_validator) @@ -486,7 +473,7 @@ def get_engine_json_data(engine_name: str = None, if engine_name and not engine_path: engine_path = get_registered(engine_name=engine_name) - return get_json_data('engine', engine_path, validation.valid_o3de_engine_json, engine_name) + return get_json_data('engine', engine_path, validation.valid_o3de_engine_json) def get_project_json_data(project_name: str = None, @@ -498,7 +485,7 @@ def get_project_json_data(project_name: str = None, if project_name and not project_path: project_path = get_registered(project_name=project_name) - return get_json_data('project', project_path, validation.valid_o3de_project_json, project_name) + return get_json_data('project', project_path, validation.valid_o3de_project_json) def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None, @@ -510,7 +497,7 @@ def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None if gem_name and not gem_path: gem_path = get_registered(gem_name=gem_name, project_path=project_path) - return get_json_data('gem', gem_path, validation.valid_o3de_gem_json, gem_name) + return get_json_data('gem', gem_path, validation.valid_o3de_gem_json) def get_template_json_data(template_name: str = None, template_path: str or pathlib.Path = None, @@ -522,7 +509,7 @@ def get_template_json_data(template_name: str = None, template_path: str or path if template_name and not template_path: template_path = get_registered(template_name=template_name, project_path=project_path) - return get_json_data('template', template_path, validation.valid_o3de_template_json, template_name) + return get_json_data('template', template_path, validation.valid_o3de_template_json) def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None, @@ -534,7 +521,7 @@ def get_restricted_json_data(restricted_name: str = None, restricted_path: str o if restricted_name and not restricted_path: restricted_path = get_registered(restricted_name=restricted_name, project_path=project_path) - return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json, restricted_name) + return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json) def get_repo_json_data(repo_uri: str) -> dict or None: if not repo_uri: From 843f993fc950c0324e303bbd1d03d2bf8c3b2624 Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Mon, 11 Oct 2021 13:17:07 -0700 Subject: [PATCH 181/293] Improve ticket tracker workflow for testing (#4610) * Improve ticket tracker workflow for testing Signed-off-by: onecent1101 --- .../AWSGameLiftClientLocalTicketTracker.cpp | 16 +++++++++++++--- .../Source/AWSGameLiftClientLocalTicketTracker.h | 2 ++ .../AWSGameLiftClientLocalTicketTrackerTest.cpp | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp index 9ae168aea9..b619a10d4a 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp @@ -47,6 +47,15 @@ namespace AWSGameLift AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket tracker is running."); return; } + + // Make sure thread and wait event are both in clean state before starting new one + m_waitEvent.release(); + if (m_trackerThread.joinable()) + { + m_trackerThread.join(); + } + m_waitEvent.acquire(); + m_status = TicketTrackerStatus::Running; m_trackerThread = AZStd::thread(AZStd::bind( &AWSGameLiftClientLocalTicketTracker::ProcessPolling, this, ticketId, playerId)); @@ -56,6 +65,7 @@ namespace AWSGameLift { AZStd::lock_guard lock(m_trackerMutex); m_status = TicketTrackerStatus::Idle; + m_waitEvent.release(); if (m_trackerThread.joinable()) { m_trackerThread.join(); @@ -81,19 +91,19 @@ namespace AWSGameLift auto ticket = describeMatchmakingOutcome.GetResult().GetTicketList().front(); if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED) { - m_status = TicketTrackerStatus::Idle; AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is complete.", ticket.GetTicketId().c_str()); RequestPlayerJoinMatch(ticket, playerId); + m_status = TicketTrackerStatus::Idle; return; } else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::TIMED_OUT || ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::FAILED || ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::CANCELLED) { - m_status = TicketTrackerStatus::Idle; AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Matchmaking ticket %s is not complete, %s", ticket.GetTicketId().c_str(), ticket.GetStatusReason().c_str()); + m_status = TicketTrackerStatus::Idle; return; } else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::REQUIRES_ACCEPTANCE) @@ -122,7 +132,7 @@ namespace AWSGameLift { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftClientMissingErrorMessage); } - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(m_pollingPeriodInMS)); + m_waitEvent.try_acquire_for(AZStd::chrono::milliseconds(m_pollingPeriodInMS)); } } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h index 7b317a0485..23083e9fd9 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include @@ -58,5 +59,6 @@ namespace AWSGameLift AZStd::mutex m_trackerMutex; AZStd::thread m_trackerThread; + AZStd::binary_semaphore m_waitEvent; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp index 6e688b28e3..6506d70704 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp @@ -16,7 +16,7 @@ using namespace AWSGameLift; -static constexpr const uint64_t TEST_RACKER_POLLING_PERIOD_MS = 100; +static constexpr const uint64_t TEST_RACKER_POLLING_PERIOD_MS = 1000; static constexpr const uint64_t TEST_WAIT_BUFFER_TIME_MS = 10; static constexpr const uint64_t TEST_WAIT_MAXIMUM_TIME_MS = 10000; From d3c2e288e92db7de43ab66676977f917648b42b3 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Mon, 11 Oct 2021 13:30:27 -0700 Subject: [PATCH 182/293] sandbox the Reflection Probe portion of the test, remove xfail marker - Reflection Probe will be re-added in the parallel test approach (#4584) Signed-off-by: jromnoa --- .../Gem/PythonTests/Atom/TestSuite_Main.py | 18 ------ .../Gem/PythonTests/Atom/TestSuite_Sandbox.py | 55 ++++++++++++++++++- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index b148ffdcdb..e4a77ca4ec 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -3,8 +3,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 - -Main suite tests for the Atom renderer. """ import logging import os @@ -25,7 +23,6 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") class TestAtomEditorComponentsMain(object): """Holds tests for Atom components.""" - @pytest.mark.xfail(reason="This test is being marked xfail as it failed during an unrelated development run. See LYN-7530 for more details.") def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform): """ Please review the hydra script run by this test for more specific test info. @@ -162,21 +159,6 @@ class TestAtomEditorComponentsMain(object): "Display Mapper_test: Entity deleted: True", "Display Mapper_test: UNDO entity deletion works: True", "Display Mapper_test: REDO entity deletion works: True", - # Reflection Probe Component - "Reflection Probe Entity successfully created", - "Reflection Probe_test: Component added to the entity: True", - "Reflection Probe_test: Component removed after UNDO: True", - "Reflection Probe_test: Component added after REDO: True", - "Reflection Probe_test: Entered game mode: True", - "Reflection Probe_test: Exit game mode: True", - "Reflection Probe_test: Entity disabled initially: True", - "Reflection Probe_test: Entity enabled after adding required components: True", - "Reflection Probe_test: Cubemap is generated: True", - "Reflection Probe_test: Entity is hidden: True", - "Reflection Probe_test: Entity is shown: True", - "Reflection Probe_test: Entity deleted: True", - "Reflection Probe_test: UNDO entity deletion works: True", - "Reflection Probe_test: REDO entity deletion works: True", ] unexpected_lines = [ diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py index 05401c0059..79caf26784 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py @@ -3,12 +3,17 @@ 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 - -Sandbox suite tests for the Atom renderer. """ +import logging +import os import pytest +import editor_python_test_tools.hydra_test_utils as hydra + +logger = logging.getLogger(__name__) +TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") + @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @@ -18,3 +23,49 @@ class TestAtomEditorComponentsSandbox(object): # It requires at least one test def test_Dummy(self, request, editor, level, workspace, project, launcher_platform): pass + + @pytest.mark.parametrize("project", ["AutomatedTesting"]) + @pytest.mark.parametrize("launcher_platform", ['windows_editor']) + @pytest.mark.parametrize("level", ["auto_test"]) + class TestAtomEditorComponentsMain(object): + """Holds tests for Atom components.""" + + def test_AtomEditorComponents_ReflectionProbeAddedToEntity( + self, request, editor, level, workspace, project, launcher_platform): + """ + Please review the hydra script run by this test for more specific test info. + Tests the following Atom components and verifies all "expected_lines" appear in Editor.log: + 1. Reflection Probe + """ + cfg_args = [level] + + expected_lines = [ + # Reflection Probe Component + "Reflection Probe Entity successfully created", + "Reflection Probe_test: Component added to the entity: True", + "Reflection Probe_test: Component removed after UNDO: True", + "Reflection Probe_test: Component added after REDO: True", + "Reflection Probe_test: Entered game mode: True", + "Reflection Probe_test: Exit game mode: True", + "Reflection Probe_test: Entity disabled initially: True", + "Reflection Probe_test: Entity enabled after adding required components: True", + "Reflection Probe_test: Cubemap is generated: True", + "Reflection Probe_test: Entity is hidden: True", + "Reflection Probe_test: Entity is shown: True", + "Reflection Probe_test: Entity deleted: True", + "Reflection Probe_test: UNDO entity deletion works: True", + "Reflection Probe_test: REDO entity deletion works: True", + ] + + hydra.launch_and_validate_results( + request, + TEST_DIRECTORY, + editor, + "hydra_AtomEditorComponents_AddedToEntity.py", + timeout=120, + expected_lines=expected_lines, + unexpected_lines=[], + halt_on_unexpected=True, + null_renderer=True, + cfg_args=cfg_args, + ) From a95c609bd8e86c84226672f6ce4296cd443d60c4 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 11 Oct 2021 14:00:42 -0700 Subject: [PATCH 183/293] [development] Migrate Atom CPU timing stats tracking to use global stats profiler (#4549) This change is a preparation for moving the CPU profiler/visualization system from Atom into its own Gem by removing the dependency on local time tracking object AZ::RHI::CpuTimingStatistics Full changes include: - Removed all usage of AZ::RHI::CpuTimingStatistics -- Replaced with pushing to AZ::Statistics::StatisticalProfilerProxy global instance - Promoted VariableTimer from AZ::RHI to AZ::Debug - Removed now unused CpuTimingStatistics.h Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- Code/Framework/AzCore/AzCore/Debug/Timer.h | 18 +++++ .../ProfilingCaptureSystemComponent.cpp | 14 +--- .../RHI/Code/Include/Atom/RHI.Reflect/Base.h | 1 + .../Atom/RHI.Reflect/CpuTimingStatistics.h | 77 ------------------- Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h | 13 ++-- .../Code/Include/Atom/RHI/FrameScheduler.h | 6 +- .../RHI/Code/Include/Atom/RHI/RHISystem.h | 2 +- .../Include/Atom/RHI/RHISystemInterface.h | 3 +- .../Atom/RHI/Code/Source/RHI/CommandQueue.cpp | 17 ++++ .../RHI/Code/Source/RHI/CpuProfilerImpl.cpp | 6 ++ Gems/Atom/RHI/Code/Source/RHI/Device.cpp | 4 +- .../RHI/Code/Source/RHI/FrameScheduler.cpp | 34 ++++++-- Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp | 4 +- Gems/Atom/RHI/Code/Tests/Device.h | 2 +- .../RHI/Code/atom_rhi_reflect_files.cmake | 1 - .../RHI/DX12/Code/Source/RHI/CommandQueue.cpp | 8 +- .../Code/Source/RHI/CommandQueueContext.cpp | 22 +++--- .../Code/Source/RHI/CommandQueueContext.h | 7 +- Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp | 4 +- Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h | 2 +- .../Metal/Code/Source/RHI/CommandQueue.cpp | 9 ++- .../Code/Source/RHI/CommandQueueContext.cpp | 24 +++--- .../Code/Source/RHI/CommandQueueContext.h | 2 +- .../Atom/RHI/Metal/Code/Source/RHI/Device.cpp | 4 +- Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h | 2 +- Gems/Atom/RHI/Null/Code/Source/RHI/Device.h | 2 +- .../Vulkan/Code/Source/RHI/CommandQueue.cpp | 9 ++- .../Code/Source/RHI/CommandQueueContext.cpp | 22 +++--- .../Code/Source/RHI/CommandQueueContext.h | 7 +- .../RHI/Vulkan/Code/Source/RHI/Device.cpp | 4 +- Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h | 2 +- Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h | 2 +- .../Viewport/PerformanceMonitorComponent.cpp | 7 +- .../Include/Atom/Utils/ImGuiCpuProfiler.h | 22 +++--- .../Include/Atom/Utils/ImGuiCpuProfiler.inl | 65 +++++++++++----- .../Source/AtomImGuiToolsSystemComponent.cpp | 6 +- 36 files changed, 213 insertions(+), 221 deletions(-) delete mode 100644 Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h diff --git a/Code/Framework/AzCore/AzCore/Debug/Timer.h b/Code/Framework/AzCore/AzCore/Debug/Timer.h index 47bd3e1b95..6585fe7468 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Timer.h +++ b/Code/Framework/AzCore/AzCore/Debug/Timer.h @@ -46,5 +46,23 @@ namespace AZ private: AZStd::sys_time_t m_timeStamp; }; + + //! Utility type that updates the given variable with the lifetime of the object in cycles. + //! Useful for quick scope based timing. + struct ScopedTimer + { + explicit ScopedTimer(AZStd::sys_time_t& variable) + : m_variable(variable) + { + m_timer.Stamp(); + } + ~ScopedTimer() + { + m_variable = m_timer.GetDeltaTimeInTicks(); + } + + AZStd::sys_time_t& m_variable; + Timer m_timer; + }; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp index a476b5b839..4accbf0bba 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -457,17 +456,8 @@ namespace AZ JsonSerializerSettings serializationSettings; serializationSettings.m_keepDefaults = true; - double frameTime = 0.0; - const AZ::RHI::CpuTimingStatistics* stats = AZ::RHI::RHISystemInterface::Get()->GetCpuTimingStatistics(); - if (stats) - { - frameTime = stats->GetFrameToFrameTimeMilliseconds(); - } - else - { - AZStd::string warning = AZStd::string::format("Failed to get Cpu frame time"); - AZ_Warning("ProfilingCaptureSystemComponent", false, warning.c_str()); - } + double frameTime = AZ::RHI::RHISystemInterface::Get()->GetCpuFrameTime(); + AZ_Warning("ProfilingCaptureSystemComponent", frameTime > 0, "Failed to get Cpu frame time"); CpuFrameTimeSerializer serializer(frameTime); const auto saveResult = JsonSerializationUtils::SaveObjectToFile(&serializer, diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Base.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Base.h index 9e1ec4585e..977c2c9ce8 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Base.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/Base.h @@ -16,6 +16,7 @@ #include AZ_DECLARE_BUDGET(RHI); +inline static constexpr AZ::Crc32 rhiMetricsId = AZ_CRC_CE("RHI"); namespace UnitTest { diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h deleted file mode 100644 index 2ab23def08..0000000000 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/CpuTimingStatistics.h +++ /dev/null @@ -1,77 +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 - * - */ -#pragma once - -#include - -#include -#include -#include -#include - -namespace AZ -{ - namespace RHI - { - //! Container and helper type for storing per frame CPU timing data. - //! Users can queue up generic timings in Scopes or add to specific timing data. - struct CpuTimingStatistics - { - struct QueueStatistics - { - //! The display name of the queue the statistics are for. - Name m_queueName; - - //! Time spent executing queued work. - AZStd::sys_time_t m_executeDuration{}; - }; - - //! Statistics for each command queue. - AZStd::vector m_queueStatistics; - - //! The amount of time spent between two calls to EndFrame. - AZStd::sys_time_t m_frameToFrameTime{}; - - //! The amount of time spent presenting (vsync can affect this). - AZStd::sys_time_t m_presentDuration{}; - - void Reset() - { - m_queueStatistics.clear(); - } - - double GetFrameToFrameTimeMilliseconds() const - { - return (m_frameToFrameTime * 1000) / aznumeric_cast(AZStd::GetTimeTicksPerSecond()); - } - }; - - //! Utility type that updates the given variable with the lifetime of the object in cycles. - //! Useful for quick scope based timing. - struct VariableTimer - { - VariableTimer() = delete; - VariableTimer(AZStd::sys_time_t& variable) - : m_variable(variable) - { - m_timer.Stamp(); - } - ~VariableTimer() - { - m_variable = m_timer.GetDeltaTimeInTicks(); - } - - AZStd::sys_time_t& m_variable; - AZ::Debug::Timer m_timer; - }; - } -} - -//! Utility for timing a section of code and writing the timing (in cycles) to the given variable. -#define AZ_PROFILE_RHI_VARIABLE(variable) \ - AZ::RHI::VariableTimer AZ_JOIN(variableTimer, __LINE__)(variable); diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h index fb4082bb25..358fdcb4c4 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h @@ -27,9 +27,6 @@ namespace AZ { namespace RHI { - struct CpuTimingStatistics; - - //! The Device is a context for managing GPU state and memory on a physical device. The user creates //! a device instance from a PhysicalDevice. Each device has its own capabilities and limits, and can //! be configured to buffer a specific number of frames. @@ -91,10 +88,10 @@ namespace AZ //! scope. Otherwise, an error code is returned. ResultCode CompileMemoryStatistics(MemoryStatistics& memoryStatistics, MemoryStatisticsReportFlags reportFlags); - //! Fills the provided data structure with cpu timing statistics specific to this device. This - //! method can only be called on an initialized device, and outside of the BeginFrame / EndFrame - //! scope. Otherwise, an error code is returned. - ResultCode UpdateCpuTimingStatistics(CpuTimingStatistics& cpuTimingStatistics) const; + //! Pushes internally recorded timing statistics upwards into the global stats profiler, under the RHI section. + //! This method can only be called on an initialized device, and outside of the BeginFrame / EndFrame scope. + //! Otherwise, an error code is returned. + ResultCode UpdateCpuTimingStatistics() const; //! Returns the physical device associated with this device. const PhysicalDevice& GetPhysicalDevice() const; @@ -186,7 +183,7 @@ namespace AZ virtual void CompileMemoryStatisticsInternal(MemoryStatisticsBuilder& builder) = 0; //! Called when the device is reporting cpu timing statistics. - virtual void UpdateCpuTimingStatisticsInternal(CpuTimingStatistics& cpuTimingStatistics) const = 0; + virtual void UpdateCpuTimingStatisticsInternal() const = 0; //! Fills the capabilities for each format. virtual void FillFormatsCapabilitiesInternal(FormatCapabilitiesList& formatsCapabilities) = 0; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h index 48e7e0f339..eb2b0b5b0c 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameScheduler.h @@ -7,7 +7,6 @@ */ #pragma once -#include #include #include #include @@ -168,8 +167,8 @@ namespace AZ /// Returns the timing statistics for the previous frame. const TransientAttachmentStatistics* GetTransientAttachmentStatistics() const; - /// Returns cpu timing statistics for the previous frame. - const CpuTimingStatistics* GetCpuTimingStatistics() const; + /// Returns current CPU frame to frame time in milliseconds. + double GetCpuFrameTime() const; /// Returns memory statistics for the previous frame. const MemoryStatistics* GetMemoryStatistics() const; @@ -216,7 +215,6 @@ namespace AZ Ptr m_transientAttachmentPool; - CpuTimingStatistics m_cpuTimingStatistics; AZStd::sys_time_t m_lastFrameEndTime{}; MemoryStatistics m_memoryStatistics; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h index 599108654a..52a44c0903 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystem.h @@ -48,7 +48,7 @@ namespace AZ RHI::PipelineStateCache* GetPipelineStateCache() override; const RHI::FrameSchedulerCompileRequest& GetFrameSchedulerCompileRequest() const override; void ModifyFrameSchedulerStatisticsFlags(RHI::FrameSchedulerStatisticsFlags statisticsFlags, bool enableFlags) override; - const RHI::CpuTimingStatistics* GetCpuTimingStatistics() const override; + double GetCpuFrameTime() const override; const RHI::TransientAttachmentStatistics* GetTransientAttachmentStatistics() const override; const RHI::MemoryStatistics* GetMemoryStatistics() const override; const RHI::TransientAttachmentPoolDescriptor* GetTransientAttachmentPoolDescriptor() const override; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h index 6a9650e0a1..19ba1cb762 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHISystemInterface.h @@ -27,7 +27,6 @@ namespace AZ class PipelineStateCache; class PlatformLimitsDescriptor; class RayTracingShaderTable; - struct CpuTimingStatistics; struct FrameSchedulerCompileRequest; struct TransientAttachmentStatistics; struct TransientAttachmentPoolDescriptor; @@ -55,7 +54,7 @@ namespace AZ virtual void ModifyFrameSchedulerStatisticsFlags(RHI::FrameSchedulerStatisticsFlags statisticsFlags, bool enableFlags) = 0; - virtual const RHI::CpuTimingStatistics* GetCpuTimingStatistics() const = 0; + virtual double GetCpuFrameTime() const = 0; virtual const RHI::TransientAttachmentStatistics* GetTransientAttachmentStatistics() const = 0; diff --git a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp index f65c36f2ed..a365b23e94 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CommandQueue.cpp @@ -32,6 +32,23 @@ namespace AZ return ResultCode::InvalidOperation; } #endif + + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) + { + auto& rhiMetrics = statsProfiler->GetProfiler(rhiMetricsId); + + static constexpr AZStd::string_view presentStatName("Present"); + static constexpr AZ::Crc32 presentStatId(presentStatName); + rhiMetrics.GetStatsManager().AddStatistic(presentStatId, presentStatName, /*units=*/"clocks", /*failIfExist=*/false); + + if (!GetName().IsEmpty()) + { + const AZStd::string commandQueueName(GetName().GetCStr()); + const AZ::Crc32 commandQueueId(GetName().GetHash()); + rhiMetrics.GetStatsManager().AddStatistic(commandQueueId, commandQueueName, /*units=*/"clocks", /*failIfExist=*/false); + } + } + const ResultCode resultCode = InitInternal(device, descriptor); if (resultCode == ResultCode::Success) diff --git a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp index 1bc17adb22..826e0b6aa3 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp @@ -12,6 +12,7 @@ #include #include +#include #include namespace AZ @@ -73,6 +74,11 @@ namespace AZ m_initialized = true; SystemTickBus::Handler::BusConnect(); m_continuousCaptureData.set_capacity(10); + + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) + { + statsProfiler->ActivateProfiler(AZ_CRC_CE("RHI"), true); + } } void CpuProfilerImpl::Shutdown() diff --git a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp index 2f4ca297a1..c8497cf7b1 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Device.cpp @@ -160,11 +160,11 @@ namespace AZ return ResultCode::InvalidOperation; } - ResultCode Device::UpdateCpuTimingStatistics(CpuTimingStatistics& cpuTimingStatistics) const + ResultCode Device::UpdateCpuTimingStatistics() const { if (ValidateIsNotInFrame()) { - UpdateCpuTimingStatisticsInternal(cpuTimingStatistics); + UpdateCpuTimingStatisticsInternal(); return ResultCode::Success; } return ResultCode::InvalidOperation; diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp index 0d3ac8216b..a15db9e24b 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp @@ -35,6 +35,9 @@ namespace AZ { namespace RHI { + static constexpr const char* frameTimeMetricName = "Frame to Frame Time"; + static constexpr AZ::Crc32 frameTimeMetricId = AZ_CRC_CE(frameTimeMetricName); + ResultCode FrameScheduler::Init(Device& device, const FrameSchedulerDescriptor& descriptor) { ResultCode resultCode = ResultCode::Success; @@ -81,6 +84,12 @@ namespace AZ m_taskGraphActive = AZ::Interface::Get(); + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) + { + auto& rhiMetrics = statsProfiler->GetProfiler(rhiMetricsId); + rhiMetrics.GetStatsManager().AddStatistic(frameTimeMetricId, frameTimeMetricName, /*units=*/"clocks", /*failIfExist=*/false); + } + m_lastFrameEndTime = AZStd::GetTimeNowTicks(); return ResultCode::Success; @@ -278,7 +287,7 @@ namespace AZ AZ::TaskDescriptor srgCompileEndDesc{"SrgCompileEnd", "Graphics"}; auto srgCompileEndTask = taskGraph.AddTask( - srgCompileEndDesc, + srgCompileEndDesc, [srgPool]() { srgPool->CompileGroupsEnd(); @@ -449,7 +458,7 @@ namespace AZ m_device->CompileMemoryStatistics(m_memoryStatistics, MemoryStatisticsReportFlags::Detail); } - m_device->UpdateCpuTimingStatistics(m_cpuTimingStatistics); + m_device->UpdateCpuTimingStatistics(); m_scopeProducers.clear(); m_scopeProducerLookup.clear(); @@ -460,7 +469,10 @@ namespace AZ } const AZStd::sys_time_t timeNowTicks = AZStd::GetTimeNowTicks(); - m_cpuTimingStatistics.m_frameToFrameTime = timeNowTicks - m_lastFrameEndTime; + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) + { + statsProfiler->PushSample(rhiMetricsId, frameTimeMetricId, static_cast(timeNowTicks - m_lastFrameEndTime)); + } m_lastFrameEndTime = timeNowTicks; return ResultCode::Success; @@ -588,12 +600,18 @@ namespace AZ : nullptr; } - const CpuTimingStatistics* FrameScheduler::GetCpuTimingStatistics() const + double FrameScheduler::GetCpuFrameTime() const { - return - CheckBitsAny(m_compileRequest.m_statisticsFlags, FrameSchedulerStatisticsFlags::GatherCpuTimingStatistics) - ? &m_cpuTimingStatistics - : nullptr; + if (CheckBitsAny(m_compileRequest.m_statisticsFlags, FrameSchedulerStatisticsFlags::GatherCpuTimingStatistics)) + { + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) + { + auto& rhiMetrics = statsProfiler->GetProfiler(rhiMetricsId); + const auto* frameTimeStat = rhiMetrics.GetStatistic(frameTimeMetricId); + return (frameTimeStat->GetMostRecentSample() * 1000) / aznumeric_cast(AZStd::GetTimeTicksPerSecond()); + } + } + return 0; } ScopeId FrameScheduler::GetRootScopeId() const diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index 744b688c60..b40ad3e11a 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -254,9 +254,9 @@ namespace AZ : RHI::ResetBits(m_compileRequest.m_statisticsFlags, statisticsFlags); } - const RHI::CpuTimingStatistics* RHISystem::GetCpuTimingStatistics() const + double RHISystem::GetCpuFrameTime() const { - return m_frameScheduler.GetCpuTimingStatistics(); + return m_frameScheduler.GetCpuFrameTime(); } const RHI::TransientAttachmentStatistics* RHISystem::GetTransientAttachmentStatistics() const diff --git a/Gems/Atom/RHI/Code/Tests/Device.h b/Gems/Atom/RHI/Code/Tests/Device.h index d3177fc823..2b6a81face 100644 --- a/Gems/Atom/RHI/Code/Tests/Device.h +++ b/Gems/Atom/RHI/Code/Tests/Device.h @@ -47,7 +47,7 @@ namespace UnitTest void CompileMemoryStatisticsInternal(AZ::RHI::MemoryStatisticsBuilder&) override {} - void UpdateCpuTimingStatisticsInternal([[maybe_unused]] AZ::RHI::CpuTimingStatistics& cpuTimingStatistics) const override {} + void UpdateCpuTimingStatisticsInternal() const override {} AZStd::chrono::microseconds GpuTimestampToMicroseconds([[maybe_unused]] uint64_t gpuTimestamp, [[maybe_unused]] AZ::RHI::HardwareQueueClass queueClass) const override { diff --git a/Gems/Atom/RHI/Code/atom_rhi_reflect_files.cmake b/Gems/Atom/RHI/Code/atom_rhi_reflect_files.cmake index e211462eeb..9a2b6e8765 100644 --- a/Gems/Atom/RHI/Code/atom_rhi_reflect_files.cmake +++ b/Gems/Atom/RHI/Code/atom_rhi_reflect_files.cmake @@ -112,7 +112,6 @@ set(FILES Source/RHI.Reflect/ShaderResourceGroupLayout.cpp Source/RHI.Reflect/ShaderResourceGroupLayoutDescriptor.cpp Source/RHI.Reflect/ShaderResourceGroupPoolDescriptor.cpp - Include/Atom/RHI.Reflect/CpuTimingStatistics.h Include/Atom/RHI.Reflect/MemoryStatistics.h Include/Atom/RHI.Reflect/TransientAttachmentStatistics.h Include/Atom/RHI.Reflect/SwapChainDescriptor.h diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp index 0cde6aeb09..7ab2b07b03 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueue.cpp @@ -10,8 +10,8 @@ #include #include #include -#include -#include + +#include namespace AZ { @@ -139,7 +139,7 @@ namespace AZ QueueCommand([=](void* commandQueue) { AZ_PROFILE_SCOPE(RHI, "ExecuteWork"); - AZ_PROFILE_RHI_VARIABLE(m_lastExecuteDuration); + AZ::Debug::ScopedTimer executionTimer(m_lastExecuteDuration); static const uint32_t CommandListCountMax = 128; ID3D12CommandQueue* dx12CommandQueue = static_cast(commandQueue); @@ -185,7 +185,7 @@ namespace AZ dx12CommandQueue->Signal(fence->Get(), fence->GetPendingValue()); } - AZ_PROFILE_RHI_VARIABLE(m_lastPresentDuration); + AZ::Debug::ScopedTimer presentTimer(m_lastPresentDuration); for (RHI::SwapChain* swapChain : request.m_swapChainsToPresent) { swapChain->Present(); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp index 012784d3fc..5692809443 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -183,17 +182,22 @@ namespace AZ return *m_commandQueues[static_cast(hardwareQueueClass)]; } - void CommandQueueContext::UpdateCpuTimingStatistics(RHI::CpuTimingStatistics& cpuTimingStatistics) const + void CommandQueueContext::UpdateCpuTimingStatistics() const { - cpuTimingStatistics.Reset(); - - AZStd::sys_time_t presentDuration = 0; - for (const RHI::Ptr& commandQueue : m_commandQueues) + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) { - cpuTimingStatistics.m_queueStatistics.push_back({ commandQueue->GetName(), commandQueue->GetLastExecuteDuration() }); - presentDuration += commandQueue->GetLastPresentDuration(); + auto& rhiMetrics = statsProfiler->GetProfiler(rhiMetricsId); + + AZStd::sys_time_t presentDuration = 0; + for (const RHI::Ptr& commandQueue : m_commandQueues) + { + const AZ::Crc32 commandQueueId(commandQueue->GetName().GetHash()); + rhiMetrics.PushSample(commandQueueId, static_cast(commandQueue->GetLastExecuteDuration())); + presentDuration += commandQueue->GetLastPresentDuration(); + } + + rhiMetrics.PushSample(AZ_CRC_CE("Present"), static_cast(presentDuration)); } - cpuTimingStatistics.m_presentDuration = presentDuration; } const FenceSet& CommandQueueContext::GetCompiledFences() diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.h index cf820026aa..dff1741109 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.h @@ -14,11 +14,6 @@ namespace AZ { - namespace RHI - { - struct CpuTimingStatistics; - } - namespace DX12 { class CommandQueueContext @@ -49,7 +44,7 @@ namespace AZ RHI::HardwareQueueClass hardwareQueueClass, const ExecuteWorkRequest& request); - void UpdateCpuTimingStatistics(RHI::CpuTimingStatistics& cpuTimingStatistics) const; + void UpdateCpuTimingStatistics() const; // Fences across all queues that are compiled by the frame graph compilation phase const FenceSet& GetCompiledFences(); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp index 6f614499d2..3d44e56953 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp @@ -184,9 +184,9 @@ namespace AZ m_stagingMemoryAllocator.ReportMemoryUsage(builder); } - void Device::UpdateCpuTimingStatisticsInternal(RHI::CpuTimingStatistics& cpuTimingStatistics) const + void Device::UpdateCpuTimingStatisticsInternal() const { - m_commandQueueContext.UpdateCpuTimingStatistics(cpuTimingStatistics); + m_commandQueueContext.UpdateCpuTimingStatistics(); } void Device::EndFrameInternal() diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h index 40e26db891..29e006fca0 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h @@ -147,7 +147,7 @@ namespace AZ void ShutdownInternal() override; void CompileMemoryStatisticsInternal(RHI::MemoryStatisticsBuilder& builder) override; - void UpdateCpuTimingStatisticsInternal(RHI::CpuTimingStatistics& cpuTimingStatistics) const override; + void UpdateCpuTimingStatisticsInternal() const override; void BeginFrameInternal() override; void EndFrameInternal() override; void WaitForIdleInternal() override; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueue.cpp index d151a11ec1..a1f4616147 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueue.cpp @@ -5,14 +5,15 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include -#include + #include #include #include #include #include +#include + namespace AZ { namespace Metal @@ -115,7 +116,7 @@ namespace AZ @autoreleasepool { AZ_PROFILE_SCOPE(RHI, "ExecuteWork"); - AZ_PROFILE_RHI_VARIABLE(m_lastExecuteDuration); + AZ::Debug::ScopedTimer executionTimer(m_lastExecuteDuration); if (request.m_signalFenceValue > 0) { @@ -128,7 +129,7 @@ namespace AZ } { - AZ_PROFILE_RHI_VARIABLE(m_lastPresentDuration); + AZ::Debug::ScopedTimer presentTimer(m_lastPresentDuration); for (RHI::SwapChain* swapChain : request.m_swapChainsToPresent) { diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp index e4c651c2b1..37f8a8bab8 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -135,18 +134,23 @@ namespace AZ m_commandQueues[hardwareQueueIdx]->QueueGpuSignal(fence); } } - - void CommandQueueContext::UpdateCpuTimingStatistics(RHI::CpuTimingStatistics& cpuTimingStatistics) const - { - cpuTimingStatistics.Reset(); - AZStd::sys_time_t presentDuration = 0; - for (const RHI::Ptr& commandQueue : m_commandQueues) + void CommandQueueContext::UpdateCpuTimingStatistics() const + { + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) { - cpuTimingStatistics.m_queueStatistics.push_back({ commandQueue->GetName(), commandQueue->GetLastExecuteDuration() }); - presentDuration += commandQueue->GetLastPresentDuration(); + auto& rhiMetrics = statsProfiler->GetProfiler(rhiMetricsId); + + AZStd::sys_time_t presentDuration = 0; + for (const RHI::Ptr& commandQueue : m_commandQueues) + { + const AZ::Crc32 commandQueueId(commandQueue->GetName().GetHash()); + rhiMetrics.PushSample(commandQueueId, static_cast(commandQueue->GetLastExecuteDuration())); + presentDuration += commandQueue->GetLastPresentDuration(); + } + + rhiMetrics.PushSample(AZ_CRC_CE("Present"), static_cast(presentDuration)); } - cpuTimingStatistics.m_presentDuration = presentDuration; } } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.h index 747667e1a3..41c0f63189 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandQueueContext.h @@ -40,7 +40,7 @@ namespace AZ /// Fences across all queues that are compiled by the frame graph compilation phase const FenceSet& GetCompiledFences(); - void UpdateCpuTimingStatistics(RHI::CpuTimingStatistics& cpuTimingStatistics) const; + void UpdateCpuTimingStatistics() const; private: AZStd::array, RHI::HardwareQueueClassCount> m_commandQueues; FenceSet m_compiledFences; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp index 782ea7174b..76af1ecab1 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp @@ -245,9 +245,9 @@ namespace AZ { } - void Device::UpdateCpuTimingStatisticsInternal(RHI::CpuTimingStatistics& cpuTimingStatistics) const + void Device::UpdateCpuTimingStatisticsInternal() const { - m_commandQueueContext.UpdateCpuTimingStatistics(cpuTimingStatistics); + m_commandQueueContext.UpdateCpuTimingStatistics(); } void Device::FillFormatsCapabilitiesInternal(FormatCapabilitiesList& formatsCapabilities) diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h index 90dd4ff4a0..8a8ef662f9 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h @@ -161,7 +161,7 @@ namespace AZ RHI::ResultCode InitInternal(RHI::PhysicalDevice& physicalDevice) override; void ShutdownInternal() override; void CompileMemoryStatisticsInternal(RHI::MemoryStatisticsBuilder& builder) override; - void UpdateCpuTimingStatisticsInternal(RHI::CpuTimingStatistics& cpuTimingStatistics) const override; + void UpdateCpuTimingStatisticsInternal() const override; void BeginFrameInternal() override; void EndFrameInternal() override; void WaitForIdleInternal() override; diff --git a/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h index 27873887d4..73e1cd9119 100644 --- a/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h @@ -32,7 +32,7 @@ namespace AZ RHI::ResultCode InitInternal([[maybe_unused]] RHI::PhysicalDevice& physicalDevice) override { return RHI::ResultCode::Success; } void ShutdownInternal() override {} void CompileMemoryStatisticsInternal([[maybe_unused]] RHI::MemoryStatisticsBuilder& builder) override {} - void UpdateCpuTimingStatisticsInternal([[maybe_unused]] RHI::CpuTimingStatistics& cpuTimingStatistics) const override {} + void UpdateCpuTimingStatisticsInternal() const override {} void BeginFrameInternal() override {} void EndFrameInternal() override {} void WaitForIdleInternal() override {} diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp index c712099172..6a43b66474 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp @@ -5,13 +5,14 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include + #include #include #include #include #include -#include + +#include namespace AZ { @@ -46,7 +47,7 @@ namespace AZ QueueCommand([=](void* queue) { AZ_PROFILE_SCOPE(RHI, "ExecuteWork"); - AZ_PROFILE_RHI_VARIABLE(m_lastExecuteDuration); + AZ::Debug::ScopedTimer executionTimer(m_lastExecuteDuration); Queue* vulkanQueue = static_cast(queue); @@ -80,7 +81,7 @@ namespace AZ } { - AZ_PROFILE_RHI_VARIABLE(m_lastPresentDuration); + AZ::Debug::ScopedTimer presentTimer(m_lastPresentDuration); // present the image of the current frame. for (RHI::SwapChain* swapChain : request.m_swapChainsToPresent) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp index ec7311cd6e..9cf6dce77b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.cpp @@ -13,7 +13,6 @@ #include #include #include -#include namespace AZ { @@ -363,17 +362,22 @@ namespace AZ return queueSelection.m_familyIndex != InvalidFamilyIndex; } - void CommandQueueContext::UpdateCpuTimingStatistics(RHI::CpuTimingStatistics& cpuTimingStatistics) const + void CommandQueueContext::UpdateCpuTimingStatistics() const { - cpuTimingStatistics.Reset(); - - AZStd::sys_time_t presentDuration = 0; - for (const RHI::Ptr& commandQueue : m_commandQueues) + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) { - cpuTimingStatistics.m_queueStatistics.push_back({ commandQueue->GetName(), commandQueue->GetLastExecuteDuration() }); - presentDuration += commandQueue->GetLastPresentDuration(); + auto& rhiMetrics = statsProfiler->GetProfiler(rhiMetricsId); + + AZStd::sys_time_t presentDuration = 0; + for (const RHI::Ptr& commandQueue : m_commandQueues) + { + const AZ::Crc32 commandQueueId(commandQueue->GetName().GetHash()); + rhiMetrics.PushSample(commandQueueId, static_cast(commandQueue->GetLastExecuteDuration())); + presentDuration += commandQueue->GetLastPresentDuration(); + } + + rhiMetrics.PushSample(AZ_CRC_CE("Present"), static_cast(presentDuration)); } - cpuTimingStatistics.m_presentDuration = presentDuration; } } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.h index 8528185686..61e9b46d9f 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueueContext.h @@ -16,11 +16,6 @@ namespace AZ { - namespace RHI - { - struct CpuTimingStatistics; - } - namespace Vulkan { class Device; @@ -62,7 +57,7 @@ namespace AZ AZStd::vector GetQueueFamilyIndices(const RHI::HardwareQueueClassMask hardwareQueueClassMask) const; VkPipelineStageFlags GetSupportedPipelineStages(uint32_t queueFamilyIndex) const; - void UpdateCpuTimingStatistics(RHI::CpuTimingStatistics& cpuTimingStatistics) const; + void UpdateCpuTimingStatistics() const; private: Descriptor m_descriptor; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp index 35bc966d1d..132f9929c1 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp @@ -547,9 +547,9 @@ namespace AZ physicalDevice.CompileMemoryStatistics(builder); } - void Device::UpdateCpuTimingStatisticsInternal(RHI::CpuTimingStatistics& cpuTimingStatistics) const + void Device::UpdateCpuTimingStatisticsInternal() const { - m_commandQueueContext.UpdateCpuTimingStatistics(cpuTimingStatistics); + m_commandQueueContext.UpdateCpuTimingStatistics(); } AZStd::vector Device::GetValidSwapChainImageFormats(const RHI::WindowHandle& windowHandle) const diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h index 13ccf9367b..9c21103929 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h @@ -126,7 +126,7 @@ namespace AZ void EndFrameInternal() override; void WaitForIdleInternal() override; void CompileMemoryStatisticsInternal(RHI::MemoryStatisticsBuilder& builder) override; - void UpdateCpuTimingStatisticsInternal(RHI::CpuTimingStatistics& cpuTimingStatistics) const override; + void UpdateCpuTimingStatisticsInternal() const override; AZStd::vector GetValidSwapChainImageFormats(const RHI::WindowHandle& windowHandle) const override; AZStd::chrono::microseconds GpuTimestampToMicroseconds(uint64_t gpuTimestamp, RHI::HardwareQueueClass queueClass) const override; void FillFormatsCapabilitiesInternal(FormatCapabilitiesList& formatsCapabilities) override; diff --git a/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h b/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h index 2ed2875cad..b8d1cfa050 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h +++ b/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h @@ -61,7 +61,7 @@ namespace UnitTest void EndFrameInternal() override {} void WaitForIdleInternal() override {} void CompileMemoryStatisticsInternal(AZ::RHI::MemoryStatisticsBuilder&) override {} - void UpdateCpuTimingStatisticsInternal([[maybe_unused]] AZ::RHI::CpuTimingStatistics& cpuTimingStatistics) const override {} + void UpdateCpuTimingStatisticsInternal() const override {} AZStd::chrono::microseconds GpuTimestampToMicroseconds([[maybe_unused]] uint64_t gpuTimestamp, [[maybe_unused]] AZ::RHI::HardwareQueueClass queueClass) const override { return AZStd::chrono::microseconds(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp index 5598d894ff..c3bb13d1d2 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -96,10 +95,10 @@ namespace MaterialEditor ResetStats(); } - const AZ::RHI::CpuTimingStatistics* stats = AZ::RHI::RHISystemInterface::Get()->GetCpuTimingStatistics(); - if (stats) + double frameTime = AZ::RHI::RHISystemInterface::Get()->GetCpuFrameTime(); + if (frameTime > 0) { - m_cpuFrameTimeMs.PushSample(stats->GetFrameToFrameTimeMilliseconds()); + m_cpuFrameTimeMs.PushSample(frameTime); } AZ::RHI::Ptr rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass(); diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index a649fcf0f7..4a326660dd 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -12,17 +12,11 @@ #include #include -#include #include namespace AZ { - namespace RHI - { - struct CpuTimingStatistics; - } - namespace Render { //! Stores all the data associated with a row in the table. @@ -88,11 +82,17 @@ namespace AZ using GroupRegionName = AZ::RHI::CachedTimeRegion::GroupRegionName; public: + struct CpuTimingEntry + { + const AZStd::string& m_name; + double m_executeDuration; + }; + ImGuiCpuProfiler() = default; ~ImGuiCpuProfiler() = default; //! Draws the overall CPU profiling window, defaults to the statistical view - void Draw(bool& keepDrawing, const AZ::RHI::CpuTimingStatistics& cpuTimingStatistics); + void Draw(bool& keepDrawing); private: static constexpr float RowHeight = 35.0; @@ -121,11 +121,14 @@ namespace AZ // Sort the table by a given column, rearranges the pointers in m_tableData. void SortTable(ImGuiTableSortSpecs* sortSpecs); + // gather the latest timing statistics + void CacheCpuTimingStatistics(); + // Get the profiling data from the last frame, only called when the profiler is not paused. void CollectFrameData(); // Cull old data from internal storage, only called when profiler is not paused. - void CullFrameData(const AZ::RHI::CpuTimingStatistics& currentCpuTimingStatistics); + void CullFrameData(); // Draws a single block onto the timeline into the specified row void DrawBlock(const TimeRegion& block, u64 targetRow); @@ -204,7 +207,8 @@ namespace AZ bool m_enableVisualizer = false; // Last captured CPU timing statistics - AZ::RHI::CpuTimingStatistics m_cpuTimingStatisticsWhenPause; + AZStd::vector m_cpuTimingStatisticsWhenPause; + AZStd::sys_time_t m_frameToFrameTime{}; AZStd::string m_lastCapturedFilePath; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index a573e3019a..daf6eca5c0 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -16,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +31,7 @@ namespace AZ { namespace CpuProfilerImGuiHelper { - inline float TicksToMs(AZStd::sys_time_t ticks) + inline float TicksToMs(double ticks) { // Note: converting to microseconds integer before converting to milliseconds float const AZStd::sys_time_t ticksPerSecond = AZStd::GetTimeTicksPerSecond(); @@ -39,6 +39,11 @@ namespace AZ return static_cast((ticks * 1000) / (ticksPerSecond / 1000)) / 1000.0f; } + inline float TicksToMs(AZStd::sys_time_t ticks) + { + return TicksToMs(static_cast(ticks)); + } + using DeserializedCpuData = AZStd::vector; inline Outcome LoadSavedCpuProfilingStatistics(const AZStd::string& capturePath) { @@ -108,7 +113,9 @@ namespace AZ } } // namespace CpuProfilerImGuiHelper - inline void ImGuiCpuProfiler::Draw(bool& keepDrawing, const AZ::RHI::CpuTimingStatistics& currentCpuTimingStatistics) + + + inline void ImGuiCpuProfiler::Draw(bool& keepDrawing) { // Cache the value to detect if it was changed by ImGui(user pressed 'x') const bool cachedShowCpuProfiler = keepDrawing; @@ -121,10 +128,10 @@ namespace AZ if (!m_paused) { // Update region map and cache the input cpu timing statistics when the profiling is not paused - m_cpuTimingStatisticsWhenPause = currentCpuTimingStatistics; + CacheCpuTimingStatistics(); CollectFrameData(); - CullFrameData(currentCpuTimingStatistics); + CullFrameData(); // Only listen to system ticks when the profiler is active if (!SystemTickBus::Handler::BusIsConnected()) @@ -354,19 +361,12 @@ namespace AZ { DrawCommonHeader(); - const AZ::RHI::CpuTimingStatistics& cpuTimingStatistics = m_cpuTimingStatisticsWhenPause; - - const auto ShowTimeInMs = [](AZStd::sys_time_t duration) - { - ImGui::Text("%.2f ms", CpuProfilerImGuiHelper::TicksToMs(duration)); - }; - - const auto ShowRow = [&ShowTimeInMs](const char* regionLabel, AZStd::sys_time_t duration) + const auto ShowRow = [](const char* regionLabel, double duration) { ImGui::Text("%s", regionLabel); ImGui::NextColumn(); - ShowTimeInMs(duration); + ImGui::Text("%.2f ms", CpuProfilerImGuiHelper::TicksToMs(duration)); ImGui::NextColumn(); }; @@ -377,11 +377,9 @@ namespace AZ ImGui::SetColumnWidth(0, 660.0f); ImGui::SetColumnWidth(1, 100.0f); - ShowRow("Frame to Frame Time", cpuTimingStatistics.m_frameToFrameTime); - ShowRow("Present Time", cpuTimingStatistics.m_presentDuration); - for (const auto& queueStatistics : cpuTimingStatistics.m_queueStatistics) + for (const auto& queueStatistics : m_cpuTimingStatisticsWhenPause) { - ShowRow(queueStatistics.m_queueName.GetCStr(), queueStatistics.m_executeDuration); + ShowRow(queueStatistics.m_name.c_str(), queueStatistics.m_executeDuration); } ImGui::Separator(); @@ -653,6 +651,32 @@ namespace AZ ImGui::EndChild(); } + inline void ImGuiCpuProfiler::CacheCpuTimingStatistics() + { + using namespace AZ::Statistics; + + m_cpuTimingStatisticsWhenPause.clear(); + if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) + { + auto& rhiMetrics = statsProfiler->GetProfiler(AZ_CRC_CE("RHI")); + + const NamedRunningStatistic* frameTimeMetric = rhiMetrics.GetStatistic(AZ_CRC_CE("Frame to Frame Time")); + if (frameTimeMetric) + { + m_frameToFrameTime = static_cast(frameTimeMetric->GetMostRecentSample()); + } + + AZStd::vector statistics; + rhiMetrics.GetStatsManager().GetAllStatistics(statistics); + + for (NamedRunningStatistic* stat : statistics) + { + m_cpuTimingStatisticsWhenPause.push_back({ stat->GetName(), stat->GetMostRecentSample() }); + stat->Reset(); + } + } + } + inline void ImGuiCpuProfiler::CollectFrameData() { // We maintain separate datastores for the visualizer and the statistical view because they require different @@ -721,10 +745,9 @@ namespace AZ } } - inline void ImGuiCpuProfiler::CullFrameData(const AZ::RHI::CpuTimingStatistics& currentCpuTimingStatistics) + inline void ImGuiCpuProfiler::CullFrameData() { - const AZStd::sys_time_t frameToFrameTime = currentCpuTimingStatistics.m_frameToFrameTime; - const AZStd::sys_time_t deleteBeforeTick = AZStd::GetTimeNowTicks() - frameToFrameTime * m_framesToCollect; + const AZStd::sys_time_t deleteBeforeTick = AZStd::GetTimeNowTicks() - m_frameToFrameTime * m_framesToCollect; // Remove old frame boundary data auto firstBoundaryToKeepItr = AZStd::upper_bound(m_frameEndTicks.begin(), m_frameEndTicks.end(), deleteBeforeTick); diff --git a/Gems/AtomLyIntegration/AtomImGuiTools/Code/Source/AtomImGuiToolsSystemComponent.cpp b/Gems/AtomLyIntegration/AtomImGuiTools/Code/Source/AtomImGuiToolsSystemComponent.cpp index ec18997a01..b369ab2ee2 100644 --- a/Gems/AtomLyIntegration/AtomImGuiTools/Code/Source/AtomImGuiToolsSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomImGuiTools/Code/Source/AtomImGuiToolsSystemComponent.cpp @@ -86,11 +86,7 @@ namespace AtomImGuiTools } if (m_showCpuProfiler) { - const AZ::RHI::CpuTimingStatistics* stats = AZ::RHI::RHISystemInterface::Get()->GetCpuTimingStatistics(); - if (stats) - { - m_imguiCpuProfiler.Draw(m_showCpuProfiler, *stats); - } + m_imguiCpuProfiler.Draw(m_showCpuProfiler); } if (m_showTransientAttachmentProfiler) { From 89e6df1c7fc6105ab6fac70964415af283768912 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Mon, 11 Oct 2021 15:18:39 -0700 Subject: [PATCH 184/293] ATOM-16575 clean up image builder presets files (#4611) ATOM-16575 clean up image builder presets files Removed unused image builder presets Deprecating preset UUID and use preset name as unique id Delete all .exportsettings file which were only used for legacy imageProcessing gem. Signed-off-by: Qing Tao --- .../Materials/Stripes.tif.exportsettings | 1 - .../Materials/voxel_editor.png.exportsettings | 1 - .../AverageMemoryUsage.TIF.exportsettings | 1 - .../Icons/HighMemoryUsage.TIF.exportsettings | 1 - .../LevelShaderCacheMiss.tif.exportsettings | 1 - .../Icons/LivePreview.TIF.exportsettings | 1 - .../Icons/LowMemoryUsage.TIF.exportsettings | 1 - .../NavigationProcessing.tif.exportsettings | 1 - .../Icons/NullSoundSystem.tif.exportsettings | 1 - .../Icons/ShaderCompiling.tif.exportsettings | 1 - .../Icons/Streaming.tif.exportsettings | 1 - .../Icons/StreamingTerrain.tif.exportsettings | 1 - .../textures/default_icon.png.exportsettings | 1 - .../grass_atlas_diff.tif.exportsettings | 1 - .../grass_atlas_sss.tif.exportsettings | 1 - ...est_texture_sequence000.png.exportsettings | 1 - .../ProxyGray_ddna.tif.exportsettings | 1 - .../lights/flare01.tif.exportsettings | 1 - .../milestone2/AMA_Grey_01.tif.exportsettings | 1 - .../milestone2/AMA_Grey_02.tif.exportsettings | 1 - .../milestone2/AMA_Grey_03.tif.exportsettings | 1 - ..._LauncherMuzzleFront_01.tif.exportsettings | 1 - ...X_LauncherMuzzleRing_01.tif.exportsettings | 1 - .../BuilderSettings/BuilderSettingManager.cpp | 78 +++++------ .../BuilderSettings/BuilderSettingManager.h | 24 ++-- .../Source/BuilderSettings/CubemapSettings.h | 8 +- .../BuilderSettings/ImageProcessingDefines.h | 4 +- .../Source/BuilderSettings/PresetSettings.h | 3 +- .../BuilderSettings/TextureSettings.cpp | 27 ++-- .../Source/BuilderSettings/TextureSettings.h | 7 +- .../Code/Source/Editor/EditorCommon.cpp | 25 ++-- .../Code/Source/Editor/EditorCommon.h | 2 +- .../Code/Source/Editor/PresetInfoPopup.cpp | 6 +- .../Editor/ResolutionSettingItemWidget.cpp | 2 +- .../Editor/ResolutionSettingItemWidget.h | 2 +- .../Editor/TexturePresetSelectionWidget.cpp | 20 +-- .../Editor/TexturePresetSelectionWidget.h | 2 +- .../Code/Source/ImageBuilderComponent.cpp | 8 +- .../Code/Source/Processing/ImageConvert.cpp | 18 ++- .../Code/Source/Processing/ImageConvert.h | 2 +- .../Code/Source/Processing/ImagePreview.cpp | 2 +- .../Code/Tests/ImageProcessing_Test.cpp | 11 +- .../1024x1024_24bit.tif.exportsettings | 1 - .../Config/AlbedoWithOpacity.preset | 104 --------------- .../Config/CloudShadows.preset | 44 ------ .../Config/ColorChart.preset | 64 --------- ...etail_MergedAlbedoNormalsSmoothness.preset | 79 ----------- ...gedAlbedoNormalsSmoothness_Lossless.preset | 74 ---------- .../Config/IBLGlobal.preset | 4 +- .../Config/IBLSkybox.preset | 20 +-- .../Config/ImageBuilder.settings | 42 +++--- .../Config/LensOptics.preset | 34 ----- .../Config/LightProjector.preset | 59 -------- .../Config/LoadingScreen.preset | 34 ----- .../ImageProcessingAtom/Config/Minimap.preset | 64 --------- .../Config/MuzzleFlash.preset | 59 -------- .../ImageProcessingAtom/Config/Normals.preset | 5 + .../Config/NormalsFromDisplacement.preset | 86 ------------ .../NormalsWithSmoothness_Legacy.preset | 101 -------------- .../ReflectanceWithSmoothness_Legacy.preset | 71 ---------- .../Config/Reflectance_Linear.preset | 81 ----------- .../ImageProcessingAtom/Config/SF_Font.preset | 49 ------- .../Config/SF_Gradient.preset | 49 ------- .../Config/SF_Image.preset | 54 -------- .../Config/SF_Image_nonpower2.preset | 49 ------- .../Config/Terrain_Albedo.preset | 69 ---------- .../Config/Terrain_Albedo_HighPassed.preset | 64 --------- .../Config/Uncompressed.preset | 54 -------- .../Actor/chicken_diff.png.imagesettings | 65 --------- .../Textures/Cowboy_01_ddna.tif.imagesettings | 126 ------------------ .../Textures/Cowboy_01_spec.tif.imagesettings | 126 ------------------ ...amepad_button_a_pressed.tif.exportsettings | 1 - ...epad_button_a_unpressed.tif.exportsettings | 1 - ...amepad_button_b_pressed.tif.exportsettings | 1 - ...epad_button_b_unpressed.tif.exportsettings | 1 - ...amepad_button_x_pressed.tif.exportsettings | 1 - ...epad_button_x_unpressed.tif.exportsettings | 1 - ...amepad_button_y_pressed.tif.exportsettings | 1 - ...epad_button_y_unpressed.tif.exportsettings | 1 - ...mepad_thumbstick_centre.tif.exportsettings | 1 - ...mepad_thumbstick_radial.tif.exportsettings | 1 - 81 files changed, 159 insertions(+), 1856 deletions(-) delete mode 100644 Assets/Editor/Materials/Stripes.tif.exportsettings delete mode 100644 Assets/Editor/Materials/voxel_editor.png.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/AverageMemoryUsage.TIF.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/HighMemoryUsage.TIF.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/LevelShaderCacheMiss.tif.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/LivePreview.TIF.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/LowMemoryUsage.TIF.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/NavigationProcessing.tif.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/NullSoundSystem.tif.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/ShaderCompiling.tif.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/Streaming.tif.exportsettings delete mode 100644 Assets/Engine/EngineAssets/Icons/StreamingTerrain.tif.exportsettings delete mode 100644 Assets/Engine/textures/default_icon.png.exportsettings delete mode 100644 AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_diff.tif.exportsettings delete mode 100644 AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_sss.tif.exportsettings delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C30936451/test_texture_sequence000.png.exportsettings delete mode 100644 AutomatedTesting/Objects/LumberTank/ProxyGray_ddna.tif.exportsettings delete mode 100644 AutomatedTesting/textures/lights/flare01.tif.exportsettings delete mode 100644 AutomatedTesting/textures/milestone2/AMA_Grey_01.tif.exportsettings delete mode 100644 AutomatedTesting/textures/milestone2/AMA_Grey_02.tif.exportsettings delete mode 100644 AutomatedTesting/textures/milestone2/AMA_Grey_03.tif.exportsettings delete mode 100644 AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleFront_01.tif.exportsettings delete mode 100644 AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleRing_01.tif.exportsettings delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/TestAssets/1024x1024_24bit.tif.exportsettings delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithOpacity.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/CloudShadows.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/ColorChart.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness_Lossless.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/LensOptics.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/LightProjector.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/LoadingScreen.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/Minimap.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/MuzzleFlash.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsFromDisplacement.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsWithSmoothness_Legacy.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/ReflectanceWithSmoothness_Legacy.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/Reflectance_Linear.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Font.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Gradient.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image_nonpower2.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo_HighPassed.preset delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/Uncompressed.preset delete mode 100644 Gems/NvCloth/Assets/Objects/cloth/Chicken/Actor/chicken_diff.png.imagesettings delete mode 100644 Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_ddna.tif.imagesettings delete mode 100644 Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_spec.tif.imagesettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_pressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_unpressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_pressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_unpressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_pressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_unpressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_pressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_unpressed.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_centre.tif.exportsettings delete mode 100644 Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_radial.tif.exportsettings diff --git a/Assets/Editor/Materials/Stripes.tif.exportsettings b/Assets/Editor/Materials/Stripes.tif.exportsettings deleted file mode 100644 index 0653bb85eb..0000000000 --- a/Assets/Editor/Materials/Stripes.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Diffuse_lowQ \ No newline at end of file diff --git a/Assets/Editor/Materials/voxel_editor.png.exportsettings b/Assets/Editor/Materials/voxel_editor.png.exportsettings deleted file mode 100644 index d19ae00148..0000000000 --- a/Assets/Editor/Materials/voxel_editor.png.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /mipmaps=0 /preset=AlbedoWithGenericAlpha /reduce=-1 \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/AverageMemoryUsage.TIF.exportsettings b/Assets/Engine/EngineAssets/Icons/AverageMemoryUsage.TIF.exportsettings deleted file mode 100644 index c48fb8632a..0000000000 --- a/Assets/Engine/EngineAssets/Icons/AverageMemoryUsage.TIF.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/HighMemoryUsage.TIF.exportsettings b/Assets/Engine/EngineAssets/Icons/HighMemoryUsage.TIF.exportsettings deleted file mode 100644 index c48fb8632a..0000000000 --- a/Assets/Engine/EngineAssets/Icons/HighMemoryUsage.TIF.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/LevelShaderCacheMiss.tif.exportsettings b/Assets/Engine/EngineAssets/Icons/LevelShaderCacheMiss.tif.exportsettings deleted file mode 100644 index c48fb8632a..0000000000 --- a/Assets/Engine/EngineAssets/Icons/LevelShaderCacheMiss.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/LivePreview.TIF.exportsettings b/Assets/Engine/EngineAssets/Icons/LivePreview.TIF.exportsettings deleted file mode 100644 index 8da27c31a4..0000000000 --- a/Assets/Engine/EngineAssets/Icons/LivePreview.TIF.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/LowMemoryUsage.TIF.exportsettings b/Assets/Engine/EngineAssets/Icons/LowMemoryUsage.TIF.exportsettings deleted file mode 100644 index c48fb8632a..0000000000 --- a/Assets/Engine/EngineAssets/Icons/LowMemoryUsage.TIF.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/NavigationProcessing.tif.exportsettings b/Assets/Engine/EngineAssets/Icons/NavigationProcessing.tif.exportsettings deleted file mode 100644 index 8da27c31a4..0000000000 --- a/Assets/Engine/EngineAssets/Icons/NavigationProcessing.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/NullSoundSystem.tif.exportsettings b/Assets/Engine/EngineAssets/Icons/NullSoundSystem.tif.exportsettings deleted file mode 100644 index 8da27c31a4..0000000000 --- a/Assets/Engine/EngineAssets/Icons/NullSoundSystem.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/ShaderCompiling.tif.exportsettings b/Assets/Engine/EngineAssets/Icons/ShaderCompiling.tif.exportsettings deleted file mode 100644 index 8da27c31a4..0000000000 --- a/Assets/Engine/EngineAssets/Icons/ShaderCompiling.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/Streaming.tif.exportsettings b/Assets/Engine/EngineAssets/Icons/Streaming.tif.exportsettings deleted file mode 100644 index 8da27c31a4..0000000000 --- a/Assets/Engine/EngineAssets/Icons/Streaming.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/EngineAssets/Icons/StreamingTerrain.tif.exportsettings b/Assets/Engine/EngineAssets/Icons/StreamingTerrain.tif.exportsettings deleted file mode 100644 index 8da27c31a4..0000000000 --- a/Assets/Engine/EngineAssets/Icons/StreamingTerrain.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=Uncompressed \ No newline at end of file diff --git a/Assets/Engine/textures/default_icon.png.exportsettings b/Assets/Engine/textures/default_icon.png.exportsettings deleted file mode 100644 index 89ea1ac93f..0000000000 --- a/Assets/Engine/textures/default_icon.png.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /mipmaps=0 /preset=Albedo /reduce=-1 /ser=1 \ No newline at end of file diff --git a/AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_diff.tif.exportsettings b/AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_diff.tif.exportsettings deleted file mode 100644 index b65133fbb0..0000000000 --- a/AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=AlbedoWithGenericAlpha /reduce="android:2,ios:2,mac:0,pc:0,provo:0" \ No newline at end of file diff --git a/AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_sss.tif.exportsettings b/AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_sss.tif.exportsettings deleted file mode 100644 index e8da408b36..0000000000 --- a/AutomatedTesting/Assets/Objects/Foliage/Textures/grass_atlas_sss.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Albedo /reduce="android:3,ios:3,mac:0,pc:0,provo:0" \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C30936451/test_texture_sequence000.png.exportsettings b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C30936451/test_texture_sequence000.png.exportsettings deleted file mode 100644 index a8fbf72992..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C30936451/test_texture_sequence000.png.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Terrain_Albedo_HighPassed /reduce=0 \ No newline at end of file diff --git a/AutomatedTesting/Objects/LumberTank/ProxyGray_ddna.tif.exportsettings b/AutomatedTesting/Objects/LumberTank/ProxyGray_ddna.tif.exportsettings deleted file mode 100644 index a4e1a9a3c5..0000000000 --- a/AutomatedTesting/Objects/LumberTank/ProxyGray_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:0,pc:0,provo:0" \ No newline at end of file diff --git a/AutomatedTesting/textures/lights/flare01.tif.exportsettings b/AutomatedTesting/textures/lights/flare01.tif.exportsettings deleted file mode 100644 index 4fee4cfc4b..0000000000 --- a/AutomatedTesting/textures/lights/flare01.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=LensOptics /reduce=-1 \ No newline at end of file diff --git a/AutomatedTesting/textures/milestone2/AMA_Grey_01.tif.exportsettings b/AutomatedTesting/textures/milestone2/AMA_Grey_01.tif.exportsettings deleted file mode 100644 index 2d1dccbf99..0000000000 --- a/AutomatedTesting/textures/milestone2/AMA_Grey_01.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Albedo /reduce=0 \ No newline at end of file diff --git a/AutomatedTesting/textures/milestone2/AMA_Grey_02.tif.exportsettings b/AutomatedTesting/textures/milestone2/AMA_Grey_02.tif.exportsettings deleted file mode 100644 index a8fbf72992..0000000000 --- a/AutomatedTesting/textures/milestone2/AMA_Grey_02.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Terrain_Albedo_HighPassed /reduce=0 \ No newline at end of file diff --git a/AutomatedTesting/textures/milestone2/AMA_Grey_03.tif.exportsettings b/AutomatedTesting/textures/milestone2/AMA_Grey_03.tif.exportsettings deleted file mode 100644 index a8fbf72992..0000000000 --- a/AutomatedTesting/textures/milestone2/AMA_Grey_03.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Terrain_Albedo_HighPassed /reduce=0 \ No newline at end of file diff --git a/AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleFront_01.tif.exportsettings b/AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleFront_01.tif.exportsettings deleted file mode 100644 index be29bd9bc0..0000000000 --- a/AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleFront_01.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=AlbedoWithOpacity /reduce=0 \ No newline at end of file diff --git a/AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleRing_01.tif.exportsettings b/AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleRing_01.tif.exportsettings deleted file mode 100644 index be29bd9bc0..0000000000 --- a/AutomatedTesting/textures/milestone2/particles/FX_LauncherMuzzleRing_01.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=AlbedoWithOpacity /reduce=0 \ No newline at end of file diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp index 924c01b916..a4ba846f1b 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp @@ -137,25 +137,6 @@ namespace ImageProcessingAtom return nullptr; } - const PresetSettings* BuilderSettingManager::GetPreset(const AZ::Uuid presetId, const PlatformName& platform, AZStd::string_view* settingsFilePathOut) - { - AZStd::lock_guard lock(m_presetMapLock); - - for (const auto& namePreset : m_presets) - { - if (namePreset.second.m_multiPreset.GetPresetId() == presetId) - { - if (settingsFilePathOut) - { - *settingsFilePathOut = namePreset.second.m_presetFilePath; - } - return namePreset.second.m_multiPreset.GetPreset(platform); - } - } - - return nullptr; - } - const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform) { if (m_builderSettings.find(platform) != m_builderSettings.end()) @@ -180,26 +161,12 @@ namespace ImageProcessingAtom return platforms; } - const AZStd::map >& BuilderSettingManager::GetPresetFilterMap() + const AZStd::map >& BuilderSettingManager::GetPresetFilterMap() { AZStd::lock_guard lock(m_presetMapLock); return m_presetFilterMap; } - const AZ::Uuid BuilderSettingManager::GetPresetIdFromName(const PresetName& presetName) - { - AZStd::lock_guard lock(m_presetMapLock); - - auto itr = m_presets.find(presetName); - - if (itr != m_presets.end()) - { - return itr->second.m_multiPreset.GetPresetId(); - } - - return AZ::Uuid::CreateNull(); - } - const PresetName BuilderSettingManager::GetPresetNameFromId(const AZ::Uuid& presetId) { AZStd::lock_guard lock(m_presetMapLock); @@ -212,7 +179,7 @@ namespace ImageProcessingAtom } } - return "Unknown"; + return {}; } void BuilderSettingManager::ClearSettings() @@ -296,7 +263,7 @@ namespace ImageProcessingAtom AZ_Warning("Image Processing", presetName == preset.GetPresetName(), "Preset file name '%s' is not" " same as preset name '%s'. Using preset file name as preset name", - filePath.toUtf8().data(), preset.GetPresetName().c_str()); + filePath.toUtf8().data(), preset.GetPresetName().GetCStr()); preset.SetPresetName(presetName); @@ -442,8 +409,20 @@ namespace ImageProcessingAtom return AZStd::string(); } - AZ::Uuid BuilderSettingManager::GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr imageFromFile) + bool BuilderSettingManager::IsValidPreset(PresetName presetName) const + { + if (presetName.IsEmpty()) + { + return false; + } + + return m_presets.find(presetName) != m_presets.end(); + } + + PresetName BuilderSettingManager::GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr imageFromFile) { + PresetName emptyPreset; + //load the image to get its size for later use IImageObjectPtr image = imageFromFile; //if the input image is empty we will try to load it from the path @@ -454,34 +433,37 @@ namespace ImageProcessingAtom if (image == nullptr) { - return AZ::Uuid::CreateNull(); + return emptyPreset; } //get file mask of this image file AZStd::string fileMask = GetFileMask(imageFilePath); - AZ::Uuid outPreset = AZ::Uuid::CreateNull(); + PresetName outPreset = emptyPreset; //check default presets for some file masks if (m_defaultPresetByFileMask.find(fileMask) != m_defaultPresetByFileMask.end()) { outPreset = m_defaultPresetByFileMask[fileMask]; + if (!IsValidPreset(outPreset)) + { + outPreset = emptyPreset; + } } //use the preset filter map to find - if (outPreset.IsNull() && !fileMask.empty()) + if (outPreset.IsEmpty() && !fileMask.empty()) { auto& presetFilterMap = GetPresetFilterMap(); if (presetFilterMap.find(fileMask) != presetFilterMap.end()) { - AZStd::string presetName = *(presetFilterMap.find(fileMask)->second.begin()); - outPreset = GetPresetIdFromName(presetName); + outPreset = *(presetFilterMap.find(fileMask)->second.begin()); } } const PresetSettings* presetInfo = nullptr; - if (!outPreset.IsNull()) + if (!outPreset.IsEmpty()) { presetInfo = GetPreset(outPreset); @@ -491,12 +473,12 @@ namespace ImageProcessingAtom // If it's not a latitude-longitude map or it doesn't match any cubemap layouts then reset its preset if (!IsValidLatLongMap(image) && CubemapLayout::GetCubemapLayoutInfo(image) == nullptr) { - outPreset = AZ::Uuid::CreateNull(); + outPreset = emptyPreset; } } } - if (outPreset.IsNull()) + if (outPreset == emptyPreset) { if (image->GetAlphaContent() == EAlphaContent::eAlphaContent_Absent) { @@ -521,7 +503,7 @@ namespace ImageProcessingAtom } else { - AZ_Warning("Image Processing", false, "Image dimensions are not compatible with preset '%s'. The default preset will be used.", presetInfo->m_name.c_str()); + AZ_Warning("Image Processing", false, "Image dimensions are not compatible with preset '%s'. The default preset will be used.", presetInfo->m_name.GetCStr()); } } @@ -540,7 +522,7 @@ namespace ImageProcessingAtom for (const auto& element : m_presets) { const PresetEntry& presetEntry = element.second; - AZStd::string fileName = AZStd::string::format("%s.preset", presetEntry.m_multiPreset.GetDefaultPreset().m_name.c_str()); + AZStd::string fileName = AZStd::string::format("%s.preset", presetEntry.m_multiPreset.GetDefaultPreset().m_name.GetCStr()); AZStd::string filePath; if (!AzFramework::StringFunc::Path::Join(outputFolder.data(), fileName.c_str(), filePath)) { @@ -552,7 +534,7 @@ namespace ImageProcessingAtom if (!result.IsSuccess()) { AZ_Warning("Image Processing", false, "Failed to save preset '%s' to file '%s'. Error: %s", - presetEntry.m_multiPreset.GetDefaultPreset().m_name.c_str(), filePath.c_str(), result.GetError().c_str()); + presetEntry.m_multiPreset.GetDefaultPreset().m_name.GetCStr(), filePath.c_str(), result.GetError().c_str()); } } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h index b0a7e103be..3bbb71ea43 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h @@ -49,7 +49,6 @@ namespace ImageProcessingAtom static void DestroyInstance(); static void Reflect(AZ::ReflectContext* context); - const PresetSettings* GetPreset(const AZ::Uuid presetId, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr); const PresetSettings* GetPreset(const PresetName& presetName, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr); const BuilderSettings* GetBuilderSetting(const PlatformName& platform); @@ -60,10 +59,7 @@ namespace ImageProcessingAtom //! Return A map of preset settings based on their filemasks. //! @key filemask string, empty string means no filemask //! @value set of preset setting names supporting the specified filemask - const AZStd::map>& GetPresetFilterMap(); - - //!Find preset id list based on the preset name. - const AZ::Uuid GetPresetIdFromName(const PresetName& presetName); + const AZStd::map>& GetPresetFilterMap(); //! Find preset name based on the preset id. const PresetName GetPresetNameFromId(const AZ::Uuid& presetId); @@ -84,8 +80,10 @@ namespace ImageProcessingAtom //! Find a suitable preset a given image file. //! @param imageFilePath: Filepath string of the image file. The function may load the image from the path for better detection //! @param image: an optional image object which can be used for preset selection if there is no match based file mask. - //! @return suggested preset uuid. - AZ::Uuid GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr image = nullptr); + //! @return suggested preset name. + PresetName GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr image = nullptr); + + bool IsValidPreset(PresetName presetName) const; bool DoesSupportPlatform(AZStd::string_view platformId); @@ -131,27 +129,27 @@ namespace ImageProcessingAtom // Builder settings for each platform AZStd::map m_builderSettings; - AZStd::map m_presets; + AZStd::unordered_map m_presets; // Cached list of presets mapped by their file masks. // @Key file mask, use empty string to indicate all presets without filtering // @Value set of preset names that matches the file mask - AZStd::map > m_presetFilterMap; + AZStd::map > m_presetFilterMap; // A mutex to protect when modifying any map in this manager AZStd::recursive_mutex m_presetMapLock; // Default presets for certain file masks - AZStd::map m_defaultPresetByFileMask; + AZStd::map m_defaultPresetByFileMask; // Default preset for none power of two image - AZ::Uuid m_defaultPresetNonePOT; + PresetName m_defaultPresetNonePOT; // Default preset for power of two - AZ::Uuid m_defaultPreset; + PresetName m_defaultPreset; // Default preset for power of two with alpha - AZ::Uuid m_defaultPresetAlpha; + PresetName m_defaultPresetAlpha; // Image builder's version AZStd::string m_analysisFingerprint; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/CubemapSettings.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/CubemapSettings.h index 281075b80c..9135a0f4d1 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/CubemapSettings.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/CubemapSettings.h @@ -43,14 +43,14 @@ namespace ImageProcessingAtom // generate an IBL specular cubemap bool m_generateIBLSpecular = false; - // the UUID of the preset to be used for generating the IBL specular cubemap - AZ::Uuid m_iblSpecularPreset = AZ::Uuid::CreateNull(); + // the name of the preset to be used for generating the IBL specular cubemap + PresetName m_iblSpecularPreset; // generate an IBL diffuse cubemap bool m_generateIBLDiffuse = false; - // the UUID of the preset to be used for generating the IBL diffuse cubemap - AZ::Uuid m_iblDiffusePreset = AZ::Uuid::CreateNull(); + // the name of the preset to be used for generating the IBL diffuse cubemap + PresetName m_iblDiffusePreset; // "cm_requiresconvolve", convolve the cubemap mips bool m_requiresConvolve = true; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/ImageProcessingDefines.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/ImageProcessingDefines.h index d735608db5..e421715995 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/ImageProcessingDefines.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/ImageProcessingDefines.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -38,7 +39,8 @@ namespace ImageProcessingAtom #define STRING_OUTCOME_ERROR(error) AZ::Failure(AZStd::string(error)) // Common typedefs (with dependent forward-declarations) - typedef AZStd::string PlatformName, PresetName, FileMask; + typedef AZStd::string PlatformName, FileMask; + typedef AZ::Name PresetName; typedef AZStd::vector PlatformNameVector; typedef AZStd::list PlatformNameList; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h index b7ef72753e..941437bbf4 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/PresetSettings.h @@ -31,7 +31,8 @@ namespace ImageProcessingAtom bool operator== (const PresetSettings& other) const; static void Reflect(AZ::ReflectContext* context); - //unique id for the preset + // unique id for the preset + // this uuid will be deprecated. The preset name will be used as an unique id for the preset AZ::Uuid m_uuid = 0; PresetName m_name; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp index 863b3358c5..29d9b21775 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.cpp @@ -23,7 +23,7 @@ namespace ImageProcessingAtom const char* TextureSettings::ExtensionName = ".assetinfo"; TextureSettings::TextureSettings() - : m_preset(0) + : m_presetId(0) , m_sizeReduceLevel(0) , m_suppressEngineReduce(false) , m_enableMipmap(true) @@ -45,8 +45,9 @@ namespace ImageProcessingAtom if (serialize) { serialize->Class() - ->Version(1) - ->Field("PresetID", &TextureSettings::m_preset) + ->Version(2) + ->Field("PresetID", &TextureSettings::m_presetId) + ->Field("Preset", &TextureSettings::m_preset) ->Field("SizeReduceLevel", &TextureSettings::m_sizeReduceLevel) ->Field("EngineReduce", &TextureSettings::m_suppressEngineReduce) ->Field("EnableMipmap", &TextureSettings::m_enableMipmap) @@ -169,9 +170,9 @@ namespace ImageProcessingAtom return 0.5f - fVal / 100.0f; } - void TextureSettings::ApplyPreset(AZ::Uuid presetId) + void TextureSettings::ApplyPreset(PresetName presetName) { - const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(presetId); + const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(presetName); if (presetSetting != nullptr) { m_sizeReduceLevel = presetSetting->m_sizeReduceLevel; @@ -181,11 +182,11 @@ namespace ImageProcessingAtom m_mipGenType = presetSetting->m_mipmapSetting->m_type; } - m_preset = presetId; + m_preset = presetName; } else { - AZ_Error("Image Processing", false, "Cannot set an invalid preset %s!", presetId.ToString().c_str()); + AZ_Error("Image Processing", false, "Cannot set an invalid preset %s!", presetName.GetCStr()); } } @@ -199,6 +200,14 @@ namespace ImageProcessingAtom } textureSettingPtrOut = *loadedTextureSettingPtr; + + // In old format, the preset name doesn't exist. Using preset id to get preset name + // We can remove this when we fully deprecate the preset uuid + if (textureSettingPtrOut.m_preset.IsEmpty()) + { + textureSettingPtrOut.m_preset = BuilderSettingManager::Instance()->GetPresetNameFromId(textureSettingPtrOut.m_presetId); + } + return AZ::Success(AZStd::string()); } @@ -216,7 +225,7 @@ namespace ImageProcessingAtom { MultiplatformTextureSettings settings; PlatformNameList platformsList = BuilderSettingManager::Instance()->GetPlatformList(); - AZ::Uuid suggestedPreset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilepath); + PresetName suggestedPreset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilepath); for (PlatformName& platform : platformsList) { TextureSettings textureSettings; @@ -234,7 +243,7 @@ namespace ImageProcessingAtom if (overrideIter == baseTextureSettings.m_platfromOverrides.end()) { return STRING_OUTCOME_ERROR(AZStd::string::format("TextureSettings preset [%s] does not have override for platform [%s]", - baseTextureSettings.m_preset.ToString().c_str(), platformName.c_str())); + baseTextureSettings.m_preset.GetCStr(), platformName.c_str())); } AZ::DataPatch& platformOverride = const_cast(overrideIter->second); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.h index 5bf4fa0d86..24a2f07bfb 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/TextureSettings.h @@ -43,7 +43,7 @@ namespace ImageProcessingAtom /** * Apply value of some preset settings to this texture settings */ - void ApplyPreset(AZ::Uuid presetId); + void ApplyPreset(PresetName presetName); /** * Performs a comprehensive comparison between two TextureSettings instances. @@ -116,7 +116,10 @@ namespace ImageProcessingAtom static const size_t s_MaxMipMaps = 6; // uuid of selected preset for this texture - AZ::Uuid m_preset; + // We are deprecating preset UUID and switching to preset name as an unique id + AZ::Uuid m_presetId; + + PresetName m_preset; // texture size reduce level. the value of this variable will override the same variable in PresetSettings unsigned int m_sizeReduceLevel; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp index c6f1398703..067faf3dab 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp @@ -165,17 +165,17 @@ namespace ImageProcessingAtomEditor // Get the preset id from one platform. The preset id for each platform should always be same AZ_Assert(m_settingsMap.size() > 0, "There is no platform information"); - AZ::Uuid presetId = m_settingsMap.begin()->second.m_preset; - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetId); + PresetName presetName = m_settingsMap.begin()->second.m_preset; + const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetName); if (!preset) { - AZ_Warning("Texture Editor", false, "Cannot find preset %s! Will assign a suggested one for the texture.", presetId.ToString().c_str()); - presetId = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath, m_img); + AZ_Warning("Texture Editor", false, "Cannot find preset %s! Will assign a suggested one for the texture.", presetName.GetCStr()); + presetName = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath, m_img); for (auto& settingIter : m_settingsMap) { - settingIter.second.ApplyPreset(presetId); + settingIter.second.ApplyPreset(presetName); } } } @@ -198,25 +198,18 @@ namespace ImageProcessingAtomEditor } else { - AZ_Error("Texture Editor", false, "Texture Preset %s is not found!", textureSetting.m_preset.ToString().c_str()); + AZ_Error("Texture Editor", false, "Texture Preset %s is not found!", textureSetting.m_preset.GetCStr()); } } } - void EditorTextureSetting::SetToPreset(const AZStd::string& presetName) + void EditorTextureSetting::SetToPreset(const PresetName& presetName) { m_overrideFromPreset = false; - AZ::Uuid presetId = BuilderSettingManager::Instance()->GetPresetIdFromName(presetName); - if (presetId.IsNull()) - { - AZ_Error("Texture Editor", false, "Texture Preset %s has no associated UUID.", presetName.c_str()); - return; - } - for (auto& settingIter : m_settingsMap) { - settingIter.second.ApplyPreset(presetId); + settingIter.second.ApplyPreset(presetName); } } @@ -305,7 +298,7 @@ namespace ImageProcessingAtomEditor { it.second.m_enableMipmap = false; enabled = false; - AZ_Error("Texture Editor", false, "Preset %s does not support mipmap!", preset->m_name.c_str()); + AZ_Error("Texture Editor", false, "Preset %s does not support mipmap!", preset->m_name.GetCStr()); } } else diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.h index 24efb7a70a..78bc403906 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.h @@ -62,7 +62,7 @@ namespace ImageProcessingAtomEditor void SetIsOverrided(); - void SetToPreset(const AZStd::string& presetName); + void SetToPreset(const ImageProcessingAtom::PresetName& presetName); //Get the texture setting on certain platform ImageProcessingAtom::TextureSettings& GetMultiplatformTextureSetting(const AZStd::string& platform = ""); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp index 2d5c89e8f5..a5b942fa58 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/PresetInfoPopup.cpp @@ -66,7 +66,7 @@ namespace ImageProcessingAtomEditor } presetInfoText += QString("UUID: %1\n").arg(presetSettings->m_uuid.ToString().c_str()); - presetInfoText += QString("Name: %1\n").arg(presetSettings->m_name.c_str()); + presetInfoText += QString("Name: %1\n").arg(presetSettings->m_name.GetCStr()); presetInfoText += QString("Generate IBL Only: %1\n").arg(presetSettings->m_generateIBLOnly ? "True" : "False"); presetInfoText += QString("RGB Weight: %1\n").arg(RGBWeightToString(presetSettings->m_rgbWeight)); presetInfoText += QString("Source ColorSpace: %1\n").arg(ColorSpaceToString(presetSettings->m_srcColorSpace)); @@ -98,9 +98,9 @@ namespace ImageProcessingAtomEditor presetInfoText += QString("Mip Slope: %1\n").arg(presetSettings->m_cubemapSetting->m_mipSlope); presetInfoText += QString("Edge Fixup: %1\n").arg(presetSettings->m_cubemapSetting->m_edgeFixup); presetInfoText += QString("Generate IBL Specular: %1\n").arg(presetSettings->m_cubemapSetting->m_generateIBLSpecular ? "True" : "False"); - presetInfoText += QString("IBL Specular Preset: %1\n").arg(presetSettings->m_cubemapSetting->m_iblSpecularPreset.ToString().c_str()); + presetInfoText += QString("IBL Specular Preset: %1\n").arg(presetSettings->m_cubemapSetting->m_iblSpecularPreset.GetCStr()); presetInfoText += QString("Generate IBL Diffuse: %1\n").arg(presetSettings->m_cubemapSetting->m_generateIBLDiffuse ? "True" : "False"); - presetInfoText += QString("IBL Diffuse Preset: %1\n").arg(presetSettings->m_cubemapSetting->m_iblDiffusePreset.ToString().c_str()); + presetInfoText += QString("IBL Diffuse Preset: %1\n").arg(presetSettings->m_cubemapSetting->m_iblDiffusePreset.GetCStr()); presetInfoText += QString("Requires Convolve: %1\n").arg(presetSettings->m_cubemapSetting->m_requiresConvolve ? "True" : "False"); presetInfoText += QString("SubId: %1\n").arg(presetSettings->m_cubemapSetting->m_subId); } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.cpp index 6df7b8f3df..43f99c4b60 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.cpp @@ -104,7 +104,7 @@ namespace ImageProcessingAtomEditor } } - QString ResolutionSettingItemWidget::GetFinalFormat([[maybe_unused]] const AZ::Uuid& presetId) + QString ResolutionSettingItemWidget::GetFinalFormat([[maybe_unused]] const ImageProcessingAtom::PresetName& preset) { if (m_preset && m_preset->m_pixelFormat >= 0 && m_preset->m_pixelFormat < ePixelFormat_Count) { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.h index dde3a0e32c..ce66ee1cd9 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/ResolutionSettingItemWidget.h @@ -60,7 +60,7 @@ namespace ImageProcessingAtomEditor void SetupFormatComboBox(); void SetupResolutionInfo(); void RefreshUI(); - QString GetFinalFormat(const AZ::Uuid& presetId); + QString GetFinalFormat(const ImageProcessingAtom::PresetName& preset); QScopedPointer m_ui; ResoultionWidgetType m_type; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.cpp index 5b34133f96..e50d95b907 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.cpp @@ -29,7 +29,7 @@ namespace ImageProcessingAtomEditor m_presetList.clear(); auto& presetFilterMap = BuilderSettingManager::Instance()->GetPresetFilterMap(); - AZStd::set noFilterPresetList; + AZStd::unordered_set noFilterPresetList; // Check if there is any filtered preset list first for(auto& presetFilter : presetFilterMap) @@ -40,7 +40,7 @@ namespace ImageProcessingAtomEditor } else if (IsMatchingWithFileMask(m_textureSetting->m_textureName, presetFilter.first)) { - for(const AZStd::string& presetName : presetFilter.second) + for(const auto& presetName : presetFilter.second) { m_presetList.insert(presetName); } @@ -52,18 +52,18 @@ namespace ImageProcessingAtomEditor m_presetList = noFilterPresetList; } - foreach (const AZStd::string& presetName, m_presetList) + foreach (const auto& presetName, m_presetList) { - m_ui->presetComboBox->addItem(QString(presetName.c_str())); + m_ui->presetComboBox->addItem(QString(presetName.GetCStr())); } // Set current preset - const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; + const auto& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset); if (presetSetting) { - m_ui->presetComboBox->setCurrentText(presetSetting->m_name.c_str()); + m_ui->presetComboBox->setCurrentText(presetSetting->m_name.GetCStr()); QObject::connect(m_ui->presetComboBox, static_cast(&QComboBox::currentIndexChanged), this, &TexturePresetSelectionWidget::OnChangePreset); // Suppress engine reduction checkbox @@ -109,20 +109,20 @@ namespace ImageProcessingAtomEditor void TexturePresetSelectionWidget::OnRestButton() { - m_textureSetting->SetToPreset(AZStd::string(m_ui->presetComboBox->currentText().toUtf8().data())); + m_textureSetting->SetToPreset(PresetName(m_ui->presetComboBox->currentText().toUtf8().data())); EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, true, BuilderSettingManager::s_defaultPlatform); } void TexturePresetSelectionWidget::OnChangePreset(int index) { QString text = m_ui->presetComboBox->itemText(index); - m_textureSetting->SetToPreset(AZStd::string(text.toUtf8().data())); + m_textureSetting->SetToPreset(PresetName(text.toUtf8().data())); EditorInternalNotificationBus::Broadcast(&EditorInternalNotificationBus::Events::OnEditorSettingsChanged, true, BuilderSettingManager::s_defaultPlatform); } void ImageProcessingAtomEditor::TexturePresetSelectionWidget::OnPresetInfoButton() { - const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; + const auto& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset); m_presetPopup.reset(new PresetInfoPopup(presetSetting, this)); m_presetPopup->installEventFilter(this); @@ -136,7 +136,7 @@ namespace ImageProcessingAtomEditor bool oldState = m_ui->serCheckBox->blockSignals(true); m_ui->serCheckBox->setChecked(m_textureSetting->GetMultiplatformTextureSetting().m_suppressEngineReduce); // If the preset's SER is true, texture setting should not override - const AZ::Uuid& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; + const auto& currPreset = m_textureSetting->GetMultiplatformTextureSetting().m_preset; const PresetSettings* presetSetting = BuilderSettingManager::Instance()->GetPreset(currPreset); if (presetSetting) { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.h index bbb6e6e7df..ad819840f9 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/TexturePresetSelectionWidget.h @@ -49,7 +49,7 @@ namespace ImageProcessingAtomEditor private: QScopedPointer m_ui; - AZStd::set m_presetList; + AZStd::unordered_set m_presetList; EditorTextureSetting* m_textureSetting; QScopedPointer m_presetPopup; bool IsMatchingWithFileMask(const AZStd::string& filename, const AZStd::string& fileMask); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp index c688b0b20c..a489c8da5e 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp @@ -74,7 +74,7 @@ namespace ImageProcessingAtom builderDescriptor.m_busId = azrtti_typeid(); builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_version = 24; // [SPEC-7821] + builderDescriptor.m_version = 25; // [ATOM-16575] builderDescriptor.m_analysisFingerprint = ImageProcessingAtom::BuilderSettingManager::Instance()->GetAnalysisFingerprint(); m_imageBuilder.BusConnect(builderDescriptor.m_busId); AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor); @@ -164,7 +164,7 @@ namespace ImageProcessingAtom AZStd::vector outProducts; AZStd::string_view presetFilePath; - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetName, platformName, &presetFilePath); + const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(PresetName(presetName), platformName, &presetFilePath); if (preset == nullptr) { AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str()); @@ -173,7 +173,7 @@ namespace ImageProcessingAtom AZStd::unique_ptr desc = AZStd::make_unique(); TextureSettings& textureSettings = desc->m_textureSetting; - textureSettings.m_preset = preset->m_uuid; + textureSettings.m_preset = preset->m_name; desc->m_inputImage = imageObject; desc->m_presetSetting = *preset; desc->m_isPreview = false; @@ -204,7 +204,7 @@ namespace ImageProcessingAtom bool BuilderPluginComponent::IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName) { AZStd::string_view filePath; - const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetName, platformName, &filePath); + const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(PresetName(presetName), platformName, &filePath); if (preset == nullptr) { AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str()); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp index 5995146c59..977359e4f6 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp @@ -186,12 +186,12 @@ namespace ImageProcessingAtom { // check and generate IBL specular and diffuse, if necessary AZStd::unique_ptr& cubemapSettings = m_input->m_presetSetting.m_cubemapSetting; - if (cubemapSettings->m_generateIBLSpecular && !cubemapSettings->m_iblSpecularPreset.IsNull()) + if (cubemapSettings->m_generateIBLSpecular && !cubemapSettings->m_iblSpecularPreset.IsEmpty()) { CreateIBLCubemap(cubemapSettings->m_iblSpecularPreset, SpecularCubemapSuffix, m_iblSpecularCubemapImage); } - if (cubemapSettings->m_generateIBLDiffuse && !cubemapSettings->m_iblDiffusePreset.IsNull()) + if (cubemapSettings->m_generateIBLDiffuse && !cubemapSettings->m_iblDiffusePreset.IsEmpty()) { CreateIBLCubemap(cubemapSettings->m_iblDiffusePreset, DiffuseCubemapSuffix, m_iblDiffuseCubemapImage); } @@ -367,7 +367,7 @@ namespace ImageProcessingAtom else { AZ_TracePrintf("Image Processing", "Image converted with preset [%s] [%s] and saved to [%s] (%d bytes) taking %f seconds\n", - m_input->m_presetSetting.m_name.c_str(), + m_input->m_presetSetting.m_name.GetCStr(), m_input->m_filePath.c_str(), m_input->m_outputFolder.c_str(), sizeTotal, m_processTime); } @@ -834,7 +834,7 @@ namespace ImageProcessingAtom // if get textureSetting failed, use the default texture setting, and find suitable preset for this file // in very rare user case, an old texture setting file may not have a preset. We fix it over here too. - if (textureSettings.m_preset.IsNull()) + if (textureSettings.m_preset.IsEmpty()) { textureSettings.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilePath, srcImage); } @@ -845,9 +845,7 @@ namespace ImageProcessingAtom if (preset == nullptr) { - AZStd::string uuidStr; - textureSettings.m_preset.ToString(uuidStr); - AZ_Assert(false, "%s cannot find image preset with ID %s.", imageFilePath.c_str(), uuidStr.c_str()); + AZ_Assert(false, "%s cannot find image preset %s.", imageFilePath.c_str(), textureSettings.m_preset.GetCStr()); return nullptr; } @@ -875,11 +873,11 @@ namespace ImageProcessingAtom return process; } - void ImageConvertProcess::CreateIBLCubemap(AZ::Uuid presetUUID, const char* fileNameSuffix, IImageObjectPtr& cubemapImage) + void ImageConvertProcess::CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage) { const AZStd::string& platformId = m_input->m_platform; AZStd::string_view filePath; - const PresetSettings* presetSettings = BuilderSettingManager::Instance()->GetPreset(presetUUID, platformId, &filePath); + const PresetSettings* presetSettings = BuilderSettingManager::Instance()->GetPreset(preset, platformId, &filePath); if (presetSettings == nullptr) { AZ_Error("Image Processing", false, "Couldn't find preset for IBL cubemap generation"); @@ -900,7 +898,7 @@ namespace ImageProcessingAtom // the diffuse irradiance cubemap is generated with a separate ImageConvertProcess TextureSettings textureSettings = m_input->m_textureSetting; - textureSettings.m_preset = presetUUID; + textureSettings.m_preset = preset; AZStd::unique_ptr desc = AZStd::make_unique(); desc->m_presetSetting = *presetSettings; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h index 6ab866ee09..eaf05c3280 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h @@ -163,7 +163,7 @@ namespace ImageProcessingAtom bool FillCubemapMipmaps(); //IBL cubemap generation, this creates a separate ImageConvertProcess - void CreateIBLCubemap(AZ::Uuid presetUUID, const char* fileNameSuffix, IImageObjectPtr& cubemapImage); + void CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage); //convert color space to linear with pixel format rgba32f bool ConvertToLinear(); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImagePreview.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImagePreview.cpp index b73157744c..f51741eba9 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImagePreview.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImagePreview.cpp @@ -43,7 +43,7 @@ namespace ImageProcessingAtom m_inputImage = IImageObjectPtr(LoadImageFromFile(m_imageFileName)); } // Get preset if the setting in texture is changed - if (m_presetSetting == nullptr || m_presetSetting->m_uuid != m_textureSetting->m_preset) + if (m_presetSetting == nullptr || m_presetSetting->m_name != m_textureSetting->m_preset) { m_presetSetting = BuilderSettingManager::Instance()->GetPreset(m_textureSetting->m_preset); } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index 9e4aa83908..3e0bbd89eb 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -145,6 +146,8 @@ namespace UnitTest AZ::Data::AssetManager::Descriptor desc; AZ::Data::AssetManager::Create(desc); + AZ::NameDictionary::Create(); + m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler()); m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler()); m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler()); @@ -153,6 +156,7 @@ namespace UnitTest //prepare reflection m_context = AZStd::make_unique(); + AZ::Name::Reflect(m_context.get()); BuilderPluginComponent::Reflect(m_context.get()); AZ::DataPatch::Reflect(m_context.get()); AZ::RHI::ReflectSystemComponent::Reflect(m_context.get()); @@ -164,6 +168,7 @@ namespace UnitTest m_jsonRegistrationContext = AZStd::make_unique(); m_jsonSystemComponent = AZStd::make_unique(); m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get()); + AZ::Name::Reflect(m_jsonRegistrationContext.get()); BuilderPluginComponent::Reflect(m_jsonRegistrationContext.get()); // Setup job context for job system @@ -227,14 +232,18 @@ namespace UnitTest m_jsonRegistrationContext->EnableRemoveReflection(); m_jsonSystemComponent->Reflect(m_jsonRegistrationContext.get()); BuilderPluginComponent::Reflect(m_jsonRegistrationContext.get()); + AZ::Name::Reflect(m_jsonRegistrationContext.get()); m_jsonRegistrationContext->DisableRemoveReflection(); m_jsonRegistrationContext.reset(); m_jsonSystemComponent.reset(); m_context.reset(); BuilderSettingManager::DestroyInstance(); + CPixelFormats::DestroyInstance(); + AZ::NameDictionary::Destroy(); + AZ::Data::AssetManager::Destroy(); AZ::AllocatorInstance::Destroy(); @@ -1027,7 +1036,7 @@ namespace UnitTest // Fill-in structure with test data TextureSettings fakeTextureSettings; - fakeTextureSettings.m_preset = AZ::Uuid::CreateRandom(); + fakeTextureSettings.m_preset = "testPreset"; fakeTextureSettings.m_sizeReduceLevel = 0; fakeTextureSettings.m_suppressEngineReduce = true; fakeTextureSettings.m_enableMipmap = false; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/TestAssets/1024x1024_24bit.tif.exportsettings b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/TestAssets/1024x1024_24bit.tif.exportsettings deleted file mode 100644 index 7bce3041b9..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/TestAssets/1024x1024_24bit.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /bumptype=none /M=62,18,32,83,50,50 /preset=Diffuse_highQ /mipgentype=kaiser /reduce="android:0,ios:3,mac:0,pc:4,provo:1" /ser=0 diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithOpacity.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithOpacity.preset deleted file mode 100644 index 346f0f8cac..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithOpacity.preset +++ /dev/null @@ -1,104 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{7BB7BC6C-D3DA-4184-AC42-BCD8C57DE565}", - "Name": "AlbedoWithOpacity", - "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], - "PixelFormat": "BC7t", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{7BB7BC6C-D3DA-4184-AC42-BCD8C57DE565}", - "Name": "AlbedoWithOpacity", - "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{7BB7BC6C-D3DA-4184-AC42-BCD8C57DE565}", - "Name": "AlbedoWithOpacity", - "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{7BB7BC6C-D3DA-4184-AC42-BCD8C57DE565}", - "Name": "AlbedoWithOpacity", - "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], - "PixelFormat": "BC3", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{7BB7BC6C-D3DA-4184-AC42-BCD8C57DE565}", - "Name": "AlbedoWithOpacity", - "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], - "PixelFormat": "BC7t", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/CloudShadows.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/CloudShadows.preset deleted file mode 100644 index 8d1105cdfc..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/CloudShadows.preset +++ /dev/null @@ -1,44 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{884B5F7C-44AC-4E9E-8B8A-559D098BE2C7}", - "Name": "CloudShadows", - "DestColor": "Linear", - "PixelFormat": "BC4", - "IsPowerOf2": true - }, - "PlatformsPresets": { - "android": { - "UUID": "{884B5F7C-44AC-4E9E-8B8A-559D098BE2C7}", - "Name": "CloudShadows", - "DestColor": "Linear", - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true - }, - "ios": { - "UUID": "{884B5F7C-44AC-4E9E-8B8A-559D098BE2C7}", - "Name": "CloudShadows", - "DestColor": "Linear", - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true - }, - "mac": { - "UUID": "{884B5F7C-44AC-4E9E-8B8A-559D098BE2C7}", - "Name": "CloudShadows", - "DestColor": "Linear", - "PixelFormat": "BC4", - "IsPowerOf2": true - }, - "provo": { - "UUID": "{884B5F7C-44AC-4E9E-8B8A-559D098BE2C7}", - "Name": "CloudShadows", - "DestColor": "Linear", - "PixelFormat": "BC4", - "IsPowerOf2": true - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ColorChart.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/ColorChart.preset deleted file mode 100644 index 5f0480cee7..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/ColorChart.preset +++ /dev/null @@ -1,64 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{0A17A85F-07EE-48A0-8BF8-D42F0A5E0B3C}", - "Name": "ColorChart", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_cch" - ], - "PixelFormat": "R8G8B8X8", - "IsColorChart": true - }, - "PlatformsPresets": { - "android": { - "UUID": "{0A17A85F-07EE-48A0-8BF8-D42F0A5E0B3C}", - "Name": "ColorChart", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_cch" - ], - "PixelFormat": "R8G8B8X8", - "IsColorChart": true - }, - "ios": { - "UUID": "{0A17A85F-07EE-48A0-8BF8-D42F0A5E0B3C}", - "Name": "ColorChart", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_cch" - ], - "PixelFormat": "R8G8B8X8", - "IsColorChart": true - }, - "mac": { - "UUID": "{0A17A85F-07EE-48A0-8BF8-D42F0A5E0B3C}", - "Name": "ColorChart", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_cch" - ], - "PixelFormat": "R8G8B8X8", - "IsColorChart": true - }, - "provo": { - "UUID": "{0A17A85F-07EE-48A0-8BF8-D42F0A5E0B3C}", - "Name": "ColorChart", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_cch" - ], - "PixelFormat": "R8G8B8X8", - "IsColorChart": true - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness.preset deleted file mode 100644 index 5bfea9a376..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness.preset +++ /dev/null @@ -1,79 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{5096FC7B-0B2D-4466-9943-AD59922968E8}", - "Name": "Detail_MergedAlbedoNormalsSmoothness", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "PixelFormat": "BC7", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{5096FC7B-0B2D-4466-9943-AD59922968E8}", - "Name": "Detail_MergedAlbedoNormalsSmoothness", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{5096FC7B-0B2D-4466-9943-AD59922968E8}", - "Name": "Detail_MergedAlbedoNormalsSmoothness", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{5096FC7B-0B2D-4466-9943-AD59922968E8}", - "Name": "Detail_MergedAlbedoNormalsSmoothness", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "PixelFormat": "BC3", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{5096FC7B-0B2D-4466-9943-AD59922968E8}", - "Name": "Detail_MergedAlbedoNormalsSmoothness", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "PixelFormat": "BC7", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness_Lossless.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness_Lossless.preset deleted file mode 100644 index fec11218e8..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Detail_MergedAlbedoNormalsSmoothness_Lossless.preset +++ /dev/null @@ -1,74 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{B6FC1AEF-907C-4157-9A1A-D9960F0E5B9A}", - "Name": "Detail_MergedAlbedoNormalsSmoothness_Lossless", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{B6FC1AEF-907C-4157-9A1A-D9960F0E5B9A}", - "Name": "Detail_MergedAlbedoNormalsSmoothness_Lossless", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{B6FC1AEF-907C-4157-9A1A-D9960F0E5B9A}", - "Name": "Detail_MergedAlbedoNormalsSmoothness_Lossless", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{B6FC1AEF-907C-4157-9A1A-D9960F0E5B9A}", - "Name": "Detail_MergedAlbedoNormalsSmoothness_Lossless", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{B6FC1AEF-907C-4157-9A1A-D9960F0E5B9A}", - "Name": "Detail_MergedAlbedoNormalsSmoothness_Lossless", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_detail" - ], - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLGlobal.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLGlobal.preset index eb829c3120..717157f2aa 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLGlobal.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLGlobal.preset @@ -15,9 +15,9 @@ ], "CubemapSettings": { "GenerateIBLSpecular": true, - "IBLSpecularPreset": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", + "IBLSpecularPreset": "IBLSpecular", "GenerateIBLDiffuse": true, - "IBLDiffusePreset": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}" + "IBLDiffusePreset": "IBLDiffuse" } } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSkybox.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSkybox.preset index 402fc470eb..eee9af4cea 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSkybox.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSkybox.preset @@ -20,9 +20,9 @@ "CubemapSettings": { "RequiresConvolve": false, "GenerateIBLSpecular": true, - "IBLSpecularPreset": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", + "IBLSpecularPreset": "IBLSpecular", "GenerateIBLDiffuse": true, - "IBLDiffusePreset": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}" + "IBLDiffusePreset": "IBLDiffuse" } }, "PlatformsPresets": { @@ -42,9 +42,9 @@ "CubemapSettings": { "RequiresConvolve": false, "GenerateIBLSpecular": true, - "IBLSpecularPreset": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", + "IBLSpecularPreset": "IBLSpecular", "GenerateIBLDiffuse": true, - "IBLDiffusePreset": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}" + "IBLDiffusePreset": "IBLDiffuse" } }, "ios": { @@ -63,9 +63,9 @@ "CubemapSettings": { "RequiresConvolve": false, "GenerateIBLSpecular": true, - "IBLSpecularPreset": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", + "IBLSpecularPreset": "IBLSpecular", "GenerateIBLDiffuse": true, - "IBLDiffusePreset": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}" + "IBLDiffusePreset": "IBLDiffuse" } }, "mac": { @@ -84,9 +84,9 @@ "CubemapSettings": { "RequiresConvolve": false, "GenerateIBLSpecular": true, - "IBLSpecularPreset": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", + "IBLSpecularPreset": "IBLSpecular", "GenerateIBLDiffuse": true, - "IBLDiffusePreset": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}" + "IBLDiffusePreset": "IBLDiffuse" } }, "provo": { @@ -105,9 +105,9 @@ "CubemapSettings": { "RequiresConvolve": false, "GenerateIBLSpecular": true, - "IBLSpecularPreset": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", + "IBLSpecularPreset": "IBLSpecular", "GenerateIBLDiffuse": true, - "IBLDiffusePreset": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}" + "IBLDiffusePreset": "IBLDiffuse" } } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ImageBuilder.settings b/Gems/Atom/Asset/ImageProcessingAtom/Config/ImageBuilder.settings index c513e05a97..466ac4b71d 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/ImageBuilder.settings +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/ImageBuilder.settings @@ -43,29 +43,25 @@ } }, "DefaultPresetsByFileMask": { - "_basecolor": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", - "_cch": "{0A17A85F-07EE-48A0-8BF8-D42F0A5E0B3C}", - "_ccm": "{2174E04B-73BB-4DF1-8961-4900DC3C9D72}", - "_cm": "{A13B2FCE-2F6A-4634-B112-5A0A912B50CE}", - "_ddn": "{508B21D5-5250-4003-97EC-1CF28D571ACF}", - "_ddna": "{6EE749F4-846E-4F7A-878C-F211F85EA59F}", - "_diff": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", - "_diffuse": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", - "_glossness": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "_ibldiffusecm": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}", - "_iblskyboxcm": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}", - "_iblglobalcm": "{A13B2FCE-2F6A-4634-B112-5A0A912B50CE}", - "_iblspecularcm": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", - "_metallic": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "_normal": "{508B21D5-5250-4003-97EC-1CF28D571ACF}", - "_refl": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "_roughness": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "_skyboxcm": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}", - "_spec": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "_specular": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}" + "_basecolor": "Albedo", + "_diff": "Albedo", + "_diffuse": "Albedo", + "_ddn": "Normals", + "_normal": "Normals", + "_ddna": "NormalsWithSmoothness", + "_glossness": "Reflectance", + "_spec": "Reflectance", + "_specular": "Reflectance", + "_metallic": "Reflectance", + "_refl": "Reflectance", + "_roughness": "Reflectance", + "_ibldiffusecm": "IBLDiffuse", + "_iblskyboxcm": "IBLSkybox", + "_iblspecularcm": "IBLSpecular", + "_skyboxcm": "Skybox" }, - "DefaultPreset": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", - "DefaultPresetAlpha": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}", - "DefaultPresetNonePOT": "{C659D222-F56B-4B61-A2F8-C1FA547F3C39}" + "DefaultPreset": "Albedo", + "DefaultPresetAlpha": "AlbedoWithGenericAlpha", + "DefaultPresetNonePOT": "ReferenceImage" } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LensOptics.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/LensOptics.preset deleted file mode 100644 index d277785151..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LensOptics.preset +++ /dev/null @@ -1,34 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{3000A993-0A04-4E08-A813-DFB1A47A0980}", - "Name": "LensOptics", - "PixelFormat": "BC1" - }, - "PlatformsPresets": { - "android": { - "UUID": "{3000A993-0A04-4E08-A813-DFB1A47A0980}", - "Name": "LensOptics", - "PixelFormat": "ASTC_4x4" - }, - "ios": { - "UUID": "{3000A993-0A04-4E08-A813-DFB1A47A0980}", - "Name": "LensOptics", - "PixelFormat": "ASTC_4x4" - }, - "mac": { - "UUID": "{3000A993-0A04-4E08-A813-DFB1A47A0980}", - "Name": "LensOptics", - "PixelFormat": "BC1" - }, - "provo": { - "UUID": "{3000A993-0A04-4E08-A813-DFB1A47A0980}", - "Name": "LensOptics", - "PixelFormat": "BC1" - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LightProjector.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/LightProjector.preset deleted file mode 100644 index 4de95427d6..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LightProjector.preset +++ /dev/null @@ -1,59 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{1DFEF41A-D97F-40FB-99D3-C142A3E5225E}", - "Name": "LightProjector", - "DestColor": "Linear", - "PixelFormat": "BC4", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{1DFEF41A-D97F-40FB-99D3-C142A3E5225E}", - "Name": "LightProjector", - "DestColor": "Linear", - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{1DFEF41A-D97F-40FB-99D3-C142A3E5225E}", - "Name": "LightProjector", - "DestColor": "Linear", - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{1DFEF41A-D97F-40FB-99D3-C142A3E5225E}", - "Name": "LightProjector", - "DestColor": "Linear", - "PixelFormat": "BC4", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{1DFEF41A-D97F-40FB-99D3-C142A3E5225E}", - "Name": "LightProjector", - "DestColor": "Linear", - "PixelFormat": "BC4", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LoadingScreen.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/LoadingScreen.preset deleted file mode 100644 index ad0e2ddf06..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LoadingScreen.preset +++ /dev/null @@ -1,34 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{9ED87726-12AB-4BE0-9397-AD62AE56D9E2}", - "Name": "LoadingScreen", - "PixelFormat": "R8G8B8X8" - }, - "PlatformsPresets": { - "android": { - "UUID": "{9ED87726-12AB-4BE0-9397-AD62AE56D9E2}", - "Name": "LoadingScreen", - "PixelFormat": "R8G8B8X8" - }, - "ios": { - "UUID": "{9ED87726-12AB-4BE0-9397-AD62AE56D9E2}", - "Name": "LoadingScreen", - "PixelFormat": "R8G8B8X8" - }, - "mac": { - "UUID": "{9ED87726-12AB-4BE0-9397-AD62AE56D9E2}", - "Name": "LoadingScreen", - "PixelFormat": "R8G8B8X8" - }, - "provo": { - "UUID": "{9ED87726-12AB-4BE0-9397-AD62AE56D9E2}", - "Name": "LoadingScreen", - "PixelFormat": "R8G8B8X8" - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Minimap.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Minimap.preset deleted file mode 100644 index 79dda1977e..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Minimap.preset +++ /dev/null @@ -1,64 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{0D2F4C31-A665-4862-9C63-9E49A58E9A37}", - "Name": "Minimap", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true, - "SizeReduceLevel": 1, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{0D2F4C31-A665-4862-9C63-9E49A58E9A37}", - "Name": "Minimap", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "SizeReduceLevel": 1, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{0D2F4C31-A665-4862-9C63-9E49A58E9A37}", - "Name": "Minimap", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "SizeReduceLevel": 1, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{0D2F4C31-A665-4862-9C63-9E49A58E9A37}", - "Name": "Minimap", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true, - "SizeReduceLevel": 1, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{0D2F4C31-A665-4862-9C63-9E49A58E9A37}", - "Name": "Minimap", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true, - "SizeReduceLevel": 1, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/MuzzleFlash.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/MuzzleFlash.preset deleted file mode 100644 index b02227b454..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/MuzzleFlash.preset +++ /dev/null @@ -1,59 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{8BCC23A5-D08E-458E-B0B3-087C65FA1D31}", - "Name": "MuzzleFlash", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{8BCC23A5-D08E-458E-B0B3-087C65FA1D31}", - "Name": "MuzzleFlash", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{8BCC23A5-D08E-458E-B0B3-087C65FA1D31}", - "Name": "MuzzleFlash", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{8BCC23A5-D08E-458E-B0B3-087C65FA1D31}", - "Name": "MuzzleFlash", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{8BCC23A5-D08E-458E-B0B3-087C65FA1D31}", - "Name": "MuzzleFlash", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Normals.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Normals.preset index 04307eada4..eee0b88686 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Normals.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/Normals.preset @@ -11,6 +11,7 @@ "FileMasks": [ "_ddn", "_normal", + "_normalmap", "_normals", "_norm", "_nor", @@ -35,6 +36,7 @@ "FileMasks": [ "_ddn", "_normal", + "_normalmap", "_normals", "_norm", "_nor", @@ -59,6 +61,7 @@ "FileMasks": [ "_ddn", "_normal", + "_normalmap", "_normals", "_norm", "_nor", @@ -83,6 +86,7 @@ "FileMasks": [ "_ddn", "_normal", + "_normalmap", "_normals", "_norm", "_nor", @@ -106,6 +110,7 @@ "FileMasks": [ "_ddn", "_normal", + "_normalmap", "_normals", "_norm", "_nor", diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsFromDisplacement.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsFromDisplacement.preset deleted file mode 100644 index a960ae41b2..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsFromDisplacement.preset +++ /dev/null @@ -1,86 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{8AE5D8D7-ECF8-4B7D-91DE-8F787E3B4210}", - "Name": "NormalsFromDisplacement", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_bump" - ], - "PixelFormat": "BC5s", - "IsPowerOf2": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{8AE5D8D7-ECF8-4B7D-91DE-8F787E3B4210}", - "Name": "NormalsFromDisplacement", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_bump" - ], - "PixelFormat": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{8AE5D8D7-ECF8-4B7D-91DE-8F787E3B4210}", - "Name": "NormalsFromDisplacement", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_bump" - ], - "PixelFormat": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{8AE5D8D7-ECF8-4B7D-91DE-8F787E3B4210}", - "Name": "NormalsFromDisplacement", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_bump" - ], - "PixelFormat": "BC5s", - "IsPowerOf2": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{8AE5D8D7-ECF8-4B7D-91DE-8F787E3B4210}", - "Name": "NormalsFromDisplacement", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_bump" - ], - "PixelFormat": "BC5s", - "IsPowerOf2": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsWithSmoothness_Legacy.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsWithSmoothness_Legacy.preset deleted file mode 100644 index f7cba42886..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsWithSmoothness_Legacy.preset +++ /dev/null @@ -1,101 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{A92541B8-2E70-4EF1-BA88-1DC1EA2A2341}", - "Name": "NormalsWithSmoothness_Legacy", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_ddna" - ], - "PixelFormat": "BC5s", - "PixelFormatAlpha": "BC4", - "IsPowerOf2": true, - "GlossFromNormal": 1, - "UseLegacyGloss": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{A92541B8-2E70-4EF1-BA88-1DC1EA2A2341}", - "Name": "NormalsWithSmoothness_Legacy", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_ddna" - ], - "PixelFormat": "ASTC_4x4", - "PixelFormatAlpha": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "GlossFromNormal": 1, - "UseLegacyGloss": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{A92541B8-2E70-4EF1-BA88-1DC1EA2A2341}", - "Name": "NormalsWithSmoothness_Legacy", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_ddna" - ], - "PixelFormat": "ASTC_4x4", - "PixelFormatAlpha": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "GlossFromNormal": 1, - "UseLegacyGloss": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{A92541B8-2E70-4EF1-BA88-1DC1EA2A2341}", - "Name": "NormalsWithSmoothness_Legacy", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_ddna" - ], - "PixelFormat": "BC5s", - "PixelFormatAlpha": "BC4", - "IsPowerOf2": true, - "GlossFromNormal": 1, - "UseLegacyGloss": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{A92541B8-2E70-4EF1-BA88-1DC1EA2A2341}", - "Name": "NormalsWithSmoothness_Legacy", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_ddna" - ], - "PixelFormat": "BC5s", - "PixelFormatAlpha": "BC4", - "IsPowerOf2": true, - "GlossFromNormal": 1, - "UseLegacyGloss": true, - "MipRenormalize": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ReflectanceWithSmoothness_Legacy.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/ReflectanceWithSmoothness_Legacy.preset deleted file mode 100644 index 7a0c137f07..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/ReflectanceWithSmoothness_Legacy.preset +++ /dev/null @@ -1,71 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{851128B5-7454-42C4-83CE-FCFE071834C5}", - "Name": "ReflectanceWithSmoothness_Legacy", - "FileMasks": [ - "_spec" - ], - "PixelFormat": "BC7", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{851128B5-7454-42C4-83CE-FCFE071834C5}", - "Name": "ReflectanceWithSmoothness_Legacy", - "FileMasks": [ - "_spec" - ], - "PixelFormat": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{851128B5-7454-42C4-83CE-FCFE071834C5}", - "Name": "ReflectanceWithSmoothness_Legacy", - "FileMasks": [ - "_spec" - ], - "PixelFormat": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{851128B5-7454-42C4-83CE-FCFE071834C5}", - "Name": "ReflectanceWithSmoothness_Legacy", - "FileMasks": [ - "_spec" - ], - "PixelFormat": "BC3", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{851128B5-7454-42C4-83CE-FCFE071834C5}", - "Name": "ReflectanceWithSmoothness_Legacy", - "FileMasks": [ - "_spec" - ], - "PixelFormat": "BC7", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Reflectance_Linear.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Reflectance_Linear.preset deleted file mode 100644 index f59fd594f4..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Reflectance_Linear.preset +++ /dev/null @@ -1,81 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{9B2114F5-118A-4B3A-9CFE-97FA01EC8CFE}", - "Name": "Reflectance_Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl" - ], - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{9B2114F5-118A-4B3A-9CFE-97FA01EC8CFE}", - "Name": "Reflectance_Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl" - ], - "PixelFormat": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{9B2114F5-118A-4B3A-9CFE-97FA01EC8CFE}", - "Name": "Reflectance_Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl" - ], - "PixelFormat": "ASTC_4x4", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{9B2114F5-118A-4B3A-9CFE-97FA01EC8CFE}", - "Name": "Reflectance_Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl" - ], - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{9B2114F5-118A-4B3A-9CFE-97FA01EC8CFE}", - "Name": "Reflectance_Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl" - ], - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Font.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Font.preset deleted file mode 100644 index f76741148c..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Font.preset +++ /dev/null @@ -1,49 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{F34E3711-5F34-4DBC-8F5D-6340D3989F4B}", - "Name": "SF_Font", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "PlatformsPresets": { - "android": { - "UUID": "{F34E3711-5F34-4DBC-8F5D-6340D3989F4B}", - "Name": "SF_Font", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "ios": { - "UUID": "{F34E3711-5F34-4DBC-8F5D-6340D3989F4B}", - "Name": "SF_Font", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "mac": { - "UUID": "{F34E3711-5F34-4DBC-8F5D-6340D3989F4B}", - "Name": "SF_Font", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "provo": { - "UUID": "{F34E3711-5F34-4DBC-8F5D-6340D3989F4B}", - "Name": "SF_Font", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Gradient.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Gradient.preset deleted file mode 100644 index aff25dc83d..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Gradient.preset +++ /dev/null @@ -1,49 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{E7F9DF56-DCB0-4683-96EE-F04DA547BE24}", - "Name": "SF_Gradient", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "PlatformsPresets": { - "android": { - "UUID": "{E7F9DF56-DCB0-4683-96EE-F04DA547BE24}", - "Name": "SF_Gradient", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "ios": { - "UUID": "{E7F9DF56-DCB0-4683-96EE-F04DA547BE24}", - "Name": "SF_Gradient", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "mac": { - "UUID": "{E7F9DF56-DCB0-4683-96EE-F04DA547BE24}", - "Name": "SF_Gradient", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - }, - "provo": { - "UUID": "{E7F9DF56-DCB0-4683-96EE-F04DA547BE24}", - "Name": "SF_Gradient", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "IsPowerOf2": true - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image.preset deleted file mode 100644 index 191425bb92..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image.preset +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{189A42CB-AEE3-4B80-B276-0FDB0ECA140C}", - "Name": "SF_Image", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true - }, - "PlatformsPresets": { - "android": { - "UUID": "{189A42CB-AEE3-4B80-B276-0FDB0ECA140C}", - "Name": "SF_Image", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true - }, - "ios": { - "UUID": "{189A42CB-AEE3-4B80-B276-0FDB0ECA140C}", - "Name": "SF_Image", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true - }, - "mac": { - "UUID": "{189A42CB-AEE3-4B80-B276-0FDB0ECA140C}", - "Name": "SF_Image", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true - }, - "provo": { - "UUID": "{189A42CB-AEE3-4B80-B276-0FDB0ECA140C}", - "Name": "SF_Image", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "BC1", - "IsPowerOf2": true - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image_nonpower2.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image_nonpower2.preset deleted file mode 100644 index 9b1a9c7c45..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/SF_Image_nonpower2.preset +++ /dev/null @@ -1,49 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{C456B8AB-C360-4822-BCDD-225252D0E697}", - "Name": "SF_Image_nonpower2", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "BC1" - }, - "PlatformsPresets": { - "android": { - "UUID": "{C456B8AB-C360-4822-BCDD-225252D0E697}", - "Name": "SF_Image_nonpower2", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_4x4" - }, - "ios": { - "UUID": "{C456B8AB-C360-4822-BCDD-225252D0E697}", - "Name": "SF_Image_nonpower2", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "ASTC_4x4" - }, - "mac": { - "UUID": "{C456B8AB-C360-4822-BCDD-225252D0E697}", - "Name": "SF_Image_nonpower2", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "BC1" - }, - "provo": { - "UUID": "{C456B8AB-C360-4822-BCDD-225252D0E697}", - "Name": "SF_Image_nonpower2", - "SourceColor": "Linear", - "DestColor": "Linear", - "SuppressEngineReduce": true, - "PixelFormat": "BC1" - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo.preset deleted file mode 100644 index 8b12a08465..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo.preset +++ /dev/null @@ -1,69 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{88D07159-2FC0-4CBE-82CC-A9DC258C9351}", - "Name": "Terrain_Albedo", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "BC1", - "IsPowerOf2": true, - "HighPassMip": 5, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{88D07159-2FC0-4CBE-82CC-A9DC258C9351}", - "Name": "Terrain_Albedo", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "HighPassMip": 5, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{88D07159-2FC0-4CBE-82CC-A9DC258C9351}", - "Name": "Terrain_Albedo", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "HighPassMip": 5, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{88D07159-2FC0-4CBE-82CC-A9DC258C9351}", - "Name": "Terrain_Albedo", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "BC1", - "IsPowerOf2": true, - "HighPassMip": 5, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{88D07159-2FC0-4CBE-82CC-A9DC258C9351}", - "Name": "Terrain_Albedo", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "BC1", - "IsPowerOf2": true, - "HighPassMip": 5, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo_HighPassed.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo_HighPassed.preset deleted file mode 100644 index d24531858f..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Terrain_Albedo_HighPassed.preset +++ /dev/null @@ -1,64 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{7827AA52-0A7B-43E7-8CD4-55E0BC513AF1}", - "Name": "Terrain_Albedo_HighPassed", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{7827AA52-0A7B-43E7-8CD4-55E0BC513AF1}", - "Name": "Terrain_Albedo_HighPassed", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{7827AA52-0A7B-43E7-8CD4-55E0BC513AF1}", - "Name": "Terrain_Albedo_HighPassed", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "ASTC_6x6", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{7827AA52-0A7B-43E7-8CD4-55E0BC513AF1}", - "Name": "Terrain_Albedo_HighPassed", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{7827AA52-0A7B-43E7-8CD4-55E0BC513AF1}", - "Name": "Terrain_Albedo_HighPassed", - "SourceColor": "Linear", - "DestColor": "Linear", - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Uncompressed.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Uncompressed.preset deleted file mode 100644 index 6e28cafe11..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Uncompressed.preset +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{E996A696-991C-4FFC-B270-F5AD408B0618}", - "Name": "Uncompressed", - "PixelFormat": "R8G8B8X8", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{E996A696-991C-4FFC-B270-F5AD408B0618}", - "Name": "Uncompressed", - "PixelFormat": "R8G8B8X8", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{E996A696-991C-4FFC-B270-F5AD408B0618}", - "Name": "Uncompressed", - "PixelFormat": "R8G8B8X8", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{E996A696-991C-4FFC-B270-F5AD408B0618}", - "Name": "Uncompressed", - "PixelFormat": "R8G8B8X8", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{E996A696-991C-4FFC-B270-F5AD408B0618}", - "Name": "Uncompressed", - "PixelFormat": "R8G8B8X8", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/NvCloth/Assets/Objects/cloth/Chicken/Actor/chicken_diff.png.imagesettings b/Gems/NvCloth/Assets/Objects/cloth/Chicken/Actor/chicken_diff.png.imagesettings deleted file mode 100644 index adbf7d20f9..0000000000 --- a/Gems/NvCloth/Assets/Objects/cloth/Chicken/Actor/chicken_diff.png.imagesettings +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_ddna.tif.imagesettings b/Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_ddna.tif.imagesettings deleted file mode 100644 index 9da169c456..0000000000 --- a/Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_ddna.tif.imagesettings +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_spec.tif.imagesettings b/Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_spec.tif.imagesettings deleted file mode 100644 index 43410a50df..0000000000 --- a/Gems/PhysXSamples/Assets/Characters/Cowboy/Actor/Textures/Cowboy_01_spec.tif.imagesettings +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_pressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_pressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_pressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_unpressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_unpressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_a_unpressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_pressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_pressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_pressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_unpressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_unpressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_b_unpressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_pressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_pressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_pressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_unpressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_unpressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_x_unpressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_pressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_pressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_pressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_unpressed.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_unpressed.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_button_y_unpressed.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_centre.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_centre.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_centre.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 diff --git a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_radial.tif.exportsettings b/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_radial.tif.exportsettings deleted file mode 100644 index 1415bea891..0000000000 --- a/Gems/VirtualGamepad/Assets/UI/Textures/VirtualGamepad/virtual_gamepad_thumbstick_radial.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /dns=1 /preset=ReferenceImage_Linear /reduce=0 /ser=0 From 9dee92a7089a53e057e9a5c26700368dd6b6f479 Mon Sep 17 00:00:00 2001 From: smurly Date: Mon, 11 Oct 2021 16:09:11 -0700 Subject: [PATCH 185/293] Mateiral component P0 tests editor script (#4585) Signed-off-by: Scott Murray --- .../Atom/TestSuite_Main_Optimized.py | 4 + ...ydra_AtomEditorComponents_MaterialAdded.py | 205 ++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index 90436fbe27..ec3d76758c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -59,5 +59,9 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_MeshAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module + @pytest.mark.test_case_id("C32078123") + class AtomEditorComponents_MaterialAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py new file mode 100644 index 0000000000..32cd5471f2 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py @@ -0,0 +1,205 @@ +""" +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: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + material_creation = ( + "Material Entity successfully created", + "Material Entity failed to be created") + material_component = ( + "Entity has a Material component", + "Entity failed to find Material component") + material_disabled = ( + "Material component disabled", + "Material component was not disabled.") + actor_component = ( + "Entity has an Actor component", + "Entity did not have an Actor component") + actor_undo = ( + "Entity Actor component gone", + "Entity Actor component add failed to undo") + mesh_component = ( + "Entity has a Mesh component", + "Entity did not have a Mesh component") + material_enabled = ( + "Material component enabled", + "Material component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_Material_AddedToEntity(): + """ + Summary: + Tests the Material component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a Material entity with no components. + 2) Add a Material component to Material entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Verify Material component not enabled. + 6) Add Actor component since it is required by the Material component. + 7) Verify Material component is enabled. + 8) UNDO add Actor component + 9) Verify Material component not enabled. + 10) Add Mesh component since it is required by the Material component. + 11) Verify Material component is enabled. + 12) Enter/Exit game mode. + 13) Test IsHidden. + 14) Test IsVisible. + 15) Delete Material entity. + 16) UNDO deletion. + 17) REDO deletion. + 18) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create a Material entity with no components. + material_name = "Material" + material_entity = EditorEntity.create_editor_entity(material_name) + Report.critical_result(Tests.material_creation, material_entity.exists()) + + # 2. Add a Material component to Material entity. + material_component = material_entity.add_component(material_name) + Report.critical_result( + Tests.material_component, + material_entity.has_component(material_name)) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not material_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, material_entity.exists()) + + # 5. Verify Material component not enabled. + Report.result(Tests.material_disabled, not material_component.is_enabled()) + + # 6. Add Actor component since it is required by the Material component. + actor_name = "Actor" + material_entity.add_component(actor_name) + Report.result(Tests.actor_component, material_entity.has_component(actor_name)) + + # 7. Verify Material component is enabled. + Report.result(Tests.material_enabled, material_component.is_enabled()) + + # 8. UNDO component addition. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.actor_undo, not material_entity.has_component(actor_name)) + + # 9. Verify Material component not enabled. + Report.result(Tests.material_disabled, not material_component.is_enabled()) + + # 10. Add Mesh component since it is required by the Material component. + mesh_name = "Mesh" + material_entity.add_component(mesh_name) + Report.result(Tests.mesh_component, material_entity.has_component(mesh_name)) + + # 11. Verify Material component is enabled. + Report.result(Tests.material_enabled, material_component.is_enabled()) + + # 12. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 13. Test IsHidden. + material_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, material_entity.is_hidden() is True) + + # 14. Test IsVisible. + material_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, material_entity.is_visible() is True) + + # 15. Delete Material entity. + material_entity.delete() + Report.result(Tests.entity_deleted, not material_entity.exists()) + + # 16. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, material_entity.exists()) + + # 17. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not material_entity.exists()) + + # 18. Look for errors or asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_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(AtomEditorComponents_Material_AddedToEntity) From 7af448c9b72aed8402e92822e403be57ddca4b0a Mon Sep 17 00:00:00 2001 From: Mikhail Naumov Date: Mon, 11 Oct 2021 20:15:56 -0500 Subject: [PATCH 186/293] PR feedback Signed-off-by: Mikhail Naumov --- .../AzFramework/Spawnable/SpawnableSystemComponent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp index af41fdd6ba..957786c6df 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableSystemComponent.cpp @@ -166,6 +166,8 @@ namespace AzFramework void SpawnableSystemComponent::Deactivate() { + ProcessSpawnableQueue(); + m_registryChangeHandler.Disconnect(); AZ::TickBus::Handler::BusDisconnect(); From 02d8596d875614316a720820e12db38e02661cfe Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 11 Oct 2021 20:24:41 -0700 Subject: [PATCH 187/293] chore: improject documentation for IntersectSegment - change return of IntersectRayDisk to bool - change return of IntersectRayBox to bool - move [out] after @param Signed-off-by: Michael Pollind --- .../AzCore/AzCore/Math/IntersectSegment.cpp | 31 ++- .../AzCore/AzCore/Math/IntersectSegment.h | 217 +++++++++--------- 2 files changed, 124 insertions(+), 124 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp index 2a00412689..1bf1e41cb7 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp @@ -352,9 +352,6 @@ AZ::Intersect::IntersectRayAABB( return ISECT_RAY_AABB_ISECT; } - - - //========================================================================= // IntersectRayAABB2 // [2/18/2011] @@ -411,7 +408,7 @@ AZ::Intersect::IntersectRayAABB2(const Vector3& rayStart, const Vector3& dirRCP, return ISECT_RAY_AABB_ISECT; } -int AZ::Intersect::IntersectRayDisk( +bool AZ::Intersect::IntersectRayDisk( const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& diskCenter, const float diskRadius, const Vector3& diskNormal, float& t) { // First intersect with the plane of the disk @@ -424,10 +421,10 @@ int AZ::Intersect::IntersectRayDisk( if (pointOnPlane.GetDistance(diskCenter) < diskRadius) { t = planeIntersectionDistance; - return 1; + return true; } } - return 0; + return false; } // Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder, and the book's errata. @@ -1015,7 +1012,7 @@ int AZ::Intersect::IntersectRayQuad( } // reference: Real-Time Collision Detection, 5.3.3 Intersecting Ray or Segment Against Box -int AZ::Intersect::IntersectRayBox( +bool AZ::Intersect::IntersectRayBox( const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& boxCenter, const Vector3& boxAxis1, const Vector3& boxAxis2, const Vector3& boxAxis3, float boxHalfExtent1, float boxHalfExtent2, float boxHalfExtent3, float& t) { @@ -1047,7 +1044,7 @@ int AZ::Intersect::IntersectRayBox( // If the ray is parallel to the slab and the ray origin is outside, return no intersection. if (tp < 0.0f || tn < 0.0f) { - return 0; + return false; } } else @@ -1068,7 +1065,7 @@ int AZ::Intersect::IntersectRayBox( tmax = AZ::GetMin(tmax, t2); if (tmin > tmax) { - return 0; + return false; } } @@ -1088,7 +1085,7 @@ int AZ::Intersect::IntersectRayBox( // If the ray is parallel to the slab and the ray origin is outside, return no intersection. if (tp < 0.0f || tn < 0.0f) { - return 0; + return false; } } else @@ -1109,7 +1106,7 @@ int AZ::Intersect::IntersectRayBox( tmax = AZ::GetMin(tmax, t2); if (tmin > tmax) { - return 0; + return false; } } @@ -1129,7 +1126,7 @@ int AZ::Intersect::IntersectRayBox( // If the ray is parallel to the slab and the ray origin is outside, return no intersection. if (tp < 0.0f || tn < 0.0f) { - return 0; + return false; } } else @@ -1150,15 +1147,15 @@ int AZ::Intersect::IntersectRayBox( tmax = AZ::GetMin(tmax, t2); if (tmin > tmax) { - return 0; + return false; } } t = (isRayOriginInsideBox ? tmax : tmin); - return 1; + return true; } -int AZ::Intersect::IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t) +bool AZ::Intersect::IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t) { return AZ::Intersect::IntersectRayBox(rayOrigin, rayDir, obb.GetPosition(), obb.GetAxisX(), obb.GetAxisY(), obb.GetAxisZ(), @@ -1366,11 +1363,11 @@ AZ::Intersect::IntersectSegmentCapsule(const Vector3& sa, const Vector3& dir, co //========================================================================= bool AZ::Intersect::IntersectSegmentPolyhedron( - const Vector3& sa, const Vector3& sBA, const Plane p[], int numPlanes, + const Vector3& sa, const Vector3& dir, const Plane p[], int numPlanes, float& tfirst, float& tlast, int& iFirstPlane, int& iLastPlane) { // Compute direction vector for the segment - Vector3 d = /*b - a*/ sBA; + Vector3 d = /*b - a*/ dir; // Set initial interval to being the whole segment. For a ray, tlast should be // set to +RR_FLT_MAX. For a line, additionally tfirst should be set to -RR_FLT_MAX tfirst = 0.0f; diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h index ecb0d7acc9..71c39fb53d 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h @@ -28,15 +28,14 @@ namespace AZ //! LineToPointDistance computes the closest point to 'p' from a segment (s1,s2). //! @param s1 segment start point //! @param s2 segment end point - //! @param p point to find the closest time to. - //! @param u time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] + //! @param p point to find the closest time to. + //! @param u time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] //! @return the closest point Vector3 LineToPointDistance(const Vector3& s1, const Vector3& s2, const Vector3& p, float& u); //! Given segment pq and triangle abc (CCW), returns whether segment intersects //! triangle and if so, also returns the barycentric coordinates (u,v,w) //! of the intersection point. - //! //! @param p segment start point //! @param q segment end point //! @param a triangle point 1 @@ -49,7 +48,7 @@ namespace AZ const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, Vector3& normal, float& t); //! Same as \ref IntersectSegmentTriangleCCW without respecting the triangle (a,b,c) vertex order (double sided). - //! //! @param p segment start point + //! @param p segment start point //! @param q segment end point //! @param a triangle point 1 //! @param b triangle point 2 @@ -86,41 +85,38 @@ namespace AZ const Aabb& aabb, float& tStart, float& tEnd, - Vector3& startNormal /*, Vector3& inter*/); + Vector3& startNormal); //! Intersect ray against AABB. - //! //! @param rayStart ray starting point. //! @param dir ray reciprocal direction. //! @param aabb Axis aligned bounding box to intersect against. //! @param start length on ray of the first intersection. //! @param end length of the of the second intersection. - //! @return \ref RayAABBIsectTypes In this faster version than IntersectRayAABB we return only ISECT_RAY_AABB_NONE and ISECT_RAY_AABB_ISECT. You can check yourself for that case. + //! @return \ref RayAABBIsectTypes In this faster version than IntersectRayAABB we return only ISECT_RAY_AABB_NONE and + //! ISECT_RAY_AABB_ISECT. You can check yourself for that case. RayAABBIsectTypes IntersectRayAABB2(const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, float& start, float& end); //! Clip a ray to an aabb. return true if ray was clipped. The ray //! can be inside so don't use the result if the ray intersect the box. - //! //! @param aabb bounds //! @param rayStart the start of the ray //! @param rayEnd the end of the ray - //! @param tClipStart[out] The proportion where the ray enterts the aabb - //! @param tClipEnd[out] The proportion where the ray exits the aabb + //! @param[out] tClipStart The proportion where the ray enterts the aabb + //! @param[out] tClipEnd The proportion where the ray exits the aabb //! @return true ray was clipped else false bool ClipRayWithAabb(const Aabb& aabb, Vector3& rayStart, Vector3& rayEnd, float& tClipStart, float& tClipEnd); //! Test segment and aabb where the segment is defined by midpoint //! midPoint = (p1-p0) * 0.5f and half vector halfVector = p1 - midPoint. //! the aabb is at the origin and defined by half extents only. - //! //! @param midPoint midpoint of a line segment //! @param halfVector half vector of an aabb //! @param aabbExtends the extends of a bounded box - //! @return 1 if the intersect, otherwise 0. + //! @return true if the intersect, otherwise false. bool TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends); //! Test if segment specified by points p0 and p1 intersects AABB. \ref TestSegmentAABBOrigin - //! //! @param p0 point 1 //! @param p1 point 2 //! @param aabb bounded box @@ -130,9 +126,9 @@ namespace AZ //! Ray sphere intersection result types. enum SphereIsectTypes : AZ::s32 { - ISECT_RAY_SPHERE_SA_INSIDE = -1, // the ray starts inside the cylinder - ISECT_RAY_SPHERE_NONE, // no intersection - ISECT_RAY_SPHERE_ISECT, // along the PQ segment + ISECT_RAY_SPHERE_SA_INSIDE = -1, //!< the ray starts inside the cylinder + ISECT_RAY_SPHERE_NONE, //!< no intersection + ISECT_RAY_SPHERE_ISECT, //!< along the PQ segment }; //! IntersectRaySphereOrigin @@ -147,25 +143,26 @@ namespace AZ const Vector3& rayStart, const Vector3& rayDirNormalized, const float sphereRadius, float& t); //! Intersect ray (rayStart,rayDirNormalized) and sphere (sphereCenter,sphereRadius) \ref IntersectRaySphereOrigin - //! - //! @param rayStart - //! @param rayDirNormalized - //! @param sphereCenter - //! @param sphereRadius - //! @param t - //! @return SphereIsectTypes + //! @param rayStart the start of the ray + //! @param rayDirNormalized the direction of the ray normalized + //! @param sphereCenter the center of the sphere + //! @param sphereRadius radius of the sphere + //! @param[out] t coefficient in the ray's explicit equation from which an + //! intersecting point is calculated as "rayOrigin + t1 * rayDir". + //! @return SphereIsectTypes SphereIsectTypes IntersectRaySphere( const Vector3& rayStart, const Vector3& rayDirNormalized, const Vector3& sphereCenter, const float sphereRadius, float& t); - //! @param rayOrigin The origin of the ray to test. - //! @param rayDir The direction of the ray to test. It has to be unit length. - //! @param diskCenter Center point of the disk - //! @param diskRadius Radius of the disk - //! @param diskNormal A normal perpendicular to the disk - //! @param[out] t If returning 1 (indicating a hit), this contains distance from rayOrigin along the normalized rayDir + //! Intersect ray (rayStarty, rayDirNormalized) and disk (center, radius, normal) + //! @param rayOrigin The origin of the ray to test. + //! @param rayDir The direction of the ray to test. It has to be unit length. + //! @param diskCenter Center point of the disk + //! @param diskRadius Radius of the disk + //! @param diskNormal A normal perpendicular to the disk + //! @param[out] t If returning 1 (indicating a hit), this contains distance from rayOrigin along the normalized rayDir //! that the hit occured at. - //! @return The number of intersecting points. - int IntersectRayDisk( + //! @return false if not interesecting and true if intersecting + bool IntersectRayDisk( const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& diskCenter, @@ -174,17 +171,14 @@ namespace AZ float& t); //! If there is only one intersecting point, the coefficient is stored in \ref t1. - //! @param rayOrigin The origin of the ray to test. - //! @param rayDir The direction of the ray to test. It has to be unit length. - //! @param cylinderEnd1 The center of the circle on one end of the cylinder. - //! @param cylinderDir The direction pointing from \ref cylinderEnd1 to the other end of the cylinder. It has to be unit - //! length. - //! @param cylinderHeight The distance between two centers of the circles on two ends of the cylinder respectively. - //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - //! as "rayOrigin + t1 * rayDir". - //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - //! as "rayOrigin + t2 * rayDir". - //! @return The number of intersecting points. + //! @param rayOrigin The origin of the ray to test. + //! @param rayDir The direction of the ray to test. It has to be unit length. + //! @param cylinderEnd1 The center of the circle on one end of the cylinder. + //! @param cylinderDir The direction pointing from \ref cylinderEnd1 to the other end of the cylinder. It has to be unit length. + //! @param cylinderHeight The distance between two centers of the circles on two ends of the cylinder respectively. + //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t1 * rayDir". + //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t2 * rayDir". + //! @return The number of intersecting points. int IntersectRayCappedCylinder( const Vector3& rayOrigin, const Vector3& rayDir, @@ -196,17 +190,15 @@ namespace AZ float& t2); //! If there is only one intersecting point, the coefficient is stored in \ref t1. - //! @param rayOrigin The origin of the ray to test. - //! @param rayDir The direction of the ray to test. It has to be unit length. - //! @param coneApex The apex of the cone. - //! @param coneDir The unit-length direction from the apex to the base. - //! @param coneHeight The height of the cone, from the apex to the base. - //! @param coneBaseRadius The radius of the cone base circle. - //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - //! as "rayOrigin + t1 * rayDir". - //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated - //! as "rayOrigin + t2 * rayDir". - //! @return The number of intersecting points. + //! @param rayOrigin The origin of the ray to test. + //! @param rayDir The direction of the ray to test. It has to be unit length. + //! @param coneApex The apex of the cone. + //! @param coneDir The unit-length direction from the apex to the base. + //! @param coneHeight The height of the cone, from the apex to the base. + //! @param coneBaseRadius The radius of the cone base circle. + //! @param[out] t1 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t1 * rayDir". + //! @param[out] t2 A possible coefficient in the ray's explicit equation from which an intersecting point is calculated as "rayOrigin + t2 * rayDir". + //! @return The number of intersecting points. int IntersectRayCone( const Vector3& rayOrigin, const Vector3& rayDir, @@ -218,11 +210,11 @@ namespace AZ float& t2); //! Test intersection between a ray and a plane in 3D. - //! @param rayOrigin The origin of the ray to test intersection with. - //! @param rayDir The direction of the ray to test intersection with. - //! @param planePos A point on the plane to test intersection with. - //! @param planeNormal The normal of the plane to test intersection with. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". + //! @param rayOrigin The origin of the ray to test intersection with. + //! @param rayDir The direction of the ray to test intersection with. + //! @param planePos A point on the plane to test intersection with. + //! @param planeNormal The normal of the plane to test intersection with. + //! @param[out] t The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". //! @return The number of intersection point. int IntersectRayPlane( const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& planePos, const Vector3& planeNormal, float& t); @@ -230,13 +222,14 @@ namespace AZ //! Test intersection between a ray and a two-sided quadrilateral defined by four points in 3D. //! The four points that define the quadrilateral could be passed in with either counter clock-wise //! winding or clock-wise winding. - //! @param rayOrigin The origin of the ray to test intersection with. - //! @param rayDir The direction of the ray to test intersection with. - //! @param vertexA One of the four points that define the quadrilateral. - //! @param vertexB One of the four points that define the quadrilateral. - //! @param vertexC One of the four points that define the quadrilateral. - //! @param vertexD One of the four points that define the quadrilateral. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". + //! @param rayOrigin The origin of the ray to test intersection with. + //! @param rayDir The direction of the ray to test intersection with. + //! @param vertexA One of the four points that define the quadrilateral. + //! @param vertexB One of the four points that define the quadrilateral. + //! @param vertexC One of the four points that define the quadrilateral. + //! @param vertexD One of the four points that define the quadrilateral. + //! @param[out] t The coefficient in the ray's explicit equation from which the + //! intersecting point is calculated as "rayOrigin + t * rayDirection". //! @return The number of intersection point. int IntersectRayQuad( const Vector3& rayOrigin, @@ -248,19 +241,18 @@ namespace AZ float& t); //! Test intersection between a ray and an oriented box in 3D. - //! - //! @param rayOrigin The origin of the ray to test intersection with. - //! @param rayDir The direction of the ray to test intersection with. - //! @param boxCenter The position of the center of the box. - //! @param boxAxis1 An axis along one dimension of the oriented box. - //! @param boxAxis2 An axis along one dimension of the oriented box. - //! @param boxAxis3 An axis along one dimension of the oriented box. - //! @param boxHalfExtent1 The half extent of the box on the dimension of \ref boxAxis1. - //! @param boxHalfExtent2 The half extent of the box on the dimension of \ref boxAxis2. - //! @param boxHalfExtent3 The half extent of the box on the dimension of \ref boxAxis3. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". - //! @return 1 if there is an intersection, 0 otherwise. - int IntersectRayBox( + //! @param rayOrigin The origin of the ray to test intersection with. + //! @param rayDir The direction of the ray to test intersection with. + //! @param boxCenter The position of the center of the box. + //! @param boxAxis1 An axis along one dimension of the oriented box. + //! @param boxAxis2 An axis along one dimension of the oriented box. + //! @param boxAxis3 An axis along one dimension of the oriented box. + //! @param boxHalfExtent1 The half extent of the box on the dimension of \ref boxAxis1. + //! @param boxHalfExtent2 The half extent of the box on the dimension of \ref boxAxis2. + //! @param boxHalfExtent3 The half extent of the box on the dimension of \ref boxAxis3. + //! @param[out] t The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". + //! @return true if there is an intersection, false otherwise. + bool IntersectRayBox( const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& boxCenter, @@ -273,23 +265,21 @@ namespace AZ float& t); //! Test intersection between a ray and an OBB. - //! //! @param rayOrigin The origin of the ray to test intersection with. //! @param rayDir The direction of the ray to test intersection with. //! @param obb The OBB to test for intersection with the ray. - //! @param t[out] The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * - //! rayDirection". - //! @return 1 if there is an intersection, 0 otherwise. - int IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t); + //! @param[out] t The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". + //! @return true if there is an intersection, false otherwise. + bool IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t); //! Ray cylinder intersection types. enum CylinderIsectTypes : AZ::s32 { - RR_ISECT_RAY_CYL_SA_INSIDE = -1, // the ray starts inside the cylinder - RR_ISECT_RAY_CYL_NONE, // no intersection - RR_ISECT_RAY_CYL_PQ, // along the PQ segment - RR_ISECT_RAY_CYL_P_SIDE, // on the P side - RR_ISECT_RAY_CYL_Q_SIDE, // on the Q side + RR_ISECT_RAY_CYL_SA_INSIDE = -1, //!< the ray starts inside the cylinder + RR_ISECT_RAY_CYL_NONE, //!< no intersection + RR_ISECT_RAY_CYL_PQ, //!< along the PQ segment + RR_ISECT_RAY_CYL_P_SIDE, //!< on the P side + RR_ISECT_RAY_CYL_Q_SIDE, //!< on the Q side }; //! Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder @@ -300,7 +290,7 @@ namespace AZ //! @param p center point of side 1 cylinder //! @param q center point of side 2 cylinder //! @param r radius of cylinder - //! @param t[out] proporition along line semgnet + //! @param[out] t proporition along line segment //! @return CylinderIsectTypes CylinderIsectTypes IntersectSegmentCylinder( const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); @@ -308,26 +298,41 @@ namespace AZ //! Capsule ray intersect types. enum CapsuleIsectTypes { - ISECT_RAY_CAPSULE_SA_INSIDE = -1, // the ray starts inside the cylinder - ISECT_RAY_CAPSULE_NONE, // no intersection - ISECT_RAY_CAPSULE_PQ, // along the PQ segment - ISECT_RAY_CAPSULE_P_SIDE, // on the P side - ISECT_RAY_CAPSULE_Q_SIDE, // on the Q side + ISECT_RAY_CAPSULE_SA_INSIDE = -1, //!< the ray starts inside the cylinder + ISECT_RAY_CAPSULE_NONE, //!< no intersection + ISECT_RAY_CAPSULE_PQ, //!< along the PQ segment + ISECT_RAY_CAPSULE_P_SIDE, //!< on the P side + ISECT_RAY_CAPSULE_Q_SIDE, //!< on the Q side }; //! This is a quick implementation of segment capsule based on segment cylinder \ref IntersectSegmentCylinder //! segment sphere intersection. We can optimize it a lot once we fix the ray //! cylinder intersection. - //! + //! @param sa the beginning of the line segment + //! @param dir the direction and length of the segment + //! @param p center point of side 1 capsule + //! @param q center point of side 1 capsule + //! @param r the radius of the capsule + //! @param[out] t proporition along line segment + //! @return CapsuleIsectTypes CapsuleIsectTypes IntersectSegmentCapsule( const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); //! Intersect segment S(t)=A+t(B-A), 0<=t<=1 against convex polyhedron specified //! by the n halfspaces defined by the planes p[]. On exit tfirst and tlast //! define the intersection, if any. + //! @param sa the beggining of the line segment + //! @param dir the direction and length of the segment + //! @param p planes that compose a convex ponvex polyhedron + //! @param numPlanes number of planes + //! @param[out] tfirst proportion along the line segment where the line enters + //! @param[out] tlast proportion along the line segment where the line exits + //! @param[out] iFirstPlane the plane where the line enters + //! @param[out] iLastPlane the plane where the line exits + //! @return true if intersects else false bool IntersectSegmentPolyhedron( const Vector3& sa, - const Vector3& sBA, + const Vector3& dir, const Plane p[], int numPlanes, float& tfirst, @@ -335,7 +340,7 @@ namespace AZ int& iFirstPlane, int& iLastPlane); - //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between + //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between //! two segments segment1Start<->segment1End and segment2Start<->segment2End. Also calculate the values of segment1Proportion and //! segment2Proportion where closestPointSegment1 = segment1Start + (segment1Proportion * (segment1End - segment1Start)) //! closestPointSegment2 = segment2Start + (segment2Proportion * (segment2End - segment2Start)) @@ -344,10 +349,10 @@ namespace AZ //! @param segment1End end of segment 1. //! @param segment2Start start of segment 2. //! @param segment2End end of segment 2. - //! @param segment1Proportion[out] the proporition along segment 1 [0..1] - //! @param segment2Proportion[out] the proporition along segment 2 [0..1] - //! @param closestPointSegment1[out] closest point on segment 1. - //! @param closestPointSegment2[out] closest point on segment 2. + //! @param[out] segment1Proportion the proporition along segment 1 [0..1] + //! @param[out] segment2Proportion the proporition along segment 2 [0..1] + //! @param[out] closestPointSegment1 closest point on segment 1. + //! @param[out] closestPointSegment2 closest point on segment 2. //! @param epsilon the minimum square distance where a line segment can be treated as a single point. void ClosestSegmentSegment( const Vector3& segment1Start, @@ -363,13 +368,12 @@ namespace AZ //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between //! two segments segment1Start<->segment1End and segment2Start<->segment2End. //! If segments are parallel returns a solution. - //! //! @param segment1Start start of segment 1. //! @param segment1End end of segment 1. //! @param segment2Start start of segment 2. //! @param segment2End end of segment 2. - //! @param closestPointSegment1[out] closest point on segment 1. - //! @param closestPointSegment2[out] closest point on segment 2. + //! @param[out] closestPointSegment1 closest point on segment 1. + //! @param[out] closestPointSegment2 closest point on segment 2. //! @param epsilon the minimum square distance where a line segment can be treated as a single point. void ClosestSegmentSegment( const Vector3& segment1Start, @@ -383,12 +387,11 @@ namespace AZ //! Calculate the point (closestPointOnSegment) that is the closest point on //! segment segmentStart/segmentEnd to point. Also calculate the value of proportion where //! closestPointOnSegment = segmentStart + (proportion * (segmentEnd - segmentStart)) - //! //! @param point the point to test //! @param segmentStart the start of the segment //! @param segmentEnd the end of the segment - //! @param proportion[out] the proportion of the segment L(t) = (end - start) * t - //! @param closestPointOnSegment[out] the point along the line segment + //! @param[out] proportion the proportion of the segment L(t) = (end - start) * t + //! @param[out] closestPointOnSegment the point along the line segment void ClosestPointSegment( const Vector3& point, const Vector3& segmentStart, From 7ca85460f752f74fc2fc111e2bcbe2ea78b41342 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 12 Oct 2021 01:41:11 -0700 Subject: [PATCH 188/293] Bug Fix: Improve display of Viewport UI (#4596) - always show controls on top of main ui - Tool window does not show visually in toolbar issue: https://github.com/o3de/o3de/issues/4380 Signed-off-by: Michael Pollind --- .../AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index 80cc7941b0..e27627eab6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -339,7 +339,7 @@ namespace AzToolsFramework::ViewportUi::Internal { // no background for the widget else each set of buttons/text-fields/etc would have a black box around them SetTransparentBackground(mainWindow); - mainWindow->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); + mainWindow->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus); } void ViewportUiDisplay::InitializeUiOverlay() From ccb686b0fca55ff5e1510d61d665a8dd014c7f8c Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Tue, 12 Oct 2021 11:15:56 +0200 Subject: [PATCH 189/293] Bug report template improvement suggestions (#4478) Signed-off-by: Benjamin Jillich --- .github/ISSUE_TEMPLATE/bug_template.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_template.md b/.github/ISSUE_TEMPLATE/bug_template.md index d197ca1312..5a6275b394 100644 --- a/.github/ISSUE_TEMPLATE/bug_template.md +++ b/.github/ISSUE_TEMPLATE/bug_template.md @@ -7,20 +7,30 @@ labels: 'needs-triage,needs-sig,kind/bug' --- **Describe the bug** -A clear and concise description of what the bug is. +A clear and concise description of what the bug is. Try to isolate the issue to help the community to reproduce it easily and increase chances for a fast fix. -**To Reproduce** +**Steps to reproduce** Steps to reproduce the behavior: 1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +2. Click on '...' +3. Select attached asset '...' +4. Scroll down to '...' +5. See error **Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** -If applicable, add screenshots to help explain your problem. +**Actual behavior** +A clear and concise description of what actually happened. + +**Assets required** +Provide sample assets needed to reproduce the issue. + +**Screenshots/Video** +If applicable, add screenshots and/or a video to help explain your problem. + +**Found in Branch** +Name of or link to the branch where the issue occurs. **Desktop/Device (please complete the following information):** - Device: [e.g. PC, Mac, iPhone, Samsung] From 129d249cb4aa3fdcc26e980f280fbb1b01aac61d Mon Sep 17 00:00:00 2001 From: Roman <69218254+amzn-rhhong@users.noreply.github.com> Date: Tue, 12 Oct 2021 08:53:30 -0700 Subject: [PATCH 190/293] Do not delete the actor instance if it's belong to an entity. (#4624) Signed-off-by: rhhong --- .../Code/Tools/EMStudio/AnimViewportRenderer.cpp | 4 ++++ .../Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index ab54b1fa38..52f857551c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -92,6 +92,7 @@ namespace EMStudio m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId); m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId); m_postProcessEntity->CreateComponent(azrtti_typeid()); + m_postProcessEntity->Init(); m_postProcessEntity->Activate(); // Init directional light processor @@ -112,6 +113,7 @@ namespace EMStudio m_iblEntity->CreateComponent(AZ::Render::ImageBasedLightComponentTypeId); m_iblEntity->CreateComponent(azrtti_typeid()); + m_iblEntity->Init(); m_iblEntity->Activate(); // Load light preset @@ -134,6 +136,7 @@ namespace EMStudio gridComponent->SetConfiguration(gridConfig); m_gridEntity->CreateComponent(azrtti_typeid()); + m_gridEntity->Init(); m_gridEntity->Activate(); Reinit(); @@ -251,6 +254,7 @@ namespace EMStudio actorEntity->CreateComponent(azrtti_typeid()); actorEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); actorEntity->CreateComponent(azrtti_typeid()); + actorEntity->Init(); actorEntity->Activate(); EMotionFX::Integration::ActorComponent* actorComponent = actorEntity->FindComponent(); diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp index 57e206560a..ef573ab40c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ActorCommands.cpp @@ -825,6 +825,11 @@ namespace CommandSystem { continue; } + // Ignore actor instances owned by entity + if (actorInstance->GetEntity()) + { + continue; + } // generate command to remove the actor instance const AZStd::string command = AZStd::string::format("RemoveActorInstance -actorInstanceID %i", actorInstance->GetID()); From 01448c5c49ef5e015fcd30f5ef869799fa042922 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Tue, 12 Oct 2021 09:11:50 -0700 Subject: [PATCH 191/293] ATOM-16658 Remove PBSreferenceMaterials gem which is a gem for legacy cry3dengine (#4616) Signed-off-by: Qing Tao --- .../Registry/assets_scan_folders.setreg | 7 ------- .../materials/pbs_reference/16_ddna.tif | 3 --- .../pbs_reference/anodized_metal.mtl | 10 ---------- .../pbs_reference/anodized_metal_diff.tif | 3 --- .../anodized_metal_diff.tif.exportsettings | 1 - .../pbs_reference/anodized_metal_spec.tif | 3 --- .../anodized_metal_spec.tif.exportsettings | 1 - .../materials/pbs_reference/brushed_steel.mtl | 10 ---------- .../materials/pbs_reference/brushed_steel.tif | 3 --- .../brushed_steel.tif.exportsettings | 1 - .../pbs_reference/brushed_steel2.mtl | 10 ---------- .../pbs_reference/brushed_steel_ddna.tif | 3 --- .../brushed_steel_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/car_paint.mtl | 8 -------- .../pbs_reference/car_paint_diff.tif | 3 --- .../car_paint_diff.tif.exportsettings | 1 - .../pbs_reference/car_paint_spec.tif | 3 --- .../car_paint_spec.tif.exportsettings | 1 - .../Assets/materials/pbs_reference/coal.mtl | 9 --------- .../materials/pbs_reference/coal_ddna.tif | 3 --- .../coal_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/coal_diff.tif | 3 --- .../coal_diff.tif.exportsettings | 1 - .../colorcharts/debug_contrast_high_cch.tif | 3 --- .../colorcharts/debug_contrast_low_cch.tif | 3 --- .../debug_contrast_veryhigh_cch.tif | 3 --- .../colorcharts/debug_saturation_0_cch.tif | 3 --- .../pbs_reference/concrete_stucco.mtl | 9 --------- .../pbs_reference/concrete_stucco_ddna.tif | 3 --- .../concrete_stucco_ddna.tif.exportsettings | 1 - .../pbs_reference/concrete_stucco_diff.tif | 3 --- .../concrete_stucco_diff.tif.exportsettings | 1 - .../pbs_reference/conductor_diff.tif | 3 --- .../conductor_diff.tif.exportsettings | 1 - .../materials/pbs_reference/copper_spec.tif | 3 --- .../copper_spec.tif.exportsettings | 1 - .../materials/pbs_reference/dark_leather.mtl | 9 --------- .../pbs_reference/dark_leather_diff.tif | 3 --- .../dark_leather_diff.tif.exportsettings | 1 - .../Assets/materials/pbs_reference/fabric.mtl | 9 --------- .../pbs_reference/galvanized_steel.mtl | 10 ---------- .../pbs_reference/galvanized_steel.tif | 3 --- .../galvanized_steel.tif.exportsettings | 1 - .../pbs_reference/galvanized_steel_ddna.tif | 3 --- .../galvanized_steel_ddna.tif.exportsettings | 1 - .../pbs_reference/galvanized_steel_spec.tif | 3 --- .../galvanized_steel_spec.tif.exportsettings | 1 - .../materials/pbs_reference/glazed_clay.mtl | 7 ------- .../pbs_reference/glazed_clay_ddna.tif | 3 --- .../glazed_clay_ddna.tif.exportsettings | 1 - .../pbs_reference/glazed_clay_diff.tif | 3 --- .../glazed_clay_diff.tif.exportsettings | 1 - .../Assets/materials/pbs_reference/gloss0.mtl | 7 ------- .../materials/pbs_reference/gloss0_ddna.tif | 3 --- .../gloss0_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss10.mtl | 7 ------- .../materials/pbs_reference/gloss100.mtl | 7 ------- .../materials/pbs_reference/gloss100_ddna.tif | 3 --- .../gloss100_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss10_ddna.tif | 3 --- .../gloss10_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss20.mtl | 7 ------- .../materials/pbs_reference/gloss20_ddna.tif | 3 --- .../gloss20_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss30.mtl | 7 ------- .../materials/pbs_reference/gloss30_ddna.tif | 3 --- .../gloss30_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss40.mtl | 7 ------- .../materials/pbs_reference/gloss40_ddna.tif | 3 --- .../gloss40_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss50.mtl | 7 ------- .../materials/pbs_reference/gloss50_ddna.tif | 3 --- .../gloss50_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss60.mtl | 7 ------- .../materials/pbs_reference/gloss60_ddna.tif | 3 --- .../gloss60_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss70.mtl | 7 ------- .../materials/pbs_reference/gloss70_ddna.tif | 3 --- .../gloss70_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss80.mtl | 7 ------- .../materials/pbs_reference/gloss80_ddna.tif | 3 --- .../gloss80_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gloss90.mtl | 7 ------- .../materials/pbs_reference/gloss90_ddna.tif | 3 --- .../gloss90_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/gold_spec.tif | 3 --- .../gold_spec.tif.exportsettings | 1 - .../ground_mats/mixed_stones1.mtl | 7 ------- .../materials/pbs_reference/iron_spec.tif | 3 --- .../iron_spec.tif.exportsettings | 1 - .../materials/pbs_reference/leather_ddna.tif | 3 --- .../leather_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/light_leather.mtl | 9 --------- .../pbs_reference/light_leather_diff.tif | 3 --- .../light_leather_diff.tif.exportsettings | 1 - .../materials/pbs_reference/mixed_stones.mtl | 9 --------- .../pbs_reference/mixed_stones_ddna.tif | 3 --- .../mixed_stones_ddna.tif.exportsettings | 1 - .../pbs_reference/mixed_stones_diff.tif | 3 --- .../mixed_stones_diff.tif.exportsettings | 1 - .../materials/pbs_reference/nickel_spec.tif | 3 --- .../nickel_spec.tif.exportsettings | 1 - .../pbs_reference/plain_fabric_ddna.tif | 3 --- .../plain_fabric_ddna.tif.exportsettings | 1 - .../pbs_reference/plain_fabric_diff.tif | 3 --- .../plain_fabric_diff.tif.exportsettings | 1 - .../materials/pbs_reference/platinum_spec.tif | 3 --- .../platinum_spec.tif.exportsettings | 1 - .../pbs_reference/polished_copper.mtl | 7 ------- .../materials/pbs_reference/polished_gold.mtl | 7 ------- .../materials/pbs_reference/polished_iron.mtl | 7 ------- .../pbs_reference/polished_nickel.mtl | 7 ------- .../pbs_reference/polished_silver.mtl | 7 ------- .../materials/pbs_reference/porcelain.mtl | 9 --------- .../pbs_reference/porcelain_diff.tif | 3 --- .../porcelain_diff.tif.exportsettings | 1 - .../materials/pbs_reference/red_diff.tif | 3 --- .../pbs_reference/red_diff.tif.exportsettings | 1 - .../rotary_brushed_steel_ddna.tif | 3 --- ...tary_brushed_steel_ddna.tif.exportsettings | 1 - .../Assets/materials/pbs_reference/rust.mtl | 9 --------- .../materials/pbs_reference/rust_blend.tif | 3 --- .../rust_blend.tif.exportsettings | 1 - .../materials/pbs_reference/rust_ddna.tif | 3 --- .../rust_ddna.tif.exportsettings | 1 - .../materials/pbs_reference/rust_diff.tif | 3 --- .../rust_diff.tif.exportsettings | 1 - .../materials/pbs_reference/rusted_metal.mtl | 13 ------------ .../materials/pbs_reference/shiny_plastic.mtl | 9 --------- .../materials/pbs_reference/silver_spec.tif | 3 --- .../silver_spec.tif.exportsettings | 1 - .../pbs_reference/skydomes/afternoon.tif | 3 --- .../pbs_reference/skydomes/evening.tif | 3 --- .../pbs_reference/skydomes/neutral.tif | 3 --- .../pbs_reference/skydomes/night.tif | 3 --- .../pbs_reference/skydomes/sky_afternoon.mtl | 6 ------ .../pbs_reference/skydomes/sky_evening.mtl | 6 ------ .../pbs_reference/skydomes/sky_neutral.mtl | 6 ------ .../pbs_reference/skydomes/sky_night.mtl | 7 ------- .../materials/pbs_reference/wood_planks.mtl | 10 ---------- .../pbs_reference/wood_planks_ddna.tif | 3 --- .../wood_planks_ddna.tif.exportsettings | 1 - .../pbs_reference/wood_planks_diff.tif | 3 --- .../wood_planks_diff.tif.exportsettings | 1 - .../pbs_reference/wood_planks_spec.tif | 3 --- .../wood_planks_spec.tif.exportsettings | 1 - .../materials/pbs_reference/worn_copper.mtl | 10 ---------- .../materials/pbs_reference/worn_gold.mtl | 10 ---------- .../materials/pbs_reference/worn_metal.mtl | 10 ---------- .../pbs_reference/worn_metal_ddna.tif | 3 --- .../worn_metal_ddna.tif.exportsettings | 1 - .../Assets/materials/test_reference/test.mtl | 12 ----------- .../materials/test_reference/test_AO.tif | 3 --- .../test_reference/test_AO.tif.exportsettings | 1 - .../materials/test_reference/test_H.tif | 3 --- .../test_reference/test_H.tif.exportsettings | 1 - .../materials/test_reference/test_albedo.tif | 3 --- .../test_albedo.tif.exportsettings | 1 - .../test_reference/test_normals_ddn.tif | 3 --- .../test_normals_ddn.tif.exportsettings | 1 - Gems/PBSreferenceMaterials/CMakeLists.txt | 12 ----------- .../Resources/test_source.psd | 3 --- Gems/PBSreferenceMaterials/gem.json | 20 ------------------- Gems/PBSreferenceMaterials/preview.png | 3 --- engine.json | 1 - 165 files changed, 634 deletions(-) delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/16_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel2.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_high_cch.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_low_cch.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_veryhigh_cch.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_saturation_0_cch.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/fabric.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/ground_mats/mixed_stones1.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_copper.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_gold.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_iron.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_nickel.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_silver.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rusted_metal.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/shiny_plastic.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/afternoon.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/evening.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/neutral.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/night.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_afternoon.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_evening.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_neutral.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_night.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_copper.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_gold.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test.mtl delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif delete mode 100644 Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif.exportsettings delete mode 100644 Gems/PBSreferenceMaterials/CMakeLists.txt delete mode 100644 Gems/PBSreferenceMaterials/Resources/test_source.psd delete mode 100644 Gems/PBSreferenceMaterials/gem.json delete mode 100644 Gems/PBSreferenceMaterials/preview.png diff --git a/AutomatedTesting/Registry/assets_scan_folders.setreg b/AutomatedTesting/Registry/assets_scan_folders.setreg index c74ba6703e..3043533b59 100644 --- a/AutomatedTesting/Registry/assets_scan_folders.setreg +++ b/AutomatedTesting/Registry/assets_scan_folders.setreg @@ -10,13 +10,6 @@ "Gems/DevTextures" ] }, - "PBSreferenceMaterials": - { - "SourcePaths": - [ - "Gems/PBSreferenceMaterials" - ] - }, "PhysicsEntities": { "SourcePaths": diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/16_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/16_ddna.tif deleted file mode 100644 index 68edfab5e2..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/16_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:78394a1c8fc1e8bb260b27c5ae3fa040cbabcbc550fb33470316f9f38b2327f7 -size 2104742 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal.mtl deleted file mode 100644 index c27dfd5bc1..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif deleted file mode 100644 index 7993c143a9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae4a72a26a2f232c6ffb42a391d81b4ca7396c73894ccb923ba2f7bc1c940f04 -size 12602810 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif.exportsettings deleted file mode 100644 index e97c4e452c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce="android:0,ios:0,mac:0,pc:2,provo:0,wiiu:0" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif deleted file mode 100644 index 531bbe52b2..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:73e215c80dcbde6b092b87aaed3532aa3e4447872a4c347248ada2e0c92b62c9 -size 12602768 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif.exportsettings deleted file mode 100644 index 0e4a4a080e..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/anodized_metal_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.mtl deleted file mode 100644 index eab5de5a5b..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif deleted file mode 100644 index 9db133e2cd..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0801f5089dc5d984fc2c88bd1cb3e0160fc0eddacdb95492d8ee433d0dfe675b -size 12602752 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif.exportsettings deleted file mode 100644 index fb61d0f55c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel2.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel2.mtl deleted file mode 100644 index dfadacee21..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel2.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif deleted file mode 100644 index 5afabeeea2..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cb714bf17f4da5b74eb0fe8eb329533f1fe76c68a915f5240a30bf496d133b2a -size 33574354 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif.exportsettings deleted file mode 100644 index a098bdcad9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/brushed_steel_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint.mtl deleted file mode 100644 index c0f0399527..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint.mtl +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif deleted file mode 100644 index 207980ec50..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cc61165bad7ff9a3f6bee23c47350bd4e69f7bce80a50acc4d353583d5a49ec2 -size 12602762 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif.exportsettings deleted file mode 100644 index d3713274e6..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif deleted file mode 100644 index 97738f104e..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8349c8ebe5b6b58f426bccd307778aeff674970b8b7761c78bf07460a51208d1 -size 12602764 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif.exportsettings deleted file mode 100644 index 0e4a4a080e..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/car_paint_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal.mtl deleted file mode 100644 index a5848a101c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif deleted file mode 100644 index f0b243c4ba..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8691f06e179e74b2035df0147b3792b28aded379fb8ca5c6a58694793bcfc7b -size 33574298 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif.exportsettings deleted file mode 100644 index 4377d1bc2a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif deleted file mode 100644 index 51afab3cae..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:51afb7f2b44b7249b7b560abd165cd07f55a8f622e7ce684aa70de0fe04fe457 -size 12602798 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif.exportsettings deleted file mode 100644 index 78867ef15c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/coal_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /mipmaps=0 /preset=Albedo /reduce=-1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_high_cch.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_high_cch.tif deleted file mode 100644 index 370a37320b..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_high_cch.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:61b26a818df92997fe0336d7e4fcb84af10328be0f49bd23b28b20dd3d70dc94 -size 19460 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_low_cch.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_low_cch.tif deleted file mode 100644 index 57bb2a9eb6..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_low_cch.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0c266cd36f1732dd6f0e86cee98d354f1301fa06c62dc8dc1d81f2dce64b589c -size 19460 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_veryhigh_cch.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_veryhigh_cch.tif deleted file mode 100644 index ac1f01f7a7..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_contrast_veryhigh_cch.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:41360332648da3dc87d441d07efdbc9074e01de03e4752775f655299870adb84 -size 19462 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_saturation_0_cch.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_saturation_0_cch.tif deleted file mode 100644 index 5a5312dac8..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/colorcharts/debug_saturation_0_cch.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8b2d948c3edd823e3ce898cb0237d37088b7c09f7a6bc4f2d5a883a3785c7b92 -size 19416 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco.mtl deleted file mode 100644 index 0bc0563dc9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif deleted file mode 100644 index 115848e63a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5e34cadedb6f04d7e2923ff39eb6aa26578f7fa66d55759a79fc8b2fc297a67 -size 33571726 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif.exportsettings deleted file mode 100644 index 4377d1bc2a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif deleted file mode 100644 index f73e9d8e29..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f6fe115f07fabdf24effa6ccf510d7df0878338cf62ec725f99548f744d8d520 -size 25183118 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif.exportsettings deleted file mode 100644 index fb61d0f55c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/concrete_stucco_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif deleted file mode 100644 index 55869c6a65..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1e83c754930c838b473d0388cb7eea6fc61f00d37756f288588706ef31fbc3e7 -size 793988 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif.exportsettings deleted file mode 100644 index d3713274e6..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/conductor_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif deleted file mode 100644 index eff0d838ff..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:eb7bb72c37f57ae9f5c8be2239d24da91d635281ee6c5394f4cd4376260dd659 -size 1580448 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif.exportsettings deleted file mode 100644 index a6837b396f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/copper_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /mipgentype=average /preset=Reflectance /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather.mtl deleted file mode 100644 index e1e04a218f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif deleted file mode 100644 index 05a2366629..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:28e1269ebe4839f329879adf0faa908eef16a975a37e614f65c9337c8095c694 -size 12602796 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif.exportsettings deleted file mode 100644 index 19e899701a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/dark_leather_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/fabric.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/fabric.mtl deleted file mode 100644 index e25536921d..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/fabric.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.mtl deleted file mode 100644 index a5becf3800..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif deleted file mode 100644 index 556be35401..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0b3d1f17036a544942d9b5ad753d9de4e77f2d72f264e75703c777a9ec36d0ff -size 16797130 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif.exportsettings deleted file mode 100644 index 6a4cbb4a3f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /mipmaps=0 /preset=NormalsWithSmoothness /reduce=-1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif deleted file mode 100644 index b3310a7902..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ece9aed5ef96c2b677922f148ef03d6186b7eca9400e90956772bce5661ecc34 -size 33574310 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif deleted file mode 100644 index c8194ca629..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d6d9d3c1577efc9df9f9200d24d338cdca684239f0e793c217e1a7358ced6ff -size 25185726 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif.exportsettings deleted file mode 100644 index 08861692ea..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/galvanized_steel_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance /reduce="android:0,ios:0,mac:0,pc:1,provo:0,wiiu:0" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay.mtl deleted file mode 100644 index 9b722cb5e6..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif deleted file mode 100644 index 629475cdef..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:02fdb16917657d8af287dc03bbaef856d99570a26bd8d92d1766c221abb4ffd3 -size 33571149 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif deleted file mode 100644 index 60698476a1..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5001487368d53bba9def9ea772b129ee1e16e738b8940a0621d1822e87105ffc -size 25182520 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif.exportsettings deleted file mode 100644 index d3713274e6..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/glazed_clay_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0.mtl deleted file mode 100644 index 217d3a979a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif deleted file mode 100644 index 69bda20789..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54c5b9d01385f9301ff5958c75ddf9f7128539dbdb8c12497ef12150fd7e3991 -size 2104738 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss0_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10.mtl deleted file mode 100644 index 2d1be1df68..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100.mtl deleted file mode 100644 index a8e096eead..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif deleted file mode 100644 index 9bb9eb9a2d..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aab4381b123765d164d222ab8260977302a49d176f1c6b601a3236013eb93c71 -size 2104740 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss100_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif deleted file mode 100644 index c7b3884843..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6c84d169f7f305dde87039b113b144335239ded615ddc060fd7648e0c69c4ebd -size 2104738 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss10_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20.mtl deleted file mode 100644 index b2b3c7643d..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif deleted file mode 100644 index 6b990d7545..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6bcd9dfe932714e63612023ea8dce2a9e2c377553e666b96771bb4f831387c7d -size 2104738 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss20_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30.mtl deleted file mode 100644 index 661a8e3de2..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif deleted file mode 100644 index 64094acf29..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:500b16679345f981c68521e6021aea5ef0e07603beb52fdac6bbb46320af98cb -size 2104738 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss30_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40.mtl deleted file mode 100644 index 70ee969fc0..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif deleted file mode 100644 index c166c9f8cc..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:36b57374a09c929f9bdec637483f3545b320a2fe18e3e33d483cd3d027b7a4cd -size 2104738 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss40_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50.mtl deleted file mode 100644 index 4f00a19269..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif deleted file mode 100644 index e92493893f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09b976c732d3b456ebd75afc814cc74c8aaa2530118e2a54127c8ce8d24c63cd -size 2104746 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss50_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60.mtl deleted file mode 100644 index c96632fe7b..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif deleted file mode 100644 index 1086d2a54d..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d733ad0c67d70aa2fbc31ac6edd1a50d99ed9f4659452707db1b107433668ef6 -size 2104746 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss60_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70.mtl deleted file mode 100644 index e7afaff4cd..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif deleted file mode 100644 index 56f751a811..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8fe277c640d2f17b80322de1218cb9b8d3f979c76f735a9741fd253a639868f -size 2104746 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss70_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80.mtl deleted file mode 100644 index 11bee418ea..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif deleted file mode 100644 index 096aa4f81f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c2019143e287e449cfa544ca8d06be38332e6bad2d92f302482670d25c27ce93 -size 2104748 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss80_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90.mtl deleted file mode 100644 index 295882a14d..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif deleted file mode 100644 index dd311c14f3..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:913e9594afce1753143c4a23ba63376844285e4cfa0353bec8c8fbb32fb55244 -size 2104748 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gloss90_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif deleted file mode 100644 index 7d053201a4..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:60df2f9dd0c960135c590b6bbb085d8054d4f98a9349a3aaae2b69ef2c084afd -size 1580458 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif.exportsettings deleted file mode 100644 index a6837b396f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/gold_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /mipgentype=average /preset=Reflectance /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/ground_mats/mixed_stones1.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/ground_mats/mixed_stones1.mtl deleted file mode 100644 index 68bc825e99..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/ground_mats/mixed_stones1.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif deleted file mode 100644 index 69162c2479..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0809fec4adb0ba0bd9143e599ae841b04bcfa924cdd55666e46c82771825e106 -size 794002 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif.exportsettings deleted file mode 100644 index 0e4a4a080e..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/iron_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif deleted file mode 100644 index ff7973839e..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:44e38b77ed21dd6c4dbe506d7449440ae5edd734d8eaf9e3fc68b49f16890598 -size 16797150 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif.exportsettings deleted file mode 100644 index a098bdcad9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/leather_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather.mtl deleted file mode 100644 index fb58f3e7d3..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif deleted file mode 100644 index 7efa3c5dc0..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ec252b4e03cb18ae458c650c392cdcd2c3d077db54279665f7b8bf7b335ff80 -size 12602808 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif.exportsettings deleted file mode 100644 index 19e899701a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/light_leather_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones.mtl deleted file mode 100644 index f7572190ce..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif deleted file mode 100644 index f65bd1efb8..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9b18ba8592261663e36608c74c763c7b80adc673f5857a605c7a1a261bb8dc3c -size 8400326 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif.exportsettings deleted file mode 100644 index a098bdcad9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif deleted file mode 100644 index 57b058e334..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54e57959423057d58ec5be9530669e613566eb1152919887b10f06ab81cf901d -size 6303154 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif.exportsettings deleted file mode 100644 index 19e899701a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/mixed_stones_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif deleted file mode 100644 index 538b6adf3a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:af459c0475bcf52150d818190480665ca0989f94a17cf979478e0bfd078cc0bf -size 793948 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif.exportsettings deleted file mode 100644 index 0e4a4a080e..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/nickel_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif deleted file mode 100644 index 28c888ac93..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c2b478231433a0d797bfe62bb087c8331a7edb32a150e2da6bd51fe55d4da60 -size 16797096 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif.exportsettings deleted file mode 100644 index 4377d1bc2a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif deleted file mode 100644 index 791d5a9068..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d460e8b5c8c026cad1b20a71c3857c562051ccd4fc66d480357375276e41ab70 -size 12602770 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif.exportsettings deleted file mode 100644 index d3713274e6..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/plain_fabric_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif deleted file mode 100644 index 293868dbcd..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a8a5517902429c5b518041cf13f09c0e68378ca0afcd53af487373bc23584953 -size 794002 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif.exportsettings deleted file mode 100644 index 2bec812694..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/platinum_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance_Linear /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_copper.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_copper.mtl deleted file mode 100644 index e440e60c07..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_copper.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_gold.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_gold.mtl deleted file mode 100644 index ff61b723c1..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_gold.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_iron.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_iron.mtl deleted file mode 100644 index a2557c8cf5..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_iron.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_nickel.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_nickel.mtl deleted file mode 100644 index 383f132414..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_nickel.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_silver.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_silver.mtl deleted file mode 100644 index e6f78b0c92..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/polished_silver.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain.mtl deleted file mode 100644 index b82aa09808..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif deleted file mode 100644 index cc0ff9e1a1..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:23383293c185f7801f466779a0f223dd3eb21a8cc2c69a742d58f699b32ac375 -size 3157400 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif.exportsettings deleted file mode 100644 index 78867ef15c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/porcelain_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /mipmaps=0 /preset=Albedo /reduce=-1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif deleted file mode 100644 index 3532880e2d..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6c38541d104c3461b22f9bf8865308f5ea07895f3cebc1fd67c29647c76ed904 -size 794036 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif.exportsettings deleted file mode 100644 index 48c18e1fe4..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/red_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce="android:0,ios:0,mac:0,pc:3,provo:0,wiiu:0" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif deleted file mode 100644 index ac1ced5071..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:00928a4cbfc43bc3d13f407d8ea6d59499e658c0fdd92981b6124e999ca7d668 -size 33574298 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif.exportsettings deleted file mode 100644 index a098bdcad9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rotary_brushed_steel_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust.mtl deleted file mode 100644 index 5861a12251..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif deleted file mode 100644 index 7bd44ad5be..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d4fc3a6dc8729848be3fa54e544e146a324198c213d91031082f911f78c2a9df -size 3154182 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif.exportsettings deleted file mode 100644 index 8092b156b4..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_blend.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /mipgentype=box /preset=Albedo /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif deleted file mode 100644 index 3d13dc2fd6..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3a673385f65153fdb1659a008229c333ccf972bf15268e051594abb97e129a20 -size 8397168 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif.exportsettings deleted file mode 100644 index a098bdcad9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif deleted file mode 100644 index 9841bdb352..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6170ca5d841592ca689316e268793094b8dde3705281ad7c9d942ed9dfd7343b -size 6299995 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif.exportsettings deleted file mode 100644 index 19e899701a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rust_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rusted_metal.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rusted_metal.mtl deleted file mode 100644 index 7ccf171972..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/rusted_metal.mtl +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/shiny_plastic.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/shiny_plastic.mtl deleted file mode 100644 index e62f3ca57b..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/shiny_plastic.mtl +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif deleted file mode 100644 index d50c32839a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9288cf57fb15fe106f335aa95910df01efa50eef2b69caf641c69640fc1f91e3 -size 793990 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif.exportsettings deleted file mode 100644 index 2bec812694..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/silver_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance_Linear /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/afternoon.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/afternoon.tif deleted file mode 100644 index 9b8f9a20fb..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/afternoon.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad6459c0fc86b2ef4f585505329a649eb30bc5940582b68d4dec0bf45aae3395 -size 6295912 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/evening.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/evening.tif deleted file mode 100644 index 9a637b17aa..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/evening.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df24d58699c82f8581a8e787c12d3dadd6df97b165cb1d6f14fe68ed43ea31c0 -size 3150154 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/neutral.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/neutral.tif deleted file mode 100644 index 48ca954942..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/neutral.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4ddbd14843b551d8d4894fa85f4512c58505573ac0c8f14b1afe357abce21396 -size 3150190 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/night.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/night.tif deleted file mode 100644 index 8780f7fba0..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/night.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2579027e45f1039a3b7cf253545aa166271556c2faf914cba9f5754577c49eaa -size 8393068 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_afternoon.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_afternoon.mtl deleted file mode 100644 index 76f9b83c9a..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_afternoon.mtl +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_evening.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_evening.mtl deleted file mode 100644 index 4c72ff536f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_evening.mtl +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_neutral.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_neutral.mtl deleted file mode 100644 index 748c25929b..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_neutral.mtl +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_night.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_night.mtl deleted file mode 100644 index d436db6ef2..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/skydomes/sky_night.mtl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks.mtl deleted file mode 100644 index eb1dea0991..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif deleted file mode 100644 index 0eaf9326d0..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bba137198cf4b87c822e12f0328dbc4ed9bc612521c7985913d6363f4e3291ab -size 33574348 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif.exportsettings deleted file mode 100644 index a098bdcad9..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:1,pc:0,provo:1,wiiu:1" diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif deleted file mode 100644 index c919feeb0f..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:76a8b871242fe618a5b5a11ddafa147890806759927606fe4dcc697c8e4d11d3 -size 25185676 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif.exportsettings deleted file mode 100644 index fb61d0f55c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_diff.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif deleted file mode 100644 index 3dd863eb05..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bbd50f58c8e889272b5734f3eb63527a2a2d560ccacf69bb3326b6dc866aa01a -size 25185678 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif.exportsettings deleted file mode 100644 index c31be74648..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/wood_planks_spec.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Reflectance /reduce=1 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_copper.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_copper.mtl deleted file mode 100644 index 1c522de4c3..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_copper.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_gold.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_gold.mtl deleted file mode 100644 index f81420b9aa..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_gold.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal.mtl b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal.mtl deleted file mode 100644 index d5300822cd..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal.mtl +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif deleted file mode 100644 index 4d831687a4..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c84a16617421d986dbbd5c12393e6aef46de9d2898becfef6eb02d065b9d0bd0 -size 8400288 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif.exportsettings deleted file mode 100644 index 0159b6ca02..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/pbs_reference/worn_metal_ddna.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test.mtl b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test.mtl deleted file mode 100644 index 25ea4b3171..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test.mtl +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif deleted file mode 100644 index ccebca85f8..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:45358825d1fa0fed1a9fb7028d8361e58e5d96f1415d56aebe7c1ca0e410000a -size 12605680 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif.exportsettings deleted file mode 100644 index 25a6d5d697..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_AO.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Reflectance /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif deleted file mode 100644 index 5f89b4c33c..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:71d137d8fd428ae6191d7c97c9b48e92484975a8bc2b0e8704adab928eeb6650 -size 16798472 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif.exportsettings deleted file mode 100644 index 08f50cf38b..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_H.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /mipgentype=sigma-six /preset=Displacement /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif deleted file mode 100644 index 1e4fd75fd5..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:caf47b0db80678caa3673566150002420677e24e7e3bc77c9f3d95cac15433e3 -size 12609308 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif.exportsettings deleted file mode 100644 index 44cd6187b1..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_albedo.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Albedo /reduce=0 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif deleted file mode 100644 index c71f243adb..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:93a0842c8d0bb3ce1d5897e415820df48cf093ff9ea4369e2e9bfac5ea018259 -size 12602730 diff --git a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif.exportsettings b/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif.exportsettings deleted file mode 100644 index d1103c9959..0000000000 --- a/Gems/PBSreferenceMaterials/Assets/materials/test_reference/test_normals_ddn.tif.exportsettings +++ /dev/null @@ -1 +0,0 @@ -/autooptimizefile=0 /preset=Normals /reduce=0 diff --git a/Gems/PBSreferenceMaterials/CMakeLists.txt b/Gems/PBSreferenceMaterials/CMakeLists.txt deleted file mode 100644 index 76a911746c..0000000000 --- a/Gems/PBSreferenceMaterials/CMakeLists.txt +++ /dev/null @@ -1,12 +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 -# -# - -# This will export its "SourcePaths" to the generated "cmake_dependencies..assetbuilder.setreg" -if(PAL_TRAIT_BUILD_HOST_TOOLS) - ly_create_alias(NAME PBSreferenceMaterials.Builders NAMESPACE Gem) -endif() diff --git a/Gems/PBSreferenceMaterials/Resources/test_source.psd b/Gems/PBSreferenceMaterials/Resources/test_source.psd deleted file mode 100644 index 2f0ca41476..0000000000 --- a/Gems/PBSreferenceMaterials/Resources/test_source.psd +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:322e2360dd2a621fc733e171d676497d5351ade274df16d223ccf3b9df8c3382 -size 19277076 diff --git a/Gems/PBSreferenceMaterials/gem.json b/Gems/PBSreferenceMaterials/gem.json deleted file mode 100644 index feddc1e465..0000000000 --- a/Gems/PBSreferenceMaterials/gem.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "gem_name": "PBSreferenceMaterials", - "display_name": "PBS Reference Materials", - "license": "Apache-2.0 Or MIT", - "origin": "Open 3D Engine - o3de.org", - "type": "Asset", - "summary": "The PBS Reference Materials Gem provides physically based reference materials for Open 3D Engine.", - "canonical_tags": [ - "Gem" - ], - "user_tags": [ - "Rendering", - "Sample", - "Assets" - ], - "icon_path": "preview.png", - "requirements": "", - "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/rendering/pbs-reference-materials/", - "dependencies": [] -} diff --git a/Gems/PBSreferenceMaterials/preview.png b/Gems/PBSreferenceMaterials/preview.png deleted file mode 100644 index 51c277678f..0000000000 --- a/Gems/PBSreferenceMaterials/preview.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:097b03d36a65678b4e12e2c0830707480034fe31fe4efba9c848bb58440eb9fb -size 24928 diff --git a/engine.json b/engine.json index 63bddc9548..2b56e255fc 100644 --- a/engine.json +++ b/engine.json @@ -53,7 +53,6 @@ "Gems/Multiplayer", "Gems/MultiplayerCompression", "Gems/NvCloth", - "Gems/PBSreferenceMaterials", "Gems/PhysX", "Gems/PhysXDebug", "Gems/PhysXSamples", From 36e201a1be032b5777b4b9a5d0ef148d76672753 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 12 Oct 2021 11:22:53 -0500 Subject: [PATCH 192/293] Update PropertyAssetCtrl and ThumbnailPropertyCtrl to support custom images Signed-off-by: Guthrie Adams --- .../UI/PropertyEditor/PropertyAssetCtrl.cpp | 57 +++++++- .../UI/PropertyEditor/PropertyAssetCtrl.hxx | 5 + .../PropertyEditor/ThumbnailPropertyCtrl.cpp | 127 +++++++++++------- .../UI/PropertyEditor/ThumbnailPropertyCtrl.h | 25 +++- 4 files changed, 159 insertions(+), 55 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index ba84e662c1..7f3b9e61fd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -28,6 +28,9 @@ AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option") #include #include #include +#include +#include +#include AZ_POP_DISABLE_WARNING #include @@ -1230,6 +1233,16 @@ namespace AzToolsFramework return m_showThumbnailDropDownButton; } + void PropertyAssetCtrl::SetCustomThumbnailEnabled(bool enabled) + { + m_thumbnail->SetCustomThumbnailEnabled(enabled); + } + + void PropertyAssetCtrl::SetCustomThumbnailPixmap(const QPixmap& pixmap) + { + m_thumbnail->SetCustomThumbnailPixmap(pixmap); + } + void PropertyAssetCtrl::SetThumbnailCallback(EditCallbackType* editNotifyCallback) { m_thumbnailCallback = editNotifyCallback; @@ -1356,15 +1369,27 @@ namespace AzToolsFramework GUI->SetClearNotifyCallback(nullptr); } } - else if (attrib == AZ_CRC("BrowseIcon", 0x507d7a4f)) + else if (attrib == AZ_CRC_CE("BrowseIcon")) { AZStd::string iconPath; - attrValue->Read(iconPath); - - if (!iconPath.empty()) + if (attrValue->Read(iconPath) && !iconPath.empty()) { GUI->SetBrowseButtonIcon(QIcon(iconPath.c_str())); } + else + { + // A QPixmap object can't be assigned directly via an attribute. + // This allows dynamic icon data to be supplied as a buffer containing a serialized QPixmap. + AZStd::vector pixmapBuffer; + if (attrValue->Read>(pixmapBuffer) && !pixmapBuffer.empty()) + { + QByteArray pixmapBytes(pixmapBuffer.data(), aznumeric_cast(pixmapBuffer.size())); + QDataStream stream(&pixmapBytes, QIODevice::ReadOnly); + QPixmap pixmap; + stream >> pixmap; + GUI->SetBrowseButtonIcon(pixmap); + } + } } else if (attrib == AZ_CRC_CE("BrowseButtonEnabled")) { @@ -1390,6 +1415,30 @@ namespace AzToolsFramework GUI->SetShowThumbnail(showThumbnail); } } + else if (attrib == AZ_CRC_CE("ThumbnailIcon")) + { + AZStd::string iconPath; + if (attrValue->Read(iconPath) && !iconPath.empty()) + { + GUI->SetCustomThumbnailEnabled(true); + GUI->SetCustomThumbnailPixmap(QPixmap::fromImage(QImage(iconPath.c_str()))); + } + else + { + // A QPixmap object can't be assigned directly via an attribute. + // This allows dynamic icon data to be supplied as a buffer containing a serialized QPixmap. + AZStd::vector pixmapBuffer; + if (attrValue->Read>(pixmapBuffer) && !pixmapBuffer.empty()) + { + QByteArray pixmapBytes(pixmapBuffer.data(), aznumeric_cast(pixmapBuffer.size())); + QDataStream stream(&pixmapBytes, QIODevice::ReadOnly); + QPixmap pixmap; + stream >> pixmap; + GUI->SetCustomThumbnailEnabled(true); + GUI->SetCustomThumbnailPixmap(pixmap); + } + } + } else if (attrib == AZ_CRC_CE("ThumbnailCallback")) { PropertyAssetCtrl::EditCallbackType* func = azdynamic_cast(attrValue->GetAttribute()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index cc4aff5649..0b98278bc5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -217,12 +217,17 @@ namespace AzToolsFramework void SetHideProductFilesInAssetPicker(bool hide); bool GetHideProductFilesInAssetPicker() const; + // Enable and configure a thumbnail widget that displays an asset preview and dropdown arrow for a dropdown menu void SetShowThumbnail(bool enable); bool GetShowThumbnail() const; void SetShowThumbnailDropDownButton(bool enable); bool GetShowThumbnailDropDownButton() const; void SetThumbnailCallback(EditCallbackType* editNotifyCallback); + // If enabled, replaces the thumbnail widget content with a custom pixmap + void SetCustomThumbnailEnabled(bool enabled); + void SetCustomThumbnailPixmap(const QPixmap& pixmap); + void SetSelectedAssetID(const AZ::Data::AssetId& newID); void SetCurrentAssetType(const AZ::Data::AssetType& newType); void SetSelectedAssetID(const AZ::Data::AssetId& newID, const AZ::Data::AssetType& newType); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp index c458f7c47e..d8ddee6b76 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp @@ -7,75 +7,117 @@ */ #include -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: 'QRawFont::d': class 'QExplicitlySharedDataPointer' needs to have dll-interface to be used by clients of class 'QRawFont' - // 4800: 'QTextEngine *const ': forcing value to bool 'true' or 'false' (performance warning) -#include -#include + +// 4251: 'QRawFont::d': class 'QExplicitlySharedDataPointer' needs to have dll-interface to be used by clients of class +// 'QRawFont' 4800: 'QTextEngine *const ': forcing value to bool 'true' or 'false' (performance warning) +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") +#include #include +#include +#include #include -#include #include -#include +#include AZ_POP_DISABLE_WARNING #include "ThumbnailPropertyCtrl.h" namespace AzToolsFramework { - ThumbnailPropertyCtrl::ThumbnailPropertyCtrl(QWidget* parent) : QWidget(parent) { - QHBoxLayout* pLayout = new QHBoxLayout(); - pLayout->setContentsMargins(0, 0, 0, 0); - pLayout->setSpacing(0); - m_thumbnail = new Thumbnailer::ThumbnailWidget(this); m_thumbnail->setFixedSize(QSize(24, 24)); + m_thumbnailEnlarged = new Thumbnailer::ThumbnailWidget(this); + m_thumbnailEnlarged->setFixedSize(QSize(180, 180)); + m_thumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + + m_customThumbnail = new QLabel(this); + m_customThumbnail->setFixedSize(QSize(24, 24)); + m_customThumbnail->setScaledContents(true); + + m_customThumbnailEnlarged = new QLabel(this); + m_customThumbnailEnlarged->setFixedSize(QSize(180, 180)); + m_customThumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + m_customThumbnailEnlarged->setScaledContents(true); + m_dropDownArrow = new AspectRatioAwarePixmapWidget(this); m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0.png")); m_dropDownArrow->setFixedSize(QSize(8, 24)); - ShowDropDownArrow(false); m_emptyThumbnail = new QLabel(this); m_emptyThumbnail->setPixmap(QPixmap(":/stylesheet/img/line.png")); m_emptyThumbnail->setFixedSize(QSize(24, 24)); - pLayout->addWidget(m_emptyThumbnail); + QHBoxLayout* pLayout = new QHBoxLayout(); + pLayout->setContentsMargins(0, 0, 0, 0); + pLayout->setSpacing(0); pLayout->addWidget(m_thumbnail); + pLayout->addWidget(m_customThumbnail); + pLayout->addWidget(m_emptyThumbnail); pLayout->addSpacing(4); pLayout->addWidget(m_dropDownArrow); pLayout->addSpacing(4); - setLayout(pLayout); + + ShowDropDownArrow(false); + UpdateVisibility(); } void ThumbnailPropertyCtrl::SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName) { - m_key = key; - m_emptyThumbnail->setVisible(false); - m_thumbnail->SetThumbnailKey(key, contextName); + if (m_customThumbnailEnabled) + { + ClearThumbnail(); + } + else + { + m_key = key; + m_thumbnail->SetThumbnailKey(m_key, contextName); + m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName); + } + UpdateVisibility(); } void ThumbnailPropertyCtrl::ClearThumbnail() { - m_emptyThumbnail->setVisible(true); + m_key.clear(); m_thumbnail->ClearThumbnail(); + m_thumbnailEnlarged->ClearThumbnail(); + UpdateVisibility(); } void ThumbnailPropertyCtrl::ShowDropDownArrow(bool visible) { - if (visible) - { - setFixedSize(QSize(40, 24)); - } - else - { - setFixedSize(QSize(24, 24)); - } + setFixedSize(QSize(visible ? 40 : 24, 24)); m_dropDownArrow->setVisible(visible); } + void ThumbnailPropertyCtrl::SetCustomThumbnailEnabled(bool enabled) + { + m_customThumbnailEnabled = enabled; + UpdateVisibility(); + } + + void ThumbnailPropertyCtrl::SetCustomThumbnailPixmap(const QPixmap& pixmap) + { + m_customThumbnail->setPixmap(pixmap); + m_customThumbnailEnlarged->setPixmap(pixmap); + UpdateVisibility(); + } + + void ThumbnailPropertyCtrl::UpdateVisibility() + { + m_thumbnail->setVisible(m_key && !m_customThumbnailEnabled); + m_thumbnailEnlarged->setVisible(false); + + m_customThumbnail->setVisible(m_customThumbnailEnabled); + m_customThumbnailEnlarged->setVisible(false); + + m_emptyThumbnail->setVisible(!m_key && !m_customThumbnailEnabled); + } + bool ThumbnailPropertyCtrl::event(QEvent* e) { if (isEnabled()) @@ -83,7 +125,7 @@ namespace AzToolsFramework if (e->type() == QEvent::MouseButtonPress) { emit clicked(); - return true; //ignore + return true; // ignore } } @@ -94,37 +136,32 @@ namespace AzToolsFramework { QPainter p(this); QRect targetRect(QPoint(), QSize(40, 24)); - p.fillRect(targetRect, QColor(17, 17, 17)); // #111111 + p.fillRect(targetRect, QColor("#111111")); QWidget::paintEvent(e); } void ThumbnailPropertyCtrl::enterEvent(QEvent* e) { m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0_highlighted.png")); - if (!m_thumbnailEnlarged && m_key) - { - QPoint position = mapToGlobal(pos() - QPoint(185, 0)); - QSize size(180, 180); - m_thumbnailEnlarged.reset(new Thumbnailer::ThumbnailWidget()); - m_thumbnailEnlarged->setFixedSize(size); - m_thumbnailEnlarged->move(position); - m_thumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); - m_thumbnailEnlarged->SetThumbnailKey(m_key); - m_thumbnailEnlarged->raise(); - m_thumbnailEnlarged->show(); - } + const QPoint offset(-m_thumbnailEnlarged->width() - 5, -m_thumbnailEnlarged->height() / 2 + m_thumbnail->height() / 2); + + m_thumbnailEnlarged->move(mapToGlobal(pos()) + offset); + m_thumbnailEnlarged->raise(); + m_thumbnailEnlarged->setVisible(m_key && !m_customThumbnailEnabled); + + m_customThumbnailEnlarged->move(mapToGlobal(pos()) + offset); + m_customThumbnailEnlarged->raise(); + m_customThumbnailEnlarged->setVisible(m_customThumbnailEnabled); QWidget::enterEvent(e); } void ThumbnailPropertyCtrl::leaveEvent(QEvent* e) { m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0.png")); - if (m_thumbnailEnlarged) - { - m_thumbnailEnlarged.reset(); - } + m_thumbnailEnlarged->setVisible(false); + m_customThumbnailEnlarged->setVisible(false); QWidget::leaveEvent(e); } -} +} // namespace AzToolsFramework #include "UI/PropertyEditor/moc_ThumbnailPropertyCtrl.cpp" diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h index 93f703c4c5..b1ce78b601 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h @@ -1,5 +1,3 @@ -#pragma once - /* * 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. @@ -8,6 +6,8 @@ * */ +#pragma once + #if !defined(Q_MOC_RUN) #include #include @@ -35,25 +35,38 @@ namespace AzToolsFramework //! Call this to set what thumbnail widget will display void SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName = "Default"); + //! Remove current thumbnail void ClearThumbnail(); + //! Display a clickble dropdown arrow next to the thumbnail void ShowDropDownArrow(bool visible); - bool event(QEvent* e) override; + //! Override the thumbnail widget with a custom image + void SetCustomThumbnailEnabled(bool enabled); + + //! Assign a custom image to dispsy in place of thumbnail + void SetCustomThumbnailPixmap(const QPixmap& pixmap); Q_SIGNALS: void clicked(); - protected: + private: + void UpdateVisibility(); + + bool event(QEvent* e) override; void paintEvent(QPaintEvent* e) override; void enterEvent(QEvent* e) override; void leaveEvent(QEvent* e) override; - private: Thumbnailer::SharedThumbnailKey m_key; Thumbnailer::ThumbnailWidget* m_thumbnail = nullptr; - QScopedPointer m_thumbnailEnlarged; + Thumbnailer::ThumbnailWidget* m_thumbnailEnlarged = nullptr; + + QLabel* m_customThumbnail = nullptr; + QLabel* m_customThumbnailEnlarged = nullptr; + bool m_customThumbnailEnabled = false; + QLabel* m_emptyThumbnail = nullptr; AspectRatioAwarePixmapWidget* m_dropDownArrow = nullptr; }; From 26aa7495a228670e31ef85201625b7633318fa39 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 12 Oct 2021 11:26:14 -0500 Subject: [PATCH 193/293] Changed preview renderer states to use construction and destruction instead of start and stop functions to make sure everything is shut down cleanly Signed-off-by: Guthrie Adams --- .../PreviewRenderer/PreviewRenderer.h | 14 +------ .../PreviewRenderer/PreviewRendererState.h | 6 --- .../PreviewRenderer/PreviewRenderer.cpp | 42 +++++-------------- .../PreviewRendererCaptureState.cpp | 21 +++------- .../PreviewRendererCaptureState.h | 6 +-- .../PreviewRendererIdleState.cpp | 6 +-- .../PreviewRendererIdleState.h | 4 +- .../PreviewRendererLoadState.cpp | 17 +++----- .../PreviewRendererLoadState.h | 6 +-- 9 files changed, 29 insertions(+), 93 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h index d4fdd3ca1e..dc03ed6715 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h @@ -47,17 +47,6 @@ namespace AtomToolsFramework AZ::RPI::ViewPtr GetView() const; AZ::Uuid GetEntityContextId() const; - enum class State : AZ::s8 - { - None, - IdleState, - LoadState, - CaptureState - }; - - void SetState(State state); - State GetState() const; - void ProcessCaptureRequests(); void CancelCaptureRequest(); void CompleteCaptureRequest(); @@ -91,7 +80,6 @@ namespace AtomToolsFramework AZStd::queue m_captureRequestQueue; CaptureRequest m_currentCaptureRequest; - AZStd::unordered_map> m_states; - State m_currentState = PreviewRenderer::State::None; + AZStd::unique_ptr m_state; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h index 264c37a122..bf68795974 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h @@ -23,12 +23,6 @@ namespace AtomToolsFramework virtual ~PreviewRendererState() = default; - //! Start is called when state begins execution - virtual void Start() = 0; - - //! Stop is called when state ends execution - virtual void Stop() = 0; - protected: PreviewRenderer* m_renderer = {}; }; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 69a8d357c9..3e4fde4e08 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -79,17 +79,15 @@ namespace AtomToolsFramework m_view->SetViewToClipMatrix(viewToClipMatrix); m_renderPipeline->SetDefaultView(m_view); - m_states[PreviewRenderer::State::IdleState] = AZStd::make_shared(this); - m_states[PreviewRenderer::State::LoadState] = AZStd::make_shared(this); - m_states[PreviewRenderer::State::CaptureState] = AZStd::make_shared(this); - SetState(PreviewRenderer::State::IdleState); + m_state.reset(new PreviewRendererIdleState(this)); } PreviewRenderer::~PreviewRenderer() { PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); - SetState(PreviewRenderer::State::None); + m_state.reset(); + m_currentCaptureRequest = {}; m_captureRequestQueue = {}; @@ -120,28 +118,6 @@ namespace AtomToolsFramework return m_entityContext->GetContextId(); } - void PreviewRenderer::SetState(State state) - { - auto stepItr = m_states.find(m_currentState); - if (stepItr != m_states.end()) - { - stepItr->second->Stop(); - } - - m_currentState = state; - - stepItr = m_states.find(m_currentState); - if (stepItr != m_states.end()) - { - stepItr->second->Start(); - } - } - - PreviewRenderer::State PreviewRenderer::GetState() const - { - return m_currentState; - } - void PreviewRenderer::ProcessCaptureRequests() { if (!m_captureRequestQueue.empty()) @@ -150,19 +126,22 @@ namespace AtomToolsFramework m_currentCaptureRequest = m_captureRequestQueue.front(); m_captureRequestQueue.pop(); - SetState(PreviewRenderer::State::LoadState); + m_state.reset(); + m_state.reset(new PreviewRendererLoadState(this)); } } void PreviewRenderer::CancelCaptureRequest() { m_currentCaptureRequest.m_captureFailedCallback(); - SetState(PreviewRenderer::State::IdleState); + m_state.reset(); + m_state.reset(new PreviewRendererIdleState(this)); } void PreviewRenderer::CompleteCaptureRequest() { - SetState(PreviewRenderer::State::IdleState); + m_state.reset(); + m_state.reset(new PreviewRendererIdleState(this)); } void PreviewRenderer::LoadContent() @@ -174,7 +153,8 @@ namespace AtomToolsFramework { if (m_currentCaptureRequest.m_content->IsReady()) { - SetState(PreviewRenderer::State::CaptureState); + m_state.reset(); + m_state.reset(new PreviewRendererCaptureState(this)); return; } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp index 9cf228b707..9a807b7d00 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp @@ -14,32 +14,23 @@ namespace AtomToolsFramework PreviewRendererCaptureState::PreviewRendererCaptureState(PreviewRenderer* renderer) : PreviewRendererState(renderer) { - } - - void PreviewRendererCaptureState::Start() - { - m_ticksToCapture = 1; m_renderer->PoseContent(); AZ::TickBus::Handler::BusConnect(); } - void PreviewRendererCaptureState::Stop() + PreviewRendererCaptureState::~PreviewRendererCaptureState() { - m_renderer->EndCapture(); - AZ::TickBus::Handler::BusDisconnect(); AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); + AZ::TickBus::Handler::BusDisconnect(); + m_renderer->EndCapture(); } void PreviewRendererCaptureState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - if (m_ticksToCapture-- <= 0) + if ((m_ticksToCapture-- <= 0) && m_renderer->StartCapture()) { - // Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick. - if (m_renderer->StartCapture()) - { - AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(); - AZ::TickBus::Handler::BusDisconnect(); - } + AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusDisconnect(); } } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h index 190cb919df..e8c6357445 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h @@ -22,9 +22,7 @@ namespace AtomToolsFramework { public: PreviewRendererCaptureState(PreviewRenderer* renderer); - - void Start() override; - void Stop() override; + ~PreviewRendererCaptureState(); private: //! AZ::TickBus::Handler interface overrides... @@ -34,6 +32,6 @@ namespace AtomToolsFramework void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override; //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials - int m_ticksToCapture = 0; + int m_ticksToCapture = 1; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp index 800aa03113..c440bafb73 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp @@ -13,15 +13,11 @@ namespace AtomToolsFramework { PreviewRendererIdleState::PreviewRendererIdleState(PreviewRenderer* renderer) : PreviewRendererState(renderer) - { - } - - void PreviewRendererIdleState::Start() { AZ::TickBus::Handler::BusConnect(); } - void PreviewRendererIdleState::Stop() + PreviewRendererIdleState::~PreviewRendererIdleState() { AZ::TickBus::Handler::BusDisconnect(); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h index 9e5380e734..f024bd8e30 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h @@ -20,9 +20,7 @@ namespace AtomToolsFramework { public: PreviewRendererIdleState(PreviewRenderer* renderer); - - void Start() override; - void Stop() override; + ~PreviewRendererIdleState(); private: //! AZ::TickBus::Handler interface overrides... diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp index bb858989f7..7e34592095 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp @@ -13,31 +13,24 @@ namespace AtomToolsFramework { PreviewRendererLoadState::PreviewRendererLoadState(PreviewRenderer* renderer) : PreviewRendererState(renderer) - { - } - - void PreviewRendererLoadState::Start() { m_renderer->LoadContent(); - m_timeRemainingS = TimeOutS; AZ::TickBus::Handler::BusConnect(); } - void PreviewRendererLoadState::Stop() + PreviewRendererLoadState::~PreviewRendererLoadState() { AZ::TickBus::Handler::BusDisconnect(); } void PreviewRendererLoadState::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - m_timeRemainingS -= deltaTime; - if (m_timeRemainingS > 0.0f) - { - m_renderer->UpdateLoadContent(); - } - else + if ((m_timeRemainingS += deltaTime) > TimeOutS) { m_renderer->CancelLoadContent(); + return; } + + m_renderer->UpdateLoadContent(); } } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h index 623d6cbdfc..702a01e862 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h @@ -20,15 +20,13 @@ namespace AtomToolsFramework { public: PreviewRendererLoadState(PreviewRenderer* renderer); - - void Start() override; - void Stop() override; + ~PreviewRendererLoadState(); private: //! AZ::TickBus::Handler interface overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; static constexpr float TimeOutS = 5.0f; - float m_timeRemainingS = TimeOutS; + float m_timeRemainingS = 0.0f; }; } // namespace AtomToolsFramework From 736c2fe27bab37239ccc0b29b55bbe918b35483a Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Tue, 12 Oct 2021 10:41:27 -0700 Subject: [PATCH 194/293] [O3DE][GameLift] Add client side change for starting and stopping matchmaking (#4536) * [O3DE][GameLift] Add client side change for starting and stopping matchmaking Signed-off-by: Junbo Liang --- .../Matchmaking/MatchmakingRequests.h | 1 + .../AWSGameLiftStartMatchmakingRequest.h | 3 + .../Source/AWSGameLiftClientManager.cpp | 109 +++++++- .../Source/AWSGameLiftClientManager.h | 4 + .../Activity/AWSGameLiftActivityUtils.cpp | 49 ++++ .../Activity/AWSGameLiftActivityUtils.h | 13 + .../AWSGameLiftStartMatchmakingActivity.cpp | 120 +++++++++ .../AWSGameLiftStartMatchmakingActivity.h | 34 +++ .../AWSGameLiftStopMatchmakingActivity.cpp | 61 +++++ .../AWSGameLiftStopMatchmakingActivity.h | 34 +++ .../Tests/AWSGameLiftClientManagerTest.cpp | 243 ++++++++++++++++++ .../Tests/AWSGameLiftClientMocks.h | 28 ++ ...WSGameLiftStartMatchmakingActivityTest.cpp | 152 +++++++++++ ...AWSGameLiftStopMatchmakingActivityTest.cpp | 38 +++ .../awsgamelift_client_files.cmake | 4 + .../awsgamelift_client_tests_files.cmake | 2 + 16 files changed, 890 insertions(+), 5 deletions(-) create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h index 58e335696f..9169a83588 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h +++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include namespace AZ diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h index cd30bc45ab..d734daa808 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h @@ -8,6 +8,9 @@ #pragma once +#include +#include + #include namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp index ee731993aa..91e76380eb 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include @@ -43,10 +45,22 @@ namespace AWSGameLift AZ::Interface::Register(this); AWSGameLiftSessionRequestBus::Handler::BusConnect(); + + AZ::Interface::Register(this); + AWSGameLiftMatchmakingAsyncRequestBus::Handler::BusConnect(); + + AZ::Interface::Register(this); + AWSGameLiftMatchmakingRequestBus::Handler::BusConnect(); } void AWSGameLiftClientManager::DeactivateManager() { + AWSGameLiftMatchmakingRequestBus::Handler::BusDisconnect(); + AZ::Interface::Unregister(this); + + AWSGameLiftMatchmakingAsyncRequestBus::Handler::BusDisconnect(); + AZ::Interface::Unregister(this); + AWSGameLiftSessionRequestBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); @@ -357,23 +371,108 @@ namespace AWSGameLift AZStd::string AWSGameLiftClientManager::StartMatchmaking(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) { - AZ_UNUSED(startMatchmakingRequest); + AZStd::string response; + if (StartMatchmakingActivity::ValidateStartMatchmakingRequest(startMatchmakingRequest)) + { + const AWSGameLiftStartMatchmakingRequest& gameliftStartMatchmakingRequest = + static_cast(startMatchmakingRequest); + response = StartMatchmakingHelper(gameliftStartMatchmakingRequest); + } - return AZStd::string{}; + return response; } void AWSGameLiftClientManager::StartMatchmakingAsync(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) { - AZ_UNUSED(startMatchmakingRequest); + if (!StartMatchmakingActivity::ValidateStartMatchmakingRequest(startMatchmakingRequest)) + { + AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( + &AzFramework::MatchmakingAsyncRequestNotifications::OnStartMatchmakingAsyncComplete, AZStd::string{}); + return; + } + + const AWSGameLiftStartMatchmakingRequest& gameliftStartMatchmakingRequest = + static_cast(startMatchmakingRequest); + + AZ::JobContext* jobContext = nullptr; + AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext); + AZ::Job* startMatchmakingJob = AZ::CreateJobFunction( + [this, gameliftStartMatchmakingRequest]() + { + AZStd::string response = StartMatchmakingHelper(gameliftStartMatchmakingRequest); + + AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( + &AzFramework::MatchmakingAsyncRequestNotifications::OnStartMatchmakingAsyncComplete, response); + }, + true, jobContext); + + startMatchmakingJob->Start(); + } + + AZStd::string AWSGameLiftClientManager::StartMatchmakingHelper(const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest) + { + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); + + AZStd::string response; + if (!gameliftClient) + { + AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage); + } + else + { + response = StartMatchmakingActivity::StartMatchmaking(*gameliftClient, startMatchmakingRequest); + } + return response; } void AWSGameLiftClientManager::StopMatchmaking(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) { - AZ_UNUSED(stopMatchmakingRequest); + if (StopMatchmakingActivity::ValidateStopMatchmakingRequest(stopMatchmakingRequest)) + { + const AWSGameLiftStopMatchmakingRequest& gameliftStopMatchmakingRequest = + static_cast(stopMatchmakingRequest); + StopMatchmakingHelper(gameliftStopMatchmakingRequest); + } } void AWSGameLiftClientManager::StopMatchmakingAsync(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) { - AZ_UNUSED(stopMatchmakingRequest); + if (!StopMatchmakingActivity::ValidateStopMatchmakingRequest(stopMatchmakingRequest)) + { + AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( + &AzFramework::MatchmakingAsyncRequestNotifications::OnStopMatchmakingAsyncComplete); + return; + } + + const AWSGameLiftStopMatchmakingRequest& gameliftStopMatchmakingRequest = + static_cast(stopMatchmakingRequest); + + AZ::JobContext* jobContext = nullptr; + AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext); + AZ::Job* stopMatchmakingJob = AZ::CreateJobFunction( + [this, gameliftStopMatchmakingRequest]() + { + StopMatchmakingHelper(gameliftStopMatchmakingRequest); + + AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( + &AzFramework::MatchmakingAsyncRequestNotifications::OnStopMatchmakingAsyncComplete); + }, + true, jobContext); + + stopMatchmakingJob->Start(); + } + + void AWSGameLiftClientManager::StopMatchmakingHelper(const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest) + { + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); + + if (!gameliftClient) + { + AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage); + } + else + { + StopMatchmakingActivity::StopMatchmaking(*gameliftClient, stopMatchmakingRequest); + } } } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h index fbdc1d6104..ba81196b07 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h @@ -19,6 +19,8 @@ namespace AWSGameLift struct AWSGameLiftCreateSessionOnQueueRequest; struct AWSGameLiftJoinSessionRequest; struct AWSGameLiftSearchSessionsRequest; + struct AWSGameLiftStartMatchmakingRequest; + struct AWSGameLiftStopMatchmakingRequest; // MatchAcceptanceNotificationBus EBus handler for scripting class AWSGameLiftMatchAcceptanceNotificationBusHandler @@ -160,5 +162,7 @@ namespace AWSGameLift AZStd::string CreateSessionOnQueueHelper(const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest); bool JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest); AzFramework::SearchSessionsResponse SearchSessionsHelper(const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) const; + AZStd::string StartMatchmakingHelper(const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest); + void StopMatchmakingHelper(const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest); }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.cpp index 5bbd1d4654..f9968a7dd9 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.cpp @@ -6,6 +6,7 @@ * */ +#include #include namespace AWSGameLift @@ -31,5 +32,53 @@ namespace AWSGameLift outGamePropertiesOutput.substr(0, outGamePropertiesOutput.size() - 1); // Trim last comma to fit array format } } + + void ConvertPlayerAttributes( + const AZStd::unordered_map& playerAttributes, + Aws::Map& outPlayerAttributes) + { + outPlayerAttributes.clear(); + for (auto& playerAttribute : playerAttributes) + { + Aws::Utils::Json::JsonValue keyJsonValue(playerAttribute.second.c_str()); + Aws::GameLift::Model::AttributeValue attribute(keyJsonValue); + outPlayerAttributes[playerAttribute.first.c_str()] = attribute; + } + } + + void ConvertRegionToLatencyMap( + const AZStd::unordered_map& regionToLatencyMap, + Aws::Map& outRegionToLatencyMap) + { + outRegionToLatencyMap.clear(); + for (auto& regionToLatencyPair : regionToLatencyMap) + { + outRegionToLatencyMap[regionToLatencyPair.first.c_str()] = regionToLatencyPair.second; + } + } + + bool ValidatePlayerAttributes( + const AZStd::unordered_map& playerAttributes) + { + for (auto& playerAttribute : playerAttributes) + { + Aws::Utils::Json::JsonValue keyJsonValue(playerAttribute.second.c_str()); + Aws::GameLift::Model::AttributeValue attribute(keyJsonValue); + + // Each AttributeValue object can use only one of the available properties: + // 1) number values (N) + // 2) single string values (S) + // 3) string to double map (SDM) + // 4) array of strings (SL) + if (!attribute.SHasBeenSet() && + !attribute.NHasBeenSet() && + !attribute.SDMHasBeenSet() && + !attribute.SLHasBeenSet()) + { + return false; + } + } + return true; + } } // namespace AWSGameLiftActivityUtils } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.h index 05ab2867d0..729f1deec6 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftActivityUtils.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace AWSGameLift { @@ -21,5 +22,17 @@ namespace AWSGameLift const AZStd::unordered_map& sessionProperties, Aws::Vector& outGameProperties, AZStd::string& outGamePropertiesOutput); + + void ConvertPlayerAttributes( + const AZStd::unordered_map& playerAttributes, + Aws::Map& outPlayerAttributes); + + void ConvertRegionToLatencyMap( + const AZStd::unordered_map& regionToLatencyMap, + Aws::Map& outRegionToLatencyMap); + + bool ValidatePlayerAttributes( + const AZStd::unordered_map& playerAttributes); + } // namespace AWSGameLiftActivityUtils } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp new file mode 100644 index 0000000000..2b2a32f74b --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#include + +#include +#include +#include + +namespace AWSGameLift +{ + namespace StartMatchmakingActivity + { + Aws::GameLift::Model::StartMatchmakingRequest BuildAWSGameLiftStartMatchmakingRequest( + const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest) + { + Aws::GameLift::Model::StartMatchmakingRequest request; + if (!startMatchmakingRequest.m_configurationName.empty()) + { + request.SetConfigurationName(startMatchmakingRequest.m_configurationName.c_str()); + } + + Aws::Vector players; + for (const AWSGameLiftPlayerInformation& playerInfo : startMatchmakingRequest.m_players) + { + Aws::GameLift::Model::Player player; + if (!playerInfo.m_playerId.empty()) + { + player.SetPlayerId(playerInfo.m_playerId.c_str()); + } + + // Optional attributes + if (!playerInfo.m_team.empty()) + { + player.SetTeam(playerInfo.m_team.c_str()); + } + if (playerInfo.m_latencyInMs.size() > 0) + { + Aws::Map regionToLatencyMap; + AWSGameLiftActivityUtils::ConvertRegionToLatencyMap(playerInfo.m_latencyInMs, regionToLatencyMap); + player.SetLatencyInMs(AZStd::move(regionToLatencyMap)); + } + if (playerInfo.m_playerAttributes.size() > 0) + { + Aws::Map playerAttributes; + AWSGameLiftActivityUtils::ConvertPlayerAttributes(playerInfo.m_playerAttributes, playerAttributes); + player.SetPlayerAttributes(AZStd::move(playerAttributes)); + } + players.emplace_back(player); + } + if (startMatchmakingRequest.m_players.size() > 0) + { + request.SetPlayers(players); + } + + // Optional attributes + if (!startMatchmakingRequest.m_ticketId.empty()) + { + request.SetTicketId(startMatchmakingRequest.m_ticketId.c_str()); + } + + AZ_TracePrintf(AWSGameLiftStartMatchmakingActivityName, + "Built StartMatchmakingRequest with TicketId=%s, ConfigurationName=%s and PlayersCount=%d", + request.GetTicketId().c_str(), + request.GetConfigurationName().c_str(), + request.GetPlayers().size()); + + return request; + } + + AZStd::string StartMatchmaking( + const Aws::GameLift::GameLiftClient& gameliftClient, + const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest) + { + AZ_TracePrintf(AWSGameLiftStartMatchmakingActivityName, "Requesting StartMatchmaking against Amazon GameLift service ..."); + + AZStd::string result = ""; + Aws::GameLift::Model::StartMatchmakingRequest request = BuildAWSGameLiftStartMatchmakingRequest(startMatchmakingRequest); + auto startMatchmakingOutcome = gameliftClient.StartMatchmaking(request); + if (startMatchmakingOutcome.IsSuccess()) + { + result = AZStd::string(startMatchmakingOutcome.GetResult().GetMatchmakingTicket().GetTicketId().c_str()); + + AZ_TracePrintf(AWSGameLiftStartMatchmakingActivityName, "StartMatchmaking request against Amazon GameLift service is complete"); + } + else + { + AZ_Error(AWSGameLiftStartMatchmakingActivityName, false, AWSGameLiftErrorMessageTemplate, + startMatchmakingOutcome.GetError().GetExceptionName().c_str(), startMatchmakingOutcome.GetError().GetMessage().c_str()); + } + + return result; + } + + bool ValidateStartMatchmakingRequest(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) + { + auto gameliftStartMatchmakingRequest = azrtti_cast(&startMatchmakingRequest); + bool isValid = gameliftStartMatchmakingRequest && + (!gameliftStartMatchmakingRequest->m_configurationName.empty()) && + gameliftStartMatchmakingRequest->m_players.size() > 0; + + if (isValid) + { + for (const AWSGameLiftPlayerInformation& playerInfo : gameliftStartMatchmakingRequest->m_players) + { + isValid &= !playerInfo.m_playerId.empty(); + isValid &= AWSGameLiftActivityUtils::ValidatePlayerAttributes(playerInfo.m_playerAttributes); + } + } + + AZ_Error(AWSGameLiftStartMatchmakingActivityName, isValid, AWSGameLiftStartMatchmakingRequestInvalidErrorMessage); + + return isValid; + } + } // namespace StartMatchmakingActivity +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h new file mode 100644 index 0000000000..5f8c4558f4 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +#include +#include +#include + +namespace AWSGameLift +{ + namespace StartMatchmakingActivity + { + static constexpr const char AWSGameLiftStartMatchmakingActivityName[] = "AWSGameLiftStartMatchmakingActivity"; + static constexpr const char AWSGameLiftStartMatchmakingRequestInvalidErrorMessage[] = "Invalid GameLift StartMatchmaking request."; + + // Build AWS GameLift StartMatchmakingRequest by using AWSGameLiftStartMatchmakingRequest + Aws::GameLift::Model::StartMatchmakingRequest BuildAWSGameLiftStartMatchmakingRequest(const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest); + + // Create StartMatchmakingRequest and make a StartMatchmaking call through GameLift client + // Will also start polling the matchmaking ticket when get success outcome from GameLift client + AZStd::string StartMatchmaking(const Aws::GameLift::GameLiftClient& gameliftClient, const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest); + + // Validate StartMatchmakingRequest and check required request parameters + bool ValidateStartMatchmakingRequest(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest); + } // namespace StartMatchmakingActivity +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp new file mode 100644 index 0000000000..204923fc02 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp @@ -0,0 +1,61 @@ +/* + * 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.StopMatchmaking + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +namespace AWSGameLift +{ + namespace StopMatchmakingActivity + { + Aws::GameLift::Model::StopMatchmakingRequest BuildAWSGameLiftStopMatchmakingRequest( + const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest) + { + Aws::GameLift::Model::StopMatchmakingRequest request; + if (!stopMatchmakingRequest.m_ticketId.empty()) + { + request.SetTicketId(stopMatchmakingRequest.m_ticketId.c_str()); + } + + AZ_TracePrintf(AWSGameLiftStopMatchmakingActivityName, "Built StopMatchmakingRequest with TicketId=%s", request.GetTicketId().c_str()); + + return request; + } + + void StopMatchmaking(const Aws::GameLift::GameLiftClient& gameliftClient, + const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest) + { + AZ_TracePrintf(AWSGameLiftStopMatchmakingActivityName, "Requesting StopMatchmaking against Amazon GameLift service ..."); + + Aws::GameLift::Model::StopMatchmakingRequest request = BuildAWSGameLiftStopMatchmakingRequest(stopMatchmakingRequest); + auto stopMatchmakingOutcome = gameliftClient.StopMatchmaking(request); + + if (stopMatchmakingOutcome.IsSuccess()) + { + AZ_TracePrintf(AWSGameLiftStopMatchmakingActivityName, "StopMatchmaking request against Amazon GameLift service is complete"); + } + else + { + AZ_Error(AWSGameLiftStopMatchmakingActivityName, false, AWSGameLiftErrorMessageTemplate, + stopMatchmakingOutcome.GetError().GetExceptionName().c_str(), stopMatchmakingOutcome.GetError().GetMessage().c_str()); + } + } + + bool ValidateStopMatchmakingRequest(const AzFramework::StopMatchmakingRequest& StopMatchmakingRequest) + { + auto gameliftStopMatchmakingRequest = azrtti_cast(&StopMatchmakingRequest); + bool isValid = gameliftStopMatchmakingRequest && (!gameliftStopMatchmakingRequest->m_ticketId.empty()); + + AZ_Error(AWSGameLiftStopMatchmakingActivityName, isValid, AWSGameLiftStopMatchmakingRequestInvalidErrorMessage); + + return isValid; + } + } // namespace StopMatchmakingActivity +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h new file mode 100644 index 0000000000..9bfeb86343 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +#include +#include +#include + +namespace AWSGameLift +{ + namespace StopMatchmakingActivity + { + static constexpr const char AWSGameLiftStopMatchmakingActivityName[] = "AWSGameLiftStopMatchmakingActivity"; + static constexpr const char AWSGameLiftStopMatchmakingRequestInvalidErrorMessage[] = "Invalid GameLift StopMatchmaking request."; + + // Build AWS GameLift StopMatchmakingRequest by using AWSGameLiftStopMatchmakingRequest + Aws::GameLift::Model::StopMatchmakingRequest BuildAWSGameLiftStopMatchmakingRequest(const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest); + + // Create StopMatchmakingRequest and make a StopMatchmaking call through GameLift client + // Will also stop polling the matchmaking ticket when get success outcome from GameLift client + void StopMatchmaking(const Aws::GameLift::GameLiftClient& gameliftClient, const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest); + + // Validate StopMatchmakingRequest and check required request parameters + bool ValidateStopMatchmakingRequest(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest); + } // namespace StopMatchmakingActivity +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp index e7612618ee..2fa332df72 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include using namespace AWSGameLift; @@ -223,11 +225,43 @@ protected: return response; } + AWSGameLiftStartMatchmakingRequest GetValidStartMatchmakingRequest() + { + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + request.m_ticketId = DummyMatchmakingTicketId; + + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"N\": \"1\"}"; + player.m_playerId = DummyPlayerId; + player.m_latencyInMs["us-east-1"] = 10; + request.m_players.emplace_back(player); + + return request; + } + + Aws::GameLift::Model::StartMatchmakingOutcome GetValidStartMatchmakingResponse() + { + Aws::GameLift::Model::MatchmakingTicket ticket; + ticket.SetTicketId(DummyMatchmakingTicketId); + Aws::GameLift::Model::StartMatchmakingResult result; + result.SetMatchmakingTicket(ticket); + Aws::GameLift::Model::StartMatchmakingOutcome outcome(result); + + return outcome; + } + + static const char* const DummyMatchmakingTicketId; + static const char* const DummyPlayerId; + public: AZStd::unique_ptr m_gameliftClientManager; AZStd::shared_ptr m_gameliftClientMockPtr; }; +const char* const AWSGameLiftClientManagerTest::DummyMatchmakingTicketId = "dummyTicketId"; +const char* const AWSGameLiftClientManagerTest::DummyPlayerId = "dummyPlayerId"; + TEST_F(AWSGameLiftClientManagerTest, ConfigureGameLiftClient_CallWithoutRegion_GetFalseAsResult) { AZ_TEST_START_TRACE_SUPPRESSION; @@ -762,3 +796,212 @@ TEST_F(AWSGameLiftClientManagerTest, LeaveSessionAsync_CallWithInterfaceRegister m_gameliftClientManager->LeaveSessionAsync(); } + +TEST_F(AWSGameLiftClientManagerTest, StartMatchmaking_CallWithoutClientSetup_GetFalseResponse) +{ + AWSGameLiftStartMatchmakingRequest request = GetValidStartMatchmakingRequest(); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->ConfigureGameLiftClient(""); + AZStd::string response = m_gameliftClientManager->StartMatchmaking(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message + EXPECT_TRUE(response.empty()); + +} +TEST_F(AWSGameLiftClientManagerTest, StartMatchmaking_CallWithInvalidRequest_GetErrorWithEmptyResponse) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"A\": \"1\"}"; + request.m_players.emplace_back(player); + + AZ_TEST_START_TRACE_SUPPRESSION; + AZStd::string response = m_gameliftClientManager->StartMatchmaking(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message + EXPECT_TRUE(response.empty()); +} + +TEST_F(AWSGameLiftClientManagerTest, StartMatchmaking_CallWithValidRequest_GetSuccessOutcome) +{ + AWSGameLiftStartMatchmakingRequest request = GetValidStartMatchmakingRequest(); + Aws::GameLift::Model::StartMatchmakingOutcome outcome = GetValidStartMatchmakingResponse(); + + EXPECT_CALL(*m_gameliftClientMockPtr, StartMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + AZStd::string response = m_gameliftClientManager->StartMatchmaking(request); + EXPECT_EQ(response, DummyMatchmakingTicketId); +} + +TEST_F(AWSGameLiftClientManagerTest, StartMatchmaking_CallWithValidRequest_GetErrorOutcome) +{ + AWSGameLiftStartMatchmakingRequest request = GetValidStartMatchmakingRequest(); + + Aws::Client::AWSError error; + Aws::GameLift::Model::StartMatchmakingOutcome outcome(error); + + EXPECT_CALL(*m_gameliftClientMockPtr, StartMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->StartMatchmaking(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, StartMatchmakingAsync_CallWithInvalidRequest_GetNotificationWithErrorOutcome) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"A\": \"1\"}"; + request.m_players.emplace_back(player); + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnStartMatchmakingAsyncComplete(AZStd::string{})).Times(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->StartMatchmakingAsync(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, StartMatchmakingAsync_CallWithValidRequest_GetNotificationWithSuccessOutcome) +{ + AWSCoreRequestsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get())); + + AWSGameLiftStartMatchmakingRequest request = GetValidStartMatchmakingRequest(); + Aws::GameLift::Model::StartMatchmakingOutcome outcome = GetValidStartMatchmakingResponse(); + + EXPECT_CALL(*m_gameliftClientMockPtr, StartMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnStartMatchmakingAsyncComplete(AZStd::string(DummyMatchmakingTicketId))).Times(1); + + m_gameliftClientManager->StartMatchmakingAsync(request); +} + +TEST_F(AWSGameLiftClientManagerTest, StartMatchmakingAsync_CallWithValidRequest_GetNotificationWithErrorOutcome) +{ + AWSCoreRequestsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get())); + + AWSGameLiftStartMatchmakingRequest request = GetValidStartMatchmakingRequest(); + + Aws::Client::AWSError error; + Aws::GameLift::Model::StartMatchmakingOutcome outcome(error); + EXPECT_CALL(*m_gameliftClientMockPtr, StartMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnStartMatchmakingAsyncComplete(AZStd::string{})).Times(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->StartMatchmakingAsync(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, StopMatchmaking_CallWithoutClientSetup_GetError) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->ConfigureGameLiftClient(""); + AWSGameLiftStopMatchmakingRequest request; + request.m_ticketId = DummyMatchmakingTicketId; + + m_gameliftClientManager->StopMatchmaking(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message +} +TEST_F(AWSGameLiftClientManagerTest, StopMatchmaking_CallWithInvalidRequest_GetError) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->StopMatchmaking(AzFramework::StopMatchmakingRequest()); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, StopMatchmaking_CallWithValidRequest_Success) +{ + AWSGameLiftStopMatchmakingRequest request; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::GameLift::Model::StopMatchmakingResult result; + Aws::GameLift::Model::StopMatchmakingResult outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, StopMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + m_gameliftClientManager->StopMatchmaking(request); +} + +TEST_F(AWSGameLiftClientManagerTest, StopMatchmaking_CallWithValidRequest_GetError) +{ + AWSGameLiftStopMatchmakingRequest request; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::Client::AWSError error; + Aws::GameLift::Model::StopMatchmakingOutcome outcome(error); + + EXPECT_CALL(*m_gameliftClientMockPtr, StopMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->StopMatchmaking(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, StopMatchmakingAsync_CallWithInvalidRequest_GetNotificationWithError) +{ + AWSGameLiftStopMatchmakingRequest request; + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnStopMatchmakingAsyncComplete()).Times(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->StopMatchmakingAsync(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, StopMatchmakingAsync_CallWithValidRequest_GetNotification) +{ + AWSCoreRequestsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get())); + + AWSGameLiftStopMatchmakingRequest request; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::GameLift::Model::StopMatchmakingResult result; + Aws::GameLift::Model::StopMatchmakingOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, StopMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnStopMatchmakingAsyncComplete()).Times(1); + + m_gameliftClientManager->StopMatchmakingAsync(request); +} + +TEST_F(AWSGameLiftClientManagerTest, StopMatchmakingAsync_CallWithValidRequest_GetNotificationWithError) +{ + AWSCoreRequestsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get())); + + AWSGameLiftStopMatchmakingRequest request; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::Client::AWSError error; + Aws::GameLift::Model::StopMatchmakingOutcome outcome(error); + EXPECT_CALL(*m_gameliftClientMockPtr, StopMatchmaking(::testing::_)) + .Times(1) + .WillOnce(::testing::Return(outcome)); + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnStopMatchmakingAsyncComplete()).Times(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->StopMatchmakingAsync(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h index 5c09f43e08..964b6a21c2 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,12 @@ #include #include #include +#include +#include +#include +#include + +#include using namespace Aws::GameLift; @@ -44,6 +51,27 @@ public: MOCK_CONST_METHOD1(DescribeMatchmaking, Model::DescribeMatchmakingOutcome(const Model::DescribeMatchmakingRequest&)); MOCK_CONST_METHOD1(SearchGameSessions, Model::SearchGameSessionsOutcome(const Model::SearchGameSessionsRequest&)); MOCK_CONST_METHOD1(StartGameSessionPlacement, Model::StartGameSessionPlacementOutcome(const Model::StartGameSessionPlacementRequest&)); + MOCK_CONST_METHOD1(StartMatchmaking, Model::StartMatchmakingOutcome(const Model::StartMatchmakingRequest&)); + MOCK_CONST_METHOD1(StopMatchmaking, Model::StopMatchmakingOutcome(const Model::StopMatchmakingRequest&)); +}; + +class MatchmakingAsyncRequestNotificationsHandlerMock + : public AzFramework::MatchmakingAsyncRequestNotificationBus::Handler +{ +public: + MatchmakingAsyncRequestNotificationsHandlerMock() + { + AzFramework::MatchmakingAsyncRequestNotificationBus::Handler::BusConnect(); + } + + ~MatchmakingAsyncRequestNotificationsHandlerMock() + { + AzFramework::MatchmakingAsyncRequestNotificationBus::Handler::BusDisconnect(); + } + + MOCK_METHOD0(OnAcceptMatchAsyncComplete, void()); + MOCK_METHOD1(OnStartMatchmakingAsyncComplete, void(const AZStd::string&)); + MOCK_METHOD0(OnStopMatchmakingAsyncComplete, void()); }; class SessionAsyncRequestNotificationsHandlerMock diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp new file mode 100644 index 0000000000..706aec04f2 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +using namespace AWSGameLift; + +using AWSGameLiftStartMatchmakingActivityTest = AWSGameLiftClientFixture; + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, BuildAWSGameLiftStartMatchmakingRequest_Call_GetExpectedResult) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + request.m_ticketId = "dummyTicketId"; + + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; + player.m_playerId = "dummyPlayerId"; + player.m_team = "dummyTeam"; + player.m_latencyInMs["us-east-1"] = 10; + request.m_players.emplace_back(player); + auto awsRequest = StartMatchmakingActivity::BuildAWSGameLiftStartMatchmakingRequest(request); + + EXPECT_TRUE(strcmp(awsRequest.GetConfigurationName().c_str(), request.m_configurationName.c_str()) == 0); + EXPECT_TRUE(strcmp(awsRequest.GetTicketId().c_str(), request.m_ticketId.c_str()) == 0); + + EXPECT_TRUE(awsRequest.GetPlayers().size() == request.m_players.size()); + EXPECT_TRUE(strcmp(awsRequest.GetPlayers()[0].GetPlayerId().c_str(), request.m_players[0].m_playerId.c_str()) == 0); + EXPECT_TRUE(strcmp(awsRequest.GetPlayers()[0].GetTeam().c_str(), request.m_players[0].m_team.c_str()) == 0); + + EXPECT_TRUE(awsRequest.GetPlayers()[0].GetLatencyInMs().size() == request.m_players[0].m_latencyInMs.size()); + EXPECT_TRUE(strcmp(awsRequest.GetPlayers()[0].GetLatencyInMs().begin()->first.c_str(), request.m_players[0].m_latencyInMs.begin()->first.c_str()) == 0); + EXPECT_TRUE(awsRequest.GetPlayers()[0].GetLatencyInMs().begin()->second == request.m_players[0].m_latencyInMs.begin()->second); + + EXPECT_TRUE(awsRequest.GetPlayers()[0].GetPlayerAttributes().size() == request.m_players[0].m_playerAttributes.size()); + EXPECT_TRUE(strcmp(awsRequest.GetPlayers()[0].GetPlayerAttributes().begin()->first.c_str(), request.m_players[0].m_playerAttributes.begin()->first.c_str()) == 0); + EXPECT_TRUE(strcmp(awsRequest.GetPlayers()[0].GetPlayerAttributes().begin()->second.GetS().c_str(), "test") == 0); +} + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithBaseType_GetFalseResult) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(AzFramework::StartMatchmakingRequest()); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithoutConfigurationName_GetFalseResult) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_ticketId = "dummyTicketId"; + + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; + player.m_playerId = "dummyPlayerId"; + player.m_team = "dummyTeam"; + player.m_latencyInMs["us-east-1"] = 10; + request.m_players.emplace_back(player); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(request); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithoutPlayers_GetFalseResult) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + request.m_ticketId = "dummyTicketId"; + + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(request); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithoutPlayerId_GetFalseResult) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + request.m_ticketId = "dummyTicketId"; + + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; + player.m_team = "dummyTeam"; + player.m_latencyInMs["us-east-1"] = 10; + request.m_players.emplace_back(player); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(request); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithInvalidPlayerAttribute_GetFalseResult) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + request.m_ticketId = "dummyTicketId"; + + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"A\": \"test\"}"; + player.m_playerId = "dummyPlayerId"; + player.m_team = "dummyTeam"; + player.m_latencyInMs["us-east-1"] = 10; + request.m_players.emplace_back(player); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(request); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithoutTicketId_GetTrueResult) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_configurationName = "dummyConfiguration"; + + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; + player.m_playerId = "dummyPlayerId"; + player.m_team = "dummyTeam"; + player.m_latencyInMs["us-east-1"] = 10; + request.m_players.emplace_back(player); + + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(request); + EXPECT_TRUE(result); +} + +TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithValidParameters_GetTrueResult) +{ + AWSGameLiftStartMatchmakingRequest request; + request.m_ticketId = "dummyTicketId"; + request.m_configurationName = "dummyConfiguration"; + + AWSGameLiftPlayerInformation player; + player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; + player.m_playerId = "dummyPlayerId"; + player.m_team = "dummyTeam"; + player.m_latencyInMs["us-east-1"] = 10; + request.m_players.emplace_back(player); + + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(request); + EXPECT_TRUE(result); +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp new file mode 100644 index 0000000000..6b53ed5055 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +using namespace AWSGameLift; + +using AWSGameLiftStopMatchmakingActivityTest = AWSGameLiftClientFixture; + +TEST_F(AWSGameLiftStopMatchmakingActivityTest, BuildAWSGameLiftStopMatchmakingRequest_Call_GetExpectedResult) +{ + AWSGameLiftStopMatchmakingRequest request; + request.m_ticketId = "dummyTicketId"; + auto awsRequest = StopMatchmakingActivity::BuildAWSGameLiftStopMatchmakingRequest(request); + EXPECT_TRUE(strcmp(awsRequest.GetTicketId().c_str(), request.m_ticketId.c_str()) == 0); +} + +TEST_F(AWSGameLiftStopMatchmakingActivityTest, ValidateStopMatchmakingRequest_CallWithoutTicketId_GetFalseResult) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = StopMatchmakingActivity::ValidateStopMatchmakingRequest(AzFramework::StopMatchmakingRequest()); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftStopMatchmakingActivityTest, ValidateStopMatchmakingRequest_CallWithTicketId_GetTrueResult) +{ + AWSGameLiftStopMatchmakingRequest request; + request.m_ticketId = "dummyTicketId"; + auto result = StopMatchmakingActivity::ValidateStopMatchmakingRequest(request); + EXPECT_TRUE(result); +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake index d3b9d8d1b9..3122ff2261 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake @@ -30,6 +30,10 @@ set(FILES Source/Activity/AWSGameLiftSearchSessionsActivity.h Source/AWSGameLiftClientLocalTicketTracker.cpp Source/AWSGameLiftClientLocalTicketTracker.h + Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp + Source/Activity/AWSGameLiftStartMatchmakingActivity.h + Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp + Source/Activity/AWSGameLiftStopMatchmakingActivity.h Source/AWSGameLiftClientManager.cpp Source/AWSGameLiftClientManager.h Source/AWSGameLiftClientSystemComponent.cpp diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake index 130ed28e4e..f8ef40d5df 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake @@ -11,6 +11,8 @@ set(FILES Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp + Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp + Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp Tests/AWSGameLiftClientFixture.h Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp Tests/AWSGameLiftClientManagerTest.cpp From e8142fa403a7e932e361ef03bfcce5652051fa43 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 12 Oct 2021 13:19:38 -0500 Subject: [PATCH 195/293] Updated editor material component slots to support dynamic previews rendered with property overrides applied Fixed scaling issues with labels used for images Reduced updating previews and material component inspector to only apply after a value is committed Storing cache of previously rendered material previews Signed-off-by: Guthrie Adams --- ...orMaterialSystemComponentNotificationBus.h | 5 +- .../EditorMaterialSystemComponentRequestBus.h | 7 ++- .../Material/EditorMaterialComponent.cpp | 14 +++++ .../Source/Material/EditorMaterialComponent.h | 10 ++- .../EditorMaterialComponentInspector.cpp | 14 +++-- .../EditorMaterialComponentInspector.h | 2 - .../Material/EditorMaterialComponentSlot.cpp | 61 +++++++++++++------ .../Material/EditorMaterialComponentSlot.h | 38 ++++++++---- .../EditorMaterialSystemComponent.cpp | 29 +++++++++ .../Material/EditorMaterialSystemComponent.h | 12 +++- 10 files changed, 148 insertions(+), 44 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h index 4e655c7835..30762a60ba 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h @@ -10,7 +10,6 @@ #include #include #include -#include class QPixmap; @@ -18,11 +17,11 @@ namespace AZ { namespace Render { - //! EditorMaterialSystemComponentNotifications provides an interface to communicate with EditorMaterialSystemComponent + //! EditorMaterialSystemComponentNotifications is an interface for handling notifications from EditorMaterialSystemComponent, like + //! being informed that material preview images are available class EditorMaterialSystemComponentNotifications : public AZ::EBusTraits { public: - // Only a single handler is allowed static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h index 059e6dec8e..0bf93fc56f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h @@ -17,7 +17,8 @@ namespace AZ { namespace Render { - //! EditorMaterialSystemComponentRequests provides an interface to communicate with MaterialEditor + //! EditorMaterialSystemComponentRequests provides an interface for interacting with EditorMaterialSystemComponent, performing + //! different operations like opening the material editor, the material instance inspector, and managing material preview images class EditorMaterialSystemComponentRequests : public AZ::EBusTraits { public: @@ -35,6 +36,10 @@ namespace AZ //! Generate a material preview image virtual void RenderMaterialPreview( const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0; + + //! Get recently rendered material preview image + virtual QPixmap GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const = 0; }; using EditorMaterialSystemComponentRequestBus = AZ::EBus; } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 8e5e7e2345..a3ae61b14b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -148,11 +148,13 @@ namespace AZ BaseClass::Activate(); MaterialReceiverNotificationBus::Handler::BusConnect(GetEntityId()); MaterialComponentNotificationBus::Handler::BusConnect(GetEntityId()); + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); UpdateMaterialSlots(); } void EditorMaterialComponent::Deactivate() { + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); MaterialReceiverNotificationBus::Handler::BusDisconnect(); MaterialComponentNotificationBus::Handler::BusDisconnect(); BaseClass::Deactivate(); @@ -260,6 +262,18 @@ namespace AZ } } + void EditorMaterialComponent::OnRenderMaterialPreviewComplete( + [[maybe_unused]] const AZ::EntityId& entityId, + [[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId, + [[maybe_unused]] const QPixmap& pixmap) + { + if (entityId == GetEntityId()) + { + AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( + &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues); + } + } + AZ::u32 EditorMaterialComponent::OnConfigurationChanged() { return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h index f8895d994f..ce21ae82ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -21,8 +22,9 @@ namespace AZ //! In-editor material component for displaying and editing material assignments. class EditorMaterialComponent final : public EditorRenderComponentAdapter - , private MaterialReceiverNotificationBus::Handler - , private MaterialComponentNotificationBus::Handler + , public MaterialReceiverNotificationBus::Handler + , public MaterialComponentNotificationBus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler { public: using BaseClass = EditorRenderComponentAdapter; @@ -52,6 +54,10 @@ namespace AZ //! MaterialComponentNotificationBus::Handler overrides... void OnMaterialInstanceCreated(const MaterialAssignment& materialAssignment) override; + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override; + // Regenerates the editor component material slots based on the material and // LOD mapping from the model or other consumer of materials. // If any corresponding material assignments are found in the component diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 7562049031..9cf39483fe 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -170,6 +170,7 @@ namespace AZ m_overviewImage = new QLabel(this); m_overviewImage->setFixedSize(QSize(120, 120)); + m_overviewImage->setScaledContents(true); m_overviewImage->setVisible(false); m_overviewText = new QLabel(this); @@ -241,8 +242,14 @@ namespace AZ m_overviewText->setText(materialInfo); m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); + + QPixmap pixmap; + EditorMaterialSystemComponentRequestBus::BroadcastResult( + pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, + m_materialAssignmentId); + m_overviewImage->setPixmap(pixmap); m_overviewImage->setVisible(true); - m_updatePreview = true; + m_updatePreview |= pixmap.isNull(); } void MaterialPropertyInspector::AddUvNamesGroup() @@ -400,7 +407,8 @@ namespace AZ m_internalEditNotification = false; } - m_updatePreview = true; + // m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs + // throttling } void MaterialPropertyInspector::RunEditorMaterialFunctors() @@ -779,5 +787,3 @@ namespace AZ } // namespace EditorMaterialComponentInspector } // namespace Render } // namespace AZ - -//#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h index 6199fba179..82f46ebc90 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h @@ -32,8 +32,6 @@ namespace AZ { namespace EditorMaterialComponentInspector { - using PropertyChangedCallback = AZStd::function; - class MaterialPropertyInspector : public AtomToolsFramework::InspectorWidget , public AzToolsFramework::IPropertyEditorNotify diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 21d045a072..d65fd0f2af 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -6,23 +6,25 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include +#include +#include #include +#include +#include AZ_POP_DISABLE_WARNING namespace AZ @@ -100,6 +102,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel) ->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true) ->Attribute("ThumbnailCallback", &EditorMaterialComponentSlot::OpenPopupMenu) + ->Attribute("ThumbnailIcon", &EditorMaterialComponentSlot::GetPreviewPixmapData) ; } } @@ -118,6 +121,33 @@ namespace AZ } }; + AZStd::vector EditorMaterialComponentSlot::GetPreviewPixmapData() const + { + if (!GetActiveAssetId().IsValid()) + { + return {}; + } + + QPixmap pixmap; + EditorMaterialSystemComponentRequestBus::BroadcastResult( + pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, m_id); + if (pixmap.isNull()) + { + if (m_updatePreview) + { + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id); + m_updatePreview = false; + } + return {}; + } + + QByteArray pixmapBytes; + QDataStream stream(&pixmapBytes, QIODevice::WriteOnly); + stream << pixmap; + return AZStd::vector(pixmapBytes.begin(), pixmapBytes.end()); + } + AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const { return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId(); @@ -169,14 +199,6 @@ namespace AZ ClearOverrides(); } - void EditorMaterialComponentSlot::ClearToDefaultAsset() - { - m_materialAsset = AZ::Data::Asset(GetDefaultAssetId(), AZ::AzTypeInfo::Uuid()); - MaterialComponentRequestBus::Event( - m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId()); - ClearOverrides(); - } - void EditorMaterialComponentSlot::ClearOverrides() { MaterialComponentRequestBus::Event( @@ -317,6 +339,7 @@ namespace AZ EditorMaterialSystemComponentRequestBus::Broadcast( &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id); + m_updatePreview = false; MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h index 377fe9a18b..78fc7449de 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h @@ -8,37 +8,52 @@ #pragma once -#include -#include - -#include -#include #include +#include +#include +#include +#include +#include namespace AZ { namespace Render { - static const size_t DefaultMaterialSlotIndex = std::numeric_limits::max(); - //! Details for a single editable material assignment struct EditorMaterialComponentSlot final { AZ_RTTI(EditorMaterialComponentSlot, "{344066EB-7C3D-4E92-B53D-3C9EBD546488}"); AZ_CLASS_ALLOCATOR(EditorMaterialComponentSlot, SystemAllocator, 0); - static void Reflect(ReflectContext* context); static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); + static void Reflect(ReflectContext* context); + + //! Get cached preview image as a buffer to use as an RPE attribute + //! If a cached image isn't avalible then a request will be made to render one + AZStd::vector GetPreviewPixmapData() const; + //! Returns the overridden asset id if it's valid, otherwise gets the default asseet id AZ::Data::AssetId GetActiveAssetId() const; + + //! Returns the default asseet id of the material provded by the model AZ::Data::AssetId GetDefaultAssetId() const; + + //! Returns the display name of the material slot AZStd::string GetLabel() const; + + //! Returns true if the active material asset has a source material bool HasSourceData() const; + //! Assign a new material override asset void SetAsset(const Data::AssetId& assetId); + + //! Assign a new material override asset void SetAsset(const Data::Asset& asset); + + //! Remove material and prperty overrides void Clear(); - void ClearToDefaultAsset(); + + //! Remove prperty overrides void ClearOverrides(); void OpenMaterialExporter(); @@ -54,6 +69,7 @@ namespace AZ void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType); void OnMaterialChanged() const; void OnDataChanged() const; + mutable bool m_updatePreview = true; }; // Vector of slots for assignable or overridable material data. @@ -62,8 +78,8 @@ namespace AZ // Table containing all editable material data that is displayed in the edit context and inspector // The vector represents all the LODs that can have material overrides. // The container will be populated with every potential material slot on an associated model, using its default values. - // Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment map - // as overrides that will be applied to material instances + // Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment + // map as overrides that will be applied to material instances using EditorMaterialComponentSlotsByLodContainer = AZStd::vector; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index 96a8e3e8d4..0939c8548b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -88,6 +88,7 @@ namespace AZ void EditorMaterialSystemComponent::Activate() { + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); EditorMaterialSystemComponentRequestBus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect(); @@ -100,6 +101,7 @@ namespace AZ { AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect(); @@ -167,6 +169,10 @@ namespace AZ { MaterialComponentRequestBus::EventResult( materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, materialAssignmentId); + if (!materialAssetId.IsValid()) + { + return; + } } AZ::Render::MaterialPropertyOverrideMap propertyOverrides; @@ -193,6 +199,29 @@ namespace AZ } } + QPixmap EditorMaterialSystemComponent::GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const + { + const auto& itr1 = m_materialPreviews.find(entityId); + if (itr1 != m_materialPreviews.end()) + { + const auto& itr2 = itr1->second.find(materialAssignmentId); + if (itr2 != itr1->second.end()) + { + return itr2->second; + } + } + return QPixmap(); + } + + void EditorMaterialSystemComponent::OnRenderMaterialPreviewComplete( + [[maybe_unused]] const AZ::EntityId& entityId, + [[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId, + [[maybe_unused]] const QPixmap& pixmap) + { + m_materialPreviews[entityId][materialAssignmentId] = pixmap; + } + void EditorMaterialSystemComponent::OnPopulateToolMenuItems() { if (!m_openMaterialEditorAction) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h index f2ccbdc435..e62c9b64dc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h @@ -16,6 +16,7 @@ #include #include #include +#include namespace AZ { @@ -24,6 +25,7 @@ namespace AZ //! System component that manages launching and maintaining connections with the material editor. class EditorMaterialSystemComponent final : public AZ::Component + , public EditorMaterialSystemComponentNotificationBus::Handler , public EditorMaterialSystemComponentRequestBus::Handler , public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler , public AzToolsFramework::EditorMenuNotificationBus::Handler @@ -50,8 +52,13 @@ namespace AZ //! EditorMaterialSystemComponentRequestBus::Handler overrides... void OpenMaterialEditor(const AZStd::string& sourcePath) override; void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; - void RenderMaterialPreview( - const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; + void RenderMaterialPreview(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; + QPixmap GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const override; + + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)override; //! AssetBrowserInteractionNotificationBus::Handler overrides... AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override; @@ -73,6 +80,7 @@ namespace AZ QAction* m_openMaterialEditorAction = nullptr; AZStd::unique_ptr m_materialBrowserInteractions; AZStd::unique_ptr m_previewRenderer; + AZStd::unordered_map> m_materialPreviews; }; } // namespace Render } // namespace AZ From 7fcaeb16c49d9c64ddc7b1874527de84b08dbea9 Mon Sep 17 00:00:00 2001 From: smurly Date: Tue, 12 Oct 2021 11:23:29 -0700 Subject: [PATCH 196/293] PostFX Layer component P0 parallel test (#4619) * PostFX Layer component P0 parallel test Signed-off-by: Scott Murray * removing an unused import Signed-off-by: Scott Murray --- .../Atom/TestSuite_Main_Optimized.py | 4 + ...a_AtomEditorComponents_PostFXLayerAdded.py | 156 ++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index ec3d76758c..31b4cb687d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -63,5 +63,9 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_MaterialAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module + @pytest.mark.test_case_id("C32078127") + class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py new file mode 100644 index 0000000000..8c2dee416b --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py @@ -0,0 +1,156 @@ +""" +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: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + postfx_layer_entity_creation = ( + "PostFX Layer Entity successfully created", + "PostFX Layer Entity failed to be created") + postfx_layer_component_added = ( + "Entity has a PostFX Layer component", + "Entity failed to find PostFX Layer component") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_postfx_layer_AddedToEntity(): + """ + Summary: + Tests the PostFX Layer component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a PostFX Layer entity with no components. + 2) Add a PostFX Layer component to PostFX Layer entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Enter/Exit game mode. + 6) Test IsHidden. + 7) Test IsVisible. + 8) Delete PostFX Layer entity. + 9) UNDO deletion. + 10) REDO deletion. + 11) Look for errors. + + :return: None + """ + + import os + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create a PostFX Layer entity with no components. + postfx_layer_name = "PostFX Layer" + postfx_layer_entity = EditorEntity.create_editor_entity(postfx_layer_name) + Report.critical_result(Tests.postfx_layer_entity_creation, postfx_layer_entity.exists()) + + # 2. Add a PostFX Layer component to PostFX Layer entity. + postfx_layer_component = postfx_layer_entity.add_component(postfx_layer_name) + Report.critical_result(Tests.postfx_layer_component_added, postfx_layer_entity.has_component(postfx_layer_name)) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not postfx_layer_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, postfx_layer_entity.exists()) + + # 5. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 6. Test IsHidden. + postfx_layer_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, postfx_layer_entity.is_hidden() is True) + + # 7. Test IsVisible. + postfx_layer_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, postfx_layer_entity.is_visible() is True) + + # 8. Delete PostFX Layer entity. + postfx_layer_entity.delete() + Report.result(Tests.entity_deleted, not postfx_layer_entity.exists()) + + # 9. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, postfx_layer_entity.exists()) + + # 10. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not postfx_layer_entity.exists()) + + # 11. Look for errors or asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_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(AtomEditorComponents_postfx_layer_AddedToEntity) From 94c938496eb3b78900000ded65fa3ab8696cd8ab Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Tue, 12 Oct 2021 13:46:54 -0500 Subject: [PATCH 197/293] Fixed logic error causing Python Scripts tree items to only show extension intead of filename. Signed-off-by: Chris Galvan --- Code/Editor/Controls/FolderTreeCtrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Editor/Controls/FolderTreeCtrl.cpp b/Code/Editor/Controls/FolderTreeCtrl.cpp index 4088ab976f..1464580ffc 100644 --- a/Code/Editor/Controls/FolderTreeCtrl.cpp +++ b/Code/Editor/Controls/FolderTreeCtrl.cpp @@ -279,7 +279,7 @@ void CFolderTreeCtrl::LoadTreeRec(const QString& currentFolder) void CFolderTreeCtrl::AddItem(const QString& path) { AZ::IO::FixedMaxPath folder{ AZ::IO::PathView(path.toUtf8().constData()) }; - AZ::IO::FixedMaxPath fileNameWithoutExtension = folder.Extension(); + AZ::IO::FixedMaxPath fileNameWithoutExtension = folder.Stem(); folder = folder.ParentPath(); auto regex = QRegExp(m_fileNameSpec, Qt::CaseInsensitive, QRegExp::Wildcard); From 05767f2d2b89f456dca74e66d69e2c0c5f882431 Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:40:12 -0400 Subject: [PATCH 198/293] Atom Timer fix - changed milliseconds to seconds (#4631) * Atom Timer fix - changed milliseconds to seconds - Tested on both fog and EyeAdaptation animations - both are the only affected and were broken before - This is a small fix for pull #3969 that replaced the timer mechanism: https://github.com/o3de/o3de/pull/3969 Signed-off-by: Adi-Amazon * Atom Timer fix - using seconds to begin with and removing obsolete variable Signed-off-by: Adi-Amazon --- Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h | 3 --- Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp | 4 +--- 3 files changed, 2 insertions(+), 7 deletions(-) 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 90389687de..fcf812cc38 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h @@ -228,9 +228,6 @@ namespace AZ PipelineViewMap m_pipelineViewsByTag; - /// The system time when the last time this pipeline render was started - float m_lastRenderStartTime = 0; - // RenderPipeline's name id, it will be used to identify the render pipeline when it's added to a Scene RenderPipelineId m_nameId; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 5df1c655d6..eb74a81e3e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -263,7 +263,7 @@ namespace AZ 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.GetMilliseconds()); + m_tickTime.m_currentGameTime = static_cast(currentTime.GetSeconds()); } void RPISystem::RenderTick() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 1b99abae4e..6378a249a4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -375,12 +375,10 @@ namespace AZ m_scene->RemoveRenderPipeline(m_nameId); } - void RenderPipeline::OnStartFrame(const TickTimeInfo& tick) + void RenderPipeline::OnStartFrame([[maybe_unused]] const TickTimeInfo& tick) { AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame"); - m_lastRenderStartTime = tick.m_currentGameTime; - OnPassModified(); for (auto& viewItr : m_pipelineViewsByTag) From 8487373b0cf1fe02210a083a9548cfc8ad4b7b79 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 12 Oct 2021 14:41:26 -0500 Subject: [PATCH 199/293] Updated thumbnail notification bus to use const QPixmap& Signed-off-by: Guthrie Adams --- .../AzToolsFramework/Thumbnails/ThumbnailerBus.h | 2 +- .../Code/Source/Thumbnail/ImageThumbnail.cpp | 2 +- .../ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h | 2 +- .../CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp | 2 +- .../CommonFeatures/Code/Source/Material/MaterialThumbnail.h | 2 +- .../CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp | 2 +- .../CommonFeatures/Code/Source/Mesh/MeshThumbnail.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h index 6f074da878..acd8ba3966 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/ThumbnailerBus.h @@ -90,7 +90,7 @@ namespace AzToolsFramework typedef SharedThumbnailKey BusIdType; //! notify product thumbnail that the data is ready - virtual void ThumbnailRendered(QPixmap& thumbnailImage) = 0; + virtual void ThumbnailRendered(const QPixmap& thumbnailImage) = 0; //! notify product thumbnail that the thumbnail failed to render virtual void ThumbnailFailedToRender() = 0; }; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp index 084e38a2db..cdd63dca18 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp @@ -67,7 +67,7 @@ namespace ImageProcessingAtom m_renderWait.acquire(); } - void ImageThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void ImageThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h index 45fd178285..eadbfca945 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.h @@ -34,7 +34,7 @@ namespace ImageProcessingAtom ~ImageThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailRendered(const QPixmap& thumbnailImage) override; void ThumbnailFailedToRender() override; protected: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp index 0723859ff5..2931b647e5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp @@ -54,7 +54,7 @@ namespace AZ AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } - void MaterialThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void MaterialThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h index dba922a1b2..8f2053ba67 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h @@ -36,7 +36,7 @@ namespace AZ ~MaterialThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailRendered(const QPixmap& thumbnailImage) override; void ThumbnailFailedToRender() override; protected: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp index 658d420a16..845197d939 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp @@ -55,7 +55,7 @@ namespace AZ AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } - void MeshThumbnail::ThumbnailRendered(QPixmap& thumbnailImage) + void MeshThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) { m_pixmap = thumbnailImage; m_renderWait.release(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h index 2975b6950c..872e1029d2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h @@ -35,7 +35,7 @@ namespace AZ ~MeshThumbnail() override; //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(QPixmap& thumbnailImage) override; + void ThumbnailRendered(const QPixmap& thumbnailImage) override; void ThumbnailFailedToRender() override; protected: From 4c5906a8d46f0f69ed590407396368d47cd0d79b Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Tue, 12 Oct 2021 13:21:55 -0700 Subject: [PATCH 200/293] PostFX Shape Weight Modifier component P0 parallel test Signed-off-by: Scott Murray --- .../Atom/TestSuite_Main_Optimized.py | 4 + ...mponents_PostFxShapeWeightModifierAdded.py | 211 ++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index 31b4cb687d..447a4ebac9 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -67,5 +67,9 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module + @pytest.mark.test_case_id("C36525665") + class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py new file mode 100644 index 0000000000..be139f83b6 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py @@ -0,0 +1,211 @@ +""" +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: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + postfx_shape_weight_creation = ( + "PostFx Shape Weight Modifier Entity successfully created", + "PostFx Shape Weight Modifier Entity failed to be created") + postfx_shape_weight_component = ( + "Entity has a PostFx Shape Weight Modifier component", + "Entity failed to find PostFx Shape Weight Modifier component") + postfx_shape_weight_disabled = ( + "PostFx Shape Weight Modifier component disabled", + "PostFx Shape Weight Modifier component was not disabled.") + postfx_layer_component = ( + "Entity has an Actor component", + "Entity did not have an Actor component") + shape_component = ( + "Entity has a Tube Shape component", + "Entity did not have a Tube Shape component") + shape_undo = ( + "Entity shape component add undone", + "Entity shape component undo failed to remove shape") + postfx_shape_weight_enabled = ( + "PostFx Shape Weight Modifier component enabled", + "PostFx Shape Weight Modifier component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): + """ + Summary: + Tests the PostFx Shape Weight Modifier component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a PostFx Shape Weight Modifier entity with no components. + 2) Add a PostFx Shape Weight Modifier component to PostFx Shape Weight Modifier entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Verify PostFx Shape Weight Modifier component not enabled. + 6) Add PostFX Layer component since it is required by the PostFx Shape Weight Modifier component. + 7) Verify PostFx Shape Weight Modifier component is NOT enabled since it also requires a shape. + 8) Add a required shape looping over a list and checking if it enables PostFX Shape Weight Modifier. + 9) Undo to remove each added shape and verify PostFX Shape Weight Modifier is not enabled + 10) Verify PostFx Shape Weight Modifier component is enabled by adding Spline and Tube Shape componen. + 11) Enter/Exit game mode. + 12) Test IsHidden. + 13) Test IsVisible. + 14) Delete PostFx Shape Weight Modifier entity. + 15) UNDO deletion. + 16) REDO deletion. + 17) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create a PostFx Shape Weight Modifier entity with no components. + postfx_shape_weight_name = "PostFX Shape Weight Modifier" + postfx_shape_weight_entity = EditorEntity.create_editor_entity(postfx_shape_weight_name) + Report.critical_result(Tests.postfx_shape_weight_creation, postfx_shape_weight_entity.exists()) + + # 2. Add a PostFx Shape Weight Modifier component to PostFx Shape Weight Modifier entity. + postfx_shape_weight_component = postfx_shape_weight_entity.add_component(postfx_shape_weight_name) + Report.critical_result( + Tests.postfx_shape_weight_component, + postfx_shape_weight_entity.has_component(postfx_shape_weight_name)) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not postfx_shape_weight_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, postfx_shape_weight_entity.exists()) + + # 5. Verify PostFx Shape Weight Modifier component not enabled. + Report.result(Tests.postfx_shape_weight_disabled, not postfx_shape_weight_component.is_enabled()) + + # 6. Add PostFX Layer component since it is required by the PostFx Shape Weight Modifier component. + postfx_layer_name = "PostFX Layer" + postfx_shape_weight_entity.add_component(postfx_layer_name) + Report.result(Tests.postfx_layer_component, postfx_shape_weight_entity.has_component(postfx_layer_name)) + + # 7. Verify PostFx Shape Weight Modifier component not enabled because shape is also required. + Report.result(Tests.postfx_shape_weight_disabled, not postfx_shape_weight_component.is_enabled()) + + # 8. Add remove each shape to test if the PostFX Shape Weight Modifier is enabled by having a required shape + for shape in ['Axis Aligned Box Shape', 'Box Shape', 'Capsule Shape', 'Compound Shape', 'Cylinder Shape', + 'Disk Shape', 'Polygon Prism Shape', 'Quad Shape', 'Sphere Shape', 'Vegetation Reference Shape']: + postfx_shape_weight_entity.add_component(shape) + test_shape = ( + f"Entity has a {shape} component", + f"Entity did not have a {shape} component") + Report.result(test_shape, postfx_shape_weight_entity.has_component(shape)) + + #Check if required shape allows PostFX Shape Weight Modifier to be enabled + Report.result(Tests.postfx_shape_weight_enabled, postfx_shape_weight_component.is_enabled()) + + # 9. UNDO component addition and check that PostFX Shape Weight Modifier is not enabled + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.shape_undo, not postfx_shape_weight_entity.has_component(shape)) + Report.result(Tests.postfx_shape_weight_disabled, not postfx_shape_weight_component.is_enabled()) + + # 10. Add Tube Shape and Spline to fulfil the required shape component + postfx_shape_weight_entity.add_components(['Spline', 'Tube Shape']) + Report.result(Tests.shape_component, postfx_shape_weight_entity.has_component('Tube Shape')) + Report.result(Tests.postfx_shape_weight_enabled, postfx_shape_weight_component.is_enabled()) + + # 11. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 12. Test IsHidden. + postfx_shape_weight_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, postfx_shape_weight_entity.is_hidden() is True) + + # 13. Test IsVisible. + postfx_shape_weight_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, postfx_shape_weight_entity.is_visible() is True) + + # 14. Delete PostFx Shape Weight Modifier entity. + postfx_shape_weight_entity.delete() + Report.result(Tests.entity_deleted, not postfx_shape_weight_entity.exists()) + + # 15. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, postfx_shape_weight_entity.exists()) + + # 16. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not postfx_shape_weight_entity.exists()) + + # 17. Look for errors or asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_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(AtomEditorComponents_postfx_shape_weight_AddedToEntity) From 5cefd552a64cd51826208b79a189b6593dd74848 Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Tue, 12 Oct 2021 13:24:40 -0700 Subject: [PATCH 201/293] - Optimize SRG compilation to not update the whole SRG if not needed across all backends (#4499) - Each resource type is tracked and updated separately - Added caching ability for Raytracing srg to save ~2ms for a scene containing 100 x 50 vegetation patch Signed-off-by: moudgils --- .../RayTracing/RayTracingFeatureProcessor.cpp | 18 +++- .../RayTracing/RayTracingFeatureProcessor.h | 4 + .../Atom/RHI/ShaderResourceGroupData.h | 62 +++++++++++-- .../Source/RHI/ShaderResourceGroupData.cpp | 58 ++++++++++++ .../Source/RHI/ShaderResourceGroupPool.cpp | 22 ++++- .../Source/RHI/ShaderResourceGroupPool.cpp | 65 ++++++++----- .../Source/RHI/ShaderResourceGroupPool.cpp | 93 ++++++++++++------- .../RPI.Public/Shader/ShaderResourceGroup.cpp | 4 + 8 files changed, 253 insertions(+), 73 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index 042e934eb0..6e78d3170c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -507,8 +507,13 @@ namespace AZ } } - RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayIndex = srgLayout->FindShaderInputBufferUnboundedArrayIndex(AZ::Name("m_meshBuffers")); - m_rayTracingSceneSrg->SetBufferViewUnboundedArray(bufferUnboundedArrayIndex, meshBuffers); + //Check if buffer view data changed from previous frame. + if (m_meshBuffers.size() != meshBuffers.size() || m_meshBuffers != meshBuffers) + { + m_meshBuffers = meshBuffers; + RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayIndex = srgLayout->FindShaderInputBufferUnboundedArrayIndex(AZ::Name("m_meshBuffers")); + m_rayTracingSceneSrg->SetBufferViewUnboundedArray(bufferUnboundedArrayIndex, m_meshBuffers); + } } m_rayTracingSceneSrg->Compile(); @@ -554,8 +559,13 @@ namespace AZ } } - RHI::ShaderInputImageUnboundedArrayIndex textureUnboundedArrayIndex = srgLayout->FindShaderInputImageUnboundedArrayIndex(AZ::Name("m_materialTextures")); - m_rayTracingMaterialSrg->SetImageViewUnboundedArray(textureUnboundedArrayIndex, materialTextures); + // Check if image view data changed from previous frame. + if (m_materialTextures.size() != materialTextures.size() || m_materialTextures != materialTextures) + { + m_materialTextures = materialTextures; + RHI::ShaderInputImageUnboundedArrayIndex textureUnboundedArrayIndex = srgLayout->FindShaderInputImageUnboundedArrayIndex(AZ::Name("m_materialTextures")); + m_rayTracingMaterialSrg->SetImageViewUnboundedArray(textureUnboundedArrayIndex, materialTextures); + } } m_rayTracingMaterialSrg->Compile(); diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h index 52bb67f547..c0ebd6a4e7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h @@ -281,6 +281,10 @@ namespace AZ using BlasInstanceMap = AZStd::unordered_map; BlasInstanceMap m_blasInstanceMap; + + // Cache view pointers so we dont need to update them if none changed from frame to frame. + AZStd::vector m_meshBuffers; + AZStd::vector m_materialTextures; }; } } diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h index cbb0db53c8..ef4e734c01 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h @@ -183,6 +183,42 @@ namespace AZ //! Returns the shader resource layout for this group. const ShaderResourceGroupLayout* GetLayout() const; + enum class ResourceType : uint32_t + { + ConstantData, + BufferView, + ImageView, + BufferViewUnboundedArray, + ImageViewUnboundedArray, + Sampler, + Count + }; + + enum class ResourceTypeMask : uint32_t + { + None = 0, + ConstantDataMask = AZ_BIT(static_cast(ResourceType::ConstantData)), + BufferViewMask = AZ_BIT(static_cast(ResourceType::BufferView)), + ImageViewMask = AZ_BIT(static_cast(ResourceType::ImageView)), + BufferViewUnboundedArrayMask = AZ_BIT(static_cast(ResourceType::BufferViewUnboundedArray)), + ImageViewUnboundedArrayMask = AZ_BIT(static_cast(ResourceType::ImageViewUnboundedArray)), + SamplerMask = AZ_BIT(static_cast(ResourceType::Sampler)) + }; + + //! Returns true if a resource type specified by resourceTypeMask is enabled for compilation + bool IsResourceTypeEnabledForCompilation(uint32_t resourceTypeMask) const; + + //! Disables all resource types for compilation after m_updateMaskResetLatency number of compiles + //! This allows higher level code to ensure that if SRG is multi-buffered it can compile multiple + //! times in order to ensure all SRG buffers are updated. + void DisableCompilationForAllResourceTypes(); + + //! Returns true if any of the resource type has been enabled for compilation. + bool IsAnyResourceTypeUpdated() const; + + //! Enable compilation for a resourceType specified by resourceType/resourceTypeMask + void EnableResourceTypeCompilation(ResourceTypeMask resourceTypeMask, ResourceType resourceType); + private: static const ConstPtr s_nullImageView; static const ConstPtr s_nullBufferView; @@ -207,23 +243,43 @@ namespace AZ //! The backing data store of constants for the shader resource group. ConstantsData m_constantsData; + + //! Mask used to check whether to compile a specific resource type + uint32_t m_updateMask = 0; + + //! Track iteration for each resource type in order to keep compiling it for m_updateMaskResetLatency number of times + uint32_t m_resourceTypeIteration[static_cast(ResourceType::Count)] = { 0 }; + uint32_t m_updateMaskResetLatency = RHI::Limits::Device::FrameCountMax; }; template bool ShaderResourceGroupData::SetConstant(ShaderInputConstantIndex inputIndex, const T& value) { + EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData); return m_constantsData.SetConstant(inputIndex, value); } template bool ShaderResourceGroupData::SetConstant(ShaderInputConstantIndex inputIndex, const T& value, uint32_t arrayIndex) { + EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData); return m_constantsData.SetConstant(inputIndex, value, arrayIndex); } + + template + bool ShaderResourceGroupData::SetConstantMatrixRows(ShaderInputConstantIndex inputIndex, const T& value, uint32_t rowCount) + { + EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData); + return m_constantsData.SetConstantMatrixRows(inputIndex, value, rowCount); + } template bool ShaderResourceGroupData::SetConstantArray(ShaderInputConstantIndex inputIndex, AZStd::array_view values) { + if (!values.empty()) + { + EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData); + } return m_constantsData.SetConstantArray(inputIndex, values); } @@ -245,12 +301,6 @@ namespace AZ return m_constantsData.GetConstant(inputIndex, arrayIndex); } - template - bool ShaderResourceGroupData::SetConstantMatrixRows(ShaderInputConstantIndex inputIndex, const T& value, uint32_t rowCount) - { - return m_constantsData.SetConstantMatrixRows(inputIndex, value, rowCount); - } - template bool ShaderResourceGroupData::ValidateImageViewAccess(TShaderInput inputIndex, const ImageView* imageView, [[maybe_unused]] uint32_t arrayIndex) const { diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp index 18b292ac64..eed14b41b7 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp @@ -7,6 +7,7 @@ */ #include #include +#include namespace AZ { @@ -126,6 +127,12 @@ namespace AZ } isValidAll &= isValid; } + + if(!imageViews.empty()) + { + EnableResourceTypeCompilation(ResourceTypeMask::ImageViewMask, ResourceType::ImageView); + } + return isValidAll; } return false; @@ -146,6 +153,11 @@ namespace AZ } isValidAll &= isValid; } + + if (!imageViews.empty()) + { + EnableResourceTypeCompilation(ResourceTypeMask::ImageViewUnboundedArrayMask, ResourceType::ImageViewUnboundedArray); + } return isValidAll; } return false; @@ -172,6 +184,11 @@ namespace AZ } isValidAll &= isValid; } + + if (!bufferViews.empty()) + { + EnableResourceTypeCompilation(ResourceTypeMask::BufferViewMask, ResourceType::BufferView); + } return isValidAll; } return false; @@ -192,6 +209,11 @@ namespace AZ } isValidAll &= isValid; } + + if (!bufferViews.empty()) + { + EnableResourceTypeCompilation(ResourceTypeMask::BufferViewUnboundedArrayMask, ResourceType::BufferViewUnboundedArray); + } return isValidAll; } return false; @@ -211,6 +233,11 @@ namespace AZ { m_samplers[interval.m_min + arrayIndex + i] = samplers[i]; } + + if (!samplers.empty()) + { + EnableResourceTypeCompilation(ResourceTypeMask::SamplerMask, ResourceType::Sampler); + } return true; } return false; @@ -223,16 +250,19 @@ namespace AZ bool ShaderResourceGroupData::SetConstantRaw(ShaderInputConstantIndex inputIndex, const void* bytes, uint32_t byteOffset, uint32_t byteCount) { + EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData); return m_constantsData.SetConstantRaw(inputIndex, bytes, byteOffset, byteCount); } bool ShaderResourceGroupData::SetConstantData(const void* bytes, uint32_t byteCount) { + EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData); return m_constantsData.SetConstantData(bytes, byteCount); } bool ShaderResourceGroupData::SetConstantData(const void* bytes, uint32_t byteOffset, uint32_t byteCount) { + EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData); return m_constantsData.SetConstantData(bytes, byteOffset, byteCount); } @@ -348,5 +378,33 @@ namespace AZ return m_constantsData; } + bool ShaderResourceGroupData::IsResourceTypeEnabledForCompilation(uint32_t resourceTypeMask) const + { + return RHI::CheckBitsAny(m_updateMask, resourceTypeMask); + } + + bool ShaderResourceGroupData::IsAnyResourceTypeUpdated() const + { + return m_updateMask != 0; + } + + void ShaderResourceGroupData::EnableResourceTypeCompilation(ResourceTypeMask resourceTypeMask, ResourceType resourceType) + { + AZ_Assert(static_cast(resourceTypeMask) == AZ_BIT(static_cast(resourceType)), "resourceType and resourceTypeMask should point to the same ResourceType"); + m_updateMask = RHI::SetBits(m_updateMask, static_cast(resourceTypeMask)); + m_resourceTypeIteration[static_cast(resourceType)] = 0; + } + + void ShaderResourceGroupData::DisableCompilationForAllResourceTypes() + { + for (uint32_t i = 0; i < static_cast(ResourceType::Count); i++) + { + if (m_resourceTypeIteration[i] == m_updateMaskResetLatency) + { + m_updateMask = RHI::ResetBits(m_updateMask, AZ_BIT(i)); + } + m_resourceTypeIteration[i]++; + } + } } // namespace RHI } // namespace AZ diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp index bd648cf535..087a36dc2f 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp @@ -206,12 +206,21 @@ namespace AZ auto& device = static_cast(GetDevice()); group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax; - if (m_constantBufferSize) + if (!groupData.IsAnyResourceTypeUpdated()) + { + return RHI::ResultCode::Success; + } + + if (m_constantBufferSize && + groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask))) { memcpy(group.GetCompiledData().m_cpuConstantAddress, groupData.GetConstantData().data(), groupData.GetConstantData().size()); } - if (m_viewsDescriptorTableSize) + if (m_viewsDescriptorTableSize && + groupData.IsResourceTypeEnabledForCompilation( + static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask) | + static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask))) { //Lazy initialization for cbv/srv/uav Descriptor Tables if (!group.m_viewsDescriptorTable.IsValid()) @@ -236,12 +245,17 @@ namespace AZ UpdateViewsDescriptorTable(descriptorTable, groupData); } - if (m_unboundedArrayCount) + if (m_unboundedArrayCount && + groupData.IsResourceTypeEnabledForCompilation( + static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask) | + static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask))) { UpdateUnboundedArrayDescriptorTables(group, groupData); } - if (m_samplersDescriptorTableSize) + if (m_samplersDescriptorTableSize && + groupData.IsResourceTypeEnabledForCompilation( + static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask))) { const DescriptorTable descriptorTable( group.m_samplersDescriptorTable.GetOffset() + group.m_compiledDataIndex * m_samplersDescriptorTableSize, diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp index 6be5ec7259..0a9c001868 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp @@ -63,39 +63,58 @@ namespace AZ { ShaderResourceGroup& group = static_cast(groupBase); group.UpdateCompiledDataIndex(); - + + if (!groupData.IsAnyResourceTypeUpdated()) + { + return RHI::ResultCode::Success; + } + ArgumentBuffer& argBuffer = *group.m_compiledArgBuffers[group.m_compiledDataIndex]; argBuffer.ClearResourceTracking(); - argBuffer.UpdateConstantBufferViews(groupData.GetConstantData()); - + + auto constantData = groupData.GetConstantData(); + if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask))) + { + argBuffer.UpdateConstantBufferViews(groupData.GetConstantData()); + } + const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout(); uint32_t shaderInputIndex = 0; - for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages()) + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask))) { - const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex); - AZStd::array_view> imageViews = groupData.GetImageViewArray(imageInputIndex); - argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews); - ++shaderInputIndex; + for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages()) + { + const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex); + AZStd::array_view> imageViews = groupData.GetImageViewArray(imageInputIndex); + argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews); + ++shaderInputIndex; + } } - - shaderInputIndex = 0; - for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers()) + + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask))) { - const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex); - AZStd::array_view samplerStates= groupData.GetSamplerArray(samplerInputIndex); - argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates); - ++shaderInputIndex; + shaderInputIndex = 0; + for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers()) + { + const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex); + AZStd::array_view samplerStates = groupData.GetSamplerArray(samplerInputIndex); + argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates); + ++shaderInputIndex; + } } - - shaderInputIndex = 0; - for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers()) + + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask))) { - const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex); - AZStd::array_view> bufferViews = groupData.GetBufferViewArray(bufferInputIndex); - argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews); - ++shaderInputIndex; + shaderInputIndex = 0; + for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers()) + { + const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex); + AZStd::array_view> bufferViews = groupData.GetBufferViewArray(bufferInputIndex); + argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews); + ++shaderInputIndex; + } } - + return RHI::ResultCode::Success; } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp index c5ca07eb27..59dbaf4377 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp @@ -105,66 +105,87 @@ namespace AZ { auto& group = static_cast(groupBase); group.UpdateCompiledDataIndex(m_currentIteration); + + if (!groupData.IsAnyResourceTypeUpdated()) + { + return RHI::ResultCode::Success; + } + DescriptorSet& descriptorSet = *group.m_compiledData[group.GetCompileDataIndex()]; const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout(); - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex) + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask))) { - const RHI::ShaderInputBufferIndex index(groupIndex); - auto bufViews = groupData.GetBufferViewArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView); - descriptorSet.UpdateBufferViews(layoutIndex, bufViews); + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex) + { + const RHI::ShaderInputBufferIndex index(groupIndex); + auto bufViews = groupData.GetBufferViewArray(index); + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView); + descriptorSet.UpdateBufferViews(layoutIndex, bufViews); + } } - auto const& shaderImageList = layout->GetShaderInputListForImages(); - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImages().size()); ++groupIndex) + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask))) { - const RHI::ShaderInputImageIndex index(groupIndex); - auto imgViews = groupData.GetImageViewArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView); - descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type); + auto const& shaderImageList = layout->GetShaderInputListForImages(); + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImages().size()); ++groupIndex) + { + const RHI::ShaderInputImageIndex index(groupIndex); + auto imgViews = groupData.GetImageViewArray(index); + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView); + descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type); + } } - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex) + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask))) { - const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex); - auto bufViews = groupData.GetBufferViewUnboundedArray(index); - if (bufViews.empty()) + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex) { - // skip empty unbounded arrays - continue; + const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex); + auto bufViews = groupData.GetBufferViewUnboundedArray(index); + if (bufViews.empty()) + { + // skip empty unbounded arrays + continue; + } + + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray); + descriptorSet.UpdateBufferViews(layoutIndex, bufViews); } - - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray); - descriptorSet.UpdateBufferViews(layoutIndex, bufViews); } - auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays(); - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImageUnboundedArrays().size()); ++groupIndex) + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask))) { - const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex); - auto imgViews = groupData.GetImageViewUnboundedArray(index); - if (imgViews.empty()) + auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays(); + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImageUnboundedArrays().size()); ++groupIndex) { - // skip empty unbounded arrays - continue; + const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex); + auto imgViews = groupData.GetImageViewUnboundedArray(index); + if (imgViews.empty()) + { + // skip empty unbounded arrays + continue; + } + + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray); + descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type); } - - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray); - descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type); } - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex) + if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask))) { - const RHI::ShaderInputSamplerIndex index(groupIndex); - auto samplerArray = groupData.GetSamplerArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler); - descriptorSet.UpdateSamplers(layoutIndex, samplerArray); + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex) + { + const RHI::ShaderInputSamplerIndex index(groupIndex); + auto samplerArray = groupData.GetSamplerArray(index); + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler); + descriptorSet.UpdateSamplers(layoutIndex, samplerArray); + } } auto constantData = groupData.GetConstantData(); - if (!constantData.empty()) + if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask))) { descriptorSet.UpdateConstantData(constantData); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp index f95c6abfcd..df16b5cd08 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp @@ -114,6 +114,10 @@ namespace AZ void ShaderResourceGroup::Compile() { m_shaderResourceGroup->Compile(m_data); + + //Disable compilation for all resource types as a performance optimization + //No need to re-update SRG data on GPU timeline if nothing was updated. + m_data.DisableCompilationForAllResourceTypes(); } bool ShaderResourceGroup::IsQueuedForCompile() const From c38c9739da40e8613fefaf2b27f927cc1fad1adb Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Tue, 12 Oct 2021 13:32:47 -0700 Subject: [PATCH 202/293] Adding vertexNormal to the Surface structure and using it for shadows (#4617) * Adding vertex shadow and using it for all shadows * Fixing small issue with it not being initialized * Adis recommendations for hair Signed-off-by: mrieggeramzn --- .../Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl | 2 +- Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl | 1 + .../Materials/Types/StandardMultilayerPBR_ForwardPass.azsl | 1 + .../Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl | 2 +- .../ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli | 2 +- .../Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli | 2 +- .../Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli | 2 +- .../ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli | 1 + .../ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli | 1 + .../ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli | 1 + .../TestData/Materials/Types/AutoBrick_ForwardPass.azsl | 1 + .../TestData/Materials/Types/MinimalPBR_ForwardPass.azsl | 1 + Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli | 3 ++- Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli | 1 + Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli | 1 + .../Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl | 1 + 16 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl index 26a7e21a6a..11859de7d6 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl @@ -185,7 +185,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex]; float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms. float detailLayerNormalFactor = MaterialSrg::m_detail_normal_factor * detailLayerBlendFactor; - + surface.vertexNormal = normalize(IN.m_normal); surface.normal = GetDetailedNormalInputWS( isFrontFace, IN.m_normal, tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_normalFactor, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, uvMatrix, o_normal_useTexture, diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl index 97cbfb2622..05059aba6f 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl @@ -237,6 +237,7 @@ PbrLightingOutput SkinPS_Common(VSOutput IN) normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture4, normalMapSample, MaterialSrg::m_wrinkle_normal_texture4, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.a); } + surface.vertexNormal = normalize(IN.m_normal); if(o_detail_normal_useTexture) { float3 normalTS = GetTangentSpaceNormal(normalMapSample, uvMatrix, MaterialSrg::m_normalFactor); diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl index 5d2aec063b..6a97c0e785 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl @@ -445,6 +445,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer3.m_normalTS); } // [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams. + surface.vertexNormal = normalize(IN.m_normal); surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex])); // ------- Combine Albedo, roughness, specular, roughness --------- diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl index 1fa5fc683c..8df5e1ba56 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl @@ -146,7 +146,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex]; float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms. - + surface.vertexNormal = normalize(IN.m_normal); surface.normal = GetNormalInputWS(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, isFrontFace, IN.m_normal, tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], uvMatrix, o_normal_useTexture, MaterialSrg::m_normalFactor); diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli index 34c17e388c..1eee53a24f 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli @@ -24,7 +24,7 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData) litRatio = DirectionalLightShadow::GetVisibility( shadowIndex, lightingData.shadowCoords, - surface.normal, + surface.vertexNormal, debugInfo); if (o_transmission_mode == TransmissionMode::ThickObject) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli index ac9227f64a..63f671f021 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli @@ -86,7 +86,7 @@ void ApplyDiskLight(ViewSrg::DiskLight light, Surface surface, inout LightingDat light.m_position, surface.position, -dirToConeTip, - surface.normal); + surface.vertexNormal); // Use backShadowRatio to carry thickness from shadow map for thick mode backShadowRatio = 1.0 - litRatio; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli index b88b6574a4..e6eea9728f 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli @@ -83,7 +83,7 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD light.m_position, surface.position, lightDir, - surface.normal); + surface.vertexNormal); // Use backShadowRatio to carry thickness from shadow map for thick mode backShadowRatio = 1.0 - litRatio; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli index 1b0ac3d76d..eb8c33cdce 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli @@ -23,6 +23,7 @@ class Surface float3 position; //!< Position in world-space float3 normal; //!< Normal in world-space + float3 vertexNormal; //!< Vertex normal in world-space float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value float3 specularF0; //!< Fresnel f0 spectral value of the surface float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli index 40f30d4f03..f82d80adee 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli @@ -22,6 +22,7 @@ class Surface float3 position; //!< Position in world-space float3 normal; //!< Normal in world-space + float3 vertexNormal; //!< Vertex normal in world-space float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value float3 specularF0; //!< Fresnel f0 spectral value of the surface float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli index 30e90323a5..084943bf38 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli @@ -22,6 +22,7 @@ class Surface float3 position; //!< Position in world-space float3 normal; //!< Normal in world-space + float3 vertexNormal; //!< Vertex normal in world-space float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value float3 specularF0; //!< Fresnel f0 spectral value of the surface float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use diff --git a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl index 7be62c9343..2dbba46d8b 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl +++ b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl @@ -170,6 +170,7 @@ ForwardPassOutput AutoBrick_ForwardPassPS(VSOutput IN) // Position, Normal, Roughness surface.position = IN.m_worldPosition.xyz; surface.normal = normalize(normal); + surface.vertexNormal = surfaceNormal; surface.roughnessLinear = 1.0f; surface.CalculateRoughnessA(); diff --git a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl index 6f73b63ad7..2f6f038e4b 100644 --- a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl +++ b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl @@ -63,6 +63,7 @@ ForwardPassOutput MinimalPBR_MainPassPS(VSOutput IN) // Position, Normal, Roughness surface.position = IN.m_worldPosition.xyz; surface.normal = normalize(IN.m_normal); + surface.vertexNormal = normalize(IN.m_normal); surface.roughnessLinear = MinimalPBRSrg::m_roughness; surface.CalculateRoughnessA(); diff --git a/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli b/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli index 535d1380e7..4b0fa654e3 100644 --- a/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli +++ b/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli @@ -135,6 +135,7 @@ void SetNormalAndUpdateLightingParams( float3 projectedNormal = cross(biNormal, tangent); surface.normal = normalize(projectedNormal); // the normalization might be redundunt + surface.vertexNormal = surface.normal; // [To Do] - support proper vertex normals in the hair shader. // Next is important in order to set NdotV and other PBR settings - needs to be set once per light UpdateLightingParameters(lightingData, surface.position, surface.normal, surface.roughnessLinear); @@ -362,7 +363,7 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData) litRatio = DirectionalLightShadow::GetVisibility( shadowIndex, lightingData.shadowCoords, - surface.normal, + surface.vertexNormal, debugInfo); } diff --git a/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli b/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli index bf452e6ba8..dcdcf43243 100644 --- a/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli +++ b/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli @@ -197,6 +197,7 @@ float3 CalculateLighting( surface.position = vPositionWS; surface.tangent = vTangent; // Redundant - will be calculated per light surface.normal = float3(0, 0, 0); // Will fail lights that did not initialize properly. + surface.vertexNormal = float3(0,0,0); // [To Do] - vertex normals are not handled yet in the hair shader. surface.roughnessLinear = material.m_roughness; surface.cuticleTilt = material.m_cuticleTilt; surface.thickness = thickness; diff --git a/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli b/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli index 16496f0dcd..6ffd342734 100644 --- a/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli +++ b/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli @@ -18,6 +18,7 @@ class Surface // ------- BasePbrSurfaceData ------- float3 position; //!< Position in world-space float3 normal; //!< Normal in world-space + float3 vertexNormal; //!< Vertex normal in world-space float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value float3 specularF0; //!< Fresnel f0 spectral value of the surface float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl index df2a801969..fedd19a498 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl @@ -95,6 +95,7 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) detailNormal = ReorientTangentSpaceNormal(macroNormal, detailNormal); surface.normal = lerp(detailNormal, macroNormal, detailFactor); surface.normal = normalize(surface.normal); + surface.vertexNormal = normalize(IN.m_normal); // ------- Macro Color ------- float3 macroColor = GetBaseColorInput(TerrainMaterialSrg::m_macroColorMap, TerrainMaterialSrg::m_sampler, origUv, TerrainMaterialSrg::m_baseColor.rgb, o_baseColor_useTexture); From 6318247b3dc43d92f2825ed7afcc51e83aabda50 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 12 Oct 2021 13:34:51 -0700 Subject: [PATCH 203/293] LYN-7279 + LYN-7192 | Focus Mode - Container unit tests + Clear container entity open state on new level load (#4558) * Change SetContainerOpenState to SetContainerOpen. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce Clear function to avoid retaining all lingering open states when switching contexts/loading a new level. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor FocusMode fixture refactors to support ContainerEntity tests Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce tests for the ContainerEntity API Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add include to fix issue with EntityContextId not being defined. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor comment fixes. Moved environment clear functions to TearDown function of test fixture. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Use default editor context id in ContainerEntitySystemComponent Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Revert previous change as the EditorEntityContextId would not be initialized correctly on ContainerEntitySystemComponent Activate. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../ContainerEntityInterface.h | 11 +- .../ContainerEntitySystemComponent.cpp | 39 ++- .../ContainerEntitySystemComponent.h | 8 +- .../Prefab/PrefabFocusHandler.cpp | 7 +- .../ContainerEntitySelectionTests.cpp | 99 ++++++ .../Tests/FocusMode/ContainerEntityTests.cpp | 293 ++++++++++++++++++ .../FocusMode/EditorFocusModeFixture.cpp | 37 ++- .../Tests/FocusMode/EditorFocusModeFixture.h | 10 +- .../EditorFocusModeSelectionFixture.h | 43 +++ .../EditorFocusModeSelectionTests.cpp | 82 +---- .../Tests/FocusMode/EditorFocusModeTests.cpp | 75 ++--- .../Tests/aztoolsframeworktests_files.cmake | 3 + 12 files changed, 576 insertions(+), 131 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h index 45da3a9d8f..95940e6dd6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h @@ -11,6 +11,8 @@ #include #include +#include + namespace AzToolsFramework { //! Outcome object that returns an error message in case of failure to allow caller to handle internal errors. @@ -43,7 +45,7 @@ namespace AzToolsFramework //! @param entityId The entityId whose open state will be set. //! @param open True if the container should be opened, false if it should be closed. //! @return An error message if the operation was invalid, success otherwise. - virtual ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) = 0; + virtual ContainerEntityOperationResult SetContainerOpen(AZ::EntityId entityId, bool open) = 0; //! If the entity id provided is registered as a container, it returns whether it's open. //! @note the default value for non-containers is true, so this function can be called without @@ -56,6 +58,13 @@ namespace AzToolsFramework //! @return The highest closed entity container id if any, or entityId otherwise. virtual AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const = 0; + //! Clears all open state information for Container Entities for the EntityContextId provided. + //! Used when context is switched, for example in the case of a new root prefab being loaded + //! in place of an old one. + //! @note Clear is meant to be called when no container is registered for the context provided. + //! @return An error message if any container was registered for the context, success otherwise. + virtual ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) = 0; + }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp index 0ea2eeb5f6..c5649c56df 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp @@ -10,16 +10,19 @@ #include #include +#include namespace AzToolsFramework { void ContainerEntitySystemComponent::Activate() { AZ::Interface::Register(this); + EditorEntityContextNotificationBus::Handler::BusConnect(); } void ContainerEntitySystemComponent::Deactivate() { + EditorEntityContextNotificationBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); } @@ -63,7 +66,7 @@ namespace AzToolsFramework return m_containers.contains(entityId); } - ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpenState(AZ::EntityId entityId, bool open) + ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpen(AZ::EntityId entityId, bool open) { if (!IsContainer(entityId)) { @@ -87,7 +90,7 @@ namespace AzToolsFramework bool ContainerEntitySystemComponent::IsContainerOpen(AZ::EntityId entityId) const { - // If the entity is not a container, it should behave as open. + // Non-container entities behave the same as open containers. This saves the caller an additional check. if(!m_containers.contains(entityId)) { return true; @@ -117,4 +120,36 @@ namespace AzToolsFramework return highestSelectableEntityId; } + void ContainerEntitySystemComponent::OnEntityStreamLoadSuccess() + { + // We don't yet support multiple entity contexts, so just use the default. + auto editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + Clear(editorEntityContextId); + } + + ContainerEntityOperationResult ContainerEntitySystemComponent::Clear(AzFramework::EntityContextId entityContextId) + { + // We don't yet support multiple entity contexts, so only clear the default. + auto editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + if (entityContextId != editorEntityContextId) + { + return AZ::Failure(AZStd::string( + "Error in ContainerEntitySystemComponent::Clear - cannot clear non-default Entity Context!")); + } + + if (!m_containers.empty()) + { + return AZ::Failure(AZStd::string( + "Error in ContainerEntitySystemComponent::Clear - cannot clear container states if entities are still registered!")); + } + + m_openContainers.clear(); + + return AZ::Success(); + } + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h index 18c0fb70c6..44261979ef 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h @@ -12,6 +12,7 @@ #include #include +#include namespace AzToolsFramework { @@ -23,6 +24,7 @@ namespace AzToolsFramework class ContainerEntitySystemComponent final : public AZ::Component , private ContainerEntityInterface + , private EditorEntityContextNotificationBus::Handler { public: AZ_COMPONENT(ContainerEntitySystemComponent, "{74349759-B36B-44A6-B89F-F45D7111DD11}"); @@ -42,9 +44,13 @@ namespace AzToolsFramework ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) override; ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) override; bool IsContainer(AZ::EntityId entityId) const override; - ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) override; + ContainerEntityOperationResult SetContainerOpen(AZ::EntityId entityId, bool open) override; bool IsContainerOpen(AZ::EntityId entityId) const override; AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const override; + ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) override; + + // EditorEntityContextNotificationBus overrides ... + void OnEntityStreamLoadSuccess() override; private: AZStd::unordered_set m_containers; //!< All entities in this set are containers. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 9ffc18af5a..fcec1edd54 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -196,6 +196,9 @@ namespace AzToolsFramework::Prefab Initialize(); } + // Clear the old focus vector + m_instanceFocusVector.clear(); + // Focus on the root prefab (AZ::EntityId() will default to it) FocusOnOwningPrefab(AZ::EntityId()); } @@ -230,7 +233,7 @@ namespace AzToolsFramework::Prefab { if (instance.has_value()) { - m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), true); + m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), true); } } } @@ -241,7 +244,7 @@ namespace AzToolsFramework::Prefab { if (instance.has_value()) { - m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), false); + m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), false); } } } diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp new file mode 100644 index 0000000000..a47e41da42 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp @@ -0,0 +1,99 @@ +/* + * 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 + +namespace AzToolsFramework +{ + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithNoContainers) + { + // When no containers are in the way, the function will just return the entityId of the entity that was clicked. + + // Click on Car Entity + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); + + // Verify the correct entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithClosedContainer) + { + // If a closed container is an ancestor of the queried entity, the closed container is selected. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); // Containers are closed by default + + // Click on Car Entity + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); + + // Verify the correct entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[StreetEntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithOpenContainer) + { + // If a closed container is an ancestor of the queried entity, the closed container is selected. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); + + // Verify the correct entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleClosedContainers) + { + // If multiple closed containers are ancestors of the queried entity, the highest closed container is selected. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); + + // Verify the correct entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CityEntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); + } + + TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleContainers) + { + // If multiple containers are ancestors of the queried entity, the highest closed container is selected. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true); + + // Click on Car Entity + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); + + // Verify the correct entity is selected + auto selectedEntitiesAfter = GetSelectedEntities(); + EXPECT_EQ(selectedEntitiesAfter.size(), 1); + EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[StreetEntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp new file mode 100644 index 0000000000..031062f027 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp @@ -0,0 +1,293 @@ +/* + * 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 + +namespace AzToolsFramework +{ + TEST_F(EditorFocusModeFixture, ContainerEntityTests_Register) + { + // Registering an entity is successful. + auto outcome = m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]); + EXPECT_TRUE(outcome.IsSuccess()); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_RegisterTwice) + { + // Registering an entity twice fails. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]); + auto outcome = m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]); + EXPECT_FALSE(outcome.IsSuccess()); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_Unregister) + { + // Unregistering a container entity is successful. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]); + auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); + EXPECT_TRUE(outcome.IsSuccess()); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterRegularEntity) + { + // Unregistering an entity that was not previously registered fails. + auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); + EXPECT_FALSE(outcome.IsSuccess()); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterTwice) + { + // Unregistering a container entity twice fails. + auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]); + EXPECT_FALSE(outcome.IsSuccess()); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegularEntity) + { + // If a regular entity is passed, IsContainer returns false. + // Note that we use a different entity than the tests above to validate a completely new EntityId. + bool isContainer = m_containerEntityInterface->IsContainer(m_entityMap[SportsCarEntityName]); + EXPECT_FALSE(isContainer); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegisteredContainer) + { + // If a container entity is passed, IsContainer returns true. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + bool isContainer = m_containerEntityInterface->IsContainer(m_entityMap[SportsCarEntityName]); + EXPECT_TRUE(isContainer); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnUnRegisteredContainer) + { + // If an entity that was previously a container but was then unregistered is passed, IsContainer returns false. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + + bool isContainer = m_containerEntityInterface->IsContainer(m_entityMap[SportsCarEntityName]); + EXPECT_FALSE(isContainer); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenOnRegularEntity) + { + // Setting a regular entity to open should return a failure. + auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); + EXPECT_FALSE(outcome.IsSuccess()); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpen) + { + // Set a container entity to open, and verify the operation was successful. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); + EXPECT_TRUE(outcome.IsSuccess()); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenTwice) + { + // Set a container entity to open twice, and verify that does not cause a failure (as intended). + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); + auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); + EXPECT_TRUE(outcome.IsSuccess()); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerClosed) + { + // Set a container entity to closed, and verify the operation was successful. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); + EXPECT_TRUE(outcome.IsSuccess()); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnRegularEntity) + { + // Query open state on a regular entity, and verify it returns true. + // Open containers behave exactly as regular entities, so this is the expected return value. + bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]); + EXPECT_TRUE(isOpen); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnDefaultContainerEntity) + { + // Query open state on a newly registered container entity, and verify it returns false. + // Containers are registered closed by default. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); + bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]); + EXPECT_FALSE(isOpen); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnOpenContainerEntity) + { + // Query open state on a container entity that was opened, and verify it returns true. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true); + bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]); + EXPECT_TRUE(isOpen); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnClosedContainerEntity) + { + // Query open state on a container entity that was opened and then closed, and verify it returns false. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true); + m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], false); + bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]); + EXPECT_FALSE(isOpen); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_ContainerOpenStateIsPreserved) + { + // Register an entity as container, open it, then unregister it. + // When the entity is registered again, the open state should be preserved. + // This behavior is necessary for the system to work alongside Prefab propagation refreshes. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); + + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]); + bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]); + EXPECT_TRUE(isOpen); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceeds) + { + // The Clear function works if no container is registered. + auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId); + EXPECT_TRUE(outcome.IsSuccess()); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearFailsIfContainersAreStillRegistered) + { + // The Clear function fails if a container is registered. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId); + EXPECT_FALSE(outcome.IsSuccess()); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceedsIfContainersAreUnregistered) + { + // The Clear function fails if a container is registered. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId); + EXPECT_TRUE(outcome.IsSuccess()); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearDeletesPreservedOpenStates) + { + // Register an entity as container, open it, unregister it, then call clear. + // When the entity is registered again, the open state should not be preserved. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[Passenger1EntityName], true); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + + m_containerEntityInterface->Clear(m_editorEntityContextId); + + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[Passenger1EntityName]); + EXPECT_FALSE(isOpen); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithNoContainers) + { + // When no containers are in the way, the function will just return the entityId that was passed to it. + AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]); + EXPECT_EQ(selectedEntityId, m_entityMap[Passenger2EntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithClosedContainer) + { + // If a closed container is an ancestor of the queried entity, the closed container is selected. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); // Containers are closed by default + AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]); + EXPECT_EQ(selectedEntityId, m_entityMap[SportsCarEntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithOpenContainer) + { + // If an open container is an ancestor of the queried entity, it is ignored. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[SportsCarEntityName], true); + + AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]); + EXPECT_EQ(selectedEntityId, m_entityMap[Passenger2EntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleClosedContainers) + { + // If multiple closed containers are ancestors of the queried entity, the highest closed container is selected. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + + AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]); + EXPECT_EQ(selectedEntityId, m_entityMap[StreetEntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + } + + TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleContainers) + { + // If multiple containers are ancestors of the queried entity, the highest closed container is selected. + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true); + + AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]); + EXPECT_EQ(selectedEntityId, m_entityMap[SportsCarEntityName]); + + // Restore default state for other tests. + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]); + m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]); + } + +} diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp index c309261a27..49bf7cee15 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp @@ -14,6 +14,20 @@ namespace AzToolsFramework { + void ClearSelectedEntities() + { + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequestBus::Events::SetSelectedEntities, AzToolsFramework::EntityIdList()); + } + + AzToolsFramework::EntityIdList EditorFocusModeFixture::GetSelectedEntities() + { + AzToolsFramework::EntityIdList selectedEntities; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( + selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities); + return selectedEntities; + } + void EditorFocusModeFixture::SetUpEditorFixtureImpl() { // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is @@ -21,6 +35,9 @@ namespace AzToolsFramework // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); + m_containerEntityInterface = AZ::Interface::Get(); + ASSERT_TRUE(m_containerEntityInterface != nullptr); + m_focusModeInterface = AZ::Interface::Get(); ASSERT_TRUE(m_focusModeInterface != nullptr); @@ -31,6 +48,24 @@ namespace AzToolsFramework m_editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); GenerateTestHierarchy(); + + // Clear the focus, disabling focus mode + m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); + + // Clear selection + ClearSelectedEntities(); + } + + void EditorFocusModeFixture::TearDownEditorFixtureImpl() + { + // Clear Container Entity preserved open states + m_containerEntityInterface->Clear(m_editorEntityContextId); + + // Clear the focus, disabling focus mode + m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); + + // Clear selection + ClearSelectedEntities(); } void EditorFocusModeFixture::GenerateTestHierarchy() @@ -59,7 +94,7 @@ namespace AzToolsFramework entity->Activate(); // Move the CarEntity so it's out of the way. - AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, CarEntityPosition); + AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, WorldCarEntityPosition); // Setup the camera so the Car entity is in view. AzFramework::SetCameraTransform( diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h index f038408012..c48795a3a4 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h @@ -14,6 +14,7 @@ #include +#include #include #include @@ -24,16 +25,20 @@ namespace AzToolsFramework { protected: void SetUpEditorFixtureImpl() override; + void TearDownEditorFixtureImpl() override; void GenerateTestHierarchy(); AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId); AZStd::unordered_map m_entityMap; + + ContainerEntityInterface* m_containerEntityInterface = nullptr; FocusModeInterface* m_focusModeInterface = nullptr; public: - AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EntityIdList GetSelectedEntities(); + AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull(); AzFramework::CameraState m_cameraState; inline static const AZ::Vector3 CameraPosition = AZ::Vector3(10.0f, 15.0f, 10.0f); @@ -45,6 +50,7 @@ namespace AzToolsFramework inline static const char* Passenger1EntityName = "Passenger1"; inline static const char* Passenger2EntityName = "Passenger2"; - inline static AZ::Vector3 CarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f); + inline static AZ::Vector3 WorldCarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f); }; + } diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h new file mode 100644 index 0000000000..4c9369bc46 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace AzToolsFramework +{ + class EditorFocusModeSelectionFixture : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin + { + public: + void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition) + { + // Calculate the world position in screen space + const auto carScreenPosition = AzFramework::WorldToScreen(worldPosition, m_cameraState); + + // Click the entity in the viewport + m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp(); + } + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp index 968bb3f293..2f746c9d63 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp @@ -6,64 +6,14 @@ * */ -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - +#include namespace AzToolsFramework { - class EditorFocusModeSelectionFixture - : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin - { - public: - void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition) - { - // Calculate the world position in screen space - const auto carScreenPosition = AzFramework::WorldToScreen(worldPosition, m_cameraState); - - // Click the entity in the viewport - m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp(); - } - }; - - void ClearSelectedEntities() - { - AzToolsFramework::ToolsApplicationRequestBus::Broadcast( - &AzToolsFramework::ToolsApplicationRequestBus::Events::SetSelectedEntities, AzToolsFramework::EntityIdList()); - } - - AzToolsFramework::EntityIdList GetSelectedEntities() - { - AzToolsFramework::EntityIdList selectedEntities; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( - selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities); - return selectedEntities; - } - TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnLevel) { - // Clear the focus, disabling focus mode - m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull()); - // Clear selection - ClearSelectedEntities(); - // Click on Car Entity - ClickAtWorldPositionOnViewport(CarEntityPosition); + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); // Verify entity is selected auto selectedEntitiesAfter = GetSelectedEntities(); @@ -75,73 +25,53 @@ namespace AzToolsFramework { // Set the focus on the Street Entity (parent of the test entity) m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); - // Clear selection - ClearSelectedEntities(); // Click on Car Entity - ClickAtWorldPositionOnViewport(CarEntityPosition); + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); // Verify entity is selected auto selectedEntitiesAfter = GetSelectedEntities(); EXPECT_EQ(selectedEntitiesAfter.size(), 1); EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); - - // Clear the focus, disabling focus mode - m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull()); } TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnItself) { // Set the focus on the Car Entity (test entity) m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - // Clear selection - ClearSelectedEntities(); // Click on Car Entity - ClickAtWorldPositionOnViewport(CarEntityPosition); + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); // Verify entity is selected auto selectedEntitiesAfter = GetSelectedEntities(); EXPECT_EQ(selectedEntitiesAfter.size(), 1); EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]); - - // Clear the focus, disabling focus mode - m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull()); } TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnSibling) { // Set the focus on the SportsCar Entity (sibling of the test entity) m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]); - // Clear selection - ClearSelectedEntities(); // Click on Car Entity - ClickAtWorldPositionOnViewport(CarEntityPosition); + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); // Verify entity is selected auto selectedEntitiesAfter = GetSelectedEntities(); EXPECT_EQ(selectedEntitiesAfter.size(), 0); - - // Clear the focus, disabling focus mode - m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull()); } TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnDescendant) { // Set the focus on the Passenger1 Entity (child of the entity) m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]); - // Clear selection - ClearSelectedEntities(); // Click on Car Entity - ClickAtWorldPositionOnViewport(CarEntityPosition); + ClickAtWorldPositionOnViewport(WorldCarEntityPosition); // Verify entity is selected auto selectedEntitiesAfter = GetSelectedEntities(); EXPECT_EQ(selectedEntitiesAfter.size(), 0); - - // Clear the focus, disabling focus mode - m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull()); } } diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp index 22bc7a494c..eec3902f99 100644 --- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp @@ -33,55 +33,40 @@ namespace AzToolsFramework TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_AncestorsDescendants) { // When the focus is set to an entity, all its descendants are in the focus subtree while the ancestors aren't. - { - m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); - - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); - } + m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); - // Restore default expected focus. - m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); } TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Siblings) { // If the root entity has siblings, they are also outside of the focus subtree. - { - m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false); - } + m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]); - // Restore default expected focus. - m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false); } TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Leaf) { // If the root is a leaf, then the focus subtree will consists of just that entity. - { - m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]); - - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); - } - - // Restore default expected focus. - m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); + m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]); + + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); } TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Clear) @@ -90,15 +75,13 @@ namespace AzToolsFramework m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]); // When the focus is cleared, the whole level is in the focus subtree; so we expect all entities to return true. - { - m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); + m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); - EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); - } + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true); + EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true); } } diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index 87d522c4a6..ef6774f620 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -37,8 +37,11 @@ set(FILES EntityTestbed.h FileFunc.cpp FingerprintingTests.cpp + FocusMode/ContainerEntitySelectionTests.cpp + FocusMode/ContainerEntityTests.cpp FocusMode/EditorFocusModeFixture.cpp FocusMode/EditorFocusModeFixture.h + FocusMode/EditorFocusModeSelectionFixture.h FocusMode/EditorFocusModeSelectionTests.cpp FocusMode/EditorFocusModeTests.cpp GenericComponentWrapperTest.cpp From f7e08d1c4bcfc983fc8d5f035b03a81673bf00a6 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 12 Oct 2021 15:36:19 -0500 Subject: [PATCH 204/293] =?UTF-8?q?PropertyAssetCtrl=20and=20ThumbnailProp?= =?UTF-8?q?ertyCtrl=20support=20custom=20thumbnail=20images=20=E2=80=A2=20?= =?UTF-8?q?PropertyAssetCtrl=20was=20previously=20extended=20with=20Thumbn?= =?UTF-8?q?ailPropertyCtrl=20to=20optionally=20display=20a=20thumbnail=20a?= =?UTF-8?q?nd=20floating=20zoomed=20in=20preview=20of=20the=20selected=20a?= =?UTF-8?q?sset.=20=E2=80=A2=20This=20change=20allows=20overriding=20the?= =?UTF-8?q?=20image=20that=20comes=20from=20the=20thumbnail=20system=20wit?= =?UTF-8?q?h=20a=20custom=20image=20provided=20as=20an=20attribute.=20The?= =?UTF-8?q?=20custom=20image=20can=20be=20specified=20as=20either=20a=20fi?= =?UTF-8?q?le=20path=20or=20a=20buffer=20containing=20a=20serialized=20QPi?= =?UTF-8?q?xmap.=20=E2=80=A2=20This=20will=20be=20used=20by=20the=20materi?= =?UTF-8?q?al=20system=20in=20the=20editor=20to=20provide=20a=20dynamicall?= =?UTF-8?q?y=20rendered=20image=20of=20the=20material=20with=20property=20?= =?UTF-8?q?overrides=20applied=20so=20that=20the=20image=20will=20update?= =?UTF-8?q?=20as=20the=20user=20customizes=20their=20material.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../UI/PropertyEditor/PropertyAssetCtrl.cpp | 57 +++++++- .../UI/PropertyEditor/PropertyAssetCtrl.hxx | 5 + .../PropertyEditor/ThumbnailPropertyCtrl.cpp | 127 +++++++++++------- .../UI/PropertyEditor/ThumbnailPropertyCtrl.h | 25 +++- 4 files changed, 159 insertions(+), 55 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index ba84e662c1..7f3b9e61fd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -28,6 +28,9 @@ AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option") #include #include #include +#include +#include +#include AZ_POP_DISABLE_WARNING #include @@ -1230,6 +1233,16 @@ namespace AzToolsFramework return m_showThumbnailDropDownButton; } + void PropertyAssetCtrl::SetCustomThumbnailEnabled(bool enabled) + { + m_thumbnail->SetCustomThumbnailEnabled(enabled); + } + + void PropertyAssetCtrl::SetCustomThumbnailPixmap(const QPixmap& pixmap) + { + m_thumbnail->SetCustomThumbnailPixmap(pixmap); + } + void PropertyAssetCtrl::SetThumbnailCallback(EditCallbackType* editNotifyCallback) { m_thumbnailCallback = editNotifyCallback; @@ -1356,15 +1369,27 @@ namespace AzToolsFramework GUI->SetClearNotifyCallback(nullptr); } } - else if (attrib == AZ_CRC("BrowseIcon", 0x507d7a4f)) + else if (attrib == AZ_CRC_CE("BrowseIcon")) { AZStd::string iconPath; - attrValue->Read(iconPath); - - if (!iconPath.empty()) + if (attrValue->Read(iconPath) && !iconPath.empty()) { GUI->SetBrowseButtonIcon(QIcon(iconPath.c_str())); } + else + { + // A QPixmap object can't be assigned directly via an attribute. + // This allows dynamic icon data to be supplied as a buffer containing a serialized QPixmap. + AZStd::vector pixmapBuffer; + if (attrValue->Read>(pixmapBuffer) && !pixmapBuffer.empty()) + { + QByteArray pixmapBytes(pixmapBuffer.data(), aznumeric_cast(pixmapBuffer.size())); + QDataStream stream(&pixmapBytes, QIODevice::ReadOnly); + QPixmap pixmap; + stream >> pixmap; + GUI->SetBrowseButtonIcon(pixmap); + } + } } else if (attrib == AZ_CRC_CE("BrowseButtonEnabled")) { @@ -1390,6 +1415,30 @@ namespace AzToolsFramework GUI->SetShowThumbnail(showThumbnail); } } + else if (attrib == AZ_CRC_CE("ThumbnailIcon")) + { + AZStd::string iconPath; + if (attrValue->Read(iconPath) && !iconPath.empty()) + { + GUI->SetCustomThumbnailEnabled(true); + GUI->SetCustomThumbnailPixmap(QPixmap::fromImage(QImage(iconPath.c_str()))); + } + else + { + // A QPixmap object can't be assigned directly via an attribute. + // This allows dynamic icon data to be supplied as a buffer containing a serialized QPixmap. + AZStd::vector pixmapBuffer; + if (attrValue->Read>(pixmapBuffer) && !pixmapBuffer.empty()) + { + QByteArray pixmapBytes(pixmapBuffer.data(), aznumeric_cast(pixmapBuffer.size())); + QDataStream stream(&pixmapBytes, QIODevice::ReadOnly); + QPixmap pixmap; + stream >> pixmap; + GUI->SetCustomThumbnailEnabled(true); + GUI->SetCustomThumbnailPixmap(pixmap); + } + } + } else if (attrib == AZ_CRC_CE("ThumbnailCallback")) { PropertyAssetCtrl::EditCallbackType* func = azdynamic_cast(attrValue->GetAttribute()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index cc4aff5649..0b98278bc5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -217,12 +217,17 @@ namespace AzToolsFramework void SetHideProductFilesInAssetPicker(bool hide); bool GetHideProductFilesInAssetPicker() const; + // Enable and configure a thumbnail widget that displays an asset preview and dropdown arrow for a dropdown menu void SetShowThumbnail(bool enable); bool GetShowThumbnail() const; void SetShowThumbnailDropDownButton(bool enable); bool GetShowThumbnailDropDownButton() const; void SetThumbnailCallback(EditCallbackType* editNotifyCallback); + // If enabled, replaces the thumbnail widget content with a custom pixmap + void SetCustomThumbnailEnabled(bool enabled); + void SetCustomThumbnailPixmap(const QPixmap& pixmap); + void SetSelectedAssetID(const AZ::Data::AssetId& newID); void SetCurrentAssetType(const AZ::Data::AssetType& newType); void SetSelectedAssetID(const AZ::Data::AssetId& newID, const AZ::Data::AssetType& newType); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp index c458f7c47e..d8ddee6b76 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp @@ -7,75 +7,117 @@ */ #include -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: 'QRawFont::d': class 'QExplicitlySharedDataPointer' needs to have dll-interface to be used by clients of class 'QRawFont' - // 4800: 'QTextEngine *const ': forcing value to bool 'true' or 'false' (performance warning) -#include -#include + +// 4251: 'QRawFont::d': class 'QExplicitlySharedDataPointer' needs to have dll-interface to be used by clients of class +// 'QRawFont' 4800: 'QTextEngine *const ': forcing value to bool 'true' or 'false' (performance warning) +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") +#include #include +#include +#include #include -#include #include -#include +#include AZ_POP_DISABLE_WARNING #include "ThumbnailPropertyCtrl.h" namespace AzToolsFramework { - ThumbnailPropertyCtrl::ThumbnailPropertyCtrl(QWidget* parent) : QWidget(parent) { - QHBoxLayout* pLayout = new QHBoxLayout(); - pLayout->setContentsMargins(0, 0, 0, 0); - pLayout->setSpacing(0); - m_thumbnail = new Thumbnailer::ThumbnailWidget(this); m_thumbnail->setFixedSize(QSize(24, 24)); + m_thumbnailEnlarged = new Thumbnailer::ThumbnailWidget(this); + m_thumbnailEnlarged->setFixedSize(QSize(180, 180)); + m_thumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + + m_customThumbnail = new QLabel(this); + m_customThumbnail->setFixedSize(QSize(24, 24)); + m_customThumbnail->setScaledContents(true); + + m_customThumbnailEnlarged = new QLabel(this); + m_customThumbnailEnlarged->setFixedSize(QSize(180, 180)); + m_customThumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + m_customThumbnailEnlarged->setScaledContents(true); + m_dropDownArrow = new AspectRatioAwarePixmapWidget(this); m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0.png")); m_dropDownArrow->setFixedSize(QSize(8, 24)); - ShowDropDownArrow(false); m_emptyThumbnail = new QLabel(this); m_emptyThumbnail->setPixmap(QPixmap(":/stylesheet/img/line.png")); m_emptyThumbnail->setFixedSize(QSize(24, 24)); - pLayout->addWidget(m_emptyThumbnail); + QHBoxLayout* pLayout = new QHBoxLayout(); + pLayout->setContentsMargins(0, 0, 0, 0); + pLayout->setSpacing(0); pLayout->addWidget(m_thumbnail); + pLayout->addWidget(m_customThumbnail); + pLayout->addWidget(m_emptyThumbnail); pLayout->addSpacing(4); pLayout->addWidget(m_dropDownArrow); pLayout->addSpacing(4); - setLayout(pLayout); + + ShowDropDownArrow(false); + UpdateVisibility(); } void ThumbnailPropertyCtrl::SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName) { - m_key = key; - m_emptyThumbnail->setVisible(false); - m_thumbnail->SetThumbnailKey(key, contextName); + if (m_customThumbnailEnabled) + { + ClearThumbnail(); + } + else + { + m_key = key; + m_thumbnail->SetThumbnailKey(m_key, contextName); + m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName); + } + UpdateVisibility(); } void ThumbnailPropertyCtrl::ClearThumbnail() { - m_emptyThumbnail->setVisible(true); + m_key.clear(); m_thumbnail->ClearThumbnail(); + m_thumbnailEnlarged->ClearThumbnail(); + UpdateVisibility(); } void ThumbnailPropertyCtrl::ShowDropDownArrow(bool visible) { - if (visible) - { - setFixedSize(QSize(40, 24)); - } - else - { - setFixedSize(QSize(24, 24)); - } + setFixedSize(QSize(visible ? 40 : 24, 24)); m_dropDownArrow->setVisible(visible); } + void ThumbnailPropertyCtrl::SetCustomThumbnailEnabled(bool enabled) + { + m_customThumbnailEnabled = enabled; + UpdateVisibility(); + } + + void ThumbnailPropertyCtrl::SetCustomThumbnailPixmap(const QPixmap& pixmap) + { + m_customThumbnail->setPixmap(pixmap); + m_customThumbnailEnlarged->setPixmap(pixmap); + UpdateVisibility(); + } + + void ThumbnailPropertyCtrl::UpdateVisibility() + { + m_thumbnail->setVisible(m_key && !m_customThumbnailEnabled); + m_thumbnailEnlarged->setVisible(false); + + m_customThumbnail->setVisible(m_customThumbnailEnabled); + m_customThumbnailEnlarged->setVisible(false); + + m_emptyThumbnail->setVisible(!m_key && !m_customThumbnailEnabled); + } + bool ThumbnailPropertyCtrl::event(QEvent* e) { if (isEnabled()) @@ -83,7 +125,7 @@ namespace AzToolsFramework if (e->type() == QEvent::MouseButtonPress) { emit clicked(); - return true; //ignore + return true; // ignore } } @@ -94,37 +136,32 @@ namespace AzToolsFramework { QPainter p(this); QRect targetRect(QPoint(), QSize(40, 24)); - p.fillRect(targetRect, QColor(17, 17, 17)); // #111111 + p.fillRect(targetRect, QColor("#111111")); QWidget::paintEvent(e); } void ThumbnailPropertyCtrl::enterEvent(QEvent* e) { m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0_highlighted.png")); - if (!m_thumbnailEnlarged && m_key) - { - QPoint position = mapToGlobal(pos() - QPoint(185, 0)); - QSize size(180, 180); - m_thumbnailEnlarged.reset(new Thumbnailer::ThumbnailWidget()); - m_thumbnailEnlarged->setFixedSize(size); - m_thumbnailEnlarged->move(position); - m_thumbnailEnlarged->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); - m_thumbnailEnlarged->SetThumbnailKey(m_key); - m_thumbnailEnlarged->raise(); - m_thumbnailEnlarged->show(); - } + const QPoint offset(-m_thumbnailEnlarged->width() - 5, -m_thumbnailEnlarged->height() / 2 + m_thumbnail->height() / 2); + + m_thumbnailEnlarged->move(mapToGlobal(pos()) + offset); + m_thumbnailEnlarged->raise(); + m_thumbnailEnlarged->setVisible(m_key && !m_customThumbnailEnabled); + + m_customThumbnailEnlarged->move(mapToGlobal(pos()) + offset); + m_customThumbnailEnlarged->raise(); + m_customThumbnailEnlarged->setVisible(m_customThumbnailEnabled); QWidget::enterEvent(e); } void ThumbnailPropertyCtrl::leaveEvent(QEvent* e) { m_dropDownArrow->setPixmap(QPixmap(":/stylesheet/img/triangle0.png")); - if (m_thumbnailEnlarged) - { - m_thumbnailEnlarged.reset(); - } + m_thumbnailEnlarged->setVisible(false); + m_customThumbnailEnlarged->setVisible(false); QWidget::leaveEvent(e); } -} +} // namespace AzToolsFramework #include "UI/PropertyEditor/moc_ThumbnailPropertyCtrl.cpp" diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h index 93f703c4c5..b1ce78b601 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h @@ -1,5 +1,3 @@ -#pragma once - /* * 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. @@ -8,6 +6,8 @@ * */ +#pragma once + #if !defined(Q_MOC_RUN) #include #include @@ -35,25 +35,38 @@ namespace AzToolsFramework //! Call this to set what thumbnail widget will display void SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName = "Default"); + //! Remove current thumbnail void ClearThumbnail(); + //! Display a clickble dropdown arrow next to the thumbnail void ShowDropDownArrow(bool visible); - bool event(QEvent* e) override; + //! Override the thumbnail widget with a custom image + void SetCustomThumbnailEnabled(bool enabled); + + //! Assign a custom image to dispsy in place of thumbnail + void SetCustomThumbnailPixmap(const QPixmap& pixmap); Q_SIGNALS: void clicked(); - protected: + private: + void UpdateVisibility(); + + bool event(QEvent* e) override; void paintEvent(QPaintEvent* e) override; void enterEvent(QEvent* e) override; void leaveEvent(QEvent* e) override; - private: Thumbnailer::SharedThumbnailKey m_key; Thumbnailer::ThumbnailWidget* m_thumbnail = nullptr; - QScopedPointer m_thumbnailEnlarged; + Thumbnailer::ThumbnailWidget* m_thumbnailEnlarged = nullptr; + + QLabel* m_customThumbnail = nullptr; + QLabel* m_customThumbnailEnlarged = nullptr; + bool m_customThumbnailEnabled = false; + QLabel* m_emptyThumbnail = nullptr; AspectRatioAwarePixmapWidget* m_dropDownArrow = nullptr; }; From c35b0e5eface4f68c85190a2fd1d3c639e9ed8ed Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Tue, 12 Oct 2021 13:46:02 -0700 Subject: [PATCH 205/293] fix a test string to indicate PostFX Layer Signed-off-by: Scott Murray --- ...dra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py index be139f83b6..fe6362c9b7 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py @@ -22,8 +22,8 @@ class Tests: "PostFx Shape Weight Modifier component disabled", "PostFx Shape Weight Modifier component was not disabled.") postfx_layer_component = ( - "Entity has an Actor component", - "Entity did not have an Actor component") + "Entity has a PostFX Layer component", + "Entity did not have an PostFX Layer component") shape_component = ( "Entity has a Tube Shape component", "Entity did not have a Tube Shape component") From 4f539b0eb7c123bb4e35bbc144db14479ad52924 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 12 Oct 2021 16:17:19 -0500 Subject: [PATCH 206/293] fixed comments Signed-off-by: Guthrie Adams --- .../UI/PropertyEditor/ThumbnailPropertyCtrl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h index b1ce78b601..ffd8234190 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h @@ -39,13 +39,13 @@ namespace AzToolsFramework //! Remove current thumbnail void ClearThumbnail(); - //! Display a clickble dropdown arrow next to the thumbnail + //! Display a clickable dropdown arrow next to the thumbnail void ShowDropDownArrow(bool visible); //! Override the thumbnail widget with a custom image void SetCustomThumbnailEnabled(bool enabled); - //! Assign a custom image to dispsy in place of thumbnail + //! Assign a custom image to display in place of thumbnail void SetCustomThumbnailPixmap(const QPixmap& pixmap); Q_SIGNALS: From 343a13a13469e2c3db46c642d1a93d0b9ed10672 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 12 Oct 2021 16:44:54 -0500 Subject: [PATCH 207/293] updating comments Signed-off-by: Guthrie Adams --- .../UI/PropertyEditor/ThumbnailPropertyCtrl.h | 4 ++-- .../PreviewRenderer/PreviewContent.h | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h index b1ce78b601..ffd8234190 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.h @@ -39,13 +39,13 @@ namespace AzToolsFramework //! Remove current thumbnail void ClearThumbnail(); - //! Display a clickble dropdown arrow next to the thumbnail + //! Display a clickable dropdown arrow next to the thumbnail void ShowDropDownArrow(bool visible); //! Override the thumbnail widget with a custom image void SetCustomThumbnailEnabled(bool enabled); - //! Assign a custom image to dispsy in place of thumbnail + //! Assign a custom image to display in place of thumbnail void SetCustomThumbnailPixmap(const QPixmap& pixmap); Q_SIGNALS: diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h index bdc7afe0b1..a96cec65b1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h @@ -12,7 +12,7 @@ namespace AtomToolsFramework { - //! Provides custom rendering of previefw images + //! Interface for describing scene content that will be rendered using the PreviewRenderer class PreviewContent { public: @@ -20,10 +20,20 @@ namespace AtomToolsFramework PreviewContent() = default; virtual ~PreviewContent() = default; + + //! Initiate loading of scene content, models, materials, etc virtual void Load() = 0; + + //! Return true if content is loaded and ready to render virtual bool IsReady() const = 0; + + //! Return true if content failed to load virtual bool IsError() const = 0; + + //! Report any issues encountered while loading virtual void ReportErrors() = 0; + + //! Prepare or pose content before rendering virtual void Update() = 0; }; } // namespace AtomToolsFramework From 80db67e90a1aa44c954d3814eaefd12c345db2b3 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Wed, 13 Oct 2021 00:06:15 +0200 Subject: [PATCH 208/293] Remove many unused variables and unused setting files (#4607) * Remove many unused variables and unused setting files Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove a few more dead config vars Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * fix android test_ConfigureSettings_DefaultValues_SetsValues Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- Assets/Editor/MapScreenshotSettings.xml | 13 -- Assets/Editor/UserTools.xml | 2 - Assets/Engine/Config/AutoTestChain.cfg | 11 -- Assets/Engine/Config/AutoTestTimeDemo.cfg | 10 -- Assets/Engine/Config/AutotestPlaythrough.cfg | 9 +- .../Config/CVarGroups/sys_spec_Full.cfg | 97 ----------- .../CVarGroups/sys_spec_GameEffects.cfg | 8 - .../CVarGroups/sys_spec_ObjectDetail.cfg | 160 ------------------ .../Config/CVarGroups/sys_spec_Particles.cfg | 94 ---------- .../Config/CVarGroups/sys_spec_Physics.cfg | 100 ----------- .../CVarGroups/sys_spec_PostProcessing.cfg | 114 ------------- .../Config/CVarGroups/sys_spec_Quality.cfg | 98 ----------- .../Config/CVarGroups/sys_spec_Shading.cfg | 120 ------------- .../Config/CVarGroups/sys_spec_Shadows.cfg | 116 ------------- .../Config/CVarGroups/sys_spec_Sound.cfg | 17 -- .../Config/CVarGroups/sys_spec_Texture.cfg | 94 ---------- .../CVarGroups/sys_spec_TextureResolution.cfg | 52 ------ .../CVarGroups/sys_spec_VolumetricEffects.cfg | 26 --- .../Config/CVarGroups/sys_spec_Water.cfg | 81 --------- Assets/Engine/Config/aidebug.cfg | 3 - Assets/Engine/Config/artprof.cfg | 14 +- Assets/Engine/Config/artprof_user.cfg | 3 - Assets/Engine/Config/benchmark_cpu.cfg | 10 -- Assets/Engine/Config/benchmark_gpu.cfg | 12 +- Assets/Engine/Config/mgpu.cfg | 6 - Assets/Engine/Config/multiplayer.cfg | 77 --------- Assets/Engine/Config/multiplayer_console.cfg | 29 ---- Assets/Engine/Config/recording.cfg | 60 ------- Assets/Engine/Config/singleplayer.cfg | 15 -- Assets/Engine/Config/sketch_off.cfg | 24 --- Assets/Engine/Config/sketch_on.cfg | 24 --- .../Engine/Config/spec/android_MaliT760.cfg | 68 -------- Assets/Engine/Config/spec/android_high.cfg | 58 ------- .../Config/spec/android_high_nogmem.cfg | 53 ------ Assets/Engine/Config/spec/android_low.cfg | 69 -------- Assets/Engine/Config/spec/android_medium.cfg | 74 -------- .../Engine/Config/spec/android_veryhigh.cfg | 55 ------ Assets/Engine/Config/spec/ios_high.cfg | 90 ---------- Assets/Engine/Config/spec/ios_low.cfg | 93 ---------- Assets/Engine/Config/spec/ios_medium.cfg | 91 ---------- Assets/Engine/Config/spec/ios_veryhigh.cfg | 92 ---------- Assets/Engine/Config/spec/osx_metal_high.cfg | 38 ----- Assets/Engine/Config/spec/osx_metal_low.cfg | 37 ---- .../Engine/Config/spec/osx_metal_medium.cfg | 37 ---- .../Engine/Config/spec/osx_metal_veryhigh.cfg | 37 ---- Assets/Engine/Config/spec/pc_high.cfg | 1 - Assets/Engine/Config/spec/pc_low.cfg | 1 - Assets/Engine/Config/spec/pc_medium.cfg | 1 - Assets/Engine/Config/spec/pc_veryhigh.cfg | 1 - Assets/Engine/Config/statoscope.cfg | 9 - Assets/Engine/Config/vr.cfg | 26 --- Assets/Engine/SeedAssetList.seed | 152 ----------------- .../Atom/atom_utils/atom_component_helper.py | 1 - ...GPUTest_AtomFeatureIntegrationBenchmark.py | 1 - .../tests/hydra_GPUTest_BasicLevelSetup.py | 1 - .../editor_python_test_tools/utils.py | 1 - .../screenshot_utils.py | 4 - Code/Legacy/CrySystem/SystemInit.cpp | 21 --- .../Code/Source/Processing/ImageFlags.h | 2 +- .../Source/LYCommonMenu/ImGuiLYCommonMenu.cpp | 14 -- .../launchers/platforms/android/launcher.py | 7 - .../launchers/platforms/linux/launcher.py | 1 - .../launchers/platforms/win/launcher.py | 2 - .../tests/unit/test_launcher_android.py | 2 +- cmake/Tools/layout_tool.py | 39 ++--- editor.cfg | 21 --- system_android_android.cfg | 30 +--- system_ios_ios.cfg | 29 ---- system_linux_pc.cfg | 22 --- system_mac_mac.cfg | 21 --- system_windows_pc.cfg | 20 --- 71 files changed, 21 insertions(+), 2800 deletions(-) delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_GameEffects.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_ObjectDetail.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Particles.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Physics.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_PostProcessing.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Quality.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Shading.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Shadows.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Sound.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Texture.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_TextureResolution.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_VolumetricEffects.cfg delete mode 100644 Assets/Engine/Config/CVarGroups/sys_spec_Water.cfg delete mode 100644 Assets/Engine/Config/sketch_off.cfg delete mode 100644 Assets/Engine/Config/sketch_on.cfg delete mode 100644 Assets/Engine/Config/spec/osx_metal_high.cfg delete mode 100644 Assets/Engine/Config/spec/osx_metal_low.cfg delete mode 100644 Assets/Engine/Config/spec/osx_metal_medium.cfg delete mode 100644 Assets/Engine/Config/spec/osx_metal_veryhigh.cfg diff --git a/Assets/Editor/MapScreenshotSettings.xml b/Assets/Editor/MapScreenshotSettings.xml index 01f90db4b3..88a8a49aef 100644 --- a/Assets/Editor/MapScreenshotSettings.xml +++ b/Assets/Editor/MapScreenshotSettings.xml @@ -1,18 +1,5 @@ - - - - - - - - - - - - - diff --git a/Assets/Editor/UserTools.xml b/Assets/Editor/UserTools.xml index 8f971cbd5c..4cc197afbe 100644 --- a/Assets/Editor/UserTools.xml +++ b/Assets/Editor/UserTools.xml @@ -7,8 +7,6 @@ - - diff --git a/Assets/Engine/Config/AutoTestChain.cfg b/Assets/Engine/Config/AutoTestChain.cfg index 8c6fae9020..4164acb271 100644 --- a/Assets/Engine/Config/AutoTestChain.cfg +++ b/Assets/Engine/Config/AutoTestChain.cfg @@ -1,16 +1,5 @@ ConsoleHide -g_godMode=1 sys_warnings=0 con_showonload=1 -i_forcefeedback=0 -g_infiniteammo=1 -e_ObjectLayersActivation=0 -e_ObjectLayersActivationPhysics=0 -g_flashrenderingduringloading=0 sys_maxfps=0 r_vsync=0 -p_max_substeps=1 -demo_file=autotest -demo_num_runs=0 -demo_quit=1 -demo_ai=1 diff --git a/Assets/Engine/Config/AutoTestTimeDemo.cfg b/Assets/Engine/Config/AutoTestTimeDemo.cfg index 687158eda9..664ea94939 100644 --- a/Assets/Engine/Config/AutoTestTimeDemo.cfg +++ b/Assets/Engine/Config/AutoTestTimeDemo.cfg @@ -1,15 +1,5 @@ ConsoleHide -g_godMode=1 -g_infiniteammo=1 r_displayinfo=1 s_profiling=1 sys_maxfps=0 -e_ObjectLayersActivation=0 -e_ObjectLayersActivationPhysics=0 - -demo_file=autotest -demo_num_runs=2 -demo_quit=1 -demo_savestats=1 -demo_profile=-1 demo diff --git a/Assets/Engine/Config/AutotestPlaythrough.cfg b/Assets/Engine/Config/AutotestPlaythrough.cfg index f453097972..664ea94939 100644 --- a/Assets/Engine/Config/AutotestPlaythrough.cfg +++ b/Assets/Engine/Config/AutotestPlaythrough.cfg @@ -1,12 +1,5 @@ ConsoleHide -g_godMode=1 -g_infiniteammo=1 r_displayinfo=1 s_profiling=1 sys_maxfps=0 -demo_file=playthru -demo_num_runs=2 -demo_quit=1 -demo_savestats=1 -demo_profile=-1 -demo \ No newline at end of file +demo diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg index 626dce3ee4..04fb56f3ca 100644 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg +++ b/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg @@ -11,113 +11,16 @@ ; default of this CVarGroup = 7 -sys_spec_ObjectDetail=7 -sys_spec_Shading=7 -sys_spec_VolumetricEffects=7 -sys_spec_Shadows=7 -sys_spec_Texture=7 -sys_spec_Physics=7 -sys_spec_PostProcessing=7 -sys_spec_Particles=7 -sys_spec_Sound=7 -sys_spec_Water=7 -sys_spec_GameEffects=7 -sys_spec_light=7 - [1] -sys_spec_ObjectDetail=1 -sys_spec_Shading=1 -sys_spec_VolumetricEffects=1 -sys_spec_Shadows=1 -sys_spec_Texture=1 -sys_spec_Physics=1 -sys_spec_PostProcessing=1 -sys_spec_Particles=1 -sys_spec_Sound=1 -sys_spec_Water=1 -sys_spec_GameEffects=1 -sys_spec_light=1 [2] -sys_spec_ObjectDetail=2 -sys_spec_Shading=2 -sys_spec_VolumetricEffects=2 -sys_spec_Shadows=2 -sys_spec_Texture=2 -sys_spec_Physics=2 -sys_spec_PostProcessing=2 -sys_spec_Particles=2 -sys_spec_Sound=2 -sys_spec_Water=2 -sys_spec_GameEffects=2 -sys_spec_light=2 [3] -sys_spec_ObjectDetail=3 -sys_spec_Shading=3 -sys_spec_VolumetricEffects=3 -sys_spec_Shadows=3 -sys_spec_Texture=3 -sys_spec_Physics=3 -sys_spec_PostProcessing=3 -sys_spec_Particles=3 -sys_spec_Sound=3 -sys_spec_Water=3 -sys_spec_GameEffects=3 -sys_spec_light=3 [4] -sys_spec_ObjectDetail=4 -sys_spec_Shading=4 -sys_spec_VolumetricEffects=4 -sys_spec_Shadows=4 -sys_spec_Texture=4 -sys_spec_Physics=4 -sys_spec_PostProcessing=4 -sys_spec_Particles=4 -sys_spec_Sound=4 -sys_spec_Water=4 -sys_spec_GameEffects=4 -sys_spec_light=4 [5] -sys_spec_ObjectDetail=5 -sys_spec_Shading=5 -sys_spec_VolumetricEffects=5 -sys_spec_Shadows=5 -sys_spec_Texture=5 -sys_spec_Physics=5 -sys_spec_PostProcessing=5 -sys_spec_Particles=5 -sys_spec_Sound=5 -sys_spec_Water=5 -sys_spec_GameEffects=5 -sys_spec_light=5 [6] -sys_spec_ObjectDetail=6 -sys_spec_Shading=6 -sys_spec_VolumetricEffects=6 -sys_spec_Shadows=6 -sys_spec_Texture=6 -sys_spec_Physics=6 -sys_spec_PostProcessing=6 -sys_spec_Particles=6 -sys_spec_Sound=6 -sys_spec_Water=6 -sys_spec_GameEffects=6 -sys_spec_light=6 [8] -sys_spec_ObjectDetail=8 -sys_spec_Shading=8 -sys_spec_VolumetricEffects=8 -sys_spec_Shadows=8 -sys_spec_Texture=8 -sys_spec_Physics=8 -sys_spec_PostProcessing=8 -sys_spec_Particles=8 -sys_spec_Sound=8 -sys_spec_Water=8 -sys_spec_GameEffects=8 -sys_spec_light=8 diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_GameEffects.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_GameEffects.cfg deleted file mode 100644 index 34e058d47d..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_GameEffects.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -mfx_Timeout = 0.01 - - - diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_ObjectDetail.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_ObjectDetail.cfg deleted file mode 100644 index a2996f7ded..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_ObjectDetail.cfg +++ /dev/null @@ -1,160 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -ca_AttachmentCullingRation=360 -es_DebrisLifetimeScale=1 -e_CoverageBufferReproj=6 -e_DecalsAllowGameDecals=1 -e_DecalsLifeTimeScale=2 -e_DecalsOverlapping=1 -e_Dissolve=2 -e_LightQuality=3 -e_LodMin=0 -e_LodRatio=20 -e_MaxViewDistSpecLerp=1 -e_MergedMeshesInstanceDist=1.0 -e_MergedMeshesPool=8192 -e_ObjQuality=3 -e_OcclusionCullingViewDistRatio=1 -e_ProcVegetation=1 -e_StatObjBufferRenderTasks=1 -e_StreamCgf=0 -e_TerrainLodRatio=1 -e_TerrainOcclusionCullingMaxDist=200 -e_Tessellation=0 -e_VegetationMinSize=0 -e_ViewDistMin=10 -e_ViewDistRatio=100 -e_ViewDistRatioCustom=100 -e_ViewDistRatioDetail=100 -e_ViewDistRatioLights=50 -e_ViewDistRatioVegetation=100 -r_DrawNearZRange=0.12 -r_FlaresTessellationRatio=1 -r_SilhouettePOM=0 -r_usezpass=2 - -[1] -ca_AttachmentCullingRation=145 -es_DebrisLifetimeScale=0.6 -e_DecalsLifeTimeScale=1 -e_Dissolve=0 -e_LightQuality=1 -e_LodRatio=10 -e_MaxViewDistSpecLerp=0.5 -e_ObjQuality=1 -e_TerrainOcclusionCullingMaxDist=130 -e_VegetationMinSize=0.5 -e_ViewDistRatioCustom=60 -e_ViewDistRatioDetail=25 -e_ViewDistRatioLights=25 -e_ViewDistRatioVegetation=21 -r_FlaresTessellationRatio=0.25 -r_usezpass=1 -e_ProcVegetation=0 -e_ViewDistRatio=50 - -[2] -ca_AttachmentCullingRation=145 -es_DebrisLifetimeScale=0.6 -e_DecalsLifeTimeScale=1 -e_Dissolve=0 -e_LightQuality=2 -e_LodRatio=10 -e_MaxViewDistSpecLerp=0.5 -e_ObjQuality=2 -e_TerrainOcclusionCullingMaxDist=130 -e_VegetationMinSize=0.5 -e_ViewDistRatioCustom=60 -e_ViewDistRatioDetail=25 -e_ViewDistRatioLights=25 -e_ViewDistRatioVegetation=50 -r_FlaresTessellationRatio=0.25 -r_usezpass=1 -e_ProcVegetation=1 -e_ViewDistRatio=50 - -[3] -ca_AttachmentCullingRation=145 -es_DebrisLifetimeScale=0.6 -e_DecalsLifeTimeScale=1 -e_Dissolve=0 -e_LightQuality=3 -e_LodRatio=10 -e_MaxViewDistSpecLerp=0.5 -e_ObjQuality=3 -e_TerrainOcclusionCullingMaxDist=130 -e_VegetationMinSize=0.5 -e_ViewDistRatioCustom=60 -e_ViewDistRatioDetail=25 -e_ViewDistRatioLights=25 -e_ViewDistRatioVegetation=50 -r_FlaresTessellationRatio=0.25 -r_usezpass=1 -e_ProcVegetation=1 -e_ViewDistRatio=75 - -[4] -ca_AttachmentCullingRation=145 -es_DebrisLifetimeScale=0.6 -e_DecalsLifeTimeScale=1 -e_Dissolve=0 -e_LightQuality=4 -e_LodRatio=10 -e_MaxViewDistSpecLerp=0.5 -e_ObjQuality=4 -e_TerrainOcclusionCullingMaxDist=130 -e_VegetationMinSize=0.5 -e_ViewDistRatioCustom=60 -e_ViewDistRatioDetail=25 -e_ViewDistRatioLights=25 -e_ViewDistRatioVegetation=50 -r_FlaresTessellationRatio=0.25 -r_usezpass=1 -e_ProcVegetation=1 -e_ViewDistRatio=75 - -[5] -ca_AttachmentCullingRation=145 -es_DebrisLifetimeScale=0.6 -e_DecalsLifeTimeScale=1 -e_LightQuality=1 -e_LodRatio=10 -e_MaxViewDistSpecLerp=0.5 -e_ObjQuality=1 -e_TerrainOcclusionCullingMaxDist=130 -e_VegetationMinSize=0.5 -e_ViewDistRatio=50 -e_ViewDistRatioCustom=60 -e_ViewDistRatioDetail=25 -e_ViewDistRatioLights=25 -e_ViewDistRatioVegetation=50 -r_FlaresTessellationRatio=0.25 - -[6] -ca_AttachmentCullingRation=300 -es_DebrisLifetimeScale=0.8 -e_LightQuality=2 -e_LodRatio=15 -e_ObjQuality=2 -e_ViewDistRatio=75 -e_ViewDistRatioDetail=35 -e_ViewDistRatioVegetation=75 - -[8] -ca_AttachmentCullingRation=400 -e_LightQuality=4 -e_LodRatio=40 -e_MergedMeshesInstanceDist=2.0 -e_MergedMeshesPool=16384 -e_ObjQuality=4 -e_TerrainLodRatio=0.5 -e_Tessellation=1 -e_ViewDistRatio=125 -e_ViewDistRatioCustom=125 -e_ViewDistRatioDetail=125 -e_ViewDistRatioLights=75 -e_ViewDistRatioVegetation=125 -r_DrawNearZRange = 0.08 -r_SilhouettePOM=1 \ No newline at end of file diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Particles.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Particles.cfg deleted file mode 100644 index 0a02170b97..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Particles.cfg +++ /dev/null @@ -1,94 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -e_ParticlesGI=1 -e_ParticlesPreload=0 -e_ParticlesMaxScreenFill=128 -e_ParticlesMinDrawPixels=1 -e_ParticlesMotionBlur=0 -e_ParticlesObjectCollisions=2 -e_ParticlesQuality=3 -e_ParticlesSortQuality=0 -e_ParticlesPoolSize=16384 -r_ParticlesHalfRes=0 -r_ParticlesTessellation=1 -r_ParticlesInstanceVertices=1 -r_ParticlesGpuMaxEmitCount=10000 - -[1] -e_ParticlesGI=0 -e_ParticlesPreload=1 -e_ParticlesMaxScreenFill=16 -e_ParticlesMinDrawPixels=2 -e_ParticlesObjectCollisions=1 -e_ParticlesQuality=2 -e_ParticlesPoolSize=4096 -r_ParticlesHalfRes=1 -r_ParticlesTessellation=0 -r_ParticlesInstanceVertices=0 -r_ParticlesGpuMaxEmitCount=10 - - -[2] -e_ParticlesGI=0 -e_ParticlesPreload=1 -e_ParticlesMaxScreenFill=16 -e_ParticlesMinDrawPixels=2 -e_ParticlesObjectCollisions=1 -e_ParticlesQuality=2 -e_ParticlesPoolSize=4096 -r_ParticlesHalfRes=1 -r_ParticlesTessellation=0 -r_ParticlesInstanceVertices=0 -r_ParticlesGpuMaxEmitCount=100 - - -[3] -e_ParticlesGI=0 -e_ParticlesPreload=1 -e_ParticlesMaxScreenFill=16 -e_ParticlesMinDrawPixels=2 -e_ParticlesObjectCollisions=1 -e_ParticlesQuality=2 -e_ParticlesPoolSize=4096 -r_ParticlesHalfRes=1 -r_ParticlesTessellation=0 -r_ParticlesInstanceVertices=0 -r_ParticlesGpuMaxEmitCount=500 - - -[4] -e_ParticlesGI=0 -e_ParticlesPreload=1 -e_ParticlesMaxScreenFill=16 -e_ParticlesMinDrawPixels=2 -e_ParticlesObjectCollisions=1 -e_ParticlesQuality=2 -e_ParticlesPoolSize=4096 -r_ParticlesHalfRes=1 -r_ParticlesTessellation=0 -r_ParticlesInstanceVertices=0 -r_ParticlesGpuMaxEmitCount=1000 - - -[5] -e_ParticlesMaxScreenFill=32 -e_ParticlesMinDrawPixels=1.5 -e_ParticlesObjectCollisions=1 -e_ParticlesQuality=1 -r_ParticlesHalfRes=1 -r_ParticlesTessellation=0 -r_ParticlesGpuMaxEmitCount=3000 - -[6] -e_ParticlesMaxScreenFill=64 -e_ParticlesObjectCollisions=1 -e_ParticlesQuality=2 -r_ParticlesGpuMaxEmitCount=5000 - -[8] -e_ParticlesMaxScreenFill=160 -e_ParticlesMotionBlur=1 -e_ParticlesQuality=4 -r_ParticlesGpuMaxEmitCount=1048576 \ No newline at end of file diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Physics.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Physics.cfg deleted file mode 100644 index 15d9fc61e3..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Physics.cfg +++ /dev/null @@ -1,100 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -es_MaxPhysDist=100 -es_MaxPhysDistInvisible=25 -e_CullVegActivation=50 -e_FoliageWindActivationDist=25 -e_PhysMinCellSize=4 -e_PhysOceanCell=0.5 -e_PhysProxyTriLimit=10000 -g_breakage_mem_limit=0 -g_breakage_particles_limit=160 -g_no_secondary_breaking=0 -g_tree_cut_reuse_dist=0 -p_gravity_z=-13 -p_max_entity_cells=300000 -p_max_MC_iters=6000 -p_max_object_splashes=3 -p_max_substeps=5 -p_max_substeps_large_group=5 -p_num_bodies_large_group=100 -p_splash_dist0=7 -p_splash_dist1=30 -p_splash_force0=10 -p_splash_force1=100 -p_splash_vel0=4.5 -p_splash_vel1=10 -v_vehicle_quality=4 - -[1] -es_MaxPhysDistInvisible=15 -e_CullVegActivation=30 -e_FoliageWindActivationDist=10 -e_PhysMinCellSize=16 -e_PhysOceanCell=1 -g_breakage_mem_limit=2000 -g_breakage_particles_limit=40 -g_no_secondary_breaking=1 -g_tree_cut_reuse_dist=1 -p_max_entity_cells=75000 -p_max_MC_iters=2000 -p_max_substeps=2 - -[2] -es_MaxPhysDistInvisible=15 -e_CullVegActivation=30 -e_FoliageWindActivationDist=10 -e_PhysMinCellSize=16 -e_PhysOceanCell=1 -g_breakage_mem_limit=2000 -g_breakage_particles_limit=40 -g_no_secondary_breaking=1 -g_tree_cut_reuse_dist=1 -p_max_entity_cells=75000 -p_max_MC_iters=2000 -p_max_substeps=2 - -[3] -es_MaxPhysDistInvisible=15 -e_CullVegActivation=30 -e_FoliageWindActivationDist=10 -e_PhysMinCellSize=16 -e_PhysOceanCell=1 -g_breakage_mem_limit=2000 -g_breakage_particles_limit=40 -g_no_secondary_breaking=1 -g_tree_cut_reuse_dist=1 -p_max_entity_cells=75000 -p_max_MC_iters=2000 -p_max_substeps=2 - -[4] -es_MaxPhysDistInvisible=15 -e_CullVegActivation=30 -e_FoliageWindActivationDist=10 -e_PhysMinCellSize=16 -e_PhysOceanCell=1 -g_breakage_mem_limit=2000 -g_breakage_particles_limit=40 -g_no_secondary_breaking=1 -g_tree_cut_reuse_dist=1 -p_max_entity_cells=75000 -p_max_MC_iters=2000 -p_max_substeps=2 - -[5] -es_MaxPhysDist=50 -es_MaxPhysDistInvisible=15 -e_CullVegActivation=30 -e_FoliageWindActivationDist=10 -e_PhysOceanCell=1 -g_breakage_particles_limit=80 -g_tree_cut_reuse_dist=0.35 -p_max_MC_iters=4000 -p_max_substeps=2 - -[6] - -[8] diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_PostProcessing.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_PostProcessing.cfg deleted file mode 100644 index 9d2cd3754d..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_PostProcessing.cfg +++ /dev/null @@ -1,114 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -r_PostProcessEffects=1 -q_ShaderHDR=2 -q_ShaderPostProcess=2 -r_ChromaticAberration=0 -r_ColorGradingChartsCache=0 -r_DepthOfField=2 -r_Flares=1 -r_HDRBloomQuality=2 -r_MotionBlur=2 -r_MotionBlurMaxViewDist=100000 -r_MotionBlurQuality=1 -r_MotionBlurShutterSpeed=125 -r_Rain=2 -r_RainMaxViewDist_Deferred=150 -r_Sharpening=0 -r_Snow=2 -r_SunShafts=2 -r_TranspDepthFixup=1 -r_ToneMapTechnique=0 -r_ToneMapExposureType=0 -r_HDRBloom=1 -r_ColorGrading=1 -r_ColorSpace=0 - -[1] -q_ShaderHDR=1 -q_ShaderPostProcess=1 -r_ColorGrading=0 -r_DepthOfField=0 -r_Flares=0 -r_HDRBloom=0 -r_HDRBloomQuality=0 -r_MotionBlur=0 -r_MotionBlurMaxViewDist=16 -r_MotionBlurQuality=0 -r_Rain=1 -r_RainMaxViewDist_Deferred=40 -r_Snow=1 -r_SunShafts=0 -r_TranspDepthFixup=0 -r_ToneMapTechnique=3 -r_ToneMapExposureType=1 -r_ColorSpace=2 - - -[2] -q_ShaderHDR=1 -q_ShaderPostProcess=1 -r_ColorGradingChartsCache=4 -r_DepthOfField=1 -r_Flares=0 -r_HDRBloomQuality=0 -r_MotionBlur=0 -r_MotionBlurMaxViewDist=16 -r_MotionBlurQuality=0 -r_Rain=1 -r_RainMaxViewDist_Deferred=40 -r_Snow=1 -r_SunShafts=1 -r_TranspDepthFixup=0 - - -[3] -q_ShaderHDR=1 -q_ShaderPostProcess=2 -r_ColorGradingChartsCache=4 -r_DepthOfField=1 -r_HDRBloomQuality=1 -r_MotionBlur=0 -r_MotionBlurMaxViewDist=16 -r_MotionBlurQuality=0 -r_Rain=1 -r_RainMaxViewDist_Deferred=40 -r_Snow=1 -r_SunShafts=1 -r_TranspDepthFixup=0 - -[4] -q_ShaderHDR=1 -q_ShaderPostProcess=2 -r_ColorGradingChartsCache=4 -r_DepthOfField=1 -r_HDRBloomQuality=1 -r_MotionBlur=0 -r_MotionBlurMaxViewDist=16 -r_MotionBlurQuality=0 -r_Rain=1 -r_RainMaxViewDist_Deferred=40 -r_Snow=1 -r_SunShafts=1 -r_TranspDepthFixup=0 - -[5] -q_ShaderHDR=1 -q_ShaderPostProcess=1 -r_ColorGradingChartsCache=4 -r_MotionBlurMaxViewDist=16 -r_MotionBlurQuality=0 -r_RainMaxViewDist_Deferred=40 -r_TranspDepthFixup=0 - -[6] -q_ShaderHDR=1 -q_ShaderPostProcess=1 -r_RainMaxViewDist_Deferred=100 - -[8] -q_ShaderHDR=3 -q_ShaderPostProcess=3 -r_MotionBlurQuality=2 diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Quality.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Quality.cfg deleted file mode 100644 index cf1bdf5184..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Quality.cfg +++ /dev/null @@ -1,98 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -q_ShaderGeneral=2 -q_ShaderMetal=2 -q_ShaderGlass=2 -q_ShaderVegetation=2 -q_ShaderIce=2 -q_ShaderTerrain=2 -q_ShaderShadow=2 -q_ShaderFX=2 -q_ShaderSky=2 -q_Renderer=2 - -[1] -q_ShaderGeneral=1 -q_ShaderMetal=1 -q_ShaderGlass=1 -q_ShaderVegetation=1 -q_ShaderIce=1 -q_ShaderTerrain=1 -q_ShaderShadow=1 -q_ShaderFX=1 -q_ShaderSky=1 -q_Renderer=1 - -[2] -q_ShaderGeneral=1 -q_ShaderMetal=1 -q_ShaderGlass=1 -q_ShaderVegetation=1 -q_ShaderIce=1 -q_ShaderTerrain=1 -q_ShaderShadow=1 -q_ShaderFX=1 -q_ShaderSky=1 -q_Renderer=1 - -[3] -q_ShaderGeneral=1 -q_ShaderMetal=1 -q_ShaderGlass=1 -q_ShaderVegetation=1 -q_ShaderIce=1 -q_ShaderTerrain=1 -q_ShaderShadow=1 -q_ShaderFX=1 -q_ShaderSky=1 -q_Renderer=2 - -[4] -q_ShaderGeneral=1 -q_ShaderMetal=1 -q_ShaderGlass=1 -q_ShaderVegetation=1 -q_ShaderIce=1 -q_ShaderTerrain=1 -q_ShaderShadow=1 -q_ShaderFX=1 -q_ShaderSky=1 -q_Renderer=2 - -[5] -q_ShaderGeneral=1 -q_ShaderMetal=1 -q_ShaderGlass=1 -q_ShaderVegetation=1 -q_ShaderIce=1 -q_ShaderTerrain=1 -q_ShaderShadow=1 -q_ShaderFX=1 -q_ShaderSky=1 -q_Renderer=1 - -[6] -q_ShaderGeneral=1 -q_ShaderMetal=1 -q_ShaderGlass=1 -q_ShaderVegetation=1 -q_ShaderIce=1 -q_ShaderTerrain=1 -q_ShaderShadow=1 -q_ShaderFX=1 -q_ShaderSky=1 -q_Renderer=1 - -[8] -q_ShaderGeneral=3 -q_ShaderMetal=3 -q_ShaderGlass=3 -q_ShaderVegetation=3 -q_ShaderIce=3 -q_ShaderTerrain=3 -q_ShaderShadow=3 -q_ShaderFX=3 -q_ShaderSky=3 -q_Renderer=3 diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Shading.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Shading.cfg deleted file mode 100644 index eb379a8583..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Shading.cfg +++ /dev/null @@ -1,120 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -e_CacheNearestCubePicking=1 -e_DynamicLightsMaxEntityLights=16 -e_GI=1 -e_LightVolumes=1 -e_SkyUpdateRate=1 -e_TerrainAo=0 -e_VegetationUseTerrainColor=1 -r_DeferredShadingDepthBoundsTest=1 -r_DeferredShadingTiled=2 -r_DeferredShadingTiledHairQuality=1 -r_deferredShadingFilterGBuffer=0 -r_DeferredShadingSSS=1 -r_AntialiasingMode=3 -r_DetailDistance=8 -r_EnvTexUpdateInterval=0.05 -r_Refraction=1 -r_RefractionPartialResolves=2 -r_ssdo=1 -r_ssdoHalfRes=2 -r_ssdoColorBleeding=1 -r_SSReflections=1 -r_SSReflHalfRes=1 -r_VisAreaClipLightsPerPixel=1 -sys_spec_Quality=7 - -[1] -e_DynamicLightsMaxEntityLights=2 -e_GI=0 -e_SkyUpdateRate=0.5 -e_VegetationUseTerrainColor=0 -r_DeferredShadingTiled=0 -r_DeferredShadingTiledHairQuality=0 -r_DeferredShadingSSS=0 -r_AntialiasingMode=0 -r_DetailDistance=4 -r_EnvTexUpdateInterval=0.075 -r_Refraction=0 -r_RefractionPartialResolves=0 -r_ssdo=0 -r_ssdoHalfRes=1 -r_ssdoColorBleeding=0 -r_SSReflections=0 -sys_spec_Quality=1 - -[2] -e_DynamicLightsMaxEntityLights=2 -e_GI=0 -e_SkyUpdateRate=0.5 -e_VegetationUseTerrainColor=0 -r_DeferredShadingTiled=0 -r_DeferredShadingTiledHairQuality=0 -r_DeferredShadingSSS=0 -r_AntialiasingMode=0 -r_DetailDistance=4 -r_EnvTexUpdateInterval=0.075 -r_RefractionPartialResolves=0 -r_ssdo=0 -r_ssdoHalfRes=1 -r_ssdoColorBleeding=0 -r_SSReflections=0 -sys_spec_Quality=2 - -[3] -e_DynamicLightsMaxEntityLights=2 -e_GI=0 -e_SkyUpdateRate=0.5 -e_VegetationUseTerrainColor=0 -r_DeferredShadingTiled=0 -r_DeferredShadingTiledHairQuality=0 -r_DeferredShadingSSS=0 -r_AntialiasingMode=0 -r_DetailDistance=4 -r_EnvTexUpdateInterval=0.075 -r_RefractionPartialResolves=0 -r_ssdo=0 -r_ssdoColorBleeding=0 -r_SSReflections=0 -sys_spec_Quality=3 - -[4] -e_DynamicLightsMaxEntityLights=2 -e_GI=0 -e_SkyUpdateRate=0.5 -e_VegetationUseTerrainColor=0 -r_DeferredShadingTiled=0 -r_DeferredShadingTiledHairQuality=0 -r_DeferredShadingSSS=0 -r_AntialiasingMode=0 -r_DetailDistance=4 -r_EnvTexUpdateInterval=0.075 -r_RefractionPartialResolves=0 -r_ssdo=1 -r_ssdoHalfRes=1 -r_ssdoColorBleeding=0 -r_SSReflections=0 -sys_spec_Quality=4 - -[5] -e_DynamicLightsMaxEntityLights=7 -e_GI=0 -e_SkyUpdateRate=0.5 -r_DetailDistance=4 -r_EnvTexUpdateInterval=0.075 -r_SSReflections=0 -r_DeferredShadingTiledHairQuality=0 -r_DeferredShadingSSS=0 -sys_spec_Quality=5 - -[6] -e_DynamicLightsMaxEntityLights=11 -sys_spec_Quality=6 - -[8] -r_DeferredShadingTiledHairQuality=2 -r_SSReflHalfRes=0 -sys_spec_Quality=8 diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Shadows.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Shadows.cfg deleted file mode 100644 index d43c28c09d..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Shadows.cfg +++ /dev/null @@ -1,116 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -e_GsmLodsNum=5 -e_GsmRange=3 -e_ParticlesShadows=1 -e_Shadows=1 -e_ShadowsBlendCascades=1 -e_ShadowsClouds=1 -e_ShadowsCastViewDistRatio=1 -e_ShadowsLodBiasFixed=0 -e_ShadowsMaxTexRes=1024 -e_ShadowsOnAlphaBlend=0 -e_ShadowsPoolSize=4096 -e_ShadowsResScale=4 -e_ShadowsTessellateCascades=1 -e_ShadowsTessellateDLights=0 -e_ShadowsUpdateViewDistRatio=256 -r_DrawNearShadows=1 -r_FogShadows=2 -r_FogShadowsWater=0 -r_ShadowJittering=2.5 -r_ShadowPoolMaxFrames=30 -r_ShadowPoolMaxTimeslicedUpdatesPerFrame=100 -r_ShadowsPCFiltering=1 -r_ShadowsCache=4 -r_ShadowsCacheFormat=1 -r_ShadowsCacheResolutions=6324,4214 -r_ShadowsUseClipVolume=1 -e_ObjShadowCastSpec=3 - -[1] -e_GsmLodsNum=3 -e_ParticlesShadows=0 -e_ShadowsBlendCascades=0 -e_ShadowsCastViewDistRatio=0.8 -e_ShadowsLodBiasFixed=1 -e_ShadowsMaxTexRes=512 -r_DrawNearShadows=0 -r_FogShadows=0 -r_ShadowJittering=0 -r_ShadowsCacheFormat=0 -r_ShadowsCacheResolutions=3162,2107 -e_ObjShadowCastSpec=1 -e_ShadowsPoolSize=1024 - -[2] -e_GsmLodsNum=4 -e_ParticlesShadows=0 -e_ShadowsBlendCascades=0 -e_ShadowsCastViewDistRatio=0.8 -e_ShadowsLodBiasFixed=1 -e_ShadowsMaxTexRes=512 -r_DrawNearShadows=0 -r_FogShadows=0 -r_ShadowJittering=0 -r_ShadowsCacheFormat=0 -r_ShadowsCacheResolutions=3162,2107 -e_ObjShadowCastSpec=1 -e_ShadowsPoolSize=1024 - -[3] -e_GsmLodsNum=4 -e_ParticlesShadows=0 -e_ShadowsBlendCascades=0 -e_ShadowsCastViewDistRatio=0.8 -e_ShadowsLodBiasFixed=1 -e_ShadowsMaxTexRes=512 -r_DrawNearShadows=0 -r_FogShadows=0 -r_ShadowJittering=0 -r_ShadowsCacheFormat=0 -r_ShadowsCacheResolutions=3162,2107 -e_ObjShadowCastSpec=1 -e_ShadowsPoolSize=1024 - -[4] -e_GsmLodsNum=4 -e_ParticlesShadows=0 -e_ShadowsBlendCascades=0 -e_ShadowsCastViewDistRatio=0.8 -e_ShadowsLodBiasFixed=1 -e_ShadowsMaxTexRes=512 -r_DrawNearShadows=0 -r_FogShadows=0 -r_ShadowJittering=0 -r_ShadowsCacheFormat=0 -r_ShadowsCacheResolutions=3162,2107 -e_ObjShadowCastSpec=1 -e_ShadowsPoolSize=1024 - -[5] -e_GsmLodsNum=4 -e_ParticlesShadows=0 -e_ShadowsBlendCascades=0 -e_ShadowsCastViewDistRatio=0.8 -e_ShadowsLodBiasFixed=1 -e_ShadowsMaxTexRes=512 -r_FogShadows=0 -r_ShadowJittering=1 -e_ObjShadowCastSpec=1 -r_ShadowsCacheResolutions=3162,2107 - -[6] -r_ShadowJittering=1 -e_ObjShadowCastSpec=2 - -[8] -r_FogShadows=1 -r_FogShadowsWater=1 -r_ShadowPoolMaxFrames=0 -r_ShadowPoolMaxTimeslicedUpdatesPerFrame=100 -e_ObjShadowCastSpec=4 -r_ShadowsCache=5 -r_ShadowsCacheResolutions=4214 diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Sound.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Sound.cfg deleted file mode 100644 index 42bd4c7f02..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Sound.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -[1] - -[2] - -[3] - -[4] - -[5] - -[6] - -[8] diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Texture.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Texture.cfg deleted file mode 100644 index 0e02c41ab2..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Texture.cfg +++ /dev/null @@ -1,94 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -e_TerrainTextureStreamingPoolItemsNum=64 -r_DynTexAtlasCloudsMaxSize=32 -r_DynTexAtlasSpritesMaxSize=32 -r_DynTexMaxSize=80 -r_EnvCMResolution=2 -r_EnvTexResolution=3 -r_ImposterRatio=1 -r_TexAtlasSize=2048 -r_TexMaxAnisotropy=4 -r_TexMinAnisotropy=4 -r_TexNoAnisoAlphaTest=0 - -[1] -e_TerrainTextureStreamingPoolItemsNum=16 -r_DynTexAtlasCloudsMaxSize=8 -r_DynTexAtlasSpritesMaxSize=8 -r_DynTexMaxSize=20 -r_EnvCMResolution=0 -r_EnvTexResolution=1 -r_ImposterRatio=2 -r_TexAtlasSize=512 -r_TexMaxAnisotropy=2 -r_TexMinAnisotropy=2 -r_TexNoAnisoAlphaTest=1 - -[2] -e_TerrainTextureStreamingPoolItemsNum=16 -r_DynTexAtlasCloudsMaxSize=8 -r_DynTexAtlasSpritesMaxSize=8 -r_DynTexMaxSize=20 -r_EnvCMResolution=0 -r_EnvTexResolution=1 -r_ImposterRatio=2 -r_TexAtlasSize=512 -r_TexMaxAnisotropy=2 -r_TexMinAnisotropy=2 -r_TexNoAnisoAlphaTest=1 - -[3] -e_TerrainTextureStreamingPoolItemsNum=16 -r_DynTexAtlasCloudsMaxSize=8 -r_DynTexAtlasSpritesMaxSize=8 -r_DynTexMaxSize=20 -r_EnvCMResolution=0 -r_EnvTexResolution=1 -r_ImposterRatio=2 -r_TexAtlasSize=512 -r_TexMaxAnisotropy=2 -r_TexMinAnisotropy=2 -r_TexNoAnisoAlphaTest=1 - -[4] -e_TerrainTextureStreamingPoolItemsNum=16 -r_DynTexAtlasCloudsMaxSize=8 -r_DynTexAtlasSpritesMaxSize=8 -r_DynTexMaxSize=20 -r_EnvCMResolution=0 -r_EnvTexResolution=1 -r_ImposterRatio=2 -r_TexAtlasSize=512 -r_TexMaxAnisotropy=2 -r_TexMinAnisotropy=2 -r_TexNoAnisoAlphaTest=1 - -[5] -r_DynTexAtlasCloudsMaxSize=24 -r_DynTexAtlasSpritesMaxSize=16 -r_DynTexMaxSize=50 -r_EnvCMResolution=0 -r_EnvTexResolution=1 -r_ImposterRatio=2 -r_TexAtlasSize=512 -r_TexMaxAnisotropy=2 -r_TexMinAnisotropy=2 -r_TexNoAnisoAlphaTest=1 - -[6] -r_DynTexAtlasCloudsMaxSize=24 -r_DynTexAtlasSpritesMaxSize=16 -r_DynTexMaxSize=60 -r_EnvCMResolution=1 -r_EnvTexResolution=2 -r_ImposterRatio=1.5 -r_TexMaxAnisotropy=8 -r_TexMinAnisotropy=8 -r_TexNoAnisoAlphaTest=1 - -[8] -r_TexMaxAnisotropy=16 -r_TexMinAnisotropy=16 diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_TextureResolution.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_TextureResolution.cfg deleted file mode 100644 index 6b6c11ddf6..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_TextureResolution.cfg +++ /dev/null @@ -1,52 +0,0 @@ -[default] -; dummy default for this CVarGroup (will be auto initialized during streaming system init or overridden by user via system.cfg) -= 0 - -; VRAM 1.0 GB -r_TexturesStreaming=1 -r_TexturesStreamingMipBias=0 -r_TexturesstreamingMinUsableMips=8 -r_TexturesStreamingSkipMips=2 -r_TexturesStreamPoolSize=256 - -[1] -; VRAM 1.0 GB -r_TexturesStreaming=0 -r_TexturesStreamingSkipMips=0 -r_TexturesStreamPoolSize=384 - -[2] -; VRAM 1.0 GB -r_TexturesStreaming=0 -r_TexturesStreamingSkipMips=0 -r_TexturesStreamPoolSize=384 - -[3] -; VRAM 1.0 GB -r_TexturesStreaming=0 -r_TexturesStreamingSkipMips=0 -r_TexturesStreamPoolSize=384 - -[4] -; VRAM 1.0 GB -r_TexturesStreaming=0 -r_TexturesStreamingSkipMips=0 -r_TexturesStreamPoolSize=384 - -[5] -; VRAM 1.0 GB - -[6] -; VRAM 1.5 GB -r_TexturesStreamingSkipMips=1 -r_TexturesStreamPoolSize=512 - -[7] -; VRAM 2.0 GB -r_TexturesStreamingSkipMips=0 -r_TexturesStreamPoolSize=640 - -[8] -; VRAM 3.0 GB -r_TexturesStreamingSkipMips=0 -r_TexturesStreamPoolSize=1536 \ No newline at end of file diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_VolumetricEffects.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_VolumetricEffects.cfg deleted file mode 100644 index b6fdfec33c..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_VolumetricEffects.cfg +++ /dev/null @@ -1,26 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -e_Clouds=1 -r_Beams=1 - -[1] -r_Beams=0 - -[2] -r_Beams=0 - -[3] -r_Beams=0 - -[4] -r_Beams=0 - -[5] -r_Beams=0 - -[6] -r_Beams=0 - -[8] diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Water.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Water.cfg deleted file mode 100644 index 720339dc98..0000000000 --- a/Assets/Engine/Config/CVarGroups/sys_spec_Water.cfg +++ /dev/null @@ -1,81 +0,0 @@ -[default] -; default of this CVarGroup -= 7 - -e_WaterOceanFFT=1 -e_WaterTessellationAmount=10 -e_WaterTessellationSwathWidth=10 -q_ShaderWater=2 -r_WaterCaustics=1 -r_WaterReflections=1 -r_WaterReflectionsQuality=4 -r_WaterReflectionsMinVisiblePixelsUpdate=0.05 -r_WaterTessellationHW=0 -r_WaterUpdateDistance=0.2 -r_WaterUpdateFactor=0.0 -r_WaterVolumeCaustics=0 -r_WaterVolumeCausticsDensity=256 -r_WaterVolumeCausticsMaxDist=35 -r_WaterVolumeCausticsRes=1024 -r_WaterVolumeCausticsSnapFactor=1 - -[1] -e_WaterTessellationAmount=20 -q_ShaderWater=1 -r_WaterReflectionsQuality=0 -r_WaterUpdateDistance=1 -r_WaterUpdateFactor=0.1 -r_WaterVolumeCausticsDensity=64 -r_WaterVolumeCausticsMaxDist=20 -r_WaterVolumeCausticsRes=384 - -[2] -e_WaterTessellationAmount=20 -q_ShaderWater=1 -r_WaterReflectionsQuality=0 -r_WaterUpdateDistance=1 -r_WaterUpdateFactor=0.1 -r_WaterVolumeCausticsDensity=64 -r_WaterVolumeCausticsMaxDist=20 -r_WaterVolumeCausticsRes=384 - -[3] -e_WaterTessellationAmount=20 -q_ShaderWater=1 -r_WaterReflectionsQuality=0 -r_WaterUpdateDistance=1 -r_WaterUpdateFactor=0.05 -r_WaterVolumeCausticsDensity=64 -r_WaterVolumeCausticsMaxDist=20 -r_WaterVolumeCausticsRes=384 - -[4] -e_WaterTessellationAmount=20 -q_ShaderWater=1 -r_WaterReflectionsQuality=4 -r_WaterUpdateDistance=1 -r_WaterUpdateFactor=0.01 -r_WaterVolumeCausticsDensity=64 -r_WaterVolumeCausticsMaxDist=20 -r_WaterVolumeCausticsRes=384 - -[5] -e_WaterTessellationAmount=20 -q_ShaderWater=1 -r_WaterUpdateDistance=1 -r_WaterUpdateFactor=0.1 -r_WaterVolumeCausticsDensity=64 -r_WaterVolumeCausticsMaxDist=20 -r_WaterVolumeCausticsRes=384 - -[6] -r_WaterUpdateDistance=1 -r_WaterUpdateFactor=0.05 -r_WaterVolumeCausticsDensity=128 -r_WaterVolumeCausticsMaxDist=25 -r_WaterVolumeCausticsRes=512 - -[8] -e_WaterTessellationAmount=85 -r_WaterTessellationHW=1 -r_WaterVolumeCaustics=1 diff --git a/Assets/Engine/Config/aidebug.cfg b/Assets/Engine/Config/aidebug.cfg index f8134c7461..b0eafaaa45 100644 --- a/Assets/Engine/Config/aidebug.cfg +++ b/Assets/Engine/Config/aidebug.cfg @@ -1,4 +1 @@ ai_DebugDraw = 1 -ai_DebugDrawNavigation = 1 -ai_DrawPath all -ai_debugMNMAgentType MediumSizedCharacters \ No newline at end of file diff --git a/Assets/Engine/Config/artprof.cfg b/Assets/Engine/Config/artprof.cfg index 2e1cf55a54..92b91623bf 100644 --- a/Assets/Engine/Config/artprof.cfg +++ b/Assets/Engine/Config/artprof.cfg @@ -1,7 +1,6 @@ ; Setup useful cvars for artists profiling GPU cost ; Once in level (e.g. map c3mp_rooftop_gardens from the frontend/cmdline), in the console: ; exec artprof.cfg -; Be sure also to set r_shadersAsyncActivation=0 in your user.cfg (or copy artprof_user.cfg -> user.cfg) ; used to allow loading of loose shaders sys_pakPriority=0 @@ -9,19 +8,8 @@ sys_pakPriority=0 ; because it's annoying and not relevant for artists sys_pakLogInvalidFileAccess=0 -; disable fog volumes and particles as they can be misleading with r_measureOverdraw 4 -e_fogVolumes=0 -e_particles=0 - ; for convenience -g_infiniteSuitEnergy=1 -g_infiniteAmmo=1 -g_timelimit=0 + bind o "r_measureOverdraw 0" bind p "r_measureOverdraw 4" -bind k "r_artProfile 0" -bind l "r_artProfile 1" - -; loading into an MP level with the map command stops you looking up and down unless you have a weapon -i_giveitem scar diff --git a/Assets/Engine/Config/artprof_user.cfg b/Assets/Engine/Config/artprof_user.cfg index 673436f6f3..265021e120 100644 --- a/Assets/Engine/Config/artprof_user.cfg +++ b/Assets/Engine/Config/artprof_user.cfg @@ -1,6 +1,3 @@ -; disable async shader activation as it crashes when r_shadersAllowCompilation=1 -r_shadersAsyncActivation=0 - ; enable shader compiliation for r_measureOverdraw 4 r_shadersAllowCompilation=1 diff --git a/Assets/Engine/Config/benchmark_cpu.cfg b/Assets/Engine/Config/benchmark_cpu.cfg index c75619107f..bbb3c9db95 100644 --- a/Assets/Engine/Config/benchmark_cpu.cfg +++ b/Assets/Engine/Config/benchmark_cpu.cfg @@ -1,13 +1,3 @@ -demo_restart_level = 2 -g_godMode=1 -g_infiniteammo=1 r_displayinfo=1 -demo_file = autotest -demo_ai = 1 -demo_num_runs = 4 -demo_quit = 1 -hud_startPaused=0 sys_maxfps=0 -e_ObjectLayersActivation=0 -sys_flash = 0 r_vsync = 0 diff --git a/Assets/Engine/Config/benchmark_gpu.cfg b/Assets/Engine/Config/benchmark_gpu.cfg index 7653b32d86..f0242d64d1 100644 --- a/Assets/Engine/Config/benchmark_gpu.cfg +++ b/Assets/Engine/Config/benchmark_gpu.cfg @@ -1,13 +1,3 @@ -demo_restart_level = 1 -g_godMode = 1 -g_infiniteammo = 1 r_displayinfo = 2 -demo_file = timedemo_short -demo_ai = 0 -demo_num_runs = 2 -demo_quit = 1 --- hud_startPaused = 0 sys_maxfps = -1 --- e_ObjectLayersActivation = 0 --- sys_flash = 0 -r_vsync = 0 \ No newline at end of file +r_vsync = 0 diff --git a/Assets/Engine/Config/mgpu.cfg b/Assets/Engine/Config/mgpu.cfg index 93da7fdfd0..e69de29bb2 100644 --- a/Assets/Engine/Config/mgpu.cfg +++ b/Assets/Engine/Config/mgpu.cfg @@ -1,6 +0,0 @@ -r_ColorGradingChartsCache = 0 -r_waterupdateFactor = 0 -r_PostProcessHUD3DCache = 0 -e_gsmcache = 0 -r_ConditionalRendering = 0 -e_gicache = 0 \ No newline at end of file diff --git a/Assets/Engine/Config/multiplayer.cfg b/Assets/Engine/Config/multiplayer.cfg index eafa434f8e..e69de29bb2 100644 --- a/Assets/Engine/Config/multiplayer.cfg +++ b/Assets/Engine/Config/multiplayer.cfg @@ -1,77 +0,0 @@ -ag_turnSpeedParamScale=0.0 -aim_assistFalloffDistance=200 -aim_assistInputForFullFollow_Ironsight=0.20 -aim_assistMaxDistance=255 -aim_assistMaxDistance_ironsight=255 -aim_assistMinTurnScale=0.5 -aim_assistMinTurnScale_ironsight=0.5 -aim_assistSlowDisableDistance=255 -aim_assistSlowFalloffStartDistance=200 -aim_assistSlowThresholdOuter=2.5 -aim_assiststrength=0.7 -aim_assiststrength_ironsight=0.75 -br_breakmaxworldsize=511 -cl_sensitivityControllerMP=0.6 -cl_shallowWaterSpeedMulPlayer=1.0 -controller_multiplier_x=3 -controller_multiplier_z=4 -g_actorViewDistRatio=255 - --- This forces broken trees to have spherical inertia, which makes them harder to rotate around their vertical axis. -g_breakageMinAxisInertia=1.0 -g_glassAutoShatterMinArea=0.5 - -g_distanceForceNoIk=35 -g_fpDbaManagementEnable=0 -g_godMode=0 -g_highlightingMaxDistanceToHighlightSquared=625 -g_hitDeathReactions_streaming=2 -g_mp_as_DefendersMaxHealth=150 -g_multiplayerDefault=1 - --- Overriden in GameSDK\Difficulty\*.cfg -g_playerLowHealthThreshold=20 -g_playerMidHealthThreshold=60 - -g_spawn_vistable_numLineTestsPerFrame=3 -g_telemetryConfig="MP" -g_telemetrySampleRateBandwidth=3 -g_telemetrySampleRateMemory=2 -g_telemetrySampleRatePerformance=1 -g_VTOLInsideBoundsScaleX=0.6 -g_VTOLInsideBoundsScaleY=1 -net_breakage_sync_entities=0 -net_enable_tfrc=0 -net_log=1 - --- Make consoles match the PC gravity -p_gravity_z="-13" - --- Sanity check for physics RepositionEntity -p_max_entity_cells=10000 - -pl_impulseEnabled=1 -pl_jump_maxTimerValue=0.0 -pl_jump_quickPressThresh=0.12 -pl_melee.angle_limit_from_behind=70 -pl_melee.impulses_enable=1 -pl_melee.melee_snap_angle_limit=45 -pl_melee.melee_snap_end_position_range=1.5 -pl_melee.melee_snap_move_speed_multiplier=10 -pl_melee.melee_snap_target_select_range=3.5 -pl_melee.mp_knockback_strength_hor=2 -pl_melee.mp_melee_system=1 -pl_melee.mp_victim_screenfx_blendout_duration=0.25 -pl_melee.mp_victim_screenfx_duration=0.1 -pl_nanovision_timetodrain=8 -pl_nanovision_timetorecharge=16 -pl_pickAndThrow.chargedThrowAutoAimConeSize=10 -pl_pickAndThrow.complexMelee_snap_angle_limit=25 -pl_sliding_control_mp.deceleration_speed=4 -pl_sliding_control_mp.max_downhill_acceleration=15 -pl_sliding_control_mp.min_speed=4 -pl_sliding_control_mp.min_speed_threshold=5 -pl_stealthKill_aimVsSpineLerp=0.65 -pl_stealthKill_useExtendedRange=1 -p_splash_vel0=0.5 -sv_bandwidth=2147483647 \ No newline at end of file diff --git a/Assets/Engine/Config/multiplayer_console.cfg b/Assets/Engine/Config/multiplayer_console.cfg index 0bed002497..e69de29bb2 100644 --- a/Assets/Engine/Config/multiplayer_console.cfg +++ b/Assets/Engine/Config/multiplayer_console.cfg @@ -1,29 +0,0 @@ -e_GI=0 -r_DeferredShadingIndexedAmbient=0 -e_ParticlesObjectCollisions=0 -g_distanceForceNoLegRaycasts=0.00001 -g_telemetryDisplaySessionId=1 -g_breakageNoDebrisCollisions=1 - -; Breakage throttling -; These are explained in ActionGame.cpp -; -g_glassAutoShatterOnExplosions=1 -g_glassNoDecals=1 -g_glassMaxPanesToBreakPerFrame=2 -g_breakageTreeMax=100 -g_breakageTreeInc=101 -g_breakageTreeDec=25 -g_breakageTreeIncGlass=51 - -sys_PakInMemoryPakSizeLimit=25 - -r_TexturesStreamPoolSecondarySize=35 -r_MotionBlur=1 - -e_CoverageBufferReproj=2 - -osm_enabled = 1 - -g_waterHitOnly = 1 -p_max_object_splashes=1 diff --git a/Assets/Engine/Config/recording.cfg b/Assets/Engine/Config/recording.cfg index 42a0dfd9bd..931dbf0858 100644 --- a/Assets/Engine/Config/recording.cfg +++ b/Assets/Engine/Config/recording.cfg @@ -1,63 +1,3 @@ --- added this lines for proper 360 deg panorama renderings - -e_ScreenShotFileFormat = jpg -demo_fixed_timestep = 60 -s_SoundEnable = 0 r_DisplayInfo = 0 -e_PanoramaScreenShotHeight = 720 -e_PanoramaScreenShotWidth = 10053 c_shakeMult = 0 -demo_ai = 1 -r_MotionBlur = 0 - --- enables full water reflection --- e_DebugMask = 2 -- e_DebugMask not allowed here - --- set weapong lighting effect to 0 to prevent flickering bug because of too much dynamic lights in the scene - - sys_spec = 2 -r_WaterRefractions = 1 -r_WaterReflections = 1 -r_WaterUpdateFactor = 0.01 -r_WaterReflections_ForceParticles = 0 - -r_EnvCMResolution = 2 -r_EnvTexResolution = 3 -r_EnvTexUpdateInterval = 0.05 -e_Decals = 1 -e_DecalsLifeTimeScale = 2 -ca_EnableDecals = 1 -e_LodRatio = 10 -e_ViewDistRatio = 55 -e_Lods = 1 -e_VegetationMinSize = 0 -r_CloudsUpdateAlways = 0 - -e_DynamicLightsMaxEntityLights = 3 -r_DepthOfField = 1 ---r_MotionBlur = 1 -r_Flares = 1 -r_checkSunVis = 1 -r_Coronas = 1 -r_CoronaFade = 0.1625 -r_UseEdgeAA = 1 -e_Clouds = 1 - -r_TexResolution = 0 -r_TexBumpResolution = 0 -r_DetailTextures = 1 -r_DetailNumLayers = 1 -r_DetailDistance = 8 - -e_ParticlesLod = 0.9 - -r_ShadowBlur = 3 -e_ShadowsMaxTexRes = 1024 -r_ShadowJittering = 1 -e_Shadows = 1 -e_VegetationBending = 1 -ai_UpdateAllAlways = 1 -r_refraction = 1 -r_sunshafts = 1 -r_ImposterRatio = 1 diff --git a/Assets/Engine/Config/singleplayer.cfg b/Assets/Engine/Config/singleplayer.cfg index fc7a4f4c05..e69de29bb2 100644 --- a/Assets/Engine/Config/singleplayer.cfg +++ b/Assets/Engine/Config/singleplayer.cfg @@ -1,15 +0,0 @@ -ai_CompatibilityMode=crysis2 -ai_BurstWhileMovingDestinationRange=9999.0 - -g_telemetryConfig=SP - -net_inactivitytimeout=3600 -net_inactivitytimeoutDevmode=3600 - -pl_movement.nonCombat_heavy_weapon_speed_scale=1.0 - --- BLM - Don't override game rules. The template project only has DummyRules. --- Furthermore, multiplayer.cfg doesn't set sv_gamerules, so the inconsistency --- is likely to create bugs. ---sv_gamerules=SinglePlayer -ca_StreamCHR=1 \ No newline at end of file diff --git a/Assets/Engine/Config/sketch_off.cfg b/Assets/Engine/Config/sketch_off.cfg deleted file mode 100644 index 6b0562daab..0000000000 --- a/Assets/Engine/Config/sketch_off.cfg +++ /dev/null @@ -1,24 +0,0 @@ -r_UseZPass = 1 -r_GeomInstancing = 1 - -e_Fog = 1 -e_Clouds = 1 -e_Decals = 1 -e_TerrainDetailMaterials = 1 -e_Dissolve = 1 -e_TerrainAo = 1 - -r_WaterReflections = 1 - -e_Shadows = 1 -e_VegetationBending = 1 - -r_PostProcessEffects = 1 -r_Flares = 1 -r_Beams = 1 -r_Glow = 1 - -r_DetailTextures = 1 - -r_refraction = 1 -r_sunshafts = 1 \ No newline at end of file diff --git a/Assets/Engine/Config/sketch_on.cfg b/Assets/Engine/Config/sketch_on.cfg deleted file mode 100644 index 6759b5d4c8..0000000000 --- a/Assets/Engine/Config/sketch_on.cfg +++ /dev/null @@ -1,24 +0,0 @@ -r_UseZPass = 0 -r_GeomInstancing = 0 - -e_Fog = 0 -e_Clouds = 0 -e_Decals = 0 -e_TerrainDetailMaterials = 0 -e_Dissolve = 0 -e_TerrainAo = 0 - -r_WaterReflections = 0 - -e_Shadows = 0 -e_VegetationBending = 0 - -r_PostProcessEffects = 0 -r_Flares = 0 -r_Beams = 0 -r_Glow = 0 - -r_DetailTextures = 0 - -r_refraction = 0 -r_sunshafts = 0 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/android_MaliT760.cfg b/Assets/Engine/Config/spec/android_MaliT760.cfg index f951e61eef..fd7c0a349d 100644 --- a/Assets/Engine/Config/spec/android_MaliT760.cfg +++ b/Assets/Engine/Config/spec/android_MaliT760.cfg @@ -1,76 +1,8 @@ -sys_spec_Full=2 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=0 --- Disable gmem for this device because it causes a crash -r_EnableGMEMPath=0 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - -sys_job_system_max_worker=2 sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 --- This allows the generation of reflections for the ocean water. Without it, the water looks really dark. -e_recursion=1 -e_CheckOcclusion=1 - -r_Fur=0 -az_Asset_EnableAsyncMeshLoading=0 - ------------------------- --- Misc. memory buffers ------------------------- -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=33554432 -ca_StreamCHR=1 - ------------------------- --- sys_spec_objectdetail ------------------------- -e_Dissolve=2 -e_LodRatio=5 -e_ViewDistRatioDetail=19 -e_ViewDistRatioVegetation=21 - - ------------------------- --- sys_spec_postprocessing ------------------------- -r_HDRBloom=0 -r_SunShafts=0 -r_ToneMapTechnique=3 -r_ToneMapExposureType=1 -r_ColorSpace=2 - ------------------------- --- sys_spec_shading ------------------------- -r_VisAreaClipLightsPerPixel=0 - ------------------------- --- sys_spec_textureresolution ------------------------- -r_TexturesstreamingMinUsableMips=7 - - - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/android_high.cfg b/Assets/Engine/Config/spec/android_high.cfg index fc46adc491..0ab8ebc37b 100644 --- a/Assets/Engine/Config/spec/android_high.cfg +++ b/Assets/Engine/Config/spec/android_high.cfg @@ -1,65 +1,7 @@ -sys_spec_Full=3 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=0 --- Enable framebufferfetch(256bpp) or pls if applicable -r_EnableGMEMPath=2 - --- Skip the native upscale as a second upscale already occurs -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - -sys_job_system_max_worker=2 sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 - -e_CheckOcclusion=1 - -r_Fur=0 -az_Asset_EnableAsyncMeshLoading=0 - ------------------------- --- Misc. memory buffers ------------------------- -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=33554432 -ca_StreamCHR=1 - ------------------------- --- sys_spec_objectdetail ------------------------- -e_Dissolve=2 -e_LodRatio=5 -e_ViewDistRatioDetail=19 - - ------------------------- --- sys_spec_shading ------------------------- -r_VisAreaClipLightsPerPixel=0 - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - -r_ClearGMEMGBuffer=1 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/android_high_nogmem.cfg b/Assets/Engine/Config/spec/android_high_nogmem.cfg index ac718a57ee..fd7c0a349d 100644 --- a/Assets/Engine/Config/spec/android_high_nogmem.cfg +++ b/Assets/Engine/Config/spec/android_high_nogmem.cfg @@ -1,61 +1,8 @@ -sys_spec_Full=3 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=0 --- Disabling gmem for this configuration -r_EnableGMEMPath=0 - --- Skip the native upscale as a second upscale already occurs -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - -sys_job_system_max_worker=2 sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 -e_CheckOcclusion=1 - -r_Fur=0 -az_Asset_EnableAsyncMeshLoading=0 - ------------------------- --- Misc. memory buffers ------------------------- -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=33554432 -ca_StreamCHR=1 - ------------------------- --- sys_spec_objectdetail ------------------------- -e_Dissolve=2 -e_LodRatio=5 -e_ViewDistRatioDetail=19 - - ------------------------- --- sys_spec_shading ------------------------- -r_VisAreaClipLightsPerPixel=0 - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 - diff --git a/Assets/Engine/Config/spec/android_low.cfg b/Assets/Engine/Config/spec/android_low.cfg index 6f2a876877..0ab8ebc37b 100644 --- a/Assets/Engine/Config/spec/android_low.cfg +++ b/Assets/Engine/Config/spec/android_low.cfg @@ -1,76 +1,7 @@ -sys_spec_Full=1 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=0 --- Enable framebufferfetch(256bpp) or pls if applicable -r_EnableGMEMPath=1 - --- Skip the native upscale as a second upscale already occurs -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - -sys_job_system_max_worker=2 sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 - --- This allows the generation of reflections for the ocean water. Without it, the water looks really dark. -e_recursion=0 -e_CheckOcclusion=1 - -r_Fur=0 - --- Water occlusion queries crash in some OpenGL ES 3.0 devices -e_HwOcclusionCullingWater = 0 -az_Asset_EnableAsyncMeshLoading=0 - ------------------------- --- Misc. memory buffers ------------------------- -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=33554432 -ca_StreamCHR=1 - ------------------------- --- sys_spec_objectdetail ------------------------- -e_Dissolve=2 -e_LodRatio=5 -e_ViewDistRatioDetail=19 - - ------------------------- --- sys_spec_shading ------------------------- -r_VisAreaClipLightsPerPixel=0 - - ------------------------- --- sys_spec_textureresolution ------------------------- -r_TexturesstreamingMinUsableMips=6 - - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 -r_ClearGMEMGBuffer=1 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/android_medium.cfg b/Assets/Engine/Config/spec/android_medium.cfg index f9d776efa7..0ab8ebc37b 100644 --- a/Assets/Engine/Config/spec/android_medium.cfg +++ b/Assets/Engine/Config/spec/android_medium.cfg @@ -1,81 +1,7 @@ -sys_spec_Full=2 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=0 --- Enable framebufferfetch(256bpp) or pls if applicable -r_EnableGMEMPath=1 - --- Skip the native upscale as a second upscale already occurs -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - -sys_job_system_max_worker=2 sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 - --- This allows the generation of reflections for the ocean water. Without it, the water looks really dark. -e_recursion=1 -e_CheckOcclusion=1 - -r_Fur=0 -az_Asset_EnableAsyncMeshLoading=0 - ------------------------- --- Misc. memory buffers ------------------------- -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=33554432 -ca_StreamCHR=1 - ------------------------- --- sys_spec_objectdetail ------------------------- -e_Dissolve=2 -e_LodRatio=5 -e_ViewDistRatioDetail=19 -e_ViewDistRatioVegetation=21 - - ------------------------- --- sys_spec_postprocessing ------------------------- -r_HDRBloom=0 -r_SunShafts=0 -r_ToneMapExposureType=1 -r_ColorSpace=2 - ------------------------- --- sys_spec_shading ------------------------- -r_VisAreaClipLightsPerPixel=0 - ------------------------- --- sys_spec_textureresolution ------------------------- -r_TexturesstreamingMinUsableMips=7 - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - -r_ClearGMEMGBuffer=1 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/android_veryhigh.cfg b/Assets/Engine/Config/spec/android_veryhigh.cfg index d4f8e9cd47..d58e319706 100644 --- a/Assets/Engine/Config/spec/android_veryhigh.cfg +++ b/Assets/Engine/Config/spec/android_veryhigh.cfg @@ -1,60 +1,5 @@ -sys_spec_Full=4 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=0 - --- Enable framebufferfetch(256bpp) or pls if applicable -r_EnableGMEMPath=1 - --- Skip the native upscale as a second upscale already occurs -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - -sys_job_system_max_worker=2 sys_streaming_in_blocks=1 - sys_streaming_memory_budget=512 - -e_CheckOcclusion=1 - -r_Fur=0 -az_Asset_EnableAsyncMeshLoading=0 - ------------------------- --- Misc. memory buffers ------------------------- -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=33554432 -ca_StreamCHR=1 - ------------------------- --- sys_spec_objectdetail ------------------------- -e_Dissolve=2 -e_LodRatio=5 -e_ViewDistRatioDetail=19 - - ------------------------- --- sys_spec_shading ------------------------- -r_VisAreaClipLightsPerPixel=0 - -r_ClearGMEMGBuffer=1 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/ios_high.cfg b/Assets/Engine/Config/spec/ios_high.cfg index 67fa99ca04..d0cf5b3bc5 100644 --- a/Assets/Engine/Config/spec/ios_high.cfg +++ b/Assets/Engine/Config/spec/ios_high.cfg @@ -1,100 +1,10 @@ -sys_spec_Full=3 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=1 --- Enable framebufferfetch or pls if applicable -r_EnableGMEMPath=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - - ------------------------- --- Job System ------------------------- -sys_job_system_enable=0 -sys_job_system_max_worker=1 - ------------------------ -- Streaming ------------------------ sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 ------------------------- --- General Rendering ------------------------- -r_Flush=0 --- Enabling this will clear the GMEM buffer before the z-pass -r_ClearGMEMGBuffer=2 -r_Fur=0 - ------------------------- --- VisArea / Portals ------------------------- -e_PortalsBlend=0 -r_GMEMVisAreasBlendWeight=0.5 - ------------------------- --- Misc. memory buffers ------------------------- -e_AutoPrecacheCgf=2 -e_AutoPrecacheTerrainAndProcVeget=1 -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=2048 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=32 -ca_StreamCHR=1 - ------------------------- --- sys_spec_water ------------------------- -e_WaterOcean=2 -e_WaterVolumes=2 -e_WaterOceanBottom=0 - ------------------------- --- batching ------------------------- -r_Batching = 1 -r_BatchType = 0 - ------------------------- --- geom instancing ------------------------- -r_GeomInstancing=1 -r_GeomInstancingThreshold=5 - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - ------------------------- --- Geometry Cache ------------------------- -e_GeomCaches=0 - - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/ios_low.cfg b/Assets/Engine/Config/spec/ios_low.cfg index 7870d65bd5..d0cf5b3bc5 100644 --- a/Assets/Engine/Config/spec/ios_low.cfg +++ b/Assets/Engine/Config/spec/ios_low.cfg @@ -1,103 +1,10 @@ -sys_spec_Full=1 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=1 --- Enable framebufferfetch or pls if applicable -r_EnableGMEMPath=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - - ------------------------- --- Job System ------------------------- -sys_job_system_enable=0 -sys_job_system_max_worker=1 - ------------------------ -- Streaming ------------------------ sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 ------------------------- --- General Rendering ------------------------- -r_Flush=0 --- Enabling this will clear the GMEM buffer before the z-pass -r_ClearGMEMGBuffer=2 -r_Fur=0 - ------------------------- --- VisArea / Portals ------------------------- -e_PortalsBlend=0 -r_GMEMVisAreasBlendWeight=0.5 - ------------------------- --- Misc. memory buffers ------------------------- -e_AutoPrecacheCgf=2 -e_AutoPrecacheTerrainAndProcVeget=1 -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=32 -ca_StreamCHR=1 - ------------------------- --- sys_spec_water ------------------------- -e_WaterOcean=2 -e_WaterVolumes=2 -e_WaterOceanBottom=0 - - ------------------------- --- batching ------------------------- -r_Batching = 1 -r_BatchType = 0 - ------------------------- --- geom instancing ------------------------- -r_GeomInstancing=1 -r_GeomInstancingThreshold=5 - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - ------------------------- --- Geometry Cache ------------------------- -e_GeomCaches=0 - - - - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/ios_medium.cfg b/Assets/Engine/Config/spec/ios_medium.cfg index 2eaecdef16..d0cf5b3bc5 100644 --- a/Assets/Engine/Config/spec/ios_medium.cfg +++ b/Assets/Engine/Config/spec/ios_medium.cfg @@ -1,101 +1,10 @@ -sys_spec_Full=2 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=1 --- Enable framebufferfetch or pls if applicable -r_EnableGMEMPath=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - - ------------------------- --- Job System ------------------------- -sys_job_system_enable=0 -sys_job_system_max_worker=1 - ------------------------ -- Streaming ------------------------ sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 ------------------------- --- General Rendering ------------------------- -r_Flush=0 --- Enabling this will clear the GMEM buffer before the z-pass -r_ClearGMEMGBuffer=2 -r_Fur=0 - ------------------------- --- VisArea / Portals ------------------------- -e_PortalsBlend=0 -r_GMEMVisAreasBlendWeight=0.5 - ------------------------- --- Misc. memory buffers ------------------------- -e_AutoPrecacheCgf=2 -e_AutoPrecacheTerrainAndProcVeget=1 -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=1024 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=32 -ca_StreamCHR=1 - ------------------------- --- sys_spec_water ------------------------- -e_WaterOcean=2 -e_WaterVolumes=2 -e_WaterOceanBottom=0 - - ------------------------- --- batching ------------------------- -r_Batching = 1 -r_BatchType = 0 - ------------------------- --- geom instancing ------------------------- -r_GeomInstancing=1 -r_GeomInstancingThreshold=5 - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - ------------------------- --- Geometry Cache ------------------------- -e_GeomCaches=0 - - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/ios_veryhigh.cfg b/Assets/Engine/Config/spec/ios_veryhigh.cfg index 53937a77bf..d0cf5b3bc5 100644 --- a/Assets/Engine/Config/spec/ios_veryhigh.cfg +++ b/Assets/Engine/Config/spec/ios_veryhigh.cfg @@ -1,102 +1,10 @@ -sys_spec_Full=4 - -- Cap frame rate at 30fps sys_maxfps=30 r_vsync=1 --- Enable framebufferfetch or pls if applicable -r_EnableGMEMPath=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - - ------------------------- --- Job System ------------------------- -sys_job_system_enable=0 -sys_job_system_max_worker=1 - ------------------------ -- Streaming ------------------------ sys_streaming_in_blocks=1 sys_streaming_memory_budget=512 ------------------------- --- General Rendering ------------------------- -r_Flush=0 --- Enabling this will clear the GMEM buffer before the z-pass -r_ClearGMEMGBuffer=2 -r_Fur=0 - ------------------------- --- VisArea / Portals ------------------------- -e_PortalsBlend=0 -r_GMEMVisAreasBlendWeight=0.5 - ------------------------- --- Misc. memory buffers ------------------------- -e_AutoPrecacheCgf=2 -e_AutoPrecacheTerrainAndProcVeget=1 -e_GeomCacheBufferSize=0 -e_CheckOcclusionQueueSize=512 -e_CheckOcclusionOutputQueueSize=2048 - ------------------------- --- Animation ------------------------- -ca_MemoryDefragPoolSize=32 -ca_StreamCHR=1 - ------------------------- --- sys_spec_water ------------------------- -e_WaterOcean=2 -e_WaterVolumes=2 -e_WaterOceanBottom=0 - - ------------------------- --- batching ------------------------- -r_Batching = 1 -r_BatchType = 0 - ------------------------- --- geom instancing ------------------------- -r_GeomInstancing=1 -r_GeomInstancingThreshold=5 - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - ------------------------- --- Geometry Cache ------------------------- -e_GeomCaches=0 - - - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 - --- Sort ligths since we have limited space in the shadowmap pool texture -r_DeferredShadingSortLights = 3 - ---Use an optimized pixel format for the lighting rendertargets during the lighting pass. -r_DeferredShadingLBuffersFmt = 2 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/osx_metal_high.cfg b/Assets/Engine/Config/spec/osx_metal_high.cfg deleted file mode 100644 index 8689e23c51..0000000000 --- a/Assets/Engine/Config/spec/osx_metal_high.cfg +++ /dev/null @@ -1,38 +0,0 @@ - -sys_spec_Full=7 -r_ShadersMETAL=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - ------------------------- --- sys_spec_postprocessing ------------------------- -r_SunShafts=1 - ------------------------- --- sys_spec_shading ------------------------- -r_DeferredShadingTiled=0 -r_RefractionPartialResolves=0 -e_GI = 0 - - -r_Fur=2 - - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 diff --git a/Assets/Engine/Config/spec/osx_metal_low.cfg b/Assets/Engine/Config/spec/osx_metal_low.cfg deleted file mode 100644 index a3084d48c5..0000000000 --- a/Assets/Engine/Config/spec/osx_metal_low.cfg +++ /dev/null @@ -1,37 +0,0 @@ - -sys_spec_Full=5 -r_ShadersMETAL=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - ------------------------- --- sys_spec_postprocessing ------------------------- -r_SunShafts=1 - ------------------------- --- sys_spec_shading ------------------------- -r_DeferredShadingTiled=0 -r_RefractionPartialResolves=0 -e_GI=0 - -r_Fur=2 - - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 diff --git a/Assets/Engine/Config/spec/osx_metal_medium.cfg b/Assets/Engine/Config/spec/osx_metal_medium.cfg deleted file mode 100644 index 6477bbb217..0000000000 --- a/Assets/Engine/Config/spec/osx_metal_medium.cfg +++ /dev/null @@ -1,37 +0,0 @@ - -sys_spec_Full=6 -r_ShadersMETAL=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - ------------------------- --- sys_spec_postprocessing ------------------------- -r_SunShafts=1 - ------------------------- --- sys_spec_shading ------------------------- -r_DeferredShadingTiled=0 -r_RefractionPartialResolves=0 -e_GI = 0 - -r_Fur=2 - - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 diff --git a/Assets/Engine/Config/spec/osx_metal_veryhigh.cfg b/Assets/Engine/Config/spec/osx_metal_veryhigh.cfg deleted file mode 100644 index 899c198f31..0000000000 --- a/Assets/Engine/Config/spec/osx_metal_veryhigh.cfg +++ /dev/null @@ -1,37 +0,0 @@ - -sys_spec_Full=8 -r_ShadersMETAL=1 - --- Default of 3 allocates all shaders (potentially >150 MB) --- 1 is most memory efficient but definitely causes hitches when converting HLSL --- shaders. Recommend 1 during dev, and 3 with optimized caches for release. -r_ShadersPreactivate=1 - --- Skip the native upscale as a second upscale occurs on Metal Present -r_SkipNativeUpscale=1 - ------------------------- --- sys_spec_postprocessing ------------------------- -r_SunShafts=1 - ------------------------- --- sys_spec_shading ------------------------- -r_DeferredShadingTiled=0 -r_RefractionPartialResolves=0 -e_GI = 0 - -r_Fur=2 - - ------------------------- --- Upscaling ------------------------- ---0 point, 1 bilinear, 2 bicubic, 3 lanczos -r_UpscalingQuality=1 - --- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame. --- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame. --- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps -e_ShadowsCacheRequireManualUpdate = 2 diff --git a/Assets/Engine/Config/spec/pc_high.cfg b/Assets/Engine/Config/spec/pc_high.cfg index a62ed25a6a..e69de29bb2 100644 --- a/Assets/Engine/Config/spec/pc_high.cfg +++ b/Assets/Engine/Config/spec/pc_high.cfg @@ -1 +0,0 @@ -sys_spec_Full = 7 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/pc_low.cfg b/Assets/Engine/Config/spec/pc_low.cfg index 068446e151..e69de29bb2 100644 --- a/Assets/Engine/Config/spec/pc_low.cfg +++ b/Assets/Engine/Config/spec/pc_low.cfg @@ -1 +0,0 @@ -sys_spec_Full = 5 diff --git a/Assets/Engine/Config/spec/pc_medium.cfg b/Assets/Engine/Config/spec/pc_medium.cfg index 0d08b956b4..e69de29bb2 100644 --- a/Assets/Engine/Config/spec/pc_medium.cfg +++ b/Assets/Engine/Config/spec/pc_medium.cfg @@ -1 +0,0 @@ -sys_spec_Full = 6 \ No newline at end of file diff --git a/Assets/Engine/Config/spec/pc_veryhigh.cfg b/Assets/Engine/Config/spec/pc_veryhigh.cfg index 33959937e8..e69de29bb2 100644 --- a/Assets/Engine/Config/spec/pc_veryhigh.cfg +++ b/Assets/Engine/Config/spec/pc_veryhigh.cfg @@ -1 +0,0 @@ -sys_spec_Full = 8 diff --git a/Assets/Engine/Config/statoscope.cfg b/Assets/Engine/Config/statoscope.cfg index d1d18c813c..ed2089bd67 100644 --- a/Assets/Engine/Config/statoscope.cfg +++ b/Assets/Engine/Config/statoscope.cfg @@ -1,12 +1,3 @@ profile=-1 -profile_allthreads=1 -i_forcefeedback=0 -g_godmode=1 log_verbosity=-1 sys_pakLogInvalidFileAccess=1 -e_StatoscopeDataGroups=fgmrtudlipny -e_StatoscopeFilenameUseBuildInfo=0 -e_StatoscopeFilenameUseMap=1 -e_StatoscopeMinFuncLengthMs=0.1 -e_StatoscopeMaxNumFuncsPerFrame=60 -e_StatoscopeScreenshotCapturePeriod=5 diff --git a/Assets/Engine/Config/vr.cfg b/Assets/Engine/Config/vr.cfg index 989f55f345..80d4b7ce81 100644 --- a/Assets/Engine/Config/vr.cfg +++ b/Assets/Engine/Config/vr.cfg @@ -3,39 +3,13 @@ ----------------------------------------------- r_width = 960 r_height = 1080 -r_backbufferWidth = 1920 -r_backbufferHeight = 1080 - ------------------------------------------- -- Set the system Spec (Medium) ------------------------------------------- sys_spec = 2 - -------------------------------------------- --- HMD related -------------------------------------------- -r_overrideDXGIoutput = 0 -r_stereodevice = 100 -r_stereomode = 1 -r_stereooutput = 7 -r_minimizeLatency = 1 -hmd_low_persistence = 1 -r_stereoScaleCoefficient = 1 - - ------------------------------------------- -- Set some video optimisations ------------------------------------------- r_vsync = 0 -r_MotionBlur = 0 -r_ssdoHalfRes = 3 -r_Refraction = 0 -r_DeferredShadingTiled = 0 -r_CBufferUseNativeDepth = 0 - -------------------------------------------- --- Hide the hud -------------------------------------------- ---hud_hide = 1 diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed index 579fd3c444..aafbffbe8f 100644 --- a/Assets/Engine/SeedAssetList.seed +++ b/Assets/Engine/SeedAssetList.seed @@ -48,22 +48,6 @@ - - - - - - - - - - - - - - - - @@ -432,110 +416,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -616,38 +496,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 821e0acfdb..11832f8846 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -113,7 +113,6 @@ def create_basic_atom_level(level_name): general.close_pane("Error Log") general.idle_wait(1.0) general.run_console("r_displayInfo=0") - general.run_console("r_antialiasingmode=0") general.idle_wait(1.0) # Delete all existing entities & create default_level entity diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py index 92199bf196..fbd9f3459a 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py @@ -66,7 +66,6 @@ def run(): general.close_pane("Error Log") general.idle_wait(1.0) general.run_console("r_displayInfo=0") - general.run_console("r_antialiasingmode=0") general.idle_wait(1.0) return True diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py index ac28e67fa1..93e78a7c0a 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py @@ -82,7 +82,6 @@ def run(): general.close_pane("Error Log") general.idle_wait(1.0) general.run_console("r_displayInfo=0") - general.run_console("r_antialiasingmode=0") general.idle_wait(1.0) return True diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py index ef3048d8d4..1b094b1cfa 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -149,7 +149,6 @@ class TestHelper: general.idle_wait(1.0) general.idle_wait(1.0) general.run_console("r_displayInfo=0") - general.run_console("r_antialiasingmode=0") general.idle_wait(1.0) diff --git a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py index 49cf17855f..22fa3aca0d 100755 --- a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py +++ b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py @@ -187,7 +187,3 @@ def prepare_for_screenshot_compare(remote_console_instance): """ wait_for(lambda: _retry_command(remote_console_instance, 'r_displayinfo 0', '$3r_DisplayInfo = $60 $5[DUMPTODISK, RESTRICTEDMODE]$4')) - wait_for(lambda: _retry_command(remote_console_instance, 'r_antialiasingmode 0', - '$3r_AntialiasingMode = $60 $5[]$4')) - wait_for(lambda: _retry_command(remote_console_instance, 'e_WaterOcean 0', - '$3e_WaterOcean = $60 $5[]$4')) diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 6de10f3855..ee1c498a9a 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -1273,17 +1273,6 @@ AZ_POP_DISABLE_WARNING //Load config files ////////////////////////////////////////////////////////////////////////// - int curSpecVal = 0; - ICVar* pSysSpecCVar = gEnv->pConsole->GetCVar("r_GraphicsQuality"); - if (gEnv->pSystem->IsDevMode()) - { - if (pSysSpecCVar && pSysSpecCVar->GetFlags() & VF_WASINCONFIG) - { - curSpecVal = pSysSpecCVar->GetIVal(); - pSysSpecCVar->SetFlags(pSysSpecCVar->GetFlags() | VF_SYSSPEC_OVERWRITE); - } - } - // tools may not interact with @user@ if (!gEnv->IsInToolMode()) { @@ -1293,16 +1282,6 @@ AZ_POP_DISABLE_WARNING } } - // If sys spec variable was specified, is not 0, and we are in devmode restore the value from before loading game.cfg - // This enables setting of a specific sys_spec outside menu and game.cfg - if (gEnv->pSystem->IsDevMode()) - { - if (pSysSpecCVar && curSpecVal && curSpecVal != pSysSpecCVar->GetIVal()) - { - pSysSpecCVar->Set(curSpecVal); - } - } - { // We have to load this file again since first time we did it without devmode LoadConfiguration(m_systemConfigName.c_str()); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h index 96393f4a1f..99e752c90a 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h @@ -22,7 +22,7 @@ namespace ImageProcessingAtom const static AZ::u32 EIF_UNUSED_BIT = 0x40; // Free to use const static AZ::u32 EIF_AttachedAlpha = 0x400; // info for the engine: it's a texture with attached alpha channel const static AZ::u32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear) - const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized with r_TexResolution + const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized const static AZ::u32 EIF_RenormalizedTexture = 0x10000; // info for the engine: for dds textures that have renormalized color range const static AZ::u32 EIF_CafeNative = 0x20000; // info for the engine: native Cafe texture format const static AZ::u32 EIF_RestrictedPlatformONative = 0x40000; // native tiled texture for restrict platform O diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp index 28a5a30e9c..81ec4b17c8 100644 --- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp +++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp @@ -199,20 +199,6 @@ namespace ImGui } } - // Lod Min - static ICVar* eLodMinCVAR = gEnv->pConsole->GetCVar("e_LodMin"); - if (eLodMinCVAR) - { - int minLodValue = eLodMinCVAR->GetIVal(); - int dragIntVal = minLodValue; - ImGui::Text("e_LodMin: %d ( Force a lowest LOD level )", minLodValue); - ImGui::SliderInt("##LodMin", &dragIntVal, 0, 5); - if (dragIntVal != minLodValue) - { - eLodMinCVAR->Set(dragIntVal); - } - } - // Texel Density static ICVar* eTexelDensityCVAR = gEnv->pConsole->GetCVar("e_texeldensity"); if (eTexelDensityCVAR) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py index 42adee91ea..75eaa65e94 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py @@ -208,13 +208,6 @@ class AndroidLauncher(Launcher): with self.android_vfs_setreg_path.open('w') as android_vfs_setreg: json.dump(vfs_settings, android_vfs_setreg, indent=4) - self.workspace.settings.modify_platform_setting('r_AssetProcessorShaderCompiler', 1) - self.workspace.settings.modify_platform_setting('r_ShadersAsyncCompiling', 0) - self.workspace.settings.modify_platform_setting('r_ShadersRemoteCompiler', 1) - self.workspace.settings.modify_platform_setting('r_ShadersAllowCompilation', 1) - self.workspace.settings.modify_platform_setting('r_ShadersAsyncActivation', 0) - self.workspace.settings.modify_platform_setting('r_ShaderCompilerServer', '127.0.0.1') - self.workspace.settings.modify_platform_setting('r_ShaderCompilerPort', '61453') self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", '127.0.0.1') def launch(self): diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py index 210519d197..047e4fdeef 100644 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py @@ -172,7 +172,6 @@ class LinuxLauncher(Launcher): self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"') self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"') - self.workspace.settings.modify_platform_setting("r_AssetProcessorShaderCompiler", 1) self.workspace.settings.modify_platform_setting("r_ShaderCompilerServer", host_ip) self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", host_ip) diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py index 4f904b0a40..d18431ba82 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py @@ -172,8 +172,6 @@ class WinLauncher(Launcher): self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"') self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"') - self.workspace.settings.modify_platform_setting("r_AssetProcessorShaderCompiler", 1) - self.workspace.settings.modify_platform_setting("r_ShaderCompilerServer", host_ip) self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", host_ip) diff --git a/Tools/LyTestTools/tests/unit/test_launcher_android.py b/Tools/LyTestTools/tests/unit/test_launcher_android.py index d2f700e35e..d1adccb096 100755 --- a/Tools/LyTestTools/tests/unit/test_launcher_android.py +++ b/Tools/LyTestTools/tests/unit/test_launcher_android.py @@ -238,7 +238,7 @@ class TestAndroidLauncher: launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"]) launcher.configure_settings() - assert mock_workspace.settings.modify_platform_setting.call_count == 8 + assert mock_workspace.settings.modify_platform_setting.call_count == 1 @mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict') @mock.patch('ly_test_tools.environment.process_utils.check_output') diff --git a/cmake/Tools/layout_tool.py b/cmake/Tools/layout_tool.py index 62e3922770..8093f72e44 100755 --- a/cmake/Tools/layout_tool.py +++ b/cmake/Tools/layout_tool.py @@ -120,10 +120,7 @@ def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_typ warning_count += _warn(f"'system_{platform_name_lower}_{asset_type}.cfg' is missing from {str(layout_path)}") system_config_values = None else: - system_config_values = common.get_config_file_values(str(platform_system_cfg_file), ['r_ShadersRemoteCompiler', - 'r_ShadersAllowCompilation', - 'r_AssetProcessorShaderCompiler', - 'r_ShaderCompilerServer']) + system_config_values = common.get_config_file_values(str(platform_system_cfg_file), []) if bootstrap_values: @@ -146,24 +143,23 @@ def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_typ elif system_config_values is not None: - shaders_remote_compiler = system_config_values.get('r_ShadersRemoteCompiler') or '0' + shaders_remote_compiler = '0' asset_processor_shader_compiler = system_config_values.get('r_AssetProcessorShaderCompiler') or '0' - shader_compiler_server = system_config_values.get('r_ShaderCompilerServer') or LOCAL_HOST + shader_compiler_server = LOCAL_HOST shaders_allow_compilation = system_config_values.get('r_ShadersAllowCompilation') def _validate_remote_shader_settings(): - if shader_compiler_server == LOCAL_HOST: - if asset_processor_shader_compiler != '1': - return _warn(f"Connection to the remote shader compiler (r_ShaderCompilerServer) is not properly " - f"set in system_{platform_name_lower}_{asset_type}.cfg. If it is set to {LOCAL_HOST}, then " - f"r_AssetProcessorShaderCompiler must be set to 1.") + if asset_processor_shader_compiler != '1': + return _warn(f"Connection to the remote shader compiler (r_ShaderCompilerServer) is not properly " + f"set in system_{platform_name_lower}_{asset_type}.cfg. If it is set to {LOCAL_HOST}, then " + f"r_AssetProcessorShaderCompiler must be set to 1.") - else: - if _validate_remote_ap(remote_ip, remote_connect, False) > 0: - return _warn(f"The system_{platform_name_lower}_{asset_type}.cfg file is configured to connect to the" - f" shader compiler server through the remote connection to the Asset Processor.") + else: + if _validate_remote_ap(remote_ip, remote_connect, False) > 0: + return _warn(f"The system_{platform_name_lower}_{asset_type}.cfg file is configured to connect to the" + f" shader compiler server through the remote connection to the Asset Processor.") return 0 # Validation steps based on the asset mode @@ -181,16 +177,9 @@ def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_typ warning_count += _warn("No pak files found for PAK mode deployment") # Check if the shader paks are set if has_shader_pak: - # If the shader paks are set, make sure that the remote shader compiler connection settings are set - # or that it is going through AP - if shaders_remote_compiler == '1': - warning_count += _warn(f"Shader paks are set for project {project_name} but remote shader compiling " - f"(r_ShadersRemoteCompiler) is still enabled " - f"for it in system_{platform_name_lower}_{asset_type}.cfg.") - else: - # Since we are not connecting to the shader compiler, also make sure bootstrap is not configured to - # connect to Asset Processor remotely - warning_count += _validate_remote_ap(remote_ip, remote_connect, False) + # Since we are not connecting to the shader compiler, also make sure bootstrap is not configured to + # connect to Asset Processor remotely + warning_count += _validate_remote_ap(remote_ip, remote_connect, False) if shaders_allow_compilation is not None and shaders_allow_compilation == '1': warning_count += _warn(f"Shader paks are set for project {project_name} but shader compiling " diff --git a/editor.cfg b/editor.cfg index 843a52824d..a8719590c5 100644 --- a/editor.cfg +++ b/editor.cfg @@ -1,33 +1,12 @@ -- Settings stored here are only used in the Editor --- Disable the Missing Asset Resolver by default -ed_MissingAssetResolver = 0 -e_ShadowsCache=0 -r_MotionBlur=0 -r_HDRVignetting=0 --- For feature-test compatibility -mn_FatalErrorOnInvalidEntity=0 - -- Do not warn on Pak file access issues sys_PakWarnOnPakAccessFailures=0 --- By default, disable any possible stereo output that might have been enabled via a GEM/other config file so that --- the editor does not startup in stereo mode (which prevents actually editing the environment) -r_StereoMode=0 -r_StereoOutput=0 - -- When editing terrain in the editor, the highest-detail octree nodes for any edited sector will be rendered until -- the level is exported and saved, which can cause an artificial increase in the number of nodes that can get -- queued for visibility checks. These numbers need to be set high enough to account for those increases. --- The CheckOcclusionQueueSize should be at least (terrain height * terrain width) / (32 * 32) in size. --- (Each queue entry is 64 bytes of RAM) -e_CheckOcclusionQueueSize=32768 - --- The CheckOcclusionOutputQueueSize should be at least double the above queue size for safety. --- (Each queue entry is 64 bytes of RAM) -e_CheckOcclusionOutputQueueSize=65536 - -- Enable warnings when asset loads take longer than the given millisecond threshold cl_assetLoadWarningEnable=true cl_assetLoadWarningMsThreshold=100 diff --git a/system_android_android.cfg b/system_android_android.cfg index d5bfddeb73..10ab95abc4 100644 --- a/system_android_android.cfg +++ b/system_android_android.cfg @@ -6,40 +6,14 @@ sys_PakLogInvalidFileAccess=1 r_WidthAndHeightAsFractionOfScreenSize=1.0 r_MaxWidth=1280 r_MaxHeight=1080 - r_fullscreen=0 +r_ShadersAllowCompilation=1 -- Enable to prevent log spam, can cause missed messages -- log_spamdelay=1 --- DXGL ---r_Batching=0 - --- Enabling aync shader compiling causes a hang on some Android devices. -r_ShadersAsyncCompiling=0 -r_ShadersRemoteCompiler=1 -r_ShadersAllowCompilation=1 -r_ShadersAsyncActivation=0 - --- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor --- to forward the request to the real shader compiler server. Your device is no --- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor: -r_AssetProcessorShaderCompiler=1 - --- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1. --- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port): -r_ShaderCompilerServer=127.0.0.1 - --- For Shader Compiler server running on other machines - 61453 is the default port -r_ShaderCompilerPort=61453 - --- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. -r_GraphicsQuality = 2 - -s_FileCacheManagerSize=262144 - -- Remote console inclusion list log_RemoteConsoleAllowedAddresses=127.0.0.1 -- Localization Settings -sys_localization_format=0 \ No newline at end of file +sys_localization_format=0 diff --git a/system_ios_ios.cfg b/system_ios_ios.cfg index 190ad4a121..abf08d0209 100644 --- a/system_ios_ios.cfg +++ b/system_ios_ios.cfg @@ -3,26 +3,7 @@ ------------------------ r_FullScreen=1 - r_ShadersAllowCompilation=1 -r_ShadersAsyncActivation=0 -r_ShadersAsyncCompiling=0 -r_ShadersRemoteCompiler=1 -r_ShadersUseLLVMDirectXCompiler=1 - --- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. -r_GraphicsQuality = 0 - --- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor --- to forward the request to the real shader compiler server. Your device is no --- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor: -r_AssetProcessorShaderCompiler=1 - --- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1. --- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port): -r_ShaderCompilerServer=127.0.0.1 - ---r_ShaderCompilerPort=61453 ------------------------ -- System @@ -39,16 +20,6 @@ sys_physics_CPU=0 -- log_spamdelay=1 log_IncludeTime=1 ------------------------- --- Audio ------------------------- -s_FileCacheManagerSize=262144 ------------------------- --- Auxiliary Geometry ------------------------- -r_enableAuxGeom=0 -r_auxGeom=0 - -- Remote console inclusion list log_RemoteConsoleAllowedAddresses=127.0.0.1 diff --git a/system_linux_pc.cfg b/system_linux_pc.cfg index 614bc44b49..5fec6b8dfd 100644 --- a/system_linux_pc.cfg +++ b/system_linux_pc.cfg @@ -10,8 +10,6 @@ sys_PakLogInvalidFileAccess = 0 -- Remote console inclusion list log_RemoteConsoleAllowedAddresses=127.0.0.1 -gm_disconnectDetection = 1 - -- Localization Settings sys_localization_format=0 @@ -20,27 +18,7 @@ r_width = 1280 r_height = 720 r_fullscreen = 0 -r_ShadersAsyncCompiling = 3 -r_ShadersAsyncActivation = 3 -r_ShadersAsyncMaxThreads = 16 -r_ShadersRemoteCompiler = 1 r_ShadersAllowCompilation = 1 --- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor --- to forward the request to the real shader compiler server. Your device is no --- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor: -r_AssetProcessorShaderCompiler=0 - --- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1. --- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port): ---r_ShaderCompilerServer=127.0.0.1 ---r_ShaderCompilerPort = 61453 - --- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. Autodetection not yet implemented for this platform. -r_GraphicsQuality = 1 - --- Texture streaming not supported on opengl -r_TexturesStreaming=0 - -- Display FPS r_displayInfo = 3 diff --git a/system_mac_mac.cfg b/system_mac_mac.cfg index 22fbca6e1e..ef145c890e 100644 --- a/system_mac_mac.cfg +++ b/system_mac_mac.cfg @@ -3,9 +3,6 @@ sys_float_exceptions=0 log_IncludeTime=1 sys_PakLogInvalidFileAccess=0 --- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. Currently overwritten by hardcoded value for this platform. -r_GraphicsQuality = 0 - r_width=1280 r_height=720 r_fullscreen=0 @@ -13,25 +10,7 @@ r_fullscreen=0 -- Enable to prevent log spam, can cause missed messages -- log_spamdelay=1 --- DXGL -r_Batching=0 - -r_ShadersAsyncCompiling=0 -r_ShadersRemoteCompiler=1 r_ShadersAllowCompilation=1 -r_ShadersAsyncActivation=0 -r_ShadersUseLLVMDirectXCompiler=1 - --- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor --- to forward the request to the real shader compiler server. Your device is no --- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor: -r_AssetProcessorShaderCompiler=1 - --- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1. --- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port): -r_ShaderCompilerServer=127.0.0.1 - ---r_ShaderCompilerPort=61453 -- Remote console inclusion list log_RemoteConsoleAllowedAddresses=127.0.0.1 diff --git a/system_windows_pc.cfg b/system_windows_pc.cfg index 05210e02e0..aa53ed9323 100644 --- a/system_windows_pc.cfg +++ b/system_windows_pc.cfg @@ -11,27 +11,7 @@ r_fullscreen = 0 -- Enable to prevent log spam, can cause missed messages -- log_spamdelay=1 -r_ShadersAsyncCompiling = 3 -r_ShadersAsyncActivation = 3 -r_ShadersAsyncMaxThreads = 16 -r_ShadersRemoteCompiler = 0 r_ShadersAllowCompilation = 1 --- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor --- to forward the request to the real shader compiler server. Your device is no --- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor: -r_AssetProcessorShaderCompiler=0 - --- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1. --- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port): -r_ShaderCompilerServer=127.0.0.1 ---r_ShaderCompilerPort = 61453 - --- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. Autodetection not yet implemented for this platform. -r_GraphicsQuality = 4 - ---r_driver=GL ---r_ShadersGL4=1 - -- Localization Settings sys_localization_format=0 From 70636572ff259873a19dd6f8c384b3025c399df1 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:08:07 -0700 Subject: [PATCH 209/293] Fix casing of editor_xml filenames to match casing in .ly files (#4640) Signed-off-by: Steve Pham --- Code/Editor/CryEditDoc.cpp | 4 ++-- Code/Editor/Util/XmlArchive.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp index 75bd0ad270..4944c3bff5 100644 --- a/Code/Editor/CryEditDoc.cpp +++ b/Code/Editor/CryEditDoc.cpp @@ -1273,7 +1273,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename) if (savedEntities) { AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel Updated PakFile levelEntities.editor_xml"); - pakFile.UpdateFile("LevelEntities.editor_xml", entitySaveBuffer.begin(), static_cast(entitySaveBuffer.size())); + pakFile.UpdateFile("levelentities.editor_xml", entitySaveBuffer.begin(), static_cast(entitySaveBuffer.size())); // Save XML archive to pak file. bool bSaved = xmlAr.SaveToPak(Path::GetPath(tempSaveFile), pakFile); @@ -1501,7 +1501,7 @@ bool CCryEditDoc::LoadEntitiesFromLevel(const QString& levelPakFile) bool pakOpened = pakSystem->OpenPack(levelPakFile.toUtf8().data()); if (pakOpened) { - const QString entityFilename = Path::GetPath(levelPakFile) + "LevelEntities.editor_xml"; + const QString entityFilename = Path::GetPath(levelPakFile) + "levelentities.editor_xml"; CCryFile entitiesFile; if (entitiesFile.Open(entityFilename.toUtf8().data(), "rt")) diff --git a/Code/Editor/Util/XmlArchive.cpp b/Code/Editor/Util/XmlArchive.cpp index 18c3fc8e63..3a965fb239 100644 --- a/Code/Editor/Util/XmlArchive.cpp +++ b/Code/Editor/Util/XmlArchive.cpp @@ -119,7 +119,7 @@ bool CXmlArchive::SaveToPak([[maybe_unused]] const QString& levelPath, CPakFile& _smart_ptr pXmlStrData = root->getXMLData(5000000); // Save xml file. - QString xmlFilename = "Level.editor_xml"; + QString xmlFilename = "level.editor_xml"; pakFile.UpdateFile(xmlFilename.toUtf8().data(), (void*)pXmlStrData->GetString(), static_cast(pXmlStrData->GetStringLength())); if (pakFile.GetArchive()) @@ -134,7 +134,7 @@ bool CXmlArchive::SaveToPak([[maybe_unused]] const QString& levelPath, CPakFile& ////////////////////////////////////////////////////////////////////////// bool CXmlArchive::LoadFromPak(const QString& levelPath, CPakFile& pakFile) { - QString xmlFilename = QDir(levelPath).absoluteFilePath("Level.editor_xml"); + QString xmlFilename = QDir(levelPath).absoluteFilePath("level.editor_xml"); root = XmlHelpers::LoadXmlFromFile(xmlFilename.toUtf8().data()); if (!root) { From 3b78132833f7537e7f5c107fa38b13987cd91f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Semp=C3=A9?= <58790905+lsemp3d@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:45:41 -0700 Subject: [PATCH 210/293] Split StyleHelper.h into a header and source file (#4614) * Split StyleHelper.h into a header and source file Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> * Missing file from commit Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> * Removed incorrect path Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> * Fixed includes Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> * Removed unnecessary comment Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> * Missing include Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../GraphCanvas/Styling/StyleHelper.cpp | 470 +++++++++++++++++ .../GraphCanvas/Styling/StyleHelper.h | 480 ++---------------- .../Code/graphcanvas_staticlib_files.cmake | 1 + .../ContainerWizard/ContainerWizard.cpp | 1 - .../Tools/UpgradeTool/UpgradeHelper.ui | 3 - 5 files changed, 510 insertions(+), 445 deletions(-) create mode 100644 Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.cpp diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.cpp new file mode 100644 index 0000000000..6313d6ec17 --- /dev/null +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.cpp @@ -0,0 +1,470 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include + +namespace GraphCanvas +{ + namespace Styling + { + + StyleHelper::StyleHelper(const AZ::EntityId& styledEntity) + { + SetStyle(styledEntity); + } + + StyleHelper::StyleHelper(const AZ::EntityId& realStyledEntity, const AZStd::string& virtualChildElement) + { + SetStyle(realStyledEntity, virtualChildElement); + } + + StyleHelper::~StyleHelper() + { + ReleaseStyle(); + } + + void StyleHelper::OnStylesUnloaded() + { + ReleaseStyle(); + } + + void StyleHelper::SetEditorId(const EditorId& editorId) + { + if (m_editorId != editorId) + { + ReleaseStyle(); + m_editorId = editorId; + + RegisterStyleSheetBus(m_editorId); + } + } + + void StyleHelper::SetScene(const AZ::EntityId& sceneId) + { + m_scene = sceneId; + + EditorId editorId; + SceneRequestBus::EventResult(editorId, m_scene, &SceneRequests::GetEditorId); + SetEditorId(editorId); + } + + void StyleHelper::SetStyle(const AZ::EntityId& styledEntity) + { + ReleaseStyle(); + + m_styledEntity = styledEntity; + + AZ::EntityId sceneId; + SceneMemberRequestBus::EventResult(sceneId, m_styledEntity, &SceneMemberRequests::GetScene); + if (!sceneId.IsValid()) + { + return; + } + + SetScene(sceneId); + + for (const auto& selector : m_styleSelectors) + { + StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str()); + } + + UpdateStyle(); + } + + void StyleHelper::SetStyle(const AZStd::string& style) + { + ReleaseStyle(); + + m_deleteStyledEntity = true; + + PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateStyleEntity, style); + + for (const auto& selector : m_styleSelectors) + { + StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str()); + } + + // TODO: remove/replace OnSceneSet and fix any systems/components listening for that event. + SceneMemberNotificationBus::Event(m_styledEntity, &SceneMemberNotifications::OnSceneSet, m_scene); + + UpdateStyle(); + + static bool enableDiagnostic = false; + if (enableDiagnostic) + { + AZStd::string description; + StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription); + qDebug() << description.c_str(); + } + } + + void StyleHelper::SetStyle(const AZ::EntityId& parentStyledEntity, const AZStd::string& virtualChildElement) + { + ReleaseStyle(); + + m_deleteStyledEntity = true; + + AZ::EntityId sceneId; + SceneMemberRequestBus::EventResult(sceneId, parentStyledEntity, &SceneMemberRequests::GetScene); + + SetScene(sceneId); + + PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateVirtualChild, parentStyledEntity, virtualChildElement); + + for (const auto& selector : m_styleSelectors) + { + StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str()); + } + + UpdateStyle(); + + static bool enableDiagnostic = false; + if (enableDiagnostic) + { + AZStd::string description; + StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription); + qDebug() << description.c_str(); + } + + } + + void StyleHelper::RemoveAttributeOverride(Styling::Attribute attribute) + { + m_attributeOverride.erase(attribute); + } + + bool StyleHelper::HasAttribute(Styling::Attribute attribute) const + { + bool hasAttribute = (m_attributeOverride.find(attribute) != m_attributeOverride.end()); + + if (!hasAttribute) + { + StyleRequestBus::EventResult(hasAttribute, m_style, &StyleRequests::HasAttribute, static_cast(attribute)); + } + + return hasAttribute; + } + + QColor StyleHelper::GetColor(Styling::Attribute color, QColor defaultValue /*= QColor()*/) const + { + return GetAttribute(color, defaultValue); + } + + QFont StyleHelper::GetFont() const + { + QFont font; + QFontInfo info(font); + info.pixelSize(); + + font.setFamily(GetAttribute(Attribute::FontFamily, font.family())); + font.setPixelSize(GetAttribute(Attribute::FontSize, info.pixelSize())); + font.setWeight(GetAttribute(Attribute::FontWeight, font.weight())); + font.setStyle(GetAttribute(Attribute::FontStyle, font.style())); + font.setCapitalization(GetAttribute(Attribute::FontVariant, font.capitalization())); + + return font; + } + + QString StyleHelper::GetFontStyleSheet() const + { + QFont font = GetFont(); + QColor color = GetColor(Styling::Attribute::Color); + + QStringList fields; + + fields.push_back(QString("color: rgba(%1,%2,%3,%4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha())); + + fields.push_back(QString("font-family: %1").arg(font.family())); + fields.push_back(QString("font-size: %1px").arg(font.pixelSize())); + + if (font.bold()) + { + fields.push_back("font-weight: bold"); + } + + switch (font.style()) + { + case QFont::StyleNormal: + break; + case QFont::StyleItalic: + fields.push_back("font-style: italic"); + break; + case QFont::StyleOblique: + fields.push_back("font-style: italic"); + break; + } + + const bool underline = font.underline(); + const bool strikeOut = font.strikeOut(); + + if (underline && strikeOut) + { + fields.push_back("text-decoration: underline line-through"); + } + else if (underline) + { + fields.push_back("text-decoration: underline"); + } + else if (strikeOut) + { + fields.push_back("text-decoration: line-through"); + } + + return fields.join("; "); + } + + QPen StyleHelper::GetPen(Styling::Attribute width, Styling::Attribute style, Styling::Attribute color, Styling::Attribute cap, bool cosmetic /*= false*/) const + { + QPen pen; + pen.setColor(GetAttribute(color, QColor(Qt::black))); + pen.setWidth(GetAttribute(width, 1)); + pen.setStyle(GetAttribute(style, Qt::SolidLine)); + pen.setCapStyle(GetAttribute(cap, Qt::SquareCap)); + pen.setCosmetic(cosmetic); + + return pen; + } + + QPen StyleHelper::GetBorder() const + { + return GetPen(Styling::Attribute::BorderWidth, Styling::Attribute::BorderStyle, Styling::Attribute::BorderColor, Styling::Attribute::CapStyle); + } + + QBrush StyleHelper::GetBrush(Styling::Attribute color, QBrush defaultValue /*= QBrush()*/) const + { + return GetAttribute(color, defaultValue); + } + + QSizeF StyleHelper::GetSize(QSizeF defaultSize) const + { + return{ + GetAttribute(Styling::Attribute::Width, defaultSize.width()), + GetAttribute(Styling::Attribute::Height, defaultSize.height()) + }; + } + + QSizeF StyleHelper::GetMinimumSize(QSizeF defaultSize /*= QSizeF(0,0)*/) const + { + return QSizeF(GetAttribute(Styling::Attribute::MinWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MinHeight, defaultSize.height())); + } + + QSizeF StyleHelper::GetMaximumSize(QSizeF defaultSize /*= QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)*/) const + { + return QSizeF(GetAttribute(Styling::Attribute::MaxWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MaxHeight, defaultSize.height())); + } + + QMarginsF StyleHelper::GetMargins(QMarginsF defaultMargins /*= QMarginsF()*/) const + { + bool hasMargin = false; + StyleRequestBus::EventResult(hasMargin, m_style, &StyleRequests::HasAttribute, static_cast(Styling::Attribute::Margin)); + + if (hasMargin) + { + qreal defaultMargin = GetAttribute(Styling::Attribute::Margin, 0); + defaultMargins = QMarginsF(defaultMargin, defaultMargin, defaultMargin, defaultMargin); + } + + return QMarginsF( + GetAttribute(Styling::Attribute::Margin/*TODO Left*/, defaultMargins.left()), + GetAttribute(Styling::Attribute::Margin/*TODO Top*/, defaultMargins.top()), + GetAttribute(Styling::Attribute::Margin/*TODO Right*/, defaultMargins.right()), + GetAttribute(Styling::Attribute::Margin/*TODO Bottom*/, defaultMargins.bottom()) + ); + } + + bool StyleHelper::HasTextAlignment() const + { + return HasAttribute(Styling::Attribute::TextAlignment) || HasAttribute(Styling::Attribute::TextVerticalAlignment); + } + + Qt::Alignment StyleHelper::GetTextAlignment(Qt::Alignment defaultAlignment) const + { + bool horizontalAlignment = HasAttribute(Styling::Attribute::TextAlignment); + bool verticalAlignment = HasAttribute(Styling::Attribute::TextVerticalAlignment); + + if (horizontalAlignment || verticalAlignment) + { + Qt::Alignment alignment = GetAttribute(Styling::Attribute::TextAlignment, Qt::AlignmentFlag::AlignLeft); + alignment = alignment | GetAttribute(Styling::Attribute::TextVerticalAlignment, Qt::AlignmentFlag::AlignTop); + + return alignment; + } + + return defaultAlignment; + } + + void StyleHelper::AddSelector(const AZStd::string_view& selector) + { + auto insertResult = m_styleSelectors.insert(AZStd::string(selector)); + + if (insertResult.second && m_styledEntity.IsValid()) + { + StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.data()); + + UpdateStyle(); + } + } + + void StyleHelper::RemoveSelector(const AZStd::string_view& selector) + { + AZStd::size_t elements = m_styleSelectors.erase(selector); + + if (elements > 0) + { + StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::RemoveSelectorState, selector.data()); + + UpdateStyle(); + } + } + + GraphCanvas::CandyStripeConfiguration StyleHelper::GetCandyStripeConfiguration() const + { + CandyStripeConfiguration config; + + config.m_initialOffset = GetAttribute(Styling::Attribute::StripeOffset, 0); + config.m_maximumSize = GetAttribute(Styling::Attribute::MaximumStripeSize, 10); + + if (config.m_maximumSize <= 0) + { + config.m_maximumSize = 1; + } + + config.m_minStripes = GetAttribute(Styling::Attribute::MinimumStripes, 2); + + if (config.m_minStripes <= 0) + { + config.m_minStripes = 1; + } + + config.m_stripeAngle = GetAttribute(Styling::Attribute::StripeAngle, 60); + + if (config.m_stripeAngle > 90) + { + config.m_stripeAngle = 89; + } + else if (config.m_stripeAngle < -90) + { + config.m_stripeAngle = -89; + } + + if (!HasAttribute(Styling::Attribute::StripeColor)) + { + QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0, 0, 0)); + + config.m_stripeColor = backgroundColor.darker(); + + int totalDifference = 0; + + totalDifference += backgroundColor.red() - config.m_stripeColor.red(); + totalDifference += backgroundColor.green() - config.m_stripeColor.green(); + totalDifference += backgroundColor.blue() - config.m_stripeColor.blue(); + + if (totalDifference < 150) + { + config.m_stripeColor = backgroundColor.lighter(); + } + } + else + { + config.m_stripeColor = GetAttribute(Styling::Attribute::StripeColor, QColor(0, 0, 0)); + } + + return config; + } + + GraphCanvas::PatternedFillGenerator StyleHelper::GetPatternedFillGenerator() const + { + PatternedFillGenerator generator; + generator.m_editorId = m_editorId; + + generator.m_id = GetAttribute(Styling::Attribute::PatternTemplate, QString()).toUtf8().data(); + + if (HasAttribute(Styling::Attribute::PatternPalettes)) + { + AZStd::string paletteStrings = GetAttribute(Styling::Attribute::PatternPalettes, QString()).toUtf8().data(); + + AzFramework::StringFunc::Tokenize(paletteStrings.c_str(), generator.m_palettes, ','); + } + else + { + QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0, 0, 0)); + + QColor patternColor = backgroundColor.darker(); + + int totalDifference = 0; + + totalDifference += backgroundColor.red() - patternColor.red(); + totalDifference += backgroundColor.green() - patternColor.green(); + totalDifference += backgroundColor.blue() - patternColor.blue(); + + if (totalDifference < 150) + { + patternColor = backgroundColor.lighter(); + } + + generator.m_colors.push_back(patternColor); + } + + generator.m_configuration = GetPatternFillConfiguration(); + + return generator; + } + + GraphCanvas::PatternFillConfiguration StyleHelper::GetPatternFillConfiguration() const + { + PatternFillConfiguration configuration; + + configuration.m_minimumTileRepetitions = GetAttribute(Styling::Attribute::MinimumRepetitions, 1); + configuration.m_evenRowOffsetPercent = GetAttribute(Styling::Attribute::EvenOffsetPercent, 0.0f); + configuration.m_oddRowOffsetPercent = GetAttribute(Styling::Attribute::OddOffsetPercent, 0.0f); + + return configuration; + } + + void StyleHelper::PopulatePaletteConfiguration(PaletteIconConfiguration& configuration) const + { + AZStd::string stylePalette; + StyledEntityRequestBus::EventResult(stylePalette, m_styledEntity, &StyledEntityRequests::GetFullStyleElement); + + if (!stylePalette.empty()) + { + configuration.SetColorPalette(stylePalette); + } + } + + void StyleHelper::UpdateStyle() + { + ReleaseStyle(false); + StyleManagerRequestBus::EventResult(m_style, m_editorId, &StyleManagerRequests::ResolveStyles, m_styledEntity); + } + + void StyleHelper::ReleaseStyle(bool destroyChildElement /*= true*/) + { + if (m_style.IsValid()) + { + if (m_deleteStyledEntity && destroyChildElement) + { + m_deleteStyledEntity = false; + AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_styledEntity); + } + AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_style); + + m_style.SetInvalid(); + } + } + + void StyleHelper::RegisterStyleSheetBus(const EditorId& editorId) + { + StyleManagerNotificationBus::Handler::BusDisconnect(); + StyleManagerNotificationBus::Handler::BusConnect(editorId); + } + +} +} diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h index cc7429f8fc..b500d4b197 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h @@ -8,7 +8,8 @@ #pragma once -AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option") +#if !defined(Q_MOC_RUN) + #include #include #include @@ -16,7 +17,6 @@ AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option") #include #include #include -AZ_POP_DISABLE_WARNING #include #include @@ -32,6 +32,8 @@ AZ_POP_DISABLE_WARNING #include #include +#endif + namespace GraphCanvas { namespace Styling @@ -45,124 +47,49 @@ namespace GraphCanvas AZ_CLASS_ALLOCATOR(StyleHelper, AZ::SystemAllocator, 0); StyleHelper() = default; - - StyleHelper(const AZ::EntityId& styledEntity) - { - SetStyle(styledEntity); - } - - StyleHelper(const AZ::EntityId& realStyledEntity, const AZStd::string& virtualChildElement) - { - SetStyle(realStyledEntity, virtualChildElement); - } - - virtual ~StyleHelper() - { - ReleaseStyle(); - } + StyleHelper(const AZ::EntityId& styledEntity); + StyleHelper(const AZ::EntityId& realStyledEntity, const AZStd::string& virtualChildElement); + virtual ~StyleHelper(); // StyleManagerNotificationBus - void OnStylesUnloaded() override - { - ReleaseStyle(); - } + void OnStylesUnloaded() override; //// - void SetEditorId(const EditorId& editorId) - { - if (m_editorId != editorId) - { - ReleaseStyle(); - m_editorId = editorId; - - RegisterStyleSheetBus(m_editorId); - } - } - - // TODO: Get rid of this and m_scene once the OnSceneSet notification is removed (see below). - void SetScene(const AZ::EntityId& sceneId) - { - m_scene = sceneId; + void SetEditorId(const EditorId& editorId); + void SetScene(const AZ::EntityId& sceneId); - EditorId editorId; - SceneRequestBus::EventResult(editorId, m_scene, &SceneRequests::GetEditorId); - SetEditorId(editorId); - } + void SetStyle(const AZStd::string& style); + void SetStyle(const AZ::EntityId& styledEntity); + void SetStyle(const AZ::EntityId& parentStyledEntity, const AZStd::string& virtualChildElement); - void SetStyle(const AZ::EntityId& styledEntity) - { - ReleaseStyle(); + bool HasAttribute(Styling::Attribute attribute) const; + void RemoveAttributeOverride(Styling::Attribute attribute); - m_styledEntity = styledEntity; + QColor GetColor(Styling::Attribute color, QColor defaultValue = QColor()) const; + QFont GetFont() const; - AZ::EntityId sceneId; - SceneMemberRequestBus::EventResult(sceneId, m_styledEntity, &SceneMemberRequests::GetScene); - if (!sceneId.IsValid()) - { - return; - } - - SetScene(sceneId); - - for (const auto& selector : m_styleSelectors) - { - StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str()); - } - - UpdateStyle(); - -#if 0 - AZStd::string description; - StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription); - qDebug() << description.c_str(); -#endif - } - - void SetStyle(const AZStd::string& style) - { - ReleaseStyle(); - - m_deleteStyledEntity = true; - - PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateStyleEntity, style); - - for (const auto& selector : m_styleSelectors) - { - StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str()); - } - - // TODO: remove/replace OnSceneSet and fix any systems/components listening for that event. - SceneMemberNotificationBus::Event(m_styledEntity, &SceneMemberNotifications::OnSceneSet, m_scene); - - UpdateStyle(); - } - - void SetStyle(const AZ::EntityId& parentStyledEntity, const AZStd::string& virtualChildElement) - { - ReleaseStyle(); - - m_deleteStyledEntity = true; - - AZ::EntityId sceneId; - SceneMemberRequestBus::EventResult(sceneId, parentStyledEntity, &SceneMemberRequests::GetScene); + //! Helper method which constructs a stylesheet based on the calculated font style. + //! We need this too pass along to certain Qt widgets because we use our own custom style parsing system. + QString GetFontStyleSheet() const; - SetScene(sceneId); + QPen GetPen(Styling::Attribute width, Styling::Attribute style, Styling::Attribute color, Styling::Attribute cap, bool cosmetic = false) const; + QPen GetBorder() const; + QBrush GetBrush(Styling::Attribute color, QBrush defaultValue = QBrush()) const; + QSizeF GetSize(QSizeF defaultSize) const; + QSizeF GetMinimumSize(QSizeF defaultSize = QSizeF(0,0)) const; + QSizeF GetMaximumSize(QSizeF defaultSize = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) const; + QMarginsF GetMargins(QMarginsF defaultMargins = QMarginsF()) const; - PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateVirtualChild, parentStyledEntity, virtualChildElement); + bool HasTextAlignment() const; + Qt::Alignment GetTextAlignment(Qt::Alignment defaultAlignment) const; - for (const auto& selector : m_styleSelectors) - { - StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str()); - } + void AddSelector(const AZStd::string_view& selector); + void RemoveSelector(const AZStd::string_view& selector); - UpdateStyle(); - -#if 0 - AZStd::string description; - StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription); - qDebug() << description.c_str(); -#endif - } + CandyStripeConfiguration GetCandyStripeConfiguration() const; + PatternedFillGenerator GetPatternedFillGenerator() const; + PatternFillConfiguration GetPatternFillConfiguration() const; + void PopulatePaletteConfiguration(PaletteIconConfiguration& configuration) const; template void AddAttributeOverride(Styling::Attribute attribute, const Value& defaultValue = Value()) @@ -170,23 +97,6 @@ namespace GraphCanvas m_attributeOverride[attribute] = QVariant(defaultValue); } - void RemoveAttributeOverride(Styling::Attribute attribute) - { - m_attributeOverride.erase(attribute); - } - - bool HasAttribute(Styling::Attribute attribute) const - { - bool hasAttribute = (m_attributeOverride.find(attribute) != m_attributeOverride.end()); - - if (!hasAttribute) - { - StyleRequestBus::EventResult(hasAttribute, m_style, &StyleRequests::HasAttribute, static_cast(attribute)); - } - - return hasAttribute; - } - template Value GetAttribute(Styling::Attribute attribute, const Value& defaultValue = Value()) const { @@ -202,7 +112,7 @@ namespace GraphCanvas { bool hasAttribute = false; auto rawAttribute = static_cast(attribute); - + StyleRequestBus::EventResult(hasAttribute, m_style, &StyleRequests::HasAttribute, rawAttribute); if (hasAttribute) @@ -217,323 +127,11 @@ namespace GraphCanvas return retVal; } - QColor GetColor(Styling::Attribute color, QColor defaultValue = QColor()) const - { - return GetAttribute(color, defaultValue); - } - - QFont GetFont() const - { - QFont font; - QFontInfo info(font); - info.pixelSize(); - - font.setFamily(GetAttribute(Attribute::FontFamily, font.family())); - font.setPixelSize(GetAttribute(Attribute::FontSize, info.pixelSize())); - font.setWeight(GetAttribute(Attribute::FontWeight, font.weight())); - font.setStyle(GetAttribute(Attribute::FontStyle, font.style())); - font.setCapitalization(GetAttribute(Attribute::FontVariant, font.capitalization())); - - return font; - } - - //! Helper method which constructs a stylesheet based on the calculated font style. - //! We need this too pass along to certain Qt widgets because we use our own custom style parsing system. - QString GetFontStyleSheet() const - { - QFont font = GetFont(); - QColor color = GetColor(Styling::Attribute::Color); - - QStringList fields; - - fields.push_back(QString("color: rgba(%1,%2,%3,%4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha())); - - fields.push_back(QString("font-family: %1").arg(font.family())); - fields.push_back(QString("font-size: %1px").arg(font.pixelSize())); - - if (font.bold()) - { - fields.push_back("font-weight: bold"); - } - - switch (font.style()) - { - case QFont::StyleNormal: - break; - case QFont::StyleItalic: - fields.push_back("font-style: italic"); - break; - case QFont::StyleOblique: - fields.push_back("font-style: italic"); - break; - } - - const bool underline = font.underline(); - const bool strikeOut = font.strikeOut(); - - if (underline && strikeOut) - { - fields.push_back("text-decoration: underline line-through"); - } - else if (underline) - { - fields.push_back("text-decoration: underline"); - } - else if (strikeOut) - { - fields.push_back("text-decoration: line-through"); - } - - return fields.join("; "); - } - - QPen GetPen(Styling::Attribute width, Styling::Attribute style, Styling::Attribute color, Styling::Attribute cap, bool cosmetic = false) const - { - QPen pen; - pen.setColor(GetAttribute(color, QColor(Qt::black))); - pen.setWidth(GetAttribute(width, 1)); - pen.setStyle(GetAttribute(style, Qt::SolidLine)); - pen.setCapStyle(GetAttribute(cap, Qt::SquareCap)); - pen.setCosmetic(cosmetic); - - return pen; - } - - QPen GetBorder() const - { - return GetPen(Styling::Attribute::BorderWidth, Styling::Attribute::BorderStyle, Styling::Attribute::BorderColor, Styling::Attribute::CapStyle); - } - - QBrush GetBrush(Styling::Attribute color, QBrush defaultValue = QBrush()) const - { - return GetAttribute(color, defaultValue); - } - - QSizeF GetSize(QSizeF defaultSize) const - { - return{ - GetAttribute(Styling::Attribute::Width, defaultSize.width()), - GetAttribute(Styling::Attribute::Height, defaultSize.height()) - }; - } - - QSizeF GetMinimumSize(QSizeF defaultSize = QSizeF(0,0)) const - { - return QSizeF(GetAttribute(Styling::Attribute::MinWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MinHeight, defaultSize.height())); - } - - QSizeF GetMaximumSize(QSizeF defaultSize = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) const - { - return QSizeF(GetAttribute(Styling::Attribute::MaxWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MaxHeight, defaultSize.height())); - } - - QMarginsF GetMargins(QMarginsF defaultMargins = QMarginsF()) const - { - bool hasMargin = false; - StyleRequestBus::EventResult(hasMargin, m_style, &StyleRequests::HasAttribute, static_cast(Styling::Attribute::Margin)); - - if (hasMargin) - { - qreal defaultMargin = GetAttribute(Styling::Attribute::Margin, 0); - defaultMargins = QMarginsF(defaultMargin, defaultMargin, defaultMargin, defaultMargin); - } - - return QMarginsF( - GetAttribute(Styling::Attribute::Margin/*TODO Left*/, defaultMargins.left()), - GetAttribute(Styling::Attribute::Margin/*TODO Top*/, defaultMargins.top()), - GetAttribute(Styling::Attribute::Margin/*TODO Right*/, defaultMargins.right()), - GetAttribute(Styling::Attribute::Margin/*TODO Bottom*/, defaultMargins.bottom()) - ); - } - - bool HasTextAlignment() const - { - return HasAttribute(Styling::Attribute::TextAlignment) || HasAttribute(Styling::Attribute::TextVerticalAlignment); - } - - Qt::Alignment GetTextAlignment(Qt::Alignment defaultAlignment) const - { - bool horizontalAlignment = HasAttribute(Styling::Attribute::TextAlignment); - bool verticalAlignment = HasAttribute(Styling::Attribute::TextVerticalAlignment); - - if (horizontalAlignment || verticalAlignment) - { - Qt::Alignment alignment = GetAttribute(Styling::Attribute::TextAlignment, Qt::AlignmentFlag::AlignLeft); - alignment = alignment | GetAttribute(Styling::Attribute::TextVerticalAlignment, Qt::AlignmentFlag::AlignTop); - - return alignment; - } - - return defaultAlignment; - } - - void AddSelector(const AZStd::string_view& selector) - { - auto insertResult = m_styleSelectors.insert(AZStd::string(selector)); - - if (insertResult.second && m_styledEntity.IsValid()) - { - StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.data()); - - UpdateStyle(); - } - } - - void RemoveSelector(const AZStd::string_view& selector) - { - AZStd::size_t elements = m_styleSelectors.erase(selector); - - if (elements > 0) - { - StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::RemoveSelectorState, selector.data()); - - UpdateStyle(); - } - } - - CandyStripeConfiguration GetCandyStripeConfiguration() const - { - CandyStripeConfiguration config; - - config.m_initialOffset = GetAttribute(Styling::Attribute::StripeOffset, 0); - config.m_maximumSize = GetAttribute(Styling::Attribute::MaximumStripeSize, 10); - - if (config.m_maximumSize <= 0) - { - config.m_maximumSize = 1; - } - - config.m_minStripes = GetAttribute(Styling::Attribute::MinimumStripes, 2); - - if (config.m_minStripes <= 0) - { - config.m_minStripes = 1; - } - - config.m_stripeAngle = GetAttribute(Styling::Attribute::StripeAngle, 60); - - if (config.m_stripeAngle > 90) - { - config.m_stripeAngle = 89; - } - else if (config.m_stripeAngle < -90) - { - config.m_stripeAngle = -89; - } - - if (!HasAttribute(Styling::Attribute::StripeColor)) - { - QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0,0,0)); - - config.m_stripeColor = backgroundColor.darker(); - - int totalDifference = 0; - - totalDifference += backgroundColor.red() - config.m_stripeColor.red(); - totalDifference += backgroundColor.green() - config.m_stripeColor.green(); - totalDifference += backgroundColor.blue() - config.m_stripeColor.blue(); - - if (totalDifference < 150) - { - config.m_stripeColor = backgroundColor.lighter(); - } - } - else - { - config.m_stripeColor = GetAttribute(Styling::Attribute::StripeColor, QColor(0, 0, 0)); - } - - return config; - } - - PatternedFillGenerator GetPatternedFillGenerator() const - { - PatternedFillGenerator generator; - generator.m_editorId = m_editorId; - - generator.m_id = GetAttribute(Styling::Attribute::PatternTemplate, QString()).toUtf8().data(); - - if (HasAttribute(Styling::Attribute::PatternPalettes)) - { - AZStd::string paletteStrings = GetAttribute(Styling::Attribute::PatternPalettes, QString()).toUtf8().data(); - - AzFramework::StringFunc::Tokenize(paletteStrings.c_str(), generator.m_palettes, ','); - } - else - { - QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0, 0, 0)); - - QColor patternColor = backgroundColor.darker(); - - int totalDifference = 0; - - totalDifference += backgroundColor.red() - patternColor.red(); - totalDifference += backgroundColor.green() - patternColor.green(); - totalDifference += backgroundColor.blue() - patternColor.blue(); - - if (totalDifference < 150) - { - patternColor = backgroundColor.lighter(); - } - - generator.m_colors.push_back(patternColor); - } - - generator.m_configuration = GetPatternFillConfiguration(); - - return generator; - } - - PatternFillConfiguration GetPatternFillConfiguration() const - { - PatternFillConfiguration configuration; - - configuration.m_minimumTileRepetitions = GetAttribute(Styling::Attribute::MinimumRepetitions, 1); - configuration.m_evenRowOffsetPercent = GetAttribute(Styling::Attribute::EvenOffsetPercent, 0.0f); - configuration.m_oddRowOffsetPercent = GetAttribute(Styling::Attribute::OddOffsetPercent, 0.0f); - - return configuration; - } - - void PopulatePaletteConfiguration(PaletteIconConfiguration& configuration) const - { - AZStd::string stylePalette; - StyledEntityRequestBus::EventResult(stylePalette, m_styledEntity, &StyledEntityRequests::GetFullStyleElement); - - if (!stylePalette.empty()) - { - configuration.SetColorPalette(stylePalette); - } - } - private: - void UpdateStyle() - { - ReleaseStyle(false); - StyleManagerRequestBus::EventResult(m_style, m_editorId, &StyleManagerRequests::ResolveStyles, m_styledEntity); - } - - void ReleaseStyle(bool destroyChildElement = true) - { - if (m_style.IsValid()) - { - if (m_deleteStyledEntity && destroyChildElement) - { - m_deleteStyledEntity = false; - AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_styledEntity); - } - AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_style); - - m_style.SetInvalid(); - } - } - - void RegisterStyleSheetBus(const EditorId& editorId) - { - StyleManagerNotificationBus::Handler::BusDisconnect(); - StyleManagerNotificationBus::Handler::BusConnect(editorId); - } + void UpdateStyle(); + void ReleaseStyle(bool destroyChildElement = true); + void RegisterStyleSheetBus(const EditorId& editorId); EditorId m_editorId; AZ::EntityId m_scene; diff --git a/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake b/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake index 58a28484f7..bedc6329d5 100644 --- a/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake +++ b/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake @@ -91,6 +91,7 @@ set(FILES StaticLib/GraphCanvas/Styling/Style.cpp StaticLib/GraphCanvas/Styling/Style.h StaticLib/GraphCanvas/Styling/StyleHelper.h + StaticLib/GraphCanvas/Styling/StyleHelper.cpp StaticLib/GraphCanvas/Styling/StyleManager.cpp StaticLib/GraphCanvas/Styling/StyleManager.h StaticLib/GraphCanvas/Types/ComponentSaveDataInterface.h diff --git a/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp b/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp index 940a2626f5..259efef392 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp @@ -226,7 +226,6 @@ namespace ScriptCanvasEditor auto dataTypeIter = m_containerDataTypeSets.find(workingCrc); if (dataTypeIter == m_containerDataTypeSets.end()) { - // No idea wtf do here we've managed to put ourselves into an invalid state AZ_Error("ScriptCanvas", false, "Unknown partial type found in Container Creation. Aborting."); close(); break; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui index 15998bd83b..b5965c9746 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui @@ -184,8 +184,5 @@
- - -
From 1cb26a31f8d51087ae586b356e6a3de72e6e1487 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 12 Oct 2021 15:53:38 -0700 Subject: [PATCH 211/293] LYN-7195 + LYN-7185 + LYN-5301 | Hide viewport helpers for entities out of focus + selection shortcut adjustments (#4615) * Light refactoring of selection logic. Only draw helpers for selectable entities according to Editor Focus Mode and Container Entity systems. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * When Escape is pressed, clear the Prefab Focus. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Alter Ctrl+A and Ctrl+Shift+I to take editor focus mode and container entity behaviors into account. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Remove redundant comments and reduce footprint of tests. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce loop protection, as GetParentId is known to loop in some situations possibly causing timeouts. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../ContainerEntityInterface.h | 3 ++ .../ContainerEntitySystemComponent.cpp | 45 +++++++++++++++++++ .../ContainerEntitySystemComponent.h | 1 + .../Entity/EditorEntityHelpers.cpp | 33 ++++++++++++-- .../UI/Prefab/PrefabIntegrationManager.cpp | 7 +++ .../UI/Prefab/PrefabIntegrationManager.h | 12 +++-- .../ViewportSelection/EditorHelpers.cpp | 27 +++++++++-- .../ViewportSelection/EditorHelpers.h | 12 +++++ 8 files changed, 129 insertions(+), 11 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h index 95940e6dd6..2d7d9dc511 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h @@ -65,6 +65,9 @@ namespace AzToolsFramework //! @return An error message if any container was registered for the context, success otherwise. virtual ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) = 0; + //! Returns true if one of the ancestors of entityId is a closed container entity. + virtual bool IsUnderClosedContainerEntity(AZ::EntityId entityId) const = 0; + }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp index c5649c56df..61b257a189 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp @@ -102,8 +102,17 @@ namespace AzToolsFramework AZ::EntityId ContainerEntitySystemComponent::FindHighestSelectableEntity(AZ::EntityId entityId) const { + if (!entityId.IsValid()) + { + return entityId; + } + + // Return the highest closed container, or the entity if none is found. AZ::EntityId highestSelectableEntityId = entityId; + // Skip the queried entity, as we only want to check its ancestors. + AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId); + // Go up the hierarchy until you hit the root while (entityId.IsValid()) { @@ -152,4 +161,40 @@ namespace AzToolsFramework return AZ::Success(); } + bool ContainerEntitySystemComponent::IsUnderClosedContainerEntity(AZ::EntityId entityId) const + { + if (!entityId.IsValid()) + { + return false; + } + + // Skip the queried entity, as we only want to check its ancestors. + AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId); + + // Go up the hierarchy until you hit the root. + while (entityId.IsValid()) + { + if (!IsContainerOpen(entityId)) + { + // One of the ancestors is a container and it's closed. + return true; + } + + AZ::EntityId parentId; + AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId); + + if (parentId == entityId) + { + // In some circumstances, querying a root level entity with GetParentId will return + // the entity itself instead of an invalid entityId. + break; + } + + entityId = parentId; + } + + // All ancestors are either regular entities or open containers. + return false; + } + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h index 44261979ef..7a11e05096 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h @@ -48,6 +48,7 @@ namespace AzToolsFramework bool IsContainerOpen(AZ::EntityId entityId) const override; AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const override; ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) override; + bool IsUnderClosedContainerEntity(AZ::EntityId entityId) const override; // EditorEntityContextNotificationBus overrides ... void OnEntityStreamLoadSuccess() override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 7789070209..8d40162f52 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -16,9 +16,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -588,15 +590,40 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AzToolsFramework); + // Detect if the Entity is Visible bool visible = false; EditorEntityInfoRequestBus::EventResult( visible, entityId, &EditorEntityInfoRequestBus::Events::IsVisible); + if (!visible) + { + return false; + } + + // Detect if the Entity is Locked bool locked = false; - EditorEntityInfoRequestBus::EventResult( - locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked); + EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked); + + if (locked) + { + return false; + } + + // Detect if the Entity is part of the Editor Focus + if (auto focusModeInterface = AZ::Interface::Get(); + !focusModeInterface->IsInFocusSubTree(entityId)) + { + return false; + } - return visible && !locked; + // Detect if the Entity is a descendant of a closed container + if (auto containerEntityInterface = AZ::Interface::Get(); + containerEntityInterface->IsUnderClosedContainerEntity(entityId)) + { + return false; + } + + return true; } static void SetEntityLockStateRecursively( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index d4b227c4ff..9bd377e3e9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -137,6 +137,7 @@ namespace AzToolsFramework } EditorContextMenuBus::Handler::BusConnect(); + EditorEventsBus::Handler::BusConnect(); PrefabInstanceContainerNotificationBus::Handler::BusConnect(); AZ::Interface::Register(this); AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension); @@ -147,6 +148,7 @@ namespace AzToolsFramework AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); PrefabInstanceContainerNotificationBus::Handler::BusDisconnect(); + EditorEventsBus::Handler::BusDisconnect(); EditorContextMenuBus::Handler::BusDisconnect(); } @@ -313,6 +315,11 @@ namespace AzToolsFramework } } + void PrefabIntegrationManager::OnEscape() + { + s_prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); + } + void PrefabIntegrationManager::HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const { auto instantiatePrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(sourceFilePath, parentId, position); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 696c05991c..6788af31e9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -51,6 +51,7 @@ namespace AzToolsFramework class PrefabIntegrationManager final : public EditorContextMenuBus::Handler + , public EditorEventsBus::Handler , public AssetBrowser::AssetBrowserSourceDropBus::Handler , public PrefabInstanceContainerNotificationBus::Handler , public PrefabIntegrationInterface @@ -64,19 +65,22 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); - // EditorContextMenuBus... + // EditorContextMenuBus overrides ... int GetMenuPosition() const override; AZStd::string GetMenuIdentifier() const override; void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; - // EntityOutlinerSourceDropHandlingBus... + // EditorEventsBus overrides ... + void OnEscape(); + + // EntityOutlinerSourceDropHandlingBus overrides ... void HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const override; - // PrefabInstanceContainerNotificationBus... + // PrefabInstanceContainerNotificationBus overrides ... void OnPrefabComponentActivate(AZ::EntityId entityId) override; void OnPrefabComponentDeactivate(AZ::EntityId entityId) override; - // PrefabIntegrationInterface... + // PrefabIntegrationInterface overrides ... AZ::EntityId CreateNewEntityAtPosition(const AZ::Vector3& position, AZ::EntityId parentId) override; int ExecuteClosePrefabDialog(TemplateId templateId) override; void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index 3ce350287f..bb718d0dc9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -187,15 +187,14 @@ namespace AzToolsFramework } // Verify if the entity Id corresponds to an entity that is focused; if not, halt selection. - if (!m_focusModeInterface->IsInFocusSubTree(entityIdUnderCursor)) + if (!IsSelectableAccordingToFocusMode(entityIdUnderCursor)) { return AZ::EntityId(); } // Container Entity support - if the entity that is being selected is part of a closed container, // change the selection to the container instead. - ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get(); - if (containerEntityInterface) + if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get()) { return containerEntityInterface->FindHighestSelectableEntity(entityIdUnderCursor); } @@ -217,7 +216,7 @@ namespace AzToolsFramework { const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex); - if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex)) + if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex) || !IsSelectableInViewport(entityId)) { continue; } @@ -263,4 +262,24 @@ namespace AzToolsFramework } } } + + bool EditorHelpers::IsSelectableInViewport(AZ::EntityId entityId) + { + return IsSelectableAccordingToFocusMode(entityId) && IsSelectableAccordingToContainerEntities(entityId); + } + + bool EditorHelpers::IsSelectableAccordingToFocusMode(AZ::EntityId entityId) + { + return m_focusModeInterface->IsInFocusSubTree(entityId); + } + + bool EditorHelpers::IsSelectableAccordingToContainerEntities(AZ::EntityId entityId) + { + if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get()) + { + return !containerEntityInterface->IsUnderClosedContainerEntity(entityId); + } + + return true; + } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h index a6a78a4e61..909a231635 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h @@ -58,7 +58,19 @@ namespace AzToolsFramework AzFramework::DebugDisplayRequests& debugDisplay, const AZStd::function& showIconCheck); + //! Returns whether the entityId can be selected in the viewport according + //! to the current Editor Focus Mode and Container Entity setup. + bool IsSelectableInViewport(AZ::EntityId entityId); + private: + //! Returns whether the entityId can be selected in the viewport according + //! to the current Editor Focus Mode setup. + bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId); + + //! Returns whether the entityId can be selected in the viewport according + //! to the current Container Entityu setup. + bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId); + const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers. const FocusModeInterface* m_focusModeInterface = nullptr; }; From 8d97f75e427cd8f4fa63b6e7236c7fd1bea28a5f Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Tue, 12 Oct 2021 23:38:01 +0000 Subject: [PATCH 212/293] Fixes to allow cmake to find files inside the render doc linux tar Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake | 4 +++- Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake b/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake index f8f17392b3..4fc54b9733 100644 --- a/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake +++ b/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake @@ -10,6 +10,8 @@ ly_add_external_target( NAME renderdoc 3RDPARTY_ROOT_DIRECTORY "${LY_RENDERDOC_PATH}" VERSION - INCLUDE_DIRECTORIES . + INCLUDE_DIRECTORIES + . + include COMPILE_DEFINITIONS USE_RENDERDOC ) diff --git a/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake b/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake index a74d250901..6225cc292a 100644 --- a/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake +++ b/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake @@ -6,4 +6,4 @@ # # -set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/librenderdoc.so") +set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/lib/librenderdoc.so") From ccd60513f1776231ba3dc1ed1fd512b3d29e972d Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Tue, 12 Oct 2021 18:34:55 -0700 Subject: [PATCH 213/293] Fix prefab close dialog Editor crash on Linux (#4623) Signed-off-by: Steve Pham --- .../AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 9bd377e3e9..24cb71499e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -1400,7 +1400,7 @@ namespace AzToolsFramework AZStd::unique_ptr PrefabIntegrationManager::ConstructUnsavedPrefabsCard(TemplateId templateId) { - FlowLayout* unsavedPrefabsLayout = new FlowLayout(AzToolsFramework::GetActiveWindow()); + FlowLayout* unsavedPrefabsLayout = new FlowLayout(nullptr); AZStd::set dirtyTemplatePaths = s_prefabSystemComponentInterface->GetDirtyTemplatePaths(templateId); From 63da5847c105092ebe23d73aefbbfd4b4d1ea086 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 12 Oct 2021 20:15:29 -0700 Subject: [PATCH 214/293] chore: correct documentation and correct method return. - change return for IntersectSegmentTriangleCCW to bool - change return for IntersectSegmentTriangle to bool Signed-off-by: Michael Pollind --- .../AzCore/AzCore/Math/IntersectSegment.cpp | 24 +- .../AzCore/AzCore/Math/IntersectSegment.h | 238 +++++++++--------- 2 files changed, 130 insertions(+), 132 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp index 1bf1e41cb7..5d13acc34c 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp @@ -15,7 +15,7 @@ using namespace Intersect; // IntersectSegmentTriangleCCW // [10/21/2009] //========================================================================= -int Intersect::IntersectSegmentTriangleCCW( +bool Intersect::IntersectSegmentTriangleCCW( const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, /*float &u, float &v, float &w,*/ Vector3& normal, float& t) { @@ -34,7 +34,7 @@ int Intersect::IntersectSegmentTriangleCCW( float d = qp.Dot(normal); if (d <= 0.0f) { - return 0; + return false; } // Compute intersection t value of pq with plane of triangle. A ray @@ -46,7 +46,7 @@ int Intersect::IntersectSegmentTriangleCCW( // range segment check t[0,1] (it this case [0,d]) if (t < 0.0f || t > d) { - return 0; + return false; } // Compute barycentric coordinate components and test if within bounds @@ -54,12 +54,12 @@ int Intersect::IntersectSegmentTriangleCCW( v = ac.Dot(e); if (v < 0.0f || v > d) { - return 0; + return false; } w = -ab.Dot(e); if (w < 0.0f || v + w > d) { - return 0; + return false; } // Segment/ray intersects triangle. Perform delayed division and @@ -72,14 +72,14 @@ int Intersect::IntersectSegmentTriangleCCW( normal.Normalize(); - return 1; + return true; } //========================================================================= // IntersectSegmentTriangle // [10/21/2009] //========================================================================= -int +bool Intersect::IntersectSegmentTriangle( const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, /*float &u, float &v, float &w,*/ Vector3& normal, float& t) @@ -111,7 +111,7 @@ Intersect::IntersectSegmentTriangle( // so either have a parallel ray or our normal is flipped if (d >= -Constants::FloatEpsilon) { - return 0; // parallel + return false; // parallel } d = -d; e = ap.Cross(qp); @@ -125,19 +125,19 @@ Intersect::IntersectSegmentTriangle( // range segment check t[0,1] (it this case [0,d]) if (t < 0.0f || t > d) { - return 0; + return false; } // Compute barycentric coordinate components and test if within bounds v = ac.Dot(e); if (v < 0.0f || v > d) { - return 0; + return false; } w = -ab.Dot(e); if (w < 0.0f || v + w > d) { - return 0; + return false; } // Segment/ray intersects the triangle. Perform delayed division and @@ -150,7 +150,7 @@ Intersect::IntersectSegmentTriangle( normal.Normalize(); - return 1; + return true; } //========================================================================= diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h index 71c39fb53d..523069987f 100644 --- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h +++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.h @@ -17,46 +17,45 @@ namespace AZ namespace Intersect { //! LineToPointDistanceTime computes the time of the shortest distance from point 'p' to segment (s1,s2). - //! To calculate the point of intersection: - //! P = s1 + u (s2 - s1) - //! @param s1 segment start point - //! @param s2 segment end point - //! @param p point to find the closest time to. - //! @return time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] + //! To calculate the point of intersection: P = s1 + u (s2 - s1) + //! @param s1 Segment start point. + //! @param s2 Segment end point. + //! @param p Point to find the closest time to. + //! @return Time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] float LineToPointDistanceTime(const Vector3& s1, const Vector3& s21, const Vector3& p); //! LineToPointDistance computes the closest point to 'p' from a segment (s1,s2). - //! @param s1 segment start point - //! @param s2 segment end point - //! @param p point to find the closest time to. - //! @param u time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] - //! @return the closest point + //! @param s1 Segment start point + //! @param s2 Segment end point + //! @param p Point to find the closest time to. + //! @param u Time (on the segment) for the shortest distance from 'p' to (s1,s2) [0.0f (s1),1.0f (s2)] + //! @return The closest point Vector3 LineToPointDistance(const Vector3& s1, const Vector3& s2, const Vector3& p, float& u); //! Given segment pq and triangle abc (CCW), returns whether segment intersects //! triangle and if so, also returns the barycentric coordinates (u,v,w) //! of the intersection point. - //! @param p segment start point - //! @param q segment end point - //! @param a triangle point 1 - //! @param b triangle point 2 - //! @param c triangle point 3 - //! @param normal at the intersection point. - //! @param t time of intersection along the segment [0.0 (p), 1.0 (q)] - //! @return true if the segments intersects the triangle otherwise false - int IntersectSegmentTriangleCCW( + //! @param p Segment start point. + //! @param q Segment end point. + //! @param a Triangle point 1. + //! @param b Triangle point 2. + //! @param c Triangle point 3. + //! @param normal At the intersection point. + //! @param t Time of intersection along the segment [0.0 (p), 1.0 (q)]. + //! @return true if the segments intersects the triangle otherwise false. + bool IntersectSegmentTriangleCCW( const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, Vector3& normal, float& t); //! Same as \ref IntersectSegmentTriangleCCW without respecting the triangle (a,b,c) vertex order (double sided). - //! @param p segment start point - //! @param q segment end point - //! @param a triangle point 1 - //! @param b triangle point 2 - //! @param c triangle point 3 - //! @param normal at the intersection point; - //! @param t time of intersection along the segment [0.0 (p), 1.0 (q)] - //! @return true if the segments intersects the triangle otherwise false - int IntersectSegmentTriangle( + //! @param p Segment start point. + //! @param q Segment end point. + //! @param a Triangle point 1. + //! @param b Triangle point 2. + //! @param c Triangle point 3. + //! @param normal At the intersection point. + //! @param t Time of intersection along the segment [0.0 (p), 1.0 (q)]. + //! @return True if the segments intersects the triangle otherwise false. + bool IntersectSegmentTriangle( const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c, Vector3& normal, float& t); //! Ray aabb intersection result types. @@ -69,14 +68,14 @@ namespace AZ //! Intersect ray R(t) = rayStart + t*d against AABB a. When intersecting, //! return intersection distance tmin and point q of intersection. - //! @param rayStart ray starting point - //! @param dir ray direction and length (dir = rayEnd - rayStart) + //! @param rayStart Ray starting point + //! @param dir Ray direction and length (dir = rayEnd - rayStart) //! @param dirRCP 1/dir (reciprocal direction - we cache this result very often so we don't need to compute it multiple times, //! otherwise just use dir.GetReciprocal()) //! @param aabb Axis aligned bounding box to intersect against - //! @param tStart time on ray of the first intersection [0,1] or 0 if the ray starts inside the aabb - check the return value - //! @param tEnd time of the of the second intersection [0,1] (it can be > 1 if intersects after the rayEnd) - //! @param startNormal normal at the start point. + //! @param tStart Time on ray of the first intersection [0,1] or 0 if the ray starts inside the aabb - check the return value + //! @param tEnd Time of the of the second intersection [0,1] (it can be > 1 if intersects after the rayEnd) + //! @param startNormal Normal at the start point. //! @return \ref RayAABBIsectTypes RayAABBIsectTypes IntersectRayAABB( const Vector3& rayStart, @@ -88,66 +87,66 @@ namespace AZ Vector3& startNormal); //! Intersect ray against AABB. - //! @param rayStart ray starting point. - //! @param dir ray reciprocal direction. + //! @param rayStart Ray starting point. + //! @param dir Ray reciprocal direction. //! @param aabb Axis aligned bounding box to intersect against. - //! @param start length on ray of the first intersection. - //! @param end length of the of the second intersection. + //! @param start Length on ray of the first intersection. + //! @param end Length of the of the second intersection. //! @return \ref RayAABBIsectTypes In this faster version than IntersectRayAABB we return only ISECT_RAY_AABB_NONE and //! ISECT_RAY_AABB_ISECT. You can check yourself for that case. RayAABBIsectTypes IntersectRayAABB2(const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, float& start, float& end); //! Clip a ray to an aabb. return true if ray was clipped. The ray //! can be inside so don't use the result if the ray intersect the box. - //! @param aabb bounds - //! @param rayStart the start of the ray - //! @param rayEnd the end of the ray - //! @param[out] tClipStart The proportion where the ray enterts the aabb - //! @param[out] tClipEnd The proportion where the ray exits the aabb - //! @return true ray was clipped else false + //! @param aabb Bounds to test against. + //! @param rayStart The start of the ray. + //! @param rayEnd The end of the ray. + //! @param[out] tClipStart The proportion where the ray enters the \ref Aabb. + //! @param[out] tClipEnd The proportion where the ray exits the \ref Aabb. + //! @return True if the ray was clipped, otherwise false. bool ClipRayWithAabb(const Aabb& aabb, Vector3& rayStart, Vector3& rayEnd, float& tClipStart, float& tClipEnd); //! Test segment and aabb where the segment is defined by midpoint //! midPoint = (p1-p0) * 0.5f and half vector halfVector = p1 - midPoint. //! the aabb is at the origin and defined by half extents only. - //! @param midPoint midpoint of a line segment - //! @param halfVector half vector of an aabb - //! @param aabbExtends the extends of a bounded box - //! @return true if the intersect, otherwise false. + //! @param midPoint Midpoint of a line segment. + //! @param halfVector Half vector of an aabb. + //! @param aabbExtends The extends of a bounded box. + //! @return True if the segment and AABB intersect, otherwise false bool TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends); - //! Test if segment specified by points p0 and p1 intersects AABB. \ref TestSegmentAABBOrigin - //! @param p0 point 1 - //! @param p1 point 2 - //! @param aabb bounded box - //! @return true if the segment and AABB intersect, otherwise false. + //! Test if segment specified by points p0 and p1 intersects AABB. \ref TestSegmentAABBOrigin. + //! @param p0 Segment start point. + //! @param p1 Segment end point. + //! @param aabb Bounded box to test against. + //! @return True if the segment and AABB intersect, otherwise false. bool TestSegmentAABB(const Vector3& p0, const Vector3& p1, const Aabb& aabb); //! Ray sphere intersection result types. enum SphereIsectTypes : AZ::s32 { - ISECT_RAY_SPHERE_SA_INSIDE = -1, //!< the ray starts inside the cylinder - ISECT_RAY_SPHERE_NONE, //!< no intersection - ISECT_RAY_SPHERE_ISECT, //!< along the PQ segment + ISECT_RAY_SPHERE_SA_INSIDE = -1, //!< The ray starts inside the cylinder + ISECT_RAY_SPHERE_NONE, //!< No intersection + ISECT_RAY_SPHERE_ISECT, //!< Along the PQ segment }; //! IntersectRaySphereOrigin //! return time t>=0 but not limited, so if you check a segment make sure - //! t <= segmentLen - //! @param rayStart ray start point + //! t <= segmentLen. + //! @param rayStart ray start point. //! @param rayDirNormalized ray direction normalized. - //! @param shereRadius sphere radius + //! @param shereRadius Radius of sphere at origin. //! @param time of closest intersection [0,+INF] in relation to the normalized direction. - //! @return \ref SphereIsectTypes + //! @return \ref SphereIsectTypes. SphereIsectTypes IntersectRaySphereOrigin( const Vector3& rayStart, const Vector3& rayDirNormalized, const float sphereRadius, float& t); //! Intersect ray (rayStart,rayDirNormalized) and sphere (sphereCenter,sphereRadius) \ref IntersectRaySphereOrigin - //! @param rayStart the start of the ray - //! @param rayDirNormalized the direction of the ray normalized - //! @param sphereCenter the center of the sphere - //! @param sphereRadius radius of the sphere - //! @param[out] t coefficient in the ray's explicit equation from which an + //! @param rayStart The start of the ray. + //! @param rayDirNormalized The direction of the ray normalized. + //! @param sphereCenter The center of the sphere. + //! @param sphereRadius Radius of the sphere. + //! @param[out] t Coefficient in the ray's explicit equation from which an //! intersecting point is calculated as "rayOrigin + t1 * rayDir". //! @return SphereIsectTypes SphereIsectTypes IntersectRaySphere( @@ -156,12 +155,12 @@ namespace AZ //! Intersect ray (rayStarty, rayDirNormalized) and disk (center, radius, normal) //! @param rayOrigin The origin of the ray to test. //! @param rayDir The direction of the ray to test. It has to be unit length. - //! @param diskCenter Center point of the disk - //! @param diskRadius Radius of the disk - //! @param diskNormal A normal perpendicular to the disk + //! @param diskCenter Center point of the disk. + //! @param diskRadius Radius of the disk. + //! @param diskNormal A normal perpendicular to the disk. //! @param[out] t If returning 1 (indicating a hit), this contains distance from rayOrigin along the normalized rayDir //! that the hit occured at. - //! @return false if not interesecting and true if intersecting + //! @return False if not interesecting and true if intersecting bool IntersectRayDisk( const Vector3& rayOrigin, const Vector3& rayDir, @@ -215,7 +214,7 @@ namespace AZ //! @param planePos A point on the plane to test intersection with. //! @param planeNormal The normal of the plane to test intersection with. //! @param[out] t The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". - //! @return The number of intersection point. + //! @return The number of intersection point. int IntersectRayPlane( const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& planePos, const Vector3& planeNormal, float& t); @@ -230,7 +229,7 @@ namespace AZ //! @param vertexD One of the four points that define the quadrilateral. //! @param[out] t The coefficient in the ray's explicit equation from which the //! intersecting point is calculated as "rayOrigin + t * rayDirection". - //! @return The number of intersection point. + //! @return The number of intersection point. int IntersectRayQuad( const Vector3& rayOrigin, const Vector3& rayDir, @@ -269,7 +268,7 @@ namespace AZ //! @param rayDir The direction of the ray to test intersection with. //! @param obb The OBB to test for intersection with the ray. //! @param[out] t The coefficient in the ray's explicit equation from which the intersecting point is calculated as "rayOrigin + t * rayDirection". - //! @return true if there is an intersection, false otherwise. + //! @return True if there is an intersection, false otherwise. bool IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t); //! Ray cylinder intersection types. @@ -284,13 +283,12 @@ namespace AZ //! Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder //! Intersect segment S(t)=sa+t(dir), 0<=t<=1 against cylinder specified by p, q and r. - //! - //! @param sa point - //! @param dir magnitude along sa - //! @param p center point of side 1 cylinder - //! @param q center point of side 2 cylinder - //! @param r radius of cylinder - //! @param[out] t proporition along line segment + //! @param sa The initial point. + //! @param dir Magnitude and direction for sa. + //! @param p Center point of side 1 cylinder. + //! @param q Center point of side 2 cylinder. + //! @param r Radius of cylinder. + //! @param[out] t Proporition along line segment. //! @return CylinderIsectTypes CylinderIsectTypes IntersectSegmentCylinder( const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); @@ -298,22 +296,22 @@ namespace AZ //! Capsule ray intersect types. enum CapsuleIsectTypes { - ISECT_RAY_CAPSULE_SA_INSIDE = -1, //!< the ray starts inside the cylinder - ISECT_RAY_CAPSULE_NONE, //!< no intersection - ISECT_RAY_CAPSULE_PQ, //!< along the PQ segment - ISECT_RAY_CAPSULE_P_SIDE, //!< on the P side - ISECT_RAY_CAPSULE_Q_SIDE, //!< on the Q side + ISECT_RAY_CAPSULE_SA_INSIDE = -1, //!< The ray starts inside the cylinder + ISECT_RAY_CAPSULE_NONE, //!< No intersection + ISECT_RAY_CAPSULE_PQ, //!< Along the PQ segment + ISECT_RAY_CAPSULE_P_SIDE, //!< On the P side + ISECT_RAY_CAPSULE_Q_SIDE, //!< On the Q side }; //! This is a quick implementation of segment capsule based on segment cylinder \ref IntersectSegmentCylinder //! segment sphere intersection. We can optimize it a lot once we fix the ray //! cylinder intersection. - //! @param sa the beginning of the line segment - //! @param dir the direction and length of the segment - //! @param p center point of side 1 capsule - //! @param q center point of side 1 capsule - //! @param r the radius of the capsule - //! @param[out] t proporition along line segment + //! @param sa The beginning of the line segment. + //! @param dir The direction and length of the segment. + //! @param p Center point of side 1 capsule. + //! @param q Center point of side 1 capsule. + //! @param r The radius of the capsule. + //! @param[out] t Proporition along line segment. //! @return CapsuleIsectTypes CapsuleIsectTypes IntersectSegmentCapsule( const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t); @@ -321,15 +319,15 @@ namespace AZ //! Intersect segment S(t)=A+t(B-A), 0<=t<=1 against convex polyhedron specified //! by the n halfspaces defined by the planes p[]. On exit tfirst and tlast //! define the intersection, if any. - //! @param sa the beggining of the line segment - //! @param dir the direction and length of the segment - //! @param p planes that compose a convex ponvex polyhedron - //! @param numPlanes number of planes - //! @param[out] tfirst proportion along the line segment where the line enters - //! @param[out] tlast proportion along the line segment where the line exits - //! @param[out] iFirstPlane the plane where the line enters - //! @param[out] iLastPlane the plane where the line exits - //! @return true if intersects else false + //! @param sa The beggining of the line segment. + //! @param dir The direction and length of the segment. + //! @param p Planes that compose a convex ponvex polyhedron. + //! @param numPlanes number of planes. + //! @param[out] tfirst Proportion along the line segment where the line enters. + //! @param[out] tlast Proportion along the line segment where the line exits. + //! @param[out] iFirstPlane The plane where the line enters. + //! @param[out] iLastPlane The plane where the line exits. + //! @return True if intersects else false. bool IntersectSegmentPolyhedron( const Vector3& sa, const Vector3& dir, @@ -345,15 +343,15 @@ namespace AZ //! segment2Proportion where closestPointSegment1 = segment1Start + (segment1Proportion * (segment1End - segment1Start)) //! closestPointSegment2 = segment2Start + (segment2Proportion * (segment2End - segment2Start)) //! If segments are parallel returns a solution. - //! @param segment1Start start of segment 1. - //! @param segment1End end of segment 1. - //! @param segment2Start start of segment 2. - //! @param segment2End end of segment 2. - //! @param[out] segment1Proportion the proporition along segment 1 [0..1] - //! @param[out] segment2Proportion the proporition along segment 2 [0..1] - //! @param[out] closestPointSegment1 closest point on segment 1. - //! @param[out] closestPointSegment2 closest point on segment 2. - //! @param epsilon the minimum square distance where a line segment can be treated as a single point. + //! @param segment1Start Start of segment 1. + //! @param segment1End End of segment 1. + //! @param segment2Start Start of segment 2. + //! @param segment2End End of segment 2. + //! @param[out] segment1Proportion The proporition along segment 1 [0..1] + //! @param[out] segment2Proportion The proporition along segment 2 [0..1] + //! @param[out] closestPointSegment1 Closest point on segment 1. + //! @param[out] closestPointSegment2 Closest point on segment 2. + //! @param epsilon The minimum square distance where a line segment can be treated as a single point. void ClosestSegmentSegment( const Vector3& segment1Start, const Vector3& segment1End, @@ -368,13 +366,13 @@ namespace AZ //! Calculate the line segment closestPointSegment1<->closestPointSegment2 that is the shortest route between //! two segments segment1Start<->segment1End and segment2Start<->segment2End. //! If segments are parallel returns a solution. - //! @param segment1Start start of segment 1. - //! @param segment1End end of segment 1. - //! @param segment2Start start of segment 2. - //! @param segment2End end of segment 2. - //! @param[out] closestPointSegment1 closest point on segment 1. - //! @param[out] closestPointSegment2 closest point on segment 2. - //! @param epsilon the minimum square distance where a line segment can be treated as a single point. + //! @param segment1Start Start of segment 1. + //! @param segment1End End of segment 1. + //! @param segment2Start Start of segment 2. + //! @param segment2End End of segment 2. + //! @param[out] closestPointSegment1 Closest point on segment 1. + //! @param[out] closestPointSegment2 Closest point on segment 2. + //! @param epsilon The minimum square distance where a line segment can be treated as a single point. void ClosestSegmentSegment( const Vector3& segment1Start, const Vector3& segment1End, @@ -387,11 +385,11 @@ namespace AZ //! Calculate the point (closestPointOnSegment) that is the closest point on //! segment segmentStart/segmentEnd to point. Also calculate the value of proportion where //! closestPointOnSegment = segmentStart + (proportion * (segmentEnd - segmentStart)) - //! @param point the point to test - //! @param segmentStart the start of the segment - //! @param segmentEnd the end of the segment - //! @param[out] proportion the proportion of the segment L(t) = (end - start) * t - //! @param[out] closestPointOnSegment the point along the line segment + //! @param point The point to test + //! @param segmentStart The start of the segment + //! @param segmentEnd The end of the segment + //! @param[out] proportion The proportion of the segment L(t) = (end - start) * t + //! @param[out] closestPointOnSegment The point along the line segment void ClosestPointSegment( const Vector3& point, const Vector3& segmentStart, From 2b79abb8c450fefa2932b4676d4b9fccf37156a1 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:13:19 +0200 Subject: [PATCH 215/293] =?UTF-8?q?EMotion=20FX:=20A=20parameter=E2=80=99s?= =?UTF-8?q?=20text=20box=20of=20Blend=20Space=202D=20and=201D=20Motions=20?= =?UTF-8?q?only=20takes=20one=20numerical=20input=20value=20including=20fr?= =?UTF-8?q?actions=20(#4626)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The on value changed event was recevied too often - with every newly typed character. As we're updating elements outside of the value spinbox, we need to wait for the actual done editing signal. This can be achieved by not tracking the keyboard for the spinbox. Signed-off-by: Benjamin Jillich --- .../Editor/PropertyWidgets/BlendSpaceMotionContainerHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/BlendSpaceMotionContainerHandler.cpp b/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/BlendSpaceMotionContainerHandler.cpp index b534603be6..8cee46133e 100644 --- a/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/BlendSpaceMotionContainerHandler.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/BlendSpaceMotionContainerHandler.cpp @@ -55,6 +55,7 @@ namespace EMotionFX m_spinboxX->setDecimals(4); m_spinboxX->setRange(-FLT_MAX, FLT_MAX); m_spinboxX->setProperty("motionId", motionId.c_str()); + m_spinboxX->setKeyboardTracking(false); layoutX->addWidget(m_spinboxX); layout->addLayout(layoutX, row, column); @@ -76,6 +77,7 @@ namespace EMotionFX m_spinboxY->setDecimals(4); m_spinboxY->setRange(-FLT_MAX, FLT_MAX); m_spinboxY->setProperty("motionId", motionId.c_str()); + m_spinboxX->setKeyboardTracking(false); layoutY->addWidget(m_spinboxY); layout->addLayout(layoutY, row, column); From da1fde8314e58641bcb21ca76987c29a754fc610 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:57:15 +0200 Subject: [PATCH 216/293] ImGui histogram container improvements (#4630) * Added auto scale mode that uses a running average to expand and shrink the visible vertical range. * Added option to set the move direction and either push new values to the front of the buffer (left) and make the histogram move to the right or the inverse. * Changed the camera monitor to use auto scaling as well as the current one was not showing anything because of an outlier. * Pre-fill the histogram with zeros so that the first pushed sample moves in without horizontal scaling effects which made it hard to read out any information from the histogram. Signed-off-by: Benjamin Jillich --- .../Include/LYImGuiUtils/HistogramContainer.h | 40 +++++++-- .../LYCommonMenu/ImGuiLYCameraMonitor.cpp | 20 ++--- .../LYImGuiUtils/HistogramContainer.cpp | 90 ++++++++++++++++--- 3 files changed, 120 insertions(+), 30 deletions(-) diff --git a/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h b/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h index 101b123bb5..6129c3ec08 100644 --- a/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h +++ b/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h @@ -18,8 +18,7 @@ namespace ImGui namespace LYImGuiUtils { /** - * A small class to help manage values for an ImGui Histogram ( ImGui doesn't want to manage the values itself ). - * Nothing crazy, just helps reduce boiler plate if you are ImGui::PlotHistogram()'ing + * A small class to help manage values for an ImGui Histogram (ImGui is not managing values itself). */ class HistogramContainer { @@ -40,9 +39,24 @@ namespace ImGui // Static Type to String function static const char* ViewTypeToString(ViewType viewType); + //! Horizontal move direction of the histogram when pushing new values. + enum MoveDirection : AZ::u8 + { + PushLeftMoveRight = 0, //! Push new values to the front of the buffer, which corresponds to the left side, and make the histogram move to the right. + PushRightMoveLeft = 1, //! Push new values to the back of the buffer, which corresponds to the right side, and make the histogram move to the left. + }; + + //! Mode determining the min and max values for the visible range of the vertical axis for the histogram. + enum ScaleMode : AZ::u8 + { + NoAutoScale = 0, //! Use the min and max values given by Init() as visible range. + AutoExpand = 1, //! Expand scale in case a sample is out of the current bounds. Does only expand the scale but not decrease it back again. + AutoScale = 2, //! Use a running average to expand and shrink the visible range. + }; + // Do all of the set up via Init - void Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale - , bool autoExpandScale, bool startCollapsed = false, bool drawMostRecentValue = true); + void Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale, + ScaleMode scaleMode = AutoScale, bool startCollapsed = false, bool drawMostRecentValue = true); // How many values are in the container currently int GetSize() { return static_cast(m_values.size()); } @@ -50,9 +64,6 @@ namespace ImGui // What is the max size of the container int GetMaxSize() { return m_maxSize; } - // Set the Max Size and clear the container - void SetMaxSize(int size) { m_values.clear(); m_maxSize = size; } - // Push a value to this histogram container void PushValue(float val); @@ -65,7 +76,18 @@ namespace ImGui // Draw this histogram with ImGui void Draw(float histogramWidth, float histogramHeight); + //! Adjust the scale mode to determine the min and max values for the visible range of the vertical axis for the histogram. + void SetScaleMode(ScaleMode scaleMode) { m_scaleMode = scaleMode; } + + //! Adjust the horizontal move direction of the histogram when pushing new values. + void SetMoveDirection(MoveDirection moveDirection) { m_moveDirection = moveDirection; } + + //! Calculate the min and maximum values for the present samples. + void CalcMinMaxValues(float& outMin, float& outMax); + private: + // Set the Max Size and clear the container + void SetMaxSize(int size); AZStd::string m_histogramName; AZStd::deque m_values; @@ -73,8 +95,10 @@ namespace ImGui ViewType m_viewType = ViewType::Histogram; float m_minScale; float m_maxScale; + MoveDirection m_moveDirection = PushLeftMoveRight; //! Specify if values will be added on the left and the histogram moves right or the other way around. bool m_dispalyOverlays; - bool m_autoExpandScale; + ScaleMode m_scaleMode; //! Determines if the vertical range of the histogram will be manually specified, auto-expanded or automatically scaled based on the samples. + float m_autoScaleSpeed = 0.05f; //! Indicates how fast the min max values and the visible vertical range are adapting to new samples. bool m_collapsed; bool m_drawMostRecentValueText; }; diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp index 1df74903e6..e079a01de1 100644 --- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp +++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp @@ -34,13 +34,13 @@ namespace ImGui ImGuiCameraMonitorRequestBus::Handler::BusConnect(); // Init Histogram Containers - m_dofMinZHisto.Init( "DOF Min Z", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); - m_dofMinZBlendMultHisto.Init( "DOF Min Z Blend Mult", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f, true); - m_dofMinZScaleHisto.Init( "DOF Min Z Scale", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f, true); + m_dofMinZHisto.Init( "DOF Min Z", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); + m_dofMinZBlendMultHisto.Init( "DOF Min Z Blend Mult", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f); + m_dofMinZScaleHisto.Init( "DOF Min Z Scale", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f); - m_globalActiveCamInfo.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f, true); - m_globalActiveCamInfo.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); - m_globalActiveCamInfo.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); + m_globalActiveCamInfo.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f); + m_globalActiveCamInfo.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); + m_globalActiveCamInfo.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); } void ImGuiLYCameraMonitor::Shutdown() @@ -214,7 +214,7 @@ namespace ImGui } // save this cam off as the current one m_currentCamera = newCamId; - + // create a new empty CameraInfo in the queue m_cameraHistory.push_front(CameraInfo()); @@ -224,9 +224,9 @@ namespace ImGui AZ::ComponentApplicationBus::BroadcastResult(newCam.m_camName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_currentCamera); newCam.m_activeTime = 0.0f; newCam.m_activeFrames = 0; - newCam.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f, true); - newCam.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); - newCam.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); + newCam.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f); + newCam.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); + newCam.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); // reset a few variables on the global camera info m_globalActiveCamInfo.m_camId = newCam.m_camId; diff --git a/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp b/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp index e3fd3f2054..1915cc3721 100644 --- a/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp +++ b/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp @@ -16,45 +16,92 @@ namespace ImGui { namespace LYImGuiUtils { - void HistogramContainer::Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale - , bool autoExpandScale, bool startCollapsed/* = false*/, bool drawMostRecentValue/* = true*/) + void HistogramContainer::Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale, + ScaleMode scaleMode, bool startCollapsed/* = false*/, bool drawMostRecentValue/* = true*/) { m_histogramName = histogramName; m_minScale = minScale; m_maxScale = maxScale; m_viewType = viewType; m_dispalyOverlays = displayOverlays; - m_autoExpandScale = autoExpandScale; + m_scaleMode = scaleMode; m_collapsed = startCollapsed; m_drawMostRecentValueText = drawMostRecentValue; SetMaxSize(maxValueCountSize); } - void HistogramContainer::PushValue(float val) + void HistogramContainer::SetMaxSize(int size) + { + m_values.resize(size); + m_maxSize = size; + + // Pre-fill the histogram with zeros so that the bars do not fill the space and + // scale horizontally when there are not enough samples yet. + for (float& value : m_values) + { + value = 0.0f; + } + } + + void HistogramContainer::PushValue(float value) { if (m_maxSize == 0) { return; } + if (m_values.size() == m_maxSize) { - m_values.pop_back(); + if (m_moveDirection == PushLeftMoveRight) + { + m_values.pop_back(); + } + else + { + m_values.pop_front(); + } } else if (m_values.size() > m_maxSize) { m_values.erase(m_values.begin() + (m_maxSize - 1), m_values.end()); } - m_values.push_front(val); - if (m_autoExpandScale) + if (m_moveDirection == PushLeftMoveRight) + { + m_values.push_front(value); + } + else + { + m_values.push_back(value); + } + + switch (m_scaleMode) { - if (val < m_minScale) + case AutoExpand: + { + if (value < m_minScale) + { + m_minScale = value; + } + else if (value > m_maxScale) + { + m_maxScale = value; + } + break; + } + case AutoScale: { - m_minScale = val; + float min = 0.0f; + float max = 0.0f; + CalcMinMaxValues(min, max); + + m_minScale = AZ::Lerp(m_minScale, min, m_autoScaleSpeed); + m_maxScale = AZ::Lerp(m_maxScale, max, m_autoScaleSpeed); + break; } - else if (val > m_maxScale) + default: { - m_maxScale = val; + break; } } } @@ -86,7 +133,6 @@ namespace ImGui ImGui::DragInt("History Size", &m_maxSize, 1, 1, 1000, "%f"); ImGui::DragFloat("Max Scale", &m_maxScale, 0.0001f, -100.0f, 100.0f); ImGui::DragFloat("Min Scale", &m_minScale, 0.0001f, -100.0f, 100.0f); - ImGui::Checkbox("Auto Expand Scale", &m_autoExpandScale); ImGui::EndPopup(); } @@ -157,6 +203,26 @@ namespace ImGui return "Lines"; } } + + void HistogramContainer::CalcMinMaxValues(float& outMin, float& outMax) + { + // Use the manually set min and max scale values in case there are no samples. + if (m_values.empty()) + { + outMin = m_minScale; + outMax = m_maxScale; + return; + } + + outMin = +AZ::Constants::FloatMax; + outMax = -AZ::Constants::FloatMax; + + for (const float x : m_values) + { + outMin = AZ::GetMin(outMin, x); + outMax = AZ::GetMax(outMax, x); + } + } } } #endif // #ifdef IMGUI_ENABLED From 48a74ca93d7df475a5ffbcfba45ad0fd95fa2604 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Wed, 13 Oct 2021 10:18:21 +0100 Subject: [PATCH 217/293] Remove clearFocus from EditorTransformComponentSelection duplicate Entity (#4571) * remove clearFocus from EditorTransformComponentSelection duplicate entity Signed-off-by: hultonha * remove extra unneeded calls to RequestWrite Signed-off-by: hultonha * update PrefabPublicHandler to use SetSelectedEntities Signed-off-by: hultonha --- .../Prefab/PrefabPublicHandler.cpp | 7 ++-- .../UI/PropertyEditor/PropertyIntCtrlCommon.h | 5 +-- .../UI/PropertyEditor/PropertyIntSpinCtrl.hxx | 5 --- .../EditorTransformComponentSelection.cpp | 41 ++++++++----------- 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 038f36eac9..b5f61b33bf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -257,9 +257,10 @@ namespace AzToolsFramework // Select Container Entity { - auto selectionUndo = aznew SelectionCommand({ containerEntityId }, "Select Prefab Container Entity"); + const EntityIdList selectedEntities = EntityIdList{ containerEntityId }; + auto selectionUndo = aznew SelectionCommand(selectedEntities, "Select Prefab Container Entity"); selectionUndo->SetParent(undoBatch.GetUndoBatch()); - ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, selectedEntities); } } @@ -1097,7 +1098,7 @@ namespace AzToolsFramework // Select the duplicated entities/instances auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances"); selectionUndo->SetParent(undoBatch.GetUndoBatch()); - ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds); } return AZ::Success(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h index eda8b482a1..01675e0044 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntCtrlCommon.h @@ -38,7 +38,7 @@ namespace AzToolsFramework static bool UnsignedToolTip(QWidget* widget, QString& toolTipString); }; - //! Base class for integer widget handlers to provide functionality independant + //! Base class for integer widget handlers to provide functionality independent //! of widget type. //! @tparam ValueType The integer primitive type of the handler. //! @tparam PropertyControl The widget type of the handler. @@ -167,8 +167,7 @@ namespace AzToolsFramework PropertyControl* newCtrl = aznew PropertyControl(pParent); this->connect(newCtrl, &PropertyControl::valueChanged, this, [newCtrl]() { - EBUS_EVENT(PropertyEditorGUIMessages::Bus, RequestWrite, newCtrl); - AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&PropertyEditorGUIMessages::Bus::Handler::RequestWrite, newCtrl); + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&PropertyEditorGUIMessages::Bus::Events::RequestWrite, newCtrl); }); // note: Qt automatically disconnects objects from each other when either end is destroyed, no need to worry about delete. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntSpinCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntSpinCtrl.hxx index 1e1e6a9592..fef4639a9f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntSpinCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyIntSpinCtrl.hxx @@ -98,11 +98,6 @@ namespace AzToolsFramework QWidget* IntSpinBoxHandler::CreateGUI(QWidget* parent) { PropertyIntSpinCtrl* newCtrl = static_cast(BaseHandler::CreateGUI(parent)); - this->connect(newCtrl, &PropertyIntSpinCtrl::valueChanged, [newCtrl]() - { - AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&PropertyEditorGUIMessages::Bus::Handler::RequestWrite, newCtrl); - }); - return newCtrl; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 7015a25ce1..6ee5c97636 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -1113,7 +1113,7 @@ namespace AzToolsFramework }); m_boxSelect.InstallLeftMouseUp( - [this, entityBoxSelectData]() + [this, entityBoxSelectData] { entityBoxSelectData->m_boxSelectSelectionCommand->UpdateSelection(EntityIdVectorFromContainer(m_selectedEntityIds)); @@ -2171,7 +2171,7 @@ namespace AzToolsFramework // lock selection AddAction( m_actions, { QKeySequence(Qt::Key_L) }, LockSelection, LockSelectionTitle, LockSelectionDesc, - [lockUnlock]() + [lockUnlock] { lockUnlock(true); }); @@ -2179,7 +2179,7 @@ namespace AzToolsFramework // unlock selection AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::Key_L) }, UnlockSelection, LockSelectionTitle, LockSelectionDesc, - [lockUnlock]() + [lockUnlock] { lockUnlock(false); }); @@ -2209,7 +2209,7 @@ namespace AzToolsFramework // hide selection AddAction( m_actions, { QKeySequence(Qt::Key_H) }, HideSelection, HideSelectionTitle, HideSelectionDesc, - [showHide]() + [showHide] { showHide(false); }); @@ -2217,7 +2217,7 @@ namespace AzToolsFramework // show selection AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::Key_H) }, ShowSelection, HideSelectionTitle, HideSelectionDesc, - [showHide]() + [showHide] { showHide(true); }); @@ -2225,7 +2225,7 @@ namespace AzToolsFramework // unlock all entities in the level/scene AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_L) }, UnlockAll, UnlockAllTitle, UnlockAllDesc, - []() + [] { AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -2242,14 +2242,14 @@ namespace AzToolsFramework // show all entities in the level/scene AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_H) }, ShowAll, ShowAllTitle, ShowAllDesc, - []() + [] { AZ_PROFILE_FUNCTION(AzToolsFramework); ScopedUndoBatch undoBatch(ShowAllEntitiesUndoRedoDesc); EnumerateEditorEntities( - [](AZ::EntityId entityId) + [](const AZ::EntityId entityId) { ScopedUndoBatch::MarkEntityDirty(entityId); SetEntityVisibility(entityId, true); @@ -2259,7 +2259,7 @@ namespace AzToolsFramework // select all entities in the level/scene AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::Key_A) }, SelectAll, SelectAllTitle, SelectAllDesc, - [this]() + [this] { AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -2299,7 +2299,7 @@ namespace AzToolsFramework // invert current selection AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I) }, InvertSelect, InvertSelectionTitle, InvertSelectionDesc, - [this]() + [this] { AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -2346,17 +2346,10 @@ namespace AzToolsFramework // duplicate selection AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::Key_D) }, DuplicateSelect, DuplicateTitle, DuplicateDesc, - []() + [] { AZ_PROFILE_FUNCTION(AzToolsFramework); - // Clear Widget selection - Prevents issues caused by cloning entities while a property in the Reflected Property Editor - // is being edited. - if (QApplication::focusWidget()) - { - QApplication::focusWidget()->clearFocus(); - } - ScopedUndoBatch undoBatch(DuplicateUndoRedoDesc); auto selectionCommand = AZStd::make_unique(EntityIdList(), DuplicateUndoRedoDesc); selectionCommand->SetParent(undoBatch.GetUndoBatch()); @@ -2371,7 +2364,7 @@ namespace AzToolsFramework // delete selection AddAction( m_actions, { QKeySequence(Qt::Key_Delete) }, DeleteSelect, DeleteTitle, DeleteDesc, - [this]() + [this] { AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -2388,21 +2381,21 @@ namespace AzToolsFramework AddAction( m_actions, { QKeySequence(Qt::Key_Space) }, EditEscaspe, "", "", - [this]() + [this] { DeselectEntities(); }); AddAction( m_actions, { QKeySequence(Qt::Key_P) }, EditPivot, TogglePivotTitleEditMenu, TogglePivotDesc, - [this]() + [this] { ToggleCenterPivotSelection(); }); AddAction( m_actions, { QKeySequence(Qt::Key_R) }, EditReset, ResetEntityTransformTitle, ResetEntityTransformDesc, - [this]() + [this] { switch (m_mode) { @@ -2427,7 +2420,7 @@ namespace AzToolsFramework AddAction( m_actions, { QKeySequence(Qt::Key_U) }, ViewportUiVisible, "Toggle Viewport UI", "Hide/Show Viewport UI", - [this]() + [this] { SetAllViewportUiVisible(!m_viewportUiVisible); }); @@ -3236,7 +3229,7 @@ namespace AzToolsFramework QAction* action = menu->addAction(QObject::tr(TogglePivotTitleRightClick)); QObject::connect( action, &QAction::triggered, action, - [this]() + [this] { ToggleCenterPivotSelection(); }); From 5bf7330f3505d4ac7837766317fa8ed7ab44ad96 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:50:11 +0100 Subject: [PATCH 218/293] made some physX tests less flaky (#4632) Joints_BallLeadFollowerCollide - changed the idle_wait to a wait_for_condition of the lead and follower colliding with a 10 second timeout. It was a 2 second timeout which is on the edge of the time from start to collision (~1.5sec). Joints_HingeNoLimitsConstrained - now measures the angle the joint is at and waits for the follower to raise up and over the lead, or fail after a 10sec timeout. This use to 'catch' the follower joint in a force region and check the position of the follower to determine pass/fail. Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- .../joints/Joints_BallLeadFollowerCollide.py | 14 +---- .../joints/Joints_HingeNoLimitsConstrained.py | 59 +++++++++++++++---- .../Joints_HingeNoLimitsConstrained.ly | 4 +- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_BallLeadFollowerCollide.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_BallLeadFollowerCollide.py index 0e8d7ea255..1209cb6caf 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_BallLeadFollowerCollide.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_BallLeadFollowerCollide.py @@ -52,9 +52,6 @@ def Joints_BallLeadFollowerCollide(): from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper - import azlmbr.legacy.general as general - import azlmbr.bus - from JointsHelper import JointEntityCollisionAware # Helper Entity class - self.collided flag is set when instance receives collision event. @@ -75,17 +72,12 @@ def Joints_BallLeadFollowerCollide(): lead = Entity("lead") follower = Entity("follower") - # 4) Wait for several seconds - general.idle_wait(2.0) # wait for lead and follower to move - - # 5) Check to see if lead and follower behaved as expected - Report.critical_result(Tests.check_collision_happened, lead.collided and follower.collided) + # 4) Wait for collision between lead and follower or timeout + Report.critical_result(Tests.check_collision_happened, helper.wait_for_condition(lambda: lead.collided and follower.collided, 10.0)) - # 6) Exit Game Mode + # 5) Exit Game Mode helper.exit_game_mode(Tests.exit_game_mode) - - if __name__ == "__main__": from editor_python_test_tools.utils import Report Report.start_test(Joints_BallLeadFollowerCollide) diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_HingeNoLimitsConstrained.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_HingeNoLimitsConstrained.py index 0870a807fc..0b3f88b4f6 100644 --- a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_HingeNoLimitsConstrained.py +++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_HingeNoLimitsConstrained.py @@ -52,11 +52,13 @@ def Joints_HingeNoLimitsConstrained(): """ import os import sys + import math from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper import azlmbr.legacy.general as general import azlmbr.bus + import azlmbr.math as azmath import JointsHelper from JointsHelper import JointEntity @@ -84,28 +86,65 @@ def Joints_HingeNoLimitsConstrained(): Report.info_vector3(lead.position, "lead initial position:") Report.info_vector3(follower.position, "follower initial position:") leadInitialPosition = lead.position - followerInitialPosition = follower.position - # 4) Wait for several seconds - general.idle_wait(4.0) # wait for lead and follower to move + # 4) Wait for the follower to move above and over the lead or Timeout + normalizedStartPos = JointsHelper.getRelativeVector(lead.position, follower.position) + normalizedStartPos = normalizedStartPos.GetNormalizedSafe() + + class WaitCondition: + ANGLE_CHECKPOINT_1 = math.radians(90) + ANGLE_CHECKPOINT_2 = math.radians(200) + + angleAchieved = 0.0 + followerMovedAbove90Deg = False #this is expected to be true to pass the test + followerMovedAbove200Deg = False #this is expected to be true to pass the test + + jointNormal = azmath.Vector3(0.0, -1.0, 0.0) # the joint rotates around the y axis + def checkConditionMet(self): + #calculate the current follower-lead vector + normalVec = JointsHelper.getRelativeVector(lead.position, follower.position) + normalVec = normalVec.GetNormalizedSafe() + + #triple product and get the angle + tripleProduct = normalizedStartPos.dot(normalVec.cross(self.jointNormal)) + currentAngle = math.acos(normalizedStartPos.Dot(normalVec)) + if tripleProduct < 0: + currentAngle = (2*math.pi) - currentAngle + + #if the angle is now less then last time, it is no longer rising, so end the test. + if currentAngle < self.angleAchieved: + return True + + #once we're passed the final check point, end the test + if currentAngle > self.ANGLE_CHECKPOINT_2: + self.followerMovedAbove200Deg = True + return True + + self.angleAchieved = currentAngle + self.followerMovedAbove90Deg = currentAngle > self.ANGLE_CHECKPOINT_1 + return False + + def isFollowerPositionCorrect(self): + return self.followerMovedAbove90Deg and self.followerMovedAbove200Deg + + waitCondition = WaitCondition() + + MAX_WAIT_TIME = 10.0 #seconds + conditionMet = helper.wait_for_condition(lambda: waitCondition.checkConditionMet(), MAX_WAIT_TIME) # 5) Check to see if lead and follower behaved as expected - Report.info_vector3(lead.position, "lead position after 1 second:") - Report.info_vector3(follower.position, "follower position after 1 second:") + Report.info_vector3(lead.position, "lead position after test run:") + Report.info_vector3(follower.position, "follower position after test run:") leadPositionDelta = lead.position.Subtract(leadInitialPosition) leadRemainedStill = JointsHelper.vector3SmallerThanScalar(leadPositionDelta, FLOAT_EPSILON) Report.critical_result(Tests.check_lead_position, leadRemainedStill) - followerSwingedOverLead = (follower.position.x < leadInitialPosition.x and - follower.position.z > leadInitialPosition.z) - Report.critical_result(Tests.check_follower_position, followerSwingedOverLead) + Report.critical_result(Tests.check_follower_position, conditionMet and waitCondition.isFollowerPositionCorrect()) # 6) Exit Game Mode helper.exit_game_mode(Tests.exit_game_mode) - - if __name__ == "__main__": from editor_python_test_tools.utils import Report Report.start_test(Joints_HingeNoLimitsConstrained) diff --git a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly index 86dd941423..9babf84ba4 100644 --- a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly +++ b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:817bd8dd22e185136418b60fba5b3552993687515d3d5ae96791f2c3be907b92 -size 7233 +oid sha256:60276c07b45a734e4f71d695278167ea61e884f8b513906168c9642078ad5954 +size 6045 From 3af07e511764e7d617cfa9b13647405a6954e61f Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:37:47 -0400 Subject: [PATCH 219/293] Hair - creating parent class for raster pass as prep for ShortCut technique (#4560) Signed-off-by: Adi-Amazon --- .../Code/Passes/HairGeometryRasterPass.cpp | 301 ++++++++++++++++++ .../Code/Passes/HairGeometryRasterPass.h | 112 +++++++ .../Code/Passes/HairPPLLRasterPass.cpp | 267 +--------------- .../Code/Passes/HairPPLLRasterPass.h | 70 +--- Gems/AtomTressFX/Hair_files.cmake | 6 + 5 files changed, 433 insertions(+), 323 deletions(-) create mode 100644 Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.cpp create mode 100644 Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.h diff --git a/Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.cpp b/Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.cpp new file mode 100644 index 0000000000..7af5903cf3 --- /dev/null +++ b/Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +//#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + namespace Hair + { + + // --- Creation & Initialization --- + RPI::Ptr HairGeometryRasterPass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew HairGeometryRasterPass(descriptor); + return pass; + } + + HairGeometryRasterPass::HairGeometryRasterPass(const RPI::PassDescriptor& descriptor) + : RasterPass(descriptor), + m_passDescriptor(descriptor) + { + // For inherited classes, override this method and set the proper path. + // Example: "Shaders/hairrenderingfillppll.azshader" + SetShaderPath("dummyShaderPath"); + } + + bool HairGeometryRasterPass::AcquireFeatureProcessor() + { + if (m_featureProcessor) + { + return true; + } + + RPI::Scene* scene = GetScene(); + if (scene) + { + m_featureProcessor = scene->GetFeatureProcessor(); + } + else + { + return false; + } + + if (!m_featureProcessor) + { + AZ_Warning("Hair Gem", false, + "HairGeometryRasterPass [%s] - Failed to retrieve Hair feature processor from the scene", + GetName().GetCStr()); + return false; + } + return true; + } + + void HairGeometryRasterPass::InitializeInternal() + { + if (GetScene()) + { + RasterPass::InitializeInternal(); + } + } + + bool HairGeometryRasterPass::IsEnabled() const + { + return (RPI::RasterPass::IsEnabled() && m_initialized) ? true : false; + } + + bool HairGeometryRasterPass::LoadShaderAndPipelineState() + { + RPI::ShaderReloadNotificationBus::Handler::BusDisconnect(); + + const RPI::RasterPassData* passData = RPI::PassUtils::GetPassData(m_passDescriptor); + + // If we successfully retrieved our custom data, use it to set the DrawListTag + if (!passData) + { + AZ_Error("Hair Gem", false, "Missing pass raster data"); + return false; + } + + // Load Shader + const char* shaderFilePath = m_shaderPath.c_str(); + Data::Asset shaderAsset = + RPI::AssetUtils::LoadAssetByProductPath(shaderFilePath, RPI::AssetUtils::TraceLevel::Error); + + if (!shaderAsset.GetId().IsValid()) + { + AZ_Error("Hair Gem", false, "Invalid shader asset for shader '%s'!", shaderFilePath); + return false; + } + + m_shader = RPI::Shader::FindOrCreate(shaderAsset); + if (m_shader == nullptr) + { + AZ_Error("Hair Gem", false, "Pass failed to load shader '%s'!", shaderFilePath); + return false; + } + + // Per Pass Srg + { + // Using 'PerPass' naming since currently RasterPass assumes that the pass Srg is always named 'PassSrg' + // [To Do] - RasterPass should use srg slot index and not name - currently this will + // result in a crash in one of the Atom existing MSAA passes that requires further dive. + // m_shaderResourceGroup = UtilityClass::CreateShaderResourceGroup(m_shader, "HairPerPassSrg", "Hair Gem"); + m_shaderResourceGroup = UtilityClass::CreateShaderResourceGroup(m_shader, "PassSrg", "Hair Gem"); + if (!m_shaderResourceGroup) + { + AZ_Error("Hair Gem", false, "Failed to create the per pass srg"); + return false; + } + } + + const RPI::ShaderVariant& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor; + shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); + + RPI::Scene* scene = GetScene(); + if (!scene) + { + AZ_Error("Hair Gem", false, "Scene could not be acquired" ); + return false; + } + RHI::DrawListTag drawListTag = m_shader->GetDrawListTag(); + scene->ConfigurePipelineState(drawListTag, pipelineStateDescriptor); + + pipelineStateDescriptor.m_renderAttachmentConfiguration = GetRenderAttachmentConfiguration(); + pipelineStateDescriptor.m_inputStreamLayout.SetTopology(AZ::RHI::PrimitiveTopology::TriangleList); + pipelineStateDescriptor.m_inputStreamLayout.Finalize(); + + m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); + if (!m_pipelineState) + { + AZ_Error("Hair Gem", false, "Pipeline state could not be acquired"); + return false; + } + + RPI::ShaderReloadNotificationBus::Handler::BusConnect(shaderAsset.GetId()); + + m_initialized = true; + return true; + } + + void HairGeometryRasterPass::SchedulePacketBuild(HairRenderObject* hairObject) + { + m_newRenderObjects.insert(hairObject); + } + + bool HairGeometryRasterPass::BuildDrawPacket(HairRenderObject* hairObject) + { + if (!m_initialized) + { + return false; + } + + RHI::DrawPacketBuilder::DrawRequest drawRequest; + drawRequest.m_listTag = m_drawListTag; + drawRequest.m_pipelineState = m_pipelineState; +// drawRequest.m_streamBufferViews = // no explicit vertex buffer. shader is using the srg buffers + drawRequest.m_stencilRef = 0; + drawRequest.m_sortKey = 0; + + // Seems that the PerView and PerScene are gathered through RenderPass::CollectSrgs() + // The PerPass is gathered through the RasterPass::m_shaderResourceGroup + AZStd::lock_guard lock(m_mutex); + + return hairObject->BuildPPLLDrawPacket(drawRequest); + } + + bool HairGeometryRasterPass::AddDrawPackets(AZStd::list>& hairRenderObjects) + { + bool overallSuccess = true; + + if (!m_currentView && + (!(m_currentView = GetView()) || !m_currentView->HasDrawListTag(m_drawListTag))) + { + m_currentView = nullptr; // set it to nullptr to prevent further attempts this frame + AZ_Warning("Hair Gem", false, "AddDrawPackets: failed to acquire or match the DrawListTag - check that your pass and shader tag name match"); + return false; + } + + for (auto& renderObject : hairRenderObjects) + { + const RHI::DrawPacket* drawPacket = renderObject->GetFillDrawPacket(); + if (!drawPacket) + { // might not be an error - the object might have just been added and the DrawPacket is + // scheduled to be built when the render frame begins + AZ_Warning("Hair Gem", !m_newRenderObjects.empty(), "HairGeometryRasterPass - DrawPacket wasn't built"); + overallSuccess = false; + continue; + } + + m_currentView->AddDrawPacket(drawPacket); + } + return overallSuccess; + } + + void HairGeometryRasterPass::FrameBeginInternal(FramePrepareParams params) + { + { + AZStd::lock_guard lock(m_mutex); + if (!m_initialized && AcquireFeatureProcessor()) + { + LoadShaderAndPipelineState(); + m_featureProcessor->ForceRebuildRenderData(); + } + } + + if (!m_initialized) + { + return; + } + + // Bind the Per Object resources and trigger the RHI validation that will use attachment + // for its validation. The attachments are invalidated outside the render begin/end frame. + for (HairRenderObject* newObject : m_newRenderObjects) + { + newObject->BindPerObjectSrgForRaster(); + BuildDrawPacket(newObject); + } + + // Clear the new added objects - BuildDrawPacket should only be carried out once per + // object/shader lifetime + m_newRenderObjects.clear(); + + // Refresh current view every frame + if (!(m_currentView = GetView()) || !m_currentView->HasDrawListTag(m_drawListTag)) + { + m_currentView = nullptr; // set it to null if view exists but no tag match + AZ_Warning("Hair Gem", false, "FrameBeginInternal: failed to acquire or match the DrawListTag - check that your pass and shader tag name match"); + return; + } + + RPI::RasterPass::FrameBeginInternal(params); + } + + void HairGeometryRasterPass::CompileResources(const RHI::FrameGraphCompileContext& context) + { + AZ_PROFILE_FUNCTION(AzRender); + + if (!m_featureProcessor) + { + return; + } + + // Compilation of remaining srgs will be done by the parent class + RPI::RasterPass::CompileResources(context); + } + + void HairGeometryRasterPass::BuildShaderAndRenderData() + { + AZStd::lock_guard lock(m_mutex); + m_initialized = false; // make sure we initialize it even if not in this frame + if (AcquireFeatureProcessor()) + { + LoadShaderAndPipelineState(); + m_featureProcessor->ForceRebuildRenderData(); + } + } + + void HairGeometryRasterPass::OnShaderReinitialized([[maybe_unused]] const RPI::Shader & shader) + { + BuildShaderAndRenderData(); + } + + void HairGeometryRasterPass::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset& shaderAsset) + { + BuildShaderAndRenderData(); + } + + void HairGeometryRasterPass::OnShaderVariantReinitialized([[maybe_unused]] const AZ::RPI::ShaderVariant& shaderVariant) + { + BuildShaderAndRenderData(); + } + } // namespace Hair + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.h b/Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.h new file mode 100644 index 0000000000..a226d2c294 --- /dev/null +++ b/Gems/AtomTressFX/Code/Passes/HairGeometryRasterPass.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +#include + +#include +#include +#include +#include + +namespace AZ +{ + namespace RHI + { + struct DrawItem; + } + + namespace Render + { + namespace Hair + { + class HairRenderObject; + class HairFeatureProcessor; + + //! A HairGeometryRasterPass is used for the render of the hair geometries. This is the base + //! class that can be inherited - for example by the HiarPPLLRasterPass and have only the specific + //! class data handling added on top. + class HairGeometryRasterPass + : public RPI::RasterPass + , private RPI::ShaderReloadNotificationBus::Handler + { + AZ_RPI_PASS(HairGeometryRasterPass); + + public: + AZ_RTTI(HairGeometryRasterPass, "{0F07360A-A286-4060-8C62-137AFFA50561}", RasterPass); + AZ_CLASS_ALLOCATOR(HairGeometryRasterPass, SystemAllocator, 0); + + //! Creates a HairGeometryRasterPass + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + bool AddDrawPackets(AZStd::list>& hairObjects); + + //! The following will be called when an object was added or shader has been compiled + void SchedulePacketBuild(HairRenderObject* hairObject); + + Data::Instance GetShader() { return m_shader; } + + void SetFeatureProcessor(HairFeatureProcessor* featureProcessor) + { + m_featureProcessor = featureProcessor; + } + + virtual bool IsEnabled() const override; + + protected: + explicit HairGeometryRasterPass(const RPI::PassDescriptor& descriptor); + + // ShaderReloadNotificationBus::Handler overrides... + void OnShaderReinitialized(const RPI::Shader& shader) override; + void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; + void OnShaderVariantReinitialized(const AZ::RPI::ShaderVariant& shaderVariant) override; + + void SetShaderPath(const char* shaderPath) { m_shaderPath = shaderPath; } + bool LoadShaderAndPipelineState(); + bool AcquireFeatureProcessor(); + void BuildShaderAndRenderData(); + bool BuildDrawPacket(HairRenderObject* hairObject); + + // Pass behavior overrides + void InitializeInternal() override; +// void BuildInternal() override; + void FrameBeginInternal(FramePrepareParams params) override; + + // Scope producer functions... + void CompileResources(const RHI::FrameGraphCompileContext& context) override; + + protected: + HairFeatureProcessor* m_featureProcessor = nullptr; + + // The shader that will be used by the pass + Data::Instance m_shader = nullptr; + + // Override the following in the inherited class + AZStd::string m_shaderPath = "dummyShaderPath"; + + // To help create the pipeline state + RPI::PassDescriptor m_passDescriptor; + + const RHI::PipelineState* m_pipelineState = nullptr; + RPI::ViewPtr m_currentView = nullptr; + + AZStd::mutex m_mutex; + + //! List of new render objects introduced this frame so that their in order to identify + //! that their PerObject (dynamic) Srg needs binding to the resources. + //! Done once per every new object introduced / requires update. + AZStd::unordered_set m_newRenderObjects; + + bool m_initialized = false; + }; + + } // namespace Hair + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.cpp b/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.cpp index 746a3c2640..a677a929a2 100644 --- a/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.cpp +++ b/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.cpp @@ -34,61 +34,25 @@ namespace AZ namespace Hair { - // --- Creation & Initialization --- - RPI::Ptr HairPPLLRasterPass::Create(const RPI::PassDescriptor& descriptor) - { - RPI::Ptr pass = aznew HairPPLLRasterPass(descriptor); - return pass; - } - HairPPLLRasterPass::HairPPLLRasterPass(const RPI::PassDescriptor& descriptor) - : RasterPass(descriptor), - m_passDescriptor(descriptor) + : HairGeometryRasterPass(descriptor) { + SetShaderPath("Shaders/hairrenderingfillppll.azshader"); } - HairPPLLRasterPass::~HairPPLLRasterPass() - { - } - - bool HairPPLLRasterPass::AcquireFeatureProcessor() - { - if (m_featureProcessor) - { - return true; - } - - RPI::Scene* scene = GetScene(); - if (scene) - { - m_featureProcessor = scene->GetFeatureProcessor(); - } - else - { - return false; - } - - if (!m_featureProcessor) - { - AZ_Warning("Hair Gem", false, - "HairPPLLRasterPass [%s] - Failed to retrieve Hair feature processor from the scene", - GetName().GetCStr()); - return false; - } - return true; - } - - void HairPPLLRasterPass::InitializeInternal() + RPI::Ptr HairPPLLRasterPass::Create(const RPI::PassDescriptor& descriptor) { - if (GetScene()) - { - RasterPass::InitializeInternal(); - } + RPI::Ptr pass = aznew HairPPLLRasterPass(descriptor); + return pass; } + //! This method is used for attaching the PPLL data buffer which is a transient buffer. + //! It is done this ways because Atom doesn't support transient structured buffers declaration + //! via Pass yet. + //! Once supported, this will be done via data driven code and the method can be removed. void HairPPLLRasterPass::BuildInternal() { - RasterPass::BuildInternal(); + RasterPass::BuildInternal(); // change this to call parent if the method exists if (!AcquireFeatureProcessor()) { @@ -104,217 +68,6 @@ namespace AZ AttachBufferToSlot(Name{ "PerPixelLinkedList" }, m_featureProcessor->GetPerPixelListBuffer()); } - bool HairPPLLRasterPass::IsEnabled() const - { - return (RPI::RasterPass::IsEnabled() && m_initialized) ? true : false; - } - - bool HairPPLLRasterPass::LoadShaderAndPipelineState() - { - RPI::ShaderReloadNotificationBus::Handler::BusDisconnect(); - - const RPI::RasterPassData* passData = RPI::PassUtils::GetPassData(m_passDescriptor); - - // If we successfully retrieved our custom data, use it to set the DrawListTag - if (!passData) - { - AZ_Error("Hair Gem", false, "Missing pass raster data"); - return false; - } - - // Load Shader - const char* shaderFilePath = "Shaders/hairrenderingfillppll.azshader"; - Data::Asset shaderAsset = - RPI::AssetUtils::LoadAssetByProductPath(shaderFilePath, RPI::AssetUtils::TraceLevel::Error); - - if (!shaderAsset.GetId().IsValid()) - { - AZ_Error("Hair Gem", false, "Invalid shader asset for shader '%s'!", shaderFilePath); - return false; - } - - m_shader = RPI::Shader::FindOrCreate(shaderAsset); - if (m_shader == nullptr) - { - AZ_Error("Hair Gem", false, "Pass failed to load shader '%s'!", shaderFilePath); - return false; - } - - // Per Pass Srg - { - // Using 'PerPass' naming since currently RasterPass assumes that the pass Srg is always named 'PassSrg' - // [To Do] - RasterPass should use srg slot index and not name - currently this will - // result in a crash in one of the Atom existing MSAA passes that requires further dive. - // m_shaderResourceGroup = UtilityClass::CreateShaderResourceGroup(m_shader, "HairPerPassSrg", "Hair Gem"); - m_shaderResourceGroup = UtilityClass::CreateShaderResourceGroup(m_shader, "PassSrg", "Hair Gem"); - if (!m_shaderResourceGroup) - { - AZ_Error("Hair Gem", false, "Failed to create the per pass srg"); - return false; - } - } - - const RPI::ShaderVariant& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); - RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor; - shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); - - RPI::Scene* scene = GetScene(); - if (!scene) - { - AZ_Error("Hair Gem", false, "Scene could not be acquired" ); - return false; - } - RHI::DrawListTag drawListTag = m_shader->GetDrawListTag(); - scene->ConfigurePipelineState(drawListTag, pipelineStateDescriptor); - - pipelineStateDescriptor.m_renderAttachmentConfiguration = GetRenderAttachmentConfiguration(); - pipelineStateDescriptor.m_inputStreamLayout.SetTopology(AZ::RHI::PrimitiveTopology::TriangleList); - pipelineStateDescriptor.m_inputStreamLayout.Finalize(); - - m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); - if (!m_pipelineState) - { - AZ_Error("Hair Gem", false, "Pipeline state could not be acquired"); - return false; - } - - RPI::ShaderReloadNotificationBus::Handler::BusConnect(shaderAsset.GetId()); - - m_initialized = true; - return true; - } - - void HairPPLLRasterPass::SchedulePacketBuild(HairRenderObject* hairObject) - { - m_newRenderObjects.insert(hairObject); - } - - bool HairPPLLRasterPass::BuildDrawPacket(HairRenderObject* hairObject) - { - if (!m_initialized) - { - return false; - } - - RHI::DrawPacketBuilder::DrawRequest drawRequest; - drawRequest.m_listTag = m_drawListTag; - drawRequest.m_pipelineState = m_pipelineState; -// drawRequest.m_streamBufferViews = // no explicit vertex buffer. shader is using the srg buffers - drawRequest.m_stencilRef = 0; - drawRequest.m_sortKey = 0; - - // Seems that the PerView and PerScene are gathered through RenderPass::CollectSrgs() - // The PerPass is gathered through the RasterPass::m_shaderResourceGroup - AZStd::lock_guard lock(m_mutex); - - return hairObject->BuildPPLLDrawPacket(drawRequest); - } - - bool HairPPLLRasterPass::AddDrawPackets(AZStd::list>& hairRenderObjects) - { - bool overallSuccess = true; - - if (!m_currentView && - (!(m_currentView = GetView()) || !m_currentView->HasDrawListTag(m_drawListTag))) - { - m_currentView = nullptr; // set it to nullptr to prevent further attempts this frame - AZ_Warning("Hair Gem", false, "HairPPLLRasterPass failed to acquire or match the DrawListTag - check that your pass and shader tag name match"); - return false; - } - - for (auto& renderObject : hairRenderObjects) - { - const RHI::DrawPacket* drawPacket = renderObject->GetFillDrawPacket(); - if (!drawPacket) - { // might not be an error - the object might have just been added and the DrawPacket is - // scheduled to be built when the render frame begins - AZ_Warning("Hair Gem", !m_newRenderObjects.empty(), "HairPPLLRasterPass - DrawPacket wasn't built"); - overallSuccess = false; - continue; - } - - m_currentView->AddDrawPacket(drawPacket); - } - return overallSuccess; - } - - void HairPPLLRasterPass::FrameBeginInternal(FramePrepareParams params) - { - { - AZStd::lock_guard lock(m_mutex); - if (!m_initialized && AcquireFeatureProcessor()) - { - LoadShaderAndPipelineState(); - m_featureProcessor->ForceRebuildRenderData(); - } - } - - if (!m_initialized) - { - return; - } - - // Bind the Per Object resources and trigger the RHI validation that will use attachment - // for its validation. The attachments are invalidated outside the render begin/end frame. - for (HairRenderObject* newObject : m_newRenderObjects) - { - newObject->BindPerObjectSrgForRaster(); - BuildDrawPacket(newObject); - } - - // Clear the new added objects - BuildDrawPacket should only be carried out once per - // object/shader lifetime - m_newRenderObjects.clear(); - - // Refresh current view every frame - if (!(m_currentView = GetView()) || !m_currentView->HasDrawListTag(m_drawListTag)) - { - m_currentView = nullptr; // set it to null if view exists but no tag match - AZ_Warning("Hair Gem", false, "HairPPLLRasterPass failed to acquire or match the DrawListTag - check that your pass and shader tag name match"); - return; - } - - RPI::RasterPass::FrameBeginInternal(params); - } - - void HairPPLLRasterPass::CompileResources(const RHI::FrameGraphCompileContext& context) - { - AZ_PROFILE_FUNCTION(AzRender); - - if (!m_featureProcessor) - { - return; - } - - // Compilation of remaining srgs will be done by the parent class - RPI::RasterPass::CompileResources(context); - } - - void HairPPLLRasterPass::BuildShaderAndRenderData() - { - AZStd::lock_guard lock(m_mutex); - m_initialized = false; // make sure we initialize it even if not in this frame - if (AcquireFeatureProcessor()) - { - LoadShaderAndPipelineState(); - m_featureProcessor->ForceRebuildRenderData(); - } - } - - void HairPPLLRasterPass::OnShaderReinitialized([[maybe_unused]] const RPI::Shader & shader) - { - BuildShaderAndRenderData(); - } - - void HairPPLLRasterPass::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset& shaderAsset) - { - BuildShaderAndRenderData(); - } - - void HairPPLLRasterPass::OnShaderVariantReinitialized([[maybe_unused]] const AZ::RPI::ShaderVariant& shaderVariant) - { - BuildShaderAndRenderData(); - } } // namespace Hair } // namespace Render } // namespace AZ diff --git a/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.h b/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.h index ef7167897f..bf90fe0521 100644 --- a/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.h +++ b/Gems/AtomTressFX/Code/Passes/HairPPLLRasterPass.h @@ -7,14 +7,7 @@ */ #pragma once -#include - -#include - -#include -#include -#include -#include +#include namespace AZ { @@ -27,11 +20,8 @@ namespace AZ { namespace Hair { - class HairRenderObject; - class HairFeatureProcessor; - //! A HairPPLLRasterPass is used for the hair fragments fill render after the data - //! went through the skinning and simulation passes. + //! went through the skinning and simulation passes. //! The output of this pass is the general list of fragment data that can now be //! traversed for depth resolve and lighting. //! The Fill pass uses the following Srgs: @@ -41,74 +31,22 @@ namespace AZ //! - HairDynamicDataSrg (PerObjectSrg) - shared buffers views for this hair object only. //! - PerViewSrg and PerSceneSrg - as per the data from Atom. class HairPPLLRasterPass - : public RPI::RasterPass - , private RPI::ShaderReloadNotificationBus::Handler + : public HairGeometryRasterPass { AZ_RPI_PASS(HairPPLLRasterPass); public: - AZ_RTTI(HairPPLLRasterPass, "{6614D7DD-24EE-4A2B-B314-7C035E2FB3C4}", RasterPass); + AZ_RTTI(HairPPLLRasterPass, "{6614D7DD-24EE-4A2B-B314-7C035E2FB3C4}", HairGeometryRasterPass); AZ_CLASS_ALLOCATOR(HairPPLLRasterPass, SystemAllocator, 0); - virtual ~HairPPLLRasterPass(); //! Creates a HairPPLLRasterPass static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); - bool AddDrawPackets(AZStd::list>& hairObjects); - - //! The following will be called when an object was added or shader has been compiled - void SchedulePacketBuild(HairRenderObject* hairObject); - - Data::Instance GetShader() { return m_shader; } - - void SetFeatureProcessor(HairFeatureProcessor* featureProcessor) - { - m_featureProcessor = featureProcessor; - } - - virtual bool IsEnabled() const override; protected: - // ShaderReloadNotificationBus::Handler overrides... - void OnShaderReinitialized(const RPI::Shader& shader) override; - void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const AZ::RPI::ShaderVariant& shaderVariant) override; - - private: explicit HairPPLLRasterPass(const RPI::PassDescriptor& descriptor); - bool LoadShaderAndPipelineState(); - bool AcquireFeatureProcessor(); - void BuildShaderAndRenderData(); - bool BuildDrawPacket(HairRenderObject* hairObject); - // Pass behavior overrides - void InitializeInternal() override; void BuildInternal() override; - void FrameBeginInternal(FramePrepareParams params) override; - - // Scope producer functions... - void CompileResources(const RHI::FrameGraphCompileContext& context) override; - - private: - HairFeatureProcessor* m_featureProcessor = nullptr; - - // The shader that will be used by the pass - Data::Instance m_shader = nullptr; - - // To help create the pipeline state - RPI::PassDescriptor m_passDescriptor; - - const RHI::PipelineState* m_pipelineState = nullptr; - RPI::ViewPtr m_currentView = nullptr; - - AZStd::mutex m_mutex; - - //! List of new render objects introduced this frame so that their - //! Per Object (dynamic) Srg should be bound to the resources. - //! Done once per every new object introduced / requires update. - AZStd::unordered_set m_newRenderObjects; - - bool m_initialized = false; }; } // namespace Hair diff --git a/Gems/AtomTressFX/Hair_files.cmake b/Gems/AtomTressFX/Hair_files.cmake index c726d931f7..000abeb559 100644 --- a/Gems/AtomTressFX/Hair_files.cmake +++ b/Gems/AtomTressFX/Hair_files.cmake @@ -61,10 +61,16 @@ set(FILES #) # #set(atom_hair_passes + # The simulation pass class shared by all simulation / skinning compute passes Code/Passes/HairSkinningComputePass.h Code/Passes/HairSkinningComputePass.cpp + # Base class of all geometry raster passes + Code/Passes/HairGeometryRasterPass.h + Code/Passes/HairGeometryRasterPass.cpp + # PPLL rendering technique - geometry raster pass Code/Passes/HairPPLLRasterPass.h Code/Passes/HairPPLLRasterPass.cpp + # PP full screen resolve pass Code/Passes/HairPPLLResolvePass.h Code/Passes/HairPPLLResolvePass.cpp #) From 97e9f4dc7d7ce343c4a64547d30dc91d274c0277 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:38:36 -0500 Subject: [PATCH 220/293] [LYN-6838] Various Monolithic shutdown fixes for the GameLauncher (#4564) * Added a stateless allocator which uses AZ_OS_MALLOC/AZ_OS_FREE to allocate memory for objects in static memory. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the Maestro and LyShine Anim Nodes to use the stateless_allocator for its static containers. This prevents crashes in static de-init due to the SystemAllocator being destroyed at that poitn Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the EBus AllocatorType to use the EBusEnvironmentAllocator Because the EBus Context resides in static memory, the SystemAllocator lifetime is shorter than the EBus Context. This results in shutdown crashes in monolithic builds due to all of the gem modules being linked in as static libraries and the EBus context now destructing at the point of the executable static de-init, instead of the module de-init, where the SystemAllocator would still be around. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed an assortment of shutdown issues due to deleting objects after AZ allocators are no longer available Fixed the NameDictionary IsReady() function to not assert when the dictionary when invoked after the environment variable it was stored in was destroyed. Updated the NameData destructor to check that the NameDictionary IsReady() before attempting to remove itself from the dictionary Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed NameDictionary destory workflow, to reset the EnvironmentVariable instance Updated the EnvironmentVariable instance to store the NameDictionary as a value. Added a rvalue reference `Set` function overload to the EnvironmentVariable class to support move only types. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Clang 6.0.0 build fixes The C++17 std::launder feature isn't available in that compiler version Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/EBus/EBus.h | 6 +- .../AzCore/AzCore/Memory/AllocatorManager.h | 4 +- .../AzCore/AzCore/Module/Environment.h | 45 ++++----- .../AzCore/AzCore/Name/Internal/NameData.cpp | 5 +- .../AzCore/AzCore/Name/NameDictionary.cpp | 24 ++--- .../AzCore/AzCore/Name/NameDictionary.h | 21 +++-- .../AzCore/AzCore/std/allocator_stateless.cpp | 94 +++++++++++++++++++ .../AzCore/AzCore/std/allocator_stateless.h | 61 ++++++++++++ .../AzCore/AzCore/std/azstd_files.cmake | 2 + .../AzCore/AzCore/std/createdestroy.h | 6 +- Code/Legacy/CryCommon/IMovieSystem.h | 5 +- Code/Legacy/CryCommon/StlUtils.h | 8 ++ .../DecalTextureArrayFeatureProcessor.cpp | 4 +- .../ProjectedShadowFeatureProcessor.cpp | 2 +- .../RHI/Vulkan/Code/Source/RHI/Instance.cpp | 19 +++- .../RHI/Vulkan/Code/Source/RHI/Instance.h | 1 + .../Code/Source/RHI/SystemComponent.cpp | 1 + .../Source/AudioSystemGemSystemComponent.cpp | 3 + Gems/ImGui/Code/Source/ImGuiManager.cpp | 7 +- Gems/LyShine/Code/Source/Animation/AnimNode.h | 3 +- .../Source/Animation/UiAnimationSystem.cpp | 29 ++++-- .../Code/Source/Cinematics/AnimPostFXNode.cpp | 3 +- Gems/Maestro/Code/Source/Cinematics/Movie.cpp | 33 +++++-- 23 files changed, 299 insertions(+), 87 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp create mode 100644 Code/Framework/AzCore/AzCore/std/allocator_stateless.h diff --git a/Code/Framework/AzCore/AzCore/EBus/EBus.h b/Code/Framework/AzCore/AzCore/EBus/EBus.h index a3dc10b103..67cffb4e41 100644 --- a/Code/Framework/AzCore/AzCore/EBus/EBus.h +++ b/Code/Framework/AzCore/AzCore/EBus/EBus.h @@ -77,9 +77,11 @@ namespace AZ public: /** * Allocator used by the EBus. - * The default setting is AZStd::allocator, which uses AZ::SystemAllocator. + * The default setting is Internal EBusEnvironmentAllocator + * EBus code stores their Context instances in static memory + * Therfore the configured allocator must last as long as the EBus in a module */ - using AllocatorType = AZStd::allocator; + using AllocatorType = AZ::Internal::EBusEnvironmentAllocator; /** * Defines how many handlers can connect to an address on the EBus diff --git a/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h b/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h index be0ab4a0a0..14dec68ad1 100644 --- a/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h +++ b/Code/Framework/AzCore/AzCore/Memory/AllocatorManager.h @@ -34,7 +34,9 @@ namespace AZ friend IAllocator; friend class AllocatorBase; friend class Debug::AllocationRecords; - friend class AZ::Internal::EnvironmentVariableHolder; + template friend constexpr auto AZStd::construct_at(T*, Args&&... args) + ->AZStd::enable_if_t()) T(AZStd::forward(args)...))>>, T*>; + template constexpr friend void AZStd::destroy_at(T*); public: typedef AZStd::function OutOfMemoryCBType; diff --git a/Code/Framework/AzCore/AzCore/Module/Environment.h b/Code/Framework/AzCore/AzCore/Module/Environment.h index e87ff81446..a2dcfbd8fa 100644 --- a/Code/Framework/AzCore/AzCore/Module/Environment.h +++ b/Code/Framework/AzCore/AzCore/Module/Environment.h @@ -251,16 +251,15 @@ namespace AZ class EnvironmentVariableHolder : public EnvironmentVariableHolderBase { - void ConstructImpl(const AZStd::true_type& /* AZStd::has_trivial_constructor */) - { - memset(&m_value, 0, sizeof(T)); - } - template - void ConstructImpl(const AZStd::false_type& /* AZStd::has_trivial_constructor */, Args&&... args) + void ConstructImpl(Args&&... args) { - // Construction of non-trivial types is left up to the type's constructor. - new(&m_value) T(AZStd::forward(args)...); + // Use std::launder to ensure that the compiler treats the T* reinterpret_cast as a new object + #if __cpp_lib_launder + AZStd::construct_at(std::launder(reinterpret_cast(&m_value)), AZStd::forward(args)...); + #else + AZStd::construct_at(reinterpret_cast(&m_value), AZStd::forward(args)...); + #endif } static void DestructDispatchNoLock(EnvironmentVariableHolderBase *base, DestroyTarget selfDestruct) { @@ -274,10 +273,12 @@ namespace AZ AZ_Assert(self->m_isConstructed, "Variable is not constructed. Please check your logic and guard if needed!"); self->m_isConstructed = false; self->m_moduleOwner = nullptr; - if constexpr(!AZStd::is_trivially_destructible_v) - { - reinterpret_cast(&self->m_value)->~T(); - } + // Use std::launder to ensure that the compiler treats the T* reinterpret_cast as a new object + #if __cpp_lib_launder + AZStd::destroy_at(std::launder(reinterpret_cast(&self->m_value))); + #else + AZStd::destroy_at(reinterpret_cast(&self->m_value)); + #endif } public: EnvironmentVariableHolder(u32 guid, bool isOwnershipTransfer, Environment::AllocatorInterface* allocator) @@ -303,24 +304,13 @@ namespace AZ UnregisterAndDestroy(DestructDispatchNoLock, moduleRelease); } - void Construct() - { - AZStd::lock_guard lock(m_mutex); - if (!m_isConstructed) - { - ConstructImpl(AZStd::is_trivially_constructible{}); - m_isConstructed = true; - m_moduleOwner = Environment::GetModuleId(); - } - } - template void Construct(Args&&... args) { AZStd::lock_guard lock(m_mutex); if (!m_isConstructed) { - ConstructImpl(typename AZStd::false_type(), AZStd::forward(args)...); + ConstructImpl(AZStd::forward(args)...); m_isConstructed = true; m_moduleOwner = Environment::GetModuleId(); } @@ -333,7 +323,7 @@ namespace AZ } // variable storage - typename AZStd::aligned_storage::value>::type m_value; + AZStd::aligned_storage_for_t m_value; static int s_moduleUseCount; }; @@ -468,6 +458,11 @@ namespace AZ Get() = value; } + void Set(T&& value) + { + Get() = AZStd::move(value); + } + explicit operator bool() const { return IsValid(); diff --git a/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp b/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp index 0086e68c6d..574b0bcc7e 100644 --- a/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp +++ b/Code/Framework/AzCore/AzCore/Name/Internal/NameData.cpp @@ -42,7 +42,10 @@ namespace AZ AZ_Assert(m_useCount > 0, "m_useCount is already 0!"); if (m_useCount.fetch_sub(1) == 1) { - AZ::NameDictionary::Instance().TryReleaseName(hash); + if (AZ::NameDictionary::IsReady()) + { + AZ::NameDictionary::Instance().TryReleaseName(hash); + } } } } diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index 8e8011add9..3047a2894e 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -21,23 +21,18 @@ namespace AZ namespace NameDictionaryInternal { - static AZ::EnvironmentVariable s_instance = nullptr; + static AZ::EnvironmentVariable s_instance = nullptr; } void NameDictionary::Create() { using namespace NameDictionaryInternal; - AZ_Assert(!s_instance || !s_instance.Get(), "NameDictionary already created!"); + AZ_Assert(!s_instance, "NameDictionary already created!"); if (!s_instance) { - s_instance = AZ::Environment::CreateVariable(NameDictionaryInstanceName); - } - - if (!s_instance.Get()) - { - s_instance.Set(aznew NameDictionary()); + s_instance = AZ::Environment::CreateVariable(NameDictionaryInstanceName); } } @@ -46,8 +41,7 @@ namespace AZ using namespace NameDictionaryInternal; AZ_Assert(s_instance, "NameDictionary not created!"); - delete (*s_instance); - *s_instance = nullptr; + s_instance.Reset(); } bool NameDictionary::IsReady() @@ -56,10 +50,10 @@ namespace AZ if (!s_instance) { - s_instance = Environment::FindVariable(NameDictionaryInstanceName); + s_instance = Environment::FindVariable(NameDictionaryInstanceName); } - return s_instance && *s_instance; + return s_instance.IsConstructed(); } NameDictionary& NameDictionary::Instance() @@ -68,12 +62,12 @@ namespace AZ if (!s_instance) { - s_instance = Environment::FindVariable(NameDictionaryInstanceName); + s_instance = Environment::FindVariable(NameDictionaryInstanceName); } - AZ_Assert(s_instance && *s_instance, "NameDictionary has not been initialized yet."); + AZ_Assert(s_instance.IsConstructed(), "NameDictionary has not been initialized yet."); - return *(*s_instance); + return *s_instance; } NameDictionary::NameDictionary() diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.h b/Code/Framework/AzCore/AzCore/Name/NameDictionary.h index fa13dbd682..8f9af4be3a 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.h +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.h @@ -16,7 +16,7 @@ #include #include -namespace MaterialEditor +namespace MaterialEditor { class MaterialEditorCoreComponent; } @@ -34,14 +34,14 @@ namespace AZ { class NameData; }; - + //! Maintains a list of unique strings for Name objects. //! The main benefit of the Name system is very fast string equality comparison, because every - //! unique name has a unique ID. The NameDictionary's purpose is to guarantee name IDs do not + //! unique name has a unique ID. The NameDictionary's purpose is to guarantee name IDs do not //! collide. It also saves memory by removing duplicate strings. //! - //! Benchmarks have shown that creating a new Name object can be quite slow when the name doesn't - //! already exist in the NameDictionary, but is comparable to creating an AZStd::string for names + //! Benchmarks have shown that creating a new Name object can be quite slow when the name doesn't + //! already exist in the NameDictionary, but is comparable to creating an AZStd::string for names //! that already exist. class NameDictionary final { @@ -51,7 +51,10 @@ namespace AZ friend Name; friend Internal::NameData; friend UnitTest::NameDictionaryTester; - + template friend constexpr auto AZStd::construct_at(T*, Args&&... args) + -> AZStd::enable_if_t()) T(AZStd::forward(args)...))>>, T*>; + template constexpr friend void AZStd::destroy_at(T*); + public: static void Create(); @@ -62,7 +65,7 @@ namespace AZ //! Makes a Name from the provided raw string. If an entry already exists in the dictionary, it is shared. //! Otherwise, it is added to the internal dictionary. - //! + //! //! @param name The name to resolve against the dictionary. //! @return A Name instance holding a dictionary entry associated with the provided raw string. Name MakeName(AZStd::string_view name); @@ -84,13 +87,13 @@ namespace AZ // Attempts to release the name from the dictionary, but checks to make sure // a reference wasn't taken by another thread. void TryReleaseName(Name::Hash hash); - + ////////////////////////////////////////////////////////////////////////// // Calculates a hash for the provided name string. // Does not attempt to resolve hash collisions; that is handled elsewhere. Name::Hash CalcHash(AZStd::string_view name); - + AZStd::unordered_map m_dictionary; mutable AZStd::shared_mutex m_sharedMutex; }; diff --git a/Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp b/Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp new file mode 100644 index 0000000000..5806cc485c --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/allocator_stateless.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace AZStd +{ + stateless_allocator::stateless_allocator(const char* name) + : m_name(name) {} + + const char* stateless_allocator::get_name() const + { + return m_name; + } + + void stateless_allocator::set_name(const char* name) + { + m_name = name; + } + + auto stateless_allocator::allocate(size_type byteSize) -> pointer_type + { + return allocate(byteSize, AZ_DEFAULT_ALIGNMENT, 0); + } + + auto stateless_allocator::allocate(size_type byteSize, size_type alignment, int) -> pointer_type + { + pointer_type address = AZ_OS_MALLOC(byteSize, alignment); + + if (address == nullptr) + { + AZ_Error("Memory", false, "stateless_allocator ran out of system memory!\n"); + } + + return address; + } + + void stateless_allocator::deallocate(pointer_type ptr, size_type) + { + AZ_OS_FREE(ptr); + } + + void stateless_allocator::deallocate(pointer_type ptr, size_type, size_type) + { + AZ_OS_FREE(ptr); + } + + auto stateless_allocator::max_size() const -> size_type + { + return AZ_CORE_MAX_ALLOCATOR_SIZE; + } + + stateless_allocator stateless_allocator::select_on_container_copy_construction() const + { + return *this; + } + + auto stateless_allocator::resize(pointer_type, size_type) -> size_type + { + return 0; + } + + bool stateless_allocator::is_lock_free() + { + return false; + } + + bool stateless_allocator::is_stale_read_allowed() + { + return false; + } + + bool stateless_allocator::is_delayed_recycling() + { + return false; + } + + // comparison operators + bool operator==(const stateless_allocator&, const stateless_allocator&) + { + return true; + } + + bool operator!=(const stateless_allocator&, const stateless_allocator&) + { + return false; + } +} diff --git a/Code/Framework/AzCore/AzCore/std/allocator_stateless.h b/Code/Framework/AzCore/AzCore/std/allocator_stateless.h new file mode 100644 index 0000000000..b73c680c32 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/allocator_stateless.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AZStd +{ + class stateless_allocator + { + public: + + AZ_TYPE_INFO(stateless_allocator, "{E4976C53-0B20-4F39-8D41-0A76F59A7D68}"); + + using value_type = uint8_t; + using pointer_type = void*; + using size_type = size_t; + using difference_type = ptrdiff_t; + using allow_memory_leaks = AZStd::true_type; + + stateless_allocator(const char* name = "AZStd::stateless_allocator"); + stateless_allocator(const stateless_allocator& rhs) = default; + + stateless_allocator& operator=(const stateless_allocator& rhs) = default; + + const char* get_name() const; + void set_name(const char* name); + + pointer_type allocate(size_type byteSize); + pointer_type allocate(size_type byteSize, size_type alignment, int flags = 0); + void deallocate(pointer_type ptr, size_type alignment); + void deallocate(pointer_type ptr, size_type byteSize, size_type alignment); + + // max_size actually returns the true maximum size of a single allocation + size_type max_size() const; + + // Returns a copy of the allocator + stateless_allocator select_on_container_copy_construction() const; + + //! extensions + size_type resize(pointer_type ptr, size_type newSize); + + bool is_lock_free(); + bool is_stale_read_allowed(); + bool is_delayed_recycling(); + + private: + const char* m_name; + }; + + bool operator==(const stateless_allocator& left, const stateless_allocator& right); + bool operator!=(const stateless_allocator& left, const stateless_allocator& right); +} diff --git a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake index 08e72c5649..2746489f8c 100644 --- a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake +++ b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake @@ -12,6 +12,8 @@ set(FILES allocator.h allocator_ref.h allocator_stack.h + allocator_stateless.cpp + allocator_stateless.h allocator_static.h allocator_traits.h any.h diff --git a/Code/Framework/AzCore/AzCore/std/createdestroy.h b/Code/Framework/AzCore/AzCore/std/createdestroy.h index 0fa6e4ed40..355374a13a 100644 --- a/Code/Framework/AzCore/AzCore/std/createdestroy.h +++ b/Code/Framework/AzCore/AzCore/std/createdestroy.h @@ -20,7 +20,7 @@ namespace AZStd { - // alias std::pointer_traits into the AZStd::namespace + // alias std::pointer_traits into the AZStd::namespace using std::pointer_traits; //! Bring the names of uninitialized_default_construct and @@ -229,7 +229,7 @@ namespace AZStd //! `new (declval()) T(declval()...)` is well-formed template constexpr auto construct_at(T* ptr, Args&&... args) - -> enable_if_t()) T(AZStd::forward(args)...))>>, T*> + -> enable_if_t()) T(AZStd::forward(args)...))>>, T*> { return ::new (ptr) T(AZStd::forward(args)...); } @@ -487,7 +487,7 @@ namespace AZStd { //! Implements the C++17 uninitialized_move function //! The functions accepts two input iterators and an output iterator - //! It performs an AZStd::move on each in in the range of the input iterator + //! It performs an AZStd::move on each in in the range of the input iterator //! and stores the result in location pointed by the output iterator template ForwardIt uninitialized_move(InputIt first, InputIt last, ForwardIt result) diff --git a/Code/Legacy/CryCommon/IMovieSystem.h b/Code/Legacy/CryCommon/IMovieSystem.h index 6cc5a06c8f..4da08d3bbf 100644 --- a/Code/Legacy/CryCommon/IMovieSystem.h +++ b/Code/Legacy/CryCommon/IMovieSystem.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -181,7 +182,7 @@ public: private: AnimParamType m_type; - AZStd::string m_name; + AZStd::basic_string, AZStd::stateless_allocator> m_name; }; namespace AZStd @@ -617,7 +618,7 @@ public: , valueType(_valueType) , flags(_flags) {}; - AZStd::string name; // parameter name. + AZStd::basic_string, AZStd::stateless_allocator> name; // parameter name. CAnimParamType paramType; // parameter id. AnimValueType valueType; // value type, defines type of track to use for animating this parameter. ESupportedParamFlags flags; // combination of flags from ESupportedParamFlags. diff --git a/Code/Legacy/CryCommon/StlUtils.h b/Code/Legacy/CryCommon/StlUtils.h index 4aafd4dd0e..f5128a564f 100644 --- a/Code/Legacy/CryCommon/StlUtils.h +++ b/Code/Legacy/CryCommon/StlUtils.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -491,6 +492,13 @@ namespace stl return type; } + //! Specialization of string to const char cast. + template <> + inline const char* constchar_cast(const AZStd::basic_string, AZStd::stateless_allocator>& type) + { + return type.c_str(); + } + //! Specialization of string to const char cast. template <> inline const char* constchar_cast(const AZStd::string& type) diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index 472dbff5c8..e9bc1a1277 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -357,7 +357,7 @@ namespace AZ // Texture2DArray m_decalTextureArrayNormalMaps0; // Texture2DArray m_decalTextureArrayNormalMaps1; // Texture2DArray m_decalTextureArrayNormalMaps2; - static const AZStd::array ShaderNames = { "m_decalTextureArrayDiffuse", + static constexpr AZStd::array ShaderNames = { "m_decalTextureArrayDiffuse", "m_decalTextureArrayNormalMaps" }; for (int mapType = 0; mapType < DecalMapType_Num; ++mapType) @@ -365,7 +365,7 @@ namespace AZ for (int texArrayIdx = 0; texArrayIdx < NumTextureArrays; ++texArrayIdx) { const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get(); - const AZStd::string baseName = ShaderNames[mapType] + AZStd::to_string(texArrayIdx); + const AZStd::string baseName = AZStd::string(ShaderNames[mapType]) + AZStd::to_string(texArrayIdx); m_decalTextureArrayIndices[texArrayIdx][mapType] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str())); AZ_Warning( diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index c0202c7c74..6452b312c8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -346,7 +346,7 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds) { - static const Name LightTypeName = Name("projected"); + const Name LightTypeName = Name("projected"); const auto* passSystem = RPI::PassSystemInterface::Get(); const AZStd::vector passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp index c2fe16b551..2dce5d85f3 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp @@ -16,12 +16,27 @@ namespace AZ { static const uint32_t s_minVulkanSupportedVersion = VK_API_VERSION_1_0; + static EnvironmentVariable s_vulkanInstance; + static constexpr const char* s_vulkanInstanceKey = "VulkanInstance"; + Instance& Instance::GetInstance() { - static Instance s_instance; - return s_instance; + if (!s_vulkanInstance) + { + s_vulkanInstance = Environment::FindVariable(s_vulkanInstanceKey); + if (!s_vulkanInstance) + { + s_vulkanInstance = Environment::CreateVariable(s_vulkanInstanceKey); + } + } + + return s_vulkanInstance.Get(); } + void Instance::Reset() + { + s_vulkanInstance.Reset(); + } Instance::~Instance() { diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h index 40a6951c2d..efa8d36d2b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.h @@ -34,6 +34,7 @@ namespace AZ }; static Instance& GetInstance(); + static void Reset(); ~Instance(); bool Init(const Descriptor& descriptor); void Shutdown(); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp index 36e0c2b2f5..0d401003d9 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SystemComponent.cpp @@ -101,6 +101,7 @@ namespace AZ RHI::FactoryManagerBus::Broadcast(&RHI::FactoryManagerRequest::UnregisterFactory, this); Instance::GetInstance().Shutdown(); + Instance::Reset(); } Name SystemComponent::GetName() diff --git a/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp b/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp index b1e7e3ac18..1af927a7e7 100644 --- a/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp +++ b/Gems/AudioSystem/Code/Source/AudioSystemGemSystemComponent.cpp @@ -90,6 +90,9 @@ namespace AudioSystemGem AudioSystemGemSystemComponent::~AudioSystemGemSystemComponent() { + // The audio system uses the Audio::AudioSystemAllocator + // so it needs to be deleted before the allocator is shutdown + m_audioSystem.reset(); Audio::Platform::ShutdownAudioAllocators(); } diff --git a/Gems/ImGui/Code/Source/ImGuiManager.cpp b/Gems/ImGui/Code/Source/ImGuiManager.cpp index 6fc1ea8b71..d631e2f83e 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.cpp +++ b/Gems/ImGui/Code/Source/ImGuiManager.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -31,11 +32,11 @@ using namespace AzFramework; using namespace ImGui; // Wheel Delta const value. -const constexpr uint32_t IMGUI_WHEEL_DELTA = 120; // From WinUser.h, for Linux +static const constexpr uint32_t IMGUI_WHEEL_DELTA = 120; // From WinUser.h, for Linux // Typedef and local static map to hold LyInput->ImGui Nav mappings ( filled up in Initialize() ) -typedef AZStd::pair LyButtonImGuiNavIndexPair; -typedef AZStd::unordered_map LyButtonImGuiNavIndexMap; +using LyButtonImGuiNavIndexPair = AZStd::pair; +using LyButtonImGuiNavIndexMap = AZStd::fixed_unordered_map; static LyButtonImGuiNavIndexMap s_lyInputToImGuiNavIndexMap; /** diff --git a/Gems/LyShine/Code/Source/Animation/AnimNode.h b/Gems/LyShine/Code/Source/Animation/AnimNode.h index 0076276204..4d139e99ca 100644 --- a/Gems/LyShine/Code/Source/Animation/AnimNode.h +++ b/Gems/LyShine/Code/Source/Animation/AnimNode.h @@ -13,6 +13,7 @@ #include #include "UiAnimationSystem.h" +#include /*! @@ -39,7 +40,7 @@ public: , valueType(_valueType) , flags(_flags) {}; - AZStd::string name; // parameter name. + AZStd::basic_string, AZStd::stateless_allocator> name; // parameter name. CUiAnimParamType paramType; // parameter id. EUiAnimValue valueType; // value type, defines type of track to use for animating this parameter. ESupportedParamFlags flags; // combination of flags from ESupportedParamFlags. diff --git a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp index 012eaacd1b..cab6ae3fa6 100644 --- a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp +++ b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp @@ -14,9 +14,11 @@ #include "UiAnimSerialize.h" #include +#include +#include +#include #include -#include #include #include #include @@ -25,22 +27,31 @@ #include ////////////////////////////////////////////////////////////////////////// +namespace +{ + using UiAnimParamSystemString = AZStd::basic_string, AZStd::stateless_allocator>; + + template > + using UiAnimSystemOrderedMap = AZStd::map; + template , typename EqualKey = AZStd::equal_to> + using UiAnimSystemUnorderedMap = AZStd::unordered_map; +} // Serialization for anim nodes & param types -#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.find(eUiAnimNodeType_ ## name) == g_animNodeEnumToStringMap.end()); \ +#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.contains(eUiAnimNodeType_ ## name)); \ g_animNodeEnumToStringMap[eUiAnimNodeType_ ## name] = AZ_STRINGIZE(name); \ - g_animNodeStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name; + g_animNodeStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name; -#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.find(eUiAnimParamType_ ## name) == g_animParamEnumToStringMap.end()); \ +#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.contains(eUiAnimParamType_ ## name)); \ g_animParamEnumToStringMap[eUiAnimParamType_ ## name] = AZ_STRINGIZE(name); \ - g_animParamStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name; + g_animParamStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name; namespace { - AZStd::unordered_map g_animNodeEnumToStringMap; - StaticInstance >> g_animNodeStringToEnumMap; + UiAnimSystemUnorderedMap g_animNodeEnumToStringMap; + UiAnimSystemOrderedMap> g_animNodeStringToEnumMap; - AZStd::unordered_map g_animParamEnumToStringMap; - StaticInstance >> g_animParamStringToEnumMap; + UiAnimSystemUnorderedMap g_animParamEnumToStringMap; + UiAnimSystemOrderedMap> g_animParamStringToEnumMap; // If you get an assert in this function, it means two node types have the same enum value. void RegisterNodeTypes() diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp index 7e32301b71..b535033351 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp @@ -8,6 +8,7 @@ #include +#include #include "AnimPostFXNode.h" #include "AnimSplineTrack.h" #include "CompoundSplineTrack.h" @@ -38,7 +39,7 @@ public: virtual void GetDefault(bool& val) const = 0; virtual void GetDefault(Vec4& val) const = 0; - AZStd::string m_name; + AZStd::basic_string, AZStd::stateless_allocator> m_name; protected: virtual ~CControlParamBase(){} diff --git a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp index 3654af52dd..9c4356560d 100644 --- a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp @@ -8,6 +8,9 @@ #include +#include +#include +#include #include #include #include "Movie.h" @@ -73,22 +76,32 @@ static SMovieSequenceAutoComplete s_movieSequenceAutoComplete; #endif ////////////////////////////////////////////////////////////////////////// +namespace +{ + using AnimParamSystemString = AZStd::basic_string, AZStd::stateless_allocator>; + + template > + using AnimSystemOrderedMap = AZStd::map; + template , typename EqualKey = AZStd::equal_to> + using AnimSystemUnorderedMap = AZStd::unordered_map; +} + // Serialization for anim nodes & param types -#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.find(AnimNodeType::name) == g_animNodeEnumToStringMap.end()); \ - g_animNodeEnumToStringMap[AnimNodeType::name] = AZ_STRINGIZE(name); \ - g_animNodeStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = AnimNodeType::name; +#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.contains(AnimNodeType::name)); \ + g_animNodeEnumToStringMap[AnimNodeType::name] = AZ_STRINGIZE(name); \ + g_animNodeStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimNodeType::name; -#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.find(AnimParamType::name) == g_animParamEnumToStringMap.end()); \ - g_animParamEnumToStringMap[AnimParamType::name] = AZ_STRINGIZE(name); \ - g_animParamStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = AnimParamType::name; +#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.contains(AnimParamType::name)); \ + g_animParamEnumToStringMap[AnimParamType::name] = AZ_STRINGIZE(name); \ + g_animParamStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimParamType::name; namespace { - AZStd::unordered_map g_animNodeEnumToStringMap; - StaticInstance >> g_animNodeStringToEnumMap; + AnimSystemUnorderedMap g_animNodeEnumToStringMap; + AnimSystemOrderedMap> g_animNodeStringToEnumMap; - AZStd::unordered_map g_animParamEnumToStringMap; - StaticInstance >> g_animParamStringToEnumMap; + AnimSystemUnorderedMap g_animParamEnumToStringMap; + AnimSystemOrderedMap> g_animParamStringToEnumMap; // If you get an assert in this function, it means two node types have the same enum value. void RegisterNodeTypes() From 4089edb33698f37d06c0bcfee9385401aab50604 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 13 Oct 2021 11:19:01 -0500 Subject: [PATCH 221/293] added missing include to fix build Signed-off-by: Guthrie Adams --- .../Material/EditorMaterialSystemComponentRequestBus.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h index 0bf93fc56f..191f444586 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace AZ { From b6a1f62dec2c248606905bdc931ee4d795c148c2 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Wed, 13 Oct 2021 18:20:48 +0200 Subject: [PATCH 222/293] EMotion FX: Fix for broken workspaces after asset path change (#4662) Some days ago an impactful change deprecated @assets@ and @root@ keywords from paths which our workspaces used. Some workspaces used these and were broken. This change makes them backward compatible and loads the assets correctly again. It also auto fixes broken paths that were present in some of the saved workspaces + making sure new workspaces are saved correctly. Signed-off-by: Benjamin Jillich --- .../EMotionStudio/EMStudioSDK/Source/Workspace.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp index ea7c92b742..cada8c7f59 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp @@ -105,7 +105,9 @@ namespace EMStudio } } - commandString = AZStd::string::format("%s -filename \"%s\"", command, resultFileName.c_str()); + AZStd::string resultFilenameString = resultFileName.c_str(); + AzFramework::StringFunc::AssetDatabasePath::Normalize(resultFilenameString); + commandString = AZStd::string::format("%s -filename \"%s\"", command, resultFilenameString.c_str()); if (additionalParameters) { @@ -428,7 +430,13 @@ namespace EMStudio continue; } - AzFramework::StringFunc::Replace(commands[i], "@products@/", assetCacheFolder.c_str(), true /* case sensitive */); + AzFramework::StringFunc::Replace(commands[i], "@products@", assetCacheFolder.c_str()); + AzFramework::StringFunc::Replace(commands[i], "@assets@", assetCacheFolder.c_str()); + AzFramework::StringFunc::Replace(commands[i], "@root@", assetCacheFolder.c_str()); + AzFramework::StringFunc::Replace(commands[i], "@projectplatformcache@", assetCacheFolder.c_str()); + AzFramework::StringFunc::Replace(commands[i], "//", AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); + AzFramework::StringFunc::Replace(commands[i], "\\\\", AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); + AzFramework::StringFunc::Replace(commands[i], "/\\", AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); // add the command to the command group commandGroup->AddCommandString(commands[i]); From 150060441eccb98318febe17d3915f0781823b19 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:50:44 -0700 Subject: [PATCH 223/293] Re-add pytest.mark.test_case_id markers (#4621) * add some test case id markers Signed-off-by: jromnoa * re-added pytest.mark.test_case_id markers for test cases Signed-off-by: jromnoa * re-add directional light log lines that were missing and re-add directional light test case id Signed-off-by: jromnoa --- .../Gem/PythonTests/Atom/TestSuite_Main.py | 44 ++++++++++++++----- .../PythonTests/Atom/TestSuite_Main_GPU.py | 4 ++ .../Atom/TestSuite_Main_GPU_Optimized.py | 1 + .../Gem/PythonTests/Atom/TestSuite_Sandbox.py | 1 + 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index e4a77ca4ec..3403c938a8 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -23,20 +23,20 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") class TestAtomEditorComponentsMain(object): """Holds tests for Atom components.""" + @pytest.mark.test_case_id("C32078118") # Decal + @pytest.mark.test_case_id("C32078119") # DepthOfField + @pytest.mark.test_case_id("C32078120") # Directional Light + @pytest.mark.test_case_id("C32078121") # Exposure Control + @pytest.mark.test_case_id("C32078115") # Global Skylight (IBL) + @pytest.mark.test_case_id("C32078125") # Physical Sky + @pytest.mark.test_case_id("C32078127") # PostFX Layer + @pytest.mark.test_case_id("C32078131") # PostFX Radius Weight Modifier + @pytest.mark.test_case_id("C32078117") # Light + @pytest.mark.test_case_id("C36525660") # Display Mapper def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform): """ Please review the hydra script run by this test for more specific test info. - Tests the following Atom components and verifies all "expected_lines" appear in Editor.log: - 1. Display Mapper - 2. Light - 3. PostFX Radius Weight Modifier - 4. PostFX Layer - 5. Physical Sky - 6. Global Skylight (IBL) - 7. Exposure Control - 8. Directional Light - 9. DepthOfField - 10. Decal + Tests the Atom components & verifies all "expected_lines" appear in Editor.log """ cfg_args = [level] @@ -69,6 +69,18 @@ class TestAtomEditorComponentsMain(object): "DepthOfField_test: Entity deleted: True", "DepthOfField_test: UNDO entity deletion works: True", "DepthOfField_test: REDO entity deletion works: True", + # Directional Light Component + "Directional Light Entity successfully created", + "Directional Light_test: Component added to the entity: True", + "Directional Light_test: Component removed after UNDO: True", + "Directional Light_test: Component added after REDO: True", + "Directional Light_test: Entered game mode: True", + "Directional Light_test: Exit game mode: True", + "Directional Light_test: Entity is hidden: True", + "Directional Light_test: Entity is shown: True", + "Directional Light_test: Entity deleted: True", + "Directional Light_test: UNDO entity deletion works: True", + "Directional Light_test: REDO entity deletion works: True", # Exposure Control Component "Exposure Control Entity successfully created", "Exposure Control_test: Component added to the entity: True", @@ -180,6 +192,7 @@ class TestAtomEditorComponentsMain(object): cfg_args=cfg_args, ) + @pytest.mark.test_case_id("C34525095") def test_AtomEditorComponents_LightComponent( self, request, editor, workspace, project, launcher_platform, level): """ @@ -266,6 +279,15 @@ class TestMaterialEditorBasicTests(object): request.addfinalizer(teardown) @pytest.mark.parametrize("exe_file_name", ["MaterialEditor"]) + @pytest.mark.test_case_id("C34448113") # Creating a New Asset. + @pytest.mark.test_case_id("C34448114") # Opening an Existing Asset. + @pytest.mark.test_case_id("C34448115") # Closing Selected Material. + @pytest.mark.test_case_id("C34448116") # Closing All Materials. + @pytest.mark.test_case_id("C34448117") # Closing all but Selected Material. + @pytest.mark.test_case_id("C34448118") # Saving Material. + @pytest.mark.test_case_id("C34448119") # Saving as a New Material. + @pytest.mark.test_case_id("C34448120") # Saving as a Child Material. + @pytest.mark.test_case_id("C34448121") # Saving all Open Materials. def test_MaterialEditorBasicTests( self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name): diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index 220623af8b..74b064a555 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -73,6 +73,7 @@ def create_screenshots_archive(screenshot_path): class TestAllComponentsIndepthTests(object): @pytest.mark.parametrize("screenshot_name", ["AtomBasicLevelSetup.ppm"]) + @pytest.mark.test_case_id("C34603773") def test_BasicLevelSetup_SetsUpLevel( self, request, editor, workspace, project, launcher_platform, level, screenshot_name): """ @@ -115,6 +116,7 @@ class TestAllComponentsIndepthTests(object): create_screenshots_archive(screenshot_directory) + @pytest.mark.test_case_id("C34525095") def test_LightComponent_ScreenshotMatchesGoldenImage( self, request, editor, workspace, project, launcher_platform, level): """ @@ -225,6 +227,8 @@ class TestMaterialEditor(object): pytest.param("-rhi=Vulkan", ["Registering vulkan RHI"]) ]) @pytest.mark.parametrize("exe_file_name", ["MaterialEditor"]) + @pytest.mark.test_case_id("C30973986") # Material Editor Launching in Dx12 + @pytest.mark.test_case_id("C30973987") # Material Editor Launching in Vulkan def test_MaterialEditorLaunch_AllRHIOptionsSucceed( self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args, expected_lines): diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py index ef572d6e5c..568768e12e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py @@ -23,6 +23,7 @@ class TestAutomation(EditorTestSuite): # Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests. global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"] + @pytest.mark.test_case_id("C34603773") class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest): use_null_renderer = False # Default is True screenshot_name = "AtomBasicLevelSetup.ppm" diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py index 79caf26784..58e5d00ff2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py @@ -30,6 +30,7 @@ class TestAtomEditorComponentsSandbox(object): class TestAtomEditorComponentsMain(object): """Holds tests for Atom components.""" + @pytest.mark.test_case_id("C32078128") def test_AtomEditorComponents_ReflectionProbeAddedToEntity( self, request, editor, level, workspace, project, launcher_platform): """ From 56f0ea68a678ce7990ea616d31464da50d0a3e37 Mon Sep 17 00:00:00 2001 From: brianherrera Date: Wed, 13 Oct 2021 10:29:53 -0700 Subject: [PATCH 224/293] Add step to verify disk is in an offline state Some Windows configs will automatically set new drives as online causing diskpart setup script to fail. Signed-off-by: brianherrera --- .../build/bootstrap/incremental_build_util.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/build/bootstrap/incremental_build_util.py b/scripts/build/bootstrap/incremental_build_util.py index 5c77559085..a33eb2af80 100644 --- a/scripts/build/bootstrap/incremental_build_util.py +++ b/scripts/build/bootstrap/incremental_build_util.py @@ -252,6 +252,18 @@ def find_snapshot_id(ec2_client, snapshot_hint, repository_name, project, pipeli snapshot_id = snapshot['SnapshotId'] return snapshot_id + +def offline_drive(disk_number=1): + """Use diskpart to offline a Windows drive""" + with tempfile.NamedTemporaryFile(delete=False) as f: + f.write(f""" + select disk {disk_number} + offline disk + """.encode('utf-8')) + subprocess.run(['diskpart', '/s', f.name]) + os.unlink(f.name) + + def create_volume(ec2_client, availability_zone, snapshot_hint, repository_name, project, pipeline, branch, platform, build_type, disk_size, disk_type): # The actual EBS default calculation for IOps is a floating point number, the closest approxmiation is 4x of the disk size for simplicity mount_name = get_mount_name(repository_name, project, pipeline, branch, platform, build_type) @@ -310,6 +322,10 @@ def create_volume(ec2_client, availability_zone, snapshot_hint, repository_name, def mount_volume_to_device(created): print('Mounting volume...') if os.name == 'nt': + # Verify drive is in an offline state. + # Some Windows configs will automatically set new drives as online causing diskpart setup script to fail. + offline_drive() + f = tempfile.NamedTemporaryFile(delete=False) f.write(""" select disk 1 From ac8201a2faebfd361dadbfa96c527895426dfa2d Mon Sep 17 00:00:00 2001 From: brianherrera Date: Wed, 13 Oct 2021 10:34:03 -0700 Subject: [PATCH 225/293] Update disk setup step to use context manager Signed-off-by: brianherrera --- .../build/bootstrap/incremental_build_util.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/scripts/build/bootstrap/incremental_build_util.py b/scripts/build/bootstrap/incremental_build_util.py index a33eb2af80..493d8a9249 100644 --- a/scripts/build/bootstrap/incremental_build_util.py +++ b/scripts/build/bootstrap/incremental_build_util.py @@ -325,24 +325,22 @@ def mount_volume_to_device(created): # Verify drive is in an offline state. # Some Windows configs will automatically set new drives as online causing diskpart setup script to fail. offline_drive() - - f = tempfile.NamedTemporaryFile(delete=False) - f.write(""" - select disk 1 - online disk - attribute disk clear readonly - """.encode('utf-8')) # assume disk # for now + + with tempfile.NamedTemporaryFile(delete=False) as f: + f.write(""" + select disk 1 + online disk + attribute disk clear readonly + """.encode('utf-8')) # assume disk # for now if created: print('Creating filesystem on new volume') f.write("""create partition primary - select partition 1 - format quick fs=ntfs - assign - active - """.encode('utf-8')) - - f.close() + select partition 1 + format quick fs=ntfs + assign + active + """.encode('utf-8')) subprocess.call(['diskpart', '/s', f.name]) From 3c7357da479acd50fb19e0619a776c6ab00069fb Mon Sep 17 00:00:00 2001 From: brianherrera Date: Wed, 13 Oct 2021 10:35:42 -0700 Subject: [PATCH 226/293] Update existing unmount step to use new offline function Signed-off-by: brianherrera --- scripts/build/bootstrap/incremental_build_util.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/scripts/build/bootstrap/incremental_build_util.py b/scripts/build/bootstrap/incremental_build_util.py index 493d8a9249..6117fe0180 100644 --- a/scripts/build/bootstrap/incremental_build_util.py +++ b/scripts/build/bootstrap/incremental_build_util.py @@ -391,14 +391,7 @@ def unmount_volume_from_device(): print('Unmounting EBS volume from device...') if os.name == 'nt': kill_processes(MOUNT_PATH + 'workspace') - f = tempfile.NamedTemporaryFile(delete=False) - f.write(""" - select disk 1 - offline disk - """.encode('utf-8')) - f.close() - subprocess.call('diskpart /s %s' % f.name) - os.unlink(f.name) + offline_drive() else: kill_processes(MOUNT_PATH) subprocess.call(['umount', '-f', MOUNT_PATH]) From 26d53690b95dfec555b1caf8c6df6b3c239b6835 Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Wed, 13 Oct 2021 11:34:13 -0700 Subject: [PATCH 227/293] [GameLift][FlexMatch] Add client side change for match acceptance (#4634) * [GameLift][FlexMatch] Add client side change for match acceptance required Signed-off-by: Junbo Liang --- .../AWSGameLiftClientLocalTicketTracker.cpp | 2 + .../Source/AWSGameLiftClientManager.cpp | 46 +++++++- .../Source/AWSGameLiftClientManager.h | 2 + .../AWSGameLiftAcceptMatchActivity.cpp | 76 +++++++++++++ .../Activity/AWSGameLiftAcceptMatchActivity.h | 31 ++++++ .../AWSGameLiftStartMatchmakingActivity.cpp | 4 + .../AWSGameLiftStartMatchmakingActivity.h | 3 - .../AWSGameLiftStopMatchmakingActivity.cpp | 3 + .../AWSGameLiftStopMatchmakingActivity.h | 3 - ...WSGameLiftClientLocalTicketTrackerTest.cpp | 38 +++++++ .../Tests/AWSGameLiftClientManagerTest.cpp | 104 ++++++++++++++++++ .../Tests/AWSGameLiftClientMocks.h | 21 ++++ .../AWSGameLiftAcceptMatchActivityTest.cpp | 77 +++++++++++++ ...WSGameLiftStartMatchmakingActivityTest.cpp | 2 + ...AWSGameLiftStopMatchmakingActivityTest.cpp | 2 + .../awsgamelift_client_files.cmake | 2 + .../awsgamelift_client_tests_files.cmake | 1 + 17 files changed, 409 insertions(+), 8 deletions(-) create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp index b619a10d4a..af0cf1c35c 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -109,6 +110,7 @@ namespace AWSGameLift else if (ticket.GetStatus() == Aws::GameLift::Model::MatchmakingConfigurationStatus::REQUIRES_ACCEPTANCE) { // broadcast acceptance requires to player + AzFramework::MatchAcceptanceNotificationBus::Broadcast(&AzFramework::MatchAcceptanceNotifications::OnMatchAcceptance); } else { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp index 91e76380eb..224f16481e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -125,12 +126,53 @@ namespace AWSGameLift void AWSGameLiftClientManager::AcceptMatch(const AzFramework::AcceptMatchRequest& acceptMatchRequest) { - AZ_UNUSED(acceptMatchRequest); + if (AcceptMatchActivity::ValidateAcceptMatchRequest(acceptMatchRequest)) + { + const AWSGameLiftAcceptMatchRequest& gameliftStartMatchmakingRequest = + static_cast(acceptMatchRequest); + AcceptMatchHelper(gameliftStartMatchmakingRequest); + } } void AWSGameLiftClientManager::AcceptMatchAsync(const AzFramework::AcceptMatchRequest& acceptMatchRequest) { - AZ_UNUSED(acceptMatchRequest); + if (!AcceptMatchActivity::ValidateAcceptMatchRequest(acceptMatchRequest)) + { + AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( + &AzFramework::MatchmakingAsyncRequestNotifications::OnAcceptMatchAsyncComplete); + return; + } + + const AWSGameLiftAcceptMatchRequest& gameliftStartMatchmakingRequest = static_cast(acceptMatchRequest); + + AZ::JobContext* jobContext = nullptr; + AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext); + AZ::Job* acceptMatchJob = AZ::CreateJobFunction( + [this, gameliftStartMatchmakingRequest]() + { + AcceptMatchHelper(gameliftStartMatchmakingRequest); + + AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( + &AzFramework::MatchmakingAsyncRequestNotifications::OnAcceptMatchAsyncComplete); + }, + true, jobContext); + + acceptMatchJob->Start(); + } + + void AWSGameLiftClientManager::AcceptMatchHelper(const AWSGameLiftAcceptMatchRequest& acceptMatchRequest) + { + auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); + + AZStd::string response; + if (!gameliftClient) + { + AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftClientMissingErrorMessage); + } + else + { + AcceptMatchActivity::AcceptMatch(*gameliftClient, acceptMatchRequest); + } } AZStd::string AWSGameLiftClientManager::CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h index ba81196b07..1f32b69f75 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h @@ -15,6 +15,7 @@ namespace AWSGameLift { + struct AWSGameLiftAcceptMatchRequest; struct AWSGameLiftCreateSessionRequest; struct AWSGameLiftCreateSessionOnQueueRequest; struct AWSGameLiftJoinSessionRequest; @@ -158,6 +159,7 @@ namespace AWSGameLift void LeaveSession() override; private: + void AcceptMatchHelper(const AWSGameLiftAcceptMatchRequest& createSessionRequest); AZStd::string CreateSessionHelper(const AWSGameLiftCreateSessionRequest& createSessionRequest); AZStd::string CreateSessionOnQueueHelper(const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest); bool JoinSessionHelper(const AWSGameLiftJoinSessionRequest& joinSessionRequest); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp new file mode 100644 index 0000000000..25ba328fd0 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp @@ -0,0 +1,76 @@ +/* + * 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.AcceptMatch + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +#include +#include + +namespace AWSGameLift +{ + namespace AcceptMatchActivity + { + Aws::GameLift::Model::AcceptMatchRequest BuildAWSGameLiftAcceptMatchRequest( + const AWSGameLiftAcceptMatchRequest& acceptMatchRequest) + { + Aws::GameLift::Model::AcceptMatchRequest request; + request.SetAcceptanceType(acceptMatchRequest.m_acceptMatch ? + Aws::GameLift::Model::AcceptanceType::ACCEPT : Aws::GameLift::Model::AcceptanceType::REJECT); + + Aws::Vector playerIds; + for (const AZStd::string& playerId : acceptMatchRequest.m_playerIds) + { + playerIds.emplace_back(playerId.c_str()); + } + request.SetPlayerIds(playerIds); + + if (!acceptMatchRequest.m_ticketId.empty()) + { + request.SetTicketId(acceptMatchRequest.m_ticketId.c_str()); + } + + AZ_TracePrintf(AWSGameLiftAcceptMatchActivityName, "Built AcceptMatchRequest with TicketId=%s", request.GetTicketId().c_str()); + + return request; + } + + void AcceptMatch(const Aws::GameLift::GameLiftClient& gameliftClient, + const AWSGameLiftAcceptMatchRequest& AcceptMatchRequest) + { + AZ_TracePrintf(AWSGameLiftAcceptMatchActivityName, "Requesting AcceptMatch against Amazon GameLift service ..."); + + Aws::GameLift::Model::AcceptMatchRequest request = BuildAWSGameLiftAcceptMatchRequest(AcceptMatchRequest); + auto AcceptMatchOutcome = gameliftClient.AcceptMatch(request); + + if (AcceptMatchOutcome.IsSuccess()) + { + AZ_TracePrintf(AWSGameLiftAcceptMatchActivityName, "AcceptMatch request against Amazon GameLift service is complete"); + } + else + { + AZ_Error(AWSGameLiftAcceptMatchActivityName, false, AWSGameLiftErrorMessageTemplate, + AcceptMatchOutcome.GetError().GetExceptionName().c_str(), AcceptMatchOutcome.GetError().GetMessage().c_str()); + } + } + + bool ValidateAcceptMatchRequest(const AzFramework::AcceptMatchRequest& AcceptMatchRequest) + { + auto gameliftAcceptMatchRequest = azrtti_cast(&AcceptMatchRequest); + bool isValid = gameliftAcceptMatchRequest && + (gameliftAcceptMatchRequest->m_playerIds.size() > 0) && + (!gameliftAcceptMatchRequest->m_ticketId.empty()); + + AZ_Error(AWSGameLiftAcceptMatchActivityName, isValid, AWSGameLiftAcceptMatchRequestInvalidErrorMessage); + + return isValid; + } + } // namespace AcceptMatchActivity +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h new file mode 100644 index 0000000000..d5f28f92e2 --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +#include + +namespace AWSGameLift +{ + namespace AcceptMatchActivity + { + static constexpr const char AWSGameLiftAcceptMatchActivityName[] = "AWSGameLiftAcceptMatchActivity"; + static constexpr const char AWSGameLiftAcceptMatchRequestInvalidErrorMessage[] = "Invalid GameLift AcceptMatch request."; + + // Build AWS GameLift AcceptMatchRequest by using AWSGameLiftAcceptMatchRequest + Aws::GameLift::Model::AcceptMatchRequest BuildAWSGameLiftAcceptMatchRequest(const AWSGameLiftAcceptMatchRequest& AcceptMatchRequest); + + // Create AcceptMatchRequest and make a AcceptMatch call through GameLift client + void AcceptMatch(const Aws::GameLift::GameLiftClient& gameliftClient, const AWSGameLiftAcceptMatchRequest& AcceptMatchRequest); + + // Validate AcceptMatchRequest and check required request parameters + bool ValidateAcceptMatchRequest(const AzFramework::AcceptMatchRequest& AcceptMatchRequest); + } // namespace AcceptMatchActivity +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp index 2b2a32f74b..e535ea0c55 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp @@ -5,12 +5,16 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #include #include #include #include +#include +#include + namespace AWSGameLift { namespace StartMatchmakingActivity diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h index 5f8c4558f4..db814c14b2 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h @@ -10,9 +10,7 @@ #include -#include #include -#include namespace AWSGameLift { @@ -25,7 +23,6 @@ namespace AWSGameLift Aws::GameLift::Model::StartMatchmakingRequest BuildAWSGameLiftStartMatchmakingRequest(const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest); // Create StartMatchmakingRequest and make a StartMatchmaking call through GameLift client - // Will also start polling the matchmaking ticket when get success outcome from GameLift client AZStd::string StartMatchmaking(const Aws::GameLift::GameLiftClient& gameliftClient, const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest); // Validate StartMatchmakingRequest and check required request parameters diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp index 204923fc02..b427d0323a 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include + namespace AWSGameLift { namespace StopMatchmakingActivity diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h index 9bfeb86343..0820f2c05e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h @@ -10,9 +10,7 @@ #include -#include #include -#include namespace AWSGameLift { @@ -25,7 +23,6 @@ namespace AWSGameLift Aws::GameLift::Model::StopMatchmakingRequest BuildAWSGameLiftStopMatchmakingRequest(const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest); // Create StopMatchmakingRequest and make a StopMatchmaking call through GameLift client - // Will also stop polling the matchmaking ticket when get success outcome from GameLift client void StopMatchmaking(const Aws::GameLift::GameLiftClient& gameliftClient, const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest); // Validate StopMatchmakingRequest and check required request parameters diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp index 6506d70704..4dc4dd85f6 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientLocalTicketTrackerTest.cpp @@ -351,3 +351,41 @@ TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_CallAndTicketComple WaitForProcessFinish(); ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); } + +TEST_F(AWSGameLiftClientLocalTicketTrackerTest, StartPolling_RequiresAcceptanceAndTicketCompleteAtLast_ProcessContinuesAndStop) +{ + Aws::GameLift::Model::MatchmakingTicket ticket1; + ticket1.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::REQUIRES_ACCEPTANCE); + + Aws::GameLift::Model::DescribeMatchmakingResult result1; + result1.AddTicketList(ticket1); + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome1(result1); + + Aws::GameLift::Model::GameSessionConnectionInfo connectionInfo; + connectionInfo.SetIpAddress("DummyIpAddress"); + connectionInfo.SetPort(123); + connectionInfo.AddMatchedPlayerSessions( + Aws::GameLift::Model::MatchedPlayerSession().WithPlayerId("player1").WithPlayerSessionId("playersession1")); + + Aws::GameLift::Model::MatchmakingTicket ticket2; + ticket2.SetStatus(Aws::GameLift::Model::MatchmakingConfigurationStatus::COMPLETED); + ticket2.SetGameSessionConnectionInfo(connectionInfo); + + Aws::GameLift::Model::DescribeMatchmakingResult result2; + result2.AddTicketList(ticket2); + Aws::GameLift::Model::DescribeMatchmakingOutcome outcome2(result2); + + EXPECT_CALL(*m_gameliftClientMockPtr, DescribeMatchmaking(::testing::_)) + .WillOnce(::testing::Return(outcome1)) + .WillOnce(::testing::Return(outcome2)); + + MatchAcceptanceNotificationsHandlerMock handlerMock1; + EXPECT_CALL(handlerMock1, OnMatchAcceptance()).Times(1); + + SessionHandlingClientRequestsMock handlerMock2; + EXPECT_CALL(handlerMock2, RequestPlayerJoinSession(::testing::_)).Times(1).WillOnce(::testing::Return(true)); + + m_gameliftClientTicketTracker->StartPolling("ticket1", "player1"); + WaitForProcessFinish(); + ASSERT_TRUE(m_gameliftClientTicketTracker->IsTrackerIdle()); +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp index 2fa332df72..3b7c7ee827 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -1005,3 +1006,106 @@ TEST_F(AWSGameLiftClientManagerTest, StopMatchmakingAsync_CallWithValidRequest_G m_gameliftClientManager->StopMatchmakingAsync(request); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } + +TEST_F(AWSGameLiftClientManagerTest, AcceptMatch_CallWithoutClientSetup_GetError) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->ConfigureGameLiftClient(""); + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_playerIds = { DummyPlayerId }; + request.m_ticketId = DummyMatchmakingTicketId; + + m_gameliftClientManager->AcceptMatch(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(2); // capture 2 error message +} +TEST_F(AWSGameLiftClientManagerTest, AcceptMatch_CallWithInvalidRequest_GetError) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->AcceptMatch(AzFramework::AcceptMatchRequest()); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, AcceptMatch_CallWithValidRequest_Success) +{ + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_playerIds = { DummyPlayerId }; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::GameLift::Model::AcceptMatchResult result; + Aws::GameLift::Model::AcceptMatchResult outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, AcceptMatch(::testing::_)).Times(1).WillOnce(::testing::Return(outcome)); + + m_gameliftClientManager->AcceptMatch(request); +} + +TEST_F(AWSGameLiftClientManagerTest, AcceptMatch_CallWithValidRequest_GetError) +{ + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_playerIds = { DummyPlayerId }; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::Client::AWSError error; + Aws::GameLift::Model::AcceptMatchOutcome outcome(error); + + EXPECT_CALL(*m_gameliftClientMockPtr, AcceptMatch(::testing::_)).Times(1).WillOnce(::testing::Return(outcome)); + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->AcceptMatch(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, AcceptMatchAsync_CallWithInvalidRequest_GetNotificationWithError) +{ + AWSGameLiftAcceptMatchRequest request; + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnAcceptMatchAsyncComplete()).Times(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->AcceptMatchAsync(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftClientManagerTest, AcceptMatchAsync_CallWithValidRequest_GetNotification) +{ + AWSCoreRequestsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get())); + + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_playerIds = { DummyPlayerId }; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::GameLift::Model::AcceptMatchResult result; + Aws::GameLift::Model::AcceptMatchOutcome outcome(result); + EXPECT_CALL(*m_gameliftClientMockPtr, AcceptMatch(::testing::_)).Times(1).WillOnce(::testing::Return(outcome)); + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnAcceptMatchAsyncComplete()).Times(1); + + m_gameliftClientManager->AcceptMatchAsync(request); +} + +TEST_F(AWSGameLiftClientManagerTest, AcceptMatchAsync_CallWithValidRequest_GetNotificationWithError) +{ + AWSCoreRequestsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, GetDefaultJobContext()).Times(1).WillOnce(::testing::Return(m_jobContext.get())); + + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_playerIds = { DummyPlayerId }; + request.m_ticketId = DummyMatchmakingTicketId; + + Aws::Client::AWSError error; + Aws::GameLift::Model::AcceptMatchOutcome outcome(error); + EXPECT_CALL(*m_gameliftClientMockPtr, AcceptMatch(::testing::_)).Times(1).WillOnce(::testing::Return(outcome)); + + MatchmakingAsyncRequestNotificationsHandlerMock matchmakingHandlerMock; + EXPECT_CALL(matchmakingHandlerMock, OnAcceptMatchAsyncComplete()).Times(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + m_gameliftClientManager->AcceptMatchAsync(request); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h index 964b6a21c2..6ba05747aa 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -18,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -46,6 +49,7 @@ public: { } + MOCK_CONST_METHOD1(AcceptMatch, Model::AcceptMatchOutcome(const Model::AcceptMatchRequest&)); MOCK_CONST_METHOD1(CreateGameSession, Model::CreateGameSessionOutcome(const Model::CreateGameSessionRequest&)); MOCK_CONST_METHOD1(CreatePlayerSession, Model::CreatePlayerSessionOutcome(const Model::CreatePlayerSessionRequest&)); MOCK_CONST_METHOD1(DescribeMatchmaking, Model::DescribeMatchmakingOutcome(const Model::DescribeMatchmakingRequest&)); @@ -74,6 +78,23 @@ public: MOCK_METHOD0(OnStopMatchmakingAsyncComplete, void()); }; +class MatchAcceptanceNotificationsHandlerMock + : public AzFramework::MatchAcceptanceNotificationBus::Handler +{ +public: + MatchAcceptanceNotificationsHandlerMock() + { + AzFramework::MatchAcceptanceNotificationBus::Handler::BusConnect(); + } + + ~MatchAcceptanceNotificationsHandlerMock() + { + AzFramework::MatchAcceptanceNotificationBus::Handler::BusDisconnect(); + } + + MOCK_METHOD0(OnMatchAcceptance, void()); +}; + class SessionAsyncRequestNotificationsHandlerMock : public AzFramework::SessionAsyncRequestNotificationBus::Handler { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp new file mode 100644 index 0000000000..af78ca8c0c --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +#include + +using namespace AWSGameLift; + +using AWSGameLiftAcceptMatchActivityTest = AWSGameLiftClientFixture; + +TEST_F(AWSGameLiftAcceptMatchActivityTest, BuildAWSGameLiftAcceptMatchRequest_Call_GetExpectedResult) +{ + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_ticketId = "dummyTicketId"; + request.m_playerIds = { "dummyPlayerId" }; + + auto awsRequest = AcceptMatchActivity::BuildAWSGameLiftAcceptMatchRequest(request); + + EXPECT_EQ(awsRequest.GetAcceptanceType(), Aws::GameLift::Model::AcceptanceType::ACCEPT); + EXPECT_TRUE(strcmp(awsRequest.GetTicketId().c_str(), request.m_ticketId.c_str()) == 0); + EXPECT_EQ(awsRequest.GetPlayerIds().size(), request.m_playerIds.size()); + EXPECT_TRUE(strcmp(awsRequest.GetPlayerIds().begin()->c_str(), request.m_playerIds.begin()->c_str()) == 0); +} + +TEST_F(AWSGameLiftAcceptMatchActivityTest, ValidateAcceptMatchRequest_CallWithBaseType_GetFalseResult) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = AcceptMatchActivity::ValidateAcceptMatchRequest(AzFramework::AcceptMatchRequest()); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftAcceptMatchActivityTest, ValidateAcceptMatchRequest_CallWithoutTicketId_GetFalseResult) +{ + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_playerIds = { "dummyPlayerId" }; + + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = AcceptMatchActivity::ValidateAcceptMatchRequest(request); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftAcceptMatchActivityTest, ValidateAcceptMatchRequest_CallWithoutPlayerIds_GetFalseResult) +{ + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_playerIds = { "dummyPlayerId" }; + + AZ_TEST_START_TRACE_SUPPRESSION; + auto result = AcceptMatchActivity::ValidateAcceptMatchRequest(request); + EXPECT_FALSE(result); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message +} + +TEST_F(AWSGameLiftAcceptMatchActivityTest, ValidateAcceptMatchRequest_CallWithValidAttributes_GetTrueResult) +{ + + AWSGameLiftAcceptMatchRequest request; + request.m_acceptMatch = true; + request.m_ticketId = "dummyTicketId"; + request.m_playerIds = { "dummyPlayerId" }; + + auto result = AcceptMatchActivity::ValidateAcceptMatchRequest(request); + EXPECT_TRUE(result); +} diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp index 706aec04f2..3eed6b0448 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp @@ -9,6 +9,8 @@ #include #include +#include + using namespace AWSGameLift; using AWSGameLiftStartMatchmakingActivityTest = AWSGameLiftClientFixture; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp index 6b53ed5055..ba0e40c7e6 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp @@ -9,6 +9,8 @@ #include #include +#include + using namespace AWSGameLift; using AWSGameLiftStopMatchmakingActivityTest = AWSGameLiftClientFixture; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake index 3122ff2261..0930c42370 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake @@ -18,6 +18,8 @@ set(FILES Include/Request/IAWSGameLiftRequests.h Source/Activity/AWSGameLiftActivityUtils.cpp Source/Activity/AWSGameLiftActivityUtils.h + Source/Activity/AWSGameLiftAcceptMatchActivity.cpp + Source/Activity/AWSGameLiftAcceptMatchActivity.h Source/Activity/AWSGameLiftCreateSessionActivity.cpp Source/Activity/AWSGameLiftCreateSessionActivity.h Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake index f8ef40d5df..3e73dd8a0a 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_tests_files.cmake @@ -7,6 +7,7 @@ # set(FILES + Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp From 7415277eed731284e9664d550f6ceb644c4e6582 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 13 Oct 2021 13:35:46 -0500 Subject: [PATCH 228/293] fixing ME shutdown Signed-off-by: Guthrie Adams --- .../Code/Source/PreviewRenderer/PreviewRenderer.cpp | 1 + .../Code/Source/SharedPreview/SharedPreviewContent.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 3e4fde4e08..2a6991dc46 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -96,6 +96,7 @@ namespace AtomToolsFramework AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); m_frameworkScene->UnsetSubsystem(m_scene); m_frameworkScene->UnsetSubsystem(m_entityContext.get()); + m_entityContext->DestroyContext(); } void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp index 21020f64b1..91b6d2b02a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp @@ -44,7 +44,7 @@ namespace AZ { // Create preview model AzFramework::EntityContextRequestBus::EventResult( - m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); + m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "SharedPreviewContentModel"); m_modelEntity->CreateComponent(Render::MeshComponentTypeId); m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); m_modelEntity->CreateComponent(azrtti_typeid()); @@ -60,6 +60,7 @@ namespace AZ { if (m_modelEntity) { + m_modelEntity->Deactivate(); AzFramework::EntityContextRequestBus::Event( m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); m_modelEntity = nullptr; From afdf35a925d987c16d8399540f04d62212376d2c Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 13 Oct 2021 13:41:31 -0500 Subject: [PATCH 229/293] updated material editor skybox and changed property icons Signed-off-by: Guthrie Adams --- .../Code/Source/Inspector/Icons/blank.png | 3 +++ .../Inspector/Icons/changed_property.svg | 5 +++++ .../Code/Source/Inspector/InspectorWidget.qrc | 2 ++ .../Code/Source/Window/Icons/skybox.svg | 21 ++++++------------- .../MaterialInspector/MaterialInspector.cpp | 4 ++-- .../Window/ToolBar/MaterialEditorToolBar.cpp | 12 +++++------ .../EditorMaterialComponentInspector.cpp | 4 ++-- 7 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/blank.png create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/changed_property.svg diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/blank.png b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/blank.png new file mode 100644 index 0000000000..d040fa2e14 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/blank.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81b5fa1f978888c3be8a40fce20455668df2723a77587aeb7039f8bf74bdd0e3 +size 119 diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/changed_property.svg b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/changed_property.svg new file mode 100644 index 0000000000..c33e340a54 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/Icons/changed_property.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.qrc b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.qrc index 81a962801d..76733c52ed 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.qrc +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.qrc @@ -2,5 +2,7 @@ Icons/group_closed.png Icons/group_open.png + Icons/blank.png + Icons/changed_property.svg diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg index 83df996198..a79bebdd46 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/Icons/skybox.svg @@ -1,15 +1,6 @@ - - - - icon / Environmental / Sky Highlight - Created with Sketch. - - - - - - - - - - \ No newline at end of file + + + + + + diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index 025de21d31..e99f456653 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -101,9 +101,9 @@ namespace MaterialEditor { if (IsInstanceNodePropertyModifed(node)) { - return ":/PropertyEditor/Resources/changed_data_item.png"; + return ":/Icons/changed_property.svg"; } - return ":/PropertyEditor/Resources/blank.png"; + return ":/Icons/blank.png"; } void MaterialInspector::AddOverviewGroup() diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp index 1e189168da..10442e0c27 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ToolBar/MaterialEditorToolBar.cpp @@ -88,18 +88,18 @@ namespace MaterialEditor toneMappingButton->setVisible(true); addWidget(toneMappingButton); - // Add model combo box - auto modelPresetComboBox = new ModelPresetComboBox(this); - modelPresetComboBox->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents); - modelPresetComboBox->view()->setMinimumWidth(200); - addWidget(modelPresetComboBox); - // Add lighting preset combo box auto lightingPresetComboBox = new LightingPresetComboBox(this); lightingPresetComboBox->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents); lightingPresetComboBox->view()->setMinimumWidth(200); addWidget(lightingPresetComboBox); + // Add model combo box + auto modelPresetComboBox = new ModelPresetComboBox(this); + modelPresetComboBox->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents); + modelPresetComboBox->view()->setMinimumWidth(200); + addWidget(modelPresetComboBox); + MaterialViewportNotificationBus::Handler::BusConnect(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 665adcd568..815f14aba7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -521,9 +521,9 @@ namespace AZ { if (IsInstanceNodePropertyModifed(node)) { - return ":/PropertyEditor/Resources/changed_data_item.png"; + return ":/Icons/changed_property.svg"; } - return ":/PropertyEditor/Resources/blank.png"; + return ":/Icons/blank.png"; } bool MaterialPropertyInspector::SaveMaterial() const From f1fa0acbb483cd7a917a2051a922c0d6bdac6e20 Mon Sep 17 00:00:00 2001 From: sweeneys Date: Wed, 13 Oct 2021 11:44:15 -0700 Subject: [PATCH 230/293] Stabilize asset processor immediately exiting Signed-off-by: sweeneys --- Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py index 0623715350..682fcd3560 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py @@ -488,6 +488,9 @@ class AssetProcessor(object): logger.info(f"Launching AP with command: {command}") try: self._ap_proc = subprocess.Popen(command, cwd=ap_exe_path, env=process_utils.get_display_env()) + time.sleep(1) + if self._ap_proc.poll() is not None: + raise AssetProcessorError(f"AssetProcessor immediately quit with errorcode {self._ap_proc.returncode}") if accept_input: self.connect_control() @@ -506,10 +509,11 @@ class AssetProcessor(object): logger.exception("Exception while starting Asset Processor", be) # clean up to avoid leaking open AP process to future tests try: - self._ap_proc.kill() + if self._ap_proc: + self._ap_proc.kill() except Exception as ex: logger.exception("Ignoring exception while trying to terminate Asset Processor", ex) - raise # raise whatever prompted us to clean up + raise be # raise whatever prompted us to clean up def connect_listen(self, timeout=DEFAULT_TIMEOUT_SECONDS): # Wait for the AP we launched to be ready to accept a connection From da3a39a6a040abddc6267a7750a65e20da4d878b Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:37:07 -0700 Subject: [PATCH 231/293] LYN-7121 | Focus Mode - Make editing a prefab an undoable operation (#4582) * Refactor the PrefabFocusInterface to differentiate between Public and Internal functions. Introduce PrefabFocusUndo nodes to allow undoing Prefab Edit operations. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix selection code to avoid warning message Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Removed changed property from PrefabFocusUndo node Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Switch from size == 0 to empty in EntityOutlinerWidget::OnSelectionChanged Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * condense if check on Prefab Edit context menu item setup Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Correct interface usage in PrefabIntegrationManager (interface was renamed to public) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Remove rej file that was included by mistake Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix missing interface initialization in PrefabFocusTests Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabFocusHandler.cpp | 74 ++++++++++++++----- .../Prefab/PrefabFocusHandler.h | 10 ++- .../Prefab/PrefabFocusInterface.h | 20 +---- .../Prefab/PrefabFocusPublicInterface.h | 53 +++++++++++++ .../Prefab/PrefabFocusUndo.cpp | 52 +++++++++++++ .../AzToolsFramework/Prefab/PrefabFocusUndo.h | 39 ++++++++++ .../UI/Outliner/EntityOutlinerWidget.cpp | 3 +- .../UI/Prefab/PrefabIntegrationManager.cpp | 27 +++---- .../UI/Prefab/PrefabIntegrationManager.h | 4 +- .../UI/Prefab/PrefabUiHandler.cpp | 16 ++-- .../UI/Prefab/PrefabUiHandler.h | 4 +- .../Prefab/PrefabViewportFocusPathHandler.cpp | 14 ++-- .../Prefab/PrefabViewportFocusPathHandler.h | 4 +- .../aztoolsframework_files.cmake | 3 + .../Prefab/PrefabFocus/PrefabFocusTests.cpp | 43 ++++++----- 15 files changed, 268 insertions(+), 98 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusPublicInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index fcec1edd54..a79b9eb73d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -8,12 +8,14 @@ #include +#include #include #include #include #include #include #include +#include namespace AzToolsFramework::Prefab { @@ -28,10 +30,12 @@ namespace AzToolsFramework::Prefab EditorEntityContextNotificationBus::Handler::BusConnect(); AZ::Interface::Register(this); + AZ::Interface::Register(this); } PrefabFocusHandler::~PrefabFocusHandler() { + AZ::Interface::Unregister(this); AZ::Interface::Unregister(this); EditorEntityContextNotificationBus::Handler::BusDisconnect(); } @@ -61,6 +65,44 @@ namespace AzToolsFramework::Prefab } PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId) + { + // Initialize Undo Batch object + ScopedUndoBatch undoBatch("Edit Prefab"); + + // Clear selection + { + const EntityIdList selectedEntities = EntityIdList{}; + auto selectionUndo = aznew SelectionCommand(selectedEntities, "Clear Selection"); + selectionUndo->SetParent(undoBatch.GetUndoBatch()); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, selectedEntities); + } + + // Edit Prefab + { + auto editUndo = aznew PrefabFocusUndo("Edit Prefab"); + editUndo->Capture(entityId); + editUndo->SetParent(undoBatch.GetUndoBatch()); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, editUndo); + } + + return AZ::Success(); + } + + PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index) + { + if (index < 0 || index >= m_instanceFocusVector.size()) + { + return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex.")); + } + + InstanceOptionalReference focusedInstance = m_instanceFocusVector[index]; + + FocusOnOwningPrefab(focusedInstance->get().GetContainerEntityId()); + + return AZ::Success(); + } + + PrefabFocusOperationResult PrefabFocusHandler::FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId) { InstanceOptionalReference focusedInstance; @@ -85,18 +127,6 @@ namespace AzToolsFramework::Prefab return FocusOnPrefabInstance(focusedInstance); } - PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index) - { - if (index < 0 || index >= m_instanceFocusVector.size()) - { - return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex.")); - } - - InstanceOptionalReference focusedInstance = m_instanceFocusVector[index]; - - return FocusOnPrefabInstance(focusedInstance); - } - PrefabFocusOperationResult PrefabFocusHandler::FocusOnPrefabInstance(InstanceOptionalReference focusedInstance) { if (!focusedInstance.has_value()) @@ -122,17 +152,10 @@ namespace AzToolsFramework::Prefab if (focusedInstance->get().GetParentInstance() != AZStd::nullopt) { containerEntityId = focusedInstance->get().GetContainerEntityId(); - - // Select the container entity - AzToolsFramework::SelectEntity(containerEntityId); } else { containerEntityId = AZ::EntityId(); - - // Clear the selection - AzToolsFramework::SelectEntities({}); - } // Focus on the descendants of the container entity @@ -161,6 +184,17 @@ namespace AzToolsFramework::Prefab return m_focusedInstance; } + AZ::EntityId PrefabFocusHandler::GetFocusedPrefabContainerEntityId([[maybe_unused]] AzFramework::EntityContextId entityContextId) const + { + if (!m_focusedInstance.has_value()) + { + // PrefabFocusHandler has not been initialized yet. + return AZ::EntityId(); + } + + return m_focusedInstance->get().GetContainerEntityId(); + } + bool PrefabFocusHandler::IsOwningPrefabBeingFocused(AZ::EntityId entityId) const { if (!m_focusedInstance.has_value()) @@ -200,7 +234,7 @@ namespace AzToolsFramework::Prefab m_instanceFocusVector.clear(); // Focus on the root prefab (AZ::EntityId() will default to it) - FocusOnOwningPrefab(AZ::EntityId()); + FocusOnPrefabInstanceOwningEntityId(AZ::EntityId()); } void PrefabFocusHandler::RefreshInstanceFocusList() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 2f631f772d..80b7a6859c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace AzToolsFramework @@ -28,6 +29,7 @@ namespace AzToolsFramework::Prefab //! Handles Prefab Focus mode, determining which prefab file entity changes will target. class PrefabFocusHandler final : private PrefabFocusInterface + , private PrefabFocusPublicInterface , private EditorEntityContextNotificationBus::Handler { public: @@ -39,10 +41,14 @@ namespace AzToolsFramework::Prefab void Initialize(); // PrefabFocusInterface overrides ... - PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; - PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override; + PrefabFocusOperationResult FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId) override; TemplateId GetFocusedPrefabTemplateId(AzFramework::EntityContextId entityContextId) const override; InstanceOptionalReference GetFocusedPrefabInstance(AzFramework::EntityContextId entityContextId) const override; + + // PrefabFocusPublicInterface overrides ... + PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; + PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override; + AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const override; bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const override; const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const override; const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h index 1c0f4f85e9..25c83b89bc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusInterface.h @@ -20,7 +20,7 @@ namespace AzToolsFramework::Prefab { using PrefabFocusOperationResult = AZ::Outcome; - //! Interface to handle operations related to the Prefab Focus system. + //! Interface to handle internal operations related to the Prefab Focus system. class PrefabFocusInterface { public: @@ -28,29 +28,13 @@ namespace AzToolsFramework::Prefab //! Set the focused prefab instance to the owning instance of the entityId provided. //! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on. - virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0; - - //! Set the focused prefab instance to the instance at position index of the current path. - //! @param index The index of the instance in the current path that we want the prefab system to focus on. - virtual PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) = 0; + virtual PrefabFocusOperationResult FocusOnPrefabInstanceOwningEntityId(AZ::EntityId entityId) = 0; //! Returns the template id of the instance the prefab system is focusing on. virtual TemplateId GetFocusedPrefabTemplateId(AzFramework::EntityContextId entityContextId) const = 0; //! Returns a reference to the instance the prefab system is focusing on. virtual InstanceOptionalReference GetFocusedPrefabInstance(AzFramework::EntityContextId entityContextId) const = 0; - - //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. - //! @param entityId The entityId of the queried entity. - //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. - virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const = 0; - - //! Returns the path from the root instance to the currently focused instance. - //! @return A path composed from the names of the container entities for the instance path. - virtual const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const = 0; - - //! Returns the size of the path to the currently focused instance. - virtual const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const = 0; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusPublicInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusPublicInterface.h new file mode 100644 index 0000000000..86e476b56f --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusPublicInterface.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include + +#include +#include + +namespace AzToolsFramework::Prefab +{ + using PrefabFocusOperationResult = AZ::Outcome; + + //! Public Interface for external systems to utilize the Prefab Focus system. + class PrefabFocusPublicInterface + { + public: + AZ_RTTI(PrefabFocusPublicInterface, "{53EE1D18-A41F-4DB1-9B73-9448F425722E}"); + + //! Set the focused prefab instance to the owning instance of the entityId provided. Supports undo/redo. + //! @param entityId The entityId of the entity whose owning instance we want the prefab system to focus on. + virtual PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) = 0; + + //! Set the focused prefab instance to the instance at position index of the current path. Supports undo/redo. + //! @param index The index of the instance in the current path that we want the prefab system to focus on. + virtual PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) = 0; + + //! Returns the entity id of the container entity for the instance the prefab system is focusing on. + virtual AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const = 0; + + //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. + //! @param entityId The entityId of the queried entity. + //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. + virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const = 0; + + //! Returns the path from the root instance to the currently focused instance. + //! @return A path composed from the names of the container entities for the instance path. + virtual const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const = 0; + + //! Returns the size of the path to the currently focused instance. + virtual const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const = 0; + }; + +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.cpp new file mode 100644 index 0000000000..e5f664ea38 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include +#include +#include + +namespace AzToolsFramework::Prefab +{ + PrefabFocusUndo::PrefabFocusUndo(const AZStd::string& undoOperationName) + : UndoSystem::URSequencePoint(undoOperationName) + { + m_prefabFocusInterface = AZ::Interface::Get(); + AZ_Assert(m_prefabFocusInterface, "PrefabFocusUndo - Failed to grab prefab focus interface"); + + m_prefabFocusPublicInterface = AZ::Interface::Get(); + AZ_Assert(m_prefabFocusPublicInterface, "PrefabFocusUndo - Failed to grab prefab focus public interface"); + } + + bool PrefabFocusUndo::Changed() const + { + return true; + } + + void PrefabFocusUndo::Capture(AZ::EntityId entityId) + { + auto entityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(entityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + m_beforeEntityId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(entityContextId); + m_afterEntityId = entityId; + } + + void PrefabFocusUndo::Undo() + { + m_prefabFocusInterface->FocusOnPrefabInstanceOwningEntityId(m_beforeEntityId); + } + + void PrefabFocusUndo::Redo() + { + m_prefabFocusInterface->FocusOnPrefabInstanceOwningEntityId(m_afterEntityId); + } + +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.h new file mode 100644 index 0000000000..3b257b6547 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusUndo.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework::Prefab +{ + class PrefabFocusInterface; + class PrefabFocusPublicInterface; + + //! Undo node for prefab focus change operations. + class PrefabFocusUndo + : public UndoSystem::URSequencePoint + { + public: + explicit PrefabFocusUndo(const AZStd::string& undoOperationName); + + bool Changed() const override; + void Capture(AZ::EntityId entityId); + + void Undo() override; + void Redo() override; + + protected: + PrefabFocusInterface* m_prefabFocusInterface = nullptr; + PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; + + AZ::EntityId m_beforeEntityId; + AZ::EntityId m_afterEntityId; + }; +} // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 459b39a290..3b48cc4967 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -324,7 +324,8 @@ namespace AzToolsFramework // Currently, the first behavior is implemented. void EntityOutlinerWidget::OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { - if (m_selectionChangeInProgress || !m_enableSelectionUpdates) + if (m_selectionChangeInProgress || !m_enableSelectionUpdates + || (selected.empty() && deselected.empty())) { return; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 24cb71499e..6ffa3aab69 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -24,11 +24,11 @@ #include #include #include -#include +#include +#include +#include #include #include -#include -#include #include #include #include @@ -39,7 +39,6 @@ #include #include - #include #include #include @@ -56,14 +55,13 @@ #include #include - namespace AzToolsFramework { namespace Prefab { ContainerEntityInterface* PrefabIntegrationManager::s_containerEntityInterface = nullptr; EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr; - PrefabFocusInterface* PrefabIntegrationManager::s_prefabFocusInterface = nullptr; + PrefabFocusPublicInterface* PrefabIntegrationManager::s_prefabFocusPublicInterface = nullptr; PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr; PrefabPublicInterface* PrefabIntegrationManager::s_prefabPublicInterface = nullptr; PrefabSystemComponentInterface* PrefabIntegrationManager::s_prefabSystemComponentInterface = nullptr; @@ -129,10 +127,10 @@ namespace AzToolsFramework return; } - s_prefabFocusInterface = AZ::Interface::Get(); - if (s_prefabFocusInterface == nullptr) + s_prefabFocusPublicInterface = AZ::Interface::Get(); + if (s_prefabFocusPublicInterface == nullptr) { - AZ_Assert(false, "Prefab - could not get PrefabFocusInterface on PrefabIntegrationManager construction."); + AZ_Assert(false, "Prefab - could not get PrefabFocusPublicInterface on PrefabIntegrationManager construction."); return; } @@ -247,12 +245,8 @@ namespace AzToolsFramework if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity)) { // Edit Prefab - if (prefabWipFeaturesEnabled) + if (prefabWipFeaturesEnabled && !s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity)) { - bool beingEdited = s_prefabFocusInterface->IsOwningPrefabBeingFocused(selectedEntity); - - if (!beingEdited) - { QAction* editAction = menu->addAction(QObject::tr("Edit Prefab")); editAction->setToolTip(QObject::tr("Edit the prefab in focus mode.")); @@ -261,7 +255,6 @@ namespace AzToolsFramework }); itemWasShown = true; - } } // Save Prefab @@ -317,7 +310,7 @@ namespace AzToolsFramework void PrefabIntegrationManager::OnEscape() { - s_prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); + s_prefabFocusPublicInterface->FocusOnOwningPrefab(AZ::EntityId()); } void PrefabIntegrationManager::HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const @@ -490,7 +483,7 @@ namespace AzToolsFramework void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity) { - s_prefabFocusInterface->FocusOnOwningPrefab(containerEntity); + s_prefabFocusPublicInterface->FocusOnOwningPrefab(containerEntity); } void PrefabIntegrationManager::ContextMenu_SavePrefab(AZ::EntityId containerEntity) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 6788af31e9..e8c10c150a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -30,7 +30,7 @@ namespace AzToolsFramework namespace Prefab { - class PrefabFocusInterface; + class PrefabFocusPublicInterface; class PrefabLoaderInterface; //! Structure for saving/retrieving user settings related to prefab workflows. @@ -144,7 +144,7 @@ namespace AzToolsFramework static ContainerEntityInterface* s_containerEntityInterface; static EditorEntityUiInterface* s_editorEntityUiInterface; - static PrefabFocusInterface* s_prefabFocusInterface; + static PrefabFocusPublicInterface* s_prefabFocusPublicInterface; static PrefabLoaderInterface* s_prefabLoaderInterface; static PrefabPublicInterface* s_prefabPublicInterface; static PrefabSystemComponentInterface* s_prefabSystemComponentInterface; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp index 7d1f3485aa..00522b29dc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp @@ -10,7 +10,7 @@ #include -#include +#include #include #include @@ -35,10 +35,10 @@ namespace AzToolsFramework return; } - m_prefabFocusInterface = AZ::Interface::Get(); - if (m_prefabFocusInterface == nullptr) + m_prefabFocusPublicInterface = AZ::Interface::Get(); + if (m_prefabFocusPublicInterface == nullptr) { - AZ_Assert(false, "PrefabUiHandler - could not get PrefabFocusInterface on PrefabUiHandler construction."); + AZ_Assert(false, "PrefabUiHandler - could not get PrefabFocusPublicInterface on PrefabUiHandler construction."); return; } } @@ -83,7 +83,7 @@ namespace AzToolsFramework QIcon PrefabUiHandler::GenerateItemIcon(AZ::EntityId entityId) const { - if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId)) + if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId)) { return QIcon(m_prefabEditIconPath); } @@ -105,7 +105,7 @@ namespace AzToolsFramework const bool hasVisibleChildren = index.data(EntityOutlinerListModel::ExpandedRole).value() && index.model()->hasChildren(index); QColor backgroundColor = m_prefabCapsuleColor; - if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId)) + if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId)) { backgroundColor = m_prefabCapsuleEditColor; } @@ -191,7 +191,7 @@ namespace AzToolsFramework const bool isLastColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnLockToggle; QColor borderColor = m_prefabCapsuleColor; - if (m_prefabFocusInterface->IsOwningPrefabBeingFocused(entityId)) + if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId)) { borderColor = m_prefabCapsuleEditColor; } @@ -329,7 +329,7 @@ namespace AzToolsFramework if (prefabWipFeaturesEnabled) { // Focus on this prefab - m_prefabFocusInterface->FocusOnOwningPrefab(entityId); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId); } } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h index bb7168f409..7c68d9fd95 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h @@ -15,7 +15,7 @@ namespace AzToolsFramework namespace Prefab { - class PrefabFocusInterface; + class PrefabFocusPublicInterface; class PrefabPublicInterface; }; @@ -39,7 +39,7 @@ namespace AzToolsFramework void OnDoubleClick(AZ::EntityId entityId) const override; private: - Prefab::PrefabFocusInterface* m_prefabFocusInterface = nullptr; + Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr; static bool IsLastVisibleChild(const QModelIndex& parent, const QModelIndex& child); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index 6b0de5dc53..21ada94184 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -8,7 +8,7 @@ #include -#include +#include namespace AzToolsFramework::Prefab { @@ -31,8 +31,8 @@ namespace AzToolsFramework::Prefab void PrefabViewportFocusPathHandler::Initialize(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton) { // Get reference to the PrefabFocusInterface handler - m_prefabFocusInterface = AZ::Interface::Get(); - if (m_prefabFocusInterface == nullptr) + m_prefabFocusPublicInterface = AZ::Interface::Get(); + if (m_prefabFocusPublicInterface == nullptr) { AZ_Assert(false, "Prefab - could not get PrefabFocusInterface on PrefabViewportFocusPathHandler construction."); return; @@ -46,7 +46,7 @@ namespace AzToolsFramework::Prefab connect(m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, [&](const QString&, int linkIndex) { - m_prefabFocusInterface->FocusOnPathIndex(m_editorEntityContextId, linkIndex); + m_prefabFocusPublicInterface->FocusOnPathIndex(m_editorEntityContextId, linkIndex); } ); @@ -54,9 +54,9 @@ namespace AzToolsFramework::Prefab connect(m_backButton, &QToolButton::clicked, this, [&]() { - if (int length = m_prefabFocusInterface->GetPrefabFocusPathLength(m_editorEntityContextId); length > 1) + if (int length = m_prefabFocusPublicInterface->GetPrefabFocusPathLength(m_editorEntityContextId); length > 1) { - m_prefabFocusInterface->FocusOnPathIndex(m_editorEntityContextId, length - 2); + m_prefabFocusPublicInterface->FocusOnPathIndex(m_editorEntityContextId, length - 2); } } ); @@ -65,7 +65,7 @@ namespace AzToolsFramework::Prefab void PrefabViewportFocusPathHandler::OnPrefabFocusChanged() { // Push new Path - m_breadcrumbsWidget->pushPath(m_prefabFocusInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str()); + m_breadcrumbsWidget->pushPath(m_prefabFocusPublicInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str()); } } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h index ce7744fb1b..a97db60e34 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.h @@ -19,7 +19,7 @@ namespace AzToolsFramework::Prefab { - class PrefabFocusInterface; + class PrefabFocusPublicInterface; class PrefabViewportFocusPathHandler : public PrefabFocusNotificationBus::Handler @@ -40,6 +40,6 @@ namespace AzToolsFramework::Prefab AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull(); - PrefabFocusInterface* m_prefabFocusInterface = nullptr; + PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 37559564db..8dec7ab611 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -646,6 +646,9 @@ set(FILES Prefab/PrefabFocusHandler.cpp Prefab/PrefabFocusInterface.h Prefab/PrefabFocusNotificationBus.h + Prefab/PrefabFocusPublicInterface.h + Prefab/PrefabFocusUndo.h + Prefab/PrefabFocusUndo.cpp Prefab/PrefabIdTypes.h Prefab/PrefabLoader.h Prefab/PrefabLoader.cpp diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp index 72489b07a1..86c73e72e5 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace UnitTest @@ -72,6 +73,9 @@ namespace UnitTest m_prefabFocusInterface = AZ::Interface::Get(); ASSERT_TRUE(m_prefabFocusInterface != nullptr); + m_prefabFocusPublicInterface = AZ::Interface::Get(); + ASSERT_TRUE(m_prefabFocusPublicInterface != nullptr); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( m_editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); @@ -91,6 +95,7 @@ namespace UnitTest AZStd::unique_ptr m_rootInstance; PrefabFocusInterface* m_prefabFocusInterface = nullptr; + PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull(); inline static const char* CityEntityName = "City"; @@ -105,7 +110,7 @@ namespace UnitTest { // Verify FocusOnOwningPrefab works when passing the container entity of the root prefab. { - m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); EXPECT_EQ( m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), m_instanceMap[CityEntityName]->GetTemplateId()); @@ -120,7 +125,7 @@ namespace UnitTest { // Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab. { - m_prefabFocusInterface->FocusOnOwningPrefab(m_entityMap[CityEntityName]->GetId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_entityMap[CityEntityName]->GetId()); EXPECT_EQ( m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), m_instanceMap[CityEntityName]->GetTemplateId()); @@ -135,7 +140,7 @@ namespace UnitTest { // Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab. { - m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CarEntityName]->GetContainerEntityId()); EXPECT_EQ( m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), m_instanceMap[CarEntityName]->GetTemplateId()); @@ -149,7 +154,7 @@ namespace UnitTest { // Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab. { - m_prefabFocusInterface->FocusOnOwningPrefab(m_entityMap[Passenger1EntityName]->GetId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_entityMap[Passenger1EntityName]->GetId()); EXPECT_EQ( m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), m_instanceMap[CarEntityName]->GetTemplateId()); @@ -169,7 +174,7 @@ namespace UnitTest prefabEditorEntityOwnershipInterface->GetRootPrefabInstance(); EXPECT_TRUE(rootPrefabInstance.has_value()); - m_prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(AZ::EntityId()); EXPECT_EQ( m_prefabFocusInterface->GetFocusedPrefabTemplateId(m_editorEntityContextId), rootPrefabInstance->get().GetTemplateId()); @@ -183,10 +188,10 @@ namespace UnitTest { // Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested) { - m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[CityEntityName]->GetContainerEntityId()); - EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); - EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); + EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); + EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); } } @@ -194,13 +199,13 @@ namespace UnitTest { // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants) { - m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[StreetEntityName]->GetContainerEntityId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[StreetEntityName]->GetContainerEntityId()); - EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[StreetEntityName]->GetContainerEntityId())); - EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); - EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); - EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); - EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); + EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[StreetEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CityEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[CityEntityName]->GetId())); + EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); } } @@ -208,12 +213,12 @@ namespace UnitTest { // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings) { - m_prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap[SportsCarEntityName]->GetContainerEntityId()); + m_prefabFocusPublicInterface->FocusOnOwningPrefab(m_instanceMap[SportsCarEntityName]->GetContainerEntityId()); - EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[SportsCarEntityName]->GetContainerEntityId())); - EXPECT_TRUE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger2EntityName]->GetId())); - EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); - EXPECT_FALSE(m_prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); + EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[SportsCarEntityName]->GetContainerEntityId())); + EXPECT_TRUE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger2EntityName]->GetId())); + EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_instanceMap[CarEntityName]->GetContainerEntityId())); + EXPECT_FALSE(m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(m_entityMap[Passenger1EntityName]->GetId())); } } From 10ab1a369fed6767a371b6afa89371ba6cb9ef01 Mon Sep 17 00:00:00 2001 From: AMZN-nggieber <52797929+AMZN-nggieber@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:52:44 -0700 Subject: [PATCH 232/293] Adds Download status info UI to Gem Catalog (#4602) * Adds Download status info UI to Gem Catalog Signed-off-by: nggieber * Removed test code Signed-off-by: nggieber * Remove unused variable Signed-off-by: nggieber * Addressed PR feedback Signed-off-by: nggieber * Fixed Open3DEngine spelling Signed-off-by: nggieber --- .../ProjectManager/Resources/Download.svg | 3 + .../Resources/ProjectManager.qrc | 4 +- .../Resources/{FeatureTagClose.svg => X.svg} | 0 .../ProjectManager/Resources/in_progress.gif | 3 + .../Source/GemCatalog/GemFilterTagWidget.cpp | 2 +- .../Source/GemCatalog/GemInfo.cpp | 48 ++++++++---- .../Source/GemCatalog/GemInfo.h | 15 +++- .../Source/GemCatalog/GemItemDelegate.cpp | 77 ++++++++++++++++++- .../Source/GemCatalog/GemItemDelegate.h | 23 ++++-- .../Source/GemCatalog/GemListHeaderWidget.cpp | 4 +- .../Source/GemCatalog/GemListView.cpp | 15 +++- .../Source/GemCatalog/GemModel.cpp | 11 +++ .../Source/GemCatalog/GemModel.h | 5 +- .../ProjectManager/Source/PythonBindings.cpp | 16 +++- 14 files changed, 194 insertions(+), 32 deletions(-) create mode 100644 Code/Tools/ProjectManager/Resources/Download.svg rename Code/Tools/ProjectManager/Resources/{FeatureTagClose.svg => X.svg} (100%) create mode 100644 Code/Tools/ProjectManager/Resources/in_progress.gif diff --git a/Code/Tools/ProjectManager/Resources/Download.svg b/Code/Tools/ProjectManager/Resources/Download.svg new file mode 100644 index 0000000000..c2b0c2ce3c --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/Download.svg @@ -0,0 +1,3 @@ + + + diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc index 30bcc1ace5..aeaf9a9248 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc @@ -34,9 +34,11 @@ Warning.svg Backgrounds/DefaultBackground.jpg Backgrounds/FtueBackground.jpg - FeatureTagClose.svg + X.svg Refresh.svg Edit.svg Delete.svg + Download.svg + in_progress.gif diff --git a/Code/Tools/ProjectManager/Resources/FeatureTagClose.svg b/Code/Tools/ProjectManager/Resources/X.svg similarity index 100% rename from Code/Tools/ProjectManager/Resources/FeatureTagClose.svg rename to Code/Tools/ProjectManager/Resources/X.svg diff --git a/Code/Tools/ProjectManager/Resources/in_progress.gif b/Code/Tools/ProjectManager/Resources/in_progress.gif new file mode 100644 index 0000000000..eb392a9b89 --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/in_progress.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64985a78205da45f4bb92b040c348d96fe7cd7277549c1f79c430469a0d3bab7 +size 166393 diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.cpp index 138880f44e..69a883d169 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.cpp @@ -33,7 +33,7 @@ namespace O3DE::ProjectManager m_closeButton = new QPushButton(); m_closeButton->setFlat(true); - m_closeButton->setIcon(QIcon(":/FeatureTagClose.svg")); + m_closeButton->setIcon(QIcon(":/X.svg")); m_closeButton->setIconSize(QSize(12, 12)); m_closeButton->setStyleSheet("QPushButton { background-color: transparent; border: 0px }"); layout->addWidget(m_closeButton); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp index 771d644617..cbdcf64162 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp @@ -8,6 +8,8 @@ #include "GemInfo.h" +#include + namespace O3DE::ProjectManager { GemInfo::GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded) @@ -29,17 +31,17 @@ namespace O3DE::ProjectManager switch (platform) { case Android: - return "Android"; + return QObject::tr("Android"); case iOS: - return "iOS"; + return QObject::tr("iOS"); case Linux: - return "Linux"; + return QObject::tr("Linux"); case macOS: - return "macOS"; + return QObject::tr("macOS"); case Windows: - return "Windows"; + return QObject::tr("Windows"); default: - return ""; + return QObject::tr(""); } } @@ -48,13 +50,13 @@ namespace O3DE::ProjectManager switch (type) { case Asset: - return "Asset"; + return QObject::tr("Asset"); case Code: - return "Code"; + return QObject::tr("Code"); case Tool: - return "Tool"; + return QObject::tr("Tool"); default: - return ""; + return QObject::tr(""); } } @@ -62,15 +64,33 @@ namespace O3DE::ProjectManager { switch (origin) { - case Open3DEEngine: - return "Open 3D Engine"; + case Open3DEngine: + return QObject::tr("Open 3D Engine"); case Local: - return "Local"; + return QObject::tr("Local"); + case Remote: + return QObject::tr("Remote"); default: - return ""; + return QObject::tr(""); } } + QString GemInfo::GetDownloadStatusString(DownloadStatus status) + { + switch (status) + { + case NotDownloaded: + return QObject::tr("Not Downloaded"); + case Downloading: + return QObject::tr("Downloading"); + case Downloaded: + return QObject::tr("Downloaded"); + case UnknownDownloadStatus: + default: + return QObject::tr(""); + } + }; + bool GemInfo::IsPlatformSupported(Platform platform) const { return (m_platforms & platform); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h index 311eeb93f6..8c6d40505a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h @@ -44,13 +44,23 @@ namespace O3DE::ProjectManager enum GemOrigin { - Open3DEEngine = 1 << 0, + Open3DEngine = 1 << 0, Local = 1 << 1, - NumGemOrigins = 2 + Remote = 1 << 2, + NumGemOrigins = 3 }; Q_DECLARE_FLAGS(GemOrigins, GemOrigin) static QString GetGemOriginString(GemOrigin origin); + enum DownloadStatus + { + UnknownDownloadStatus = -1, + NotDownloaded, + Downloading, + Downloaded, + }; + static QString GetDownloadStatusString(DownloadStatus status); + GemInfo() = default; GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded); bool IsPlatformSupported(Platform platform) const; @@ -68,6 +78,7 @@ namespace O3DE::ProjectManager QString m_summary = "No summary provided."; Platforms m_platforms; Types m_types; //! Asset and/or Code and/or Tool + DownloadStatus m_downloadStatus = UnknownDownloadStatus; QStringList m_features; QString m_requirement; QString m_directoryLink; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index 2c7f17db32..e15c4b3b39 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -10,6 +10,7 @@ #include #include #include + #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -32,6 +34,11 @@ namespace O3DE::ProjectManager AddPlatformIcon(GemInfo::Linux, ":/Linux.svg"); AddPlatformIcon(GemInfo::macOS, ":/macOS.svg"); AddPlatformIcon(GemInfo::Windows, ":/Windows.svg"); + + SetStatusIcon(m_notDownloadedPixmap, ":/Download.svg"); + SetStatusIcon(m_unknownStatusPixmap, ":/X.svg"); + + m_downloadingMovie = new QMovie(":/in_progress.gif"); } void GemItemDelegate::AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath) @@ -41,6 +48,25 @@ namespace O3DE::ProjectManager m_platformIcons.insert(platform, QIcon(iconPath).pixmap(static_cast(static_cast(s_platformIconSize) * aspectRatio), s_platformIconSize)); } + void GemItemDelegate::SetStatusIcon(QPixmap& m_iconPixmap, const QString& iconPath) + { + QPixmap pixmap(iconPath); + float aspectRatio = static_cast(pixmap.width()) / pixmap.height(); + int xScaler = s_statusIconSize; + int yScaler = s_statusIconSize; + + if (aspectRatio > 1.0f) + { + yScaler = static_cast(1.0f / aspectRatio * s_statusIconSize); + } + else if (aspectRatio < 1.0f) + { + xScaler = static_cast(aspectRatio * s_statusIconSize); + } + + m_iconPixmap = QPixmap(QIcon(iconPath).pixmap(xScaler, yScaler)); + } + void GemItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const { if (!modelIndex.isValid()) @@ -56,6 +82,8 @@ namespace O3DE::ProjectManager QRect fullRect, itemRect, contentRect; CalcRects(options, fullRect, itemRect, contentRect); + QRect buttonRect = CalcButtonRect(contentRect); + QFont standardFont(options.font); standardFont.setPixelSize(static_cast(s_fontSize)); QFontMetrics standardFontMetrics(standardFont); @@ -114,7 +142,8 @@ namespace O3DE::ProjectManager const QRect summaryRect = CalcSummaryRect(contentRect, hasTags); DrawText(summary, painter, summaryRect, standardFont); - DrawButton(painter, contentRect, modelIndex); + DrawDownloadStatusIcon(painter, contentRect, buttonRect, modelIndex); + DrawButton(painter, buttonRect, modelIndex); DrawPlatformIcons(painter, contentRect, modelIndex); DrawFeatureTags(painter, contentRect, featureTags, standardFont, summaryRect); @@ -270,7 +299,7 @@ namespace O3DE::ProjectManager QRect GemItemDelegate::CalcButtonRect(const QRect& contentRect) const { - const QPoint topLeft = QPoint(contentRect.right() - s_buttonWidth - s_itemMargins.right(), contentRect.top() + contentRect.height() / 2 - s_buttonHeight / 2); + const QPoint topLeft = QPoint(contentRect.right() - s_buttonWidth, contentRect.center().y() - s_buttonHeight / 2); const QSize size = QSize(s_buttonWidth, s_buttonHeight); return QRect(topLeft, size); } @@ -378,10 +407,9 @@ namespace O3DE::ProjectManager painter->restore(); } - void GemItemDelegate::DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const + void GemItemDelegate::DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const { painter->save(); - const QRect buttonRect = CalcButtonRect(contentRect); QPoint circleCenter; if (GemModel::IsAdded(modelIndex)) @@ -427,4 +455,45 @@ namespace O3DE::ProjectManager return QString(); } + + void GemItemDelegate::DrawDownloadStatusIcon(QPainter* painter, const QRect& contentRect, const QRect& buttonRect, const QModelIndex& modelIndex) const + { + const GemInfo::DownloadStatus downloadStatus = GemModel::GetDownloadStatus(modelIndex); + + // Show no icon if gem is already downloaded + if (downloadStatus == GemInfo::DownloadStatus::Downloaded) + { + return; + } + + QPixmap currentFrame; + const QPixmap* statusPixmap; + if (downloadStatus == GemInfo::DownloadStatus::Downloading) + { + if (m_downloadingMovie->state() != QMovie::Running) + { + m_downloadingMovie->start(); + emit MovieStartedPlaying(m_downloadingMovie); + } + + currentFrame = m_downloadingMovie->currentPixmap(); + currentFrame = currentFrame.scaled(s_statusIconSize, s_statusIconSize); + statusPixmap = ¤tFrame; + } + else if (downloadStatus == GemInfo::DownloadStatus::NotDownloaded) + { + statusPixmap = &m_notDownloadedPixmap; + } + else + { + statusPixmap = &m_unknownStatusPixmap; + } + + QSize statusSize = statusPixmap->size(); + + painter->drawPixmap( + buttonRect.left() - s_statusButtonSpacing - statusSize.width(), + contentRect.center().y() - statusSize.height() / 2, + *statusPixmap); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h index 52b5a4f58e..c013be0d9e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h @@ -49,13 +49,13 @@ namespace O3DE::ProjectManager // Margin and borders inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/16, /*top=*/8, /*right=*/16, /*bottom=*/8); // Item border distances - inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/12, /*right=*/15, /*bottom=*/12); // Distances of the elements within an item to the item borders + inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/12, /*right=*/20, /*bottom=*/12); // Distances of the elements within an item to the item borders inline constexpr static int s_borderWidth = 4; // Button - inline constexpr static int s_buttonWidth = 55; - inline constexpr static int s_buttonHeight = 18; - inline constexpr static int s_buttonBorderRadius = 9; + inline constexpr static int s_buttonWidth = 32; + inline constexpr static int s_buttonHeight = 16; + inline constexpr static int s_buttonBorderRadius = s_buttonHeight / 2; inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2; inline constexpr static qreal s_buttonFontSize = 10.0; @@ -65,6 +65,9 @@ namespace O3DE::ProjectManager inline constexpr static int s_featureTagBorderMarginY = 3; inline constexpr static int s_featureTagSpacing = 7; + signals: + void MovieStartedPlaying(const QMovie* playingMovie) const; + protected: bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override; bool helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) override; @@ -74,9 +77,10 @@ namespace O3DE::ProjectManager QRect CalcButtonRect(const QRect& contentRect) const; QRect CalcSummaryRect(const QRect& contentRect, bool hasTags) const; void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; - void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; + void DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const; void DrawFeatureTags(QPainter* painter, const QRect& contentRect, const QStringList& featureTags, const QFont& standardFont, const QRect& summaryRect) const; void DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const; + void DrawDownloadStatusIcon(QPainter* painter, const QRect& contentRect, const QRect& buttonRect, const QModelIndex& modelIndex) const; QAbstractItemModel* m_model = nullptr; @@ -85,5 +89,14 @@ namespace O3DE::ProjectManager void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath); inline constexpr static int s_platformIconSize = 12; QHash m_platformIcons; + + // Status icons + void SetStatusIcon(QPixmap& m_iconPixmap, const QString& iconPath); + inline constexpr static int s_statusIconSize = 16; + inline constexpr static int s_statusButtonSpacing = 5; + + QPixmap m_unknownStatusPixmap; + QPixmap m_notDownloadedPixmap; + QMovie* m_downloadingMovie = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp index ab51c7511c..10ff31f33b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp @@ -103,11 +103,11 @@ namespace O3DE::ProjectManager QSpacerItem* horizontalSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); columnHeaderLayout->addSpacerItem(horizontalSpacer); - QLabel* gemSelectedLabel = new QLabel(tr("Selected")); + QLabel* gemSelectedLabel = new QLabel(tr("Status")); gemSelectedLabel->setObjectName("GemCatalogHeaderLabel"); columnHeaderLayout->addWidget(gemSelectedLabel); - columnHeaderLayout->addSpacing(65); + columnHeaderLayout->addSpacing(72); vLayout->addLayout(columnHeaderLayout); } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp index f5b54a364b..cfdf7fa5b3 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace O3DE::ProjectManager { GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent) @@ -19,6 +21,17 @@ namespace O3DE::ProjectManager setModel(model); setSelectionModel(selectionModel); - setItemDelegate(new GemItemDelegate(model, this)); + GemItemDelegate* itemDelegate = new GemItemDelegate(model, this); + + connect(itemDelegate, &GemItemDelegate::MovieStartedPlaying, [=](const QMovie* playingMovie) + { + // Force redraw when movie is playing so animation is smooth + connect(playingMovie, &QMovie::frameChanged, this, [=] + { + this->viewport()->repaint(); + }); + }); + + setItemDelegate(itemDelegate); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index c8911de360..35491f4ddd 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -48,6 +48,7 @@ namespace O3DE::ProjectManager item->setData(gemInfo.m_features, RoleFeatures); item->setData(gemInfo.m_path, RolePath); item->setData(gemInfo.m_requirement, RoleRequirement); + item->setData(gemInfo.m_downloadStatus, RoleDownloadStatus); appendRow(item); @@ -132,6 +133,11 @@ namespace O3DE::ProjectManager return static_cast(modelIndex.data(RoleTypes).toInt()); } + GemInfo::DownloadStatus GemModel::GetDownloadStatus(const QModelIndex& modelIndex) + { + return static_cast(modelIndex.data(RoleDownloadStatus).toInt()); + } + QString GemModel::GetSummary(const QModelIndex& modelIndex) { return modelIndex.data(RoleSummary).toString(); @@ -373,6 +379,11 @@ namespace O3DE::ProjectManager return previouslyAdded && !added; } + void GemModel::SetDownloadStatus(QAbstractItemModel& model, const QModelIndex& modelIndex, GemInfo::DownloadStatus status) + { + model.setData(modelIndex, status, RoleDownloadStatus); + } + bool GemModel::HasRequirement(const QModelIndex& modelIndex) { return !modelIndex.data(RoleRequirement).toString().isEmpty(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index ef2d1a903d..0d1c225f74 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -40,6 +40,7 @@ namespace O3DE::ProjectManager static GemInfo::GemOrigin GetGemOrigin(const QModelIndex& modelIndex); static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex); static GemInfo::Types GetTypes(const QModelIndex& modelIndex); + static GemInfo::DownloadStatus GetDownloadStatus(const QModelIndex& modelIndex); static QString GetSummary(const QModelIndex& modelIndex); static QString GetDirectoryLink(const QModelIndex& modelIndex); static QString GetDocLink(const QModelIndex& modelIndex); @@ -64,6 +65,7 @@ namespace O3DE::ProjectManager static bool NeedsToBeRemoved(const QModelIndex& modelIndex, bool includeDependencies = false); static bool HasRequirement(const QModelIndex& modelIndex); static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex); + static void SetDownloadStatus(QAbstractItemModel& model, const QModelIndex& modelIndex, GemInfo::DownloadStatus status); bool DoGemsToBeAddedHaveRequirements() const; bool HasDependentGemsToRemove() const; @@ -101,7 +103,8 @@ namespace O3DE::ProjectManager RoleFeatures, RoleTypes, RolePath, - RoleRequirement + RoleRequirement, + RoleDownloadStatus }; QHash m_nameToIndexMap; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 83f93630ac..d91f08c73e 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -668,7 +668,21 @@ namespace O3DE::ProjectManager if (gemInfo.m_creator.contains("Open 3D Engine")) { - gemInfo.m_gemOrigin = GemInfo::GemOrigin::Open3DEEngine; + gemInfo.m_gemOrigin = GemInfo::GemOrigin::Open3DEngine; + } + else if (gemInfo.m_creator.contains("Amazon Web Services")) + { + gemInfo.m_gemOrigin = GemInfo::GemOrigin::Local; + } + else if (data.contains("origin")) + { + gemInfo.m_gemOrigin = GemInfo::GemOrigin::Remote; + } + + // As long Base Open3DEngine gems are installed before first startup non-remote gems will be downloaded + if (gemInfo.m_gemOrigin != GemInfo::GemOrigin::Remote) + { + gemInfo.m_downloadStatus = GemInfo::DownloadStatus::Downloaded; } if (data.contains("user_tags")) From 718fc97bb66d07a0f04c41c100783c5c8a6adbec Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Wed, 13 Oct 2021 12:57:31 -0700 Subject: [PATCH 233/293] changes from review feedback Signed-off-by: Scott Murray --- ...mponents_PostFxShapeWeightModifierAdded.py | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py index fe6362c9b7..0ba7038c47 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py @@ -24,12 +24,9 @@ class Tests: postfx_layer_component = ( "Entity has a PostFX Layer component", "Entity did not have an PostFX Layer component") - shape_component = ( + tube_shape_component = ( "Entity has a Tube Shape component", "Entity did not have a Tube Shape component") - shape_undo = ( - "Entity shape component add undone", - "Entity shape component undo failed to remove shape") postfx_shape_weight_enabled = ( "PostFx Shape Weight Modifier component enabled", "PostFx Shape Weight Modifier component was not enabled.") @@ -78,8 +75,8 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): 6) Add PostFX Layer component since it is required by the PostFx Shape Weight Modifier component. 7) Verify PostFx Shape Weight Modifier component is NOT enabled since it also requires a shape. 8) Add a required shape looping over a list and checking if it enables PostFX Shape Weight Modifier. - 9) Undo to remove each added shape and verify PostFX Shape Weight Modifier is not enabled - 10) Verify PostFx Shape Weight Modifier component is enabled by adding Spline and Tube Shape componen. + 9) Undo to remove each added shape and verify PostFX Shape Weight Modifier is not enabled. + 10) Verify PostFx Shape Weight Modifier component is enabled by adding Spline and Tube Shape component. 11) Enter/Exit game mode. 12) Test IsHidden. 13) Test IsVisible. @@ -146,10 +143,10 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): postfx_shape_weight_entity.add_component(postfx_layer_name) Report.result(Tests.postfx_layer_component, postfx_shape_weight_entity.has_component(postfx_layer_name)) - # 7. Verify PostFx Shape Weight Modifier component not enabled because shape is also required. + # 7. Verify PostFx Shape Weight Modifier component is NOT enabled since it also requires a shape. Report.result(Tests.postfx_shape_weight_disabled, not postfx_shape_weight_component.is_enabled()) - # 8. Add remove each shape to test if the PostFX Shape Weight Modifier is enabled by having a required shape + # 8. Add a required shape looping over a list and checking if it enables PostFX Shape Weight Modifier. for shape in ['Axis Aligned Box Shape', 'Box Shape', 'Capsule Shape', 'Compound Shape', 'Cylinder Shape', 'Disk Shape', 'Polygon Prism Shape', 'Quad Shape', 'Sphere Shape', 'Vegetation Reference Shape']: postfx_shape_weight_entity.add_component(shape) @@ -158,18 +155,16 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): f"Entity did not have a {shape} component") Report.result(test_shape, postfx_shape_weight_entity.has_component(shape)) - #Check if required shape allows PostFX Shape Weight Modifier to be enabled + # Check if required shape allows PostFX Shape Weight Modifier to be enabled Report.result(Tests.postfx_shape_weight_enabled, postfx_shape_weight_component.is_enabled()) - # 9. UNDO component addition and check that PostFX Shape Weight Modifier is not enabled + # 9. Undo to remove each added shape and verify PostFX Shape Weight Modifier is not enabled. general.undo() - general.idle_wait_frames(1) - Report.result(Tests.shape_undo, not postfx_shape_weight_entity.has_component(shape)) Report.result(Tests.postfx_shape_weight_disabled, not postfx_shape_weight_component.is_enabled()) - # 10. Add Tube Shape and Spline to fulfil the required shape component + # 10. Verify PostFx Shape Weight Modifier component is enabled by adding Spline and Tube Shape component. postfx_shape_weight_entity.add_components(['Spline', 'Tube Shape']) - Report.result(Tests.shape_component, postfx_shape_weight_entity.has_component('Tube Shape')) + Report.result(Tests.tube_shape_component, postfx_shape_weight_entity.has_component('Tube Shape')) Report.result(Tests.postfx_shape_weight_enabled, postfx_shape_weight_component.is_enabled()) # 11. Enter/Exit game mode. From e7d7720d020104b169b19fb9bbe323bca8b5804c Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 13 Oct 2021 15:14:14 -0500 Subject: [PATCH 234/293] Procedural Prefabs: Don't activate prefab when saving to manifest (#4663) * Generate prefab group dom without activating prefab Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Fix bad merge Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../PrefabGroup/PrefabGroupBehavior.cpp | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp index 13828e5f8c..44a95c1b6b 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp @@ -124,24 +124,10 @@ namespace AZ::SceneAPI::Behaviors return {}; } - // create instance to update the asset hints - auto instance = prefabSystemComponentInterface->InstantiatePrefab(templateId); - if (!instance) - { - AZ_Error("prefab", false, "PrefabGroup(%s) Could not instantiate prefab", prefabGroup->GetName().c_str()); - return {}; - } - - auto* instanceToTemplateInterface = AZ::Interface::Get(); - if (!instanceToTemplateInterface) - { - AZ_Error("prefab", false, "Could not get InstanceToTemplateInterface"); - return {}; - } - - // fill out a JSON DOM + const rapidjson::Document& generatedInstanceDom = prefabSystemComponentInterface->FindTemplateDom(templateId); auto proceduralPrefab = AZStd::make_unique(rapidjson::kObjectType); - instanceToTemplateInterface->GenerateDomForInstance(*proceduralPrefab.get(), *instance.get()); + proceduralPrefab->CopyFrom(generatedInstanceDom, proceduralPrefab->GetAllocator(), true); + return proceduralPrefab; } From 29b62c7b842f77872ec9467aeabb14685e5d53cc Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Wed, 13 Oct 2021 15:22:25 -0500 Subject: [PATCH 235/293] Various updates to get pak builds working (#4552) * Various updates to get pak builds working -Fix basing config file merges off engine root. -Merge command-line in relelase to make sure they override defaults. -Fix nullptrs. -Exclude more paths from being sent to bootstrap setreg. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Reverting a change that caused some test failures. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Change tabs to spaces Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> --- .../AzGameFramework/Application/GameApplication.cpp | 2 ++ .../Code/Source/Grid/GridComponentController.cpp | 4 ++++ .../Code/Source/SkyBox/HDRiSkyboxComponentController.cpp | 2 +- Registry/setregbuilder.assetprocessor.setreg | 7 ++++++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index 462de43262..0cce93d751 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -96,6 +96,8 @@ namespace AzGameFramework AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); +#else + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); #endif // Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp index 52a4cd4343..b4131894f4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp @@ -175,6 +175,10 @@ namespace AZ void GridComponentController::OnBeginPrepareRender() { auto* auxGeomFP = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_entityId); + if (!auxGeomFP) + { + return; + } if (auto auxGeom = auxGeomFP->GetDrawQueue()) { BuildGrid(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentController.cpp index b71ba1e148..171c5e417f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkyBox/HDRiSkyboxComponentController.cpp @@ -65,7 +65,7 @@ namespace AZ m_featureProcessorInterface = RPI::Scene::GetFeatureProcessorForEntity(entityId); // only activate if there is no other skybox activate - if (!m_featureProcessorInterface->IsEnabled()) + if (m_featureProcessorInterface && !m_featureProcessorInterface->IsEnabled()) { m_featureProcessorInterface->SetSkyboxMode(SkyBoxMode::Cubemap); m_featureProcessorInterface->Enable(true); diff --git a/Registry/setregbuilder.assetprocessor.setreg b/Registry/setregbuilder.assetprocessor.setreg index 00e6e2f7f8..d67b6047f6 100644 --- a/Registry/setregbuilder.assetprocessor.setreg +++ b/Registry/setregbuilder.assetprocessor.setreg @@ -20,8 +20,13 @@ "Excludes": [ "/Amazon/AzCore/Runtime", + "/Amazon/AzCore/Bootstrap/engine_path", "/Amazon/AzCore/Bootstrap/project_path", - "/O3DE/Runtime", + "/Amazon/AzCore/Bootstrap/project_cache_path", + "/Amazon/AzCore/Bootstrap/project_user_path", + "/Amazon/AzCore/Bootstrap/project_log_path", + "/Amazon/Project/Settings/Build/project_build_path", + "/O3DE/Runtime" ] } } From 3934ac24e00135d79a01101c8f590ffac088e521 Mon Sep 17 00:00:00 2001 From: allisaurus <34254888+allisaurus@users.noreply.github.com> Date: Wed, 13 Oct 2021 13:25:19 -0700 Subject: [PATCH 236/293] Add field titles, tooltips to AWSClientAuth AWSCognitoUserManagementRequestBus nodes (#4613) Signed-off-by: Stanko --- .../Source/AWSClientAuthSystemComponent.cpp | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp index dbde19aad6..92c01dab19 100644 --- a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp +++ b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp @@ -33,7 +33,7 @@ namespace AWSClientAuth AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { - serialize->Class()->Version(1); + serialize->Class()->Version(2); if (AZ::EditContext* ec = serialize->GetEditContext()) { @@ -105,12 +105,22 @@ namespace AWSClientAuth behaviorContext->EBus("AWSCognitoUserManagementRequestBus") ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Event("Initialize", &AWSCognitoUserManagementRequestBus::Events::Initialize) - ->Event("EmailSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::EmailSignUpAsync) - ->Event("PhoneSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::PhoneSignUpAsync) - ->Event("ConfirmSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmSignUpAsync) - ->Event("ForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ForgotPasswordAsync) - ->Event("ConfirmForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmForgotPasswordAsync) - ->Event("EnableMFAAsync", &AWSCognitoUserManagementRequestBus::Events::EnableMFAAsync); + ->Event( + "EmailSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::EmailSignUpAsync, + { { { "Username", "The client's username" }, { "Password", "The client's password" }, { "Email", "The email address used to sign up" } } }) + ->Event( + "PhoneSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::PhoneSignUpAsync, + { { { "Username", "The client's username" }, { "Password", "The client's password" }, { "Phone number", "The phone number used to sign up" } } }) + ->Event( + "ConfirmSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmSignUpAsync, + { { { "Username", "The client's username" }, { "Confirmation code", "The client's confirmation code" } } }) + ->Event( + "ForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ForgotPasswordAsync, + { { { "Username", "The client's username" } } }) + ->Event( + "ConfirmForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmForgotPasswordAsync, + { { { "Username", "The client's username" }, { "Confirmation code", "The client's confirmation code" }, { "New password", "The new password for the client" } } }) + ->Event("EnableMFAAsync", &AWSCognitoUserManagementRequestBus::Events::EnableMFAAsync, { { { "Access token", "The MFA access token" } } }); behaviorContext->EBus("AuthenticationProviderNotificationBus") From 3c3cde99bed5f589c7522243b029e9f79baa949d Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 13 Oct 2021 13:33:59 -0700 Subject: [PATCH 237/293] LYN-7189 | Outliner - Disable context menu if right clicking on disabled entity (#4651) * Don't allow right clicking on a non selectable entity in the Outliner Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Also check that the index is valid to still allow the right click context menu to appear on empty areas of the widget. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Change if check to a more readable bool. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 3b48cc4967..4d53102edb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -553,6 +553,13 @@ namespace AzToolsFramework return; } + // Do not display the context menu if the item under the mouse cursor is not selectable. + if (const QModelIndex& index = m_gui->m_objectTree->indexAt(pos); index.isValid() + && (index.flags() & Qt::ItemIsSelectable) == 0) + { + return; + } + QMenu* contextMenu = new QMenu(this); // Populate global context menu. From 4625e6d315fae6b343604d3e9654745bd352ee52 Mon Sep 17 00:00:00 2001 From: brianherrera Date: Wed, 13 Oct 2021 13:35:44 -0700 Subject: [PATCH 238/293] Fix indentation Signed-off-by: brianherrera --- .../build/bootstrap/incremental_build_util.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/build/bootstrap/incremental_build_util.py b/scripts/build/bootstrap/incremental_build_util.py index 6117fe0180..68e764e56f 100644 --- a/scripts/build/bootstrap/incremental_build_util.py +++ b/scripts/build/bootstrap/incremental_build_util.py @@ -333,14 +333,14 @@ def mount_volume_to_device(created): attribute disk clear readonly """.encode('utf-8')) # assume disk # for now - if created: - print('Creating filesystem on new volume') - f.write("""create partition primary - select partition 1 - format quick fs=ntfs - assign - active - """.encode('utf-8')) + if created: + print('Creating filesystem on new volume') + f.write("""create partition primary + select partition 1 + format quick fs=ntfs + assign + active + """.encode('utf-8')) subprocess.call(['diskpart', '/s', f.name]) From 5ba30f9a3746af4550ba4b0bcd89519e5375dfac Mon Sep 17 00:00:00 2001 From: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Wed, 13 Oct 2021 13:46:20 -0700 Subject: [PATCH 239/293] Update tiff to the new package revision (fixes IOS TIFF package) (#4638) The new tiff package works for all platforms, including android and IOS, which had issues before. Android - was missing tiff.h ios - wrong minimum ios revision --- Code/Editor/CMakeLists.txt | 2 +- Code/Legacy/CrySystem/CMakeLists.txt | 2 +- Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt | 2 +- cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake | 2 +- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 2 +- cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 2 +- cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 2 +- cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index 2ea0aa1a74..bdfac373eb 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -102,7 +102,7 @@ ly_add_target( 3rdParty::Qt::Gui 3rdParty::Qt::Widgets 3rdParty::Qt::Concurrent - 3rdParty::tiff + 3rdParty::TIFF 3rdParty::squish-ccr 3rdParty::AWSNativeSDK::STS Legacy::CryCommon diff --git a/Code/Legacy/CrySystem/CMakeLists.txt b/Code/Legacy/CrySystem/CMakeLists.txt index 4c1f0d9b82..ebfc866f4a 100644 --- a/Code/Legacy/CrySystem/CMakeLists.txt +++ b/Code/Legacy/CrySystem/CMakeLists.txt @@ -27,7 +27,7 @@ ly_add_target( 3rdParty::expat 3rdParty::lz4 3rdParty::md5 - 3rdParty::tiff + 3rdParty::TIFF 3rdParty::zstd Legacy::CryCommon Legacy::CrySystem.XMLBinary diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt index 836f173632..982ec43715 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/CMakeLists.txt @@ -64,7 +64,7 @@ ly_add_target( 3rdParty::Qt::Gui 3rdParty::astc-encoder 3rdParty::squish-ccr - 3rdParty::tiff + 3rdParty::TIFF 3rdParty::ISPCTexComp 3rdParty::ilmbase AZ::AzFramework diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index c1a770d1ff..9dbdbbd8aa 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -16,7 +16,7 @@ ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zst ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5) # platform-specific: -ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-android TARGETS tiff PACKAGE_HASH 252b99e5886ec59fdccf38603c1399dd3fc02d878641aba35a7f8d2504065a06) +ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev4-android TARGETS TIFF PACKAGE_HASH 2c62cdf34a8ee6c7eb091d05d98f60b4da7634c74054d4dbb8736886182f4589) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-android TARGETS freetype PACKAGE_HASH df9e4d559ea0f03b0666b48c79813b1cd4d9624429148a249865de9f5c2c11cd) ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.9.50-rev1-android TARGETS AWSNativeSDK PACKAGE_HASH 33771499f9080cbaab613459927e52911e68f94fa356397885e85005efbd1490) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-android TARGETS Lua PACKAGE_HASH 1f638e94a17a87fe9e588ea456d5893876094b4db191234380e4c4eb9e06c300) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 8e4a3ef828..d6fdc5cd9b 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -23,7 +23,7 @@ ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform # platform-specific: ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-linux TARGETS AWSGameLiftServerSDK PACKAGE_HASH a8149a95bd100384af6ade97e2b21a56173740d921e6c3da8188cd51554d39af) -ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-linux TARGETS tiff PACKAGE_HASH 19791da0a370470a6c187199f97c2c46efcc2d89146e2013775fb3600fd7317d) +ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-linux TARGETS TIFF PACKAGE_HASH 2377f48b2ebc2d1628d9f65186c881544c92891312abe478a20d10b85877409a) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-linux TARGETS freetype PACKAGE_HASH 3f10c703d9001ecd2bb51a3bd003d3237c02d8f947ad0161c0252fdc54cbcf97) ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev6-linux TARGETS AWSNativeSDK PACKAGE_HASH 490291e4c8057975c3ab86feb971b8a38871c58bac5e5d86abdd1aeb7141eec4) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-linux TARGETS Lua PACKAGE_HASH 1adc812abe3dd0dbb2ca9756f81d8f0e0ba45779ac85bf1d8455b25c531a38b0) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 631c42784a..41df718b71 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -25,7 +25,7 @@ ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform # platform-specific: ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-mac TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 3f77367dbb0342136ec4ebbd44bc1fedf7198089a0f83c5631248530769b2be6) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-mac TARGETS SPIRVCross PACKAGE_HASH 78c6376ed2fd195b9b1f5fb2b56e5267a32c3aa21fb399e905308de470eb4515) -ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-mac TARGETS tiff PACKAGE_HASH b6f3040319f5bfe465d7e3f9b12ceed0dc951e66e05562beaac1c8da3b1b5d3f) +ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-mac TARGETS TIFF PACKAGE_HASH c2615ccdadcc0e1d6c5ed61e5965c4d3a82193d206591b79b805c3b3ff35a4bf) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-mac TARGETS freetype PACKAGE_HASH f159b346ac3251fb29cb8dd5f805c99b0015ed7fdb3887f656945ca701a61d0d) ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev5-mac TARGETS AWSNativeSDK PACKAGE_HASH ffb890bd9cf23afb429b9214ad9bac1bf04696f07a0ebb93c42058c482ab2f01) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev6-mac TARGETS Lua PACKAGE_HASH b9079fd35634774c9269028447562c6b712dbc83b9c64975c095fd423ff04c08) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 428e5e9526..cccd2591e8 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -26,7 +26,7 @@ ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-windows TARGETS AWSGameLiftServerSDK PACKAGE_HASH a0586b006e4def65cc25f388de17dc475e417dc1e6f9d96749777c88aa8271b0) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 803e10b94006b834cbbdd30f562a8ddf04174c2cb6956c8399ec164ef8418d1f) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-windows TARGETS SPIRVCross PACKAGE_HASH 7d601ea9d625b1d509d38bd132a1f433d7e895b16adab76bac6103567a7a6817) -ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-windows TARGETS tiff PACKAGE_HASH ff03464ca460fc34a8406b2a0c548ad221b10e40480b0abb954f1e649c20bad0) +ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-windows TARGETS TIFF PACKAGE_HASH c6000a906e6d2a0816b652e93dfbeab41c9ed73cdd5a613acd53e553d0510b60) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-windows TARGETS freetype PACKAGE_HASH 9809255f1c59b07875097aa8d8c6c21c97c47a31fb35e30f2bb93188e99a85ff) ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-windows TARGETS AWSNativeSDK PACKAGE_HASH a900e80f7259e43aed5c847afee2599ada37f29db70505481397675bcbb6c76c) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-windows TARGETS Lua PACKAGE_HASH 136faccf1f73891e3fa3b95f908523187792e56f5b92c63c6a6d7e72d1158d40) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index abfba29e5a..8042c888c7 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -17,7 +17,7 @@ ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS gla ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5) # platform-specific: -ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-ios TARGETS tiff PACKAGE_HASH d864beb0c955a55f28c2a993843afb2ecf6e01519ddfc857cedf34fc5db68d49) +ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-ios TARGETS TIFF PACKAGE_HASH e9067e88649fb6e93a926d9ed38621a9fae360a2e6f6eb24ebca63c1bc7761ea) ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-ios TARGETS freetype PACKAGE_HASH 3ac3c35e056ae4baec2e40caa023d76a7a3320895ef172b6655e9261b0dc2e29) ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-ios TARGETS AWSNativeSDK PACKAGE_HASH d10e7496ca705577032821011beaf9f2507689f23817bfa0ed4d2a2758afcd02) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-ios TARGETS Lua PACKAGE_HASH c2d3c4e67046c293049292317a7d60fdb8f23effeea7136aefaef667163e5ffe) From b792ff3d33002c121e083562f476bacbb1c8fce0 Mon Sep 17 00:00:00 2001 From: brianherrera Date: Wed, 13 Oct 2021 14:12:18 -0700 Subject: [PATCH 240/293] Fix command formatting Signed-off-by: brianherrera --- scripts/build/bootstrap/incremental_build_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/build/bootstrap/incremental_build_util.py b/scripts/build/bootstrap/incremental_build_util.py index 68e764e56f..ff243ab02b 100644 --- a/scripts/build/bootstrap/incremental_build_util.py +++ b/scripts/build/bootstrap/incremental_build_util.py @@ -335,7 +335,8 @@ def mount_volume_to_device(created): if created: print('Creating filesystem on new volume') - f.write("""create partition primary + f.write(""" + create partition primary select partition 1 format quick fs=ntfs assign From 2b7262f566f3e27ee644c0c38de045bc93fcee6e Mon Sep 17 00:00:00 2001 From: sweeneys Date: Wed, 13 Oct 2021 14:14:01 -0700 Subject: [PATCH 241/293] Mock additional popen calls Signed-off-by: sweeneys --- Tools/LyTestTools/tests/unit/test_asset_processor.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tools/LyTestTools/tests/unit/test_asset_processor.py b/Tools/LyTestTools/tests/unit/test_asset_processor.py index aabbf2f2f5..743ca9a2e4 100755 --- a/Tools/LyTestTools/tests/unit/test_asset_processor.py +++ b/Tools/LyTestTools/tests/unit/test_asset_processor.py @@ -45,6 +45,7 @@ class TestAssetProcessor(object): @mock.patch('subprocess.Popen') @mock.patch('ly_test_tools.o3de.asset_processor.AssetProcessor.connect_socket') @mock.patch('ly_test_tools.o3de.asset_processor.ASSET_PROCESSOR_PLATFORM_MAP', {'foo': 'bar'}) + @mock.patch('time.sleep', mock.MagicMock()) def test_Start_NoneRunning_ProcStarted(self, mock_connect, mock_popen, mock_workspace): mock_ap_path = 'mock_ap_path' mock_workspace.asset_processor_platform = 'foo' @@ -54,6 +55,9 @@ class TestAssetProcessor(object): under_test = ly_test_tools.o3de.asset_processor.AssetProcessor(mock_workspace) under_test.enable_asset_processor_platform = mock.MagicMock() under_test.wait_for_idle = mock.MagicMock() + mock_proc_object = mock.MagicMock() + mock_proc_object.poll.return_value = None + mock_popen.return_value = mock_proc_object under_test.start(connect_to_ap=True) From f7e2d07a4be6554141956246120d0a76f224b183 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 13 Oct 2021 14:17:09 -0700 Subject: [PATCH 242/293] LYN-7333 | Fix multiple selection by dragging to take focus mode and containers into account. (#4620) * Change FocusModeNotificationBus's OnEditorFocusChanged arguments to also pass the previous focus root entity id. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add focus mode and container entity states to the visibility cache for the viewport. Use that data to correctly select entities when a rect is dragged on the viewport. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor code adjustments Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor fixes and optimizations Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../FocusMode/FocusModeNotificationBus.h | 6 +- .../FocusMode/FocusModeSystemComponent.cpp | 3 +- .../UI/Outliner/EntityOutlinerTreeView.cpp | 3 +- .../UI/Outliner/EntityOutlinerTreeView.hxx | 2 +- .../EditorTransformComponentSelection.cpp | 2 +- .../EditorVisibleEntityDataCache.cpp | 112 +++++++++++++++++- .../EditorVisibleEntityDataCache.h | 24 ++-- 7 files changed, 136 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h index ab8629ac85..81f1f7bb3b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeNotificationBus.h @@ -28,8 +28,10 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// //! Triggered when the editor focus is changed to a different entity. - //! @param entityId The entity the focus has been moved to. - virtual void OnEditorFocusChanged(AZ::EntityId entityId) = 0; + //! @param previousFocusEntityId The entity the focus has been moved from. + //! @param newFocusEntityId The entity the focus has been moved to. + virtual void OnEditorFocusChanged( + [[maybe_unused]] AZ::EntityId previousFocusEntityId, [[maybe_unused]] AZ::EntityId newFocusEntityId) {} protected: ~FocusModeNotifications() = default; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp index af518afd66..f592c471d0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp @@ -71,8 +71,9 @@ namespace AzToolsFramework return; } + AZ::EntityId previousFocusEntityId = m_focusRoot; m_focusRoot = entityId; - FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, m_focusRoot); + FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, previousFocusEntityId, m_focusRoot); if (auto tracker = AZ::Interface::Get(); tracker != nullptr) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp index 4364ae1efc..d3138f5139 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp @@ -313,7 +313,8 @@ namespace AzToolsFramework StyledTreeView::StartCustomDrag(indexListSorted, supportedActions); } - void EntityOutlinerTreeView::OnEditorFocusChanged([[maybe_unused]] AZ::EntityId entityId) + void EntityOutlinerTreeView::OnEditorFocusChanged( + [[maybe_unused]] AZ::EntityId previousFocusEntityId, [[maybe_unused]] AZ::EntityId newFocusEntityId) { viewport()->repaint(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx index 2ddbaaafa9..5d76ec6db2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx @@ -64,7 +64,7 @@ namespace AzToolsFramework void leaveEvent(QEvent* event) override; // FocusModeNotificationBus overrides ... - void OnEditorFocusChanged(AZ::EntityId entityId) override; + void OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId) override; //! Renders the left side of the item: appropriate background, branch lines, icons. void drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 6ee5c97636..d5a0595049 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -407,7 +407,7 @@ namespace AzToolsFramework const AzFramework::CameraState cameraState = GetCameraState(viewportId); for (size_t entityCacheIndex = 0; entityCacheIndex < entityDataCache.VisibleEntityDataCount(); ++entityCacheIndex) { - if (entityDataCache.IsVisibleEntityLocked(entityCacheIndex) || !entityDataCache.IsVisibleEntityVisible(entityCacheIndex)) + if (!entityDataCache.IsVisibleEntitySelectableInViewport(entityCacheIndex)) { continue; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp index babc6f972c..328cfc3ae5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp @@ -9,7 +9,9 @@ #include "EditorVisibleEntityDataCache.h" #include +#include #include +#include #include #include @@ -21,13 +23,23 @@ namespace AzToolsFramework using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType; EntityData() = default; - EntityData(AZ::EntityId entityId, const AZ::Transform& worldFromLocal, bool locked, bool visible, bool selected, bool iconHidden); + EntityData( + AZ::EntityId entityId, + const AZ::Transform& worldFromLocal, + bool locked, + bool visible, + bool inFocus, + bool descendantOfClosedContainer, + bool selected, + bool iconHidden); AZ::Transform m_worldFromLocal; AZ::EntityId m_entityId; ComponentEntityAccentType m_accent = ComponentEntityAccentType::None; bool m_locked = false; bool m_visible = true; + bool m_inFocus = true; + bool m_descendantOfClosedContainer = false; bool m_selected = false; bool m_iconHidden = false; }; @@ -57,12 +69,16 @@ namespace AzToolsFramework const AZ::Transform& worldFromLocal, const bool locked, const bool visible, + const bool inFocus, + const bool descendantOfClosedContainer, const bool selected, const bool iconHidden) : m_worldFromLocal(worldFromLocal) , m_entityId(entityId) , m_locked(locked) , m_visible(visible) + , m_inFocus(inFocus) + , m_descendantOfClosedContainer(descendantOfClosedContainer) , m_selected(selected) , m_iconHidden(iconHidden) { @@ -106,6 +122,18 @@ namespace AzToolsFramework bool locked = false; EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked); + bool inFocus = false; + if (auto focusModeInterface = AZ::Interface::Get()) + { + inFocus = focusModeInterface->IsInFocusSubTree(entityId); + } + + bool descendantOfClosedContainer = false; + if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get()) + { + descendantOfClosedContainer = containerEntityInterface->IsUnderClosedContainerEntity(entityId); + } + bool iconHidden = false; EditorEntityIconComponentRequestBus::EventResult( iconHidden, entityId, &EditorEntityIconComponentRequests::IsEntityIconHiddenInViewport); @@ -113,7 +141,7 @@ namespace AzToolsFramework AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); - return { entityId, worldFromLocal, locked, visible, IsSelected(entityId), iconHidden }; + return { entityId, worldFromLocal, locked, visible, inFocus, descendantOfClosedContainer, IsSelected(entityId), iconHidden }; } EditorVisibleEntityDataCache::EditorVisibleEntityDataCache() @@ -126,10 +154,17 @@ namespace AzToolsFramework EntitySelectionEvents::Bus::Router::BusRouterConnect(); EditorEntityIconComponentNotificationBus::Router::BusRouterConnect(); ToolsApplicationNotificationBus::Handler::BusConnect(); + + AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId(); + + ContainerEntityNotificationBus::Handler::BusConnect(editorEntityContextId); + FocusModeNotificationBus::Handler::BusConnect(editorEntityContextId); } EditorVisibleEntityDataCache::~EditorVisibleEntityDataCache() { + FocusModeNotificationBus::Handler::BusDisconnect(); + ContainerEntityNotificationBus::Handler::BusDisconnect(); ToolsApplicationNotificationBus::Handler::BusDisconnect(); EditorEntityIconComponentNotificationBus::Router::BusRouterDisconnect(); EntitySelectionEvents::Bus::Router::BusRouterDisconnect(); @@ -260,7 +295,10 @@ namespace AzToolsFramework bool EditorVisibleEntityDataCache::IsVisibleEntitySelectableInViewport(size_t index) const { - return m_impl->m_visibleEntityDatas[index].m_visible && !m_impl->m_visibleEntityDatas[index].m_locked; + return m_impl->m_visibleEntityDatas[index].m_visible + && !m_impl->m_visibleEntityDatas[index].m_locked + && m_impl->m_visibleEntityDatas[index].m_inFocus + && !m_impl->m_visibleEntityDatas[index].m_descendantOfClosedContainer; } AZStd::optional EditorVisibleEntityDataCache::GetVisibleEntityIndexFromId(const AZ::EntityId entityId) const @@ -371,4 +409,72 @@ namespace AzToolsFramework m_impl->m_visibleEntityDatas[entityIndex.value()].m_iconHidden = iconHidden; } } + + void EditorVisibleEntityDataCache::OnContainerEntityStatusChanged(AZ::EntityId entityId, [[maybe_unused]] bool open) + { + // Get container descendants + AzToolsFramework::EntityIdList descendantIds; + AZ::TransformBus::EventResult(descendantIds, entityId, &AZ::TransformBus::Events::GetAllDescendants); + + // Update cached values + if (auto containerEntityInterface = AZ::Interface::Get()) + { + for (AZ::EntityId descendantId : descendantIds) + { + if (AZStd::optional entityIndex = GetVisibleEntityIndexFromId(descendantId)) + { + m_impl->m_visibleEntityDatas[entityIndex.value()].m_descendantOfClosedContainer = + containerEntityInterface->IsUnderClosedContainerEntity(descendantId); + } + } + } + } + + void EditorVisibleEntityDataCache::OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId) + { + if (previousFocusEntityId.IsValid() && newFocusEntityId.IsValid()) + { + // Get previous focus root descendants + AzToolsFramework::EntityIdList previousDescendantIds; + AZ::TransformBus::EventResult(previousDescendantIds, previousFocusEntityId, &AZ::TransformBus::Events::GetAllDescendants); + + // Get new focus root descendants + AzToolsFramework::EntityIdList newDescendantIds; + AZ::TransformBus::EventResult(newDescendantIds, newFocusEntityId, &AZ::TransformBus::Events::GetAllDescendants); + + // Merge EntityId Lists to avoid refreshing values twice + AzToolsFramework::EntityIdSet descendantsSet; + descendantsSet.insert(previousFocusEntityId); + descendantsSet.insert(newFocusEntityId); + descendantsSet.insert(previousDescendantIds.begin(), previousDescendantIds.end()); + descendantsSet.insert(newDescendantIds.begin(), newDescendantIds.end()); + + // Update cached values + if (auto focusModeInterface = AZ::Interface::Get()) + { + for (const AZ::EntityId& descendantId : descendantsSet) + { + if (AZStd::optional entityIndex = GetVisibleEntityIndexFromId(descendantId)) + { + m_impl->m_visibleEntityDatas[entityIndex.value()].m_inFocus = focusModeInterface->IsInFocusSubTree(descendantId); + } + } + } + } + else + { + // If either focus was the invalid entity, refresh all entities. + if (auto focusModeInterface = AZ::Interface::Get()) + { + for (size_t entityIndex = 0; entityIndex < m_impl->m_visibleEntityDatas.size(); ++entityIndex) + { + if (AZ::EntityId descendantId = GetVisibleEntityId(entityIndex); descendantId.IsValid()) + { + m_impl->m_visibleEntityDatas[entityIndex].m_inFocus = focusModeInterface->IsInFocusSubTree(descendantId); + } + } + } + } + } + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h index b34defc25b..16fa1b6d14 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -28,6 +30,8 @@ namespace AzToolsFramework , private EntitySelectionEvents::Bus::Router , private EditorEntityIconComponentNotificationBus::Router , private ToolsApplicationNotificationBus::Handler + , private ContainerEntityNotificationBus::Handler + , private FocusModeNotificationBus::Handler { public: EditorVisibleEntityDataCache(); @@ -58,28 +62,34 @@ namespace AzToolsFramework void AddEntityIds(const EntityIdList& entityIds); private: - // ToolsApplicationNotificationBus + // ToolsApplicationNotificationBus overrides ... void AfterUndoRedo() override; - // EditorEntityVisibilityNotificationBus + // EditorEntityVisibilityNotificationBus overrides ... void OnEntityVisibilityChanged(bool visibility) override; - // EditorEntityLockComponentNotificationBus + // EditorEntityLockComponentNotificationBus overrides ... void OnEntityLockChanged(bool locked) override; - // TransformNotificationBus + // TransformNotificationBus overrides ... void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; - // EditorComponentSelectionNotificationsBus + // EditorComponentSelectionNotificationsBus overrides ... void OnAccentTypeChanged(EntityAccentType accent) override; - // EntitySelectionEvents::Bus + // EntitySelectionEvents::Bus overrides ... void OnSelected() override; void OnDeselected() override; - // EditorEntityIconComponentNotificationBus + // EditorEntityIconComponentNotificationBus overrides ... void OnEntityIconChanged(const AZ::Data::AssetId& entityIconAssetId) override; + // ContainerEntityNotificationBus overrides ... + void OnContainerEntityStatusChanged(AZ::EntityId entityId, bool open) override; + + // FocusModeNotificationBus overrides ... + void OnEditorFocusChanged(AZ::EntityId previousFocusEntityId, AZ::EntityId newFocusEntityId) override; + class EditorVisibleEntityDataCacheImpl; AZStd::unique_ptr m_impl; //!< Internal representation of entity data cache. }; From f83c8bcb5aa17754c42f85e9471c42f08ec9225e Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 13 Oct 2021 16:28:56 -0500 Subject: [PATCH 243/293] Added gem template for custom tool in C++. Signed-off-by: Chris Galvan --- Templates/CustomTool/Template/CMakeLists.txt | 22 + .../Code/${NameLower}_editor_files.cmake | 15 + .../${NameLower}_editor_shared_files.cmake | 11 + .../${NameLower}_editor_tests_files.cmake | 11 + .../Template/Code/${NameLower}_files.cmake | 14 + .../Code/${NameLower}_shared_files.cmake | 11 + .../Code/${NameLower}_tests_files.cmake | 11 + .../CustomTool/Template/Code/CMakeLists.txt | 168 ++++++++ .../Code/Include/${Name}/${Name}Bus.h | 40 ++ .../Android/${NameLower}_android_files.cmake | 15 + .../${NameLower}_shared_android_files.cmake | 15 + .../Code/Platform/Android/PAL_android.cmake | 11 + .../Linux/${NameLower}_linux_files.cmake | 15 + .../${NameLower}_shared_linux_files.cmake | 15 + .../Code/Platform/Linux/PAL_linux.cmake | 11 + .../Platform/Mac/${NameLower}_mac_files.cmake | 15 + .../Mac/${NameLower}_shared_mac_files.cmake | 15 + .../Template/Code/Platform/Mac/PAL_mac.cmake | 11 + .../${NameLower}_shared_windows_files.cmake | 15 + .../Windows/${NameLower}_windows_files.cmake | 15 + .../Code/Platform/Windows/PAL_windows.cmake | 11 + .../Platform/iOS/${NameLower}_ios_files.cmake | 15 + .../iOS/${NameLower}_shared_ios_files.cmake | 15 + .../Template/Code/Platform/iOS/PAL_ios.cmake | 11 + .../Template/Code/Source/${Name}.qrc | 5 + .../Code/Source/${Name}EditorModule.cpp | 55 +++ .../Source/${Name}EditorSystemComponent.cpp | 78 ++++ .../Source/${Name}EditorSystemComponent.h | 45 +++ .../Template/Code/Source/${Name}Module.cpp | 25 ++ .../Code/Source/${Name}ModuleInterface.h | 45 +++ .../Code/Source/${Name}SystemComponent.cpp | 92 +++++ .../Code/Source/${Name}SystemComponent.h | 56 +++ .../Template/Code/Source/${Name}Widget.cpp | 44 ++ .../Template/Code/Source/${Name}Widget.h | 28 ++ .../Template/Code/Source/toolbar_icon.svg | 1 + .../Template/Code/Tests/${Name}EditorTest.cpp | 13 + .../Template/Code/Tests/${Name}Test.cpp | 13 + .../Platform/Android/android_gem.cmake | 8 + .../Platform/Android/android_gem.json | 3 + .../Template/Platform/Linux/linux_gem.cmake | 8 + .../Template/Platform/Linux/linux_gem.json | 3 + .../Template/Platform/Mac/mac_gem.cmake | 8 + .../Template/Platform/Mac/mac_gem.json | 3 + .../Platform/Windows/windows_gem.cmake | 8 + .../Platform/Windows/windows_gem.json | 3 + .../Template/Platform/iOS/ios_gem.cmake | 8 + .../Template/Platform/iOS/ios_gem.json | 3 + Templates/CustomTool/Template/gem.json | 17 + Templates/CustomTool/Template/preview.png | 3 + Templates/CustomTool/template.json | 382 ++++++++++++++++++ engine.json | 1 + 51 files changed, 1466 insertions(+) create mode 100644 Templates/CustomTool/Template/CMakeLists.txt create mode 100644 Templates/CustomTool/Template/Code/${NameLower}_editor_files.cmake create mode 100644 Templates/CustomTool/Template/Code/${NameLower}_editor_shared_files.cmake create mode 100644 Templates/CustomTool/Template/Code/${NameLower}_editor_tests_files.cmake create mode 100644 Templates/CustomTool/Template/Code/${NameLower}_files.cmake create mode 100644 Templates/CustomTool/Template/Code/${NameLower}_shared_files.cmake create mode 100644 Templates/CustomTool/Template/Code/${NameLower}_tests_files.cmake create mode 100644 Templates/CustomTool/Template/Code/CMakeLists.txt create mode 100644 Templates/CustomTool/Template/Code/Include/${Name}/${Name}Bus.h create mode 100644 Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_android_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Linux/PAL_linux.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Mac/PAL_mac.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/Windows/PAL_windows.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake create mode 100644 Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}.qrc create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}EditorModule.cpp create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.cpp create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.h create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}Module.cpp create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}ModuleInterface.h create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.cpp create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.h create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}Widget.cpp create mode 100644 Templates/CustomTool/Template/Code/Source/${Name}Widget.h create mode 100644 Templates/CustomTool/Template/Code/Source/toolbar_icon.svg create mode 100644 Templates/CustomTool/Template/Code/Tests/${Name}EditorTest.cpp create mode 100644 Templates/CustomTool/Template/Code/Tests/${Name}Test.cpp create mode 100644 Templates/CustomTool/Template/Platform/Android/android_gem.cmake create mode 100644 Templates/CustomTool/Template/Platform/Android/android_gem.json create mode 100644 Templates/CustomTool/Template/Platform/Linux/linux_gem.cmake create mode 100644 Templates/CustomTool/Template/Platform/Linux/linux_gem.json create mode 100644 Templates/CustomTool/Template/Platform/Mac/mac_gem.cmake create mode 100644 Templates/CustomTool/Template/Platform/Mac/mac_gem.json create mode 100644 Templates/CustomTool/Template/Platform/Windows/windows_gem.cmake create mode 100644 Templates/CustomTool/Template/Platform/Windows/windows_gem.json create mode 100644 Templates/CustomTool/Template/Platform/iOS/ios_gem.cmake create mode 100644 Templates/CustomTool/Template/Platform/iOS/ios_gem.json create mode 100644 Templates/CustomTool/Template/gem.json create mode 100644 Templates/CustomTool/Template/preview.png create mode 100644 Templates/CustomTool/template.json diff --git a/Templates/CustomTool/Template/CMakeLists.txt b/Templates/CustomTool/Template/CMakeLists.txt new file mode 100644 index 0000000000..b19ea2edce --- /dev/null +++ b/Templates/CustomTool/Template/CMakeLists.txt @@ -0,0 +1,22 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(o3de_gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(o3de_gem_json ${o3de_gem_path}/gem.json) +o3de_read_json_key(o3de_gem_name ${o3de_gem_json} "gem_name") +o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path) + +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${o3de_gem_restricted_path}" ${o3de_gem_path} ${o3de_gem_name}) + +# Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the +# project cmake for this platform. +include(${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_gem.cmake) + +ly_add_external_target_path(${CMAKE_CURRENT_LIST_DIR}/3rdParty) + +add_subdirectory(Code) diff --git a/Templates/CustomTool/Template/Code/${NameLower}_editor_files.cmake b/Templates/CustomTool/Template/Code/${NameLower}_editor_files.cmake new file mode 100644 index 0000000000..d73efffa2e --- /dev/null +++ b/Templates/CustomTool/Template/Code/${NameLower}_editor_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Source/${Name}EditorSystemComponent.cpp + Source/${Name}EditorSystemComponent.h + Source/${Name}Widget.cpp + Source/${Name}Widget.h + Source/${Name}.qrc +) diff --git a/Templates/CustomTool/Template/Code/${NameLower}_editor_shared_files.cmake b/Templates/CustomTool/Template/Code/${NameLower}_editor_shared_files.cmake new file mode 100644 index 0000000000..2d4ceae97d --- /dev/null +++ b/Templates/CustomTool/Template/Code/${NameLower}_editor_shared_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Source/${Name}EditorModule.cpp +) diff --git a/Templates/CustomTool/Template/Code/${NameLower}_editor_tests_files.cmake b/Templates/CustomTool/Template/Code/${NameLower}_editor_tests_files.cmake new file mode 100644 index 0000000000..ff45c2fc1c --- /dev/null +++ b/Templates/CustomTool/Template/Code/${NameLower}_editor_tests_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Tests/${Name}EditorTest.cpp +) diff --git a/Templates/CustomTool/Template/Code/${NameLower}_files.cmake b/Templates/CustomTool/Template/Code/${NameLower}_files.cmake new file mode 100644 index 0000000000..b7d6d37bdf --- /dev/null +++ b/Templates/CustomTool/Template/Code/${NameLower}_files.cmake @@ -0,0 +1,14 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Include/${Name}/${Name}Bus.h + Source/${Name}ModuleInterface.h + Source/${Name}SystemComponent.cpp + Source/${Name}SystemComponent.h +) diff --git a/Templates/CustomTool/Template/Code/${NameLower}_shared_files.cmake b/Templates/CustomTool/Template/Code/${NameLower}_shared_files.cmake new file mode 100644 index 0000000000..b85916191c --- /dev/null +++ b/Templates/CustomTool/Template/Code/${NameLower}_shared_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Source/${Name}Module.cpp +) diff --git a/Templates/CustomTool/Template/Code/${NameLower}_tests_files.cmake b/Templates/CustomTool/Template/Code/${NameLower}_tests_files.cmake new file mode 100644 index 0000000000..adcfe2645f --- /dev/null +++ b/Templates/CustomTool/Template/Code/${NameLower}_tests_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Tests/${Name}Test.cpp +) diff --git a/Templates/CustomTool/Template/Code/CMakeLists.txt b/Templates/CustomTool/Template/Code/CMakeLists.txt new file mode 100644 index 0000000000..f5cda477fc --- /dev/null +++ b/Templates/CustomTool/Template/Code/CMakeLists.txt @@ -0,0 +1,168 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Currently we are in the Code folder: ${CMAKE_CURRENT_LIST_DIR} +# Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} +# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform +# in which case it will see if that platform is present here or in the restricted folder. +# i.e. It could here in our gem : Gems/${Name}/Code/Platform/ or +# //Gems/${Name}/Code +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) + +# Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the +# traits for this platform. Traits for a platform are defines for things like whether or not something in this gem +# is supported by this platform. +include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + +# Add the ${Name}.Static target +# Note: We include the common files and the platform specific files which are set in ${NameLower}_common_files.cmake +# and in ${pal_dir}/${NameLower}_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake +ly_add_target( + NAME ${Name}.Static STATIC + NAMESPACE Gem + FILES_CMAKE + ${NameLower}_files.cmake + ${pal_dir}/${NameLower}_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + INCLUDE_DIRECTORIES + PUBLIC + Include + PRIVATE + Source + BUILD_DEPENDENCIES + PUBLIC + AZ::AzCore + AZ::AzFramework +) + +# Here add ${Name} target, it depends on the ${Name}.Static +ly_add_target( + NAME ${Name} ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} + NAMESPACE Gem + FILES_CMAKE + ${NameLower}_shared_files.cmake + ${pal_dir}/${NameLower}_shared_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + INCLUDE_DIRECTORIES + PUBLIC + Include + PRIVATE + Source + BUILD_DEPENDENCIES + PRIVATE + Gem::${Name}.Static +) + +# By default, we will specify that the above target ${Name} would be used by +# Client and Server type targets when this gem is enabled. If you don't want it +# active in Clients or Servers by default, delete one of both of the following lines: +ly_create_alias(NAME ${Name}.Clients NAMESPACE Gem TARGETS Gem::${Name}) +ly_create_alias(NAME ${Name}.Servers NAMESPACE Gem TARGETS Gem::${Name}) + +# If we are on a host platform, we want to add the host tools targets like the ${Name}.Editor target which +# will also depend on ${Name}.Static +if(PAL_TRAIT_BUILD_HOST_TOOLS) + ly_add_target( + NAME ${Name}.Editor.Static STATIC + NAMESPACE Gem + AUTOMOC + AUTORCC + FILES_CMAKE + ${NameLower}_editor_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + AZ::AzToolsFramework + Gem::${Name}.Static + ) + + ly_add_target( + NAME ${Name}.Editor GEM_MODULE + NAMESPACE Gem + AUTOMOC + FILES_CMAKE + ${NameLower}_editor_shared_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + Gem::${Name}.Editor.Static + ) + + # By default, we will specify that the above target ${Name} would be used by + # Tool and Builder type targets when this gem is enabled. If you don't want it + # active in Tools or Builders by default, delete one of both of the following lines: + ly_create_alias(NAME ${Name}.Tools NAMESPACE Gem TARGETS Gem::${Name}.Editor) + ly_create_alias(NAME ${Name}.Builders NAMESPACE Gem TARGETS Gem::${Name}.Editor) + + +endif() + +################################################################################ +# Tests +################################################################################ +# See if globally, tests are supported +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + # We globally support tests, see if we support tests on this platform for ${Name}.Static + if(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED) + # We support ${Name}.Tests on this platform, add ${Name}.Tests target which depends on ${Name}.Static + ly_add_target( + NAME ${Name}.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + ${NameLower}_files.cmake + ${NameLower}_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + Source + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + AZ::AzFramework + Gem::${Name}.Static + ) + + # Add ${Name}.Tests to googletest + ly_add_googletest( + NAME Gem::${Name}.Tests + ) + endif() + + # If we are a host platform we want to add tools test like editor tests here + if(PAL_TRAIT_BUILD_HOST_TOOLS) + # We are a host platform, see if Editor tests are supported on this platform + if(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED) + # We support ${Name}.Editor.Tests on this platform, add ${Name}.Editor.Tests target which depends on ${Name}.Editor + ly_add_target( + NAME ${Name}.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + ${NameLower}_editor_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + Source + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + Gem::${Name}.Editor + ) + + # Add ${Name}.Editor.Tests to googletest + ly_add_googletest( + NAME Gem::${Name}.Editor.Tests + ) + endif() + endif() +endif() diff --git a/Templates/CustomTool/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/CustomTool/Template/Code/Include/${Name}/${Name}Bus.h new file mode 100644 index 0000000000..d09bb2b009 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Include/${Name}/${Name}Bus.h @@ -0,0 +1,40 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#pragma once + +#include +#include + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}Requests + { + public: + AZ_RTTI(${SanitizedCppName}Requests, "{${Random_Uuid}}"); + virtual ~${SanitizedCppName}Requests() = default; + // Put your public methods here + }; + + class ${SanitizedCppName}BusTraits + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + }; + + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests, ${SanitizedCppName}BusTraits>; + using ${SanitizedCppName}Interface = AZ::Interface<${SanitizedCppName}Requests>; + +} // namespace ${SanitizedCppName} diff --git a/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_android_files.cmake b/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_android_files.cmake new file mode 100644 index 0000000000..5b6da14a20 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_android_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Android +# i.e. ../Source/Android/${Name}Android.cpp +# ../Source/Android/${Name}Android.h +# ../Include/Android/${Name}Android.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake b/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake new file mode 100644 index 0000000000..5b6da14a20 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Android/${NameLower}_shared_android_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Android +# i.e. ../Source/Android/${Name}Android.cpp +# ../Source/Android/${Name}Android.h +# ../Include/Android/${Name}Android.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake b/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake new file mode 100644 index 0000000000..49dfe71f53 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) diff --git a/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake new file mode 100644 index 0000000000..2f58a2e6f5 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Linux +# i.e. ../Source/Linux/${Name}Linux.cpp +# ../Source/Linux/${Name}Linux.h +# ../Include/Linux/${Name}Linux.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake b/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake new file mode 100644 index 0000000000..2f58a2e6f5 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Linux +# i.e. ../Source/Linux/${Name}Linux.cpp +# ../Source/Linux/${Name}Linux.h +# ../Include/Linux/${Name}Linux.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Linux/PAL_linux.cmake b/Templates/CustomTool/Template/Code/Platform/Linux/PAL_linux.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Linux/PAL_linux.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake new file mode 100644 index 0000000000..1cf737a2f1 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Mac +# i.e. ../Source/Mac/${Name}Mac.cpp +# ../Source/Mac/${Name}Mac.h +# ../Include/Mac/${Name}Mac.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake b/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake new file mode 100644 index 0000000000..1cf737a2f1 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Mac +# i.e. ../Source/Mac/${Name}Mac.cpp +# ../Source/Mac/${Name}Mac.h +# ../Include/Mac/${Name}Mac.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Mac/PAL_mac.cmake b/Templates/CustomTool/Template/Code/Platform/Mac/PAL_mac.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Mac/PAL_mac.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake b/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake new file mode 100644 index 0000000000..712aad1207 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Windows +# i.e. ../Source/Windows/${Name}Windows.cpp +# ../Source/Windows/${Name}Windows.h +# ../Include/Windows/${Name}Windows.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake new file mode 100644 index 0000000000..712aad1207 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Windows +# i.e. ../Source/Windows/${Name}Windows.cpp +# ../Source/Windows/${Name}Windows.h +# ../Include/Windows/${Name}Windows.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/Windows/PAL_windows.cmake b/Templates/CustomTool/Template/Code/Platform/Windows/PAL_windows.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/Windows/PAL_windows.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake b/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake new file mode 100644 index 0000000000..61efde11c2 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for iOS +# i.e. ../Source/iOS/${Name}iOS.cpp +# ../Source/iOS/${Name}iOS.h +# ../Include/iOS/${Name}iOS.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake b/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake new file mode 100644 index 0000000000..61efde11c2 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/iOS/${NameLower}_shared_ios_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for iOS +# i.e. ../Source/iOS/${Name}iOS.cpp +# ../Source/iOS/${Name}iOS.h +# ../Include/iOS/${Name}iOS.h + +set(FILES +) diff --git a/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake b/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/CustomTool/Template/Code/Source/${Name}.qrc b/Templates/CustomTool/Template/Code/Source/${Name}.qrc new file mode 100644 index 0000000000..90d7695b88 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}.qrc @@ -0,0 +1,5 @@ + + + toolbar_icon.svg + + diff --git a/Templates/CustomTool/Template/Code/Source/${Name}EditorModule.cpp b/Templates/CustomTool/Template/Code/Source/${Name}EditorModule.cpp new file mode 100644 index 0000000000..0027af011a --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}EditorModule.cpp @@ -0,0 +1,55 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include <${Name}ModuleInterface.h> +#include <${Name}EditorSystemComponent.h> + +void Init${SanitizedCppName}Resources() +{ + // We must register our Qt resources (.qrc file) since this is being loaded from a separate module (gem) + Q_INIT_RESOURCE(${SanitizedCppName}); +} + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}EditorModule + : public ${SanitizedCppName}ModuleInterface + { + public: + AZ_RTTI(${SanitizedCppName}EditorModule, "${ModuleClassId}", ${SanitizedCppName}ModuleInterface); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}EditorModule, AZ::SystemAllocator, 0); + + ${SanitizedCppName}EditorModule() + { + Init${SanitizedCppName}Resources(); + + // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. + // Add ALL components descriptors associated with this gem to m_descriptors. + // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and EditContext. + // This happens through the [MyComponent]::Reflect() function. + m_descriptors.insert(m_descriptors.end(), { + ${SanitizedCppName}EditorSystemComponent::CreateDescriptor(), + }); + } + + /** + * Add required SystemComponents to the SystemEntity. + * Non-SystemComponents should not be added here + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList { + azrtti_typeid<${SanitizedCppName}EditorSystemComponent>(), + }; + } + }; +}// namespace ${SanitizedCppName} + +AZ_DECLARE_MODULE_CLASS(Gem_${SanitizedCppName}, ${SanitizedCppName}::${SanitizedCppName}EditorModule) diff --git a/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.cpp new file mode 100644 index 0000000000..f12fa04929 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.cpp @@ -0,0 +1,78 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include + +#include + +#include <${Name}Widget.h> +#include <${Name}EditorSystemComponent.h> + +namespace ${SanitizedCppName} +{ + void ${SanitizedCppName}EditorSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class<${SanitizedCppName}EditorSystemComponent, ${SanitizedCppName}SystemComponent>() + ->Version(0); + } + } + + ${SanitizedCppName}EditorSystemComponent::${SanitizedCppName}EditorSystemComponent() = default; + + ${SanitizedCppName}EditorSystemComponent::~${SanitizedCppName}EditorSystemComponent() = default; + + void ${SanitizedCppName}EditorSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + BaseSystemComponent::GetProvidedServices(provided); + provided.push_back(AZ_CRC_CE("${SanitizedCppName}EditorService")); + } + + void ${SanitizedCppName}EditorSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + BaseSystemComponent::GetIncompatibleServices(incompatible); + incompatible.push_back(AZ_CRC_CE("${SanitizedCppName}EditorService")); + } + + void ${SanitizedCppName}EditorSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + BaseSystemComponent::GetRequiredServices(required); + } + + void ${SanitizedCppName}EditorSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + BaseSystemComponent::GetDependentServices(dependent); + } + + void ${SanitizedCppName}EditorSystemComponent::Activate() + { + ${SanitizedCppName}SystemComponent::Activate(); + AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + } + + void ${SanitizedCppName}EditorSystemComponent::Deactivate() + { + AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + ${SanitizedCppName}SystemComponent::Deactivate(); + } + + void ${SanitizedCppName}EditorSystemComponent::NotifyRegisterViews() + { + AzToolsFramework::ViewPaneOptions options; + options.paneRect = QRect(100, 100, 500, 400); + options.showOnToolsToolbar = true; + options.toolbarIcon = ":/${Name}/toolbar_icon.svg"; + + // Register our custom widget as a dockable tool with the Editor + AzToolsFramework::RegisterViewPane<${SanitizedCppName}Widget>("${Name}", "Tools", options); + } + +} // namespace ${SanitizedCppName} diff --git a/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.h b/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.h new file mode 100644 index 0000000000..bbeac97da3 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}EditorSystemComponent.h @@ -0,0 +1,45 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#pragma once + +#include <${Name}SystemComponent.h> + +#include + +namespace ${SanitizedCppName} +{ + /// System component for ${SanitizedCppName} editor + class ${SanitizedCppName}EditorSystemComponent + : public ${SanitizedCppName}SystemComponent + , private AzToolsFramework::EditorEvents::Bus::Handler + { + using BaseSystemComponent = ${SanitizedCppName}SystemComponent; + public: + AZ_COMPONENT(${SanitizedCppName}EditorSystemComponent, "${EditorSysCompClassId}", BaseSystemComponent); + static void Reflect(AZ::ReflectContext* context); + + ${SanitizedCppName}EditorSystemComponent(); + ~${SanitizedCppName}EditorSystemComponent(); + + private: + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + // AZ::Component + void Activate() override; + void Deactivate() override; + + // AzToolsFramework::EditorEventsBus overrides ... + void NotifyRegisterViews() override; + }; +} // namespace ${SanitizedCppName} diff --git a/Templates/CustomTool/Template/Code/Source/${Name}Module.cpp b/Templates/CustomTool/Template/Code/Source/${Name}Module.cpp new file mode 100644 index 0000000000..0a6e8bde3c --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}Module.cpp @@ -0,0 +1,25 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include <${Name}ModuleInterface.h> +#include <${Name}SystemComponent.h> + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}Module + : public ${SanitizedCppName}ModuleInterface + { + public: + AZ_RTTI(${SanitizedCppName}Module, "${ModuleClassId}", ${SanitizedCppName}ModuleInterface); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}Module, AZ::SystemAllocator, 0); + }; +}// namespace ${SanitizedCppName} + +AZ_DECLARE_MODULE_CLASS(Gem_${SanitizedCppName}, ${SanitizedCppName}::${SanitizedCppName}Module) diff --git a/Templates/CustomTool/Template/Code/Source/${Name}ModuleInterface.h b/Templates/CustomTool/Template/Code/Source/${Name}ModuleInterface.h new file mode 100644 index 0000000000..925632491a --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}ModuleInterface.h @@ -0,0 +1,45 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include +#include +#include <${Name}SystemComponent.h> + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}ModuleInterface + : public AZ::Module + { + public: + AZ_RTTI(${SanitizedCppName}ModuleInterface, "{${Random_Uuid}}", AZ::Module); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}ModuleInterface, AZ::SystemAllocator, 0); + + ${SanitizedCppName}ModuleInterface() + { + // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. + // Add ALL components descriptors associated with this gem to m_descriptors. + // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and EditContext. + // This happens through the [MyComponent]::Reflect() function. + m_descriptors.insert(m_descriptors.end(), { + ${SanitizedCppName}SystemComponent::CreateDescriptor(), + }); + } + + /** + * Add required SystemComponents to the SystemEntity. + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList{ + azrtti_typeid<${SanitizedCppName}SystemComponent>(), + }; + } + }; +}// namespace ${SanitizedCppName} diff --git a/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.cpp b/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.cpp new file mode 100644 index 0000000000..cb4d58418e --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.cpp @@ -0,0 +1,92 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include <${Name}SystemComponent.h> + +#include +#include +#include + +namespace ${SanitizedCppName} +{ + void ${SanitizedCppName}SystemComponent::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class<${SanitizedCppName}SystemComponent, AZ::Component>() + ->Version(0) + ; + + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class<${SanitizedCppName}SystemComponent>("${SanitizedCppName}", "[Description of functionality provided by this System Component]") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ; + } + } + } + + void ${SanitizedCppName}SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("${SanitizedCppName}Service")); + } + + void ${SanitizedCppName}SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("${SanitizedCppName}Service")); + } + + void ${SanitizedCppName}SystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + } + + void ${SanitizedCppName}SystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + } + + ${SanitizedCppName}SystemComponent::${SanitizedCppName}SystemComponent() + { + if (${SanitizedCppName}Interface::Get() == nullptr) + { + ${SanitizedCppName}Interface::Register(this); + } + } + + ${SanitizedCppName}SystemComponent::~${SanitizedCppName}SystemComponent() + { + if (${SanitizedCppName}Interface::Get() == this) + { + ${SanitizedCppName}Interface::Unregister(this); + } + } + + void ${SanitizedCppName}SystemComponent::Init() + { + } + + void ${SanitizedCppName}SystemComponent::Activate() + { + ${SanitizedCppName}RequestBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusConnect(); + } + + void ${SanitizedCppName}SystemComponent::Deactivate() + { + AZ::TickBus::Handler::BusDisconnect(); + ${SanitizedCppName}RequestBus::Handler::BusDisconnect(); + } + + void ${SanitizedCppName}SystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + } + +} // namespace ${SanitizedCppName} diff --git a/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.h b/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.h new file mode 100644 index 0000000000..5495d18e48 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}SystemComponent.h @@ -0,0 +1,56 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#pragma once + +#include +#include +#include <${Name}/${Name}Bus.h> + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}SystemComponent + : public AZ::Component + , protected ${SanitizedCppName}RequestBus::Handler + , public AZ::TickBus::Handler + { + public: + AZ_COMPONENT(${SanitizedCppName}SystemComponent, "${SysCompClassId}"); + + static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + ${SanitizedCppName}SystemComponent(); + ~${SanitizedCppName}SystemComponent(); + + protected: + //////////////////////////////////////////////////////////////////////// + // ${SanitizedCppName}RequestBus interface implementation + + //////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////// + // AZ::Component interface implementation + void Init() override; + void Activate() override; + void Deactivate() override; + //////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////// + // AZTickBus interface implementation + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + //////////////////////////////////////////////////////////////////////// + }; + +} // namespace ${SanitizedCppName} diff --git a/Templates/CustomTool/Template/Code/Source/${Name}Widget.cpp b/Templates/CustomTool/Template/Code/Source/${Name}Widget.cpp new file mode 100644 index 0000000000..bd6dd6c86a --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}Widget.cpp @@ -0,0 +1,44 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include + +#include +#include + +#include <${Name}Widget.h> + +namespace ${SanitizedCppName} +{ + ${SanitizedCppName}Widget::${SanitizedCppName}Widget(QWidget* parent) + : QWidget(parent) + { + setWindowTitle(QObject::tr("${Name}")); + + QVBoxLayout* mainLayout = new QVBoxLayout(this); + + QLabel* introLabel = new QLabel(QObject::tr("Put your cool stuff here!"), this); + mainLayout->addWidget(introLabel, 0, Qt::AlignCenter); + + QString helpText = QString( + "For help getting started, visit the UI Development documentation
or come ask a question in the sig-ui-ux channel on Discord"); + + QLabel* helpLabel = new QLabel(this); + helpLabel->setTextFormat(Qt::RichText); + helpLabel->setText(helpText); + helpLabel->setOpenExternalLinks(true); + + mainLayout->addWidget(helpLabel, 0, Qt::AlignCenter); + + setLayout(mainLayout); + } +} + +#include diff --git a/Templates/CustomTool/Template/Code/Source/${Name}Widget.h b/Templates/CustomTool/Template/Code/Source/${Name}Widget.h new file mode 100644 index 0000000000..4d0c86d043 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/${Name}Widget.h @@ -0,0 +1,28 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +#include +#endif + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}Widget + : public QWidget + { + Q_OBJECT + public: + explicit ${SanitizedCppName}Widget(QWidget* parent = nullptr); + }; +} diff --git a/Templates/CustomTool/Template/Code/Source/toolbar_icon.svg b/Templates/CustomTool/Template/Code/Source/toolbar_icon.svg new file mode 100644 index 0000000000..59de66961c --- /dev/null +++ b/Templates/CustomTool/Template/Code/Source/toolbar_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Templates/CustomTool/Template/Code/Tests/${Name}EditorTest.cpp b/Templates/CustomTool/Template/Code/Tests/${Name}EditorTest.cpp new file mode 100644 index 0000000000..9b84575fa0 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Tests/${Name}EditorTest.cpp @@ -0,0 +1,13 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Templates/CustomTool/Template/Code/Tests/${Name}Test.cpp b/Templates/CustomTool/Template/Code/Tests/${Name}Test.cpp new file mode 100644 index 0000000000..9b84575fa0 --- /dev/null +++ b/Templates/CustomTool/Template/Code/Tests/${Name}Test.cpp @@ -0,0 +1,13 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Templates/CustomTool/Template/Platform/Android/android_gem.cmake b/Templates/CustomTool/Template/Platform/Android/android_gem.cmake new file mode 100644 index 0000000000..063b3be9ac --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Android/android_gem.cmake @@ -0,0 +1,8 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + diff --git a/Templates/CustomTool/Template/Platform/Android/android_gem.json b/Templates/CustomTool/Template/Platform/Android/android_gem.json new file mode 100644 index 0000000000..23bbb28e66 --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Android/android_gem.json @@ -0,0 +1,3 @@ +{ + "Tags": ["Android"], +} \ No newline at end of file diff --git a/Templates/CustomTool/Template/Platform/Linux/linux_gem.cmake b/Templates/CustomTool/Template/Platform/Linux/linux_gem.cmake new file mode 100644 index 0000000000..063b3be9ac --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Linux/linux_gem.cmake @@ -0,0 +1,8 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + diff --git a/Templates/CustomTool/Template/Platform/Linux/linux_gem.json b/Templates/CustomTool/Template/Platform/Linux/linux_gem.json new file mode 100644 index 0000000000..d08fbf53ba --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Linux/linux_gem.json @@ -0,0 +1,3 @@ +{ + "Tags": ["Linux"] +} \ No newline at end of file diff --git a/Templates/CustomTool/Template/Platform/Mac/mac_gem.cmake b/Templates/CustomTool/Template/Platform/Mac/mac_gem.cmake new file mode 100644 index 0000000000..063b3be9ac --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Mac/mac_gem.cmake @@ -0,0 +1,8 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + diff --git a/Templates/CustomTool/Template/Platform/Mac/mac_gem.json b/Templates/CustomTool/Template/Platform/Mac/mac_gem.json new file mode 100644 index 0000000000..d42b6f8186 --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Mac/mac_gem.json @@ -0,0 +1,3 @@ +{ + "Tags": ["Mac"] +} \ No newline at end of file diff --git a/Templates/CustomTool/Template/Platform/Windows/windows_gem.cmake b/Templates/CustomTool/Template/Platform/Windows/windows_gem.cmake new file mode 100644 index 0000000000..063b3be9ac --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Windows/windows_gem.cmake @@ -0,0 +1,8 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + diff --git a/Templates/CustomTool/Template/Platform/Windows/windows_gem.json b/Templates/CustomTool/Template/Platform/Windows/windows_gem.json new file mode 100644 index 0000000000..a052f1e05a --- /dev/null +++ b/Templates/CustomTool/Template/Platform/Windows/windows_gem.json @@ -0,0 +1,3 @@ +{ + "Tags": ["Windows"] +} \ No newline at end of file diff --git a/Templates/CustomTool/Template/Platform/iOS/ios_gem.cmake b/Templates/CustomTool/Template/Platform/iOS/ios_gem.cmake new file mode 100644 index 0000000000..063b3be9ac --- /dev/null +++ b/Templates/CustomTool/Template/Platform/iOS/ios_gem.cmake @@ -0,0 +1,8 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + diff --git a/Templates/CustomTool/Template/Platform/iOS/ios_gem.json b/Templates/CustomTool/Template/Platform/iOS/ios_gem.json new file mode 100644 index 0000000000..b2dab56d05 --- /dev/null +++ b/Templates/CustomTool/Template/Platform/iOS/ios_gem.json @@ -0,0 +1,3 @@ +{ + "Tags": ["iOS"] +} \ No newline at end of file diff --git a/Templates/CustomTool/Template/gem.json b/Templates/CustomTool/Template/gem.json new file mode 100644 index 0000000000..518d831e0f --- /dev/null +++ b/Templates/CustomTool/Template/gem.json @@ -0,0 +1,17 @@ +{ + "gem_name": "${Name}", + "display_name": "${Name}", + "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", + "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "type": "Code", + "summary": "A short description of ${Name}.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "${Name}" + ], + "icon_path": "preview.png", + "requirements": "", + "restricted_name": "gems" +} diff --git a/Templates/CustomTool/Template/preview.png b/Templates/CustomTool/Template/preview.png new file mode 100644 index 0000000000..0f393ac886 --- /dev/null +++ b/Templates/CustomTool/Template/preview.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ac9dd09bde78f389e3725ac49d61eff109857e004840bc0bc3881739df9618d +size 2217 diff --git a/Templates/CustomTool/template.json b/Templates/CustomTool/template.json new file mode 100644 index 0000000000..e3221db106 --- /dev/null +++ b/Templates/CustomTool/template.json @@ -0,0 +1,382 @@ +{ + "template_name": "CustomTool", + "origin": "The primary repo for CustomTool goes here: i.e. http://www.mydomain.com", + "license": "What license CustomTool uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "CustomTool", + "summary": "A gem template for a custom tool in C++ that gets registered with the Editor.", + "canonical_tags": [], + "user_tags": [ + "CustomTool" + ], + "icon_path": "preview.png", + "copyFiles": [ + { + "file": "CMakeLists.txt", + "origin": "CMakeLists.txt", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_files.cmake", + "origin": "Code/${NameLower}_editor_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_shared_files.cmake", + "origin": "Code/${NameLower}_editor_shared_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_tests_files.cmake", + "origin": "Code/${NameLower}_editor_tests_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_files.cmake", + "origin": "Code/${NameLower}_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_shared_files.cmake", + "origin": "Code/${NameLower}_shared_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_tests_files.cmake", + "origin": "Code/${NameLower}_tests_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/CMakeLists.txt", + "origin": "Code/CMakeLists.txt", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Include/${Name}/${Name}Bus.h", + "origin": "Code/Include/${Name}/${Name}Bus.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Android/${NameLower}_android_files.cmake", + "origin": "Code/Platform/Android/${NameLower}_android_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", + "origin": "Code/Platform/Android/${NameLower}_shared_android_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Android/PAL_android.cmake", + "origin": "Code/Platform/Android/PAL_android.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", + "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/PAL_linux.cmake", + "origin": "Code/Platform/Linux/PAL_linux.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", + "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/PAL_mac.cmake", + "origin": "Code/Platform/Mac/PAL_mac.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", + "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/PAL_windows.cmake", + "origin": "Code/Platform/Windows/PAL_windows.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/iOS/${NameLower}_ios_files.cmake", + "origin": "Code/Platform/iOS/${NameLower}_ios_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", + "origin": "Code/Platform/iOS/${NameLower}_shared_ios_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/iOS/PAL_ios.cmake", + "origin": "Code/Platform/iOS/PAL_ios.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}.qrc", + "origin": "Code/Source/${Name}.qrc", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorModule.cpp", + "origin": "Code/Source/${Name}EditorModule.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorSystemComponent.cpp", + "origin": "Code/Source/${Name}EditorSystemComponent.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorSystemComponent.h", + "origin": "Code/Source/${Name}EditorSystemComponent.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}Module.cpp", + "origin": "Code/Source/${Name}Module.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}ModuleInterface.h", + "origin": "Code/Source/${Name}ModuleInterface.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}SystemComponent.cpp", + "origin": "Code/Source/${Name}SystemComponent.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}SystemComponent.h", + "origin": "Code/Source/${Name}SystemComponent.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}Widget.cpp", + "origin": "Code/Source/${Name}Widget.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}Widget.h", + "origin": "Code/Source/${Name}Widget.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/toolbar_icon.svg", + "origin": "Code/Source/toolbar_icon.svg", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Code/Tests/${Name}EditorTest.cpp", + "origin": "Code/Tests/${Name}EditorTest.cpp", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Code/Tests/${Name}Test.cpp", + "origin": "Code/Tests/${Name}Test.cpp", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Android/android_gem.cmake", + "origin": "Platform/Android/android_gem.cmake", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Android/android_gem.json", + "origin": "Platform/Android/android_gem.json", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Linux/linux_gem.cmake", + "origin": "Platform/Linux/linux_gem.cmake", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Linux/linux_gem.json", + "origin": "Platform/Linux/linux_gem.json", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Mac/mac_gem.cmake", + "origin": "Platform/Mac/mac_gem.cmake", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Mac/mac_gem.json", + "origin": "Platform/Mac/mac_gem.json", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Windows/windows_gem.cmake", + "origin": "Platform/Windows/windows_gem.cmake", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/Windows/windows_gem.json", + "origin": "Platform/Windows/windows_gem.json", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/iOS/ios_gem.cmake", + "origin": "Platform/iOS/ios_gem.cmake", + "isTemplated": false, + "isOptional": false + }, + { + "file": "Platform/iOS/ios_gem.json", + "origin": "Platform/iOS/ios_gem.json", + "isTemplated": false, + "isOptional": false + }, + { + "file": "gem.json", + "origin": "gem.json", + "isTemplated": true, + "isOptional": false + }, + { + "file": "preview.png", + "origin": "preview.png", + "isTemplated": false, + "isOptional": false + } + ], + "createDirectories": [ + { + "dir": "Assets", + "origin": "Assets" + }, + { + "dir": "Code", + "origin": "Code" + }, + { + "dir": "Code/Include", + "origin": "Code/Include" + }, + { + "dir": "Code/Include/${Name}", + "origin": "Code/Include/${Name}" + }, + { + "dir": "Code/Platform", + "origin": "Code/Platform" + }, + { + "dir": "Code/Platform/Android", + "origin": "Code/Platform/Android" + }, + { + "dir": "Code/Platform/Linux", + "origin": "Code/Platform/Linux" + }, + { + "dir": "Code/Platform/Mac", + "origin": "Code/Platform/Mac" + }, + { + "dir": "Code/Platform/Windows", + "origin": "Code/Platform/Windows" + }, + { + "dir": "Code/Platform/iOS", + "origin": "Code/Platform/iOS" + }, + { + "dir": "Code/Source", + "origin": "Code/Source" + }, + { + "dir": "Code/Tests", + "origin": "Code/Tests" + }, + { + "dir": "Platform", + "origin": "Platform" + }, + { + "dir": "Platform/Android", + "origin": "Platform/Android" + }, + { + "dir": "Platform/Linux", + "origin": "Platform/Linux" + }, + { + "dir": "Platform/Mac", + "origin": "Platform/Mac" + }, + { + "dir": "Platform/Windows", + "origin": "Platform/Windows" + }, + { + "dir": "Platform/iOS", + "origin": "Platform/iOS" + } + ] +} diff --git a/engine.json b/engine.json index 2b56e255fc..3d522ce175 100644 --- a/engine.json +++ b/engine.json @@ -92,6 +92,7 @@ "templates": [ "Templates/AssetGem", "Templates/DefaultGem", + "Templates/CustomTool", "Templates/DefaultProject", "Templates/MinimalProject" ] From 6a2020ec6cc5ac94d9b3350c1faa063967e5c8b6 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 13 Oct 2021 14:32:12 -0700 Subject: [PATCH 244/293] fixes some warnings for newer versions of VS2022 Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Tests/Asset/AssetManagerLoadingTests.cpp | 3 +++ .../Tests/Debug/LocalFileEventLoggerTests.cpp | 6 ++++++ .../IO/Streamer/StorageDriveTests_Windows.cpp | 18 ++++++++++++++++++ Code/Framework/AzCore/Tests/StringFunc.cpp | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index 3e6376323c..e33dbce9c1 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -736,7 +736,10 @@ namespace UnitTest auto& assetManager = AssetManager::Instance(); AssetBusCallbacks callbacks{}; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning callbacks.SetOnAssetReadyCallback([&, AssetNoRefB](const Asset&, AssetBusCallbacks&) + AZ_POP_DISABLE_WARNING { // This callback should run inside the "main thread" dispatch events loop auto loadAsset = assetManager.GetAsset(AZ::Uuid(AssetNoRefB), AssetLoadBehavior::Default); diff --git a/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp b/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp index 242ac0e65d..d4b3351dbe 100644 --- a/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp +++ b/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp @@ -109,7 +109,10 @@ namespace AZ::Debug AZStd::thread threads[totalThreads]; for (size_t threadIndex = 0; threadIndex < totalThreads; ++threadIndex) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning threads[threadIndex] = AZStd::thread([&startLogging, &messages]() + AZ_POP_DISABLE_WARNING { while (!startLogging) { @@ -226,7 +229,10 @@ namespace AZ::Debug AZStd::thread threads[totalThreads]; for (size_t threadIndex = 0; threadIndex < totalThreads; ++threadIndex) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning threads[threadIndex] = AZStd::thread([&startLogging, &message, &totalRecordsWritten]() + AZ_POP_DISABLE_WARNING { AZ_UNUSED(message); diff --git a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp index 22fb6379d2..e312e2058d 100644 --- a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp +++ b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp @@ -597,7 +597,10 @@ namespace AZ::IO path.InitFromAbsolutePath(m_dummyFilepath); request->CreateRead(nullptr, buffer.get(), fileSize, path, 0, fileSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [&fileSize, this](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -639,7 +642,10 @@ namespace AZ::IO path.InitFromAbsolutePath(m_dummyFilepath); request->CreateRead(nullptr, buffer, unalignedSize + 4, path, unalignedOffset, unalignedSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [unalignedOffset, unalignedSize, this](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -784,7 +790,10 @@ namespace AZ::IO requests[i] = m_context->GetNewInternalRequest(); requests[i]->CreateRead(nullptr, buffers[i].get(), chunkSize, path, i * chunkSize, chunkSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [chunkSize, i](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -970,7 +979,10 @@ namespace AZ::IO i * chunkSize )); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [numChunks, &numCallbacks, &waitForReads](FileRequestHandle request) + AZ_POP_DISABLE_WARNING { IStreamer* streamer = Interface::Get(); if (streamer) @@ -1038,7 +1050,10 @@ namespace AZ::IO i * chunkSize )); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [numChunks, &waitForReads, &waitForSingleRead, &numReadCallbacks]([[maybe_unused]] FileRequestHandle request) + AZ_POP_DISABLE_WARNING { numReadCallbacks++; if (numReadCallbacks == 1) @@ -1059,7 +1074,10 @@ namespace AZ::IO for (size_t i = 0; i < numChunks; ++i) { cancels.push_back(m_streamer->Cancel(requests[numChunks - i - 1])); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [&numCancelCallbacks, &waitForCancels, numChunks](FileRequestHandle request) + AZ_POP_DISABLE_WARNING { auto result = Interface::Get()->GetRequestStatus(request); EXPECT_EQ(result, IStreamerTypes::RequestStatus::Completed); diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index 68821ba3f9..dc4bc40e5b 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -363,7 +363,10 @@ namespace AZ { constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" }; size_t visitIndex{}; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token) + AZ_POP_DISABLE_WARNING { if (visitIndex > visitTokens.size()) { @@ -389,7 +392,10 @@ namespace AZ { constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" }; size_t visitIndex = visitTokens.size() - 1; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token) + AZ_POP_DISABLE_WARNING { if (visitIndex > visitTokens.size()) { From 80dcc34e6fab19c89c6286b60668a81543009f14 Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Wed, 13 Oct 2021 16:46:30 -0500 Subject: [PATCH 245/293] Add "Registry" folders as scan folders (#4583) * Add "Registry" folders as scan folders For projects, Gems, and Engine, add the "Registry" folder as scan folders. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Change params for adding scan folder Also add trailing newlines to setreg files. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Adjust the priority order for project templates Scan folder orders were way too high, they should be very low to become highest priority order. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes change of default assets folder to Assets Need to revert this change so it can be done separately. Renamed the scan folder to 'Project/Assets' to prep for Assets folder change later on. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Update platform configuration test to pass Adjusted expectation of scan folder count from 1 to 2 per Gem for 'Assets' and 'Registry' now. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> --- .../AzFramework/AzFramework/Gem/GemInfo.h | 4 +++ .../platformconfigurationtests.cpp | 14 +++++---- .../utilities/PlatformConfiguration.cpp | 18 ++++++++++++ Registry/AssetProcessorPlatformConfig.setreg | 7 ++++- .../Registry/assets_scan_folders.setreg | 29 ++++++++++++------- .../Registry/assets_scan_folders.setreg | 29 ++++++++++++------- 6 files changed, 72 insertions(+), 29 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h index 1f300af770..3435d810fd 100644 --- a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h +++ b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.h @@ -29,6 +29,10 @@ namespace AzFramework AZStd::vector m_absoluteSourcePaths; //!< Where the gem's source path folder are located(as an absolute path) static constexpr const char* GetGemAssetFolder() { return "Assets"; } + static constexpr const char* GetGemRegistryFolder() + { + return "Registry"; + } }; //! Returns a list of GemInfo of all the gems that are active for the for the specified game project. diff --git a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp index 6f07901e27..69397745f1 100644 --- a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp @@ -590,20 +590,22 @@ TEST_F(PlatformConfigurationUnitTests, Test_GemHandling) AssetUtilities::ResetAssetRoot(); - ASSERT_EQ(2, config.GetScanFolderCount()); + ASSERT_EQ(4, config.GetScanFolderCount()); EXPECT_FALSE(config.GetScanFolderAt(0).IsRoot()); EXPECT_TRUE(config.GetScanFolderAt(0).RecurseSubFolders()); // the first one is a game gem, so its order should be above 1 but below 100. EXPECT_GE(config.GetScanFolderAt(0).GetOrder(), 100); EXPECT_EQ(0, config.GetScanFolderAt(0).ScanPath().compare(expectedScanFolder, Qt::CaseInsensitive)); - // for each gem, there are currently 1 scan folder, the gem assets folder, with no output prefix + // for each gem, there are currently 2 scan folders: + // The Gem's 'Assets' folder + // The Gem's 'Registry' folder expectedScanFolder = tempPath.absoluteFilePath("Gems/LmbrCentral/v2/Assets"); - EXPECT_FALSE(config.GetScanFolderAt(1).IsRoot() ); - EXPECT_TRUE(config.GetScanFolderAt(1).RecurseSubFolders()); - EXPECT_GT(config.GetScanFolderAt(1).GetOrder(), config.GetScanFolderAt(0).GetOrder()); - EXPECT_EQ(0, config.GetScanFolderAt(1).ScanPath().compare(expectedScanFolder, Qt::CaseInsensitive)); + EXPECT_FALSE(config.GetScanFolderAt(2).IsRoot() ); + EXPECT_TRUE(config.GetScanFolderAt(2).RecurseSubFolders()); + EXPECT_GT(config.GetScanFolderAt(2).GetOrder(), config.GetScanFolderAt(0).GetOrder()); + EXPECT_EQ(0, config.GetScanFolderAt(2).ScanPath().compare(expectedScanFolder, Qt::CaseInsensitive)); } TEST_F(PlatformConfigurationUnitTests, Test_MetaFileTypes) diff --git a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp index 52df8e901d..4a033cf6ca 100644 --- a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp @@ -1582,6 +1582,24 @@ namespace AssetProcessor gemOrder, /*scanFolderId*/ 0, /*canSaveNewAssets*/ true)); // Users can create assets like slices in Gem asset folders. + + // Now add another scan folder on Gem/GemName/Registry... + gemFolder = gemDir.absoluteFilePath(AzFramework::GemInfo::GetGemRegistryFolder()); + gemFolder = AssetUtilities::NormalizeDirectoryPath(gemFolder); + + assetBrowserDisplayName = AzFramework::GemInfo::GetGemRegistryFolder(); + portableKey = QString("gemregistry-%1").arg(gemNameAsUuid); + gemOrder++; + + AZ_TracePrintf(AssetProcessor::DebugChannel, "Adding GEM registry folder for monitoring / scanning: %s.\n", gemFolder.toUtf8().data()); + AddScanFolder(ScanFolderInfo( + gemFolder, + assetBrowserDisplayName, + portableKey, + isRoot, + isRecursive, + platforms, + gemOrder)); } } } diff --git a/Registry/AssetProcessorPlatformConfig.setreg b/Registry/AssetProcessorPlatformConfig.setreg index 3e90b063b5..ddc465c201 100644 --- a/Registry/AssetProcessorPlatformConfig.setreg +++ b/Registry/AssetProcessorPlatformConfig.setreg @@ -106,7 +106,7 @@ // "exclude": "mac" // } - "ScanFolder Game": { + "ScanFolder Project/Assets": { "watch": "@PROJECTROOT@", "display": "@PROJECTNAME@", "recursive": 1, @@ -129,6 +129,11 @@ "order": 30000, "include": "tools,renderer" }, + "ScanFolder Engine/Registry": { + "watch": "@ENGINEROOT@/Registry", + "recursive": 1, + "order": 40000 + }, // Excludes files that match the pattern or glob // if you use a pattern, remember to escape your backslashes (\\) diff --git a/Templates/DefaultProject/Template/Registry/assets_scan_folders.setreg b/Templates/DefaultProject/Template/Registry/assets_scan_folders.setreg index a42f65efb4..05f6314da4 100644 --- a/Templates/DefaultProject/Template/Registry/assets_scan_folders.setreg +++ b/Templates/DefaultProject/Template/Registry/assets_scan_folders.setreg @@ -1,14 +1,21 @@ { - "Amazon": - { - "${Name}.Assets": - { - "SourcePaths": - [ - "Assets", - "ShaderLib", - "Shaders" - ] + "Amazon": { + "AssetProcessor": { + "ScanFolder Project/ShaderLib": { + "watch": "@PROJECTROOT@/ShaderLib", + "recursive": 1, + "order": 1 + }, + "ScanFolder Project/Shaders": { + "watch": "@PROJECTROOT@/Shaders", + "recurisve": 1, + "order": 2 + }, + "ScanFolder Project/Registry": { + "watch": "@PROJECTROOT@/Registry", + "recursive": 1, + "order": 3 + } } } -} \ No newline at end of file +} diff --git a/Templates/MinimalProject/Template/Registry/assets_scan_folders.setreg b/Templates/MinimalProject/Template/Registry/assets_scan_folders.setreg index a42f65efb4..05f6314da4 100644 --- a/Templates/MinimalProject/Template/Registry/assets_scan_folders.setreg +++ b/Templates/MinimalProject/Template/Registry/assets_scan_folders.setreg @@ -1,14 +1,21 @@ { - "Amazon": - { - "${Name}.Assets": - { - "SourcePaths": - [ - "Assets", - "ShaderLib", - "Shaders" - ] + "Amazon": { + "AssetProcessor": { + "ScanFolder Project/ShaderLib": { + "watch": "@PROJECTROOT@/ShaderLib", + "recursive": 1, + "order": 1 + }, + "ScanFolder Project/Shaders": { + "watch": "@PROJECTROOT@/Shaders", + "recurisve": 1, + "order": 2 + }, + "ScanFolder Project/Registry": { + "watch": "@PROJECTROOT@/Registry", + "recursive": 1, + "order": 3 + } } } -} \ No newline at end of file +} From 937c2b2e88c325046bc0e6933af1f169b55af406 Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Wed, 13 Oct 2021 16:58:23 -0500 Subject: [PATCH 246/293] Terrain FP supports macro material component (#4587) * Adding basic support for TerrainMacroMaterialNotificationBus. Tracking macro materials in list. Signed-off-by: Ken Pruiksma (cherry picked from commit b4773454334de940d730620ffff300b46d6c611d) * Adding bus connection Signed-off-by: Ken Pruiksma (cherry picked from commit 66c99f503adb24f4be4f81716b544202d8e237d9) * Additions to indexed data vector to allow for getting an index from the data or deleting data with a reference to the data itself instead of the index. Additions to the feature processor for tracking macro material indices in sectors. Signed-off-by: Ken Pruiksma (cherry picked from commit 06365dbde5454e18e5fdf941f03b17b0d632027c) * Macro materials updating which macro materials are used in which sectors. Correctly handling construction / destruction. Signed-off-by: Ken Pruiksma * Updating the terrain macro material type to have the correct properties and also not attempt to render. Refactored some of the update loop in the TerrainFP to only rebuild the sectors when necessary, otherwise just update the srgs. Signed-off-by: Ken Pruiksma * Fixed up macro material to not try to actually render anything with shaders or hook to any shader data Terrain FP now pulls data pulling from macro material instance to use in the terrain material Various bug fixes around when terrain sectors needed reprocessing Signed-off-by: Ken Pruiksma * Adding basic support for TerrainMacroMaterialNotificationBus. Tracking macro materials in list. Signed-off-by: Ken Pruiksma (cherry picked from commit b4773454334de940d730620ffff300b46d6c611d) * Adding bus connection Signed-off-by: Ken Pruiksma (cherry picked from commit 66c99f503adb24f4be4f81716b544202d8e237d9) * Additions to indexed data vector to allow for getting an index from the data or deleting data with a reference to the data itself instead of the index. Additions to the feature processor for tracking macro material indices in sectors. Signed-off-by: Ken Pruiksma (cherry picked from commit 06365dbde5454e18e5fdf941f03b17b0d632027c) * Macro materials updating which macro materials are used in which sectors. Correctly handling construction / destruction. Signed-off-by: Ken Pruiksma * Updating the terrain macro material type to have the correct properties and also not attempt to render. Refactored some of the update loop in the TerrainFP to only rebuild the sectors when necessary, otherwise just update the srgs. Signed-off-by: Ken Pruiksma * Fixed up macro material to not try to actually render anything with shaders or hook to any shader data Terrain FP now pulls data pulling from macro material instance to use in the terrain material Various bug fixes around when terrain sectors needed reprocessing Signed-off-by: Ken Pruiksma * Constify all the things Signed-off-by: Ken Pruiksma * Updates from PR review. Signed-off-by: Ken Pruiksma --- .../Atom/Feature/Utils/IndexedDataVector.h | 2 + .../Atom/Feature/Utils/IndexedDataVector.inl | 20 + .../Terrain/DefaultPbrTerrain.material | 6 - .../Materials/Terrain/PbrTerrain.materialtype | 77 --- .../Terrain/TerrainMacroMaterial.materialtype | 63 ++- .../Shaders/Terrain/TerrainCommon.azsli | 26 +- .../Terrain/TerrainPBR_ForwardPass.azsl | 32 +- .../TerrainFeatureProcessor.cpp | 529 ++++++++++++++---- .../TerrainRenderer/TerrainFeatureProcessor.h | 83 ++- 9 files changed, 589 insertions(+), 249 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h index 37835bd6a8..82cc1e7d50 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h @@ -30,6 +30,7 @@ namespace AZ::Render void Clear(); IndexType GetFreeSlotIndex(); void RemoveIndex(IndexType index); + void RemoveData(DataType* data); DataType& GetData(IndexType index); const DataType& GetData(IndexType index) const; @@ -42,6 +43,7 @@ namespace AZ::Render const AZStd::vector& GetIndexVector() const; IndexType GetRawIndex(IndexType index) const; + IndexType GetIndexForData(const DataType* data) const; private: constexpr static size_t InitialReservedSize = 128; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl index 076caad7f4..581186dbcc 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl @@ -83,6 +83,16 @@ namespace AZ::Render m_indices.at(index) = m_firstFreeSlot; m_firstFreeSlot = index; } + + template + inline void IndexedDataVector::RemoveData(DataType* data) + { + IndexType indexForData = GetIndexForData(data); + if (indexForData != NoFreeSlot) + { + RemoveIndex(indexForData); + } + } template inline DataType& IndexedDataVector::GetData(IndexType index) @@ -131,4 +141,14 @@ namespace AZ::Render { return m_indices.at(index); } + + template + IndexType IndexedDataVector::GetIndexForData(const DataType* data) const + { + if (data >= &m_data.front() && data <= &m_data.back()) + { + return m_dataToIndices.at(data - &m_data.front()); + } + return NoFreeSlot; + } } // namespace AZ::Render diff --git a/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material b/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material index c0de5969b2..d2acc2516a 100644 --- a/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material +++ b/Gems/Terrain/Assets/Materials/Terrain/DefaultPbrTerrain.material @@ -4,12 +4,6 @@ "parentMaterial": "", "propertyLayoutVersion": 1, "properties": { - "macroColor": { - "useTexture": false - }, - "macroNormal": { - "useTexture": false - }, "baseColor": { "color": [ 0.18, 0.18, 0.18 ], "useTexture": false diff --git a/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype b/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype index 191fa7a731..ec04412fe6 100644 --- a/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype +++ b/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype @@ -133,67 +133,6 @@ } } ], - "macroColor": [ - { - "id": "textureMap", - "displayName": "Texture", - "description": "Macro color texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "id": "m_macroColorMap" - } - }, - { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - } - - ], - "macroNormal": [ - { - "id": "textureMap", - "displayName": "Texture", - "description": "Macro normal texture map", - "type": "Image", - "connection": { - "type": "ShaderInput", - "id": "m_macroNormalMap" - } - }, - { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true - }, - { - "id": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "id": "m_flipMacroNormalX" - } - }, - { - "id": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderInput", - "id": "m_flipMacroNormalY" - } - } - ], "baseColor": [ { "id": "color", @@ -380,22 +319,6 @@ } ], "functors": [ - { - "type": "UseTexture", - "args": { - "textureProperty": "macroColor.textureMap", - "useTextureProperty": "macroColor.useTexture", - "shaderOption": "o_macroColor_useTexture" - } - }, - { - "type": "UseTexture", - "args": { - "textureProperty": "macroNormal.textureMap", - "useTextureProperty": "macroNormal.useTexture", - "shaderOption": "o_macroNormal_useTexture" - } - }, { "type": "UseTexture", "args": { diff --git a/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype b/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype index 0a4f6d0229..3cdab8da10 100644 --- a/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype +++ b/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype @@ -4,42 +4,59 @@ "version": 1, "groups": [ { - "id": "settings", - "displayName": "Settings" + "name": "baseColor", + "displayName": "Base Color", + "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." + }, + { + "name": "normal", + "displayName": "Normal", + "description": "Properties related to configuring surface normal." } ], "properties": { - "macroColor": [ + "baseColor": [ { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", - "type": "Bool", - "defaultValue": true + "name": "textureMap", + "displayName": "Texture", + "description": "Base color of the macro material", + "type": "Image" } - ], - "macroNormal": [ + "normal": [ { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture.", + "name": "textureMap", + "displayName": "Texture", + "description": "Texture for defining surface normal direction. These will override normals generated from the geometry.", + "type": "Image" + }, + { + "name": "flipX", + "displayName": "Flip X Channel", + "description": "Flip tangent direction for this normal map.", "type": "Bool", - "defaultValue": true + "defaultValue": false + }, + { + "name": "flipY", + "displayName": "Flip Y Channel", + "description": "Flip bitangent direction for this normal map.", + "type": "Bool", + "defaultValue": false + }, + { + "name": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0 } ] } }, "shaders": [ - { - "file": "../../Shaders/Terrain/TerrainPBR_ForwardPass.shader" - }, - { - "file": "../../Shaders/Terrain/Terrain_Shadowmap.shader" - }, - { - "file": "../../Shaders/Terrain/Terrain_DepthPass.shader" - } ], "functors": [ ] diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli index 95d1a73bbd..72c1af953c 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli @@ -26,8 +26,24 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float m_heightScale; }; + struct MacroMaterialData + { + float2 m_uvMin; + float2 m_uvMax; + float m_normalFactor; + bool m_flipNormalX; + bool m_flipNormalY; + uint m_mapsInUse; + }; + TerrainData m_terrainData; + MacroMaterialData m_macroMaterialData[4]; + uint m_macroMaterialCount; + + Texture2D m_macroColorMap[4]; + Texture2D m_macroNormalMap[4]; + // The below shouldn't be in this SRG but needs to be for now because the lighting functions depend on them. //! Reflection Probe (smallest probe volume that overlaps the object position) @@ -101,14 +117,6 @@ ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial MaxAnisotropy = 16; }; - // Macro Color - Texture2D m_macroColorMap; - - // Macro normal - Texture2D m_macroNormalMap; - bool m_flipMacroNormalX; - bool m_flipMacroNormalY; - // Base Color float3 m_baseColor; float m_baseColorFactor; @@ -130,8 +138,6 @@ ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial } option bool o_useTerrainSmoothing = false; -option bool o_macroColor_useTexture = true; -option bool o_macroNormal_useTexture = true; option bool o_baseColor_useTexture = true; option bool o_specularF0_useTexture = true; option bool o_normal_useTexture = true; diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl index fedd19a498..91e367500b 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl @@ -68,7 +68,6 @@ VSOutput TerrainPBR_MainPassVS(VertexInput IN) ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) { // ------- Surface ------- - Surface surface; // Position @@ -83,12 +82,32 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) // ------- Normal ------- float3 macroNormal = IN.m_normal; - if (o_macroNormal_useTexture) + + // ------- Macro Color / Normal ------- + float3 macroColor = TerrainMaterialSrg::m_baseColor.rgb; + [unroll] for (uint i = 0; i < 4; ++i) { - macroNormal = GetNormalInputTS(TerrainMaterialSrg::m_macroNormalMap, TerrainMaterialSrg::m_sampler, - origUv, TerrainMaterialSrg::m_flipMacroNormalX, TerrainMaterialSrg::m_flipMacroNormalY, CreateIdentity3x3(), true, 1.0); + float2 macroUvMin = ObjectSrg::m_macroMaterialData[i].m_uvMin; + float2 macroUvMax = ObjectSrg::m_macroMaterialData[i].m_uvMax; + float2 macroUv = lerp(macroUvMin, macroUvMax, IN.m_uv); + if (macroUv.x >= 0.0 && macroUv.x <= 1.0 && macroUv.y >= 0.0 && macroUv.y <= 1.0) + { + if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 1) > 0) + { + macroColor = GetBaseColorInput(ObjectSrg::m_macroColorMap[i], TerrainMaterialSrg::m_sampler, macroUv, macroColor, true); + } + if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 2) > 0) + { + bool flipX = ObjectSrg::m_macroMaterialData[i].m_flipNormalX; + bool flipY = ObjectSrg::m_macroMaterialData[i].m_flipNormalY; + bool factor = ObjectSrg::m_macroMaterialData[i].m_normalFactor; + macroNormal = GetNormalInputTS(ObjectSrg::m_macroNormalMap[i], TerrainMaterialSrg::m_sampler, + macroUv, flipX, flipY, CreateIdentity3x3(), true, factor); + } + break; + } } - + float3 detailNormal = GetNormalInputTS(TerrainMaterialSrg::m_normalMap, TerrainMaterialSrg::m_sampler, detailUv, TerrainMaterialSrg::m_flipNormalX, TerrainMaterialSrg::m_flipNormalY, CreateIdentity3x3(), o_normal_useTexture, TerrainMaterialSrg::m_normalFactor); @@ -97,9 +116,6 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) surface.normal = normalize(surface.normal); surface.vertexNormal = normalize(IN.m_normal); - // ------- Macro Color ------- - float3 macroColor = GetBaseColorInput(TerrainMaterialSrg::m_macroColorMap, TerrainMaterialSrg::m_sampler, origUv, TerrainMaterialSrg::m_baseColor.rgb, o_baseColor_useTexture); - // ------- Base Color ------- float3 detailColor = GetBaseColorInput(TerrainMaterialSrg::m_baseColorMap, TerrainMaterialSrg::m_sampler, detailUv, TerrainMaterialSrg::m_baseColor.rgb, o_baseColor_useTexture); float3 blendedColor = BlendBaseColor(lerp(detailColor, TerrainMaterialSrg::m_baseColor.rgb, detailFactor), macroColor, TerrainMaterialSrg::m_baseColorFactor, o_baseColorTextureBlendMode, o_baseColor_useTexture); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index 560fe1eb60..d7300cdc48 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -49,13 +49,25 @@ namespace Terrain namespace MaterialInputs { + // Terrain material static const char* const HeightmapImage("settings.heightmapImage"); + + // Macro material + static const char* const MacroColorTextureMap("baseColor.textureMap"); + static const char* const MacroNormalTextureMap("normal.textureMap"); + static const char* const MacroNormalFlipX("normal.flipX"); + static const char* const MacroNormalFlipY("normal.flipY"); + static const char* const MacroNormalFactor("normal.factor"); } namespace ShaderInputs { static const char* const ModelToWorld("m_modelToWorld"); static const char* const TerrainData("m_terrainData"); + static const char* const MacroMaterialData("m_macroMaterialData"); + static const char* const MacroMaterialCount("m_macroMaterialCount"); + static const char* const MacroColorMap("m_macroColorMap"); + static const char* const MacroNormalMap("m_macroNormalMap"); } @@ -71,8 +83,6 @@ namespace Terrain void TerrainFeatureProcessor::Activate() { - m_areaData = {}; - m_dirtyRegion = AZ::Aabb::CreateNull(); Initialize(); AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect(); } @@ -94,6 +104,10 @@ namespace Terrain { AZ_Error("TerrainFeatureProcessor", false, "No per-object ShaderResourceGroup found on terrain material."); } + else + { + PrepareMaterialData(); + } } } ); @@ -107,11 +121,17 @@ namespace Terrain void TerrainFeatureProcessor::Deactivate() { + TerrainMacroMaterialNotificationBus::Handler::BusDisconnect(); AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect(); AZ::RPI::MaterialReloadNotificationBus::Handler::BusDisconnect(); m_patchModel = {}; m_areaData = {}; + m_dirtyRegion = AZ::Aabb::CreateNull(); + m_sectorData.clear(); + m_macroMaterials.Clear(); + m_materialAssetLoader = {}; + m_materialInstance = {}; } void TerrainFeatureProcessor::Render(const AZ::RPI::FeatureProcessor::RenderPacket& packet) @@ -126,7 +146,7 @@ namespace Terrain void TerrainFeatureProcessor::OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) { - if (dataChangedMask != TerrainDataChangedMask::HeightData && dataChangedMask != TerrainDataChangedMask::Settings) + if ((dataChangedMask & (TerrainDataChangedMask::HeightData | TerrainDataChangedMask::Settings)) == 0) { return; } @@ -140,14 +160,21 @@ namespace Terrain m_dirtyRegion.AddAabb(regionToUpdate); m_dirtyRegion.Clamp(worldBounds); - AZ::Transform transform = AZ::Transform::CreateTranslation(worldBounds.GetCenter()); + const AZ::Transform transform = AZ::Transform::CreateTranslation(worldBounds.GetCenter()); AZ::Vector2 queryResolution = AZ::Vector2(1.0f); AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution); + // Sectors need to be rebuilt if the world bounds change in the x/y, or the sample spacing changes. + m_areaData.m_rebuildSectors = m_areaData.m_rebuildSectors || + m_areaData.m_terrainBounds.GetMin().GetX() != worldBounds.GetMin().GetX() || + m_areaData.m_terrainBounds.GetMin().GetY() != worldBounds.GetMin().GetY() || + m_areaData.m_terrainBounds.GetMax().GetX() != worldBounds.GetMax().GetX() || + m_areaData.m_terrainBounds.GetMax().GetY() != worldBounds.GetMax().GetY() || + m_areaData.m_sampleSpacing != queryResolution.GetX(); + m_areaData.m_transform = transform; - m_areaData.m_heightScale = worldBounds.GetZExtent(); m_areaData.m_terrainBounds = worldBounds; m_areaData.m_heightmapImageWidth = aznumeric_cast(worldBounds.GetXExtent() / queryResolution.GetX()); m_areaData.m_heightmapImageHeight = aznumeric_cast(worldBounds.GetYExtent() / queryResolution.GetY()); @@ -155,7 +182,93 @@ namespace Terrain m_areaData.m_updateHeight = aznumeric_cast(m_dirtyRegion.GetYExtent() / queryResolution.GetY()); // Currently query resolution is multidimensional but the rendering system only supports this changing in one dimension. m_areaData.m_sampleSpacing = queryResolution.GetX(); - m_areaData.m_propertiesDirty = true; + m_areaData.m_heightmapUpdated = true; + } + + void TerrainFeatureProcessor::OnTerrainMacroMaterialCreated(AZ::EntityId entityId, MaterialInstance material, const AZ::Aabb& region) + { + MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId); + materialData.m_bounds = region; + + UpdateMacroMaterialData(materialData, material); + + // Update all sectors in region. + ForOverlappingSectors(materialData.m_bounds, + [&](SectorData& sectorData) { + if (sectorData.m_macroMaterials.size() < sectorData.m_macroMaterials.max_size()) + { + sectorData.m_macroMaterials.push_back(m_macroMaterials.GetIndexForData(&materialData)); + } + } + ); + } + + void TerrainFeatureProcessor::OnTerrainMacroMaterialChanged(AZ::EntityId entityId, MaterialInstance macroMaterial) + { + if (macroMaterial) + { + MacroMaterialData& data = FindOrCreateMacroMaterial(entityId); + UpdateMacroMaterialData(data, macroMaterial); + } + else + { + RemoveMacroMaterial(entityId); + } + } + + void TerrainFeatureProcessor::OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) + { + MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId); + for (SectorData& sectorData : m_sectorData) + { + bool overlapsOld = sectorData.m_aabb.Overlaps(materialData.m_bounds); + bool overlapsNew = sectorData.m_aabb.Overlaps(newRegion); + if (overlapsOld && !overlapsNew) + { + // Remove the macro material from this sector + for (uint16_t& idx : sectorData.m_macroMaterials) + { + if (m_macroMaterials.GetData(idx).m_entityId == entityId) + { + idx = sectorData.m_macroMaterials.back(); + sectorData.m_macroMaterials.pop_back(); + } + } + } + else if (overlapsNew && !overlapsOld) + { + // Add the macro material to this sector + if (sectorData.m_macroMaterials.size() < MaxMaterialsPerSector) + { + sectorData.m_macroMaterials.push_back(m_macroMaterials.GetIndexForData(&materialData)); + } + } + } + m_areaData.m_macroMaterialsUpdated = true; + materialData.m_bounds = newRegion; + } + + void TerrainFeatureProcessor::OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId) + { + MacroMaterialData* materialData = FindMacroMaterial(entityId); + + if (materialData) + { + uint16_t destroyedMaterialIndex = m_macroMaterials.GetIndexForData(materialData); + ForOverlappingSectors(materialData->m_bounds, + [&](SectorData& sectorData) { + for (uint16_t& idx : sectorData.m_macroMaterials) + { + if (idx == destroyedMaterialIndex) + { + idx = sectorData.m_macroMaterials.back(); + sectorData.m_macroMaterials.pop_back(); + } + } + }); + } + + m_areaData.m_macroMaterialsUpdated = true; } void TerrainFeatureProcessor::UpdateTerrainData() @@ -165,9 +278,9 @@ namespace Terrain uint32_t width = m_areaData.m_updateWidth; uint32_t height = m_areaData.m_updateHeight; const AZ::Aabb& worldBounds = m_areaData.m_terrainBounds; - float queryResolution = m_areaData.m_sampleSpacing; + const float queryResolution = m_areaData.m_sampleSpacing; - AZ::RHI::Size worldSize = AZ::RHI::Size(m_areaData.m_heightmapImageWidth, m_areaData.m_heightmapImageHeight, 1); + const AZ::RHI::Size worldSize = AZ::RHI::Size(m_areaData.m_heightmapImageWidth, m_areaData.m_heightmapImageHeight, 1); if (!m_areaData.m_heightmapImage || m_areaData.m_heightmapImage->GetDescriptor().m_size != worldSize) { @@ -176,7 +289,7 @@ namespace Terrain height = worldSize.m_height; m_dirtyRegion = worldBounds; - AZ::Data::Instance imagePool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); + const AZ::Data::Instance imagePool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D( AZ::RHI::ImageBindFlags::ShaderRead, width, height, AZ::RHI::Format::R16_UNORM ); @@ -210,9 +323,9 @@ namespace Terrain AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, &terrainExists); - float clampedHeight = AZ::GetClamp((terrainHeight - worldBounds.GetMin().GetZ()) / worldBounds.GetExtents().GetZ(), 0.0f, 1.0f); - float expandedHeight = AZStd::roundf(clampedHeight * AZStd::numeric_limits::max()); - uint16_t uint16Height = aznumeric_cast(expandedHeight); + const float clampedHeight = AZ::GetClamp((terrainHeight - worldBounds.GetMin().GetZ()) / worldBounds.GetExtents().GetZ(), 0.0f, 1.0f); + const float expandedHeight = AZStd::roundf(clampedHeight * AZStd::numeric_limits::max()); + const uint16_t uint16Height = aznumeric_cast(expandedHeight); pixels.push_back(uint16Height); } @@ -241,118 +354,248 @@ namespace Terrain m_dirtyRegion = AZ::Aabb::CreateNull(); } + void TerrainFeatureProcessor::PrepareMaterialData() + { + const auto layout = m_materialInstance->GetAsset()->GetObjectSrgLayout(); + + m_modelToWorldIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::ModelToWorld)); + AZ_Error(TerrainFPName, m_modelToWorldIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::ModelToWorld); + + m_terrainDataIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::TerrainData)); + AZ_Error(TerrainFPName, m_terrainDataIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::TerrainData); + + m_macroMaterialDataIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::MacroMaterialData)); + AZ_Error(TerrainFPName, m_macroMaterialDataIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::MacroMaterialData); + + m_macroMaterialCountIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::MacroMaterialCount)); + AZ_Error(TerrainFPName, m_macroMaterialCountIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::MacroMaterialCount); + + m_macroColorMapIndex = layout->FindShaderInputImageIndex(AZ::Name(ShaderInputs::MacroColorMap)); + AZ_Error(TerrainFPName, m_macroColorMapIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::MacroColorMap); + + m_macroNormalMapIndex = layout->FindShaderInputImageIndex(AZ::Name(ShaderInputs::MacroNormalMap)); + AZ_Error(TerrainFPName, m_macroNormalMapIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::MacroNormalMap); + + m_heightmapPropertyIndex = m_materialInstance->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name(MaterialInputs::HeightmapImage)); + AZ_Error(TerrainFPName, m_heightmapPropertyIndex.IsValid(), "Failed to find material input constant %s.", MaterialInputs::HeightmapImage); + + TerrainMacroMaterialRequestBus::EnumerateHandlers( + [&](TerrainMacroMaterialRequests* handler) + { + MaterialInstance macroMaterial; + AZ::Aabb bounds; + handler->GetTerrainMacroMaterialData(macroMaterial, bounds); + AZ::EntityId entityId = *(Terrain::TerrainMacroMaterialRequestBus::GetCurrentBusId()); + OnTerrainMacroMaterialCreated(entityId, macroMaterial, bounds); + return true; + } + ); + TerrainMacroMaterialNotificationBus::Handler::BusConnect(); + } + + void TerrainFeatureProcessor::UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, MaterialInstance material) + { + // Since we're using an actual macro material instance for now, get the values from it that we care about. + const auto materialLayout = material->GetMaterialPropertiesLayout(); + + const AZ::RPI::MaterialPropertyIndex macroColorTextureMapIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroColorTextureMap)); + AZ_Error(TerrainFPName, macroColorTextureMapIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroColorTextureMap); + + const AZ::RPI::MaterialPropertyIndex macroNormalTextureMapIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalTextureMap)); + AZ_Error(TerrainFPName, macroNormalTextureMapIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalTextureMap); + + const AZ::RPI::MaterialPropertyIndex macroNormalFlipXIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFlipX)); + AZ_Error(TerrainFPName, macroNormalFlipXIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFlipX); + + const AZ::RPI::MaterialPropertyIndex macroNormalFlipYIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFlipY)); + AZ_Error(TerrainFPName, macroNormalFlipYIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFlipY); + + const AZ::RPI::MaterialPropertyIndex macroNormalFactorIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFactor)); + AZ_Error(TerrainFPName, macroNormalFactorIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFactor); + + macroMaterialData.m_colorImage = material->GetPropertyValue(macroColorTextureMapIndex).GetValue>(); + macroMaterialData.m_normalImage = material->GetPropertyValue(macroNormalTextureMapIndex).GetValue>(); + macroMaterialData.m_normalFlipX = material->GetPropertyValue(macroNormalFlipXIndex).GetValue(); + macroMaterialData.m_normalFlipY = material->GetPropertyValue(macroNormalFlipYIndex).GetValue(); + macroMaterialData.m_normalFactor = material->GetPropertyValue(macroNormalFactorIndex).GetValue(); + + if (macroMaterialData.m_bounds.IsValid()) + { + m_areaData.m_macroMaterialsUpdated = true; + } + } + void TerrainFeatureProcessor::ProcessSurfaces(const FeatureProcessor::RenderPacket& process) { AZ_PROFILE_FUNCTION(AzRender); + + const AZ::Aabb& terrainBounds = m_areaData.m_terrainBounds; - if (!m_areaData.m_terrainBounds.IsValid()) + if (!terrainBounds.IsValid()) { return; } - - if (m_areaData.m_propertiesDirty && m_materialInstance && m_materialInstance->CanCompile()) - { - UpdateTerrainData(); - m_areaData.m_propertiesDirty = false; - m_sectorData.clear(); + if (m_materialInstance && m_materialInstance->CanCompile()) + { + if (m_areaData.m_rebuildSectors) + { + // Something about the whole world changed, so the sectors need to be rebuilt - AZ::RPI::MaterialPropertyIndex heightmapPropertyIndex = - m_materialInstance->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name(MaterialInputs::HeightmapImage)); - AZ_Error(TerrainFPName, heightmapPropertyIndex.IsValid(), "Failed to find material input constant %s.", MaterialInputs::HeightmapImage); - AZ::Data::Instance heightmapImage = m_areaData.m_heightmapImage; - m_materialInstance->SetPropertyValue(heightmapPropertyIndex, heightmapImage); - m_materialInstance->Compile(); + m_areaData.m_rebuildSectors = false; - const auto layout = m_materialInstance->GetAsset()->GetObjectSrgLayout(); + m_sectorData.clear(); + const float xFirstPatchStart = terrainBounds.GetMin().GetX() - fmod(terrainBounds.GetMin().GetX(), GridMeters); + const float xLastPatchStart = terrainBounds.GetMax().GetX() - fmod(terrainBounds.GetMax().GetX(), GridMeters); + const float yFirstPatchStart = terrainBounds.GetMin().GetY() - fmod(terrainBounds.GetMin().GetY(), GridMeters); + const float yLastPatchStart = terrainBounds.GetMax().GetY() - fmod(terrainBounds.GetMax().GetY(), GridMeters); + + const auto& materialAsset = m_materialInstance->GetAsset(); + const auto& shaderAsset = materialAsset->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg(); - m_modelToWorldIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::ModelToWorld)); - AZ_Error(TerrainFPName, m_modelToWorldIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::ModelToWorld); + for (float yPatch = yFirstPatchStart; yPatch <= yLastPatchStart; yPatch += GridMeters) + { + for (float xPatch = xFirstPatchStart; xPatch <= xLastPatchStart; xPatch += GridMeters) + { + auto objectSrg = AZ::RPI::ShaderResourceGroup::Create(shaderAsset, materialAsset->GetObjectSrgLayout()->GetName()); + if (!objectSrg) + { + AZ_Warning("TerrainFeatureProcessor", false, "Failed to create a new shader resource group, skipping."); + continue; + } + + m_sectorData.push_back(); + SectorData& sectorData = m_sectorData.back(); - m_terrainDataIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::TerrainData)); - AZ_Error(TerrainFPName, m_terrainDataIndex.IsValid(), "Failed to find shader input constant %s.", ShaderInputs::TerrainData); + for (auto& lod : m_patchModel->GetLods()) + { + AZ::RPI::ModelLod& modelLod = *lod.get(); + sectorData.m_drawPackets.emplace_back(modelLod, 0, m_materialInstance, objectSrg); + AZ::RPI::MeshDrawPacket& drawPacket = sectorData.m_drawPackets.back(); + + // set the shader option to select forward pass IBL specular if necessary + if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ false })) + { + AZ_Warning("MeshDrawPacket", false, "Failed to set o_meshUseForwardPassIBLSpecular on mesh draw packet"); + } + const uint8_t stencilRef = AZ::Render::StencilRefs::UseDiffuseGIPass | AZ::Render::StencilRefs::UseIBLSpecularPass; + drawPacket.SetStencilRef(stencilRef); + drawPacket.Update(*GetParentScene(), true); + } - float xFirstPatchStart = - m_areaData.m_terrainBounds.GetMin().GetX() - fmod(m_areaData.m_terrainBounds.GetMin().GetX(), GridMeters); - float xLastPatchStart = m_areaData.m_terrainBounds.GetMax().GetX() - fmod(m_areaData.m_terrainBounds.GetMax().GetX(), GridMeters); - float yFirstPatchStart = - m_areaData.m_terrainBounds.GetMin().GetY() - fmod(m_areaData.m_terrainBounds.GetMin().GetY(), GridMeters); - float yLastPatchStart = m_areaData.m_terrainBounds.GetMax().GetY() - fmod(m_areaData.m_terrainBounds.GetMax().GetY(), GridMeters); + sectorData.m_aabb = + AZ::Aabb::CreateFromMinMax( + AZ::Vector3(xPatch, yPatch, terrainBounds.GetMin().GetZ()), + AZ::Vector3(xPatch + GridMeters, yPatch + GridMeters, terrainBounds.GetMax().GetZ()) + ); + sectorData.m_srg = objectSrg; + } + } - for (float yPatch = yFirstPatchStart; yPatch <= yLastPatchStart; yPatch += GridMeters) - { - for (float xPatch = xFirstPatchStart; xPatch <= xLastPatchStart; xPatch += GridMeters) + if (m_areaData.m_macroMaterialsUpdated) { - const auto& materialAsset = m_materialInstance->GetAsset(); - auto& shaderAsset = materialAsset->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg(); - auto objectSrg = AZ::RPI::ShaderResourceGroup::Create(shaderAsset, materialAsset->GetObjectSrgLayout()->GetName()); - if (!objectSrg) + // sectors were rebuilt, so any cached macro material data needs to be regenerated + for (SectorData& sectorData : m_sectorData) { - AZ_Warning("TerrainFeatureProcessor", false, "Failed to create a new shader resource group, skipping."); - continue; + for (MacroMaterialData& macroMaterialData : m_macroMaterials.GetDataVector()) + { + if (macroMaterialData.m_bounds.Overlaps(sectorData.m_aabb)) + { + sectorData.m_macroMaterials.push_back(m_macroMaterials.GetIndexForData(¯oMaterialData)); + if (sectorData.m_macroMaterials.size() == MaxMaterialsPerSector) + { + break; + } + } + } } + } + } - { // Update SRG - - AZStd::array uvMin = { 0.0f, 0.0f }; - AZStd::array uvMax = { 1.0f, 1.0f }; + if (m_areaData.m_heightmapUpdated) + { + UpdateTerrainData(); - uvMin[0] = (float)((xPatch - m_areaData.m_terrainBounds.GetMin().GetX()) / m_areaData.m_terrainBounds.GetXExtent()); - uvMin[1] = (float)((yPatch - m_areaData.m_terrainBounds.GetMin().GetY()) / m_areaData.m_terrainBounds.GetYExtent()); + const AZ::Data::Instance heightmapImage = m_areaData.m_heightmapImage; + m_materialInstance->SetPropertyValue(m_heightmapPropertyIndex, heightmapImage); + m_materialInstance->Compile(); + } - uvMax[0] = - (float)(((xPatch + GridMeters) - m_areaData.m_terrainBounds.GetMin().GetX()) / m_areaData.m_terrainBounds.GetXExtent()); - uvMax[1] = - (float)(((yPatch + GridMeters) - m_areaData.m_terrainBounds.GetMin().GetY()) / m_areaData.m_terrainBounds.GetYExtent()); + if (m_areaData.m_heightmapUpdated || m_areaData.m_macroMaterialsUpdated) + { + // Currently when anything in the heightmap changes we're updating all the srgs, but this could probably + // be optimized to only update the srgs that changed. - AZStd::array uvStep = - { - 1.0f / m_areaData.m_heightmapImageWidth, 1.0f / m_areaData.m_heightmapImageHeight, - }; + m_areaData.m_heightmapUpdated = false; + m_areaData.m_macroMaterialsUpdated = false; - AZ::Transform transform = m_areaData.m_transform; - transform.SetTranslation(xPatch, yPatch, m_areaData.m_transform.GetTranslation().GetZ()); + for (SectorData& sectorData : m_sectorData) + { + ShaderTerrainData terrainDataForSrg; + + const float xPatch = sectorData.m_aabb.GetMin().GetX(); + const float yPatch = sectorData.m_aabb.GetMin().GetY(); + + terrainDataForSrg.m_uvMin = { + (xPatch - terrainBounds.GetMin().GetX()) / terrainBounds.GetXExtent(), + (yPatch - terrainBounds.GetMin().GetY()) / terrainBounds.GetYExtent() + }; + + terrainDataForSrg.m_uvMax = { + ((xPatch + GridMeters) - terrainBounds.GetMin().GetX()) / terrainBounds.GetXExtent(), + ((yPatch + GridMeters) - terrainBounds.GetMin().GetY()) / terrainBounds.GetYExtent() + }; + + terrainDataForSrg.m_uvStep = + { + 1.0f / m_areaData.m_heightmapImageWidth, + 1.0f / m_areaData.m_heightmapImageHeight, + }; - AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromTransform(transform); + AZ::Transform transform = m_areaData.m_transform; + transform.SetTranslation(xPatch, yPatch, m_areaData.m_transform.GetTranslation().GetZ()); - objectSrg->SetConstant(m_modelToWorldIndex, matrix3x4); + terrainDataForSrg.m_sampleSpacing = m_areaData.m_sampleSpacing; + terrainDataForSrg.m_heightScale = terrainBounds.GetZExtent(); - ShaderTerrainData terrainDataForSrg; - terrainDataForSrg.m_sampleSpacing = m_areaData.m_sampleSpacing; - terrainDataForSrg.m_heightScale = m_areaData.m_heightScale; - terrainDataForSrg.m_uvMin = uvMin; - terrainDataForSrg.m_uvMax = uvMax; - terrainDataForSrg.m_uvStep = uvStep; - objectSrg->SetConstant(m_terrainDataIndex, terrainDataForSrg); + sectorData.m_srg->SetConstant(m_terrainDataIndex, terrainDataForSrg); - objectSrg->Compile(); - } + AZStd::array macroMaterialData; + for (uint32_t i = 0; i < sectorData.m_macroMaterials.size(); ++i) + { + const MacroMaterialData& materialData = m_macroMaterials.GetData(sectorData.m_macroMaterials.at(i)); + ShaderMacroMaterialData& shaderData = macroMaterialData.at(i); + const AZ::Aabb& materialBounds = materialData.m_bounds; - m_sectorData.push_back(); - SectorData& sectorData = m_sectorData.back(); + shaderData.m_uvMin = { + (xPatch - materialBounds.GetMin().GetX()) / materialBounds.GetXExtent(), + (yPatch - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent() + }; + shaderData.m_uvMax = { + ((xPatch + GridMeters) - materialBounds.GetMin().GetX()) / materialBounds.GetXExtent(), + ((yPatch + GridMeters) - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent() + }; + shaderData.m_normalFactor = materialData.m_normalFactor; + shaderData.m_flipNormalX = materialData.m_normalFlipX; + shaderData.m_flipNormalY = materialData.m_normalFlipY; - for (auto& lod : m_patchModel->GetLods()) - { - AZ::RPI::ModelLod& modelLod = *lod.get(); - sectorData.m_drawPackets.emplace_back(modelLod, 0, m_materialInstance, objectSrg); - AZ::RPI::MeshDrawPacket& drawPacket = sectorData.m_drawPackets.back(); + const AZ::RHI::ImageView* colorImageView = materialData.m_colorImage ? materialData.m_colorImage->GetImageView() : nullptr; + sectorData.m_srg->SetImageView(m_macroColorMapIndex, colorImageView, i); + + const AZ::RHI::ImageView* normalImageView = materialData.m_normalImage ? materialData.m_normalImage->GetImageView() : nullptr; + sectorData.m_srg->SetImageView(m_macroNormalMapIndex, normalImageView, i); - // set the shader option to select forward pass IBL specular if necessary - if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ false })) - { - AZ_Warning("MeshDrawPacket", false, "Failed to set o_meshUseForwardPassIBLSpecular on mesh draw packet"); - } - uint8_t stencilRef = AZ::Render::StencilRefs::UseDiffuseGIPass | AZ::Render::StencilRefs::UseIBLSpecularPass; - drawPacket.SetStencilRef(stencilRef); - drawPacket.Update(*GetParentScene(), true); + // set flags for which images are used. + shaderData.m_mapsInUse = (colorImageView ? ColorImageUsed : 0) | (normalImageView ? NormalImageUsed : 0); } - sectorData.m_aabb = - AZ::Aabb::CreateFromMinMax( - AZ::Vector3(xPatch, yPatch, m_areaData.m_terrainBounds.GetMin().GetZ()), - AZ::Vector3(xPatch + GridMeters, yPatch + GridMeters, m_areaData.m_terrainBounds.GetMax().GetZ()) - ); - sectorData.m_srg = objectSrg; + sectorData.m_srg->SetConstantArray(m_macroMaterialDataIndex, macroMaterialData); + sectorData.m_srg->SetConstant(m_macroMaterialCountIndex, aznumeric_cast(sectorData.m_macroMaterials.size())); + + const AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromTransform(transform); + sectorData.m_srg->SetConstant(m_modelToWorldIndex, matrix3x4); + + sectorData.m_srg->Compile(); } } } @@ -366,12 +609,20 @@ namespace Terrain { if ((view->GetUsageFlags() & AZ::RPI::View::UsageFlags::UsageCamera) > 0) { - AZ::Vector3 cameraPosition = view->GetCameraTransform().GetTranslation(); - AZ::Vector2 cameraPositionXY = AZ::Vector2(cameraPosition.GetX(), cameraPosition.GetY()); - AZ::Vector2 sectorCenterXY = AZ::Vector2(sectorData.m_aabb.GetCenter().GetX(), sectorData.m_aabb.GetCenter().GetY()); + const AZ::Vector3 cameraPosition = view->GetCameraTransform().GetTranslation(); + const AZ::Vector2 cameraPositionXY = AZ::Vector2(cameraPosition.GetX(), cameraPosition.GetY()); + const AZ::Vector2 sectorCenterXY = AZ::Vector2(sectorData.m_aabb.GetCenter().GetX(), sectorData.m_aabb.GetCenter().GetY()); + + const float sectorDistance = sectorCenterXY.GetDistance(cameraPositionXY); - float sectorDistance = sectorCenterXY.GetDistance(cameraPositionXY); - float lodForCamera = floorf(AZ::GetMax(0.0f, log2f(sectorDistance / (GridMeters * 4.0f)))); + // This will be configurable later + const float minDistanceForLod0 = (GridMeters * 4.0f); + + // For every distance doubling beyond a minDistanceForLod0, we only need half the mesh density. Each LOD + // is exactly half the resolution of the last. + const float lodForCamera = floorf(AZ::GetMax(0.0f, log2f(sectorDistance / minDistanceForLod0))); + + // All cameras should render the same LOD so effects like shadows are consistent. lodChoice = AZ::GetMin(lodChoice, aznumeric_cast(lodForCamera)); } } @@ -382,7 +633,7 @@ namespace Terrain AZ::Frustum viewFrustum = AZ::Frustum::CreateFromMatrixColumnMajor(view->GetWorldToClipMatrix()); if (viewFrustum.IntersectAabb(sectorData.m_aabb) != AZ::IntersectResult::Exterior) { - uint8_t lodToRender = AZ::GetMin(lodChoice, aznumeric_cast(sectorData.m_drawPackets.size() - 1)); + const uint8_t lodToRender = AZ::GetMin(lodChoice, aznumeric_cast(sectorData.m_drawPackets.size() - 1)); view->AddDrawPacket(sectorData.m_drawPackets.at(lodToRender).GetRHIDrawPacket()); } } @@ -395,9 +646,8 @@ namespace Terrain patchdata.m_uvs.clear(); patchdata.m_indices.clear(); - uint16_t gridVertices = gridSize + 1; // For m_gridSize quads, (m_gridSize + 1) vertices are needed. - size_t size = gridVertices * gridVertices; - size *= size; + const uint16_t gridVertices = gridSize + 1; // For m_gridSize quads, (m_gridSize + 1) vertices are needed. + const size_t size = gridVertices * gridVertices; patchdata.m_positions.reserve(size); patchdata.m_uvs.reserve(size); @@ -417,10 +667,10 @@ namespace Terrain { for (uint16_t x = 0; x < gridSize; ++x) { - uint16_t topLeft = y * gridVertices + x; - uint16_t topRight = topLeft + 1; - uint16_t bottomLeft = (y + 1) * gridVertices + x; - uint16_t bottomRight = bottomLeft + 1; + const uint16_t topLeft = y * gridVertices + x; + const uint16_t topRight = topLeft + 1; + const uint16_t bottomLeft = (y + 1) * gridVertices + x; + const uint16_t bottomRight = bottomLeft + 1; patchdata.m_indices.emplace_back(topLeft); patchdata.m_indices.emplace_back(topRight); @@ -469,14 +719,14 @@ namespace Terrain PatchData patchData; InitializeTerrainPatch(gridSize, gridSpacing, patchData); - auto positionBufferViewDesc = AZ::RHI::BufferViewDescriptor::CreateTyped(0, aznumeric_cast(patchData.m_positions.size()), AZ::RHI::Format::R32G32_FLOAT); - auto positionsOutcome = CreateBufferAsset(patchData.m_positions.data(), positionBufferViewDesc, "TerrainPatchPositions"); + const auto positionBufferViewDesc = AZ::RHI::BufferViewDescriptor::CreateTyped(0, aznumeric_cast(patchData.m_positions.size()), AZ::RHI::Format::R32G32_FLOAT); + const auto positionsOutcome = CreateBufferAsset(patchData.m_positions.data(), positionBufferViewDesc, "TerrainPatchPositions"); - auto uvBufferViewDesc = AZ::RHI::BufferViewDescriptor::CreateTyped(0, aznumeric_cast(patchData.m_uvs.size()), AZ::RHI::Format::R32G32_FLOAT); - auto uvsOutcome = CreateBufferAsset(patchData.m_uvs.data(), uvBufferViewDesc, "TerrainPatchUvs"); + const auto uvBufferViewDesc = AZ::RHI::BufferViewDescriptor::CreateTyped(0, aznumeric_cast(patchData.m_uvs.size()), AZ::RHI::Format::R32G32_FLOAT); + const auto uvsOutcome = CreateBufferAsset(patchData.m_uvs.data(), uvBufferViewDesc, "TerrainPatchUvs"); - auto indexBufferViewDesc = AZ::RHI::BufferViewDescriptor::CreateTyped(0, aznumeric_cast(patchData.m_indices.size()), AZ::RHI::Format::R16_UINT); - auto indicesOutcome = CreateBufferAsset(patchData.m_indices.data(), indexBufferViewDesc, "TerrainPatchIndices"); + const auto indexBufferViewDesc = AZ::RHI::BufferViewDescriptor::CreateTyped(0, aznumeric_cast(patchData.m_indices.size()), AZ::RHI::Format::R16_UINT); + const auto indicesOutcome = CreateBufferAsset(patchData.m_indices.data(), indexBufferViewDesc, "TerrainPatchIndices"); if (!positionsOutcome.IsSuccess() || !uvsOutcome.IsSuccess() || !indicesOutcome.IsSuccess()) { @@ -514,7 +764,7 @@ namespace Terrain return success; } - void TerrainFeatureProcessor::OnMaterialReinitialized([[maybe_unused]] const AZ::Data::Instance& material) + void TerrainFeatureProcessor::OnMaterialReinitialized([[maybe_unused]] const MaterialInstance& material) { for (auto& sectorData : m_sectorData) { @@ -530,4 +780,57 @@ namespace Terrain // This will control the max rendering size. Actual terrain size can be much // larger but this will limit how much is rendered. } + + TerrainFeatureProcessor::MacroMaterialData* TerrainFeatureProcessor::FindMacroMaterial(AZ::EntityId entityId) + { + for (MacroMaterialData& data : m_macroMaterials.GetDataVector()) + { + if (data.m_entityId == entityId) + { + return &data; + } + } + return nullptr; + } + + TerrainFeatureProcessor::MacroMaterialData& TerrainFeatureProcessor::FindOrCreateMacroMaterial(AZ::EntityId entityId) + { + MacroMaterialData* dataPtr = FindMacroMaterial(entityId); + if (dataPtr != nullptr) + { + return *dataPtr; + } + + const uint16_t slotId = m_macroMaterials.GetFreeSlotIndex(); + AZ_Assert(slotId != m_macroMaterials.NoFreeSlot, "Ran out of indices for macro materials"); + + MacroMaterialData& data = m_macroMaterials.GetData(slotId); + data.m_entityId = entityId; + return data; + } + + void TerrainFeatureProcessor::RemoveMacroMaterial(AZ::EntityId entityId) + { + for (MacroMaterialData& data : m_macroMaterials.GetDataVector()) + { + if (data.m_entityId == entityId) + { + m_macroMaterials.RemoveData(&data); + return; + } + } + AZ_Assert(false, "Entity Id not found in m_macroMaterials.") + } + + template + void TerrainFeatureProcessor::ForOverlappingSectors(const AZ::Aabb& bounds, Callback callback) + { + for (SectorData& sectorData : m_sectorData) + { + if (sectorData.m_aabb.Overlaps(bounds)) + { + callback(sectorData); + } + } + } } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h index d8df9b328c..d9f15f2d47 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h @@ -11,11 +11,13 @@ #include #include +#include #include #include #include #include +#include namespace AZ::RPI { @@ -25,6 +27,7 @@ namespace AZ::RPI } class Material; class Model; + class StreamingImage; } namespace Terrain @@ -33,6 +36,7 @@ namespace Terrain : public AZ::RPI::FeatureProcessor , private AZ::RPI::MaterialReloadNotificationBus::Handler , private AzFramework::Terrain::TerrainDataNotificationBus::Handler + , private TerrainMacroMaterialNotificationBus::Handler { public: AZ_RTTI(TerrainFeatureProcessor, "{D7DAC1F9-4A9F-4D3C-80AE-99579BF8AB1C}", AZ::RPI::FeatureProcessor); @@ -52,6 +56,15 @@ namespace Terrain void SetWorldSize(AZ::Vector2 sizeInMeters); private: + + using MaterialInstance = AZ::Data::Instance; + static constexpr uint32_t MaxMaterialsPerSector = 4; + + enum MacroMaterialFlags + { + ColorImageUsed = 0b01, + NormalImageUsed = 0b10, + }; struct ShaderTerrainData // Must align with struct in Object Srg { @@ -61,7 +74,17 @@ namespace Terrain float m_sampleSpacing; float m_heightScale; }; - + + struct ShaderMacroMaterialData + { + AZStd::array m_uvMin; + AZStd::array m_uvMax; + float m_normalFactor; + uint32_t m_flipNormalX{ 0 }; // bool in shader + uint32_t m_flipNormalY{ 0 }; // bool in shader + uint32_t m_mapsInUse{ 0b00 }; // 0b01 = color, 0b10 = normal + }; + struct VertexPosition { float m_posx; @@ -81,21 +104,56 @@ namespace Terrain AZStd::vector m_indices; }; + struct SectorData + { + AZ::Data::Instance m_srg; // Hold on to ref so it's not dropped + AZ::Aabb m_aabb; + AZStd::fixed_vector m_drawPackets; + AZStd::fixed_vector m_macroMaterials; + }; + + struct MacroMaterialData + { + AZ::EntityId m_entityId; + AZ::Aabb m_bounds = AZ::Aabb::CreateNull(); + + AZ::Data::Instance m_colorImage; + AZ::Data::Instance m_normalImage; + bool m_normalFlipX{ false }; + bool m_normalFlipY{ false }; + float m_normalFactor{ 0.0f }; + }; + // AZ::RPI::MaterialReloadNotificationBus::Handler overrides... - void OnMaterialReinitialized(const AZ::Data::Instance& material) override; + void OnMaterialReinitialized(const MaterialInstance& material) override; // AzFramework::Terrain::TerrainDataNotificationBus overrides... void OnTerrainDataDestroyBegin() override; void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override; + // TerrainMacroMaterialNotificationBus overrides... + void OnTerrainMacroMaterialCreated(AZ::EntityId entityId, MaterialInstance material, const AZ::Aabb& region) override; + void OnTerrainMacroMaterialChanged(AZ::EntityId entityId, MaterialInstance material) override; + void OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override; + void OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId) override; + void Initialize(); void InitializeTerrainPatch(uint16_t gridSize, float gridSpacing, PatchData& patchdata); bool InitializePatchModel(); void UpdateTerrainData(); + void PrepareMaterialData(); + void UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, MaterialInstance material); void ProcessSurfaces(const FeatureProcessor::RenderPacket& process); + MacroMaterialData* FindMacroMaterial(AZ::EntityId entityId); + MacroMaterialData& FindOrCreateMacroMaterial(AZ::EntityId entityId); + void RemoveMacroMaterial(AZ::EntityId entityId); + + template + void ForOverlappingSectors(const AZ::Aabb& bounds, Callback callback); + AZ::Outcome> CreateBufferAsset( const void* data, const AZ::RHI::BufferViewDescriptor& bufferViewDescriptor, const AZStd::string& bufferName); @@ -105,10 +163,15 @@ namespace Terrain static constexpr float GridMeters{ GridSpacing * GridSize }; AZStd::unique_ptr m_materialAssetLoader; - AZ::Data::Instance m_materialInstance; + MaterialInstance m_materialInstance; AZ::RHI::ShaderInputConstantIndex m_modelToWorldIndex; AZ::RHI::ShaderInputConstantIndex m_terrainDataIndex; + AZ::RHI::ShaderInputConstantIndex m_macroMaterialDataIndex; + AZ::RHI::ShaderInputConstantIndex m_macroMaterialCountIndex; + AZ::RHI::ShaderInputImageIndex m_macroColorMapIndex; + AZ::RHI::ShaderInputImageIndex m_macroNormalMapIndex; + AZ::RPI::MaterialPropertyIndex m_heightmapPropertyIndex; AZ::Data::Instance m_patchModel; @@ -117,26 +180,22 @@ namespace Terrain { AZ::Transform m_transform{ AZ::Transform::CreateIdentity() }; AZ::Aabb m_terrainBounds{ AZ::Aabb::CreateNull() }; - float m_heightScale{ 0.0f }; AZ::Data::Instance m_heightmapImage; uint32_t m_heightmapImageWidth{ 0 }; uint32_t m_heightmapImageHeight{ 0 }; uint32_t m_updateWidth{ 0 }; uint32_t m_updateHeight{ 0 }; - bool m_propertiesDirty{ true }; float m_sampleSpacing{ 0.0f }; + bool m_heightmapUpdated{ true }; + bool m_macroMaterialsUpdated{ true }; + bool m_rebuildSectors{ true }; }; TerrainAreaData m_areaData; AZ::Aabb m_dirtyRegion{ AZ::Aabb::CreateNull() }; - struct SectorData - { - AZ::Data::Instance m_srg; // Hold on to ref so it's not dropped - AZ::Aabb m_aabb; - AZStd::fixed_vector m_drawPackets; - }; - AZStd::vector m_sectorData; + + AZ::Render::IndexedDataVector m_macroMaterials; }; } From 2474ffc5a1fb7ed5a6d5df753034e196fc9732f0 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 13 Oct 2021 16:59:46 -0500 Subject: [PATCH 247/293] Fixed contains check in the Global AnimNode Map macros (#4674) Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp | 4 ++-- Gems/Maestro/Code/Source/Cinematics/Movie.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp index cab6ae3fa6..ab45042b4c 100644 --- a/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp +++ b/Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp @@ -37,11 +37,11 @@ namespace using UiAnimSystemUnorderedMap = AZStd::unordered_map; } // Serialization for anim nodes & param types -#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.contains(eUiAnimNodeType_ ## name)); \ +#define REGISTER_NODE_TYPE(name) assert(!g_animNodeEnumToStringMap.contains(eUiAnimNodeType_ ## name)); \ g_animNodeEnumToStringMap[eUiAnimNodeType_ ## name] = AZ_STRINGIZE(name); \ g_animNodeStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name; -#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.contains(eUiAnimParamType_ ## name)); \ +#define REGISTER_PARAM_TYPE(name) assert(!g_animParamEnumToStringMap.contains(eUiAnimParamType_ ## name)); \ g_animParamEnumToStringMap[eUiAnimParamType_ ## name] = AZ_STRINGIZE(name); \ g_animParamStringToEnumMap[UiAnimParamSystemString(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name; diff --git a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp index 9c4356560d..2a9a231177 100644 --- a/Gems/Maestro/Code/Source/Cinematics/Movie.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/Movie.cpp @@ -87,11 +87,11 @@ namespace } // Serialization for anim nodes & param types -#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.contains(AnimNodeType::name)); \ +#define REGISTER_NODE_TYPE(name) assert(!g_animNodeEnumToStringMap.contains(AnimNodeType::name)); \ g_animNodeEnumToStringMap[AnimNodeType::name] = AZ_STRINGIZE(name); \ g_animNodeStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimNodeType::name; -#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.contains(AnimParamType::name)); \ +#define REGISTER_PARAM_TYPE(name) assert(!g_animParamEnumToStringMap.contains(AnimParamType::name)); \ g_animParamEnumToStringMap[AnimParamType::name] = AZ_STRINGIZE(name); \ g_animParamStringToEnumMap[AnimParamSystemString(AZ_STRINGIZE(name))] = AnimParamType::name; From 6823ea22740e8c26b5d417772cdf75db2c8e4fed Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Wed, 13 Oct 2021 16:59:37 -0700 Subject: [PATCH 248/293] Add GameLift matchmaking backfill server support (#4622) * Add GameLift matchmaking backfill server support Signed-off-by: onecent1101 --- .../AzFramework/Session/SessionConfig.cpp | 3 + .../AzFramework/Session/SessionConfig.h | 3 + .../Session/SessionNotifications.h | 5 + .../Code/AWSGameLiftClient/CMakeLists.txt | 6 +- .../AWSGameLiftStartMatchmakingRequest.h | 30 +- .../AWSGameLiftClientSystemComponent.cpp | 1 + .../AWSGameLiftSearchSessionsActivity.cpp | 1 + .../AWSGameLiftStartMatchmakingActivity.cpp | 5 +- .../AWSGameLiftStartMatchmakingRequest.cpp | 45 +- .../Tests/AWSGameLiftClientManagerTest.cpp | 7 +- ...WSGameLiftStartMatchmakingActivityTest.cpp | 13 +- .../awsgamelift_client_files.cmake | 2 + .../Include/AWSGameLiftPlayer.h | 44 ++ .../Source/AWSGameLiftPlayer.cpp | 58 ++ .../Code/AWSGameLiftServer/CMakeLists.txt | 3 + .../Request/IAWSGameLiftServerRequests.h | 21 +- .../Source/AWSGameLiftServerManager.cpp | 378 ++++++++++++- .../Source/AWSGameLiftServerManager.h | 75 ++- .../Source/GameLiftServerSDKWrapper.cpp | 19 + .../Source/GameLiftServerSDKWrapper.h | 19 + .../Tests/AWSGameLiftServerManagerTest.cpp | 516 ++++++++++++++++++ .../Tests/AWSGameLiftServerMocks.h | 23 + .../awsgamelift_server_files.cmake | 2 + .../Source/MultiplayerSystemComponent.cpp | 6 + .../Code/Source/MultiplayerSystemComponent.h | 1 + 25 files changed, 1194 insertions(+), 92 deletions(-) create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftCommon/Include/AWSGameLiftPlayer.h create mode 100644 Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftPlayer.cpp diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.cpp b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.cpp index 0c879a930f..0856ddeed6 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.cpp +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.cpp @@ -22,6 +22,7 @@ namespace AzFramework ->Field("terminationTime", &SessionConfig::m_terminationTime) ->Field("creatorId", &SessionConfig::m_creatorId) ->Field("sessionProperties", &SessionConfig::m_sessionProperties) + ->Field("matchmakingData", &SessionConfig::m_matchmakingData) ->Field("sessionId", &SessionConfig::m_sessionId) ->Field("sessionName", &SessionConfig::m_sessionName) ->Field("dnsName", &SessionConfig::m_dnsName) @@ -46,6 +47,8 @@ namespace AzFramework "CreatorId", "A unique identifier for a player or entity creating the session.") ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionProperties, "SessionProperties", "A collection of custom properties for a session.") + ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_matchmakingData, + "MatchmakingData", "The matchmaking process information that was used to create the session.") ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionId, "SessionId", "A unique identifier for the session.") ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionName, diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h index cfd6aa7c8b..45e40c2f29 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h @@ -35,6 +35,9 @@ namespace AzFramework // A collection of custom properties for a session. AZStd::unordered_map m_sessionProperties; + + // The matchmaking process information that was used to create the session. + AZStd::string m_matchmakingData; // A unique identifier for the session. AZStd::string m_sessionId; diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h b/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h index 7788c2d030..902500fe9a 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h +++ b/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h @@ -41,6 +41,11 @@ namespace AzFramework // OnDestroySessionBegin is fired at the beginning of session termination // @return The result of all OnDestroySessionBegin notifications virtual bool OnDestroySessionBegin() = 0; + + // OnUpdateSessionBegin is fired at the beginning of session update + // @param sessionConfig The properties to describe a session + // @param updateReason The reason for session update + virtual void OnUpdateSessionBegin(const SessionConfig& sessionConfig, const AZStd::string& updateReason) = 0; }; using SessionNotificationBus = AZ::EBus; } // namespace AzFramework diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt b/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt index 3eb5eafab0..1fab09e9f4 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt @@ -15,10 +15,11 @@ ly_add_target( awsgamelift_client_files.cmake INCLUDE_DIRECTORIES PUBLIC + ../AWSGameLiftCommon/Include Include PRIVATE - Source ../AWSGameLiftCommon/Source + Source COMPILE_DEFINITIONS PRIVATE ${awsgameliftclient_compile_definition} @@ -78,10 +79,11 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) awsgamelift_client_tests_files.cmake INCLUDE_DIRECTORIES PRIVATE + ../AWSGameLiftCommon/Include + ../AWSGameLiftCommon/Source Include Tests Source - ../AWSGameLiftCommon/Source BUILD_DEPENDENCIES PRIVATE AZ::AzCore diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h index d734daa808..ec3719c6d3 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h @@ -10,36 +10,12 @@ #include #include - #include +#include + namespace AWSGameLift { - //! AWSGameLiftPlayerInformation - //! Information on each player to be matched - //! This information must include a player ID, and may contain player attributes and latency data to be used in the matchmaking process - //! After a successful match, Player objects contain the name of the team the player is assigned to - struct AWSGameLiftPlayerInformation - { - AZ_RTTI(AWSGameLiftPlayerInformation, "{B62C118E-C55D-4903-8ECB-E58E8CA613C4}"); - static void Reflect(AZ::ReflectContext* context); - - AWSGameLiftPlayerInformation() = default; - virtual ~AWSGameLiftPlayerInformation() = default; - - // A map of region names to latencies in millseconds, that indicates - // the amount of latency that a player experiences when connected to AWS Regions - AZStd::unordered_map m_latencyInMs; - // A collection of key:value pairs containing player information for use in matchmaking - // Player attribute keys must match the playerAttributes used in a matchmaking rule set - // Example: {"skill": "{\"N\": \"23\"}", "gameMode": "{\"S\": \"deathmatch\"}"} - AZStd::unordered_map m_playerAttributes; - // A unique identifier for a player - AZStd::string m_playerId; - // Name of the team that the player is assigned to in a match - AZStd::string m_team; - }; - //! AWSGameLiftStartMatchmakingRequest //! GameLift start matchmaking request which corresponds to Amazon GameLift //! Uses FlexMatch to create a game match for a group of players based on custom matchmaking rules @@ -57,6 +33,6 @@ namespace AWSGameLift // Name of the matchmaking configuration to use for this request AZStd::string m_configurationName; // Information on each player to be matched - AZStd::vector m_players; + AZStd::vector m_players; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp index ea5fff99a3..ed7830ce57 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp @@ -210,6 +210,7 @@ namespace AWSGameLift ->Property("SessionId", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionId)) ->Property("SessionName", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionName)) ->Property("SessionProperties", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionProperties)) + ->Property("MatchmakingData", BehaviorValueProperty(&AzFramework::SessionConfig::m_matchmakingData)) ->Property("Status", BehaviorValueProperty(&AzFramework::SessionConfig::m_status)) ->Property("StatusReason", BehaviorValueProperty(&AzFramework::SessionConfig::m_statusReason)) ->Property("TerminationTime", BehaviorValueProperty(&AzFramework::SessionConfig::m_terminationTime)) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp index 3d29fa2b71..5f0b6fd012 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp @@ -105,6 +105,7 @@ namespace AWSGameLift session.m_status = AWSGameLiftSessionStatusNames[(int)gameSession.GetStatus()]; session.m_statusReason = AWSGameLiftSessionStatusReasons[(int)gameSession.GetStatusReason()]; session.m_terminationTime = gameSession.GetTerminationTime().Millis(); + session.m_matchmakingData = gameSession.GetMatchmakerData().c_str(); // TODO: Update the AWS Native SDK to get the new game session attributes. //session.m_dnsName = gameSession.GetDnsName(); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp index e535ea0c55..00a7773491 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -29,7 +30,7 @@ namespace AWSGameLift } Aws::Vector players; - for (const AWSGameLiftPlayerInformation& playerInfo : startMatchmakingRequest.m_players) + for (const AWSGameLiftPlayer& playerInfo : startMatchmakingRequest.m_players) { Aws::GameLift::Model::Player player; if (!playerInfo.m_playerId.empty()) @@ -109,7 +110,7 @@ namespace AWSGameLift if (isValid) { - for (const AWSGameLiftPlayerInformation& playerInfo : gameliftStartMatchmakingRequest->m_players) + for (const AWSGameLiftPlayer& playerInfo : gameliftStartMatchmakingRequest->m_players) { isValid &= !playerInfo.m_playerId.empty(); isValid &= AWSGameLiftActivityUtils::ValidatePlayerAttributes(playerInfo.m_playerAttributes); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp index 03d802fd36..31e9c5eff7 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp @@ -14,53 +14,10 @@ namespace AWSGameLift { - void AWSGameLiftPlayerInformation::Reflect(AZ::ReflectContext* context) - { - if (auto serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(0) - ->Field("latencyInMs", &AWSGameLiftPlayerInformation::m_latencyInMs) - ->Field("playerAttributes", &AWSGameLiftPlayerInformation::m_playerAttributes) - ->Field("playerId", &AWSGameLiftPlayerInformation::m_playerId) - ->Field("team", &AWSGameLiftPlayerInformation::m_team); - - if (AZ::EditContext* editContext = serializeContext->GetEditContext()) - { - editContext->Class("AWSGameLiftPlayerInformation", "") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement( - AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_latencyInMs, "LatencyInMs", - "A set of values, expressed in milliseconds, that indicates the amount of latency that" - "a player experiences when connected to AWS Regions") - ->DataElement( - AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_playerAttributes, "PlayerAttributes", - "A collection of key:value pairs containing player information for use in matchmaking") - ->DataElement( - AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_playerId, "PlayerId", - "A unique identifier for a player") - ->DataElement( - AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayerInformation::m_team, "Team", - "Name of the team that the player is assigned to in a match"); - } - } - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->Class("AWSGameLiftPlayerInformation") - ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) - ->Property("LatencyInMs", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_latencyInMs)) - ->Property("PlayerAttributes", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_playerAttributes)) - ->Property("PlayerId", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_playerId)) - ->Property("Team", BehaviorValueProperty(&AWSGameLiftPlayerInformation::m_team)); - } - } - void AWSGameLiftStartMatchmakingRequest::Reflect(AZ::ReflectContext* context) { AzFramework::StartMatchmakingRequest::Reflect(context); - AWSGameLiftPlayerInformation::Reflect(context); + AWSGameLiftPlayer::Reflect(context); if (auto serializeContext = azrtti_cast(context)) { diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp index 3b7c7ee827..1c3e8726fd 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp @@ -208,6 +208,7 @@ protected: sessionConfig.m_terminationTime = 0; sessionConfig.m_creatorId = "dummyCreatorId"; sessionConfig.m_sessionProperties["dummyKey"] = "dummyValue"; + sessionConfig.m_matchmakingData = "dummyMatchmakingData"; sessionConfig.m_sessionId = "dummyGameSessionId"; sessionConfig.m_sessionName = "dummyGameSessionName"; sessionConfig.m_ipAddress = "dummyIpAddress"; @@ -232,7 +233,7 @@ protected: request.m_configurationName = "dummyConfiguration"; request.m_ticketId = DummyMatchmakingTicketId; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"N\": \"1\"}"; player.m_playerId = DummyPlayerId; player.m_latencyInMs["us-east-1"] = 10; @@ -813,7 +814,7 @@ TEST_F(AWSGameLiftClientManagerTest, StartMatchmaking_CallWithInvalidRequest_Get { AWSGameLiftStartMatchmakingRequest request; request.m_configurationName = "dummyConfiguration"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"A\": \"1\"}"; request.m_players.emplace_back(player); @@ -855,7 +856,7 @@ TEST_F(AWSGameLiftClientManagerTest, StartMatchmakingAsync_CallWithInvalidReques { AWSGameLiftStartMatchmakingRequest request; request.m_configurationName = "dummyConfiguration"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"A\": \"1\"}"; request.m_players.emplace_back(player); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp index 3eed6b0448..6da932828c 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp @@ -8,6 +8,7 @@ #include #include +#include #include @@ -21,7 +22,7 @@ TEST_F(AWSGameLiftStartMatchmakingActivityTest, BuildAWSGameLiftStartMatchmaking request.m_configurationName = "dummyConfiguration"; request.m_ticketId = "dummyTicketId"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; player.m_playerId = "dummyPlayerId"; player.m_team = "dummyTeam"; @@ -58,7 +59,7 @@ TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_ AWSGameLiftStartMatchmakingRequest request; request.m_ticketId = "dummyTicketId"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; player.m_playerId = "dummyPlayerId"; player.m_team = "dummyTeam"; @@ -89,7 +90,7 @@ TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_ request.m_configurationName = "dummyConfiguration"; request.m_ticketId = "dummyTicketId"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; player.m_team = "dummyTeam"; player.m_latencyInMs["us-east-1"] = 10; @@ -107,7 +108,7 @@ TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_ request.m_configurationName = "dummyConfiguration"; request.m_ticketId = "dummyTicketId"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"A\": \"test\"}"; player.m_playerId = "dummyPlayerId"; player.m_team = "dummyTeam"; @@ -125,7 +126,7 @@ TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_ AWSGameLiftStartMatchmakingRequest request; request.m_configurationName = "dummyConfiguration"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; player.m_playerId = "dummyPlayerId"; player.m_team = "dummyTeam"; @@ -142,7 +143,7 @@ TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_ request.m_ticketId = "dummyTicketId"; request.m_configurationName = "dummyConfiguration"; - AWSGameLiftPlayerInformation player; + AWSGameLiftPlayer player; player.m_playerAttributes["dummy"] = "{\"S\": \"test\"}"; player.m_playerId = "dummyPlayerId"; player.m_team = "dummyTeam"; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake index 0930c42370..cd54414cc1 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/awsgamelift_client_files.cmake @@ -7,6 +7,8 @@ # set(FILES + ../AWSGameLiftCommon/Include/AWSGameLiftPlayer.h + ../AWSGameLiftCommon/Source/AWSGameLiftPlayer.cpp ../AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h Include/Request/AWSGameLiftAcceptMatchRequest.h Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h diff --git a/Gems/AWSGameLift/Code/AWSGameLiftCommon/Include/AWSGameLiftPlayer.h b/Gems/AWSGameLift/Code/AWSGameLiftCommon/Include/AWSGameLiftPlayer.h new file mode 100644 index 0000000000..1fbdadc8bf --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftCommon/Include/AWSGameLiftPlayer.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AWSGameLift +{ + //! AWSGameLiftPlayer + //! Information on each player to be matched + //! This information must include a player ID, and may contain player attributes and latency data to be used in the matchmaking process + //! After a successful match, Player objects contain the name of the team the player is assigned to + struct AWSGameLiftPlayer + { + AZ_RTTI(AWSGameLiftPlayer, "{B62C118E-C55D-4903-8ECB-E58E8CA613C4}"); + static void Reflect(AZ::ReflectContext* context); + + AWSGameLiftPlayer() = default; + virtual ~AWSGameLiftPlayer() = default; + + // A map of region names to latencies in millseconds, that indicates + // the amount of latency that a player experiences when connected to AWS Regions + AZStd::unordered_map m_latencyInMs; + + // A collection of key:value pairs containing player information for use in matchmaking + // Player attribute keys must match the playerAttributes used in a matchmaking rule set + // Example: {"skill": "{\"N\": 23}", "gameMode": "{\"S\": \"deathmatch\"}"} + AZStd::unordered_map m_playerAttributes; + + // A unique identifier for a player + AZStd::string m_playerId; + + // Name of the team that the player is assigned to in a match + AZStd::string m_team; + }; +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftPlayer.cpp b/Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftPlayer.cpp new file mode 100644 index 0000000000..80a3915a6b --- /dev/null +++ b/Gems/AWSGameLift/Code/AWSGameLiftCommon/Source/AWSGameLiftPlayer.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include + +namespace AWSGameLift +{ + void AWSGameLiftPlayer::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("latencyInMs", &AWSGameLiftPlayer::m_latencyInMs) + ->Field("playerAttributes", &AWSGameLiftPlayer::m_playerAttributes) + ->Field("playerId", &AWSGameLiftPlayer::m_playerId) + ->Field("team", &AWSGameLiftPlayer::m_team); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("AWSGameLiftPlayer", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayer::m_latencyInMs, "LatencyInMs", + "A set of values, expressed in milliseconds, that indicates the amount of latency that" + "a player experiences when connected to AWS Regions") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayer::m_playerAttributes, "PlayerAttributes", + "A collection of key:value pairs containing player information for use in matchmaking") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayer::m_playerId, "PlayerId", + "A unique identifier for a player") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AWSGameLiftPlayer::m_team, "Team", + "Name of the team that the player is assigned to in a match"); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AWSGameLiftPlayer") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("LatencyInMs", BehaviorValueProperty(&AWSGameLiftPlayer::m_latencyInMs)) + ->Property("PlayerAttributes", BehaviorValueProperty(&AWSGameLiftPlayer::m_playerAttributes)) + ->Property("PlayerId", BehaviorValueProperty(&AWSGameLiftPlayer::m_playerId)) + ->Property("Team", BehaviorValueProperty(&AWSGameLiftPlayer::m_team)); + } + } +} // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt b/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt index 798c6a6a25..d05ec46b52 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt @@ -17,6 +17,7 @@ ly_add_target( awsgamelift_server_files.cmake INCLUDE_DIRECTORIES PUBLIC + ../AWSGameLiftCommon/Include Include PRIVATE ../AWSGameLiftCommon/Source @@ -54,6 +55,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) awsgamelift_server_tests_files.cmake INCLUDE_DIRECTORIES PRIVATE + ../AWSGameLiftCommon/Include + ../AWSGameLiftCommon/Source Tests Source BUILD_DEPENDENCIES diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Include/Request/IAWSGameLiftServerRequests.h b/Gems/AWSGameLift/Code/AWSGameLiftServer/Include/Request/IAWSGameLiftServerRequests.h index e5b14319a8..777086e633 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Include/Request/IAWSGameLiftServerRequests.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Include/Request/IAWSGameLiftServerRequests.h @@ -9,9 +9,11 @@ #pragma once #include -#include +#include +#include #include -#include + +#include namespace AWSGameLift { @@ -26,8 +28,21 @@ namespace AWSGameLift virtual ~IAWSGameLiftServerRequests() = default; //! Notify GameLift that the server process is ready to host a game session. - //! @return Whether the ProcessReady notification is sent to GameLift. + //! @return True if the ProcessReady notification is sent to GameLift successfully, false otherwise virtual bool NotifyGameLiftProcessReady() = 0; + + //! Sends a request to find new players for open slots in a game session created with FlexMatch. + //! @param ticketId Unique identifier for match backfill request ticket + //! @param players A set of data representing all players who are currently in the game session, + //! if not provided, system will use lazy loaded game session data which is not guaranteed to + //! be accurate (no latency data either) + //! @return True if StartMatchBackfill succeeds, false otherwise + virtual bool StartMatchBackfill(const AZStd::string& ticketId, const AZStd::vector& players) = 0; + + //! Cancels an active match backfill request that was created with StartMatchBackfill + //! @param ticketId Unique identifier of the backfill request ticket to be canceled + //! @return True if StopMatchBackfill succeeds, false otherwise + virtual bool StopMatchBackfill(const AZStd::string& ticketId) = 0; }; // IAWSGameLiftServerRequests EBus wrapper for scripting diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp index e739933ab2..70d0063b61 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #include #include @@ -112,6 +115,7 @@ namespace AWSGameLift { propertiesOutput = propertiesOutput.substr(0, propertiesOutput.size() - 1); // Trim last comma to fit array format } + sessionConfig.m_matchmakingData = gameSession.GetMatchmakerData().c_str(); sessionConfig.m_sessionId = gameSession.GetGameSessionId().c_str(); sessionConfig.m_ipAddress = gameSession.GetIpAddress().c_str(); sessionConfig.m_maxPlayer = gameSession.GetMaximumPlayerSessionCount(); @@ -133,6 +137,276 @@ namespace AWSGameLift return sessionConfig; } + bool AWSGameLiftServerManager::BuildServerMatchBackfillPlayer( + const AWSGameLiftPlayer& player, Aws::GameLift::Server::Model::Player& outBackfillPlayer) + { + outBackfillPlayer.SetPlayerId(player.m_playerId.c_str()); + outBackfillPlayer.SetTeam(player.m_team.c_str()); + for (auto latencyPair : player.m_latencyInMs) + { + outBackfillPlayer.AddLatencyInMs(latencyPair.first.c_str(), latencyPair.second); + } + + for (auto attributePair : player.m_playerAttributes) + { + Aws::GameLift::Server::Model::AttributeValue playerAttribute; + rapidjson::Document attributeDocument; + rapidjson::ParseResult parseResult = attributeDocument.Parse(attributePair.second.c_str()); + // player attribute json content should always be a single member object + if (parseResult && attributeDocument.IsObject() && attributeDocument.MemberCount() == 1) + { + if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSTypeName) || + attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSServerTypeName)) && + attributeDocument.MemberBegin()->value.IsString()) + { + playerAttribute = Aws::GameLift::Server::Model::AttributeValue( + attributeDocument.MemberBegin()->value.GetString()); + } + else if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeNTypeName) || + attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeNServerTypeName)) && + attributeDocument.MemberBegin()->value.IsNumber()) + { + playerAttribute = Aws::GameLift::Server::Model::AttributeValue( + attributeDocument.MemberBegin()->value.GetDouble()); + } + else if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSDMTypeName) || + attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSDMServerTypeName)) && + attributeDocument.MemberBegin()->value.IsObject()) + { + playerAttribute = Aws::GameLift::Server::Model::AttributeValue::ConstructStringDoubleMap(); + for (auto iter = attributeDocument.MemberBegin()->value.MemberBegin(); + iter != attributeDocument.MemberBegin()->value.MemberEnd(); iter++) + { + if (iter->name.IsString() && iter->value.IsNumber()) + { + playerAttribute.AddStringAndDouble(iter->name.GetString(), iter->value.GetDouble()); + } + else + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage, + player.m_playerId.c_str(), "String double map key must be string type and value must be number type"); + return false; + } + } + } + else if ((attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSLTypeName) || + attributeDocument.HasMember(AWSGameLiftMatchmakingPlayerAttributeSLServerTypeName)) && + attributeDocument.MemberBegin()->value.IsArray()) + { + playerAttribute = Aws::GameLift::Server::Model::AttributeValue::ConstructStringList(); + for (auto iter = attributeDocument.MemberBegin()->value.Begin(); + iter != attributeDocument.MemberBegin()->value.End(); iter++) + { + if (iter->IsString()) + { + playerAttribute.AddString(iter->GetString()); + } + else + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage, + player.m_playerId.c_str(), "String list element must be string type"); + return false; + } + } + } + else + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage, + player.m_playerId.c_str(), "S, N, SDM or SLM is expected as attribute type."); + return false; + } + } + else + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage, + player.m_playerId.c_str(), rapidjson::GetParseError_En(parseResult.Code())); + return false; + } + outBackfillPlayer.AddPlayerAttribute(attributePair.first.c_str(), playerAttribute); + } + return true; + } + + AZStd::vector AWSGameLiftServerManager::GetActiveServerMatchBackfillPlayers() + { + AZStd::vector activePlayers; + // Keep processing only when game session has matchmaking data + if (IsMatchmakingDataValid()) + { + auto activePlayerSessions = GetActivePlayerSessions(); + for (auto playerSession : activePlayerSessions) + { + AWSGameLiftPlayer player; + if (BuildActiveServerMatchBackfillPlayer(playerSession.GetPlayerId().c_str(), player)) + { + activePlayers.push_back(player); + } + } + } + return activePlayers; + } + + bool AWSGameLiftServerManager::IsMatchmakingDataValid() + { + return m_matchmakingData.IsObject() && + m_matchmakingData.HasMember(AWSGameLiftMatchmakingConfigurationKeyName) && + m_matchmakingData.HasMember(AWSGameLiftMatchmakingTeamsKeyName); + } + + AZStd::vector AWSGameLiftServerManager::GetActivePlayerSessions() + { + Aws::GameLift::Server::Model::DescribePlayerSessionsRequest describeRequest; + describeRequest.SetGameSessionId(m_gameSession.GetGameSessionId()); + describeRequest.SetPlayerSessionStatusFilter( + Aws::GameLift::Server::Model::PlayerSessionStatusMapper::GetNameForPlayerSessionStatus( + Aws::GameLift::Server::Model::PlayerSessionStatus::ACTIVE)); + int maxPlayerSession = m_gameSession.GetMaximumPlayerSessionCount(); + + AZStd::vector activePlayerSessions; + if (maxPlayerSession <= AWSGameLiftDescribePlayerSessionsPageSize) + { + describeRequest.SetLimit(maxPlayerSession); + auto outcome = m_gameLiftServerSDKWrapper->DescribePlayerSessions(describeRequest); + if (outcome.IsSuccess()) + { + for (auto playerSession : outcome.GetResult().GetPlayerSessions()) + { + activePlayerSessions.push_back(playerSession); + } + } + else + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftDescribePlayerSessionsErrorMessage, + outcome.GetError().GetErrorMessage().c_str()); + } + } + else + { + describeRequest.SetLimit(AWSGameLiftDescribePlayerSessionsPageSize); + while (true) + { + auto outcome = m_gameLiftServerSDKWrapper->DescribePlayerSessions(describeRequest); + if (outcome.IsSuccess()) + { + for (auto playerSession : outcome.GetResult().GetPlayerSessions()) + { + activePlayerSessions.push_back(playerSession); + } + if (outcome.GetResult().GetNextToken().empty()) + { + break; + } + else + { + describeRequest.SetNextToken(outcome.GetResult().GetNextToken()); + } + } + else + { + activePlayerSessions.clear(); + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftDescribePlayerSessionsErrorMessage, + outcome.GetError().GetErrorMessage().c_str()); + break; + } + } + } + return activePlayerSessions; + } + + bool AWSGameLiftServerManager::BuildActiveServerMatchBackfillPlayer(const AZStd::string& playerId, AWSGameLiftPlayer& outPlayer) + { + // As data is from GameLift service, assume it is always in correct format + rapidjson::Value& teams = m_matchmakingData[AWSGameLiftMatchmakingTeamsKeyName]; + + // Iterate through teams to find target player + for (rapidjson::SizeType teamIndex = 0; teamIndex < teams.Size(); ++teamIndex) + { + rapidjson::Value& players = teams[teamIndex][AWSGameLiftMatchmakingPlayersKeyName]; + + // Iterate through players under the team to find target player + for (rapidjson::SizeType playerIndex = 0; playerIndex < players.Size(); ++playerIndex) + { + if (std::strcmp(players[playerIndex][AWSGameLiftMatchmakingPlayerIdKeyName].GetString(), playerId.c_str()) == 0) + { + outPlayer.m_playerId = playerId; + outPlayer.m_team = teams[teamIndex][AWSGameLiftMatchmakingTeamNameKeyName].GetString(); + // Get player attributes if target player has + if (players[playerIndex].HasMember(AWSGameLiftMatchmakingPlayerAttributesKeyName)) + { + BuildServerMatchBackfillPlayerAttributes( + players[playerIndex][AWSGameLiftMatchmakingPlayerAttributesKeyName], outPlayer); + } + } + else + { + return false; + } + } + } + return true; + } + + void AWSGameLiftServerManager::BuildServerMatchBackfillPlayerAttributes( + const rapidjson::Value& playerAttributes, AWSGameLiftPlayer& outPlayer) + { + for (auto iter = playerAttributes.MemberBegin(); iter != playerAttributes.MemberEnd(); iter++) + { + AZStd::string attributeName = iter->name.GetString(); + + rapidjson::StringBuffer jsonStringBuffer; + rapidjson::Writer writer(jsonStringBuffer); + iter->value[AWSGameLiftMatchmakingPlayerAttributeValueKeyName].Accept(writer); + AZStd::string attributeType = iter->value[AWSGameLiftMatchmakingPlayerAttributeTypeKeyName].GetString(); + AZStd::string attributeValue = AZStd::string::format("{\"%s\": %s}", + attributeType.c_str(), jsonStringBuffer.GetString()); + + outPlayer.m_playerAttributes.emplace(attributeName, attributeValue); + } + } + + bool AWSGameLiftServerManager::BuildStartMatchBackfillRequest( + const AZStd::string& ticketId, + const AZStd::vector& players, + Aws::GameLift::Server::Model::StartMatchBackfillRequest& outRequest) + { + outRequest.SetGameSessionArn(m_gameSession.GetGameSessionId()); + outRequest.SetMatchmakingConfigurationArn(m_matchmakingData[AWSGameLiftMatchmakingConfigurationKeyName].GetString()); + if (!ticketId.empty()) + { + outRequest.SetTicketId(ticketId.c_str()); + } + + AZStd::vector requestPlayers(players); + if (players.size() == 0) + { + requestPlayers = GetActiveServerMatchBackfillPlayers(); + } + for (auto player : requestPlayers) + { + Aws::GameLift::Server::Model::Player backfillPlayer; + if (BuildServerMatchBackfillPlayer(player, backfillPlayer)) + { + outRequest.AddPlayer(backfillPlayer); + } + else + { + return false; + } + } + return true; + } + + void AWSGameLiftServerManager::BuildStopMatchBackfillRequest( + const AZStd::string& ticketId, Aws::GameLift::Server::Model::StopMatchBackfillRequest& outRequest) + { + outRequest.SetGameSessionArn(m_gameSession.GetGameSessionId()); + outRequest.SetMatchmakingConfigurationArn(m_matchmakingData[AWSGameLiftMatchmakingConfigurationKeyName].GetString()); + if (!ticketId.empty()) + { + outRequest.SetTicketId(ticketId.c_str()); + } + } + AZ::IO::Path AWSGameLiftServerManager::GetExternalSessionCertificate() { // TODO: Add support to get TLS cert file path @@ -238,7 +512,7 @@ namespace AWSGameLift Aws::GameLift::Server::ProcessParameters processReadyParameter = Aws::GameLift::Server::ProcessParameters( AZStd::bind(&AWSGameLiftServerManager::OnStartGameSession, this, AZStd::placeholders::_1), - AZStd::bind(&AWSGameLiftServerManager::OnUpdateGameSession, this), + AZStd::bind(&AWSGameLiftServerManager::OnUpdateGameSession, this, AZStd::placeholders::_1), AZStd::bind(&AWSGameLiftServerManager::OnProcessTerminate, this), AZStd::bind(&AWSGameLiftServerManager::OnHealthCheck, this), desc.m_port, Aws::GameLift::Server::LogParameters(logPaths)); @@ -260,6 +534,7 @@ namespace AWSGameLift void AWSGameLiftServerManager::OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession) { + UpdateGameSessionData(gameSession); AzFramework::SessionConfig sessionConfig = BuildSessionConfig(gameSession); bool createSessionResult = true; @@ -311,10 +586,19 @@ namespace AWSGameLift return m_serverSDKInitialized && healthCheckResult; } - void AWSGameLiftServerManager::OnUpdateGameSession() + void AWSGameLiftServerManager::OnUpdateGameSession(const Aws::GameLift::Server::Model::UpdateGameSession& updateGameSession) { - // TODO: Perform game-specific tasks to prep for newly matched players - return; + Aws::GameLift::Server::Model::UpdateReason updateReason = updateGameSession.GetUpdateReason(); + if (updateReason == Aws::GameLift::Server::Model::UpdateReason::MATCHMAKING_DATA_UPDATED) + { + UpdateGameSessionData(updateGameSession.GetGameSession()); + } + AzFramework::SessionConfig sessionConfig = BuildSessionConfig(updateGameSession.GetGameSession()); + + AzFramework::SessionNotificationBus::Broadcast( + &AzFramework::SessionNotifications::OnUpdateSessionBegin, + sessionConfig, + Aws::GameLift::Server::Model::UpdateReasonMapper::GetNameForUpdateReason(updateReason).c_str()); } bool AWSGameLiftServerManager::RemoveConnectedPlayer(uint32_t playerConnectionId, AZStd::string& outPlayerSessionId) @@ -340,6 +624,92 @@ namespace AWSGameLift m_gameLiftServerSDKWrapper = AZStd::move(gameLiftServerSDKWrapper); } + bool AWSGameLiftServerManager::StartMatchBackfill(const AZStd::string& ticketId, const AZStd::vector& players) + { + if (!m_serverSDKInitialized) + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKNotInitErrorMessage); + return false; + } + + if (!IsMatchmakingDataValid()) + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingDataMissingErrorMessage); + return false; + } + + Aws::GameLift::Server::Model::StartMatchBackfillRequest request; + if (!BuildStartMatchBackfillRequest(ticketId, players, request)) + { + return false; + } + + AZ_TracePrintf(AWSGameLiftServerManagerName, "Starting match backfill %s ...", ticketId.c_str()); + auto outcome = m_gameLiftServerSDKWrapper->StartMatchBackfill(request); + if (!outcome.IsSuccess()) + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftStartMatchBackfillErrorMessage, + outcome.GetError().GetErrorMessage().c_str()); + return false; + } + else + { + AZ_TracePrintf(AWSGameLiftServerManagerName, "StartMatchBackfill request against Amazon GameLift service is complete."); + return true; + } + } + + bool AWSGameLiftServerManager::StopMatchBackfill(const AZStd::string& ticketId) + { + if (!m_serverSDKInitialized) + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftServerSDKNotInitErrorMessage); + return false; + } + + if (!IsMatchmakingDataValid()) + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftMatchmakingDataMissingErrorMessage); + return false; + } + + Aws::GameLift::Server::Model::StopMatchBackfillRequest request; + BuildStopMatchBackfillRequest(ticketId, request); + + AZ_TracePrintf(AWSGameLiftServerManagerName, "Stopping match backfill %s ...", ticketId.c_str()); + auto outcome = m_gameLiftServerSDKWrapper->StopMatchBackfill(request); + if (!outcome.IsSuccess()) + { + AZ_Error(AWSGameLiftServerManagerName, false, AWSGameLiftStopMatchBackfillErrorMessage, + outcome.GetError().GetErrorMessage().c_str()); + return false; + } + else + { + AZ_TracePrintf(AWSGameLiftServerManagerName, "StopMatchBackfill request against Amazon GameLift service is complete."); + return true; + } + } + + void AWSGameLiftServerManager::UpdateGameSessionData(const Aws::GameLift::Server::Model::GameSession& gameSession) + { + AZ_TracePrintf(AWSGameLiftServerManagerName, "Lazy loading game session and matchmaking data from Amazon GameLift service ..."); + m_gameSession = Aws::GameLift::Server::Model::GameSession(gameSession); + if (m_gameSession.GetMatchmakerData().empty()) + { + m_matchmakingData.Parse("{}"); + } + else + { + rapidjson::ParseResult parseResult = m_matchmakingData.Parse(m_gameSession.GetMatchmakerData().c_str()); + if (!parseResult) + { + AZ_Error(AWSGameLiftServerManagerName, false, + AWSGameLiftMatchmakingDataInvalidErrorMessage, rapidjson::GetParseError_En(parseResult.Code())); + } + } + } + bool AWSGameLiftServerManager::ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) { uint32_t playerConnectionId = playerConnectionConfig.m_playerConnectionId; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h index c0f1c00bea..fa2f783eca 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h @@ -11,11 +11,15 @@ #include #include +#include +#include #include #include #include #include #include + +#include #include namespace AWSGameLift @@ -66,6 +70,36 @@ namespace AWSGameLift "Invalid player connection config, player connection id: %d, player session id: %s"; static constexpr const char AWSGameLiftServerRemovePlayerSessionErrorMessage[] = "Failed to notify GameLift that the player with the player session id %s has disconnected from the server process. ErrorMessage: %s"; + static constexpr const char AWSGameLiftMatchmakingDataInvalidErrorMessage[] = + "Failed to parse GameLift matchmaking data. ErrorMessage: %s"; + static constexpr const char AWSGameLiftMatchmakingDataMissingErrorMessage[] = + "GameLift matchmaking data is missing or invalid to parse."; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeInvalidErrorMessage[] = + "Failed to build player %s attributes. ErrorMessage: %s"; + static constexpr const char AWSGameLiftDescribePlayerSessionsErrorMessage[] = + "Failed to describe player sessions. ErrorMessage: %s"; + static constexpr const char AWSGameLiftStartMatchBackfillErrorMessage[] = + "Failed to start match backfill. ErrorMessage: %s"; + static constexpr const char AWSGameLiftStopMatchBackfillErrorMessage[] = + "Failed to stop match backfill. ErrorMessage: %s"; + + static constexpr const char AWSGameLiftMatchmakingConfigurationKeyName[] = "matchmakingConfigurationArn"; + static constexpr const char AWSGameLiftMatchmakingTeamsKeyName[] = "teams"; + static constexpr const char AWSGameLiftMatchmakingTeamNameKeyName[] = "name"; + static constexpr const char AWSGameLiftMatchmakingPlayersKeyName[] = "players"; + static constexpr const char AWSGameLiftMatchmakingPlayerIdKeyName[] = "playerId"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributesKeyName[] = "attributes"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeTypeKeyName[] = "attributeType"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeValueKeyName[] = "valueAttribute"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSTypeName[] = "S"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSServerTypeName[] = "STRING"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeNTypeName[] = "N"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeNServerTypeName[] = "NUMBER"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSLTypeName[] = "SL"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSLServerTypeName[] = "STRING_LIST"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSDMTypeName[] = "SDM"; + static constexpr const char AWSGameLiftMatchmakingPlayerAttributeSDMServerTypeName[] = "STRING_DOUBLE_MAP"; + static constexpr const uint16_t AWSGameLiftDescribePlayerSessionsPageSize = 30; AWSGameLiftServerManager(); virtual ~AWSGameLiftServerManager(); @@ -78,6 +112,8 @@ namespace AWSGameLift // AWSGameLiftServerRequestBus interface implementation bool NotifyGameLiftProcessReady() override; + bool StartMatchBackfill(const AZStd::string& ticketId, const AZStd::vector& players) override; + bool StopMatchBackfill(const AZStd::string& ticketId) override; // ISessionHandlingProviderRequests interface implementation void HandleDestroySession() override; @@ -92,18 +128,48 @@ namespace AWSGameLift //! Add connected player session id. bool AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig); + //! Get active server player data from lazy loaded game session for server match backfill + AZStd::vector GetActiveServerMatchBackfillPlayers(); + + //! Update local game session data to latest one + void UpdateGameSessionData(const Aws::GameLift::Server::Model::GameSession& gameSession); + private: //! Build the serverProcessDesc with appropriate server port number and log paths. GameLiftServerProcessDesc BuildGameLiftServerProcessDesc(); + //! Build active server player data from lazy loaded game session based on player id + bool BuildActiveServerMatchBackfillPlayer(const AZStd::string& playerId, AWSGameLiftPlayer& outPlayer); + + //! Build server player attribute data from lazy load matchmaking data + void BuildServerMatchBackfillPlayerAttributes(const rapidjson::Value& playerAttributes, AWSGameLiftPlayer& outPlayer); + + //! Build server player data for server match backfill + bool BuildServerMatchBackfillPlayer(const AWSGameLiftPlayer& player, Aws::GameLift::Server::Model::Player& outBackfillPlayer); + + //! Build start match backfill request for StartMatchBackfill operation + bool BuildStartMatchBackfillRequest( + const AZStd::string& ticketId, + const AZStd::vector& players, + Aws::GameLift::Server::Model::StartMatchBackfillRequest& outRequest); + + //! Build stop match backfill request for StopMatchBackfill operation + void BuildStopMatchBackfillRequest(const AZStd::string& ticketId, Aws::GameLift::Server::Model::StopMatchBackfillRequest& outRequest); + //! Build session config by using AWS GameLift Server GameSession Model. AzFramework::SessionConfig BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession); + //! Check whether matchmaking data is in proper format + bool IsMatchmakingDataValid(); + + //! Fetch active player sessions in game session. + AZStd::vector GetActivePlayerSessions(); + //! Callback function that the GameLift service invokes to activate a new game session. void OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession); //! Callback function that the GameLift service invokes to pass an updated game session object to the server process. - void OnUpdateGameSession(); + void OnUpdateGameSession(const Aws::GameLift::Server::Model::UpdateGameSession& updateGameSession); //! Callback function that the server process or GameLift service invokes to force the server process to shut down. void OnProcessTerminate(); @@ -125,5 +191,12 @@ namespace AWSGameLift using PlayerConnectionId = uint32_t; using PlayerSessionId = AZStd::string; AZStd::unordered_map m_connectedPlayers; + + // Lazy loaded game session and matchmaking data + Aws::GameLift::Server::Model::GameSession m_gameSession; + // Matchmaking data contains a unique match ID, it identifies the matchmaker that created the match + // and describes the teams, team assignments, and players. + // Reference https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-server.html#match-server-data + rapidjson::Document m_matchmakingData; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.cpp b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.cpp index 7e216f33be..d51c8eb8cb 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.cpp @@ -22,6 +22,12 @@ namespace AWSGameLift return Aws::GameLift::Server::ActivateGameSession(); } + Aws::GameLift::DescribePlayerSessionsOutcome GameLiftServerSDKWrapper::DescribePlayerSessions( + const Aws::GameLift::Server::Model::DescribePlayerSessionsRequest& describePlayerSessionsRequest) + { + return Aws::GameLift::Server::DescribePlayerSessions(describePlayerSessionsRequest); + } + Aws::GameLift::Server::InitSDKOutcome GameLiftServerSDKWrapper::InitSDK() { return Aws::GameLift::Server::InitSDK(); @@ -69,4 +75,17 @@ namespace AWSGameLift { return Aws::GameLift::Server::RemovePlayerSession(playerSessionId.c_str()); } + + Aws::GameLift::StartMatchBackfillOutcome GameLiftServerSDKWrapper::StartMatchBackfill( + const Aws::GameLift::Server::Model::StartMatchBackfillRequest& startMatchBackfillRequest) + { + return Aws::GameLift::Server::StartMatchBackfill(startMatchBackfillRequest); + } + + Aws::GameLift::GenericOutcome GameLiftServerSDKWrapper::StopMatchBackfill( + const Aws::GameLift::Server::Model::StopMatchBackfillRequest& stopMatchBackfillRequest) + { + return Aws::GameLift::Server::StopMatchBackfill(stopMatchBackfillRequest); + } + } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.h b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.h index a656087206..e56366d75a 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/GameLiftServerSDKWrapper.h @@ -33,6 +33,14 @@ namespace AWSGameLift //! @return Returns a generic outcome consisting of success or failure with an error message. virtual Aws::GameLift::GenericOutcome ActivateGameSession(); + //! Retrieves player session data, including settings, session metadata, and player data. + //! Use this action to get information for a single player session, + //! for all player sessions in a game session, or for all player sessions associated with a single player ID. + //! @param describePlayerSessionsRequest The request object describing which player sessions to retrieve. + //! @return If successful, returns a DescribePlayerSessionsOutcome object containing a set of player session objects that fit the request parameters. + virtual Aws::GameLift::DescribePlayerSessionsOutcome DescribePlayerSessions( + const Aws::GameLift::Server::Model::DescribePlayerSessionsRequest& describePlayerSessionsRequest); + //! Initializes the GameLift SDK. //! Should be called when the server starts, before any GameLift-dependent initialization happens. //! @return If successful, returns an InitSdkOutcome object indicating that the server process is ready to call ProcessReady(). @@ -56,5 +64,16 @@ namespace AWSGameLift //! @param playerSessionId Unique ID issued by the Amazon GameLift service in response to a call to the AWS SDK Amazon GameLift API action CreatePlayerSession. //! @return Returns a generic outcome consisting of success or failure with an error message. virtual Aws::GameLift::GenericOutcome RemovePlayerSession(const AZStd::string& playerSessionId); + + //! Sends a request to find new players for open slots in a game session created with FlexMatch. + //! When the match has been successfully, backfilled updated matchmaker data will be sent to the OnUpdateGameSession callback. + //! @param startMatchBackfillRequest This data type is used to send a matchmaking backfill request. + //! @return Returns a StartMatchBackfillOutcome object with the match backfill ticket or failure with an error message. + virtual Aws::GameLift::StartMatchBackfillOutcome StartMatchBackfill(const Aws::GameLift::Server::Model::StartMatchBackfillRequest& startMatchBackfillRequest); + + //! Cancels an active match backfill request that was created with StartMatchBackfill + //! @param stopMatchBackfillRequest This data type is used to cancel a matchmaking backfill request. + //! @return Returns a generic outcome consisting of success or failure with an error message. + virtual Aws::GameLift::GenericOutcome StopMatchBackfill(const Aws::GameLift::Server::Model::StopMatchBackfillRequest& stopMatchBackfillRequest); }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp index 2c8929b297..d172734ec0 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp @@ -16,6 +16,136 @@ namespace UnitTest { + static constexpr const char TEST_SERVER_MATCHMAKING_DATA[] = +R"({ + "matchId":"testmatchid", + "matchmakingConfigurationArn":"testmatchconfig", + "teams":[ + {"name":"testteam", + "players":[ + {"playerId":"testplayer", + "attributes":{ + "skills":{ + "attributeType":"STRING_DOUBLE_MAP", + "valueAttribute":{"test1":10.0,"test2":20.0,"test3":30.0,"test4":40.0} + }, + "mode":{ + "attributeType":"STRING", + "valueAttribute":"testmode" + }, + "level":{ + "attributeType":"NUMBER", + "valueAttribute":10.0 + }, + "items":{ + "attributeType":"STRING_LIST", + "valueAttribute":["test1","test2","test3"] + } + }} + ]} + ] +})"; + + Aws::GameLift::Server::Model::StartMatchBackfillRequest GetTestStartMatchBackfillRequest() + { + Aws::GameLift::Server::Model::StartMatchBackfillRequest request; + request.SetMatchmakingConfigurationArn("testmatchconfig"); + Aws::GameLift::Server::Model::Player player; + player.SetPlayerId("testplayer"); + player.SetTeam("testteam"); + player.AddPlayerAttribute("mode", Aws::GameLift::Server::Model::AttributeValue("testmode")); + player.AddPlayerAttribute("level", Aws::GameLift::Server::Model::AttributeValue(10.0)); + auto sdmValue = Aws::GameLift::Server::Model::AttributeValue::ConstructStringDoubleMap(); + sdmValue.AddStringAndDouble("test1", 10.0); + player.AddPlayerAttribute("skills", sdmValue); + auto slValue = Aws::GameLift::Server::Model::AttributeValue::ConstructStringList(); + slValue.AddString("test1"); + player.AddPlayerAttribute("items", slValue); + player.AddLatencyInMs("testregion", 10); + request.AddPlayer(player); + request.SetTicketId("testticket"); + return request; + } + + AWSGameLiftPlayer GetTestGameLiftPlayer() + { + AWSGameLiftPlayer player; + player.m_team = "testteam"; + player.m_playerId = "testplayer"; + player.m_playerAttributes.emplace("mode", "{\"S\": \"testmode\"}"); + player.m_playerAttributes.emplace("level", "{\"N\": 10.0}"); + player.m_playerAttributes.emplace("skills", "{\"SDM\": {\"test1\":10.0}}"); + player.m_playerAttributes.emplace("items", "{\"SL\": [\"test1\"]}"); + player.m_latencyInMs.emplace("testregion", 10); + return player; + } + + MATCHER_P(StartMatchBackfillRequestMatcher, expectedRequest, "") + { + // Custome matcher for checking the SearchSessionsResponse type argument. + AZ_UNUSED(result_listener); + if (strcmp(arg.GetGameSessionArn().c_str(), expectedRequest.GetGameSessionArn().c_str()) != 0) + { + return false; + } + if (strcmp(arg.GetMatchmakingConfigurationArn().c_str(), expectedRequest.GetMatchmakingConfigurationArn().c_str()) != 0) + { + return false; + } + if (strcmp(arg.GetTicketId().c_str(), expectedRequest.GetTicketId().c_str()) != 0) + { + return false; + } + if (arg.GetPlayers().size() != expectedRequest.GetPlayers().size()) + { + return false; + } + for (int playerIndex = 0; playerIndex < expectedRequest.GetPlayers().size(); playerIndex++) + { + auto actualPlayerAttributes = arg.GetPlayers()[playerIndex].GetPlayerAttributes(); + auto expectedPlayerAttributes = expectedRequest.GetPlayers()[playerIndex].GetPlayerAttributes(); + if (actualPlayerAttributes.size() != expectedPlayerAttributes.size()) + { + return false; + } + for (auto attributePair : expectedPlayerAttributes) + { + if (actualPlayerAttributes.find(attributePair.first) == actualPlayerAttributes.end()) + { + return false; + } + if (!(attributePair.second.GetType() == actualPlayerAttributes[attributePair.first].GetType() && + (attributePair.second.GetS() == actualPlayerAttributes[attributePair.first].GetS() || + attributePair.second.GetN() == actualPlayerAttributes[attributePair.first].GetN() || + attributePair.second.GetSL() == actualPlayerAttributes[attributePair.first].GetSL() || + attributePair.second.GetSDM() == actualPlayerAttributes[attributePair.first].GetSDM()))) + { + return false; + } + } + + auto actualLatencies = arg.GetPlayers()[playerIndex].GetLatencyInMs(); + auto expectedLatencies = expectedRequest.GetPlayers()[playerIndex].GetLatencyInMs(); + if (actualLatencies.size() != expectedLatencies.size()) + { + return false; + } + for (auto latencyPair : expectedLatencies) + { + if (actualLatencies.find(latencyPair.first) == actualLatencies.end()) + { + return false; + } + if (latencyPair.second != actualLatencies[latencyPair.first]) + { + return false; + } + } + } + + return true; + } + class SessionNotificationsHandlerMock : public AzFramework::SessionNotificationBus::Handler { @@ -33,6 +163,7 @@ namespace UnitTest MOCK_METHOD0(OnSessionHealthCheck, bool()); MOCK_METHOD1(OnCreateSessionBegin, bool(const AzFramework::SessionConfig&)); MOCK_METHOD0(OnDestroySessionBegin, bool()); + MOCK_METHOD2(OnUpdateSessionBegin, void(const AzFramework::SessionConfig&, const AZStd::string&)); }; class GameLiftServerManagerTest @@ -228,6 +359,64 @@ namespace UnitTest AZ_TEST_STOP_TRACE_SUPPRESSION(1); } + TEST_F(GameLiftServerManagerTest, OnUpdateGameSession_TriggerWithUnknownReason_OnUpdateSessionBeginGetCalledOnce) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->NotifyGameLiftProcessReady(); + SessionNotificationsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, OnUpdateSessionBegin(testing::_, testing::_)).Times(1); + + m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onUpdateGameSessionFunc( + Aws::GameLift::Server::Model::UpdateGameSession( + Aws::GameLift::Server::Model::GameSession(), + Aws::GameLift::Server::Model::UpdateReason::UNKNOWN, + "testticket")); + } + + TEST_F(GameLiftServerManagerTest, OnUpdateGameSession_TriggerWithEmptyMatchmakingData_OnUpdateSessionBeginGetCalledOnce) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->NotifyGameLiftProcessReady(); + SessionNotificationsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, OnUpdateSessionBegin(testing::_, testing::_)).Times(1); + + m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onUpdateGameSessionFunc( + Aws::GameLift::Server::Model::UpdateGameSession( + Aws::GameLift::Server::Model::GameSession(), + Aws::GameLift::Server::Model::UpdateReason::MATCHMAKING_DATA_UPDATED, + "testticket")); + } + + TEST_F(GameLiftServerManagerTest, OnUpdateGameSession_TriggerWithValidMatchmakingData_OnUpdateSessionBeginGetCalledOnce) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->NotifyGameLiftProcessReady(); + SessionNotificationsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, OnUpdateSessionBegin(testing::_, testing::_)).Times(1); + + Aws::GameLift::Server::Model::GameSession gameSession; + gameSession.SetMatchmakerData(TEST_SERVER_MATCHMAKING_DATA); + m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onUpdateGameSessionFunc( + Aws::GameLift::Server::Model::UpdateGameSession( + gameSession, Aws::GameLift::Server::Model::UpdateReason::MATCHMAKING_DATA_UPDATED, "testticket")); + } + + TEST_F(GameLiftServerManagerTest, OnUpdateGameSession_TriggerWithInvalidMatchmakingData_OnUpdateSessionBeginGetCalledOnce) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->NotifyGameLiftProcessReady(); + SessionNotificationsHandlerMock handlerMock; + EXPECT_CALL(handlerMock, OnUpdateSessionBegin(testing::_, testing::_)).Times(1); + + Aws::GameLift::Server::Model::GameSession gameSession; + gameSession.SetMatchmakerData("{invalid}"); + AZ_TEST_START_TRACE_SUPPRESSION; + m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onUpdateGameSessionFunc( + Aws::GameLift::Server::Model::UpdateGameSession( + gameSession, Aws::GameLift::Server::Model::UpdateReason::MATCHMAKING_DATA_UPDATED, "testticket")); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithInvalidConnectionConfig_GetFalseResultAndExpectedErrorLog) { AZ_TEST_START_TRACE_SUPPRESSION; @@ -425,4 +614,331 @@ namespace UnitTest } AZ_TEST_STOP_TRACE_SUPPRESSION(testThreadNumber - 1); // The player is only disconnected once. } + + TEST_F(GameLiftServerManagerTest, UpdateGameSessionData_CallWithInvalidMatchmakingData_GetExpectedError) + { + AZ_TEST_START_TRACE_SUPPRESSION; + m_serverManager->SetupTestMatchmakingData("{invalid}"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + + TEST_F(GameLiftServerManagerTest, GetActiveServerMatchBackfillPlayers_CallWithInvalidMatchmakingData_GetEmptyResult) + { + AZ_TEST_START_TRACE_SUPPRESSION; + m_serverManager->SetupTestMatchmakingData("{invalid}"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + auto actualResult = m_serverManager->GetTestServerMatchBackfillPlayers(); + EXPECT_TRUE(actualResult.empty()); + } + + TEST_F(GameLiftServerManagerTest, GetActiveServerMatchBackfillPlayers_CallWithEmptyMatchmakingData_GetEmptyResult) + { + m_serverManager->SetupTestMatchmakingData(""); + + auto actualResult = m_serverManager->GetTestServerMatchBackfillPlayers(); + EXPECT_TRUE(actualResult.empty()); + } + + TEST_F(GameLiftServerManagerTest, GetActiveServerMatchBackfillPlayers_CallButDescribePlayerError_GetEmptyResult) + { + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + Aws::GameLift::GameLiftError error; + Aws::GameLift::DescribePlayerSessionsOutcome errorOutcome(error); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), DescribePlayerSessions(testing::_)) + .Times(1) + .WillOnce(Return(errorOutcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->GetTestServerMatchBackfillPlayers(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_TRUE(actualResult.empty()); + } + + TEST_F(GameLiftServerManagerTest, GetActiveServerMatchBackfillPlayers_CallButNoActivePlayer_GetEmptyResult) + { + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + Aws::GameLift::Server::Model::DescribePlayerSessionsResult result; + Aws::GameLift::DescribePlayerSessionsOutcome successOutcome(result); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), DescribePlayerSessions(testing::_)) + .Times(1) + .WillOnce(Return(successOutcome)); + + auto actualResult = m_serverManager->GetTestServerMatchBackfillPlayers(); + EXPECT_TRUE(actualResult.empty()); + } + + TEST_F(GameLiftServerManagerTest, GetActiveServerMatchBackfillPlayers_CallWithValidMatchmakingData_GetExpectedResult) + { + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + Aws::GameLift::Server::Model::PlayerSession playerSession; + playerSession.SetPlayerId("testplayer"); + Aws::GameLift::Server::Model::DescribePlayerSessionsResult result; + result.AddPlayerSessions(playerSession); + Aws::GameLift::DescribePlayerSessionsOutcome successOutcome(result); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), DescribePlayerSessions(testing::_)) + .Times(1) + .WillOnce(Return(successOutcome)); + + auto actualResult = m_serverManager->GetTestServerMatchBackfillPlayers(); + EXPECT_TRUE(actualResult.size() == 1); + EXPECT_TRUE(actualResult[0].m_team == "testteam"); + EXPECT_TRUE(actualResult[0].m_playerId == "testplayer"); + EXPECT_TRUE(actualResult[0].m_playerAttributes.size() == 4); + } + + TEST_F(GameLiftServerManagerTest, GetActiveServerMatchBackfillPlayers_CallWithMultiDescribePlayerButError_GetEmptyResult) + { + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA, 50); + + Aws::GameLift::GameLiftError error; + Aws::GameLift::DescribePlayerSessionsOutcome errorOutcome(error); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), DescribePlayerSessions(testing::_)) + .Times(1) + .WillOnce(Return(errorOutcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->GetTestServerMatchBackfillPlayers(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_TRUE(actualResult.empty()); + } + + TEST_F(GameLiftServerManagerTest, GetActiveServerMatchBackfillPlayers_CallWithMultiDescribePlayer_GetExpectedResult) + { + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA, 50); + + Aws::GameLift::Server::Model::PlayerSession playerSession1; + playerSession1.SetPlayerId("testplayer"); + Aws::GameLift::Server::Model::DescribePlayerSessionsResult result1; + result1.AddPlayerSessions(playerSession1); + result1.SetNextToken("testtoken"); + Aws::GameLift::DescribePlayerSessionsOutcome successOutcome1(result1); + + Aws::GameLift::Server::Model::PlayerSession playerSession2; + playerSession2.SetPlayerId("playernotinmatch"); + Aws::GameLift::Server::Model::DescribePlayerSessionsResult result2; + result2.AddPlayerSessions(playerSession2); + Aws::GameLift::DescribePlayerSessionsOutcome successOutcome2(result2); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), DescribePlayerSessions(testing::_)) + .WillOnce(Return(successOutcome1)) + .WillOnce(Return(successOutcome2)); + + auto actualResult = m_serverManager->GetTestServerMatchBackfillPlayers(); + EXPECT_TRUE(actualResult.size() == 1); + EXPECT_TRUE(actualResult[0].m_team == "testteam"); + EXPECT_TRUE(actualResult[0].m_playerId == "testplayer"); + EXPECT_TRUE(actualResult[0].m_playerAttributes.size() == 4); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_SDKNotInitialized_GetExpectedError) + { + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", {}); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithEmptyMatchmakingData_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(""); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", {}); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithInvalidPlayerAttribute_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + AWSGameLiftPlayer testPlayer = GetTestGameLiftPlayer(); + testPlayer.m_playerAttributes.clear(); + testPlayer.m_playerAttributes.emplace("invalidattribute", "{invalid}"); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", { testPlayer }); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithWrongPlayerAttributeType_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + AWSGameLiftPlayer testPlayer = GetTestGameLiftPlayer(); + testPlayer.m_playerAttributes.clear(); + testPlayer.m_playerAttributes.emplace("invalidattribute", "{\"SDM\": [\"test1\"]}"); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", { testPlayer }); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithUnexpectedPlayerAttributeType_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + AWSGameLiftPlayer testPlayer = GetTestGameLiftPlayer(); + testPlayer.m_playerAttributes.clear(); + testPlayer.m_playerAttributes.emplace("invalidattribute", "{\"UNEXPECTED\": [\"test1\"]}"); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", { testPlayer }); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithWrongSLPlayerAttributeValue_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + AWSGameLiftPlayer testPlayer = GetTestGameLiftPlayer(); + testPlayer.m_playerAttributes.clear(); + testPlayer.m_playerAttributes.emplace("invalidattribute", "{\"SL\": [10.0]}"); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", { testPlayer }); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithWrongSDMPlayerAttributeValue_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + AWSGameLiftPlayer testPlayer = GetTestGameLiftPlayer(); + testPlayer.m_playerAttributes.clear(); + testPlayer.m_playerAttributes.emplace("invalidattribute", "{\"SDM\": {10.0: \"test1\"}}"); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", { testPlayer }); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithValidPlayersData_GetExpectedResult) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + Aws::GameLift::Server::Model::StartMatchBackfillResult backfillResult; + Aws::GameLift::StartMatchBackfillOutcome backfillSuccessOutcome(backfillResult); + Aws::GameLift::Server::Model::StartMatchBackfillRequest request = GetTestStartMatchBackfillRequest(); + + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), StartMatchBackfill(StartMatchBackfillRequestMatcher(request))) + .Times(1) + .WillOnce(Return(backfillSuccessOutcome)); + + AWSGameLiftPlayer testPlayer = GetTestGameLiftPlayer(); + auto actualResult = m_serverManager->StartMatchBackfill("testticket", {testPlayer}); + EXPECT_TRUE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallWithoutGivingPlayersData_GetExpectedResult) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + Aws::GameLift::Server::Model::PlayerSession playerSession; + playerSession.SetPlayerId("testplayer"); + Aws::GameLift::Server::Model::DescribePlayerSessionsResult result; + result.AddPlayerSessions(playerSession); + Aws::GameLift::DescribePlayerSessionsOutcome successOutcome(result); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), DescribePlayerSessions(testing::_)) + .Times(1) + .WillOnce(Return(successOutcome)); + + Aws::GameLift::Server::Model::StartMatchBackfillResult backfillResult; + Aws::GameLift::StartMatchBackfillOutcome backfillSuccessOutcome(backfillResult); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), StartMatchBackfill(testing::_)) + .Times(1) + .WillOnce(Return(backfillSuccessOutcome)); + + auto actualResult = m_serverManager->StartMatchBackfill("testticket", {}); + EXPECT_TRUE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StartMatchBackfill_CallButStartBackfillFail_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + Aws::GameLift::Server::Model::PlayerSession playerSession; + playerSession.SetPlayerId("testplayer"); + Aws::GameLift::Server::Model::DescribePlayerSessionsResult result; + result.AddPlayerSessions(playerSession); + Aws::GameLift::DescribePlayerSessionsOutcome successOutcome(result); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), DescribePlayerSessions(testing::_)) + .Times(1) + .WillOnce(Return(successOutcome)); + + Aws::GameLift::GameLiftError error; + Aws::GameLift::StartMatchBackfillOutcome errorOutcome(error); + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), StartMatchBackfill(testing::_)) + .Times(1) + .WillOnce(Return(errorOutcome)); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StartMatchBackfill("testticket", {}); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StopMatchBackfill_SDKNotInitialized_GetExpectedError) + { + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StopMatchBackfill("testticket"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StopMatchBackfill_CallWithEmptyMatchmakingData_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(""); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StopMatchBackfill("testticket"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StopMatchBackfill_CallAndSuccessOutcome_GetExpectedResult) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), StopMatchBackfill(testing::_)) + .Times(1) + .WillOnce(Return(Aws::GameLift::GenericOutcome(nullptr))); + + auto actualResult = m_serverManager->StopMatchBackfill("testticket"); + EXPECT_TRUE(actualResult); + } + + TEST_F(GameLiftServerManagerTest, StopMatchBackfill_CallButErrorOutcome_GetExpectedError) + { + m_serverManager->InitializeGameLiftServerSDK(); + m_serverManager->SetupTestMatchmakingData(TEST_SERVER_MATCHMAKING_DATA); + + EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), StopMatchBackfill(testing::_)) + .Times(1) + .WillOnce(Return(Aws::GameLift::GenericOutcome())); + + AZ_TEST_START_TRACE_SUPPRESSION; + auto actualResult = m_serverManager->StopMatchBackfill("testticket"); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + EXPECT_FALSE(actualResult); + } } // namespace UnitTest diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h index 24336680b0..7ab9c51cd1 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -40,17 +41,25 @@ namespace UnitTest MOCK_METHOD1(AcceptPlayerSession, GenericOutcome(const std::string&)); MOCK_METHOD0(ActivateGameSession, GenericOutcome()); + MOCK_METHOD1(DescribePlayerSessions, DescribePlayerSessionsOutcome( + const Aws::GameLift::Server::Model::DescribePlayerSessionsRequest&)); MOCK_METHOD0(InitSDK, Server::InitSDKOutcome()); MOCK_METHOD1(ProcessReady, GenericOutcome(const Server::ProcessParameters& processParameters)); MOCK_METHOD0(ProcessEnding, GenericOutcome()); MOCK_METHOD1(RemovePlayerSession, GenericOutcome(const AZStd::string& playerSessionId)); MOCK_METHOD0(GetTerminationTime, AZStd::string()); + MOCK_METHOD1(StartMatchBackfill, StartMatchBackfillOutcome( + const Aws::GameLift::Server::Model::StartMatchBackfillRequest&)); + MOCK_METHOD1(StopMatchBackfill, GenericOutcome( + const Aws::GameLift::Server::Model::StopMatchBackfillRequest&)); + GenericOutcome ProcessReadyMock(const Server::ProcessParameters& processParameters) { m_healthCheckFunc = processParameters.getOnHealthCheck(); m_onStartGameSessionFunc = processParameters.getOnStartGameSession(); m_onProcessTerminateFunc = processParameters.getOnProcessTerminate(); + m_onUpdateGameSessionFunc = processParameters.getOnUpdateGameSession(); GenericOutcome successOutcome(nullptr); return successOutcome; @@ -59,6 +68,7 @@ namespace UnitTest AZStd::function m_healthCheckFunc; AZStd::function m_onProcessTerminateFunc; AZStd::function m_onStartGameSessionFunc; + AZStd::function m_onUpdateGameSessionFunc; }; class AWSGameLiftServerManagerMock @@ -78,12 +88,25 @@ namespace UnitTest m_gameLiftServerSDKWrapperMockPtr = nullptr; } + void SetupTestMatchmakingData(const AZStd::string& matchmakingData, int maxPlayer = 10) + { + m_testGameSession.SetMatchmakerData(matchmakingData.c_str()); + m_testGameSession.SetMaximumPlayerSessionCount(maxPlayer); + UpdateGameSessionData(m_testGameSession); + } + bool AddConnectedTestPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) { return AddConnectedPlayer(playerConnectionConfig); } + AZStd::vector GetTestServerMatchBackfillPlayers() + { + return GetActiveServerMatchBackfillPlayers(); + } + NiceMock* m_gameLiftServerSDKWrapperMockPtr; + Aws::GameLift::Server::Model::GameSession m_testGameSession; }; class AWSGameLiftServerSystemComponentMock diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_files.cmake b/Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_files.cmake index 95b5e1d2d2..9039c9943e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_files.cmake +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/awsgamelift_server_files.cmake @@ -7,6 +7,8 @@ # set(FILES + ../AWSGameLiftCommon/Include/AWSGameLiftPlayer.h + ../AWSGameLiftCommon/Source/AWSGameLiftPlayer.cpp ../AWSGameLiftCommon/Source/AWSGameLiftSessionConstants.h Include/Request/IAWSGameLiftServerRequests.h Source/AWSGameLiftServerManager.cpp diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 35174e31fb..4fad5697c7 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -308,6 +308,12 @@ namespace Multiplayer return true; } + void MultiplayerSystemComponent::OnUpdateSessionBegin(const AzFramework::SessionConfig& sessionConfig, const AZStd::string& updateReason) + { + AZ_UNUSED(sessionConfig); + AZ_UNUSED(updateReason); + } + void MultiplayerSystemComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { const AZ::TimeMs deltaTimeMs = aznumeric_cast(static_cast(deltaTime * 1000.0f)); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index e46bbb59bc..ef1fb0da5b 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -70,6 +70,7 @@ namespace Multiplayer bool OnSessionHealthCheck() override; bool OnCreateSessionBegin(const AzFramework::SessionConfig& sessionConfig) override; bool OnDestroySessionBegin() override; + void OnUpdateSessionBegin(const AzFramework::SessionConfig& sessionConfig, const AZStd::string& updateReason) override; //! @} //! AZ::TickBus::Handler overrides. From 66c25f3a029fd675002c695213a6056126e2cedd Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 13 Oct 2021 20:36:15 -0500 Subject: [PATCH 249/293] Making sure that all capture requests are cleaned up before the preview renderer gets destroyed A request was captured and held onto to by a lambda that was not getting cleared before the system was destroyed This caused an entity to be destroyed late, accessing the culling system that was already torn down Solution is to only store the success and failure callbacks inside of the attachment pass read back callback lambda so the rest of the content can be released Signed-off-by: Guthrie Adams --- .../PreviewRenderer/PreviewRenderer.cpp | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 2a6991dc46..6e47360a84 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -96,7 +96,6 @@ namespace AtomToolsFramework AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); m_frameworkScene->UnsetSubsystem(m_scene); m_frameworkScene->UnsetSubsystem(m_entityContext.get()); - m_entityContext->DestroyContext(); } void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) @@ -134,7 +133,10 @@ namespace AtomToolsFramework void PreviewRenderer::CancelCaptureRequest() { - m_currentCaptureRequest.m_captureFailedCallback(); + if (m_currentCaptureRequest.m_captureFailedCallback) + { + m_currentCaptureRequest.m_captureFailedCallback(); + } m_state.reset(); m_state.reset(new PreviewRendererIdleState(this)); } @@ -179,17 +181,25 @@ namespace AtomToolsFramework bool PreviewRenderer::StartCapture() { - auto captureCallback = [currentCaptureRequest = m_currentCaptureRequest](const AZ::RPI::AttachmentReadback::ReadbackResult& result) + auto captureCompleteCallback = m_currentCaptureRequest.m_captureCompleteCallback; + auto captureFailedCallback = m_currentCaptureRequest.m_captureFailedCallback; + auto captureCallback = [captureCompleteCallback, captureFailedCallback](const AZ::RPI::AttachmentReadback::ReadbackResult& result) { if (result.m_dataBuffer) { - currentCaptureRequest.m_captureCompleteCallback(QPixmap::fromImage(QImage( - result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, - QImage::Format_RGBA8888))); + if (captureCompleteCallback) + { + captureCompleteCallback(QPixmap::fromImage(QImage( + result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, + result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888))); + } } else { - currentCaptureRequest.m_captureFailedCallback(); + if (captureFailedCallback) + { + captureFailedCallback(); + } } }; @@ -209,6 +219,7 @@ namespace AtomToolsFramework void PreviewRenderer::EndCapture() { + m_currentCaptureRequest = {}; m_renderPipeline->RemoveFromRenderTick(); } From 922a9914438b55464984c330c6ac8a8496a5febf Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Wed, 13 Oct 2021 21:15:29 -0700 Subject: [PATCH 250/293] change expected_lines to something that appears in both AR + locally (#4680) Signed-off-by: jromnoa --- AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index 74b064a555..381f266fab 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -148,7 +148,7 @@ class TestAllComponentsIndepthTests(object): golden_image_path = os.path.join(golden_images_directory(), golden_image) golden_images.append(golden_image_path) - expected_lines = ["Light component tests completed."] + expected_lines = ["spot_light Controller|Configuration|Shadows|Shadowmap size: SUCCESS"] unexpected_lines = [ "Trace::Assert", "Trace::Error", From 5a204dc80b65c322be7fb038cd9c5783cadf4533 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 13 Oct 2021 21:26:03 -0700 Subject: [PATCH 251/293] chore: remove equality from boolean expression Signed-off-by: Michael Pollind --- .../AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp | 2 +- Gems/LmbrCentral/Code/Source/Shape/BoxShape.cpp | 2 +- Gems/LmbrCentral/Code/Source/Shape/DiskShape.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp index 3a7fffb3be..4c7afa2275 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp @@ -116,7 +116,7 @@ namespace AzToolsFramework { return AZ::Intersect::IntersectRayBox( rayOrigin, rayDirection, m_center, m_axis1, m_axis2, m_axis3, m_halfExtents.GetX(), m_halfExtents.GetY(), - m_halfExtents.GetZ(), rayIntersectionDistance) > 0; + m_halfExtents.GetZ(), rayIntersectionDistance); } void ManipulatorBoundBox::SetShapeData(const BoundRequestShapeBase& shapeData) diff --git a/Gems/LmbrCentral/Code/Source/Shape/BoxShape.cpp b/Gems/LmbrCentral/Code/Source/Shape/BoxShape.cpp index a776a01ccc..4f6089ba16 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/BoxShape.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/BoxShape.cpp @@ -166,7 +166,7 @@ namespace LmbrCentral return intersection; } - const bool intersection = AZ::Intersect::IntersectRayObb(src, dir, m_intersectionDataCache.m_obb, distance) > 0; + const bool intersection = AZ::Intersect::IntersectRayObb(src, dir, m_intersectionDataCache.m_obb, distance); return intersection; } diff --git a/Gems/LmbrCentral/Code/Source/Shape/DiskShape.cpp b/Gems/LmbrCentral/Code/Source/Shape/DiskShape.cpp index 8eaf03457f..1c4a94ced3 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/DiskShape.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/DiskShape.cpp @@ -153,7 +153,7 @@ namespace LmbrCentral m_intersectionDataCache.UpdateIntersectionParams(m_currentTransform, m_diskShapeConfig); return AZ::Intersect::IntersectRayDisk( - src, dir, m_intersectionDataCache.m_position, m_intersectionDataCache.m_radius, m_intersectionDataCache.m_normal, distance) > 0; + src, dir, m_intersectionDataCache.m_position, m_intersectionDataCache.m_radius, m_intersectionDataCache.m_normal, distance); } void DiskShape::DiskIntersectionDataCache::UpdateIntersectionParamsImpl( From 5967b419a29805c1db276eb33704fff9ca4a3a67 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Thu, 14 Oct 2021 07:45:44 -0700 Subject: [PATCH 252/293] Only enable the Keyboard device in the XcbKeyboard unit tests (#4682) This prevents other input devices from interfering with the expected calls that the Keyboard tests should make. Signed-off-by: Chris Burel --- .../Input/System/InputSystemComponent.cpp | 20 +++++++++ .../Xcb/AzFramework/XcbNativeWindow.cpp | 1 + .../Xcb/XcbInputDeviceKeyboardTests.cpp | 42 ++++++++++--------- .../Platform/Common/Xcb/XcbTestApplication.h | 38 +++++++++++++++++ .../Xcb/azframework_xcb_tests_files.cmake | 1 + 5 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbTestApplication.h diff --git a/Code/Framework/AzFramework/AzFramework/Input/System/InputSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Input/System/InputSystemComponent.cpp index 33690f2246..14fb7ea5eb 100644 --- a/Code/Framework/AzFramework/AzFramework/Input/System/InputSystemComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Input/System/InputSystemComponent.cpp @@ -20,6 +20,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////////////////////////////////////////////// namespace AzFramework @@ -190,6 +191,25 @@ namespace AzFramework //////////////////////////////////////////////////////////////////////////////////////////////// void InputSystemComponent::Activate() { + const auto* settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry) + { + AZ::u64 value = 0; + if (settingsRegistry->Get(value, "/O3DE/InputSystem/MouseMovementSampleRateHertz")) + { + m_mouseMovementSampleRateHertz = aznumeric_caster(value); + } + if (settingsRegistry->Get(value, "/O3DE/InputSystem/GamepadsEnabled")) + { + m_gamepadsEnabled = aznumeric_caster(value); + } + settingsRegistry->Get(m_keyboardEnabled, "/O3DE/InputSystem/KeyboardEnabled"); + settingsRegistry->Get(m_motionEnabled, "/O3DE/InputSystem/MotionEnabled"); + settingsRegistry->Get(m_mouseEnabled, "/O3DE/InputSystem/MouseEnabled"); + settingsRegistry->Get(m_touchEnabled, "/O3DE/InputSystem/TouchEnabled"); + settingsRegistry->Get(m_virtualKeyboardEnabled, "/O3DE/InputSystem/VirtualKeyboardEnabled"); + } + // Create all enabled input devices CreateEnabledInputDevices(); diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp index 6ab97fd616..43f7e7140f 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp index 2b1f21ede7..76d00eda50 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbInputDeviceKeyboardTests.cpp @@ -12,7 +12,6 @@ #include -#include #include #include #include @@ -20,6 +19,7 @@ #include "Matchers.h" #include "Actions.h" #include "XcbBaseTestFixture.h" +#include "XcbTestApplication.h" template xcb_generic_event_t MakeEvent(T event) @@ -33,6 +33,7 @@ namespace AzFramework class XcbInputDeviceKeyboardTests : public XcbBaseTestFixture { + public: void SetUp() override { using testing::Return; @@ -123,6 +124,15 @@ namespace AzFramework static constexpr xcb_keycode_t s_keycodeForAKey{38}; static constexpr xcb_keycode_t s_keycodeForShiftLKey{50}; + + XcbTestApplication m_application{ + /*enabledGamepadsCount=*/0, + /*keyboardEnabled=*/true, + /*motionEnabled=*/false, + /*mouseEnabled=*/false, + /*touchEnabled=*/false, + /*virtualKeyboardEnabled=*/false + }; }; class InputTextNotificationListener @@ -195,27 +205,23 @@ namespace AzFramework EXPECT_CALL(m_interface, xkb_state_key_get_one_sym(&m_xkbState, s_keycodeForAKey)) .Times(2); - Application application; - application.Start({}, {}); - AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); + m_application.Start(); const InputChannel* inputChannel = InputChannelRequests::FindInputChannel(InputDeviceKeyboard::Key::AlphanumericA); ASSERT_TRUE(inputChannel); EXPECT_THAT(inputChannel->GetState(), Eq(InputChannel::State::Idle)); - application.PumpSystemEventLoopUntilEmpty(); - application.TickSystem(); - application.Tick(); + m_application.PumpSystemEventLoopUntilEmpty(); + m_application.TickSystem(); + m_application.Tick(); EXPECT_THAT(inputChannel->GetState(), Eq(InputChannel::State::Began)); - application.PumpSystemEventLoopUntilEmpty(); - application.TickSystem(); - application.Tick(); + m_application.PumpSystemEventLoopUntilEmpty(); + m_application.TickSystem(); + m_application.Tick(); EXPECT_THAT(inputChannel->GetState(), Eq(InputChannel::State::Ended)); - - application.Stop(); } TEST_F(XcbInputDeviceKeyboardTests, TextEnteredFromXcbKeyPressEvents) @@ -420,17 +426,13 @@ namespace AzFramework EXPECT_CALL(textListener, OnInputTextEvent(StrEq("a"), _)).Times(1); EXPECT_CALL(textListener, OnInputTextEvent(StrEq("A"), _)).Times(1); - Application application; - application.Start({}, {}); - AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); + m_application.Start(); for (int i = 0; i < 4; ++i) { - application.PumpSystemEventLoopUntilEmpty(); - application.TickSystem(); - application.Tick(); + m_application.PumpSystemEventLoopUntilEmpty(); + m_application.TickSystem(); + m_application.Tick(); } - - application.Stop(); } } // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbTestApplication.h b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbTestApplication.h new file mode 100644 index 0000000000..3035a9de74 --- /dev/null +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/XcbTestApplication.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AzFramework +{ + class XcbTestApplication + : public Application + { + public: + XcbTestApplication(AZ::u64 enabledGamepadsCount, bool keyboardEnabled, bool motionEnabled, bool mouseEnabled, bool touchEnabled, bool virtualKeyboardEnabled) + { + auto* settingsRegistry = AZ::SettingsRegistry::Get(); + settingsRegistry->Set("/O3DE/InputSystem/GamepadsEnabled", enabledGamepadsCount); + settingsRegistry->Set("/O3DE/InputSystem/KeyboardEnabled", keyboardEnabled); + settingsRegistry->Set("/O3DE/InputSystem/MotionEnabled", motionEnabled); + settingsRegistry->Set("/O3DE/InputSystem/MouseEnabled", mouseEnabled); + settingsRegistry->Set("/O3DE/InputSystem/TouchEnabled", touchEnabled); + settingsRegistry->Set("/O3DE/InputSystem/VirtualKeyboardEnabled", virtualKeyboardEnabled); + } + + void Start(const Descriptor& descriptor = {}, const StartupParameters& startupParameters = {}) override + { + Application::Start(descriptor, startupParameters); + AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); + } + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake index 762d5d74fe..147fd2bfe1 100644 --- a/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake +++ b/Code/Framework/AzFramework/Tests/Platform/Common/Xcb/azframework_xcb_tests_files.cmake @@ -17,4 +17,5 @@ set(FILES XcbBaseTestFixture.cpp XcbBaseTestFixture.h XcbInputDeviceKeyboardTests.cpp + XcbTestApplication.h ) From ec10bb078e1e21f5a749f55c33c5a05758cb53be Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 14 Oct 2021 16:06:13 +0100 Subject: [PATCH 253/293] improve wording for all PhysX gem tooltips apart from pipeline, fixes 3898 Signed-off-by: greerdv --- Gems/PhysX/Code/Editor/DebugDraw.cpp | 6 +- .../Code/Editor/EditorJointConfiguration.cpp | 52 +++++++++------- .../Configuration/PhysXConfiguration.cpp | 10 ++-- .../Configuration/PhysXDebugConfiguration.cpp | 25 ++++---- .../Code/Source/EditorBallJointComponent.cpp | 6 +- .../Code/Source/EditorColliderComponent.cpp | 30 +++++----- .../Code/Source/EditorFixedJointComponent.cpp | 5 +- .../Source/EditorForceRegionComponent.cpp | 9 +-- .../Code/Source/EditorHingeJointComponent.cpp | 6 +- .../Code/Source/EditorJointComponent.cpp | 4 +- .../Code/Source/EditorRigidBodyComponent.cpp | 59 ++++++++++--------- .../Source/EditorShapeColliderComponent.cpp | 9 +-- Gems/PhysX/Code/Source/ForceRegion.cpp | 4 +- Gems/PhysX/Code/Source/ForceRegionForces.cpp | 39 ++++++------ .../Configuration/PhysXJointConfiguration.cpp | 8 +-- .../API/CharacterController.cpp | 6 +- .../Components/CharacterGameplayComponent.cpp | 2 +- .../EditorCharacterControllerComponent.cpp | 15 ++--- .../EditorCharacterGameplayComponent.cpp | 4 +- .../Components/RagdollComponent.cpp | 20 ++++--- Gems/PhysX/Code/Source/SystemComponent.cpp | 2 +- 21 files changed, 174 insertions(+), 147 deletions(-) diff --git a/Gems/PhysX/Code/Editor/DebugDraw.cpp b/Gems/PhysX/Code/Editor/DebugDraw.cpp index 440b198675..5936312ecf 100644 --- a/Gems/PhysX/Code/Editor/DebugDraw.cpp +++ b/Gems/PhysX/Code/Editor/DebugDraw.cpp @@ -148,16 +148,16 @@ namespace PhysX using VisibilityFunc = bool(*)(); editContext->Class( - "PhysX Collider Debug Draw", "Manages global and per-collider debug draw settings and logic") + "PhysX Collider Debug Draw", "Global and per-collider debug draw preferences.") ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Collider::m_locallyEnabled, "Draw collider", - "Shows the geometry for the collider in the viewport") + "Display collider geometry in the viewport.") ->Attribute(AZ::Edit::Attributes::CheckboxTooltip, "If set, the geometry of this collider is visible in the viewport. 'Draw Helpers' needs to be enabled to use.") ->Attribute(AZ::Edit::Attributes::Visibility, VisibilityFunc{ []() { return IsGlobalColliderDebugCheck(GlobalCollisionDebugState::Manual); } }) ->Attribute(AZ::Edit::Attributes::ReadOnly, &IsDrawColliderReadOnly) ->DataElement(AZ::Edit::UIHandlers::Button, &Collider::m_globalButtonState, "Draw collider", - "Shows the geometry for the collider in the viewport") + "Display collider geometry in the viewport.") ->Attribute(AZ::Edit::Attributes::ButtonText, "Global override") ->Attribute(AZ::Edit::Attributes::ButtonTooltip, "A global setting is overriding this property (to disable the override, " diff --git a/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp b/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp index b9ed827ce0..ee3988ded4 100644 --- a/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp +++ b/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp @@ -51,23 +51,27 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "Editor Joint Limit Config Base", "Base joint limit parameters") + "Editor Joint Limit Config Base", "Base joint limit parameters.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isLimited, "Limit", "True if the motion about the unconstrained axes of this joint are limited") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isLimited, "Limit", + "When active, the joint's degrees of freedom are limited.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointLimitConfig::IsInComponentMode) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isSoftLimit, "Soft limit", "True if the joint is allowed to rotate beyond limits and spring back") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isSoftLimit, "Soft limit", + "When active, motion beyond the joint limit with a spring-like return is allowed.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::m_isLimited) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointLimitConfig::IsInComponentMode) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_damping, "Damping", "The damping strength of the drive, the force proportional to the velocity error") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_damping, "Damping", + "Dissipation of energy and reduction in spring oscillations when outside the joint limit.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::IsSoftLimited) ->Attribute(AZ::Edit::Attributes::Max, s_springMax) ->Attribute(AZ::Edit::Attributes::Min, s_springMin) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_stiffness, "Stiffness", "The spring strength of the drive, the force proportional to the position error") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_stiffness, "Stiffness", + "The spring's drive relative to the position of the follower when outside the rotation limit.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::IsSoftLimited) ->Attribute(AZ::Edit::Attributes::Max, s_springMax) ->Attribute(AZ::Edit::Attributes::Min, s_springMin) @@ -115,18 +119,20 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "Angular Limit", "Rotation limitation") + "Angular Limit", "Rotation limitation.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_standardLimitConfig , "Standard limit configuration" - , "Common limit parameters to all joint types") - ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitPositive, "Positive angular limit", "Positive rotation angle") + , "Common limit parameters to all joint types.") + ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitPositive, "Positive angular limit", + "Positive rotation angle.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitPairConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMax) ->Attribute(AZ::Edit::Attributes::Min, s_angleMin) - ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitNegative, "Negative angular limit", "Negative rotation angle") + ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitNegative, "Negative angular limit", + "Negative rotation angle.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitPairConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMin) ->Attribute(AZ::Edit::Attributes::Min, -s_angleMax) @@ -164,18 +170,20 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "Angular Limit", "Rotation limitation") + "Angular Limit", "Rotation limitation.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_standardLimitConfig , "Standard limit configuration" - , "Common limit parameters to all joint types") - ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitY, "Y axis angular limit", "Limit for swing angle about Y axis") + , "Common limit parameters to all joint types.") + ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitY, "Y axis angular limit", + "Limit for swing angle about Y axis.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConeConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMax) ->Attribute(AZ::Edit::Attributes::Min, s_angleMin) - ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitZ, "Z axis angular limit", "Limit for swing angle about Z axis") + ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitZ, "Z axis angular limit", + "Limit for swing angle about Z axis.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConeConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMax) ->Attribute(AZ::Edit::Attributes::Min, s_angleMin) @@ -226,33 +234,33 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &PhysX::EditorJointConfig::m_localPosition, "Local Position" - , "Local Position of joint, relative to its entity") + , "Local Position of joint, relative to its entity.") ->DataElement(0, &PhysX::EditorJointConfig::m_localRotation, "Local Rotation" - , "Local Rotation of joint, relative to its entity") + , "Local Rotation of joint, relative to its entity.") ->Attribute(AZ::Edit::Attributes::Min, LocalRotationMin) ->Attribute(AZ::Edit::Attributes::Max, LocalRotationMax) ->DataElement(0, &PhysX::EditorJointConfig::m_leadEntity, "Lead Entity" - , "Parent entity associated with joint") + , "Parent entity associated with joint.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorJointConfig::ValidateLeadEntityId) ->DataElement(0, &PhysX::EditorJointConfig::m_selfCollide, "Lead-Follower Collide" - , "Lead and follower pair will collide with each other") + , "When active, the lead and follower pair will collide with each other.") ->DataElement(0, &PhysX::EditorJointConfig::m_displayJointSetup, "Display Setup in Viewport" - , "Display joint setup in the viewport") + , "Display joint setup in the viewport.") ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointConfig::IsInComponentMode) ->DataElement(0, &PhysX::EditorJointConfig::m_selectLeadOnSnap, "Select Lead on Snap" - , "Select lead entity on snap to position in component mode") + , "Select lead entity on snap to position in component mode.") ->DataElement(0, &PhysX::EditorJointConfig::m_breakable , "Breakable" - , "Joint is breakable when force or torque exceeds limit") + , "Joint is breakable when force or torque exceeds limit.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointConfig::IsInComponentMode) ->DataElement(0, &PhysX::EditorJointConfig::m_forceMax, - "Maximum Force", "Amount of force joint can withstand before breakage") + "Maximum Force", "Amount of force joint can withstand before breakage.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointConfig::m_breakable) ->Attribute(AZ::Edit::Attributes::Max, s_breakageMax) ->Attribute(AZ::Edit::Attributes::Min, s_breakageMin) ->DataElement(0, &PhysX::EditorJointConfig::m_torqueMax, - "Maximum Torque", "Amount of torque joint can withstand before breakage") + "Maximum Torque", "Amount of torque joint can withstand before breakage.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointConfig::m_breakable) ->Attribute(AZ::Edit::Attributes::Max, s_breakageMax) ->Attribute(AZ::Edit::Attributes::Min, s_breakageMin) diff --git a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp index 7a441a1c55..02f0bc038a 100644 --- a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp @@ -54,17 +54,17 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("Wind Configuration", "Wind settings for PhysX") + editContext->Class("Wind Configuration", "Wind force entity tags.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &WindConfiguration::m_globalWindTag, "Global wind tag", - "Tag value that will be used to mark entities that provide global wind value.\n" - "Global wind has no bounds and affects objects across entire level.") + "Global wind provider tags.\n" + "Global winds apply to entire world.") ->DataElement(AZ::Edit::UIHandlers::Default, &WindConfiguration::m_localWindTag, "Local wind tag", - "Tag value that will be used to mark entities that provide local wind value.\n" - "Local wind is only applied within bounds defined by PhysX collider.") + "Local wind provider tags.\n" + "Local winds are constrained to a PhysX collider's boundaries.") ; } } diff --git a/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp b/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp index e14ce62537..c199159a43 100644 --- a/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp @@ -31,38 +31,39 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("PhysX PVD Settings", "PhysX PVD Settings") + editContext->Class("PhysX PVD Settings", + "Connection configuration settings for the PhysX Visual Debugger (PVD). Requires PhysX Debug Gem.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &PvdConfiguration::m_transportType, - "PVD Transport Type", "PVD supports writing to a TCP/IP network socket or to a file.") + "PVD Transport Type", "Output PhysX Visual Debugger data to a TCP/IP network socket or to a file.") ->EnumAttribute(Debug::PvdTransportType::Network, "Network") ->EnumAttribute(Debug::PvdTransportType::File, "File") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_host, - "PVD Host", "Host IP address of the PhysX Visual Debugger application") + "PVD Host", "Host IP address of the PhysX Visual Debugger server.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_port, - "PVD Port", "Port of the PhysX Visual Debugger application") + "PVD Port", "Port of the PhysX Visual Debugger server.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug) + ->Attribute(AZ::Edit::Attributes::Min, AZStd::numeric_limits::min()) + ->Attribute(AZ::Edit::Attributes::Max, AZStd::numeric_limits::max()) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_timeoutInMilliseconds, - "PVD Timeout", "Timeout (in milliseconds) used when connecting to the PhysX Visual Debugger application") + "PVD Timeout", "Timeout (in milliseconds) when connecting to the PhysX Visual Debugger server.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_fileName, - "PVD FileName", "Filename to output PhysX Visual Debugger data.") + "PVD FileName", "Output filename for PhysX Visual Debugger data.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsFileDebug) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &PvdConfiguration::m_autoConnectMode, - "PVD Auto Connect", "Automatically connect to the PhysX Visual Debugger " - "(Requires PhysX Debug gem for Editor and Game modes).") + "PVD Auto Connect", "Automatically connect to the PhysX Visual Debugger.") ->EnumAttribute(Debug::PvdAutoConnectMode::Disabled, "Disabled") ->EnumAttribute(Debug::PvdAutoConnectMode::Editor, "Editor") ->EnumAttribute(Debug::PvdAutoConnectMode::Game, "Game") - ->DataElement(AZ::Edit::UIHandlers::CheckBox, &PvdConfiguration::m_reconnect, - "PVD Reconnect", "Reconnect (Disconnect and Connect) when switching between game and edit mode " - "(Requires PhysX Debug gem).") + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &PvdConfiguration::m_reconnect, "PVD Reconnect", + "Reconnect (disconnect and connect) to the PhysX Visual Debugger server when switching between game and edit mode.") ; } } @@ -131,7 +132,7 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("Editor Configuration", "Editor settings for PhysX") + editContext->Class("Editor Configuration", "Editor settings for PhysX.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Slider, &DebugDisplayData::m_centerOfMassDebugSize, diff --git a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp index 92952bcdaa..fa71fa0061 100644 --- a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp @@ -33,14 +33,14 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Ball Joint", "The ball joint supports a cone limiting the maximum rotation around the y and z axes.") + "PhysX Ball Joint", "A dynamic joint constraint with swing rotation limits around the Y and Z axes of the joint.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ball-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &EditorBallJointComponent::m_swingLimit, "Swing Limit", "Limitations for the swing (Y and Z axis) about joint") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorBallJointComponent::m_componentModeDelegate, "Component Mode", "Ball Joint Component Mode") + ->DataElement(0, &EditorBallJointComponent::m_swingLimit, "Swing Limit", "The rotation angle limit around the joint's Y and Z axes.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorBallJointComponent::m_componentModeDelegate, "Component Mode", "Ball Joint Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index f8d0adf156..262e40cb99 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -53,13 +53,15 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { - editContext->Class("EditorProxyShapeConfig", "PhysX Base shape collider") + editContext->Class("EditorProxyShapeConfig", "PhysX Base collider.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_pxAsset, "PhysX Mesh", "PhysX mesh collider asset") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_pxAsset, "PhysX Mesh", + "Specifies the PhysX mesh collider asset for this PhysX collider component.") ->Attribute(AZ_CRC_CE("EditButton"), "") ->Attribute(AZ_CRC_CE("EditDescription"), "Open in Scene Settings") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_configuration, "Configuration", "Configuration of asset shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_configuration, "Configuration", + "PhysX mesh asset collider configuration.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); } } @@ -86,7 +88,7 @@ namespace PhysX { editContext->Class( "EditorProxyShapeConfig", "PhysX Base shape collider") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorProxyShapeConfig::m_shapeType, "Shape", "The shape of the collider") + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorProxyShapeConfig::m_shapeType, "Shape", "The shape of the collider.") ->EnumAttribute(Physics::ShapeType::Sphere, "Sphere") ->EnumAttribute(Physics::ShapeType::Box, "Box") ->EnumAttribute(Physics::ShapeType::Capsule, "Capsule") @@ -96,20 +98,20 @@ namespace PhysX // potentially be different ComponentModes for different shape types) ->Attribute(AZ::Edit::Attributes::ReadOnly, &AzToolsFramework::ComponentModeFramework::InComponentMode) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_sphere, "Sphere", "Configuration of sphere shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_sphere, "Sphere", "Configuration of sphere shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsSphereConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_box, "Box", "Configuration of box shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_box, "Box", "Configuration of box shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsBoxConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_capsule, "Capsule", "Configuration of capsule shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_capsule, "Capsule", "Configuration of capsule shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsCapsuleConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_physicsAsset, "Asset", "Configuration of asset shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_physicsAsset, "Asset", "Configuration of asset shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsAssetConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_subdivisionLevel, "Subdivision level", - "The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling") + "The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling.") ->Attribute(AZ::Edit::Attributes::Min, Utils::MinCapsuleSubdivisionLevel) ->Attribute(AZ::Edit::Attributes::Max, Utils::MaxCapsuleSubdivisionLevel) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::ShowingSubdivisionLevel) @@ -200,7 +202,7 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Collider", "PhysX shape collider") + "PhysX Collider", "Creates geometry in the PhysX simulation, using either a primitive shape or geometry from an asset.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg") @@ -208,17 +210,17 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/collider/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_configuration, "Collider Configuration", "Configuration of the collider") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_configuration, "Collider Configuration", "Configuration of the collider.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorColliderComponent::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_shapeConfiguration, "Shape Configuration", "Configuration of the shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_shapeConfiguration, "Shape Configuration", "Configuration of the shape.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorColliderComponent::OnConfigurationChanged) ->Attribute(AZ::Edit::Attributes::RemoveNotify, &EditorColliderComponent::ValidateRigidBodyMeshGeometryType) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_componentModeDelegate, "Component Mode", "Collider Component Mode") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_componentModeDelegate, "Component Mode", "Collider Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_colliderDebugDraw, - "Debug draw settings", "Debug draw settings") + "Debug draw settings", "Debug draw settings.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp index 94f57690ba..692671174b 100644 --- a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp @@ -30,13 +30,14 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Fixed Joint", "The fixed joint constraints the position and orientation of a body to another.") + "PhysX Fixed Joint", + "A dynamic joint constraint that constrains a rigid body to the joint with no free translation or rotation on any axis.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/fixed-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorFixedJointComponent::m_componentModeDelegate, "Component Mode", "Fixed Joint Component Mode") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorFixedJointComponent::m_componentModeDelegate, "Component Mode", "Fixed Joint Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp b/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp index 610a0a9b2e..dff1ff86bb 100644 --- a/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp @@ -164,7 +164,7 @@ namespace PhysX { // EditorForceRegionComponent editContext->Class( - "PhysX Force Region", "The force region component is used to apply a physical force on objects within the region") + "PhysX Force Region", "The force region component is used to apply a physical force on objects within the region.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/ForceVolume.svg") @@ -173,9 +173,10 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/force-region/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::RequiredService, AZ_CRC("PhysXTriggerService", 0x3a117d7b)) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_visibleInEditor, "Visible", "Always show the component in viewport") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_debugForces, "Debug Forces", "Draws debug arrows when an entity enters a force region. This occurs in gameplay mode to show the force direction on an entity.") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_forces, "Forces", "Forces in force region") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_visibleInEditor, "Visible", "Always show the component in viewport.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_debugForces, "Debug Forces", + "Draws debug arrows when an entity enters a force region. This occurs in gameplay mode to show the force direction on an entity.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_forces, "Forces", "Forces in force region.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorForceRegionComponent::OnForcesChanged) ; diff --git a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp index 5537502327..1b575074e2 100644 --- a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp @@ -33,14 +33,14 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Hinge Joint", "The entity constrains two actors in PhysX, keeping the origins and x-axes together, and allows free rotation around this common axis") + "PhysX Hinge Joint", "A dynamic joint that constrains a rigid body with rotation limits around a single axis.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/hinge-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &EditorHingeJointComponent::m_angularLimit, "Angular Limit", "Limitations for the rotation about hinge axis") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorHingeJointComponent::m_componentModeDelegate, "Component Mode", "Hinge Joint Component Mode") + ->DataElement(0, &EditorHingeJointComponent::m_angularLimit, "Angular Limit", "The rotation angle limit around the joint's axis.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorHingeJointComponent::m_componentModeDelegate, "Component Mode", "Hinge Joint Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorJointComponent.cpp b/Gems/PhysX/Code/Source/EditorJointComponent.cpp index 88e192026d..9a24392fd0 100644 --- a/Gems/PhysX/Code/Source/EditorJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorJointComponent.cpp @@ -37,11 +37,11 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Joint", "The joint constrains the position and orientation of a body to another.") + "PhysX Joint", "A dynamic joint that constrains the position and orientation of one rigid body to another.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &EditorJointComponent::m_config, "Standard Joint Parameters", "Joint parameters shared by all joint types") + ->DataElement(0, &EditorJointComponent::m_config, "Standard Joint Parameters", "Joint parameters shared by all joint types.") ; } } diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp index 24b2586c9e..e384f222e8 100644 --- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp @@ -122,38 +122,38 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_initialLinearVelocity, - "Initial linear velocity", "Initial linear velocity") + "Initial linear velocity", "Linear velocity applied when the rigid body is activated.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInitialVelocitiesVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetSpeedUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_initialAngularVelocity, - "Initial angular velocity", "Initial angular velocity (limited by maximum angular velocity)") + "Initial angular velocity", "Angular velocity applied when the rigid body is activated (limited by maximum angular velocity).") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInitialVelocitiesVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetAngularVelocityUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_linearDamping, - "Linear damping", "Linear damping (must be non-negative)") + "Linear damping", "The rate of decay over time for linear velocity even if no forces are acting on the rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetDampingVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_angularDamping, - "Angular damping", "Angular damping (must be non-negative)") + "Angular damping", "The rate of decay over time for angular velocity even if no forces are acting on the rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetDampingVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_sleepMinEnergy, - "Sleep threshold", "Kinetic energy per unit mass below which body can go to sleep (must be non-negative)") + "Sleep threshold", "The rigid body can go to sleep (settle) when kinetic energy per unit mass is persistently below this value.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetSleepOptionsVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetSleepThresholdUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_startAsleep, - "Start asleep", "The rigid body will be asleep when spawned") + "Start asleep", "When active, the rigid body will be asleep when spawned, and wake when the body is disturbed.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetSleepOptionsVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_interpolateMotion, - "Interpolate motion", "Makes object motion look smoother") + "Interpolate motion", "When active, simulation results are interpolated resulting in smoother motion.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInterpolationVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_gravityEnabled, - "Gravity enabled", "Rigid body will be affected by gravity") + "Gravity enabled", "When active, global gravity affects this rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetGravityVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_kinematic, - "Kinematic", "Rigid body is kinematic") + "Kinematic", "When active, the rigid body is not affected by gravity or other forces and is moved by script.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetKinematicVisibility) // Linear axis locking properties @@ -161,85 +161,90 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearX, "Lock X", - "Lock motion along X direction") + "When active, forces won't create translation on the X axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearY, "Lock Y", - "Lock motion along Y direction") + "When active, forces won't create translation on the Y axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearZ, "Lock Z", - "Lock motion along Z direction") + "When active, forces won't create translation on the Z axis of the rigid body.") // Angular axis locking properties ->ClassElement(AZ::Edit::ClassElements::Group, "Angular Axis Locking") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularX, "Lock X", - "Lock rotation around X direction") + "When active, forces won't create rotation on the X axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularY, "Lock Y", - "Lock rotation around Y direction") + "When active, forces won't create rotation on the Y axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularZ, "Lock Z", - "Lock rotation around Z direction") + "When active, forces won't create rotation on the Z axis of the rigid body.") ->ClassElement(AZ::Edit::ClassElements::Group, "Continuous Collision Detection") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCCDVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdEnabled, - "CCD enabled", "Whether continuous collision detection is enabled for this body") + "CCD enabled", "When active, the rigid body has continuous collision detection (CCD). Use this to ensure accurate " + "collision detection, particularly for fast moving rigid bodies. CCD must be activated in the global PhysX preferences.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCCDVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdMinAdvanceCoefficient, - "Min advance coefficient", "Lower values reduce clipping but can affect simulation smoothness") + "Min advance coefficient", "Lower values reduce clipping but can affect simulation smoothness.") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) ->Attribute(AZ::Edit::Attributes::Max, 0.99f) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::IsCCDEnabled) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdFrictionEnabled, - "CCD friction", "Whether friction is applied when CCD collisions are resolved") + "CCD friction", "When active, friction is applied when continuous collision detection (CCD) collisions are resolved.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::IsCCDEnabled) ->ClassElement(AZ::Edit::ClassElements::Group, "") // end previous group by starting new unnamed expanded group ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_maxAngularVelocity, - "Maximum angular velocity", "The PhysX solver will clamp angular velocities with magnitude exceeding this value") + "Maximum angular velocity", "Clamp angular velocities to this maximum value. " + "This prevents rigid bodies from rotating at unrealistic velocities after collisions.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetMaxVelocitiesVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetAngularVelocityUnit()) // Mass properties ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeCenterOfMass, - "Compute COM", "Whether to automatically compute the center of mass") + "Compute COM", "Compute the center of mass (COM) for this rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_centerOfMassOffset, - "COM offset", "Center of mass offset in local frame") + "COM offset", "Local space offset for the center of mass (COM).") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCoMVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetLengthUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeMass, - "Compute Mass", "Whether to automatically compute the mass") + "Compute Mass", "When active, the mass of the rigid body is computed based on the volume and density values of its colliders.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_mass, - "Mass", "The mass of the object (must be non-negative, with a value of zero treated as infinite)") + "Mass", "The mass of the rigid body in kilograms. A value of 0 is treated as infinite. " + "The trajectory of infinite mass bodies cannot be affected by any collisions or forces other than gravity.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetMassUnit()) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetMassVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeInertiaTensor, - "Compute inertia", "Whether to automatically compute the inertia values based on the mass and shape of the rigid body") + "Compute inertia", "When active, inertia is computed based on the mass and shape of the rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(Editor::InertiaHandler, &AzPhysics::RigidBodyConfiguration::m_inertiaTensor, - "Inertia diagonal", "Diagonal elements of the inertia tensor") + "Inertia diagonal", "Inertia diagonal elements that specify an inertia tensor; determines the " + "torque required to rotate the rigid body on each axis.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetInertiaUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_includeAllShapesInMassCalculation, - "Include non-simulated shapes in Mass", "If set, non-simulated shapes will also be included in the center of mass, inertia and mass calculations.") + "Include non-simulated shapes in Mass", + "When active, non-simulated shapes are included in the center of mass, inertia, and mass calculations.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ; @@ -250,7 +255,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorRigidBodyConfiguration::m_centerOfMassDebugDraw, - "Debug draw COM", "Whether to debug draw the center of mass for this body") + "Debug draw COM", "Display the rigid body's center of mass (COM) in the viewport.") ; } } diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index 2bbc04faae..4ee51d7787 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -79,7 +79,7 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Shape Collider", "Creates geometry in the PhysX simulation based on an attached shape component") + "PhysX Shape Collider", "Create a PhysX collider using a shape provided by a Shape component.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg") @@ -88,13 +88,14 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/shape-collider/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_colliderConfig, - "Collider configuration", "Configuration of the collider") + "Collider configuration", "Configuration of the collider.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnConfigurationChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_colliderDebugDraw, - "Debug draw settings", "Debug draw settings") + "Debug draw settings", "Debug draw settings.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_subdivisionCount, "Subdivision count", "Number of angular subdivisions in the PhysX cylinder") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_subdivisionCount, "Subdivision count", + "Number of angular subdivisions in the PhysX cylinder.") ->Attribute(AZ::Edit::Attributes::Min, Utils::MinFrustumSubdivisions) ->Attribute(AZ::Edit::Attributes::Max, Utils::MaxFrustumSubdivisions) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSubdivisionCountChange) diff --git a/Gems/PhysX/Code/Source/ForceRegion.cpp b/Gems/PhysX/Code/Source/ForceRegion.cpp index 63426d304e..5314f97f9a 100644 --- a/Gems/PhysX/Code/Source/ForceRegion.cpp +++ b/Gems/PhysX/Code/Source/ForceRegion.cpp @@ -62,10 +62,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Force Region", "Applies forces on entities within a region") + "Force Region", "Applies forces on entities within a region.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceRegion::m_forces, "Forces", "Forces acting in the region") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceRegion::m_forces, "Forces", "Forces acting in the region.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } diff --git a/Gems/PhysX/Code/Source/ForceRegionForces.cpp b/Gems/PhysX/Code/Source/ForceRegionForces.cpp index 202a073640..6ed4c3e93a 100644 --- a/Gems/PhysX/Code/Source/ForceRegionForces.cpp +++ b/Gems/PhysX/Code/Source/ForceRegionForces.cpp @@ -37,13 +37,13 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "World Space Force", "Applies a force in world space") + "World Space Force", "Applies a force in world space.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceWorldSpace::m_direction, "Direction", "Direction of the force in world space") + ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceWorldSpace::m_direction, "Direction", "Direction of the force in world space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceWorldSpace::m_magnitude, "Magnitude", "Magnitude of the force in world space") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceWorldSpace::m_magnitude, "Magnitude", "Magnitude of the force in world space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -109,13 +109,13 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Local Space Force", "Applies a force in the volume's local space") + "Local Space Force", "Applies a force in the volume's local space.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceLocalSpace::m_direction, "Direction", "Direction of the force in local space") + ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceLocalSpace::m_direction, "Direction", "Direction of the force in local space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLocalSpace::m_magnitude, "Magnitude", "Magnitude of the force in local space") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLocalSpace::m_magnitude, "Magnitude", "Magnitude of the force in local space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -179,10 +179,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Point Force", "Applies a force relative to the center of the volume") + "Point Force", "Applies a force directed towards or away from the center of the volume.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForcePoint::m_magnitude, "Magnitude", "Magnitude of the point force") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForcePoint::m_magnitude, "Magnitude", "Magnitude of the point force.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -242,19 +242,24 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Spline Follow Force", "Applies a force to make objects follow a spline at a given speed") + "Spline Follow Force", "Applies a force to make objects follow a spline at a given speed.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_dampingRatio, "Damping Ratio", "Amount of damping applied to an entity that is moving towards a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_dampingRatio, "Damping Ratio", + "Values below 1 cause the entity to approach the spline faster but lead to overshooting and oscillation, " + "while higher values will cause it to approach more slowly but more smoothly.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDampingRatio) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_frequency, "Frequency", "Frequency at which an entity moves towards a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_frequency, "Frequency", + "Affects how quickly the entity approaches the spline.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinFrequency) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxFrequency) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_targetSpeed, "Target Speed", "Speed at which entities in the force region move along a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_targetSpeed, "Target Speed", + "Speed at which entities in the force region move along a spline.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_lookAhead, "Lookahead", "Distance at which entities look ahead in their path to reach a point on a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_lookAhead, "Lookahead", + "Distance at which entities look ahead in their path to reach a point on a spline.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -393,10 +398,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Simple Drag Force", "Simulates a drag force on entities") + "Simple Drag Force", "Simulates a drag force on entities.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSimpleDrag::m_volumeDensity, "Region Density", "Density of the region") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSimpleDrag::m_volumeDensity, "Region Density", "Density of the region.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDensity) ; @@ -463,10 +468,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Linear Damping Force", "Applies an opposite force to the entity's velocity") + "Linear Damping Force", "Applies an opposite force to the entity's velocity.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLinearDamping::m_damping, "Damping", "Amount of damping applied to an opposite force") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLinearDamping::m_damping, "Damping", "Amount of damping applied to an opposite force.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDamping) ; diff --git a/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp b/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp index 530bd03732..ae74859528 100644 --- a/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp @@ -59,22 +59,22 @@ namespace PhysX ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitY, "Swing limit Y", - "Maximum angle from the Y axis of the joint frame") + "The rotation angle limit around the joint's Y axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitZ, "Swing limit Z", - "Maximum angle from the Z axis of the joint frame") + "The rotation angle limit around the joint's Z axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitLower, "Twist lower limit", - "Lower limit for rotation about the X axis of the joint frame") + "The lower rotation angle limit around the joint's X axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, -180.0f) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitUpper, "Twist upper limit", - "Upper limit for rotation about the X axis of the joint frame") + "The upper rotation angle limit around the joint's X axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, -180.0f) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp index ed9030ac4f..6af08cfaeb 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp @@ -42,16 +42,16 @@ namespace PhysX "PhysX Character Controller Configuration", "PhysX Character Controller Configuration") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &CharacterControllerConfiguration::m_slopeBehaviour, - "Slope Behaviour", "Behaviour of the controller on surfaces above the maximum slope") + "Slope Behavior", "Behavior of the controller on surfaces that exceed the Maximum Slope Angle.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->EnumAttribute(SlopeBehaviour::PreventClimbing, "Prevent Climbing") ->EnumAttribute(SlopeBehaviour::ForceSliding, "Force Sliding") ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterControllerConfiguration::m_contactOffset, - "Contact Offset", "Extra distance outside the controller used for smoother contact resolution") + "Contact Offset", "Distance from the controller boundary where contact with surfaces can be resolved.") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterControllerConfiguration::m_scaleCoefficient, - "Scale", "Scalar coefficient used to scale the controller, usually slightly smaller than 1") + "Scale", "Scales the controller. Usually less than 1.0 to ensure visual contact between the character and surface.") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) ; diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp index 4a4f12558d..e86b81359c 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp @@ -33,7 +33,7 @@ namespace PhysX "PhysX Character Gameplay Configuration", "PhysX Character Gameplay Configuration") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterGameplayConfiguration::m_gravityMultiplier, - "Gravity Multiplier", "Multiplier to be combined with the world gravity value for applying character gravity") + "Gravity Multiplier", "Multiplier for global gravity value that applies only to this character entity.") ->Attribute(AZ::Edit::Attributes::Step, 0.1f) ; } diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp index 4e24067dbf..114f9bc2f7 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp @@ -36,18 +36,18 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "EditorCharacterControllerProxyShapeConfig", "PhysX character controller shape") + "EditorCharacterControllerProxyShapeConfig", "PhysX character controller shape.") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorCharacterControllerProxyShapeConfig::m_shapeType, "Shape", - "The shape associated with the character controller") + "The shape of the character controller.") ->EnumAttribute(Physics::ShapeType::Capsule, "Capsule") ->EnumAttribute(Physics::ShapeType::Box, "Box") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerProxyShapeConfig::m_box, "Box", - "Configuration of box shape") + "Configuration of box shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorCharacterControllerProxyShapeConfig::IsBoxConfig) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerProxyShapeConfig::m_capsule, "Capsule", - "Configuration of capsule shape") + "Configuration of capsule shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorCharacterControllerProxyShapeConfig::IsCapsuleConfig) ; } @@ -93,7 +93,8 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Character Controller", "PhysX Character Controller") + "PhysX Character Controller", + "Provides basic character interactions with the physical world, such as preventing movement through other PhysX bodies.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg") @@ -101,12 +102,12 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-controller/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerComponent::m_configuration, - "Configuration", "Configuration for the character controller") + "Configuration", "Configuration for the character controller.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCharacterControllerComponent::OnControllerConfigChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerComponent::m_proxyShapeConfiguration, - "Shape Configuration", "The configuration for the shape associated with the character controller") + "Shape Configuration", "The configuration for the shape associated with the character controller.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCharacterControllerComponent::OnShapeConfigChanged) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp index 81d158d81c..de4deb442f 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp @@ -43,7 +43,7 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Character Gameplay", "PhysX Character Gameplay") + "PhysX Character Gameplay", "An example implementation of character physics behavior such as gravity.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg") @@ -51,7 +51,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-gameplay/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterGameplayComponent::m_gameplayConfig, - "Gameplay Configuration", "Gameplay Configuration") + "Gameplay Configuration", "Gameplay Configuration.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp index 6fa3bdbffd..57972fea3e 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp @@ -82,7 +82,7 @@ namespace PhysX if (editContext) { editContext->Class( - "PhysX Ragdoll", "Provides simulation of characters in PhysX.") + "PhysX Ragdoll", "Creates a PhysX ragdoll simulation for an animation actor.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXRagdoll.svg") @@ -91,26 +91,28 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ragdoll/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_positionIterations, "Position Iteration Count", - "A higher iteration count generally improves fidelity at the cost of performance, but note that very high " - "values may lead to severe instability if ragdoll colliders interfere with satisfying joint constraints") + "The frequency at which ragdoll collider positions are resolved. Higher values can increase fidelity but decrease " + "performance. Very high values might introduce instability.") ->Attribute(AZ::Edit::Attributes::Min, 1) ->Attribute(AZ::Edit::Attributes::Max, 255) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_velocityIterations, "Velocity Iteration Count", - "A higher iteration count generally improves fidelity at the cost of performance, but note that very high " - "values may lead to severe instability if ragdoll colliders interfere with satisfying joint constraints") + "The frequency at which ragdoll collider velocities are resolved. Higher values can increase fidelity but decrease " + "performance. Very high values might introduce instability.") ->Attribute(AZ::Edit::Attributes::Min, 1) ->Attribute(AZ::Edit::Attributes::Max, 255) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_enableJointProjection, - "Enable Joint Projection", "Whether to use joint projection to preserve joint constraints " - "in demanding situations at the expense of potentially reducing physical correctness") + "Enable Joint Projection", "When active, preserves joint constraints in volatile simulations. " + "Might not be physically correct in all simulations.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_jointProjectionLinearTolerance, - "Joint Projection Linear Tolerance", "Linear joint error above which projection will be applied") + "Joint Projection Linear Tolerance", + "Maximum linear joint error. Projection is applied to linear joint errors above this value.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Step, 1e-3f) ->Attribute(AZ::Edit::Attributes::Visibility, &RagdollComponent::IsJointProjectionVisible) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_jointProjectionAngularToleranceDegrees, - "Joint Projection Angular Tolerance", "Angular joint error (in degrees) above which projection will be applied") + "Joint Projection Angular Tolerance", + "Maximum angular joint error. Projection is applied to angular joint errors above this value.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Step, 0.1f) ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") diff --git a/Gems/PhysX/Code/Source/SystemComponent.cpp b/Gems/PhysX/Code/Source/SystemComponent.cpp index f56ad43079..2f4d082ccb 100644 --- a/Gems/PhysX/Code/Source/SystemComponent.cpp +++ b/Gems/PhysX/Code/Source/SystemComponent.cpp @@ -101,7 +101,7 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("PhysX", "Global PhysX physics configuration") + editContext->Class("PhysX", "Global PhysX physics configuration.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) From 8d7b03c8592ccc219f4de0629f8bed2386ba4774 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Thu, 14 Oct 2021 08:27:43 -0700 Subject: [PATCH 254/293] Implement open in file browser for Linux (#4677) * Add support to open folder browser for Linux * PAL'ified DesktopUtilities.cpp Signed-off-by: Steve Pham --- .../Platform/Linux/platform_linux_files.cmake | 1 + .../Platform/Mac/platform_mac_files.cmake | 1 + .../Windows/platform_windows_files.cmake | 1 + .../AzQtComponents/azqtcomponents_files.cmake | 1 - .../Utilities/DesktopUtilities_Linux.cpp | 49 +++++++++++++++++++ .../Utilities/DesktopUtilities_Mac.cpp} | 23 --------- .../Utilities/DesktopUtilities_Windows.cpp | 35 +++++++++++++ 7 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/Utilities/DesktopUtilities_Linux.cpp rename Code/Framework/AzQtComponents/{AzQtComponents/Utilities/DesktopUtilities.cpp => Platform/Mac/AzQtComponents/Utilities/DesktopUtilities_Mac.cpp} (67%) create mode 100644 Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/Utilities/DesktopUtilities_Windows.cpp diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake index ec71d7b508..f292c29c3c 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Linux/platform_linux_files.cmake @@ -12,6 +12,7 @@ set(FILES ../../Utilities/QtWindowUtilities_linux.cpp ../../Utilities/ScreenGrabber_linux.cpp ../../../Platform/Linux/AzQtComponents/Components/StyledDockWidget_Linux.cpp + ../../../Platform/Linux/AzQtComponents/Utilities/DesktopUtilities_Linux.cpp ../../../Platform/Linux/AzQtComponents/AzQtComponents_Traits_Linux.h ../../../Platform/Linux/AzQtComponents/AzQtComponents_Traits_Platform.h ) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake index 18f9479289..4addf53599 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Mac/platform_mac_files.cmake @@ -12,6 +12,7 @@ set(FILES ../../Utilities/QtWindowUtilities_mac.mm ../../Utilities/ScreenGrabber_mac.mm ../../../Platform/Mac/AzQtComponents/Components/StyledDockWidget_Mac.cpp + ../../../Platform/Mac/AzQtComponents/Utilities/DesktopUtilities_Mac.cpp ../../../Platform/Mac/AzQtComponents/AzQtComponents_Traits_Mac.h ../../../Platform/Mac/AzQtComponents/AzQtComponents_Traits_Platform.h ) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake index ca4145ef35..bf0d0bb785 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/Platform/Windows/platform_windows_files.cmake @@ -9,6 +9,7 @@ set(FILES ../../natvis/qt.natvis ../../../Platform/Windows/AzQtComponents/Utilities/HandleDpiAwareness_Windows.cpp + ../../../Platform/Windows/AzQtComponents/Utilities/DesktopUtilities_Windows.cpp ../../Utilities/MouseHider_win.cpp ../../Utilities/QtWindowUtilities_win.cpp ../../Utilities/ScreenGrabber_win.cpp diff --git a/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_files.cmake b/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_files.cmake index 8219ab04b2..4c343b852c 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_files.cmake +++ b/Code/Framework/AzQtComponents/AzQtComponents/azqtcomponents_files.cmake @@ -271,7 +271,6 @@ set(FILES Utilities/ColorUtilities.h Utilities/Conversions.h Utilities/Conversions.cpp - Utilities/DesktopUtilities.cpp Utilities/DesktopUtilities.h Utilities/HandleDpiAwareness.cpp Utilities/HandleDpiAwareness.h diff --git a/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/Utilities/DesktopUtilities_Linux.cpp b/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/Utilities/DesktopUtilities_Linux.cpp new file mode 100644 index 0000000000..e4ddaceec7 --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Linux/AzQtComponents/Utilities/DesktopUtilities_Linux.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +namespace AzQtComponents +{ + void ShowFileOnDesktop(const QString& path) + { + const char* defaultNautilusPath = "/usr/bin/nautilus"; + const char* defaultXdgOpenPath = "/usr/bin/xdg-open"; + + // Determine if Nautilus (for Gnome Desktops) is available because it supports opening the file manager + // and selecting a specific file + bool nautilusAvailable = QFileInfo(defaultNautilusPath).exists(); + + QFileInfo pathInfo(path); + if (pathInfo.isDir()) + { + QProcess::startDetached(defaultXdgOpenPath, { path }); + } + else + { + if (nautilusAvailable) + { + QProcess::startDetached(defaultNautilusPath, { "--select", path }); + } + else + { + QDir parentDir { pathInfo.dir() }; + QProcess::startDetached(defaultXdgOpenPath, { parentDir.path() }); + } + } + } + + QString fileBrowserActionName() + { + const char* exploreActionName = "Open in file browser"; + return QObject::tr(exploreActionName); + } +} diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Utilities/DesktopUtilities.cpp b/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/Utilities/DesktopUtilities_Mac.cpp similarity index 67% rename from Code/Framework/AzQtComponents/AzQtComponents/Utilities/DesktopUtilities.cpp rename to Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/Utilities/DesktopUtilities_Mac.cpp index c210f17136..5920dc76c6 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Utilities/DesktopUtilities.cpp +++ b/Code/Framework/AzQtComponents/Platform/Mac/AzQtComponents/Utilities/DesktopUtilities_Mac.cpp @@ -15,21 +15,6 @@ namespace AzQtComponents { void ShowFileOnDesktop(const QString& path) { -#if defined(AZ_PLATFORM_WINDOWS) - - // Launch explorer at the path provided - QStringList args; - if (!QFileInfo(path).isDir()) - { - // Folders are just opened, files are selected - args << "/select,"; - } - args << QDir::toNativeSeparators(path); - - QProcess::startDetached("explorer", args); - -#else - if (QFileInfo(path).isDir()) { QProcess::startDetached("/usr/bin/osascript", { "-e", @@ -43,19 +28,11 @@ namespace AzQtComponents QProcess::startDetached("/usr/bin/osascript", { "-e", QStringLiteral("tell application \"Finder\" to activate") }); - -#endif } QString fileBrowserActionName() { -#ifdef AZ_PLATFORM_WINDOWS - const char* exploreActionName = "Open in Explorer"; -#elif defined(AZ_PLATFORM_MAC) const char* exploreActionName = "Open in Finder"; -#else - const char* exploreActionName = "Open in file browser"; -#endif return QObject::tr(exploreActionName); } } diff --git a/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/Utilities/DesktopUtilities_Windows.cpp b/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/Utilities/DesktopUtilities_Windows.cpp new file mode 100644 index 0000000000..796e2c0ccf --- /dev/null +++ b/Code/Framework/AzQtComponents/Platform/Windows/AzQtComponents/Utilities/DesktopUtilities_Windows.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +#include +#include + +namespace AzQtComponents +{ + void ShowFileOnDesktop(const QString& path) + { + // Launch explorer at the path provided + QStringList args; + if (!QFileInfo(path).isDir()) + { + // Folders are just opened, files are selected + args << "/select,"; + } + args << QDir::toNativeSeparators(path); + + QProcess::startDetached("explorer", args); + } + + QString fileBrowserActionName() + { + const char* exploreActionName = "Open in Explorer"; + return QObject::tr(exploreActionName); + } +} From 999ec261c9dcf060ed99555a740e7566f4701df6 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Thu, 14 Oct 2021 08:28:36 -0700 Subject: [PATCH 255/293] Update linux AP connection settings to connect to remote AP and wait for the connection (#4685) Signed-off-by: Steve Pham --- Registry/bootstrap.setreg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Registry/bootstrap.setreg b/Registry/bootstrap.setreg index 3a15d59450..b2bcdd7f3f 100644 --- a/Registry/bootstrap.setreg +++ b/Registry/bootstrap.setreg @@ -17,7 +17,7 @@ "remote_port": 45643, "connect_to_remote": 0, "windows_connect_to_remote": 1, - "linux_connect_to_remote": 0, + "linux_connect_to_remote": 1, "provo_connect_to_remote": 1, "salem_connect_to_remote": 0, "jasper_connect_to_remote": 0, @@ -29,7 +29,7 @@ "salem_wait_for_connect": 0, "jasper_wait_for_connect": 0, "windows_wait_for_connect": 1, - "linux_wait_for_connect": 0, + "linux_wait_for_connect": 1, "android_wait_for_connect": 0, "ios_wait_for_connect": 0, "mac_wait_for_connect": 0, From cff2315654a016d5c1e8a40f0fc3e55f957dd3af Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 14 Oct 2021 16:55:07 +0100 Subject: [PATCH 256/293] small correction to wording Signed-off-by: greerdv --- Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp b/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp index ee3988ded4..02e684de63 100644 --- a/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp +++ b/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp @@ -71,7 +71,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Max, s_springMax) ->Attribute(AZ::Edit::Attributes::Min, s_springMin) ->DataElement(0, &PhysX::EditorJointLimitConfig::m_stiffness, "Stiffness", - "The spring's drive relative to the position of the follower when outside the rotation limit.") + "The spring's drive relative to the position of the follower when outside the joint limit.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::IsSoftLimited) ->Attribute(AZ::Edit::Attributes::Max, s_springMax) ->Attribute(AZ::Edit::Attributes::Min, s_springMin) From 2dd00e298313b58c4ec9d4e3c023e4aa44ed5152 Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Thu, 14 Oct 2021 08:58:50 -0700 Subject: [PATCH 257/293] Move wrinkle mask data out of default object srg (#4578) * Refactored depth, shadow, and motion vector shaders to support custom object srgs. Added a new skin object srg and moved wrinklemask data out of the default object srg. Added a new minimal morph target asset for testing wrinkle masks to AutomatedTesting. Signed-off-by: Tommy Walton * Fix copyright header Signed-off-by: Tommy Walton --- .../DisplayWrinkleMaskBlendValues.material | 13 +++ .../Objects/MorphTargets/morphActor.fbx | 3 + .../Morph1_wrinklemask.tif | 3 + .../Morph2_wriklemask.tif | 3 + .../Morph3_wrinklemask.tif | 3 + .../Objects/MorphTargets/morphAnimation.fbx | 3 + .../Common/Assets/Materials/Types/Skin.azsl | 2 +- .../Assets/Materials/Types/Skin.materialtype | 6 +- .../Atom/Features/PBR/DefaultObjectSrg.azsli | 10 --- .../Atom/Features/Skin/SkinObjectSrg.azsli | 81 ++++++++++++++++++ .../Assets/Shaders/Depth/DepthPass.azsl | 27 +----- .../Shaders/Depth/DepthPassCommon.azsli | 36 ++++++++ .../Assets/Shaders/Depth/DepthPassSkin.azsl | 12 +++ .../Assets/Shaders/Depth/DepthPassSkin.shader | 24 ++++++ .../MotionVector/MeshMotionVector.azsl | 74 +---------------- .../MotionVector/MeshMotionVectorCommon.azsli | 83 +++++++++++++++++++ .../MotionVector/MeshMotionVectorSkin.azsl | 12 +++ .../MotionVector/MeshMotionVectorSkin.shader | 24 ++++++ .../Assets/Shaders/Shadow/Shadowmap.azsl | 24 +----- .../Shaders/Shadow/ShadowmapCommon.azsli | 33 ++++++++ .../Assets/Shaders/Shadow/ShadowmapSkin.azsl | 12 +++ .../Shaders/Shadow/ShadowmapSkin.shader | 26 ++++++ 22 files changed, 381 insertions(+), 133 deletions(-) create mode 100644 AutomatedTesting/Objects/MorphTargets/DisplayWrinkleMaskBlendValues.material create mode 100644 AutomatedTesting/Objects/MorphTargets/morphActor.fbx create mode 100644 AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph1_wrinklemask.tif create mode 100644 AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph2_wriklemask.tif create mode 100644 AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph3_wrinklemask.tif create mode 100644 AutomatedTesting/Objects/MorphTargets/morphAnimation.fbx create mode 100644 Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassCommon.azsli create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapCommon.azsli create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.shader diff --git a/AutomatedTesting/Objects/MorphTargets/DisplayWrinkleMaskBlendValues.material b/AutomatedTesting/Objects/MorphTargets/DisplayWrinkleMaskBlendValues.material new file mode 100644 index 0000000000..878b3ac39f --- /dev/null +++ b/AutomatedTesting/Objects/MorphTargets/DisplayWrinkleMaskBlendValues.material @@ -0,0 +1,13 @@ +{ + "description": "", + "materialType": "Materials/Types/Skin.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 3, + "properties": { + "wrinkleLayers": { + "count": 3, + "enable": true, + "showBlendValues": true + } + } +} diff --git a/AutomatedTesting/Objects/MorphTargets/morphActor.fbx b/AutomatedTesting/Objects/MorphTargets/morphActor.fbx new file mode 100644 index 0000000000..ffb75e680e --- /dev/null +++ b/AutomatedTesting/Objects/MorphTargets/morphActor.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53e17ec8155911c8b42e85436130f600bd6dddd8931a8ccb1b2f8a9f8674cc85 +size 45104 diff --git a/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph1_wrinklemask.tif b/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph1_wrinklemask.tif new file mode 100644 index 0000000000..3bc18cf450 --- /dev/null +++ b/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph1_wrinklemask.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0da56a05daa0ec1c476cfe25ca6d3b65267c98886cf33408f6e852fb325a8e2c +size 198084 diff --git a/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph2_wriklemask.tif b/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph2_wriklemask.tif new file mode 100644 index 0000000000..39e70f5acf --- /dev/null +++ b/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph2_wriklemask.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3537fbe9205731a242251c525a67bbb5f3b8f5307537f1dc0c318b5b885ce52 +size 198112 diff --git a/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph3_wrinklemask.tif b/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph3_wrinklemask.tif new file mode 100644 index 0000000000..43e19f0d5f --- /dev/null +++ b/AutomatedTesting/Objects/MorphTargets/morphActor_wrinklemasks/Morph3_wrinklemask.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd794d5dd4b749c3275bfab79b9b5ae3f8e007d3e6741c0566c9c2d3931123bf +size 198112 diff --git a/AutomatedTesting/Objects/MorphTargets/morphAnimation.fbx b/AutomatedTesting/Objects/MorphTargets/morphAnimation.fbx new file mode 100644 index 0000000000..c0dcc007dc --- /dev/null +++ b/AutomatedTesting/Objects/MorphTargets/morphAnimation.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45ded862987a64061deffd8e4c9aa1dff4eec3bcff5f7b505679f1959e8ae137 +size 51440 diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl index 05059aba6f..523353f8fa 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl @@ -9,7 +9,7 @@ #include "Skin_Common.azsli" // SRGs -#include +#include #include // Pass Output diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype index 0969cc36e8..e4da9c6022 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype @@ -973,15 +973,15 @@ "tag": "ForwardPass" }, { - "file": "Shaders/Shadow/Shadowmap.shader", + "file": "Shaders/Shadow/ShadowmapSkin.shader", "tag": "Shadowmap" }, { - "file": "Shaders/Depth/DepthPass.shader", + "file": "Shaders/Depth/DepthPassSkin.shader", "tag": "DepthPass" }, { - "file": "Shaders/MotionVector/MeshMotionVector.shader", + "file": "Shaders/MotionVector/MeshMotionVectorSkin.shader", "tag": "MeshMotionVector" } ], 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 7a2d2ee428..10526597cb 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 @@ -27,16 +27,6 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject return SceneSrg::GetObjectToWorldInverseTransposeMatrix(m_objectId); } - //[GFX TODO][ATOM-15280] Move wrinkle mask data from the default object srg into something specific to the Skin shader - uint m_wrinkle_mask_count; - float4 m_wrinkle_mask_weights[4]; - Texture2D m_wrinkle_masks[16]; - - float GetWrinkleMaskWeight(uint index) - { - return m_wrinkle_mask_weights[index / 4][index % 4]; - } - //! Reflection Probe (smallest probe volume that overlaps the object position) struct ReflectionProbeData { 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 new file mode 100644 index 0000000000..d0766c295d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli @@ -0,0 +1,81 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +ShaderResourceGroup ObjectSrg : SRG_PerObject +{ + uint m_objectId; + + //! Returns the matrix for transforming points from Object Space to World Space. + float4x4 GetWorldMatrix() + { + return SceneSrg::GetObjectToWorldMatrix(m_objectId); + } + + //! Returns the inverse-transpose of the world matrix. + //! Commonly used to transform normals while supporting non-uniform scale. + float3x3 GetWorldMatrixInverseTranspose() + { + return SceneSrg::GetObjectToWorldInverseTransposeMatrix(m_objectId); + } + + uint m_wrinkle_mask_count; + float4 m_wrinkle_mask_weights[4]; + Texture2D m_wrinkle_masks[16]; + + float GetWrinkleMaskWeight(uint index) + { + return m_wrinkle_mask_weights[index / 4][index % 4]; + } + + //! Reflection Probe (smallest probe volume that overlaps the object position) + struct ReflectionProbeData + { + row_major float3x4 m_modelToWorld; + row_major float3x4 m_modelToWorldInverse; // does not include extents + float3 m_outerObbHalfLengths; + float3 m_innerObbHalfLengths; + float m_padding; + bool m_useReflectionProbe; + bool m_useParallaxCorrection; + }; + + ReflectionProbeData m_reflectionProbeData; + TextureCube m_reflectionProbeCubeMap; + + float4x4 GetReflectionProbeWorldMatrix() + { + float4x4 modelToWorld = float4x4( + float4(1, 0, 0, 0), + float4(0, 1, 0, 0), + float4(0, 0, 1, 0), + float4(0, 0, 0, 1)); + + modelToWorld[0] = m_reflectionProbeData.m_modelToWorld[0]; + modelToWorld[1] = m_reflectionProbeData.m_modelToWorld[1]; + modelToWorld[2] = m_reflectionProbeData.m_modelToWorld[2]; + return modelToWorld; + } + + float4x4 GetReflectionProbeWorldMatrixInverse() + { + float4x4 modelToWorldInverse = float4x4( + float4(1, 0, 0, 0), + float4(0, 1, 0, 0), + float4(0, 0, 1, 0), + float4(0, 0, 0, 1)); + + modelToWorldInverse[0] = m_reflectionProbeData.m_modelToWorldInverse[0]; + modelToWorldInverse[1] = m_reflectionProbeData.m_modelToWorldInverse[1]; + modelToWorldInverse[2] = m_reflectionProbeData.m_modelToWorldInverse[2]; + return modelToWorldInverse; + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPass.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPass.azsl index 8eb657f8f5..876f4b1a61 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPass.azsl @@ -6,30 +6,7 @@ * */ -#include #include +#include -struct VSInput -{ - float3 m_position : POSITION; -}; - -struct VSDepthOutput -{ - float4 m_position : SV_Position; -}; - -VSDepthOutput DepthPassVS(VSInput IN) -{ - VSDepthOutput OUT; - - float4x4 objectToWorld = ObjectSrg::GetWorldMatrix(); - float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)); - OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition); - - return OUT; -} - - - - +// Use the depth pass shader with the default object srg diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassCommon.azsli new file mode 100644 index 0000000000..f658dd13da --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassCommon.azsli @@ -0,0 +1,36 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +struct VSInput +{ + float3 m_position : POSITION; +}; + +struct VSDepthOutput +{ + float4 m_position : SV_Position; +}; + +VSDepthOutput DepthPassVS(VSInput IN) +{ + VSDepthOutput OUT; + + float4x4 objectToWorld = ObjectSrg::GetWorldMatrix(); + float4 worldPosition = mul(objectToWorld, float4(IN.m_position, 1.0)); + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, worldPosition); + + return OUT; +} + + + + diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.azsl new file mode 100644 index 0000000000..0947be6cf8 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.azsl @@ -0,0 +1,12 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +// Use the depth pass shader with the skin object srg diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.shader b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.shader new file mode 100644 index 0000000000..de6c989223 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Depth/DepthPassSkin.shader @@ -0,0 +1,24 @@ +{ + "Source" : "DepthPassSkin", + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "CompilerHints" : { + "DisableOptimizations" : false + }, + + "ProgramSettings" : + { + "EntryPoints": + [ + { + "name": "DepthPassVS", + "type" : "Vertex" + } + ] + }, + + "DrawList" : "depth" +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.azsl index 11cf20dcaf..a14d07194f 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.azsl @@ -6,77 +6,7 @@ * */ -#include -#include - #include -#include - -struct VSInput -{ - float3 m_position : POSITION; - - // This gets set automatically by the system at runtime only if it's available. - // There is a soft naming convention that associates this with o_prevPosition_isBound, which will be set to true whenever m_optional_prevPosition is available. - // (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). - // [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. - // Vertex position of last frame to capture small scale motion due to vertex animation - float3 m_optional_prevPosition : POSITIONT; -}; - -struct VSOutput -{ - float4 m_position : SV_Position; - float3 m_worldPos : TEXCOORD0; - float3 m_worldPosPrev: TEXCOORD1; -}; - -struct PSOutput -{ - float2 m_motion : SV_Target0; -}; - -// Indicates whether the vertex input struct's "m_optional_prevPosition" is bound. If false, it is not safe to read from m_optional_prevPosition. -// This option gets set automatically by the system at runtime; there is a soft naming convention that associates it with m_optional_prevPosition. -// (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). -// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. -option bool o_prevPosition_isBound; - -VSOutput MainVS(VSInput IN) -{ - VSOutput OUT; - - OUT.m_worldPos = mul(SceneSrg::GetObjectToWorldMatrix(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz; - OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPos, 1.0)); - - if (o_prevPosition_isBound) - { - OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_optional_prevPosition, 1.0)).xyz; - } - else - { - OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz; - } - - return OUT; -} - -PSOutput MainPS(VSOutput IN) -{ - PSOutput OUT; - - // Current clip position - float4 clipPos = mul(ViewSrg::m_viewProjectionMatrix, float4(IN.m_worldPos, 1.0)); - - // Reprojected last frame's clip position, for skinned mesh it also implies last key frame - float4 clipPosPrev = mul(ViewSrg::m_viewProjectionPrevMatrix, float4(IN.m_worldPosPrev, 1.0)); - - float2 motion = (clipPos.xy / clipPos.w - clipPosPrev.xy / clipPosPrev.w) * 0.5; +#include - OUT.m_motion = motion; - - // Flip y to line up with uv coordinates - OUT.m_motion.y = -OUT.m_motion.y; - - return OUT; -} +// Use the mesh motion vector with the default object srg diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli new file mode 100644 index 0000000000..c934b056db --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli @@ -0,0 +1,83 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include + +struct VSInput +{ + float3 m_position : POSITION; + + // This gets set automatically by the system at runtime only if it's available. + // There is a soft naming convention that associates this with o_prevPosition_isBound, which will be set to true whenever m_optional_prevPosition is available. + // (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). + // [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. + // Vertex position of last frame to capture small scale motion due to vertex animation + float3 m_optional_prevPosition : POSITIONT; +}; + +struct VSOutput +{ + float4 m_position : SV_Position; + float3 m_worldPos : TEXCOORD0; + float3 m_worldPosPrev: TEXCOORD1; +}; + +struct PSOutput +{ + float2 m_motion : SV_Target0; +}; + +// Indicates whether the vertex input struct's "m_optional_prevPosition" is bound. If false, it is not safe to read from m_optional_prevPosition. +// This option gets set automatically by the system at runtime; there is a soft naming convention that associates it with m_optional_prevPosition. +// (search "m_optional_" in ShaderVariantAssetBuilder for details on the naming convention). +// [GFX TODO][ATOM-14475]: Come up with a more elegant way to associate the isBound flag with the input stream. +option bool o_prevPosition_isBound; + +VSOutput MainVS(VSInput IN) +{ + VSOutput OUT; + + OUT.m_worldPos = mul(SceneSrg::GetObjectToWorldMatrix(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz; + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPos, 1.0)); + + if (o_prevPosition_isBound) + { + OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_optional_prevPosition, 1.0)).xyz; + } + else + { + OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz; + } + + return OUT; +} + +PSOutput MainPS(VSOutput IN) +{ + PSOutput OUT; + + // Current clip position + float4 clipPos = mul(ViewSrg::m_viewProjectionMatrix, float4(IN.m_worldPos, 1.0)); + + // Reprojected last frame's clip position, for skinned mesh it also implies last key frame + float4 clipPosPrev = mul(ViewSrg::m_viewProjectionPrevMatrix, float4(IN.m_worldPosPrev, 1.0)); + + float2 motion = (clipPos.xy / clipPos.w - clipPosPrev.xy / clipPosPrev.w) * 0.5; + + OUT.m_motion = motion; + + // Flip y to line up with uv coordinates + OUT.m_motion.y = -OUT.m_motion.y; + + return OUT; +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.azsl new file mode 100644 index 0000000000..fc089ac7a3 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.azsl @@ -0,0 +1,12 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +// Use the mesh motion vector with the skin object srg diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.shader b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.shader new file mode 100644 index 0000000000..9a50e4e2cf --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorSkin.shader @@ -0,0 +1,24 @@ +{ + "Source" : "MeshMotionVectorSkin", + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "DrawList" : "motion", + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/Shadowmap.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/Shadowmap.azsl index 713ff7c393..7a958a73ca 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/Shadowmap.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/Shadowmap.azsl @@ -6,27 +6,7 @@ * */ -#include -#include #include +#include -struct VertexInput -{ - float3 m_position : POSITION; -}; - -struct VertexOutput -{ - float4 m_position : SV_Position; -}; - -VertexOutput MainVS(VertexInput input) -{ - const float4x4 worldMatrix = ObjectSrg::GetWorldMatrix(); - VertexOutput output; - - const float3 worldPosition = mul(worldMatrix, float4(input.m_position, 1.0)).xyz; - output.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0)); - - return output; -} +// Use the shadowmap shader with the default object srg diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapCommon.azsli new file mode 100644 index 0000000000..213fb18dc4 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapCommon.azsli @@ -0,0 +1,33 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +struct VertexInput +{ + float3 m_position : POSITION; +}; + +struct VertexOutput +{ + float4 m_position : SV_Position; +}; + +VertexOutput MainVS(VertexInput input) +{ + const float4x4 worldMatrix = ObjectSrg::GetWorldMatrix(); + VertexOutput output; + + const float3 worldPosition = mul(worldMatrix, float4(input.m_position, 1.0)).xyz; + output.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0)); + + return output; +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.azsl new file mode 100644 index 0000000000..6f0d8e1a31 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.azsl @@ -0,0 +1,12 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +// Use the shadowmap shader with the skin object srg diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.shader b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.shader new file mode 100644 index 0000000000..14c1352c08 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/ShadowmapSkin.shader @@ -0,0 +1,26 @@ +{ + "Source" : "ShadowmapSkin", + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "LessEqual" } + }, + + "DrawList" : "shadow", + + "RasterState" : + { + "depthBias" : "10", + "depthBiasSlopeScale" : "4" + }, + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + } + ] + } +} From 1fc69aa9c51dfc25ee26abac90c3202ea35b1e14 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 14 Oct 2021 11:15:21 -0500 Subject: [PATCH 258/293] Set EDITOR_TEST_SUPPORTED to false for Android/iOS in the template. Signed-off-by: Chris Galvan --- .../CustomTool/Template/Code/Platform/Android/PAL_android.cmake | 2 +- Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake b/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake index 49dfe71f53..90d1caccf4 100644 --- a/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake +++ b/Templates/CustomTool/Template/Code/Platform/Android/PAL_android.cmake @@ -8,4 +8,4 @@ set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) -set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED FALSE) diff --git a/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake b/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake index 0abcd887e8..332f4469b6 100644 --- a/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake +++ b/Templates/CustomTool/Template/Code/Platform/iOS/PAL_ios.cmake @@ -8,4 +8,4 @@ set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) -set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED FALSE) \ No newline at end of file From 63ece6e3ca035087b9ee7e31151aefefef0f975c Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu, 14 Oct 2021 11:54:13 -0500 Subject: [PATCH 259/293] Change Asset Hint fixup code to not request assets be queued for load. (#4664) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp index ea0fa55256..a84d6bf706 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp @@ -262,7 +262,7 @@ namespace AzToolsFramework if (assetId.IsValid()) { - asset.Create(assetId, true); + asset.Create(assetId, false); } } }; From c7e690706404ce745cf3fce9c6d92d82d5b905db Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 14 Oct 2021 13:03:19 -0500 Subject: [PATCH 260/293] Flipped y value on uv so that the macro material lines up with the corresponding height data. (#4701) Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index d7300cdc48..8c85e21490 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -567,13 +567,15 @@ namespace Terrain ShaderMacroMaterialData& shaderData = macroMaterialData.at(i); const AZ::Aabb& materialBounds = materialData.m_bounds; + // Use reverse coordinates (1 - y) for the y direction so that the lower left corner of the macro material images + // map to the lower left corner in world space. This will match up with the height uv coordinate mapping. shaderData.m_uvMin = { (xPatch - materialBounds.GetMin().GetX()) / materialBounds.GetXExtent(), - (yPatch - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent() + 1.0f - ((yPatch - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent()) }; shaderData.m_uvMax = { ((xPatch + GridMeters) - materialBounds.GetMin().GetX()) / materialBounds.GetXExtent(), - ((yPatch + GridMeters) - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent() + 1.0f - (((yPatch + GridMeters) - materialBounds.GetMin().GetY()) / materialBounds.GetYExtent()) }; shaderData.m_normalFactor = materialData.m_normalFactor; shaderData.m_flipNormalX = materialData.m_normalFlipX; From 88cc3c774a731ebc3aae7a5cd3f2777d56bf40cf Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 12:32:15 -0700 Subject: [PATCH 261/293] adds stack trace conversion from native Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../AzCore/AzCore/Debug/StackTracer.h | 6 ++ Code/Framework/AzCore/AzCore/Debug/Trace.cpp | 10 ++- .../Debug/StackTracer_Unimplemented.cpp | 5 ++ .../AzCore/Debug/StackTracer_UnixLike.cpp | 6 ++ .../AzCore/Debug/StackTracer_Windows.cpp | 75 ++++++++++++++++--- 5 files changed, 89 insertions(+), 13 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/StackTracer.h b/Code/Framework/AzCore/AzCore/Debug/StackTracer.h index 430fd69168..2d09c16e99 100644 --- a/Code/Framework/AzCore/AzCore/Debug/StackTracer.h +++ b/Code/Framework/AzCore/AzCore/Debug/StackTracer.h @@ -40,6 +40,12 @@ namespace AZ static unsigned int Record(StackFrame* frames, unsigned int maxNumOfFrames, unsigned int suppressCount = 0, void* nativeThread = 0); }; + class StackConverter + { + public: + static unsigned int FromNative(StackFrame* frames, unsigned int maxNumOfFrames, void* nativeContext); + }; + class SymbolStorage { public: diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp index 3edcbaa273..38e31393f5 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp @@ -31,6 +31,8 @@ namespace AZ { namespace Debug { + struct StackFrame; + namespace Platform { #if defined(AZ_ENABLE_DEBUG_TOOLS) @@ -556,12 +558,18 @@ namespace AZ //size_t bla = AZStd::alignment_of::value; //printf("Alignment value %d address 0x%08x : 0x%08x\n",bla,frames); SymbolStorage::StackLine lines[AZ_ARRAY_SIZE(frames)]; + unsigned int numFrames = 0; if (!nativeContext) { suppressCount += 1; /// If we don't provide a context we will capture in the RecordFunction, so skip us (Trace::PrinCallstack). + numFrames = StackRecorder::Record(frames, AZ_ARRAY_SIZE(frames), suppressCount); } - unsigned int numFrames = StackRecorder::Record(frames, AZ_ARRAY_SIZE(frames), suppressCount, nativeContext); + else + { + numFrames = StackConverter::FromNative(frames, AZ_ARRAY_SIZE(frames), nativeContext); + } + if (numFrames) { SymbolStorage::DecodeFrames(frames, numFrames, lines); diff --git a/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp index 0c091a7242..a751eb505c 100644 --- a/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp +++ b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp @@ -17,6 +17,11 @@ namespace AZ return false; } + unsigned int StackConverter::FromNative(StackFrame*, unsigned int, void*) + { + return 0; + } + void SymbolStorage::LoadModuleData(const void*, unsigned int) {} diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp index f66a9d3b18..1948bbf2fe 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp @@ -78,6 +78,12 @@ StackRecorder::Record(StackFrame* frames, unsigned int maxNumOfFrames, unsigned return count; } +unsigned int StackConverter::FromNative([[maybe_unused]] StackFrame* frames, [[maybe_unused]] unsigned int maxNumOfFrames, [[maybe_unused]] void* nativeContext) +{ + AZ_Assert(false, "StackConverter::FromNative() is not supported for UnixLike platform yet"); + return 0; +} + void SymbolStorage::DecodeFrames(const StackFrame* frames, unsigned int numFrames, StackLine* textLines) { diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp index b2a1410bf5..b4ccb07296 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp @@ -1048,9 +1048,9 @@ cleanup: unsigned int StackRecorder::Record(StackFrame* frames, unsigned int maxNumOfFrames, unsigned int suppressCount, void* nativeThread) { -#if defined(AZ_ENABLE_DEBUG_TOOLS) unsigned int numFrames = 0; +#if defined(AZ_ENABLE_DEBUG_TOOLS) if (nativeThread == NULL) { ++suppressCount; // Skip current call @@ -1079,9 +1079,8 @@ cleanup: STACKFRAME64 sf; memset(&sf, 0, sizeof(STACKFRAME64)); - DWORD imageType; + DWORD imageType = IMAGE_FILE_MACHINE_AMD64; - imageType = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = context.Rip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.Rsp; @@ -1090,8 +1089,7 @@ cleanup: sf.AddrStack.Mode = AddrModeFlat; EnterCriticalSection(&g_csDbgHelpDll); - s32 frame = -(s32)suppressCount; - for (; frame < (s32)maxNumOfFrames; ++frame) + for (s32 frame = -static_cast(suppressCount); frame < static_cast(maxNumOfFrames); ++frame) { if (!g_StackWalk64(imageType, g_currentProcess, hThread, &sf, &context, 0, g_SymFunctionTableAccess64, g_SymGetModuleBase64, 0)) { @@ -1111,15 +1109,68 @@ cleanup: } LeaveCriticalSection(&g_csDbgHelpDll); - } - return numFrames; + } #else - (void)frames; - (void)maxNumOfFrames; - (void)suppressCount; - (void)nativeThread; - return 0; + AZ_UNUSED(frames); + AZ_UNUSED(maxNumOfFrames); + AZ_UNUSED(suppressCount); + AZ_UNUSED(nativeThread); #endif // AZ_ENABLE_DEBUG_TOOLS + + return numFrames; + } + + unsigned int StackConverter::FromNative(StackFrame* frames, unsigned int maxNumOfFrames, void* nativeContext) + { + unsigned int numFrames = 0; + +#if defined(AZ_ENABLE_DEBUG_TOOLS) + if (!g_dbgHelpLoaded) + { + LoadDbgHelp(); + } + + HANDLE hThread; + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS); + + PCONTEXT nativeContextType = reinterpret_cast(nativeContext); + STACKFRAME64 sf; + memset(&sf, 0, sizeof(STACKFRAME64)); + + DWORD imageType = IMAGE_FILE_MACHINE_AMD64; + + sf.AddrPC.Offset = nativeContextType->Rip; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrFrame.Offset = nativeContextType->Rsp; + sf.AddrFrame.Mode = AddrModeFlat; + sf.AddrStack.Offset = nativeContextType->Rsp; + sf.AddrStack.Mode = AddrModeFlat; + + EnterCriticalSection(&g_csDbgHelpDll); + for (unsigned int frame = 0; frame < maxNumOfFrames; ++frame) + { + if (!g_StackWalk64(imageType, g_currentProcess, hThread, &sf, nativeContext, 0, g_SymFunctionTableAccess64, g_SymGetModuleBase64, 0)) + { + break; + } + + if (sf.AddrPC.Offset == sf.AddrReturn.Offset) + { + // "StackWalk64-Endless-Callstack!" + break; + } + + frames[numFrames++].m_programCounter = sf.AddrPC.Offset; + } + + LeaveCriticalSection(&g_csDbgHelpDll); +#else + AZ_UNUSED(frame); + AZ_UNUSED(maxNumOfFrames); + AZ_UNUSED(nativeContext); +#endif + + return numFrames; } ////////////////////////////////////////////////////////////////////////// From 3e729638b51368dce474e2d68d1b3aad3d573fe3 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 12:32:39 -0700 Subject: [PATCH 262/293] adds unhandled exception test Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Tests/Debug/UnhandledExceptions.cpp | 31 +++++++++++++++++++ .../AzCore/Tests/azcoretests_files.cmake | 1 + 2 files changed, 32 insertions(+) create mode 100644 Code/Framework/AzCore/Tests/Debug/UnhandledExceptions.cpp diff --git a/Code/Framework/AzCore/Tests/Debug/UnhandledExceptions.cpp b/Code/Framework/AzCore/Tests/Debug/UnhandledExceptions.cpp new file mode 100644 index 0000000000..cd9055085f --- /dev/null +++ b/Code/Framework/AzCore/Tests/Debug/UnhandledExceptions.cpp @@ -0,0 +1,31 @@ +/* + * 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 + +namespace UnitTest +{ + class UnhandledExceptions + : public ScopedAllocatorSetupFixture + { + + public: + void causeAccessViolation() + { + int* someVariable = reinterpret_cast(0); + *someVariable = 0; + } + }; + +#if GTEST_HAS_DEATH_TEST + TEST_F(UnhandledExceptions, Handle) + { + EXPECT_DEATH(causeAccessViolation(), ""); + } +#endif +} diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index 6ba9944f7d..cc6000209f 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -72,6 +72,7 @@ set(FILES Debug/AssetTracking.cpp Debug/LocalFileEventLoggerTests.cpp Debug/Trace.cpp + Debug/UnhandledExceptions.cpp Name/NameJsonSerializerTests.cpp Name/NameTests.cpp RTTI/TypeSafeIntegralTests.cpp From e078580f2cce3d00fee44cf74932c2e157948916 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 12:33:18 -0700 Subject: [PATCH 263/293] Changes GTEST_OS_SUPPORTS_DEATH_TEST to the right define which is GTEST_HAS_DEATH_TEST Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/Tests/AZStd/Hashed.cpp | 8 ++++---- Code/Framework/AzCore/Tests/AZStd/Ordered.cpp | 8 ++++---- Code/Framework/AzCore/Tests/AZStd/Parallel.cpp | 4 ++-- Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp | 5 ++--- .../Serialization/Json/JsonRegistrationContextTests.cpp | 5 +++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp b/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp index b92dee44b6..c982868c4f 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp @@ -1413,7 +1413,7 @@ namespace UnitTest >; TYPED_TEST_CASE(HashedSetDifferentAllocatorFixture, SetTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(HashedSetDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1435,7 +1435,7 @@ namespace UnitTest } }, ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST template class HashedMapContainers @@ -1811,7 +1811,7 @@ namespace UnitTest >; TYPED_TEST_CASE(HashedMapDifferentAllocatorFixture, MapTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(HashedMapDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1833,7 +1833,7 @@ namespace UnitTest } } , ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST namespace HashedContainerTransparentTestInternal { diff --git a/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp b/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp index ca7d5cba42..26838eeb63 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp @@ -1095,7 +1095,7 @@ namespace UnitTest >; TYPED_TEST_CASE(TreeSetDifferentAllocatorFixture, SetTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(TreeSetDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1117,7 +1117,7 @@ namespace UnitTest } }, ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST TYPED_TEST(TreeSetDifferentAllocatorFixture, SwapMovesElementsWhenAllocatorsDiffer) { @@ -1516,7 +1516,7 @@ namespace UnitTest >; TYPED_TEST_CASE(TreeMapDifferentAllocatorFixture, MapTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(TreeMapDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1538,7 +1538,7 @@ namespace UnitTest } }, ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST TYPED_TEST(TreeMapDifferentAllocatorFixture, SwapMovesElementsWhenAllocatorsDiffer) { diff --git a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp index 407cd3c258..6b9202133c 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp @@ -1595,7 +1595,7 @@ namespace UnitTest } }; -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TEST_F(ThreadEventsDeathTest, UsingClientBus_AvoidsDeadlock) { EXPECT_EXIT( @@ -1608,5 +1608,5 @@ namespace UnitTest , ::testing::ExitedWithCode(0),".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST } diff --git a/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp b/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp index b4f129bb48..09255ce16f 100644 --- a/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp +++ b/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp @@ -144,14 +144,13 @@ namespace UnitTest } }; -#if GTEST_OS_SUPPORTS_DEATH_TEST - // SPEC-2669: Disabled since it is causing hangs on Linux +#if GTEST_HAS_DEATH_TEST TEST_F(AllocatorsTestFixtureLeakDetectionDeathTest_SKIPCODECOVERAGE, AllocatorLeak) { // testing that the TraceBusHook will fail on cause the test to die EXPECT_DEATH(TestAllocatorLeak(), ""); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Testing ScopedAllocatorSetupFixture. Testing that detects leaks diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp index cc4d31eca9..9d4af1def5 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp @@ -327,7 +327,7 @@ namespace JsonSerializationTests SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get()); } -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST using JsonSerializationDeathTests = JsonRegistrationContextTests; TEST_F(JsonSerializationDeathTests, DoubleUnregisterSerializer_Asserts) { @@ -338,5 +338,6 @@ namespace JsonSerializationTests }, ".*" ); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST + } //namespace JsonSerializationTests From 04a6744765494eecf2a6941e4b9518769dd0c566 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 12:33:53 -0700 Subject: [PATCH 264/293] enables our exception handling and disables gtest's Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzTest/AzTest/AzTest.cpp | 8 ++++++-- Code/Tools/AzTestRunner/src/main.cpp | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzTest/AzTest/AzTest.cpp b/Code/Framework/AzTest/AzTest/AzTest.cpp index 3b809d2c96..baf80d8f83 100644 --- a/Code/Framework/AzTest/AzTest/AzTest.cpp +++ b/Code/Framework/AzTest/AzTest/AzTest.cpp @@ -99,10 +99,14 @@ namespace AZ void ApplyGlobalParameters(int* argc, char** argv) { - // this is a hook that can be used to apply any other global non-google parameters - // that we use. + // this is a hook that can be used to apply any other global parameters that we use. AZ_UNUSED(argc); AZ_UNUSED(argv); + + // Disable gtest catching unhandled exceptions, instead, AzTestRunner will do it through: + // AZ::Debug::Trace::HandleExceptions(true). This gives us a stack trace when the exception + // is thrown (googletest does not). + testing::FLAGS_gtest_catch_exceptions = false; } //! Print out parameters that are not used by the framework diff --git a/Code/Tools/AzTestRunner/src/main.cpp b/Code/Tools/AzTestRunner/src/main.cpp index 0874efeff2..cdd1c97d04 100644 --- a/Code/Tools/AzTestRunner/src/main.cpp +++ b/Code/Tools/AzTestRunner/src/main.cpp @@ -258,6 +258,8 @@ namespace AzTestRunner int wrapped_main(int argc/*=0*/, char** argv/*=nullptr*/) { + AZ::Debug::Trace::HandleExceptions(true); + if (argc>0 && argv!=nullptr) { return wrapped_command_arg_main(argc, argv); From 16a7b896ee27a4a2814361ef9b1e3d0e7fb6572c Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Thu, 14 Oct 2021 12:58:53 -0700 Subject: [PATCH 265/293] Fix to prevent using legacy windows based logic to create a Path on Linx (#4704) Signed-off-by: Steve Pham --- Code/Editor/Util/FileUtil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp index eeb6912acf..baca69d628 100644 --- a/Code/Editor/Util/FileUtil.cpp +++ b/Code/Editor/Util/FileUtil.cpp @@ -1195,7 +1195,7 @@ bool CFileUtil::IsFileExclusivelyAccessable(const QString& strFilePath) ////////////////////////////////////////////////////////////////////////// bool CFileUtil::CreatePath(const QString& strPath) { -#if defined(AZ_PLATFORM_MAC) +#if !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS bool pathCreated = true; QString cleanPath = QDir::cleanPath(strPath); @@ -1252,7 +1252,7 @@ bool CFileUtil::CreatePath(const QString& strPath) } return true; -#endif +#endif // !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS } ////////////////////////////////////////////////////////////////////////// From a6c506c12181d2cf2e0f3e89f94ae8df0d0e4218 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 13:02:29 -0700 Subject: [PATCH 266/293] some warning fixes Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Tests/Spawnable/SpawnableEntitiesManagerTests.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 407ab1d21f..8693198eb9 100644 --- a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -569,8 +569,11 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { AZ_UNUSED(refScheme); AZ_UNUSED(NumEntities); @@ -591,8 +594,11 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { AZ_UNUSED(refScheme); AZ_UNUSED(NumEntities); @@ -720,8 +726,11 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { AZ_UNUSED(refScheme); AZ_UNUSED(NumEntities); From 3df2ca341f573c23f7b63193cb45e3775b88ab8f Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 13:28:26 -0700 Subject: [PATCH 267/293] function was converted to return a bool but this code was not updated Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp b/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp index 878ede5e68..a11f2c9905 100644 --- a/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp +++ b/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp @@ -48,10 +48,10 @@ namespace WhiteBox float time; AZ::Vector3 normal; const float rayLength = 1000.0f; - const int intersected = AZ::Intersect::IntersectSegmentTriangleCCW( + const bool intersected = AZ::Intersect::IntersectSegmentTriangleCCW( rayOrigin, rayOrigin + rayDirection * rayLength, p0, p1, p2, normal, time); - if (intersected != 0) + if (intersected) { rayIntersectionDistance = time * rayLength; intersectedTriangleIndex = triangleIndex / 3; From c5da705b469edeac655010d46a5bbc1101616aba Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 14:39:18 -0700 Subject: [PATCH 268/293] fixes typo Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp index b4ccb07296..90362a3ce8 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp @@ -1165,7 +1165,7 @@ cleanup: LeaveCriticalSection(&g_csDbgHelpDll); #else - AZ_UNUSED(frame); + AZ_UNUSED(frames); AZ_UNUSED(maxNumOfFrames); AZ_UNUSED(nativeContext); #endif From c510ef105093d641eb0a77c7c321308cbb6f1219 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Thu, 14 Oct 2021 16:44:14 -0500 Subject: [PATCH 269/293] Palify RenderDoc cmake include directories Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake | 3 --- Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake b/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake index 4fc54b9733..b95a246afe 100644 --- a/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake +++ b/Gems/Atom/RHI/3rdParty/Findrenderdoc.cmake @@ -10,8 +10,5 @@ ly_add_external_target( NAME renderdoc 3RDPARTY_ROOT_DIRECTORY "${LY_RENDERDOC_PATH}" VERSION - INCLUDE_DIRECTORIES - . - include COMPILE_DEFINITIONS USE_RENDERDOC ) diff --git a/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake b/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake index 6225cc292a..5e88fcec2f 100644 --- a/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake +++ b/Gems/Atom/RHI/3rdParty/Platform/Linux/renderdoc_linux.cmake @@ -7,3 +7,4 @@ # set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/lib/librenderdoc.so") +set(RENDERDOC_INCLUDE_DIRECTORIES "include") From b7c478b85efa13f9e7e0c325e11bf2360e770278 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 14 Oct 2021 15:02:16 -0700 Subject: [PATCH 270/293] fix for empty expression primitive type serialization Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../ExpressionPrimitivesSerializers.inl | 84 ++++++++++++------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl b/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl index be9ddb4f20..800257e157 100644 --- a/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl +++ b/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl @@ -28,6 +28,19 @@ namespace AZ private: using VariableDescriptor = ExpressionEvaluation::ExpressionTree::VariableDescriptor; + static constexpr AZStd::string_view EmptyAnyIdentifier = "Empty AZStd::any"; + + static bool IsEmptyAny(const rapidjson::Value& typeId) + { + if (typeId.IsString()) + { + AZStd::string_view typeName(typeId.GetString(), typeId.GetStringLength()); + return typeName == EmptyAnyIdentifier; + } + + return false; + } + JsonSerializationResult::Result Load ( void* outputValue , [[maybe_unused]] const Uuid& outputValueTypeId @@ -62,22 +75,25 @@ namespace AZ , JsonSerialization::TypeIdFieldIdentifier)); } - result.Combine(LoadTypeId(typeId, typeIdMember->value, context)); - if (typeId.IsNull()) - { - return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic - , "ExpressionTreeVariableDescriptorSerializer::Load failed to load the AZ TypeId of the value"); - } - - AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId); - if (storage.empty() || storage.type() != typeId) + if (!IsEmptyAny(typeIdMember->value)) { - return context.Report(result, "ExpressionTreeVariableDescriptorSerializer::Load failed to load a value matched the " - "reported AZ TypeId. The C++ declaration may have been deleted or changed."); + result.Combine(LoadTypeId(typeId, typeIdMember->value, context)); + if (typeId.IsNull()) + { + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic + , "ExpressionTreeVariableDescriptorSerializer::Load failed to load the AZ TypeId of the value"); + } + + AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId); + if (storage.empty() || storage.type() != typeId) + { + return context.Report(result, "ExpressionTreeVariableDescriptorSerializer::Load failed to load a value matched the " + "reported AZ TypeId. The C++ declaration may have been deleted or changed."); + } + + result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast(&storage), typeId, inputValue, "Value", context)); + outputDatum->m_value = storage; } - - result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast(&storage), typeId, inputValue, "Value", context)); - outputDatum->m_value = storage; // any storage end return context.Report(result, result.GetProcessing() != JSR::Processing::Halted @@ -123,20 +139,32 @@ namespace AZ , azrtti_typeidm_supportedTypes)>() , context)); - rapidjson::Value typeValue; - result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_value.type(), context)); - outputValue.AddMember - ( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier) - , AZStd::move(typeValue) - , context.GetJsonAllocator()); - - result.Combine(ContinueStoringToJsonObjectField - ( outputValue - , "Value" - , AZStd::any_cast(const_cast(&inputScriptDataPtr->m_value)) - , defaultScriptDataPtr ? AZStd::any_cast(const_cast(&defaultScriptDataPtr->m_value)) : nullptr - , inputScriptDataPtr->m_value.type() - , context)); + if (!inputScriptDataPtr->m_value.empty()) + { + rapidjson::Value typeValue; + result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_value.type(), context)); + outputValue.AddMember + ( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier) + , AZStd::move(typeValue) + , context.GetJsonAllocator()); + + result.Combine(ContinueStoringToJsonObjectField + ( outputValue + , "Value" + , AZStd::any_cast(const_cast(&inputScriptDataPtr->m_value)) + , defaultScriptDataPtr ? AZStd::any_cast(const_cast(&defaultScriptDataPtr->m_value)) : nullptr + , inputScriptDataPtr->m_value.type() + , context)); + } + else + { + rapidjson::Value emptyAny; + emptyAny.SetString(EmptyAnyIdentifier.data(), aznumeric_caster(EmptyAnyIdentifier.size()), context.GetJsonAllocator()); + outputValue.AddMember + ( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier) + , AZStd::move(emptyAny) + , context.GetJsonAllocator()); + } return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ? "VariableDescriptor Store finished saving VariableDescriptor" From bcf3980de6295a1cb522f20e8482c3222625542c Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Thu, 14 Oct 2021 15:32:34 -0700 Subject: [PATCH 271/293] LYN-7191 + LYN-7194 | Adjust Prefab operations to conform with Prefab Focus/Edit workflows. (#4684) * Disable ability to delete container entity of focused prefab. Default entity creation to parent to container entity of focused prefab. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Disable detach and duplicate operations for the container of the focused prefab. Update the context menu accordingly. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix spacing Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Address minor issues from PR (error message, optimization in RetrieveAndSortPrefabEntitiesAndInstances). Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabPublicHandler.cpp | 76 +++++++++++++------ .../Prefab/PrefabPublicHandler.h | 4 +- .../UI/Prefab/PrefabIntegrationManager.cpp | 56 +++++++++----- .../UI/Prefab/PrefabUiHandler.cpp | 6 -- 4 files changed, 91 insertions(+), 51 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index b5f61b33bf..081655a166 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -43,6 +43,12 @@ namespace AzToolsFramework m_instanceToTemplateInterface = AZ::Interface::Get(); AZ_Assert(m_instanceToTemplateInterface, "PrefabPublicHandler - Could not retrieve instance of InstanceToTemplateInterface"); + m_prefabFocusInterface = AZ::Interface::Get(); + AZ_Assert(m_prefabFocusInterface, "Could not get PrefabFocusInterface on PrefabPublicHandler construction."); + + m_prefabFocusPublicInterface = AZ::Interface::Get(); + AZ_Assert(m_prefabFocusPublicInterface, "Could not get PrefabFocusPublicInterface on PrefabPublicHandler construction."); + m_prefabLoaderInterface = AZ::Interface::Get(); AZ_Assert(m_prefabLoaderInterface, "Could not get PrefabLoaderInterface on PrefabPublicHandler construction."); @@ -552,6 +558,13 @@ namespace AzToolsFramework PrefabEntityResult PrefabPublicHandler::CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position) { + // If the parent is invalid, parent to the container of the currently focused prefab. + if (!parentId.IsValid()) + { + AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId(); + parentId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); + } + InstanceOptionalReference owningInstanceOfParentEntity = GetOwnerInstanceByEntityId(parentId); if (!owningInstanceOfParentEntity) { @@ -968,13 +981,13 @@ namespace AzToolsFramework return AZ::Failure(AZStd::string("No entities to duplicate.")); } - const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds); - if (entityIdsNoLevelInstance.empty()) + const EntityIdList entityIdsNoFocusContainer = GenerateEntityIdListWithoutFocusedInstanceContainer(entityIds); + if (entityIdsNoFocusContainer.empty()) { - return AZ::Failure(AZStd::string("No entities to duplicate because only instance selected is the level instance.")); + return AZ::Failure(AZStd::string("No entities to duplicate because only instance selected is the container entity of the focused instance.")); } - if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance)) + if (!EntitiesBelongToSameInstance(entityIdsNoFocusContainer)) { return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation." "Change your selection to contain entities in the same instance.")); @@ -982,7 +995,7 @@ namespace AzToolsFramework // We've already verified the entities are all owned by the same instance, // so we can just retrieve our instance from the first entity in the list. - AZ::EntityId firstEntityIdToDuplicate = entityIdsNoLevelInstance[0]; + AZ::EntityId firstEntityIdToDuplicate = entityIdsNoFocusContainer[0]; InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate); if (!commonOwningInstance.has_value()) { @@ -1002,7 +1015,7 @@ namespace AzToolsFramework // This will cull out any entities that have ancestors in the list, since we will end up duplicating // the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances - AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIdsNoLevelInstance); + AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entityIdsNoFocusContainer); AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -1106,19 +1119,21 @@ namespace AzToolsFramework PrefabOperationResult PrefabPublicHandler::DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants) { - const EntityIdList entityIdsNoLevelInstance = GenerateEntityIdListWithoutLevelInstance(entityIds); + // Remove the container entity of the focused prefab from the list, if it is included. + const EntityIdList entityIdsNoFocusContainer = GenerateEntityIdListWithoutFocusedInstanceContainer(entityIds); - if (entityIdsNoLevelInstance.empty()) + if (entityIdsNoFocusContainer.empty()) { return AZ::Success(); } - if (!EntitiesBelongToSameInstance(entityIdsNoLevelInstance)) + // All entities in this list need to belong to the same prefab instance for the operation to be valid. + if (!EntitiesBelongToSameInstance(entityIdsNoFocusContainer)) { return AZ::Failure(AZStd::string("Cannot delete multiple entities belonging to different instances with one operation.")); } - AZ::EntityId firstEntityIdToDelete = entityIdsNoLevelInstance[0]; + AZ::EntityId firstEntityIdToDelete = entityIdsNoFocusContainer[0]; InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete); // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you @@ -1128,8 +1143,15 @@ namespace AzToolsFramework commonOwningInstance = commonOwningInstance->get().GetParentInstance(); } + // We only allow explicit deletions for entities inside the currently focused prefab. + AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId(); + if (&m_prefabFocusInterface->GetFocusedPrefabInstance(editorEntityContextId)->get() != &commonOwningInstance->get()) + { + return AZ::Failure(AZStd::string("Cannot delete entities belonging to an instance that is not being edited.")); + } + // Retrieve entityList from entityIds - EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoLevelInstance); + EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoFocusContainer); AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -1186,7 +1208,7 @@ namespace AzToolsFramework } else { - for (AZ::EntityId entityId : entityIdsNoLevelInstance) + for (AZ::EntityId entityId : entityIdsNoFocusContainer) { InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId); // If this is the container entity, it actually represents the instance so get its owner @@ -1227,9 +1249,12 @@ namespace AzToolsFramework return AZ::Failure(AZStd::string("Cannot detach Prefab Instance with invalid container entity.")); } - if (IsLevelInstanceContainerEntity(containerEntityId)) + auto editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + if (containerEntityId == m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId)) { - return AZ::Failure(AZStd::string("Cannot detach level Prefab Instance.")); + return AZ::Failure(AZStd::string("Cannot detach focused Prefab Instance.")); } InstanceOptionalReference owningInstance = GetOwnerInstanceByEntityId(containerEntityId); @@ -1452,9 +1477,14 @@ namespace AzToolsFramework AZStd::queue entityQueue; + auto editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + AZ::EntityId focusedPrefabContainerEntityId = + m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); for (auto inputEntity : inputEntities) { - if (inputEntity && !IsLevelInstanceContainerEntity(inputEntity->GetId())) + if (inputEntity && inputEntity->GetId() != focusedPrefabContainerEntityId) { entityQueue.push(inputEntity); } @@ -1548,19 +1578,19 @@ namespace AzToolsFramework return AZ::Success(); } - EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutLevelInstance( + EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutFocusedInstanceContainer( const EntityIdList& entityIds) const { - EntityIdList outEntityIds; - outEntityIds.reserve(entityIds.size()); // Actual size could be smaller. + EntityIdList outEntityIds(entityIds); + + AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId(); + AZ::EntityId focusedInstanceContainerEntityId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); - for (const AZ::EntityId& entityId : entityIds) + if (auto iter = AZStd::find(outEntityIds.begin(), outEntityIds.end(), focusedInstanceContainerEntityId); iter != outEntityIds.end()) { - if (!IsLevelInstanceContainerEntity(entityId)) - { - outEntityIds.emplace_back(entityId); - } + outEntityIds.erase(iter); } + return outEntityIds; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index f3c0e67d46..a9dadc3336 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -74,7 +74,7 @@ namespace AzToolsFramework Instance& commonRootEntityOwningInstance, EntityList& outEntities, AZStd::vector& outInstances) const; - EntityIdList GenerateEntityIdListWithoutLevelInstance(const EntityIdList& entityIds) const; + EntityIdList GenerateEntityIdListWithoutFocusedInstanceContainer(const EntityIdList& entityIds) const; InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const; bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const; @@ -187,6 +187,8 @@ namespace AzToolsFramework InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr; InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr; + PrefabFocusInterface* m_prefabFocusInterface = nullptr; + PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; PrefabLoaderInterface* m_prefabLoaderInterface = nullptr; PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 6ffa3aab69..16e3c047b5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -175,12 +176,16 @@ namespace AzToolsFramework AzFramework::ApplicationRequests::Bus::BroadcastResult( prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + auto editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + // Create Prefab { if (!selectedEntities.empty()) { - // Hide if the only selected entity is the Level Container - if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0])) + // Hide if the only selected entity is the Focused Instance Container + if (selectedEntities.size() > 1 || + selectedEntities[0] != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId)) { bool layerInSelection = false; @@ -247,14 +252,14 @@ namespace AzToolsFramework // Edit Prefab if (prefabWipFeaturesEnabled && !s_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(selectedEntity)) { - QAction* editAction = menu->addAction(QObject::tr("Edit Prefab")); - editAction->setToolTip(QObject::tr("Edit the prefab in focus mode.")); + QAction* editAction = menu->addAction(QObject::tr("Edit Prefab")); + editAction->setToolTip(QObject::tr("Edit the prefab in focus mode.")); - QObject::connect(editAction, &QAction::triggered, editAction, [selectedEntity] { - ContextMenu_EditPrefab(selectedEntity); - }); + QObject::connect(editAction, &QAction::triggered, editAction, [selectedEntity] { + ContextMenu_EditPrefab(selectedEntity); + }); - itemWasShown = true; + itemWasShown = true; } // Save Prefab @@ -283,8 +288,9 @@ namespace AzToolsFramework QAction* deleteAction = menu->addAction(QObject::tr("Delete")); QObject::connect(deleteAction, &QAction::triggered, deleteAction, [] { ContextMenu_DeleteSelected(); }); - if (selectedEntities.size() == 0 || - (selectedEntities.size() == 1 && s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))) + + if (selectedEntities.empty() || + (selectedEntities.size() == 1 && selectedEntities[0] == s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId))) { deleteAction->setDisabled(true); } @@ -292,17 +298,17 @@ namespace AzToolsFramework // Detach Prefab if (selectedEntities.size() == 1) { - AZ::EntityId selectedEntity = selectedEntities[0]; + AZ::EntityId selectedEntityId = selectedEntities[0]; - if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity) && - !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntity)) + if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntityId) && + selectedEntityId != s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId)) { QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab...")); QObject::connect( detachPrefabAction, &QAction::triggered, detachPrefabAction, - [selectedEntity] + [selectedEntityId] { - ContextMenu_DetachPrefab(selectedEntity); + ContextMenu_DetachPrefab(selectedEntityId); }); } } @@ -331,13 +337,21 @@ namespace AzToolsFramework QWidget* activeWindow = QApplication::activeWindow(); const AZStd::string prefabFilesPath = "@projectroot@/Prefabs"; - // Remove Level entity if it's part of the list - - auto levelContainerIter = - AZStd::find(selectedEntities.begin(), selectedEntities.end(), s_prefabPublicInterface->GetLevelInstanceContainerEntityId()); - if (levelContainerIter != selectedEntities.end()) + // Remove focused instance container entity if it's part of the list + auto editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + + auto focusedContainerIter = AZStd::find( + selectedEntities.begin(), selectedEntities.end(), + s_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId)); + if (focusedContainerIter != selectedEntities.end()) { - selectedEntities.erase(levelContainerIter); + selectedEntities.erase(focusedContainerIter); + } + + if (selectedEntities.empty()) + { + return; } // Set default folder for prefabs diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp index 00522b29dc..ccad85e32b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp @@ -178,12 +178,6 @@ namespace AzToolsFramework AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value()); - // We hide the root instance container entity from the Outliner, so avoid drawing its full container on children - if (m_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId)) - { - return; - } - const QTreeView* outlinerTreeView(qobject_cast(option.widget)); const int ancestorLeft = outlinerTreeView->visualRect(index).left() + (m_prefabBorderThickness / 2) - 1; const int curveRectSize = m_prefabCapsuleRadius * 2; From 17b5312ce5c3ae2a8ef67e507807968eb8725d17 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 14 Oct 2021 15:53:21 -0700 Subject: [PATCH 272/293] PR comments Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/Trace.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp index 38e31393f5..cde8c36a4e 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp @@ -553,16 +553,12 @@ namespace AZ { StackFrame frames[25]; - // Without StackFrame explicit alignment frames array is aligned to 4 bytes - // which causes the stack tracing to fail. - //size_t bla = AZStd::alignment_of::value; - //printf("Alignment value %d address 0x%08x : 0x%08x\n",bla,frames); SymbolStorage::StackLine lines[AZ_ARRAY_SIZE(frames)]; unsigned int numFrames = 0; if (!nativeContext) { - suppressCount += 1; /// If we don't provide a context we will capture in the RecordFunction, so skip us (Trace::PrinCallstack). + suppressCount += 1; /// If we don't provide a context we will capture in the RecordFunction, so skip us (Trace::PrintCallstack). numFrames = StackRecorder::Record(frames, AZ_ARRAY_SIZE(frames), suppressCount); } else From 0ace221eb82bace5eb5b1037beca199f99c29046 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Thu, 14 Oct 2021 18:13:32 -0500 Subject: [PATCH 273/293] Add '.' path to render doc include directories on windows Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Gems/Atom/RHI/3rdParty/Platform/Windows/renderdoc_windows.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/RHI/3rdParty/Platform/Windows/renderdoc_windows.cmake b/Gems/Atom/RHI/3rdParty/Platform/Windows/renderdoc_windows.cmake index 559863ca07..70c8564a82 100644 --- a/Gems/Atom/RHI/3rdParty/Platform/Windows/renderdoc_windows.cmake +++ b/Gems/Atom/RHI/3rdParty/Platform/Windows/renderdoc_windows.cmake @@ -7,3 +7,4 @@ # set(RENDERDOC_RUNTIME_DEPENDENCIES "${BASE_PATH}/renderdoc.dll") +set(RENDERDOC_INCLUDE_DIRECTORIES ".") From c8be25a9cee96b003b23a21d43ad139d6e8c5340 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 14 Oct 2021 20:22:48 -0500 Subject: [PATCH 274/293] Converted preview renderer to use AZ::Interface Made some files private when exposing public interfaces Updated a few comments Signed-off-by: Guthrie Adams --- .../PreviewRendererCaptureRequest.h | 28 +++++++ .../PreviewRendererInterface.h | 29 +++++++ .../PreviewRendererSystemRequestBus.h | 24 ++++++ .../Code/Source/AtomToolsFrameworkModule.cpp | 3 + .../PreviewRenderer/PreviewRenderer.cpp | 9 ++- .../PreviewRenderer/PreviewRenderer.h | 38 ++++------ .../PreviewRendererCaptureState.cpp | 2 +- .../PreviewRendererCaptureState.h | 2 +- .../PreviewRendererIdleState.cpp | 2 +- .../PreviewRendererIdleState.h | 2 +- .../PreviewRendererLoadState.cpp | 2 +- .../PreviewRendererLoadState.h | 2 +- .../PreviewRenderer/PreviewRendererState.h | 2 +- .../PreviewRendererSystemComponent.cpp | 75 +++++++++++++++++++ .../PreviewRendererSystemComponent.h | 49 ++++++++++++ .../Code/atomtoolsframework_files.cmake | 9 ++- .../EditorMaterialSystemComponent.cpp | 49 +++++------- .../Material/EditorMaterialSystemComponent.h | 14 +--- .../Source/SharedPreview/SharedThumbnail.cpp | 2 +- .../Source/SharedPreview/SharedThumbnail.h | 7 +- .../SharedPreview/SharedThumbnailRenderer.cpp | 44 +++++------ .../SharedPreview/SharedThumbnailRenderer.h | 5 +- 22 files changed, 294 insertions(+), 105 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h rename Gems/Atom/Tools/AtomToolsFramework/Code/{Include/AtomToolsFramework => Source}/PreviewRenderer/PreviewRenderer.h (70%) rename Gems/Atom/Tools/AtomToolsFramework/Code/{Include/AtomToolsFramework => Source}/PreviewRenderer/PreviewRendererState.h (84%) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h new file mode 100644 index 0000000000..2212c553c8 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +class QPixmap; + +namespace AtomToolsFramework +{ + //! PreviewRendererCaptureRequest describes the size, content, and behavior of a scene to be rendered to an image + struct PreviewRendererCaptureRequest final + { + AZ_CLASS_ALLOCATOR(PreviewRendererCaptureRequest, AZ::SystemAllocator, 0); + + int m_size = 512; + AZStd::shared_ptr m_content; + AZStd::function m_captureFailedCallback; + AZStd::function m_captureCompleteCallback; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h new file mode 100644 index 0000000000..8fab1cb5c1 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AtomToolsFramework +{ + struct PreviewRendererCaptureRequest; + + //! Public interface for PreviewRenderer so that it can be used in other modules + class PreviewRendererInterface + { + public: + AZ_RTTI(PreviewRendererInterface, "{C5B5E3D0-0055-4C08-9B98-FDBBB5F05BED}"); + + virtual ~PreviewRendererInterface() = default; + virtual void AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest) = 0; + virtual AZ::RPI::ScenePtr GetScene() const = 0; + virtual AZ::RPI::ViewPtr GetView() const = 0; + virtual AZ::Uuid GetEntityContextId() const = 0; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h new file mode 100644 index 0000000000..810eccaa20 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h @@ -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 + * + */ + +#pragma once + +#include + +namespace AtomToolsFramework +{ + //! PreviewRendererSystemRequests provides an interface for PreviewRendererSystemComponent + class PreviewRendererSystemRequests : public AZ::EBusTraits + { + public: + // Only a single handler is allowed + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + }; + using PreviewRendererSystemRequestBus = AZ::EBus; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp index 21a185b290..865f12d904 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace AtomToolsFramework { @@ -19,6 +20,7 @@ namespace AtomToolsFramework AtomToolsFrameworkSystemComponent::CreateDescriptor(), AtomToolsDocumentSystemComponent::CreateDescriptor(), AtomToolsMainWindowSystemComponent::CreateDescriptor(), + PreviewRendererSystemComponent::CreateDescriptor(), }); } @@ -28,6 +30,7 @@ namespace AtomToolsFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), }; } } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 6e47360a84..a0d2034082 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -15,11 +15,12 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include #include @@ -80,6 +81,8 @@ namespace AtomToolsFramework m_renderPipeline->SetDefaultView(m_view); m_state.reset(new PreviewRendererIdleState(this)); + + AZ::Interface::Register(this); } PreviewRenderer::~PreviewRenderer() @@ -96,9 +99,11 @@ namespace AtomToolsFramework AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); m_frameworkScene->UnsetSubsystem(m_scene); m_frameworkScene->UnsetSubsystem(m_entityContext.get()); + + AZ::Interface::Unregister(this); } - void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) + void PreviewRenderer::AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest) { m_captureRequestQueue.push(captureRequest); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.h similarity index 70% rename from Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.h index dc03ed6715..6c8e282d80 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.h @@ -11,41 +11,31 @@ #include #include #include -#include +#include +#include #include #include - -namespace AzFramework -{ - class Scene; -} - -class QPixmap; +#include namespace AtomToolsFramework { //! Processes requests for setting up content that gets rendered to a texture and captured to an image - class PreviewRenderer final : public PreviewerFeatureProcessorProviderBus::Handler + class PreviewRenderer final + : public PreviewRendererInterface + , public PreviewerFeatureProcessorProviderBus::Handler { public: AZ_CLASS_ALLOCATOR(PreviewRenderer, AZ::SystemAllocator, 0); + AZ_RTTI(PreviewRenderer, "{60FCB7AB-2A94-417A-8C5E-5B588D17F5D1}", PreviewRendererInterface); PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName); - ~PreviewRenderer(); - - struct CaptureRequest final - { - int m_size = 512; - AZStd::shared_ptr m_content; - AZStd::function m_captureFailedCallback; - AZStd::function m_captureCompleteCallback; - }; + ~PreviewRenderer() override; - void AddCaptureRequest(const CaptureRequest& captureRequest); + void AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest) override; - AZ::RPI::ScenePtr GetScene() const; - AZ::RPI::ViewPtr GetView() const; - AZ::Uuid GetEntityContextId() const; + AZ::RPI::ScenePtr GetScene() const override; + AZ::RPI::ViewPtr GetView() const override; + AZ::Uuid GetEntityContextId() const override; void ProcessCaptureRequests(); void CancelCaptureRequest(); @@ -77,8 +67,8 @@ namespace AtomToolsFramework AZStd::unique_ptr m_entityContext; //! Incoming requests are appended to this queue and processed one at a time in OnTick function. - AZStd::queue m_captureRequestQueue; - CaptureRequest m_currentCaptureRequest; + AZStd::queue m_captureRequestQueue; + PreviewRendererCaptureRequest m_currentCaptureRequest; AZStd::unique_ptr m_state; }; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp index 9a807b7d00..5d1bd9158a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h index e8c6357445..74195ab396 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h @@ -9,8 +9,8 @@ #pragma once #include -#include #include +#include namespace AtomToolsFramework { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp index c440bafb73..b60142dd14 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h index f024bd8e30..4a0bc9067e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h @@ -8,8 +8,8 @@ #pragma once -#include #include +#include namespace AtomToolsFramework { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp index 7e34592095..2a1d99a090 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h index 702a01e862..359329c8da 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h @@ -9,7 +9,7 @@ #pragma once #include -#include +#include namespace AtomToolsFramework { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h similarity index 84% rename from Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h index bf68795974..53c452ef51 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h @@ -12,7 +12,7 @@ namespace AtomToolsFramework { class PreviewRenderer; - //! PreviewRendererState decouples PreviewRenderer logic into easy-to-understand and debug pieces + //! PreviewRendererState is an interface for defining states that manages the logic flow of the PreviewRenderer class PreviewRendererState { public: diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp new file mode 100644 index 0000000000..f88adfc65d --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AtomToolsFramework +{ + void PreviewRendererSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class() + ->Version(0); + + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class("PreviewRendererSystemComponent", "System component that manages a global PreviewRenderer.") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ; + } + } + } + + void PreviewRendererSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("PreviewRendererSystem")); + } + + void PreviewRendererSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("PreviewRendererSystem")); + } + + void PreviewRendererSystemComponent::Init() + { + } + + void PreviewRendererSystemComponent::Activate() + { + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); + PreviewRendererSystemRequestBus::Handler::BusConnect(); + } + + void PreviewRendererSystemComponent::Deactivate() + { + PreviewRendererSystemRequestBus::Handler::BusDisconnect(); + AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + m_previewRenderer.reset(); + } + + void PreviewRendererSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) + { + AZ::TickBus::QueueFunction([this](){ + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "PreviewRendererSystemComponent Preview Scene", "PreviewRendererSystemComponent Preview Pipeline")); + }); + } + + void PreviewRendererSystemComponent::OnApplicationAboutToStop() + { + m_previewRenderer.reset(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h new file mode 100644 index 0000000000..8110d84794 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AtomToolsFramework +{ + //! System component that manages a global PreviewRenderer. + class PreviewRendererSystemComponent final + : public AZ::Component + , public AzFramework::AssetCatalogEventBus::Handler + , public AzFramework::ApplicationLifecycleEvents::Bus::Handler + , public PreviewRendererSystemRequestBus::Handler + { + public: + AZ_COMPONENT(PreviewRendererSystemComponent, "{E9F79FD8-82F2-4C80-966D-95F28484F229}"); + + static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + + protected: + // AZ::Component interface overrides... + void Init() override; + void Activate() override; + void Deactivate() override; + + private: + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + + // AzFramework::ApplicationLifecycleEvents overrides... + void OnApplicationAboutToStop() override; + + AZStd::unique_ptr m_previewRenderer; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index df0dba2678..a2446cebcc 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -59,14 +59,19 @@ set(FILES Source/Window/AtomToolsMainWindowSystemComponent.cpp Source/Window/AtomToolsMainWindowSystemComponent.h Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h - Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h - Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h Source/PreviewRenderer/PreviewRenderer.cpp + Source/PreviewRenderer/PreviewRenderer.h + Source/PreviewRenderer/PreviewRendererState.h Source/PreviewRenderer/PreviewRendererIdleState.cpp Source/PreviewRenderer/PreviewRendererIdleState.h Source/PreviewRenderer/PreviewRendererLoadState.cpp Source/PreviewRenderer/PreviewRendererLoadState.h Source/PreviewRenderer/PreviewRendererCaptureState.cpp Source/PreviewRenderer/PreviewRendererCaptureState.h + Source/PreviewRenderer/PreviewRendererSystemComponent.cpp + Source/PreviewRenderer/PreviewRendererSystemComponent.h ) \ No newline at end of file diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index 0939c8548b..5df17a5478 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -6,10 +6,12 @@ * */ -#include #include #include +#include #include +#include +#include #include #include #include @@ -59,7 +61,7 @@ namespace AZ { ec->Class("EditorMaterialSystemComponent", "System component that manages launching and maintaining connections the material editor.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } @@ -68,12 +70,17 @@ namespace AZ void EditorMaterialSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { - provided.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e)); + provided.push_back(AZ_CRC_CE("EditorMaterialSystem")); } void EditorMaterialSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { - incompatible.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e)); + incompatible.push_back(AZ_CRC_CE("EditorMaterialSystem")); + } + + void EditorMaterialSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC_CE("PreviewRendererSystem")); } void EditorMaterialSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) @@ -93,21 +100,18 @@ namespace AZ AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); + + m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); } void EditorMaterialSystemComponent::Deactivate() { - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); - m_previewRenderer.reset(); m_materialBrowserInteractions.reset(); if (m_openMaterialEditorAction) @@ -160,7 +164,7 @@ namespace AZ static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - if (m_previewRenderer) + if (auto previewRenderer = AZ::Interface::Get()) { AZ::Data::AssetId materialAssetId = {}; MaterialComponentRequestBus::EventResult( @@ -180,15 +184,17 @@ namespace AZ propertyOverrides, entityId, &AZ::Render::MaterialComponentRequestBus::Events::GetPropertyOverrides, materialAssignmentId); - m_previewRenderer->AddCaptureRequest( + previewRenderer->AddCaptureRequest( { 128, AZStd::make_shared( - m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), + previewRenderer->GetScene(), previewRenderer->GetView(), previewRenderer->GetEntityContextId(), AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId, AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides), - []() + [entityId, materialAssignmentId]() { - // failed + AZ_Warning( + "EditorMaterialSystemComponent", false, "RenderMaterialPreview capture failed for entity %s slot %s.", + entityId.ToString().c_str(), materialAssignmentId.ToString().c_str()); }, [entityId, materialAssignmentId](const QPixmap& pixmap) { @@ -264,21 +270,6 @@ namespace AZ "Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions); } - void EditorMaterialSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) - { - AZ::TickBus::QueueFunction([this](){ - m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); - m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( - "EditorMaterialSystemComponent Preview Scene", "EditorMaterialSystemComponent Preview Pipeline")); - }); - } - - void EditorMaterialSystemComponent::OnApplicationAboutToStop() - { - m_previewRenderer.reset(); - m_materialBrowserInteractions.reset(); - } - AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails( const char* fullSourceFileName) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h index e62c9b64dc..6fce538ead 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h @@ -5,13 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include -#include #include #include -#include #include #include #include @@ -30,8 +29,6 @@ namespace AZ , public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler , public AzToolsFramework::EditorMenuNotificationBus::Handler , public AzToolsFramework::EditorEvents::Bus::Handler - , public AzFramework::AssetCatalogEventBus::Handler - , public AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}"); @@ -40,6 +37,7 @@ namespace AZ static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); protected: @@ -70,16 +68,8 @@ namespace AZ // AztoolsFramework::EditorEvents::Bus::Handler overrides... void NotifyRegisterViews() override; - - // AzFramework::AssetCatalogEventBus::Handler overrides ... - void OnCatalogLoaded(const char* catalogFile) override; - - // AzFramework::ApplicationLifecycleEvents overrides... - void OnApplicationAboutToStop() override; - QAction* m_openMaterialEditorAction = nullptr; AZStd::unique_ptr m_materialBrowserInteractions; - AZStd::unique_ptr m_previewRenderer; AZStd::unordered_map> m_materialPreviews; }; } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp index ebfad39229..5d82bac139 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp @@ -87,7 +87,7 @@ namespace AZ int SharedThumbnailCache::GetPriority() const { - // Thumbnails override default source thumbnails, so carry higher priority + // Custom thumbnails have a higher priority to override default source thumbnails return 1; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h index d65e94a7a3..dee433e0bb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h @@ -19,7 +19,8 @@ namespace AZ { namespace LyIntegration { - //! Custom thumbnail that detects when an asset changes and updates the thumbnail + //! Custom thumbnail for most common Atom assets + //! Detects asset changes and updates the thumbnail class SharedThumbnail final : public AzToolsFramework::Thumbnailer::Thumbnail , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler @@ -46,7 +47,7 @@ namespace AZ AZ::Uuid m_typeId; }; - //! Cache configuration for large thumbnails + //! Cache configuration for shared thumbnails class SharedThumbnailCache final : public AzToolsFramework::Thumbnailer::ThumbnailCache { public: @@ -56,7 +57,7 @@ namespace AZ int GetPriority() const override; const char* GetProviderName() const override; - static constexpr const char* ProviderName = "Common Feature Shared Thumbnail= Provider"; + static constexpr const char* ProviderName = "Common Feature Shared Thumbnail Provider"; protected: bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp index c20cef548f..c43ba5f1cf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp @@ -6,6 +6,8 @@ * */ +#include +#include #include #include #include @@ -18,9 +20,6 @@ namespace AZ { SharedThumbnailRenderer::SharedThumbnailRenderer() { - m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( - "SharedThumbnailRenderer Preview Scene", "SharedThumbnailRenderer Preview Pipeline")); - m_defaultModelAsset.Create(DefaultModelAssetId, true); m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); @@ -40,24 +39,27 @@ namespace AZ void SharedThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) { - m_previewRenderer->AddCaptureRequest( - { thumbnailSize, - AZStd::make_shared( - m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), - SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId), - SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId), - SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId), - Render::MaterialPropertyOverrideMap()), - [thumbnailKey]() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - }, - [thumbnailKey](const QPixmap& pixmap) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap); - } }); + if (auto previewRenderer = AZ::Interface::Get()) + { + previewRenderer->AddCaptureRequest( + { thumbnailSize, + AZStd::make_shared( + previewRenderer->GetScene(), previewRenderer->GetView(), previewRenderer->GetEntityContextId(), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId), + Render::MaterialPropertyOverrideMap()), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QPixmap& pixmap) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap); + } }); + } } bool SharedThumbnailRenderer::Installed() const diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h index bcefbd6f4e..4db7728109 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -22,7 +21,7 @@ namespace AZ { namespace LyIntegration { - //! Provides custom rendering thumbnails of supported asset types + //! Provides custom thumbnail rendering of supported asset types class SharedThumbnailRenderer final : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler , public SystemTickBus::Handler @@ -53,8 +52,6 @@ namespace AZ static constexpr const char* DefaultMaterialPath = ""; const Data::AssetId DefaultMaterialAssetId; Data::Asset m_defaultMaterialAsset; - - AZStd::unique_ptr m_previewRenderer; }; } // namespace LyIntegration } // namespace AZ From ed9ecb3906cfe5285756f5564bf7e412f91bd875 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 14 Oct 2021 23:43:35 -0500 Subject: [PATCH 275/293] adding missing includes to fix build Signed-off-by: Guthrie Adams --- .../AtomToolsFramework/PreviewRenderer/PreviewContent.h | 1 + .../PreviewRenderer/PreviewRendererCaptureRequest.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h index a96cec65b1..27876622da 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h @@ -9,6 +9,7 @@ #pragma once #include +#include namespace AtomToolsFramework { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h index 2212c553c8..ea8f5fb356 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h @@ -10,6 +10,9 @@ #include #include +#include +#include +#include class QPixmap; From d89b1b0aa1449e952547c6c69a8c59b60b49bab9 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 14 Oct 2021 23:34:17 -0700 Subject: [PATCH 276/293] Fixed frame capture on vulkan. It just wasn't passing the correct RHI Format value. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Common/Code/Source/FrameCaptureSystemComponent.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 51e18b8e31..66b5cff8ce 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -54,10 +54,14 @@ namespace AZ { AZStd::shared_ptr> buffer = readbackResult.m_dataBuffer; + RHI::Format finalFormat = readbackResult.m_imageDescriptor.m_format; + // convert bgra to rgba by swapping channels const int numChannels = AZ::RHI::GetFormatComponentCount(readbackResult.m_imageDescriptor.m_format); if (readbackResult.m_imageDescriptor.m_format == RHI::Format::B8G8R8A8_UNORM) { + finalFormat = RHI::Format::R8G8B8A8_UNORM; + buffer = AZStd::make_shared>(readbackResult.m_dataBuffer->size()); AZStd::copy(readbackResult.m_dataBuffer->begin(), readbackResult.m_dataBuffer->end(), buffer->begin()); @@ -89,7 +93,7 @@ namespace AZ jobCompletion.StartAndWaitForCompletion(); } - Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer); + Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, finalFormat, *buffer); Utils::PngFile::SaveSettings saveSettings; saveSettings.m_compressionLevel = r_pngCompressionLevel; From 1626d2d00741771053c288285fb5e6e4cf54f367 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 14 Oct 2021 23:36:45 -0700 Subject: [PATCH 277/293] Minor code cleanup. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Common/Code/Source/FrameCaptureSystemComponent.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 66b5cff8ce..cdcc07b545 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -54,13 +54,13 @@ namespace AZ { AZStd::shared_ptr> buffer = readbackResult.m_dataBuffer; - RHI::Format finalFormat = readbackResult.m_imageDescriptor.m_format; + RHI::Format format = readbackResult.m_imageDescriptor.m_format; // convert bgra to rgba by swapping channels const int numChannels = AZ::RHI::GetFormatComponentCount(readbackResult.m_imageDescriptor.m_format); - if (readbackResult.m_imageDescriptor.m_format == RHI::Format::B8G8R8A8_UNORM) + if (format == RHI::Format::B8G8R8A8_UNORM) { - finalFormat = RHI::Format::R8G8B8A8_UNORM; + format = RHI::Format::R8G8B8A8_UNORM; buffer = AZStd::make_shared>(readbackResult.m_dataBuffer->size()); AZStd::copy(readbackResult.m_dataBuffer->begin(), readbackResult.m_dataBuffer->end(), buffer->begin()); @@ -93,7 +93,7 @@ namespace AZ jobCompletion.StartAndWaitForCompletion(); } - Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, finalFormat, *buffer); + Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, format, *buffer); Utils::PngFile::SaveSettings saveSettings; saveSettings.m_compressionLevel = r_pngCompressionLevel; From 3b9762142a198c6d35ddc8b9fa1ea492e41beffe Mon Sep 17 00:00:00 2001 From: moraaar Date: Fri, 15 Oct 2021 08:58:18 +0100 Subject: [PATCH 278/293] Triangle Mesh with a Kinematic PhysX Rigid Body warns the user instead of error. (#4657) Using triangle mesh with a kinematic rigid body is allowed, but the options "Compute COM", "Compute Mass" and "Compute Inertia" are not supported by PhysX and an error in logged that default values for COM, Mass and Inertia will be used. Now this situation is captured and an explanatory warning is used instead. - Improved RigidBody::UpdateMassProperties function to apply the same logic in the treatment of shapes for all three parameters: COM, Mass and Inertia. - Improved UpdateMassProperties function by using references for the override parameters instead of pointers. - Improved function that computes the Center of Mass UpdateCenterOfMass (renamed from UpdateComputedCenterOfMass), to include the same shapes that the compute mass and inertia functions in physx updateMassAndInertia, which is to include all shapes if includeAllShapesInMassCalculation is true, else include only the shapes with eSIMULATION_SHAPE flag. - Removed unused private function RigidBody::ComputeInertia. - Added unit test to check when the warnings are fired correctly when COM, Mass or Inertia are asked to be computed on a rigid body with triangle mesh shapes. - Improved MassComputeFixture tests by not only using Box shape, but also sphere and capture, plus improved the PossibleMassComputeFlags parameters to include all possible variations of the MassComputeFlags flags. Fixes #3322 Fixes #3979 Signed-off-by: moraaar --- .../AzFramework/Physics/RigidBody.h | 234 --------------- .../Physics/SimulatedBodies/RigidBody.h | 6 +- Gems/Blast/Code/Tests/Mocks/BlastMocks.h | 6 +- Gems/PhysX/Code/Source/RigidBody.cpp | 277 ++++++++++-------- Gems/PhysX/Code/Source/RigidBody.h | 10 +- Gems/PhysX/Code/Source/Scene/PhysXScene.cpp | 4 +- Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp | 223 ++++++++++---- Gems/PhysX/Code/Tests/PhysXTestCommon.cpp | 30 ++ Gems/PhysX/Code/Tests/PhysXTestCommon.h | 1 + .../Components/WhiteBoxColliderComponent.cpp | 5 + 10 files changed, 367 insertions(+), 429 deletions(-) delete mode 100644 Code/Framework/AzFramework/AzFramework/Physics/RigidBody.h diff --git a/Code/Framework/AzFramework/AzFramework/Physics/RigidBody.h b/Code/Framework/AzFramework/AzFramework/Physics/RigidBody.h deleted file mode 100644 index 13d29b6bb9..0000000000 --- a/Code/Framework/AzFramework/AzFramework/Physics/RigidBody.h +++ /dev/null @@ -1,234 +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 - * - */ - -#pragma once - -#include -#include -#include - -#include -#include - -namespace -{ - class ReflectContext; -} - -namespace Physics -{ - class ShapeConfiguration; - class World; - class Shape; - - /// Default values used for initializing RigidBodySettings. - /// These can be modified by Physics Implementation gems. // O3DE_DEPRECATED(LY-114472) - DefaultRigidBodyConfiguration values are not shared across modules. - // Use RigidBodyConfiguration default values. - struct DefaultRigidBodyConfiguration - { - static float m_mass; - static bool m_computeInertiaTensor; - static float m_linearDamping; - static float m_angularDamping; - static float m_sleepMinEnergy; - static float m_maxAngularVelocity; - }; - - enum class MassComputeFlags : AZ::u8 - { - NONE = 0, - - //! Flags indicating whether a certain mass property should be auto-computed or not. - COMPUTE_MASS = 1, - COMPUTE_INERTIA = 1 << 1, - COMPUTE_COM = 1 << 2, - - //! If set, non-simulated shapes will also be included in the mass properties calculation. - INCLUDE_ALL_SHAPES = 1 << 3, - - DEFAULT = COMPUTE_COM | COMPUTE_INERTIA | COMPUTE_MASS - }; - - class RigidBodyConfiguration - : public WorldBodyConfiguration - { - public: - AZ_CLASS_ALLOCATOR(RigidBodyConfiguration, AZ::SystemAllocator, 0); - AZ_RTTI(RigidBodyConfiguration, "{ACFA8900-8530-4744-AF00-AA533C868A8E}", WorldBodyConfiguration); - static void Reflect(AZ::ReflectContext* context); - - enum PropertyVisibility : AZ::u16 - { - InitialVelocities = 1 << 0, ///< Whether the initial linear and angular velocities are visible. - InertiaProperties = 1 << 1, ///< Whether the whole category of inertia properties (mass, compute inertia, - ///< inertia tensor etc) is visible. - Damping = 1 << 2, ///< Whether linear and angular damping are visible. - SleepOptions = 1 << 3, ///< Whether the sleep threshold and start asleep options are visible. - Interpolation = 1 << 4, ///< Whether the interpolation option is visible. - Gravity = 1 << 5, ///< Whether the effected by gravity option is visible. - Kinematic = 1 << 6, ///< Whether the option to make the body kinematic is visible. - ContinuousCollisionDetection = 1 << 7, ///< Whether the option to enable continuous collision detection is visible. - MaxVelocities = 1 << 8 ///< Whether upper limits on velocities are visible. - }; - - RigidBodyConfiguration() = default; - RigidBodyConfiguration(const RigidBodyConfiguration& settings) = default; - - // Visibility functions. - AZ::Crc32 GetPropertyVisibility(PropertyVisibility property) const; - void SetPropertyVisibility(PropertyVisibility property, bool isVisible); - - AZ::Crc32 GetInitialVelocitiesVisibility() const; - /// Returns whether the whole category of inertia settings (mass, inertia, center of mass offset etc) is visible. - AZ::Crc32 GetInertiaSettingsVisibility() const; - /// Returns whether the individual inertia tensor field is visible or is hidden because the compute inertia option is selected. - AZ::Crc32 GetInertiaVisibility() const; - /// Returns whether the mass field is visible or is hidden because compute mass option is selected. - AZ::Crc32 GetMassVisibility() const; - /// Returns whether the individual centre of mass offset field is visible or is hidden because compute CoM option is selected. - AZ::Crc32 GetCoMVisibility() const; - AZ::Crc32 GetDampingVisibility() const; - AZ::Crc32 GetSleepOptionsVisibility() const; - AZ::Crc32 GetInterpolationVisibility() const; - AZ::Crc32 GetGravityVisibility() const; - AZ::Crc32 GetKinematicVisibility() const; - AZ::Crc32 GetCCDVisibility() const; - AZ::Crc32 GetMaxVelocitiesVisibility() const; - MassComputeFlags GetMassComputeFlags() const; - void SetMassComputeFlags(MassComputeFlags flags); - - bool IsCCDEnabled() const; - - // Basic initial settings. - AZ::Vector3 m_initialLinearVelocity = AZ::Vector3::CreateZero(); - AZ::Vector3 m_initialAngularVelocity = AZ::Vector3::CreateZero(); - AZ::Vector3 m_centerOfMassOffset = AZ::Vector3::CreateZero(); - - // Simulation parameters. - float m_mass = DefaultRigidBodyConfiguration::m_mass; - AZ::Matrix3x3 m_inertiaTensor = AZ::Matrix3x3::CreateIdentity(); - float m_linearDamping = DefaultRigidBodyConfiguration::m_linearDamping; - float m_angularDamping = DefaultRigidBodyConfiguration::m_angularDamping; - float m_sleepMinEnergy = DefaultRigidBodyConfiguration::m_sleepMinEnergy; - float m_maxAngularVelocity = DefaultRigidBodyConfiguration::m_maxAngularVelocity; - - // Visibility settings. - AZ::u16 m_propertyVisibilityFlags = (std::numeric_limits::max)(); - - bool m_startAsleep = false; - bool m_interpolateMotion = false; - bool m_gravityEnabled = true; - bool m_simulated = true; - bool m_kinematic = false; - bool m_ccdEnabled = false; ///< Whether continuous collision detection is enabled. - float m_ccdMinAdvanceCoefficient = 0.15f; ///< Coefficient affecting how granularly time is subdivided in CCD. - bool m_ccdFrictionEnabled = false; ///< Whether friction is applied when resolving CCD collisions. - - bool m_computeCenterOfMass = true; - bool m_computeInertiaTensor = true; - bool m_computeMass = true; - - //! If set, non-simulated shapes will also be included in the mass properties calculation. - bool m_includeAllShapesInMassCalculation = false; - }; - - /// Dynamic rigid body. - class RigidBody - : public WorldBody - { - public: - - AZ_CLASS_ALLOCATOR(RigidBody, AZ::SystemAllocator, 0); - AZ_RTTI(RigidBody, "{156E459F-7BB7-4B4E-ADA0-2130D96B7E80}", WorldBody); - - public: - RigidBody() = default; - explicit RigidBody(const RigidBodyConfiguration& settings); - - - virtual void AddShape(AZStd::shared_ptr shape) = 0; - virtual void RemoveShape(AZStd::shared_ptr shape) = 0; - virtual AZ::u32 GetShapeCount() { return 0; } - virtual AZStd::shared_ptr GetShape(AZ::u32 /*index*/) { return nullptr; } - - virtual AZ::Vector3 GetCenterOfMassWorld() const = 0; - virtual AZ::Vector3 GetCenterOfMassLocal() const = 0; - - virtual AZ::Matrix3x3 GetInverseInertiaWorld() const = 0; - virtual AZ::Matrix3x3 GetInverseInertiaLocal() const = 0; - - virtual float GetMass() const = 0; - virtual float GetInverseMass() const = 0; - virtual void SetMass(float mass) = 0; - virtual void SetCenterOfMassOffset(const AZ::Vector3& comOffset) = 0; - - /// Retrieves the velocity at center of mass; only linear velocity, no rotational velocity contribution. - virtual AZ::Vector3 GetLinearVelocity() const = 0; - virtual void SetLinearVelocity(const AZ::Vector3& velocity) = 0; - virtual AZ::Vector3 GetAngularVelocity() const = 0; - virtual void SetAngularVelocity(const AZ::Vector3& angularVelocity) = 0; - virtual AZ::Vector3 GetLinearVelocityAtWorldPoint(const AZ::Vector3& worldPoint) = 0; - virtual void ApplyLinearImpulse(const AZ::Vector3& impulse) = 0; - virtual void ApplyLinearImpulseAtWorldPoint(const AZ::Vector3& impulse, const AZ::Vector3& worldPoint) = 0; - virtual void ApplyAngularImpulse(const AZ::Vector3& angularImpulse) = 0; - - virtual float GetLinearDamping() const = 0; - virtual void SetLinearDamping(float damping) = 0; - virtual float GetAngularDamping() const = 0; - virtual void SetAngularDamping(float damping) = 0; - - virtual bool IsAwake() const = 0; - virtual void ForceAsleep() = 0; - virtual void ForceAwake() = 0; - virtual float GetSleepThreshold() const = 0; - virtual void SetSleepThreshold(float threshold) = 0; - - virtual bool IsKinematic() const = 0; - virtual void SetKinematic(bool kinematic) = 0; - virtual void SetKinematicTarget(const AZ::Transform& targetPosition) = 0; - - virtual bool IsGravityEnabled() const = 0; - virtual void SetGravityEnabled(bool enabled) = 0; - virtual void SetSimulationEnabled(bool enabled) = 0; - virtual void SetCCDEnabled(bool enabled) = 0; - - //! Recalculates mass, inertia and center of mass based on the flags passed. - //! @param flags MassComputeFlags specifying which properties should be recomputed. - //! @param centerOfMassOffsetOverride Optional override of the center of mass. Note: This parameter will be ignored if COMPUTE_COM is passed in flags. - //! @param inertiaTensorOverride Optional override of the inertia. Note: This parameter will be ignored if COMPUTE_INERTIA is passed in flags. - //! @param massOverride Optional override of the mass. Note: This parameter will be ignored if COMPUTE_MASS is passed in flags. - virtual void UpdateMassProperties(MassComputeFlags flags = MassComputeFlags::DEFAULT, - const AZ::Vector3* centerOfMassOffsetOverride = nullptr, - const AZ::Matrix3x3* inertiaTensorOverride = nullptr, - const float* massOverride = nullptr) = 0; - }; - - /// Bitwise operators for MassComputeFlags - inline MassComputeFlags operator|(MassComputeFlags lhs, MassComputeFlags rhs) - { - return aznumeric_cast(aznumeric_cast(lhs) | aznumeric_cast(rhs)); - } - - inline MassComputeFlags operator&(MassComputeFlags lhs, MassComputeFlags rhs) - { - return aznumeric_cast(aznumeric_cast(lhs) & aznumeric_cast(rhs)); - } - - /// Static rigid body. - class RigidBodyStatic - : public WorldBody - { - public: - AZ_CLASS_ALLOCATOR(RigidBodyStatic, AZ::SystemAllocator, 0); - AZ_RTTI(RigidBodyStatic, "{13A677BB-7085-4EDB-BCC8-306548238692}", WorldBody); - - virtual void AddShape(const AZStd::shared_ptr& shape) = 0; - virtual AZ::u32 GetShapeCount() { return 0; } - virtual AZStd::shared_ptr GetShape(AZ::u32 /*index*/) { return nullptr; } - }; -} // namespace Physics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h b/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h index 3c0a1afa1d..e9bf8a7307 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h @@ -89,9 +89,9 @@ namespace AzPhysics //! @param inertiaTensorOverride Optional override of the inertia. Note: This parameter will be ignored if COMPUTE_INERTIA is passed in flags. //! @param massOverride Optional override of the mass. Note: This parameter will be ignored if COMPUTE_MASS is passed in flags. virtual void UpdateMassProperties(MassComputeFlags flags = MassComputeFlags::DEFAULT, - const AZ::Vector3* centerOfMassOffsetOverride = nullptr, - const AZ::Matrix3x3* inertiaTensorOverride = nullptr, - const float* massOverride = nullptr) = 0; + const AZ::Vector3& centerOfMassOffsetOverride = AZ::Vector3::CreateZero(), + const AZ::Matrix3x3& inertiaTensorOverride = AZ::Matrix3x3::CreateIdentity(), + const float massOverride = 1.0f) = 0; }; } // namespace AzPhysics diff --git a/Gems/Blast/Code/Tests/Mocks/BlastMocks.h b/Gems/Blast/Code/Tests/Mocks/BlastMocks.h index dddd1e275a..1fe6e35d75 100644 --- a/Gems/Blast/Code/Tests/Mocks/BlastMocks.h +++ b/Gems/Blast/Code/Tests/Mocks/BlastMocks.h @@ -344,9 +344,9 @@ namespace Blast void UpdateMassProperties( [[maybe_unused]] AzPhysics::MassComputeFlags flags, - [[maybe_unused]] const AZ::Vector3* centerOfMassOffsetOverride, - [[maybe_unused]] const AZ::Matrix3x3* inertiaTensorOverride, - [[maybe_unused]] const float* massOverride) override + [[maybe_unused]] const AZ::Vector3& centerOfMassOffsetOverride, + [[maybe_unused]] const AZ::Matrix3x3& inertiaTensorOverride, + [[maybe_unused]] const float massOverride) override { } diff --git a/Gems/PhysX/Code/Source/RigidBody.cpp b/Gems/PhysX/Code/Source/RigidBody.cpp index f8b22affe0..5b36376da5 100644 --- a/Gems/PhysX/Code/Source/RigidBody.cpp +++ b/Gems/PhysX/Code/Source/RigidBody.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,28 @@ namespace PhysX { + namespace + { + const AZ::Vector3 DefaultCenterOfMass = AZ::Vector3::CreateZero(); + const float DefaultMass = 1.0f; + const AZ::Matrix3x3 DefaultInertiaTensor = AZ::Matrix3x3::CreateIdentity(); + + bool IsSimulationShape(const physx::PxShape& pxShape) + { + return (pxShape.getFlags() & physx::PxShapeFlag::eSIMULATION_SHAPE); + } + + bool CanShapeComputeMassProperties(const physx::PxShape& pxShape) + { + // Note: List based on computeMassAndInertia function in ExtRigidBodyExt.cpp file in PhysX. + const physx::PxGeometryType::Enum geometryType = pxShape.getGeometryType(); + return geometryType == physx::PxGeometryType::eSPHERE + || geometryType == physx::PxGeometryType::eBOX + || geometryType == physx::PxGeometryType::eCAPSULE + || geometryType == physx::PxGeometryType::eCONVEXMESH; + } + } + void RigidBody::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -152,104 +175,120 @@ namespace PhysX m_shapes.erase(found); } - void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3* centerOfMassOffsetOverride, const AZ::Matrix3x3* inertiaTensorOverride, const float* massOverride) + void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3& centerOfMassOffsetOverride, const AZ::Matrix3x3& inertiaTensorOverride, const float massOverride) { - // Input validation - bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM); - AZ_Assert(computeCenterOfMass || centerOfMassOffsetOverride, - "UpdateMassProperties: MassComputeFlags::COMPUTE_COM is not set but COM offset is not specified"); - computeCenterOfMass = computeCenterOfMass || !centerOfMassOffsetOverride; - - bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA); - AZ_Assert(computeInertiaTensor || inertiaTensorOverride, - "UpdateMassProperties: MassComputeFlags::COMPUTE_INERTIA is not set but inertia tensor is not specified"); - computeInertiaTensor = computeInertiaTensor || !inertiaTensorOverride; - - bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS); - AZ_Assert(computeMass || massOverride, - "UpdateMassProperties: MassComputeFlags::COMPUTE_MASS is not set but mass is not specified"); - computeMass = computeMass || !massOverride; + const bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM); + const bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA); + const bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS); + const bool needsCompute = computeCenterOfMass || computeInertiaTensor || computeMass; + const bool includeAllShapesInMassCalculation = AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES); - AZ::u32 shapesCount = GetShapeCount(); - - // Basic cases when we don't need to compute anything - if (shapesCount == 0 || flags == AzPhysics::MassComputeFlags::NONE) + // Basic case where all properties are set directly. + if (!needsCompute) { - if (massOverride) - { - SetMass(*massOverride); - } - - if (inertiaTensorOverride) - { - SetInertia(*inertiaTensorOverride); - } - - if (centerOfMassOffsetOverride) - { - SetCenterOfMassOffset(*centerOfMassOffsetOverride); - } + SetCenterOfMassOffset(centerOfMassOffsetOverride); + SetMass(massOverride); + SetInertia(inertiaTensorOverride); return; } - // Setup center of mass offset pointer for PxRigidBodyExt::updateMassAndInertia function - AZStd::optional optionalComOverride; - if (!computeCenterOfMass && centerOfMassOffsetOverride) + // If there are no shapes then set the properties directly without computing anything. + if (m_shapes.empty()) { - optionalComOverride = PxMathConvert(*centerOfMassOffsetOverride); + SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride); + SetMass(computeMass ? DefaultMass : massOverride); + SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride); + return; } - const physx::PxVec3* massLocalPose = optionalComOverride.has_value() ? &optionalComOverride.value() : nullptr; + auto cannotComputeMassProperties = [this, includeAllShapesInMassCalculation] + { + PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); + return AZStd::any_of(m_shapes.cbegin(), m_shapes.cend(), + [includeAllShapesInMassCalculation](const AZStd::shared_ptr& shape) + { + const physx::PxShape& pxShape = *shape->GetPxShape(); + const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape); + + return includeShape && !CanShapeComputeMassProperties(pxShape); + }); + }; + + // If contains shapes that cannot compute mass properties (triangle mesh, + // plane or heightfield) then default values will be used. + if (cannotComputeMassProperties()) + { + AZ_Warning("RigidBody", !computeCenterOfMass, + "Rigid body '%s' cannot compute COM because it contains triangle mesh, plane or heightfield shapes, it will default to %s.", + GetName().c_str(), AZ::ToString(DefaultCenterOfMass).c_str()); + AZ_Warning("RigidBody", !computeMass, + "Rigid body '%s' cannot compute Mass because it contains triangle mesh, plane or heightfield shapes, it will default to %0.1f.", + GetName().c_str(), DefaultMass); + AZ_Warning("RigidBody", !computeInertiaTensor, + "Rigid body '%s' cannot compute Inertia because it contains triangle mesh, plane or heightfield shapes, it will default to %s.", + GetName().c_str(), AZ::ToString(DefaultInertiaTensor.RetrieveScale()).c_str()); + + SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride); + SetMass(computeMass ? DefaultMass : massOverride); + SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride); + return; + } - bool includeAllShapesInMassCalculation = - AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES); + // Center of mass needs to be considered first since + // it's needed when computing mass and inertia. + if (computeCenterOfMass) + { + // Compute Center of Mass + UpdateCenterOfMass(includeAllShapesInMassCalculation); + } + else + { + SetCenterOfMassOffset(centerOfMassOffsetOverride); + } + const physx::PxVec3 pxCenterOfMass = PxMathConvert(GetCenterOfMassLocal()); - // Handle the case when we don't compute mass - if (!computeMass) + if (computeMass) { + // Gather material densities from all shapes, + // mass computation is based on them. + AZStd::vector densities; + densities.reserve(m_shapes.size()); + for (const auto& shape : m_shapes) + { + densities.emplace_back(shape->GetMaterial()->GetDensity()); + } + + // Compute Mass + Inertia { PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, *massOverride, massLocalPose, - includeAllShapesInMassCalculation); + physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, + densities.data(), static_cast(densities.size()), + &pxCenterOfMass, includeAllShapesInMassCalculation); } + // There is no physx function to only compute the mass without + // computing the inertia. So now that both have been computed + // we can override the inertia if it's suppose to use a + // specific value set by the user. if (!computeInertiaTensor) { - SetInertia(*inertiaTensorOverride); + SetInertia(inertiaTensorOverride); } - - return; - } - - // Handle the cases when mass should be computed from density - if (shapesCount == 1) - { - AZStd::shared_ptr shape = GetShape(0); - float density = shape->GetMaterial()->GetDensity(); - - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, density, massLocalPose, - includeAllShapesInMassCalculation); } else { - AZStd::vector densities(shapesCount); - for (AZ::u32 i = 0; i < shapesCount; ++i) + if (computeInertiaTensor) { - densities[i] = GetShape(i)->GetMaterial()->GetDensity(); + // Set Mass + Compute Inertia + PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); + physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, massOverride, + &pxCenterOfMass, includeAllShapesInMassCalculation); + } + else + { + SetMass(massOverride); + SetInertia(inertiaTensorOverride); } - - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, densities.data(), - shapesCount, massLocalPose, includeAllShapesInMassCalculation); - } - - // Set the overrides if provided. - // Note: We don't set the center of mass here because it was already provided - // to PxRigidBodyExt::updateMassAndInertia above - if (!computeInertiaTensor) - { - SetInertia(*inertiaTensorOverride); } } @@ -344,70 +383,57 @@ namespace PhysX } } - void RigidBody::UpdateComputedCenterOfMass() + void RigidBody::UpdateCenterOfMass(bool includeAllShapesInMassCalculation) { - if (m_pxRigidActor) + if (m_shapes.empty()) { - physx::PxU32 shapeCount = 0; - { - PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); - shapeCount = m_pxRigidActor->getNbShapes(); - } - if (shapeCount > 0) - { - AZStd::vector shapes; - shapes.resize(shapeCount); - - { - PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->getShapes(&shapes[0], shapeCount); - } - - shapes.erase(AZStd::remove_if(shapes.begin() - , shapes.end() - , [](const physx::PxShape* shape) - { - return shape->getFlags() & physx::PxShapeFlag::eTRIGGER_SHAPE; - }) - , shapes.end()); - shapeCount = static_cast(shapes.size()); + SetCenterOfMassOffset(DefaultCenterOfMass); + return; + } - if (shapeCount == 0) - { - SetZeroCenterOfMass(); - return; - } + AZStd::vector pxShapes; + pxShapes.reserve(m_shapes.size()); + { + // Filter shapes in the same way that updateMassAndInertia function does. + PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); + for (const auto& shape : m_shapes) + { + const physx::PxShape& pxShape = *shape->GetPxShape(); + const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape); - const auto properties = physx::PxRigidBodyExt::computeMassPropertiesFromShapes(&shapes[0], shapeCount); - const physx::PxTransform computedCenterOfMass(properties.centerOfMass); + if (includeShape && CanShapeComputeMassProperties(pxShape)) { - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->setCMassLocalPose(computedCenterOfMass); + pxShapes.emplace_back(&pxShape); } } - else - { - SetZeroCenterOfMass(); - } } - } - void RigidBody::SetInertia(const AZ::Matrix3x3& inertia) - { - if (m_pxRigidActor) + if (pxShapes.empty()) { - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->setMassSpaceInertiaTensor(PxMathConvert(inertia.RetrieveScale())); + SetCenterOfMassOffset(DefaultCenterOfMass); + return; } + + const physx::PxMassProperties pxMassProperties = [this, &pxShapes] + { + // Note: PhysX computeMassPropertiesFromShapes function does not use densities + // to compute the shape's masses, which are needed to calculate the center of mass. + // This differs from updateMassAndInertia function, which uses material density values. + // So the masses used during center of mass calculation do not match the masses + // used during mass/inertia calculation. This is an inconsistency in PhysX. + PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); + return physx::PxRigidBodyExt::computeMassPropertiesFromShapes(pxShapes.data(), static_cast(pxShapes.size())); + }(); + + SetCenterOfMassOffset(PxMathConvert(pxMassProperties.centerOfMass)); } - void RigidBody::ComputeInertia() + void RigidBody::SetInertia(const AZ::Matrix3x3& inertia) { if (m_pxRigidActor) { PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - auto localPose = m_pxRigidActor->getCMassLocalPose().p; - physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, m_pxRigidActor->getMass(), &localPose); + m_pxRigidActor->setMassSpaceInertiaTensor(PxMathConvert(inertia.RetrieveScale())); } } @@ -783,13 +809,4 @@ namespace PhysX { return m_name; } - - void RigidBody::SetZeroCenterOfMass() - { - if (m_pxRigidActor) - { - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->setCMassLocalPose(physx::PxTransform(PxMathConvert(AZ::Vector3::CreateZero()))); - } - } } diff --git a/Gems/PhysX/Code/Source/RigidBody.h b/Gems/PhysX/Code/Source/RigidBody.h index 10f2ebb556..a20f79b161 100644 --- a/Gems/PhysX/Code/Source/RigidBody.h +++ b/Gems/PhysX/Code/Source/RigidBody.h @@ -109,17 +109,15 @@ namespace PhysX void RemoveShape(AZStd::shared_ptr shape) override; void UpdateMassProperties(AzPhysics::MassComputeFlags flags = AzPhysics::MassComputeFlags::DEFAULT, - const AZ::Vector3* centerOfMassOffsetOverride = nullptr, - const AZ::Matrix3x3* inertiaTensorOverride = nullptr, - const float* massOverride = nullptr) override; + const AZ::Vector3& centerOfMassOffsetOverride = AZ::Vector3::CreateZero(), + const AZ::Matrix3x3& inertiaTensorOverride = AZ::Matrix3x3::CreateIdentity(), + const float massOverride = 1.0f) override; private: void CreatePhysXActor(const AzPhysics::RigidBodyConfiguration& configuration); - void UpdateComputedCenterOfMass(); - void ComputeInertia(); + void UpdateCenterOfMass(bool includeAllShapesInMassCalculation); void SetInertia(const AZ::Matrix3x3& inertia); - void SetZeroCenterOfMass(); AZStd::shared_ptr m_pxRigidActor; AZStd::vector> m_shapes; diff --git a/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp index 3b5c98ba2d..86e3ceb98f 100644 --- a/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp +++ b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp @@ -198,8 +198,8 @@ namespace PhysX AZ_Warning("PhysXScene", shapeAdded, "No Collider or Shape information found when creating Rigid body [%s]", configuration->m_debugName.c_str()); } const AzPhysics::MassComputeFlags& flags = configuration->GetMassComputeFlags(); - newBody->UpdateMassProperties(flags, &configuration->m_centerOfMassOffset, - &configuration->m_inertiaTensor, &configuration->m_mass); + newBody->UpdateMassProperties(flags, configuration->m_centerOfMassOffset, + configuration->m_inertiaTensor, configuration->m_mass); crc = AZ::Crc32(newBody, sizeof(*newBody)); return newBody; diff --git a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp index 0c0eee3eb0..9e3a738370 100644 --- a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -1283,11 +1285,13 @@ namespace PhysX EXPECT_TRUE(AZ::IsClose(expectedMass, mass, 0.001f)); } + // Valid material density values: [0.01f, 1e5f] INSTANTIATE_TEST_CASE_P(PhysX, MultiShapesDensityTestFixture, ::testing::Values( - AZStd::make_pair(std::numeric_limits::min(), std::numeric_limits::max()), - AZStd::make_pair(-std::numeric_limits::max(), 0.0f), - AZStd::make_pair(1.0f, 1e9f) + AZStd::make_pair(0.01f, 0.01f), + AZStd::make_pair(1e5f, 1e5f), + AZStd::make_pair(0.01f, 1e5f), + AZStd::make_pair(2364.0f, 10.0f) )); // Fixture for testing extreme density values @@ -1311,6 +1315,7 @@ namespace PhysX && resultingDensity <= Physics::MaterialConfiguration::MaxDensityLimit); } + // Valid material density values: [0.01f, 1e5f] INSTANTIATE_TEST_CASE_P(PhysX, DensityBoundariesTestFixture, ::testing::Values( std::numeric_limits::min(), @@ -1318,7 +1323,9 @@ namespace PhysX -std::numeric_limits::max(), 0.0f, 1.0f, - 1e9f + 1e9f, + 0.01f, + 1e5f )); enum class SimulatedShapesMode @@ -1329,7 +1336,7 @@ namespace PhysX }; class MassComputeFixture - : public ::testing::TestWithParam<::testing::tuple> + : public ::testing::TestWithParam<::testing::tuple> { public: void SetUp() override final @@ -1349,6 +1356,8 @@ namespace PhysX AzPhysics::SimulatedBodyHandle simBodyHandle = sceneInterface->AddSimulatedBody(m_testSceneHandle, &m_rigidBodyConfig); m_rigidBody = azdynamic_cast(sceneInterface->GetSimulatedBodyFromHandle(m_testSceneHandle, simBodyHandle)); } + + ASSERT_TRUE(m_rigidBody != nullptr); } void TearDown() override final @@ -1363,130 +1372,242 @@ namespace PhysX m_rigidBody = nullptr; } - SimulatedShapesMode GetShapesMode() const + Physics::ShapeType GetShapeType() const { return ::testing::get<0>(GetParam()); } - AzPhysics::MassComputeFlags GetMassComputeFlags() const + SimulatedShapesMode GetShapesMode() const { return ::testing::get<1>(GetParam()); } + AzPhysics::MassComputeFlags GetMassComputeFlags() const + { + const AzPhysics::MassComputeFlags massComputeFlags = ::testing::get<2>(GetParam()); + if (IncludeAllShapes()) + { + return massComputeFlags | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES; + } + else + { + return massComputeFlags; + } + } + + bool IncludeAllShapes() const + { + return ::testing::get<3>(GetParam()); + } + bool IsMultiShapeTest() const { - return ::testing::get<2>(GetParam()); + return ::testing::get<4>(GetParam()); } bool IsMassExpectedToChange() const { return m_rigidBodyConfig.m_computeMass && - (!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); + (GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); } bool IsComExpectedToChange() const { return m_rigidBodyConfig.m_computeCenterOfMass && - (!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); + (GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); } bool IsInertiaExpectedToChange() const { return m_rigidBodyConfig.m_computeInertiaTensor && - (!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); + (GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); } + AZStd::shared_ptr CreateShape(const Physics::ColliderConfiguration& colliderConfiguration, Physics::ShapeType shapeType) + { + AZStd::shared_ptr shape; + Physics::System* physics = AZ::Interface::Get(); + switch (shapeType) + { + case Physics::ShapeType::Sphere: + shape = physics->CreateShape(colliderConfiguration, Physics::SphereShapeConfiguration()); + break; + case Physics::ShapeType::Box: + shape = physics->CreateShape(colliderConfiguration, Physics::BoxShapeConfiguration()); + break; + case Physics::ShapeType::Capsule: + shape = physics->CreateShape(colliderConfiguration, Physics::CapsuleShapeConfiguration()); + break; + } + return shape; + }; + AzPhysics::RigidBodyConfiguration m_rigidBodyConfig; - AzPhysics::RigidBody* m_rigidBody; + AzPhysics::RigidBody* m_rigidBody = nullptr; AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle; }; TEST_P(MassComputeFixture, RigidBody_ComputeMassFlagsCombinationsTwoShapes_MassPropertiesCalculatedAccordingly) { - SimulatedShapesMode shapeMode = GetShapesMode(); - AzPhysics::MassComputeFlags massComputeFlags = GetMassComputeFlags(); - bool multiShapeTest = IsMultiShapeTest(); - Physics::System* physics = AZ::Interface::Get(); + const Physics::ShapeType shapeType = GetShapeType(); + const SimulatedShapesMode shapeMode = GetShapesMode(); + const AzPhysics::MassComputeFlags massComputeFlags = GetMassComputeFlags(); + const bool multiShapeTest = IsMultiShapeTest(); // Save initial values - AZ::Vector3 comBefore = m_rigidBody->GetCenterOfMassWorld(); - AZ::Matrix3x3 inertiaBefore = m_rigidBody->GetInverseInertiaWorld(); - float massBefore = m_rigidBody->GetMass(); + const AZ::Vector3 comBefore = m_rigidBody->GetCenterOfMassWorld(); + const AZ::Matrix3x3 inertiaBefore = m_rigidBody->GetInverseInertiaWorld(); + const float massBefore = m_rigidBody->GetMass(); - // Box shape will be simulated for ALL and MIXED shape modes - Physics::ColliderConfiguration boxColliderConfig; - boxColliderConfig.m_isSimulated = + // Shape will be simulated for ALL and MIXED shape modes + Physics::ColliderConfiguration colliderConfig; + colliderConfig.m_isSimulated = (shapeMode == SimulatedShapesMode::ALL || shapeMode == SimulatedShapesMode::MIXED); - boxColliderConfig.m_position = AZ::Vector3(1.0f, 0.0f, 0.0f); + colliderConfig.m_position = AZ::Vector3(1.0f, 0.0f, 0.0f); - AZStd::shared_ptr boxShape = - physics->CreateShape(boxColliderConfig, Physics::BoxShapeConfiguration()); - m_rigidBody->AddShape(boxShape); + AZStd::shared_ptr shape = CreateShape(colliderConfig, shapeType); + m_rigidBody->AddShape(shape); if (multiShapeTest) { // Sphere shape will be simulated only for the ALL shape mode Physics::ColliderConfiguration sphereColliderConfig; sphereColliderConfig.m_isSimulated = (shapeMode == SimulatedShapesMode::ALL); - sphereColliderConfig.m_position = AZ::Vector3(-1.0f, 0.0f, 0.0f); - AZStd::shared_ptr sphereShape = - physics->CreateShape(sphereColliderConfig, Physics::SphereShapeConfiguration()); + sphereColliderConfig.m_position = AZ::Vector3(-2.0f, 0.0f, 0.0f); + AZStd::shared_ptr sphereShape = CreateShape(sphereColliderConfig, Physics::ShapeType::Sphere); m_rigidBody->AddShape(sphereShape); } // Verify swapping materials results in changes in the mass. - m_rigidBody->UpdateMassProperties(massComputeFlags, &m_rigidBodyConfig.m_centerOfMassOffset, - &m_rigidBodyConfig.m_inertiaTensor, &m_rigidBodyConfig.m_mass); + m_rigidBody->UpdateMassProperties(massComputeFlags, m_rigidBodyConfig.m_centerOfMassOffset, + m_rigidBodyConfig.m_inertiaTensor, m_rigidBodyConfig.m_mass); - float massAfter = m_rigidBody->GetMass(); - AZ::Vector3 comAfter = m_rigidBody->GetCenterOfMassWorld(); - AZ::Matrix3x3 inertiaAfter = m_rigidBody->GetInverseInertiaWorld(); + const float massAfter = m_rigidBody->GetMass(); + const AZ::Vector3 comAfter = m_rigidBody->GetCenterOfMassWorld(); + const AZ::Matrix3x3 inertiaAfter = m_rigidBody->GetInverseInertiaWorld(); + using ::testing::Not; + using ::testing::FloatNear; + using ::UnitTest::IsClose; if (IsMassExpectedToChange()) { - EXPECT_FALSE(AZ::IsClose(massBefore, massAfter, FLT_EPSILON)); + EXPECT_THAT(massBefore, Not(FloatNear(massAfter, FLT_EPSILON))); } else { - EXPECT_TRUE(AZ::IsClose(massBefore, massAfter, FLT_EPSILON)); + EXPECT_THAT(massBefore, FloatNear(massAfter, FLT_EPSILON)); } if (IsComExpectedToChange()) { - EXPECT_FALSE(comBefore.IsClose(comAfter)); + EXPECT_THAT(comBefore, Not(IsClose(comAfter))); } else { - EXPECT_TRUE(comBefore.IsClose(comAfter)); + EXPECT_THAT(comBefore, IsClose(comAfter)); } if (IsInertiaExpectedToChange()) { - EXPECT_FALSE(inertiaBefore.IsClose(inertiaAfter)); + EXPECT_THAT(inertiaBefore, Not(IsClose(inertiaAfter))); } else { - EXPECT_TRUE(inertiaBefore.IsClose(inertiaAfter)); + EXPECT_THAT(inertiaBefore, IsClose(inertiaAfter)); } } - AzPhysics::MassComputeFlags possibleMassComputeFlags[] = { - AzPhysics::MassComputeFlags::NONE, AzPhysics::MassComputeFlags::DEFAULT, AzPhysics::MassComputeFlags::COMPUTE_MASS, - AzPhysics::MassComputeFlags::COMPUTE_COM, AzPhysics::MassComputeFlags::COMPUTE_INERTIA, - AzPhysics::MassComputeFlags::DEFAULT | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, - AzPhysics::MassComputeFlags::COMPUTE_COM, AzPhysics::MassComputeFlags::COMPUTE_INERTIA, AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, + static const AzPhysics::MassComputeFlags PossibleMassComputeFlags[] = + { + // No compute + AzPhysics::MassComputeFlags::NONE, + + // Compute Mass only + AzPhysics::MassComputeFlags::COMPUTE_MASS, + + // Compute Inertia only + AzPhysics::MassComputeFlags::COMPUTE_INERTIA, + + // Compute COM only + AzPhysics::MassComputeFlags::COMPUTE_COM, + + // Compute combinations of 2 AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_COM, - AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_INERTIA, - AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_INERTIA | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::COMPUTE_INERTIA, - AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::COMPUTE_INERTIA | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES + + // Compute all + AzPhysics::MassComputeFlags::DEFAULT, // COMPUTE_COM | COMPUTE_INERTIA | COMPUTE_MASS }; INSTANTIATE_TEST_CASE_P(PhysX, MassComputeFixture, ::testing::Combine( - ::testing::ValuesIn({ SimulatedShapesMode::NONE, SimulatedShapesMode::MIXED, SimulatedShapesMode::ALL }), - ::testing::ValuesIn(possibleMassComputeFlags), - ::testing::Bool())); + ::testing::ValuesIn({ Physics::ShapeType::Sphere, Physics::ShapeType::Box, Physics::ShapeType::Capsule }), // Values for GetShapeType() + ::testing::ValuesIn({ SimulatedShapesMode::NONE, SimulatedShapesMode::MIXED, SimulatedShapesMode::ALL }), // Values for GetShapesMode() + ::testing::ValuesIn(PossibleMassComputeFlags), // Values for GetMassComputeFlags() + ::testing::Bool(), // Values for IncludeAllShapes() + ::testing::Bool())); // Values for IsMultiShapeTest() + + class MassPropertiesWithTriangleMesh + : public ::testing::TestWithParam + { + public: + void SetUp() override + { + if (auto* physicsSystem = AZ::Interface::Get()) + { + AzPhysics::SceneConfiguration sceneConfiguration = physicsSystem->GetDefaultSceneConfiguration(); + sceneConfiguration.m_sceneName = AzPhysics::DefaultPhysicsSceneName; + m_testSceneHandle = physicsSystem->AddScene(sceneConfiguration); + } + } + + void TearDown() override + { + // Clean up the Test scene + if (auto* physicsSystem = AZ::Interface::Get()) + { + physicsSystem->RemoveScene(m_testSceneHandle); + } + m_testSceneHandle = AzPhysics::InvalidSceneHandle; + } + + AzPhysics::MassComputeFlags GetMassComputeFlags() const + { + return GetParam(); + } + + AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle; + }; + + TEST_P(MassPropertiesWithTriangleMesh, KinematicRigidBody_ComputeMassProperties_TriggersWarnings) + { + const AzPhysics::MassComputeFlags flags = GetMassComputeFlags(); + + const bool doesComputeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM); + const bool doesComputeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS); + const bool doesComputeInertia = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA); + + UnitTest::ErrorHandler computeCenterOfMassWarningHandler( + "cannot compute COM"); + UnitTest::ErrorHandler computeMassWarningHandler( + "cannot compute Mass"); + UnitTest::ErrorHandler computeIneriaWarningHandler( + "cannot compute Inertia"); + + AzPhysics::SimulatedBodyHandle rigidBodyhandle = TestUtils::AddKinematicTriangleMeshCubeToScene(m_testSceneHandle, 3.0f, flags); + + EXPECT_TRUE(rigidBodyhandle != AzPhysics::InvalidSimulatedBodyHandle); + EXPECT_EQ(computeCenterOfMassWarningHandler.GetExpectedWarningCount(), doesComputeCenterOfMass ? 1 : 0); + EXPECT_EQ(computeMassWarningHandler.GetExpectedWarningCount(), doesComputeMass ? 1 : 0); + EXPECT_EQ(computeIneriaWarningHandler.GetExpectedWarningCount(), doesComputeInertia ? 1 : 0); + + if (auto* sceneInterface = AZ::Interface::Get()) + { + sceneInterface->RemoveSimulatedBody(m_testSceneHandle, rigidBodyhandle); + } + } + INSTANTIATE_TEST_CASE_P(PhysX, MassPropertiesWithTriangleMesh, + ::testing::ValuesIn(PossibleMassComputeFlags)); // Values for GetMassComputeFlags() } // namespace PhysX diff --git a/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp b/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp index 6186db6f1e..67fe67bc23 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp +++ b/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp @@ -253,6 +253,36 @@ namespace PhysX return AzPhysics::InvalidSimulatedBodyHandle; } + AzPhysics::SimulatedBodyHandle AddKinematicTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent, AzPhysics::MassComputeFlags massComputeFlags) + { + // Generate input data + VertexIndexData cubeMeshData = GenerateCubeMeshData(halfExtent); + AZStd::vector cookedData; + bool cookingResult = false; + Physics::SystemRequestBus::BroadcastResult(cookingResult, &Physics::SystemRequests::CookTriangleMeshToMemory, + cubeMeshData.first.data(), static_cast(cubeMeshData.first.size()), + cubeMeshData.second.data(), static_cast(cubeMeshData.second.size()), + cookedData); + AZ_Assert(cookingResult, "Failed to cook the cube mesh."); + + // Setup shape & collider configurations + auto shapeConfig = AZStd::make_shared(); + shapeConfig->SetCookedMeshData(cookedData.data(), cookedData.size(), + Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh); + + AzPhysics::RigidBodyConfiguration rigidBodyConfiguration; + rigidBodyConfiguration.m_kinematic = true; + rigidBodyConfiguration.SetMassComputeFlags(massComputeFlags); + rigidBodyConfiguration.m_colliderAndShapeData = AzPhysics::ShapeColliderPair( + AZStd::make_shared(), shapeConfig); + + if (auto* sceneInterface = AZ::Interface::Get()) + { + return sceneInterface->AddSimulatedBody(scene, &rigidBodyConfiguration); + } + return AzPhysics::InvalidSimulatedBodyHandle; + } + void SetCollisionLayer(EntityPtr& entity, const AZStd::string& layerName, const AZStd::string& colliderTag) { Physics::CollisionFilteringRequestBus::Event(entity->GetId(), &Physics::CollisionFilteringRequests::SetCollisionLayer, layerName, AZ::Crc32(colliderTag.c_str())); diff --git a/Gems/PhysX/Code/Tests/PhysXTestCommon.h b/Gems/PhysX/Code/Tests/PhysXTestCommon.h index ef12ca8350..95859a3f86 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestCommon.h +++ b/Gems/PhysX/Code/Tests/PhysXTestCommon.h @@ -89,6 +89,7 @@ namespace PhysX const AzPhysics::CollisionLayer& layer = AzPhysics::CollisionLayer::Default); AzPhysics::SimulatedBodyHandle AddStaticTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent); + AzPhysics::SimulatedBodyHandle AddKinematicTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent, AzPhysics::MassComputeFlags massComputeFlags); // Collision Filtering void SetCollisionLayer(EntityPtr& entity, const AZStd::string& layerName, const AZStd::string& colliderTag = ""); diff --git a/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp b/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp index a7e6b6c707..18bddfa26f 100644 --- a/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp +++ b/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp @@ -91,6 +91,11 @@ namespace WhiteBox bodyConfiguration.m_position = worldTransform.GetTranslation(); bodyConfiguration.m_kinematic = true; // note: this field is ignored in the WhiteBoxBodyType::Static case bodyConfiguration.m_colliderAndShapeData = shape; + // Since the shape used is a triangle mesh the COM, Mass and Inertia + // cannot be computed. Disable them to use default values. + bodyConfiguration.m_computeCenterOfMass = false; + bodyConfiguration.m_computeMass = false; + bodyConfiguration.m_computeInertiaTensor = false; m_simulatedBodyHandle = sceneInterface->AddSimulatedBody(defaultScene, &bodyConfiguration); } break; From f7eb906516644d3e628f739d33324f89460da4da Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Fri, 15 Oct 2021 10:55:41 +0200 Subject: [PATCH 279/293] Moved Max Number of Entries Shown in Asset Browser Search View to EditorViewportSettings (#4660) * removed references to maxNumberOfItemsShownInSearch Signed-off-by: igarri * Move Max Number of Entries Shown in Asset Browser Search View to EditorViewportSettings Signed-off-by: igarri * Fixed extra spaces Signed-off-by: igarri * Code review feedback Signed-off-by: igarri --- Code/Editor/EditorPreferencesPageFiles.cpp | 22 ++++++++++--------- Code/Editor/EditorPreferencesPageFiles.h | 11 ++++------ Code/Editor/EditorViewportSettings.cpp | 11 ++++++++++ Code/Editor/EditorViewportSettings.h | 3 +++ Code/Editor/Settings.cpp | 7 +++--- Code/Editor/Settings.h | 10 +-------- .../AssetBrowser/AssetBrowserTableModel.h | 2 +- .../Editor/EditorSettingsAPIBus.h | 2 +- 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Code/Editor/EditorPreferencesPageFiles.cpp b/Code/Editor/EditorPreferencesPageFiles.cpp index 4be3269d42..c3423c4e5b 100644 --- a/Code/Editor/EditorPreferencesPageFiles.cpp +++ b/Code/Editor/EditorPreferencesPageFiles.cpp @@ -14,6 +14,7 @@ // Editor #include "Settings.h" +#include "EditorViewportSettings.h" @@ -43,17 +44,16 @@ void CEditorPreferencesPage_Files::Reflect(AZ::SerializeContext& serialize) ->Field("MaxCount", &AutoBackup::m_maxCount) ->Field("RemindTime", &AutoBackup::m_remindTime); - serialize.Class() + serialize.Class() ->Version(1) - ->Field("Max number of items displayed", &AssetBrowserSearch::m_maxNumberOfItemsShownInSearch); + ->Field("MaxEntriesShownCount", &AssetBrowserSettings::m_maxNumberOfItemsShownInSearch); serialize.Class() ->Version(1) ->Field("Files", &CEditorPreferencesPage_Files::m_files) ->Field("Editors", &CEditorPreferencesPage_Files::m_editors) ->Field("AutoBackup", &CEditorPreferencesPage_Files::m_autoBackup) - ->Field("AssetBrowserSearch", &CEditorPreferencesPage_Files::m_assetBrowserSearch); - + ->Field("AssetBrowserSettings", &CEditorPreferencesPage_Files::m_assetBrowserSettings); AZ::EditContext* editContext = serialize.GetEditContext(); if (editContext) @@ -85,9 +85,10 @@ void CEditorPreferencesPage_Files::Reflect(AZ::SerializeContext& serialize) ->Attribute(AZ::Edit::Attributes::Max, 100) ->DataElement(AZ::Edit::UIHandlers::SpinBox, &AutoBackup::m_remindTime, "Remind Time", "Auto Remind Every (Minutes)"); - editContext->Class("Asset Browser Search View", "Asset Browser Search View") - ->DataElement(AZ::Edit::UIHandlers::SpinBox, &AssetBrowserSearch::m_maxNumberOfItemsShownInSearch, "Maximum number of displayed items", - "Maximum number of displayed items displayed in the Search View") + editContext->Class("Asset Browser Settings", "Asset Browser Settings") + ->DataElement( + AZ::Edit::UIHandlers::SpinBox, &AssetBrowserSettings::m_maxNumberOfItemsShownInSearch, "Maximum number of displayed items", + "Maximum number of items to display in the Search View.") ->Attribute(AZ::Edit::Attributes::Min, 50) ->Attribute(AZ::Edit::Attributes::Max, 5000); @@ -97,7 +98,7 @@ void CEditorPreferencesPage_Files::Reflect(AZ::SerializeContext& serialize) ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_Files::m_files, "Files", "File Preferences") ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_Files::m_editors, "External Editors", "External Editors") ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_Files::m_autoBackup, "Auto Backup", "Auto Backup") - ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_Files::m_assetBrowserSearch, "Asset Browser Search", "Asset Browser Search"); + ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_Files::m_assetBrowserSettings, "Asset Browser Settings","Asset Browser Settings"); } } @@ -117,6 +118,7 @@ QIcon& CEditorPreferencesPage_Files::GetIcon() void CEditorPreferencesPage_Files::OnApply() { using namespace AzToolsFramework::SliceUtilities; + auto sliceSettings = AZ::UserSettings::CreateFind(AZ_CRC("SliceUserSettings", 0x055b32eb), AZ::UserSettings::CT_LOCAL); sliceSettings->m_autoNumber = m_files.m_autoNumberSlices; sliceSettings->m_saveLocation = m_files.m_saveLocation; @@ -137,7 +139,7 @@ void CEditorPreferencesPage_Files::OnApply() gSettings.autoBackupMaxCount = m_autoBackup.m_maxCount; gSettings.autoRemindTime = m_autoBackup.m_remindTime; - gSettings.maxNumberOfItemsShownInSearch = m_assetBrowserSearch.m_maxNumberOfItemsShownInSearch; + SandboxEditor::SetMaxItemsShownInAssetBrowserSearch(m_assetBrowserSettings.m_maxNumberOfItemsShownInSearch); } void CEditorPreferencesPage_Files::InitializeSettings() @@ -163,5 +165,5 @@ void CEditorPreferencesPage_Files::InitializeSettings() m_autoBackup.m_maxCount = gSettings.autoBackupMaxCount; m_autoBackup.m_remindTime = gSettings.autoRemindTime; - m_assetBrowserSearch.m_maxNumberOfItemsShownInSearch = gSettings.maxNumberOfItemsShownInSearch; + m_assetBrowserSettings.m_maxNumberOfItemsShownInSearch = SandboxEditor::MaxItemsShownInAssetBrowserSearch(); } diff --git a/Code/Editor/EditorPreferencesPageFiles.h b/Code/Editor/EditorPreferencesPageFiles.h index 368cd91fc3..9022032edc 100644 --- a/Code/Editor/EditorPreferencesPageFiles.h +++ b/Code/Editor/EditorPreferencesPageFiles.h @@ -69,18 +69,15 @@ private: int m_remindTime; }; - struct AssetBrowserSearch + struct AssetBrowserSettings { - AZ_TYPE_INFO(AssetBrowserSearch, "{9FBFCD24-9452-49DF-99F4-2711443CEAAE}") - - int m_maxNumberOfItemsShownInSearch; + AZ_TYPE_INFO(AssetBrowserSettings, "{5F407EC4-BBD1-4A87-92DB-D938D7127BB0}") + AZ::u64 m_maxNumberOfItemsShownInSearch; }; Files m_files; ExternalEditors m_editors; AutoBackup m_autoBackup; - AssetBrowserSearch m_assetBrowserSearch; + AssetBrowserSettings m_assetBrowserSettings; QIcon m_icon; }; - - diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index 2354c6d63a..2b54622d1c 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -15,6 +15,7 @@ namespace SandboxEditor { + constexpr AZStd::string_view AssetBrowserMaxItemsShownInSearchSetting = "/Amazon/Preferences/Editor/AssetBrowser/MaxItemsShowInSearch"; constexpr AZStd::string_view GridSnappingSetting = "/Amazon/Preferences/Editor/GridSnapping"; constexpr AZStd::string_view GridSizeSetting = "/Amazon/Preferences/Editor/GridSize"; constexpr AZStd::string_view AngleSnappingSetting = "/Amazon/Preferences/Editor/AngleSnapping"; @@ -110,6 +111,16 @@ namespace SandboxEditor return AZStd::make_unique(); } + AZ::u64 MaxItemsShownInAssetBrowserSearch() + { + return GetRegistry(AssetBrowserMaxItemsShownInSearchSetting, aznumeric_cast(50)); + } + + void SetMaxItemsShownInAssetBrowserSearch(const AZ::u64 numberOfItemsShown) + { + SetRegistry(AssetBrowserMaxItemsShownInSearchSetting, numberOfItemsShown); + } + bool GridSnappingEnabled() { return GetRegistry(GridSnappingSetting, false); diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index c1394f7404..c6f51cf461 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -32,6 +32,9 @@ namespace SandboxEditor //! event will fire when a value in the settings registry (editorpreferences.setreg) is modified. SANDBOX_API AZStd::unique_ptr CreateEditorViewportSettingsCallbacks(); + SANDBOX_API AZ::u64 MaxItemsShownInAssetBrowserSearch(); + SANDBOX_API void SetMaxItemsShownInAssetBrowserSearch(AZ::u64 numberOfItemsShown); + SANDBOX_API bool GridSnappingEnabled(); SANDBOX_API void SetGridSnapping(bool enabled); diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index 47743d1c42..d548cffb52 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -10,6 +10,7 @@ #include "EditorDefs.h" #include "Settings.h" +#include "EditorViewportSettings.h" // Qt #include @@ -487,7 +488,6 @@ void SEditorSettings::Save() SaveValue("Settings", "AutoBackupTime", autoBackupTime); SaveValue("Settings", "AutoBackupMaxCount", autoBackupMaxCount); SaveValue("Settings", "AutoRemindTime", autoRemindTime); - SaveValue("Settings", "MaxDisplayedItemsNumInSearch", maxNumberOfItemsShownInSearch); SaveValue("Settings", "CameraMoveSpeed", cameraMoveSpeed); SaveValue("Settings", "CameraRotateSpeed", cameraRotateSpeed); SaveValue("Settings", "StylusMode", stylusMode); @@ -682,7 +682,6 @@ void SEditorSettings::Load() LoadValue("Settings", "AutoBackupTime", autoBackupTime); LoadValue("Settings", "AutoBackupMaxCount", autoBackupMaxCount); LoadValue("Settings", "AutoRemindTime", autoRemindTime); - LoadValue("Settings", "MaxDisplayedItemsNumInSearch", maxNumberOfItemsShownInSearch); LoadValue("Settings", "CameraMoveSpeed", cameraMoveSpeed); LoadValue("Settings", "CameraRotateSpeed", cameraRotateSpeed); LoadValue("Settings", "StylusMode", stylusMode); @@ -1174,7 +1173,7 @@ AzToolsFramework::ConsoleColorTheme SEditorSettings::GetConsoleColorTheme() cons return consoleBackgroundColorTheme; } -int SEditorSettings::GetMaxNumberOfItemsShownInSearchView() const +AZ::u64 SEditorSettings::GetMaxNumberOfItemsShownInSearchView() const { - return SEditorSettings::maxNumberOfItemsShownInSearch; + return SandboxEditor::MaxItemsShownInAssetBrowserSearch(); } diff --git a/Code/Editor/Settings.h b/Code/Editor/Settings.h index 8bf22b43e5..426d2300d3 100644 --- a/Code/Editor/Settings.h +++ b/Code/Editor/Settings.h @@ -279,7 +279,7 @@ AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING SettingOutcome GetValue(const AZStd::string_view path) override; SettingOutcome SetValue(const AZStd::string_view path, const AZStd::any& value) override; AzToolsFramework::ConsoleColorTheme GetConsoleColorTheme() const override; - int GetMaxNumberOfItemsShownInSearchView() const override; + AZ::u64 GetMaxNumberOfItemsShownInSearchView() const override; void ConvertPath(const AZStd::string_view sourcePath, AZStd::string& category, AZStd::string& attribute); @@ -353,14 +353,6 @@ AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING int autoRemindTime; ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - // Asset Browser Search View. - ////////////////////////////////////////////////////////////////////////// - //! Current maximum number of items that can be displayed in the AssetBrowser Search View. - int maxNumberOfItemsShownInSearch; - ////////////////////////////////////////////////////////////////////////// - - //! If true preview windows is displayed when browsing geometries. bool bPreviewGeometryWindow; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h index 55dcbb1532..f84e6bd81c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h @@ -53,7 +53,7 @@ namespace AzToolsFramework private slots: void SourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); private: - int m_numberOfItemsDisplayed = 50; + AZ::u64 m_numberOfItemsDisplayed = 0; int m_displayedItemsCounter = 0; QPointer m_filterModel; QMap m_indexMap; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorSettingsAPIBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorSettingsAPIBus.h index fedb889fbb..52d8395377 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorSettingsAPIBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/EditorSettingsAPIBus.h @@ -38,7 +38,7 @@ namespace AzToolsFramework virtual SettingOutcome GetValue(const AZStd::string_view path) = 0; virtual SettingOutcome SetValue(const AZStd::string_view path, const AZStd::any& value) = 0; virtual ConsoleColorTheme GetConsoleColorTheme() const = 0; - virtual int GetMaxNumberOfItemsShownInSearchView() const = 0; + virtual AZ::u64 GetMaxNumberOfItemsShownInSearchView() const = 0; }; using EditorSettingsAPIBus = AZ::EBus; From 606de5427b161d7cad7e1abfc0b5f10c7f7938c8 Mon Sep 17 00:00:00 2001 From: ffarahmand-DPS Date: Fri, 15 Oct 2021 02:30:48 -0700 Subject: [PATCH 280/293] Fixes debug console autocomplete issues (#4223) * Fixed a crash caused by large autocomplete results in the debug console. A fixed vector was growing beyond its allocated size. Signed-off-by: ffarahmand-DPS * Fixes printing duplicate autocomplete results, caused by looping over multiple CVARs registered with the same name. Also adds an erase to prevent undefined behavior. Signed-off-by: ffarahmand-DPS * Adds a test case for autocomplete duplication in the event of multiple cvars existing under the same name. Two matching cvars are created and checked against the number of matches produced by autocomplete. Signed-off-by: ffarahmand-DPS * Added two safety checks and made a pointer const as per reviewer feedback. Signed-off-by: ffarahmand-DPS --- .../AzCore/AzCore/Console/Console.cpp | 27 ++++++++++++++++--- .../AzCore/Tests/Console/ConsoleTests.cpp | 15 +++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Console/Console.cpp b/Code/Framework/AzCore/AzCore/Console/Console.cpp index 9f207d9afd..79e1f79697 100644 --- a/Code/Framework/AzCore/AzCore/Console/Console.cpp +++ b/Code/Framework/AzCore/AzCore/Console/Console.cpp @@ -225,8 +225,16 @@ namespace AZ ConsoleCommandContainer commandSubset; - for (ConsoleFunctorBase* curr = m_head; curr != nullptr; curr = curr->m_next) + for (const auto& functor : m_commands) { + if (functor.second.empty()) + { + continue; + } + + // Filter functors registered with the same name + const ConsoleFunctorBase* curr = functor.second.front(); + if ((curr->GetFlags() & ConsoleFunctorFlags::IsInvisible) == ConsoleFunctorFlags::IsInvisible) { // Filter functors marked as invisible @@ -236,7 +244,12 @@ namespace AZ if (StringFunc::StartsWith(curr->m_name, command, false)) { AZLOG_INFO("- %s : %s\n", curr->m_name, curr->m_desc); - commandSubset.push_back(curr->m_name); + + if (commandSubset.size() < MaxConsoleCommandPlusArgsLength) + { + commandSubset.push_back(curr->m_name); + } + if (matches) { matches->push_back(curr->m_name); @@ -271,7 +284,10 @@ namespace AZ { for (auto& curr : m_commands) { - visitor(curr.second.front()); + if (!curr.second.empty()) + { + visitor(curr.second.front()); + } } } @@ -336,6 +352,11 @@ namespace AZ { iter->second.erase(iter2); } + + if (iter->second.empty()) + { + m_commands.erase(iter); + } } functor->Unlink(m_head); functor->m_console = nullptr; diff --git a/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp b/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp index d91ec5ba58..e01129a7bc 100644 --- a/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp +++ b/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp @@ -288,6 +288,21 @@ namespace AZ AZStd::string completeCommand = console->AutoCompleteCommand("testVec3"); AZ_TEST_ASSERT(completeCommand == "testVec3"); } + + // Duplicate names + { + // Register two cvars with the same name + auto id = AZ::TypeId(); + auto flag = AZ::ConsoleFunctorFlags::Null; + auto signature = AZ::ConsoleFunctor::FunctorSignature(); + AZ::ConsoleFunctor cvarOne(*console, "testAutoCompleteDuplication", "", flag, id, signature); + AZ::ConsoleFunctor cvarTwo(*console, "testAutoCompleteDuplication", "", flag, id, signature); + + // Autocomplete given name expecting one match (not two) + AZStd::vector matches; + AZStd::string completeCommand = console->AutoCompleteCommand("testAutoCompleteD", &matches); + AZ_TEST_ASSERT(matches.size() == 1 && completeCommand == "testAutoCompleteDuplication"); + } } TEST_F(ConsoleTests, ConsoleFunctor_FreeFunctorExecutionTest) From 5c8a1b573e8520315b093700626e73022861d547 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Fri, 15 Oct 2021 12:56:05 +0100 Subject: [PATCH 281/293] Add support for border in Focus Mode (#4692) * restore component mode border Signed-off-by: hultonha * add viewport border for focus mode, remove dead code in ObjectManager Signed-off-by: hultonha * ensure the focus mode border is restored when leaving component mode Signed-off-by: hultonha * update FocusModeNotification call order after merge from development Signed-off-by: hultonha --- Code/Editor/Objects/ObjectManager.cpp | 35 ----------- Code/Editor/Objects/ObjectManager.h | 8 --- ...ViewportEditorModeTrackerNotificationBus.h | 10 ++-- .../ComponentMode/ComponentModeCollection.cpp | 52 ++++++++++++++++ .../ComponentMode/EditorBaseComponentMode.cpp | 2 +- .../FocusMode/FocusModeSystemComponent.cpp | 11 ++-- .../EditorTransformComponentSelection.cpp | 59 +++++++++++++++---- .../ViewportUi/ViewportUiDisplay.cpp | 8 ++- .../ViewportUi/ViewportUiDisplay.h | 4 +- .../ViewportUi/ViewportUiManager.cpp | 8 +-- .../ViewportUi/ViewportUiManager.h | 4 +- .../ViewportUi/ViewportUiRequestBus.h | 10 ++-- 12 files changed, 130 insertions(+), 81 deletions(-) diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp index 7057cc5b7b..ee7e9a8e96 100644 --- a/Code/Editor/Objects/ObjectManager.cpp +++ b/Code/Editor/Objects/ObjectManager.cpp @@ -108,15 +108,11 @@ CObjectManager::CObjectManager() m_objectsByName.reserve(1024); LoadRegistry(); - - AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); } ////////////////////////////////////////////////////////////////////////// CObjectManager::~CObjectManager() { - AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); - m_bExiting = true; SaveRegistry(); DeleteAllObjects(); @@ -2307,37 +2303,6 @@ void CObjectManager::SelectObjectInRect(CBaseObject* pObj, CViewport* view, HitC } } -void CObjectManager::OnEditorModeActivated( - [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) -{ - if (mode == AzToolsFramework::ViewportEditorMode::Component) - { - // hide current gizmo for entity (translate/rotate/scale) - IGizmoManager* gizmoManager = GetGizmoManager(); - const size_t gizmoCount = static_cast(gizmoManager->GetGizmoCount()); - for (size_t i = 0; i < gizmoCount; ++i) - { - gizmoManager->RemoveGizmo(gizmoManager->GetGizmoByIndex(static_cast(i))); - } - } -} - -void CObjectManager::OnEditorModeDeactivated( - [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) -{ - if (mode == AzToolsFramework::ViewportEditorMode::Component) - { - // show translate/rotate/scale gizmo again - if (IGizmoManager* gizmoManager = GetGizmoManager()) - { - if (CBaseObject* selectedObject = GetIEditor()->GetSelectedObject()) - { - gizmoManager->AddGizmo(new CAxisGizmo(selectedObject)); - } - } - } -} - ////////////////////////////////////////////////////////////////////////// namespace { diff --git a/Code/Editor/Objects/ObjectManager.h b/Code/Editor/Objects/ObjectManager.h index 7fb2342e40..7389dfa6a1 100644 --- a/Code/Editor/Objects/ObjectManager.h +++ b/Code/Editor/Objects/ObjectManager.h @@ -20,7 +20,6 @@ #include "ObjectManagerEventBus.h" #include -#include #include #include #include @@ -59,7 +58,6 @@ public: */ class CObjectManager : public IObjectManager - , private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler { public: //! Selection functor callback. @@ -330,12 +328,6 @@ private: void FindDisplayableObjects(DisplayContext& dc, bool bDisplay); - // ViewportEditorModeNotificationsBus overrides ... - void OnEditorModeActivated( - const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; - void OnEditorModeDeactivated( - const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; - private: typedef std::map Objects; Objects m_objects; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index 4fb4191d45..966b9f8478 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -43,8 +43,7 @@ namespace AzToolsFramework }; //! Provides a bus to notify when the different editor modes are entered/exit. - class ViewportEditorModeNotifications - : public AZ::EBusTraits + class ViewportEditorModeNotifications : public AZ::EBusTraits { public: ////////////////////////////////////////////////////////////////////////// @@ -58,14 +57,17 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); //! Notifies subscribers of the a given viewport to the activation of the specified editor mode. - virtual void OnEditorModeActivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeActivated( + [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } //! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode. - virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeDeactivated( + [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; + using ViewportEditorModeNotificationsBus = AZ::EBus; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 1768cb5920..07e025fc60 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -137,6 +137,7 @@ namespace AzToolsFramework if (componentTypeIt == m_activeComponentTypes.end()) { m_activeComponentTypes.push_back(componentType); + m_viewportUiHandlers.emplace_back(componentType); } // see if we already have a ComponentModeBuilder for the specific component on this entity @@ -225,6 +226,7 @@ namespace AzToolsFramework if (!m_entitiesAndComponentModes.empty()) { RefreshActions(); + PopulateViewportUi(); } // if entering ComponentMode not as an undo/redo step (an action was @@ -285,6 +287,10 @@ namespace AzToolsFramework componentModeCommand.release(); } + // remove the component mode viewport border + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveViewportBorder); + // notify listeners the editor has left ComponentMode - listeners may // wish to modify state to indicate this (e.g. appearance, functionality etc.) m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Component); @@ -301,6 +307,7 @@ namespace AzToolsFramework } m_entitiesAndComponentModeBuilders.clear(); m_activeComponentTypes.clear(); + m_viewportUiHandlers.clear(); m_componentMode = false; m_selectedComponentModeIndex = 0; @@ -385,6 +392,24 @@ namespace AzToolsFramework return m_activeComponentTypes.size() > 1; } + static ComponentModeViewportUi* FindViewportUiHandlerForType( + AZStd::vector& viewportUiHandlers, const AZ::Uuid& componentType) + { + auto handler = AZStd::find_if( + viewportUiHandlers.begin(), viewportUiHandlers.end(), + [componentType](const ComponentModeViewportUi& handler) + { + return handler.GetComponentType() == componentType; + }); + + if (handler == viewportUiHandlers.end()) + { + return nullptr; + } + + return handler; + } + bool ComponentModeCollection::ActiveComponentModeChanged(const AZ::Uuid& previousComponentType) { if (m_activeComponentTypes[m_selectedComponentModeIndex] != previousComponentType) @@ -410,6 +435,20 @@ namespace AzToolsFramework // replace the current component mode by invoking the builder // for the new 'active' component mode componentMode.m_componentMode = componentModeBuilder->m_componentModeBuilder(); + + // populate the viewport UI with the new component mode + PopulateViewportUi(); + + // set the appropriate viewportUiHandler to active + if (auto viewportUiHandler = + FindViewportUiHandlerForType(m_viewportUiHandlers, m_activeComponentTypes[m_selectedComponentModeIndex])) + { + viewportUiHandler->SetComponentModeViewportUiActive(true); + } + + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, + componentMode.m_componentMode->GetComponentModeName().c_str()); } RefreshActions(); @@ -519,5 +558,18 @@ namespace AzToolsFramework } } + void ComponentModeCollection::PopulateViewportUi() + { + // update viewport UI for new component type + if (m_selectedComponentModeIndex < m_activeComponentTypes.size()) + { + // iterate over all entities and their active Component Mode, populate viewport UI for the new mode + for (auto& entityAndComponentMode : m_entitiesAndComponentModes) + { + // build viewport UI based on current state + entityAndComponentMode.m_componentMode->PopulateViewportUi(); + } + } + } } // namespace ComponentModeFramework } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp index 9e043a5c86..f449478306 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp @@ -55,7 +55,7 @@ namespace AzToolsFramework GetEntityComponentIdPair(), elementIdsToDisplay); // create the component mode border with the specific name for this component mode ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateComponentModeBorder, + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, GetComponentModeName()); // set the EntityComponentId for this ComponentMode to active in the ComponentModeViewportUi system ComponentModeViewportUiRequestBus::Event( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp index f592c471d0..44ff603c0c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp @@ -71,12 +71,7 @@ namespace AzToolsFramework return; } - AZ::EntityId previousFocusEntityId = m_focusRoot; - m_focusRoot = entityId; - FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, previousFocusEntityId, m_focusRoot); - - if (auto tracker = AZ::Interface::Get(); - tracker != nullptr) + if (auto tracker = AZ::Interface::Get()) { if (!m_focusRoot.IsValid() && entityId.IsValid()) { @@ -87,6 +82,10 @@ namespace AzToolsFramework tracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Focus); } } + + AZ::EntityId previousFocusEntityId = m_focusRoot; + m_focusRoot = entityId; + FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, previousFocusEntityId, m_focusRoot); } void FocusModeSystemComponent::ClearFocusRoot([[maybe_unused]] AzFramework::EntityContextId entityContextId) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index d5a0595049..a37b84fdf8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -3663,26 +3663,63 @@ namespace AzToolsFramework void EditorTransformComponentSelection::OnEditorModeActivated( [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) { - if (mode == ViewportEditorMode::Component) + switch (mode) { - SetAllViewportUiVisible(false); + case ViewportEditorMode::Component: + { + SetAllViewportUiVisible(false); - EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); - EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); - ToolsApplicationNotificationBus::Handler::BusDisconnect(); + EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); + EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); + ToolsApplicationNotificationBus::Handler::BusDisconnect(); + } + break; + case ViewportEditorMode::Focus: + { + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, "Focus Mode"); + } + break; + case ViewportEditorMode::Default: + case ViewportEditorMode::Pick: + // noop + break; } } void EditorTransformComponentSelection::OnEditorModeDeactivated( - [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + const ViewportEditorModesInterface& editorModeState, const ViewportEditorMode mode) { - if (mode == ViewportEditorMode::Component) + switch (mode) { - SetAllViewportUiVisible(true); + case ViewportEditorMode::Component: + { + SetAllViewportUiVisible(true); + + ToolsApplicationNotificationBus::Handler::BusConnect(); + EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); + EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); - ToolsApplicationNotificationBus::Handler::BusConnect(); - EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); - EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); + // note: when leaving component mode, we check if we're still in focus mode (i.e. component mode was + // started from within focus mode), if we are, ensure we create/update the viewport border (as leaving + // component mode will attempt to remove it) + if (editorModeState.IsModeActive(ViewportEditorMode::Focus)) + { + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, "Focus Mode"); + } + } + break; + case ViewportEditorMode::Focus: + { + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveViewportBorder); + } + break; + case ViewportEditorMode::Default: + case ViewportEditorMode::Pick: + // noop + break; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index e27627eab6..a289d914d6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -290,9 +290,9 @@ namespace AzToolsFramework::ViewportUi::Internal return false; } - void ViewportUiDisplay::CreateComponentModeBorder(const AZStd::string& borderTitle) + void ViewportUiDisplay::CreateViewportBorder(const AZStd::string& borderTitle) { - AZStd::string styleSheet = AZStd::string::format( + const AZStd::string styleSheet = AZStd::string::format( "border: %dpx solid %s; border-top: %dpx solid %s;", HighlightBorderSize, HighlightBorderColor, TopHighlightBorderSize, HighlightBorderColor); m_uiOverlay.setStyleSheet(styleSheet.c_str()); @@ -303,7 +303,7 @@ namespace AzToolsFramework::ViewportUi::Internal m_componentModeBorderText.setText(borderTitle.c_str()); } - void ViewportUiDisplay::RemoveComponentModeBorder() + void ViewportUiDisplay::RemoveViewportBorder() { m_componentModeBorderText.setVisible(false); m_uiOverlay.setStyleSheet("border: none;"); @@ -420,6 +420,7 @@ namespace AzToolsFramework::ViewportUi::Internal m_uiMainWindow.setVisible(true); m_uiOverlay.setVisible(true); } + m_uiMainWindow.setMask(region); } @@ -437,6 +438,7 @@ namespace AzToolsFramework::ViewportUi::Internal { return element->second; } + return ViewportUiElementInfo{ nullptr, InvalidViewportUiElementId, false }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h index aafaf61ff3..5020241815 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h @@ -89,8 +89,8 @@ namespace AzToolsFramework::ViewportUi::Internal AZStd::shared_ptr GetViewportUiElement(ViewportUiElementId elementId); bool IsViewportUiElementVisible(ViewportUiElementId elementId); - void CreateComponentModeBorder(const AZStd::string& borderTitle); - void RemoveComponentModeBorder(); + void CreateViewportBorder(const AZStd::string& borderTitle); + void RemoveViewportBorder(); private: void PrepareWidgetForViewportUi(QPointer widget); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp index 255d11f561..1f14b12b7d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp @@ -240,14 +240,14 @@ namespace AzToolsFramework::ViewportUi } } - void ViewportUiManager::CreateComponentModeBorder(const AZStd::string& borderTitle) + void ViewportUiManager::CreateViewportBorder(const AZStd::string& borderTitle) { - m_viewportUi->CreateComponentModeBorder(borderTitle); + m_viewportUi->CreateViewportBorder(borderTitle); } - void ViewportUiManager::RemoveComponentModeBorder() + void ViewportUiManager::RemoveViewportBorder() { - m_viewportUi->RemoveComponentModeBorder(); + m_viewportUi->RemoveViewportBorder(); } void ViewportUiManager::PressButton(ClusterId clusterId, ButtonId buttonId) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h index 9ec6648451..ce7e5aafe9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h @@ -50,8 +50,8 @@ namespace AzToolsFramework::ViewportUi void RegisterTextFieldCallback(TextFieldId textFieldId, AZ::Event::Handler& handler) override; void RemoveTextField(TextFieldId textFieldId) override; void SetTextFieldVisible(TextFieldId textFieldId, bool visible) override; - void CreateComponentModeBorder(const AZStd::string& borderTitle) override; - void RemoveComponentModeBorder() override; + void CreateViewportBorder(const AZStd::string& borderTitle) override; + void RemoveViewportBorder() override; void PressButton(ClusterId clusterId, ButtonId buttonId) override; void PressButton(SwitcherId switcherId, ButtonId buttonId) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h index 108d23950a..3c6f7094cb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h @@ -78,7 +78,7 @@ namespace AzToolsFramework::ViewportUi virtual void RegisterSwitcherEventHandler(SwitcherId switcherId, AZ::Event::Handler& handler) = 0; //! Removes a cluster from the Viewport UI system. virtual void RemoveCluster(ClusterId clusterId) = 0; - //! + //! Removes a switcher from the Viewport UI system. virtual void RemoveSwitcher(SwitcherId switcherId) = 0; //! Sets the visibility of the cluster. virtual void SetClusterVisible(ClusterId clusterId, bool visible) = 0; @@ -96,12 +96,12 @@ namespace AzToolsFramework::ViewportUi //! Sets the visibility of the text field. virtual void SetTextFieldVisible(TextFieldId textFieldId, bool visible) = 0; //! Create the highlight border for Component Mode. - virtual void CreateComponentModeBorder(const AZStd::string& borderTitle) = 0; + virtual void CreateViewportBorder(const AZStd::string& borderTitle) = 0; //! Remove the highlight border for Component Mode. - virtual void RemoveComponentModeBorder() = 0; - //! Invoke a button press in a cluster. + virtual void RemoveViewportBorder() = 0; + //! Invoke a button press on a cluster. virtual void PressButton(ClusterId clusterId, ButtonId buttonId) = 0; - //! + //! Invoke a button press on a switcher. virtual void PressButton(SwitcherId switcherId, ButtonId buttonId) = 0; }; From 716c561cb7cd4f26ec85738503b93e3b62e09ed7 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Fri, 15 Oct 2021 04:56:20 -0700 Subject: [PATCH 282/293] bugfix: correct broken layout when searching global preferences (#4689) Signed-off-by: Michael Pollind --- Code/Editor/EditorPreferencesDialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Code/Editor/EditorPreferencesDialog.cpp b/Code/Editor/EditorPreferencesDialog.cpp index c56df15908..a1859b0f14 100644 --- a/Code/Editor/EditorPreferencesDialog.cpp +++ b/Code/Editor/EditorPreferencesDialog.cpp @@ -264,6 +264,9 @@ void EditorPreferencesDialog::SetFilter(const QString& filter) else if (m_currentPageItem) { m_currentPageItem->UpdateEditorFilter(ui->propertyEditor, m_filter); + + // Refresh the Stylesheet - when using search functionality. + AzQtComponents::StyleManager::repolishStyleSheet(this); } } From d84bb6a72fc9c7928b1fb2aa20c5235d2c1691e6 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Fri, 15 Oct 2021 07:32:10 -0500 Subject: [PATCH 283/293] {LYN5384} splitting Blast builder and processor Python scripts (#4712) splitting the asset builder and asset processor Python scripts for the Blast processor This fixes a mulitiple build issue found while developing other scripts Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> --- .../Editor/Scripts/blast_asset_builder.py | 125 +--------------- .../Editor/Scripts/blast_chunk_processor.py | 141 ++++++++++++++++++ 2 files changed, 144 insertions(+), 122 deletions(-) create mode 100644 Gems/Blast/Editor/Scripts/blast_chunk_processor.py diff --git a/Gems/Blast/Editor/Scripts/blast_asset_builder.py b/Gems/Blast/Editor/Scripts/blast_asset_builder.py index 06dc15f5c1..a570489ed1 100644 --- a/Gems/Blast/Editor/Scripts/blast_asset_builder.py +++ b/Gems/Blast/Editor/Scripts/blast_asset_builder.py @@ -95,7 +95,9 @@ def generate_assetinfo_product(request): outputFilename = os.path.join(request.tempDirPath, assetinfoFilename) # the only rule in it is to run this file again as a scene processor - currentScript = pathlib.Path(__file__).resolve() + currentScript = str(pathlib.Path(__file__).resolve()) + currentScript = currentScript.replace('\\', '/').lower() + currentScript = currentScript.replace('blast_asset_builder.py', 'blast_chunk_processor.py') aDict = {"values": [{"$type": "ScriptProcessorRule", "scriptFilename": f"{currentScript}"}]} jsonString = json.dumps(aDict) jsonFile = open(outputFilename, "w") @@ -167,124 +169,3 @@ try: pythonAssetBuilderHandler = register_asset_builder() except: pythonAssetBuilderHandler = None - -# -# SceneAPI Processor -# -blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) - -def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): - import azlmbr.scene - import azlmbr.object - import azlmbr.paths - import json, os - - jsonFilename = os.path.basename(scene.sourceFilename) - jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks') - - # prepare output folder - basePath, _ = os.path.split(jsonFilename) - outputPath = os.path.join(outputDirectory, basePath) - if not os.path.exists(outputPath): - os.makedirs(outputPath, False) - - # write out a JSON file with the chunk file info - with open(jsonFilename, "w") as jsonFile: - jsonFile.write(scene.manifest.ExportToJson()) - - exportProduct = azlmbr.scene.ExportProduct() - exportProduct.filename = jsonFilename - exportProduct.sourceId = scene.sourceGuid - exportProduct.assetType = blastChunksAssetType - exportProduct.subId = 101 - - exportProductList = azlmbr.scene.ExportProductList() - exportProductList.AddProduct(exportProduct) - return exportProductList - -def on_prepare_for_export(args): - try: - scene = args[0] # azlmbr.scene.Scene - outputDirectory = args[1] # string - platformIdentifier = args[2] # string - productList = args[3] # azlmbr.scene.ExportProductList - return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList) - except: - log_exception_traceback() - -def get_mesh_node_names(sceneGraph): - import azlmbr.scene as sceneApi - import azlmbr.scene.graph - from scene_api import scene_data as sceneData - - meshDataList = [] - node = sceneGraph.get_root() - children = [] - - while node.IsValid(): - # store children to process after siblings - if sceneGraph.has_node_child(node): - children.append(sceneGraph.get_node_child(node)) - - # store any node that has mesh data content - nodeContent = sceneGraph.get_node_content(node) - if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): - if sceneGraph.is_node_end_point(node) is False: - nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) - nodePath = nodeName.get_path() - if (len(nodeName.get_path())): - meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) - - # advance to next node - if sceneGraph.has_node_sibling(node): - node = sceneGraph.get_node_sibling(node) - elif children: - node = children.pop() - else: - node = azlmbr.scene.graph.NodeIndex() - - return meshDataList - -def update_manifest(scene): - import uuid, os - import azlmbr.scene as sceneApi - import azlmbr.scene.graph - from scene_api import scene_data as sceneData - - graph = sceneData.SceneGraph(scene.graph) - meshNameList = get_mesh_node_names(graph) - sceneManifest = sceneData.SceneManifest() - sourceFilenameOnly = os.path.basename(scene.sourceFilename) - sourceFilenameOnly = sourceFilenameOnly.replace('.','_') - - for activeMeshIndex in range(len(meshNameList)): - chunkName = meshNameList[activeMeshIndex] - chunkPath = chunkName.get_path() - meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) - meshGroup = sceneManifest.add_mesh_group(meshGroupName) - meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' - sceneManifest.mesh_group_select_node(meshGroup, chunkPath) - - return sceneManifest.export() - -sceneJobHandler = None - -def on_update_manifest(args): - try: - scene = args[0] - return update_manifest(scene) - except: - global sceneJobHandler - sceneJobHandler = None - log_exception_traceback() - -# try to create SceneAPI handler for processing -try: - import azlmbr.scene as sceneApi - if (sceneJobHandler == None): - sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() - sceneJobHandler.connect() - sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) - sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export) -except: - sceneJobHandler = None diff --git a/Gems/Blast/Editor/Scripts/blast_chunk_processor.py b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py new file mode 100644 index 0000000000..d112f465e9 --- /dev/null +++ b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py @@ -0,0 +1,141 @@ +""" +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 a Python Asset Builder script examines each .blast file to see if an +associated .fbx file needs to be processed by exporting all of its chunks +into a scene manifest + +This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene +manifest that writes out asset chunk data for .blast files +""" +import os, traceback, binascii, sys, json, pathlib +import azlmbr.math +import azlmbr.asset +import azlmbr.asset.entity +import azlmbr.asset.builder +import azlmbr.bus + +# +# SceneAPI Processor +# +blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) + +def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): + import azlmbr.scene + import azlmbr.object + import azlmbr.paths + import json, os + + jsonFilename = os.path.basename(scene.sourceFilename) + jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks') + + # prepare output folder + basePath, _ = os.path.split(jsonFilename) + outputPath = os.path.join(outputDirectory, basePath) + if not os.path.exists(outputPath): + os.makedirs(outputPath, False) + + # write out a JSON file with the chunk file info + with open(jsonFilename, "w") as jsonFile: + jsonFile.write(scene.manifest.ExportToJson()) + + exportProduct = azlmbr.scene.ExportProduct() + exportProduct.filename = jsonFilename + exportProduct.sourceId = scene.sourceGuid + exportProduct.assetType = blastChunksAssetType + exportProduct.subId = 101 + + exportProductList = azlmbr.scene.ExportProductList() + exportProductList.AddProduct(exportProduct) + return exportProductList + +def on_prepare_for_export(args): + try: + scene = args[0] # azlmbr.scene.Scene + outputDirectory = args[1] # string + platformIdentifier = args[2] # string + productList = args[3] # azlmbr.scene.ExportProductList + return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList) + except: + log_exception_traceback() + +def get_mesh_node_names(sceneGraph): + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + meshDataList = [] + node = sceneGraph.get_root() + children = [] + + while node.IsValid(): + # store children to process after siblings + if sceneGraph.has_node_child(node): + children.append(sceneGraph.get_node_child(node)) + + # store any node that has mesh data content + nodeContent = sceneGraph.get_node_content(node) + if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): + if sceneGraph.is_node_end_point(node) is False: + nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) + nodePath = nodeName.get_path() + if (len(nodeName.get_path())): + meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) + + # advance to next node + if sceneGraph.has_node_sibling(node): + node = sceneGraph.get_node_sibling(node) + elif children: + node = children.pop() + else: + node = azlmbr.scene.graph.NodeIndex() + + return meshDataList + +def update_manifest(scene): + import uuid, os + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + graph = sceneData.SceneGraph(scene.graph) + meshNameList = get_mesh_node_names(graph) + sceneManifest = sceneData.SceneManifest() + sourceFilenameOnly = os.path.basename(scene.sourceFilename) + sourceFilenameOnly = sourceFilenameOnly.replace('.','_') + + for activeMeshIndex in range(len(meshNameList)): + chunkName = meshNameList[activeMeshIndex] + chunkPath = chunkName.get_path() + meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) + meshGroup = sceneManifest.add_mesh_group(meshGroupName) + meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' + sceneManifest.mesh_group_select_node(meshGroup, chunkPath) + + return sceneManifest.export() + +sceneJobHandler = None + +def on_update_manifest(args): + try: + scene = args[0] + return update_manifest(scene) + except: + global sceneJobHandler + sceneJobHandler = None + log_exception_traceback() + +# try to create SceneAPI handler for processing +try: + import azlmbr.scene as sceneApi + if (sceneJobHandler == None): + sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() + sceneJobHandler.connect() + sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) + sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export) +except: + sceneJobHandler = None From 969a55170e362e8d025c0354a825de0cafcb7f26 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri, 15 Oct 2021 07:33:01 -0500 Subject: [PATCH 284/293] Procedural Prefabs: Entity parenting fixes (#4669) * Parent top level entities to container entity when creating prefab Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add to_json method to PythonProxyObject to allow serializing any AZ serialializable type Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Update scene_mesh_to_prefab.py to parent entities in a chain Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Remove redundant eval Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Improve error handling in ToJson Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add maybe_unused for commonRoot since it's not used Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../Editor/Scripts/scene_mesh_to_prefab.py | 30 +++++++++++++-- .../Prefab/PrefabSystemScriptingHandler.cpp | 27 ++++++++++++- .../Code/Source/PythonProxyObject.cpp | 38 +++++++++++++++++++ .../Code/Source/PythonProxyObject.h | 2 + 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py index d5a7acfe91..4aeff06f18 100644 --- a/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py +++ b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py @@ -74,6 +74,7 @@ def update_manifest(scene): source_filename_only = os.path.basename(clean_filename) created_entities = [] + previous_entity_id = azlmbr.entity.InvalidEntityId # Loop every mesh node in the scene for activeMeshIndex in range(len(mesh_name_list)): @@ -102,14 +103,33 @@ def update_manifest(scene): # The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel # The assetHint will be converted to an AssetId later during prefab loading json_update = json.dumps({ - "Controller": { "Configuration": { "ModelAsset": { - "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}} - }); + "Controller": { "Configuration": { "ModelAsset": { + "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}} + }); # Apply the JSON above to the component we created result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update) if not result: - raise RuntimeError("UpdateComponentForEntity failed") + raise RuntimeError("UpdateComponentForEntity failed for Mesh component") + + # Get the transform component + transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0") + + # Set this entity to be a child of the last entity we created + # This is just an example of how to do parenting and isn't necessarily useful to parent everything like this + if previous_entity_id is not None: + transform_json = json.dumps({ + "Parent Entity" : previous_entity_id.to_json() + }); + + # Apply the JSON update + result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, transform_component, transform_json) + + if not result: + raise RuntimeError("UpdateComponentForEntity failed for Transform component") + + # Update the last entity id for next time + previous_entity_id = entity_id # Keep track of the entity we set up, we'll add them all to the prefab we're creating later created_entities.append(entity_id) @@ -147,6 +167,8 @@ def on_update_manifest(args): except RuntimeError as err: print (f'ERROR - {err}') log_exception_traceback() + except: + log_exception_traceback() global sceneJobHandler sceneJobHandler = None diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp index d34e2cfc92..884c463bff 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp @@ -6,11 +6,14 @@ * */ +#include #include #include #include #include #include +#include +#include namespace AzToolsFramework::Prefab { @@ -61,9 +64,29 @@ namespace AzToolsFramework::Prefab entities.push_back(entity); } } - - auto prefab = m_prefabSystemComponentInterface->CreatePrefab(entities, {}, AZ::IO::PathView(AZStd::string_view(filePath))); + bool result = false; + [[maybe_unused]] AZ::EntityId commonRoot; + EntityList topLevelEntities; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(result, &AzToolsFramework::ToolsApplicationRequestBus::Events::FindCommonRootInactive, + entities, commonRoot, &topLevelEntities); + + auto containerEntity = AZStd::make_unique(); + + for (AZ::Entity* entity : topLevelEntities) + { + AzToolsFramework::Components::TransformComponent* transformComponent = + entity->FindComponent(); + + if (transformComponent) + { + transformComponent->SetParent(containerEntity->GetId()); + } + } + + auto prefab = m_prefabSystemComponentInterface->CreatePrefab( + entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)), AZStd::move(containerEntity)); + if (!prefab) { AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str()); diff --git a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp index 706ca48156..df246d230d 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp @@ -17,10 +17,16 @@ #include #include +#include +#include #include +#include #include #include +#include +#include +#include namespace EditorPythonBindings { @@ -571,6 +577,37 @@ namespace EditorPythonBindings return false; } + pybind11::object PythonProxyObject::ToJson() + { + rapidjson::Document document; + AZ::JsonSerializerSettings settings; + settings.m_keepDefaults = true; + + auto resultCode = + AZ::JsonSerialization::Store(document, document.GetAllocator(), m_wrappedObject.m_address, nullptr, m_wrappedObject.m_typeId, settings); + + if (resultCode.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted) + { + AZ_Error("PythonProxyObject", false, "Failed to serialize to json"); + return pybind11::cast(Py_None); + } + + AZStd::string jsonString; + AZ::Outcome outcome = AZ::JsonSerializationUtils::WriteJsonString(document, jsonString); + + if (!outcome.IsSuccess()) + { + AZ_Error("PythonProxyObject", false, "Failed to write json string: %s", outcome.GetError().c_str()); + return pybind11::cast(Py_None); + } + + jsonString.erase(AZStd::remove(jsonString.begin(), jsonString.end(), '\n'), jsonString.end()); + auto pythonCode = AZStd::string::format( + R"PYTHON(exec("import json") or json.loads("""%s"""))PYTHON", jsonString.c_str()); + + return pybind11::eval(pythonCode.c_str()); + } + bool PythonProxyObject::DoComparisonEvaluation(pybind11::object pythonOther, Comparison comparison) { bool invertLogic = false; @@ -912,6 +949,7 @@ namespace EditorPythonBindings .def("set_property", &PythonProxyObject::SetPropertyValue) .def("get_property", &PythonProxyObject::GetPropertyValue) .def("invoke", &PythonProxyObject::Invoke) + .def("to_json", &PythonProxyObject::ToJson) .def(Operator::s_isEqual, [](PythonProxyObject& self, pybind11::object rhs) { return self.DoEqualityEvaluation(rhs); diff --git a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h index 5b611c32c0..a9d2fad5a0 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h +++ b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h @@ -58,6 +58,8 @@ namespace EditorPythonBindings //! Performs an equality operation to compare this object with another object bool DoEqualityEvaluation(pybind11::object pythonOther); + pybind11::object ToJson(); + //! Perform a comparison of a Python operator enum class Comparison { From 87533d80c11812c14b1262b151493f3be655739e Mon Sep 17 00:00:00 2001 From: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com> Date: Fri, 15 Oct 2021 18:25:26 +0530 Subject: [PATCH 285/293] Delay propagation for all template updates in detach prefab workflow (#4707) * Delay propagation for all template updates in detach prefab workflow Signed-off-by: srikappa-amzn * Some minor changes to the PrefabUndo constructor Signed-off-by: srikappa-amzn --- .../Prefab/PrefabPublicHandler.cpp | 6 +++--- .../AzToolsFramework/Prefab/PrefabUndo.cpp | 14 ++++---------- .../AzToolsFramework/Prefab/PrefabUndo.h | 8 ++++---- .../AzToolsFramework/Prefab/PrefabUndoHelpers.cpp | 4 ++-- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 081655a166..ee34b628bb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1052,10 +1052,10 @@ namespace AzToolsFramework DuplicateNestedEntitiesInInstance(commonOwningInstance->get(), entities, instanceDomAfter, duplicatedEntityAndInstanceIds, duplicateEntityAliasMap); - PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication"); + PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication", false); command->SetParent(undoBatch.GetUndoBatch()); command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId()); - command->RedoBatched(); + command->Redo(); DuplicateNestedInstancesInInstance(commonOwningInstance->get(), instances, instanceDomAfter, duplicatedEntityAndInstanceIds, newInstanceAliasToOldInstanceMap); @@ -1323,7 +1323,7 @@ namespace AzToolsFramework Prefab::PrefabDom instanceDomAfter; m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, parentInstance); - PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment"); + PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment", false); command->Capture(instanceDomBefore, instanceDomAfter, parentTemplateId); command->SetParent(undoBatch.GetUndoBatch()); { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp index b298304e3b..6c96209d56 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp @@ -17,17 +17,16 @@ namespace AzToolsFramework { PrefabUndoBase::PrefabUndoBase(const AZStd::string& undoOperationName) : UndoSystem::URSequencePoint(undoOperationName) - , m_changed(true) - , m_templateId(InvalidTemplateId) { m_instanceToTemplateInterface = AZ::Interface::Get(); AZ_Assert(m_instanceToTemplateInterface, "Failed to grab instance to template interface"); } //PrefabInstanceUndo - PrefabUndoInstance::PrefabUndoInstance(const AZStd::string& undoOperationName) + PrefabUndoInstance::PrefabUndoInstance(const AZStd::string& undoOperationName, const bool useImmediatePropagation) : PrefabUndoBase(undoOperationName) { + m_useImmediatePropagation = useImmediatePropagation; } void PrefabUndoInstance::Capture( @@ -43,17 +42,12 @@ namespace AzToolsFramework void PrefabUndoInstance::Undo() { - m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, true); + m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, m_useImmediatePropagation); } void PrefabUndoInstance::Redo() { - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, true); - } - - void PrefabUndoInstance::RedoBatched() - { - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, m_useImmediatePropagation); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h index 8669024df7..0946a36951 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h @@ -29,14 +29,15 @@ namespace AzToolsFramework bool Changed() const override { return m_changed; } protected: - TemplateId m_templateId; + TemplateId m_templateId = InvalidTemplateId; PrefabDom m_redoPatch; PrefabDom m_undoPatch; InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr; - bool m_changed; + bool m_changed = true; + bool m_useImmediatePropagation = true; }; //! handles the addition and removal of entities from instances @@ -44,7 +45,7 @@ namespace AzToolsFramework : public PrefabUndoBase { public: - explicit PrefabUndoInstance(const AZStd::string& undoOperationName); + explicit PrefabUndoInstance(const AZStd::string& undoOperationName, const bool useImmediatePropagation = true); void Capture( const PrefabDom& initialState, @@ -53,7 +54,6 @@ namespace AzToolsFramework void Undo() override; void Redo() override; - void RedoBatched(); }; //! handles entity updates, such as when the values on an entity change diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp index 9803b55324..31a0c60bcb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp @@ -23,10 +23,10 @@ namespace AzToolsFramework PrefabDom instanceDomAfterUpdate; PrefabDomUtils::StoreInstanceInPrefabDom(instance, instanceDomAfterUpdate); - PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage); + PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage, false); state->Capture(instanceDomBeforeUpdate, instanceDomAfterUpdate, instance.GetTemplateId()); state->SetParent(undoBatch); - state->RedoBatched(); + state->Redo(); } LinkId CreateLink( From 9aafc51ff5a2551cabed9fe322917ed6842f1dda Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Fri, 15 Oct 2021 15:25:27 +0100 Subject: [PATCH 286/293] Add first pass version of click feedback while in Focus Mode (#4693) * add first pass version of click feedback while in Focus Mode Signed-off-by: hultonha * add more WIP experimental feedback ideas for Focus Mode Signed-off-by: hultonha * small updates after UX feedback to improve focus mode feedback Signed-off-by: hultonha * refactor and improve invalid click feedback Signed-off-by: hultonha * update comments from review feedback Signed-off-by: hultonha --- .../ViewportSelection/EditorHelpers.cpp | 33 +++- .../ViewportSelection/EditorHelpers.h | 20 ++- .../EditorTransformComponentSelection.cpp | 2 + .../ViewportSelection/InvalidClicks.cpp | 142 ++++++++++++++++++ .../ViewportSelection/InvalidClicks.h | 108 +++++++++++++ .../aztoolsframework_files.cmake | 2 + .../AtomDebugDisplayViewportInterface.cpp | 3 +- 7 files changed, 297 insertions(+), 13 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index bb718d0dc9..6399a64635 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -9,6 +9,7 @@ #include "EditorHelpers.h" #include +#include #include #include #include @@ -123,6 +124,11 @@ namespace AzToolsFramework "EditorHelpers - " "Focus Mode Interface could not be found. " "Check that it is being correctly initialized."); + + AZStd::vector> invalidClicks; + invalidClicks.push_back(AZStd::make_unique("Not in focus")); + invalidClicks.push_back(AZStd::make_unique()); + m_invalidClicks = AZStd::make_unique(AZStd::move(invalidClicks)); } AZ::EntityId EditorHelpers::HandleMouseInteraction( @@ -186,13 +192,20 @@ namespace AzToolsFramework } } - // Verify if the entity Id corresponds to an entity that is focused; if not, halt selection. - if (!IsSelectableAccordingToFocusMode(entityIdUnderCursor)) + // verify if the entity Id corresponds to an entity that is focused; if not, halt selection. + if (entityIdUnderCursor.IsValid() && !IsSelectableAccordingToFocusMode(entityIdUnderCursor)) { + if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() && + mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down || + mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::DoubleClick) + { + m_invalidClicks->AddInvalidClick(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); + } + return AZ::EntityId(); } - // Container Entity support - if the entity that is being selected is part of a closed container, + // container entity support - if the entity that is being selected is part of a closed container, // change the selection to the container instead. if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get()) { @@ -202,6 +215,12 @@ namespace AzToolsFramework return entityIdUnderCursor; } + void EditorHelpers::Display2d( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + m_invalidClicks->Display2d(viewportInfo, debugDisplay); + } + void EditorHelpers::DisplayHelpers( const AzFramework::ViewportInfo& viewportInfo, const AzFramework::CameraState& cameraState, @@ -263,19 +282,19 @@ namespace AzToolsFramework } } - bool EditorHelpers::IsSelectableInViewport(AZ::EntityId entityId) + bool EditorHelpers::IsSelectableInViewport(const AZ::EntityId entityId) const { return IsSelectableAccordingToFocusMode(entityId) && IsSelectableAccordingToContainerEntities(entityId); } - bool EditorHelpers::IsSelectableAccordingToFocusMode(AZ::EntityId entityId) + bool EditorHelpers::IsSelectableAccordingToFocusMode(const AZ::EntityId entityId) const { return m_focusModeInterface->IsInFocusSubTree(entityId); } - bool EditorHelpers::IsSelectableAccordingToContainerEntities(AZ::EntityId entityId) + bool EditorHelpers::IsSelectableAccordingToContainerEntities(const AZ::EntityId entityId) const { - if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get()) + if (const auto* containerEntityInterface = AZ::Interface::Get()) { return !containerEntityInterface->IsUnderClosedContainerEntity(entityId); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h index 909a231635..6623221bdc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include namespace AzFramework { @@ -58,20 +61,27 @@ namespace AzToolsFramework AzFramework::DebugDisplayRequests& debugDisplay, const AZStd::function& showIconCheck); + //! Handle 2d drawing for EditorHelper functionality. + void Display2d( + const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay); + //! Returns whether the entityId can be selected in the viewport according //! to the current Editor Focus Mode and Container Entity setup. - bool IsSelectableInViewport(AZ::EntityId entityId); + bool IsSelectableInViewport(AZ::EntityId entityId) const; private: //! Returns whether the entityId can be selected in the viewport according //! to the current Editor Focus Mode setup. - bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId); + bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId) const; //! Returns whether the entityId can be selected in the viewport according - //! to the current Container Entityu setup. - bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId); + //! to the current Container Entity setup. + bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId) const; + + AZStd::unique_ptr m_invalidClicks; //!< Display for invalid click behavior. const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers. - const FocusModeInterface* m_focusModeInterface = nullptr; + const FocusModeInterface* m_focusModeInterface = nullptr; //!< API to interact with focus mode functionality. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index a37b84fdf8..c73742da4d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -3560,6 +3560,8 @@ namespace AzToolsFramework DrawAxisGizmo(viewportInfo, debugDisplay); m_boxSelect.Display2d(viewportInfo, debugDisplay); + + m_editorHelpers->Display2d(viewportInfo, debugDisplay); } void EditorTransformComponentSelection::RefreshSelectedEntityIds() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.cpp new file mode 100644 index 0000000000..dfff4da08f --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +AZ_CVAR(float, ed_invalidClickRadius, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum invalid click radius to expand to"); +AZ_CVAR(float, ed_invalidClickDuration, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Duration to display the invalid click feedback"); +AZ_CVAR(float, ed_invalidClickMessageSize, 0.8f, nullptr, AZ::ConsoleFunctorFlags::Null, "Size of text for invalid message"); +AZ_CVAR( + float, + ed_invalidClickMessageVerticalOffset, + 30.0f, + nullptr, + AZ::ConsoleFunctorFlags::Null, + "Vertical offset from cursor of invalid click message"); + +namespace AzToolsFramework +{ + void ExpandingFadingCircles::Begin(const AzFramework::ScreenPoint& screenPoint) + { + FadingCircle fadingCircle; + fadingCircle.m_position = screenPoint; + fadingCircle.m_opacity = 1.0f; + fadingCircle.m_radius = 0.0f; + m_fadingCircles.push_back(fadingCircle); + } + + void ExpandingFadingCircles::Update(const float deltaTime) + { + for (auto& fadingCircle : m_fadingCircles) + { + fadingCircle.m_opacity = AZStd::max(fadingCircle.m_opacity - (deltaTime / ed_invalidClickDuration), 0.0f); + fadingCircle.m_radius += deltaTime * ed_invalidClickRadius; + } + + m_fadingCircles.erase( + AZStd::remove_if( + m_fadingCircles.begin(), m_fadingCircles.end(), + [](const FadingCircle& fadingCircle) + { + return fadingCircle.m_opacity <= 0.0f; + }), + m_fadingCircles.end()); + } + + bool ExpandingFadingCircles::Updating() + { + return !m_fadingCircles.empty(); + } + + void ExpandingFadingCircles::Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + const AZ::Vector2 viewportSize = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId).m_viewportSize; + + for (const auto& fadingCircle : m_fadingCircles) + { + const auto position = AzFramework::Vector2FromScreenPoint(fadingCircle.m_position) / viewportSize; + debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, fadingCircle.m_opacity)); + debugDisplay.DrawWireCircle2d(position, fadingCircle.m_radius * 0.005f, 0.0f); + } + } + + void FadingText::Begin(const AzFramework::ScreenPoint& screenPoint) + { + m_opacity = 1.0f; + m_invalidClickPosition = screenPoint; + } + + void FadingText::Update(const float deltaTime) + { + m_opacity -= deltaTime / ed_invalidClickDuration; + } + + bool FadingText::Updating() + { + return m_opacity >= 0.0f; + } + + void FadingText::Display( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + if (constexpr float MinOpacity = 0.05f; m_opacity >= MinOpacity) + { + debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, m_opacity)); + debugDisplay.Draw2dTextLabel( + aznumeric_cast(m_invalidClickPosition.m_x), + aznumeric_cast(m_invalidClickPosition.m_y) - ed_invalidClickMessageVerticalOffset, ed_invalidClickMessageSize, + m_message.c_str(), true); + } + } + + void InvalidClicks::AddInvalidClick(const AzFramework::ScreenPoint& screenPoint) + { + AZ::TickBus::Handler::BusConnect(); + + for (auto& invalidClickBehavior : m_invalidClickBehaviors) + { + invalidClickBehavior->Begin(screenPoint); + } + } + + void InvalidClicks::OnTick(const float deltaTime, [[maybe_unused]] const AZ::ScriptTimePoint time) + { + for (auto& invalidClickBehavior : m_invalidClickBehaviors) + { + invalidClickBehavior->Update(deltaTime); + } + + const auto updating = AZStd::any_of( + m_invalidClickBehaviors.begin(), m_invalidClickBehaviors.end(), + [](const auto& invalidClickBehavior) + { + return invalidClickBehavior->Updating(); + }); + + if (!updating && AZ::TickBus::Handler::BusIsConnected()) + { + AZ::TickBus::Handler::BusDisconnect(); + } + } + + void InvalidClicks::Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + debugDisplay.DepthTestOff(); + + for (const auto& invalidClickBehavior : m_invalidClickBehaviors) + { + invalidClickBehavior->Display(viewportInfo, debugDisplay); + } + + debugDisplay.DepthTestOn(); + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h new file mode 100644 index 0000000000..55a6d614ea --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AzFramework +{ + class DebugDisplayRequests; + struct ViewportInfo; +} // namespace AzFramework + +namespace AzToolsFramework +{ + namespace ViewportInteraction + { + struct MouseInteractionEvent; + } + + //! An interface to provide invalid click feedback in the editor viewport. + class InvalidClick + { + public: + virtual ~InvalidClick() = default; + + //! Begin the feedback. + //! @param screenPoint The position of the click in screen coordinates. + virtual void Begin(const AzFramework::ScreenPoint& screenPoint) = 0; + //! Update the invalid click feedback + virtual void Update(float deltaTime) = 0; + //! Report if the click feedback is running or not (returning false will signal the TickBus can be disconnected from). + virtual bool Updating() = 0; + //! Display the click feedback in the viewport. + virtual void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) = 0; + }; + + //! Display expanding fading circles for every click of the mouse that is invalid. + class ExpandingFadingCircles : public InvalidClick + { + public: + void Begin(const AzFramework::ScreenPoint& screenPoint) override; + void Update(float deltaTime) override; + bool Updating() override; + void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + private: + //! Stores a circle representation with a lifetime to grow and fade out over time. + struct FadingCircle + { + AzFramework::ScreenPoint m_position; + float m_radius; + float m_opacity; + }; + + using FadingCircles = AZStd::vector; + FadingCircles m_fadingCircles; //!< Collection of fading circles to draw for clicks that have no effect. + }; + + //! Display fading text where an invalid click happened. + //! @note There is only one fading text, each click will update its position. + class FadingText : public InvalidClick + { + public: + explicit FadingText(AZStd::string message) + : m_message(AZStd::move(message)) + { + } + + void Begin(const AzFramework::ScreenPoint& screenPoint) override; + void Update(float deltaTime) override; + bool Updating() override; + void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + private: + AZStd::string m_message; //!< Message to display for fading text. + float m_opacity = 1.0f; //!< The opacity of the invalid click message. + AzFramework::ScreenPoint m_invalidClickPosition; //!< The position to display the invalid click message. + }; + + //! Interface to begin invalid click feedback (will run all added InvalidClick behaviors). + class InvalidClicks : private AZ::TickBus::Handler + { + public: + explicit InvalidClicks(AZStd::vector> invalidClickBehaviors) + : m_invalidClickBehaviors(AZStd::move(invalidClickBehaviors)) + { + } + + //! Add an invalid click and activate one or more of the added invalid click behaviors. + void AddInvalidClick(const AzFramework::ScreenPoint& screenPoint); + + //! Handle 2d drawing for EditorHelper functionality. + void Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay); + + private: + //! AZ::TickBus overrides ... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + AZStd::vector> m_invalidClickBehaviors; //!< Invalid click behaviors to run. + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 8dec7ab611..5db65f89f4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -553,6 +553,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp + ViewportSelection/InvalidClicks.h + ViewportSelection/InvalidClicks.cpp ViewportSelection/ViewportEditorModeTracker.cpp ViewportSelection/ViewportEditorModeTracker.h ToolsFileUtils/ToolsFileUtils.h diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index b45fbe05f6..39d8933863 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -1353,8 +1353,9 @@ namespace AZ::AtomBridge // if 2d draw need to project pos to screen first AzFramework::TextDrawParameters params; AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor(); params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works - params.m_position = AZ::Vector3(x, y, 1.0f); + params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f); params.m_color = m_rendState.m_color; params.m_scale = AZ::Vector2(size); params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment From 7651ba621c59fc2efa7b95bb5a837ee66bd20f38 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 15 Oct 2021 08:53:26 -0700 Subject: [PATCH 287/293] Remove old "Integ" functionality from tests (#4688) * fixes some warnings for newer versions of VS2022 Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * more warning fixes Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * remove integ test filters from AzTest Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * remove integ test handling from AzTestRunner Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * changes integ tests of gridmate to regular tests and disables failing ones Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * removes the Integ from the EMotionFX tests, but leaves them disabled since they are failing Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * removes the Integ from the HttpRequestor tests and disables it since is not passing Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * changing integ tests for DISABLED, these ones are using files that are not there Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * fixes linux build gridmate tests that were Integ are now disabled Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * fixes linux warnings Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Tests/Asset/AssetManagerLoadingTests.cpp | 3 + .../Tests/Debug/LocalFileEventLoggerTests.cpp | 6 + .../IO/Streamer/StorageDriveTests_Windows.cpp | 18 ++ Code/Framework/AzCore/Tests/StringFunc.cpp | 6 + .../SpawnableEntitiesManagerTests.cpp | 15 +- Code/Framework/AzTest/AzTest/AzTest.cpp | 9 - Code/Framework/AzTest/AzTest/AzTest.h | 2 - Code/Framework/GridMate/Tests/Carrier.cpp | 80 +++--- .../Tests/CarrierStreamSocketDriverTests.cpp | 22 +- Code/Framework/GridMate/Tests/Replica.cpp | 95 ++++--- .../GridMate/Tests/ReplicaBehavior.cpp | 88 +++---- .../GridMate/Tests/ReplicaMedium.cpp | 160 ++++++------ Code/Framework/GridMate/Tests/Session.cpp | 60 ++--- .../Tests/StreamSecureSocketDriverTests.cpp | 30 +-- .../Tests/StreamSocketDriverTests.cpp | 4 +- .../Framework/GridMate/Tests/TestProfiler.cpp | 244 ------------------ Code/Framework/GridMate/Tests/TestProfiler.h | 24 -- .../GridMate/Tests/gridmate_test_files.cmake | 1 + Code/Tools/AzTestRunner/src/main.cpp | 79 +----- .../Tests/Integration/PoseComparisonFixture.h | 6 +- .../Tests/Integration/PoseComparisonTests.cpp | 38 +-- .../Code/Tests/HttpRequestorTest.cpp | 58 ++--- .../Tests/BundlingSystemComponentTests.cpp | 18 +- 23 files changed, 376 insertions(+), 690 deletions(-) delete mode 100644 Code/Framework/GridMate/Tests/TestProfiler.cpp delete mode 100644 Code/Framework/GridMate/Tests/TestProfiler.h diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index 3e6376323c..e33dbce9c1 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -736,7 +736,10 @@ namespace UnitTest auto& assetManager = AssetManager::Instance(); AssetBusCallbacks callbacks{}; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning callbacks.SetOnAssetReadyCallback([&, AssetNoRefB](const Asset&, AssetBusCallbacks&) + AZ_POP_DISABLE_WARNING { // This callback should run inside the "main thread" dispatch events loop auto loadAsset = assetManager.GetAsset(AZ::Uuid(AssetNoRefB), AssetLoadBehavior::Default); diff --git a/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp b/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp index 242ac0e65d..d4b3351dbe 100644 --- a/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp +++ b/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp @@ -109,7 +109,10 @@ namespace AZ::Debug AZStd::thread threads[totalThreads]; for (size_t threadIndex = 0; threadIndex < totalThreads; ++threadIndex) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning threads[threadIndex] = AZStd::thread([&startLogging, &messages]() + AZ_POP_DISABLE_WARNING { while (!startLogging) { @@ -226,7 +229,10 @@ namespace AZ::Debug AZStd::thread threads[totalThreads]; for (size_t threadIndex = 0; threadIndex < totalThreads; ++threadIndex) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning threads[threadIndex] = AZStd::thread([&startLogging, &message, &totalRecordsWritten]() + AZ_POP_DISABLE_WARNING { AZ_UNUSED(message); diff --git a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp index 22fb6379d2..e312e2058d 100644 --- a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp +++ b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp @@ -597,7 +597,10 @@ namespace AZ::IO path.InitFromAbsolutePath(m_dummyFilepath); request->CreateRead(nullptr, buffer.get(), fileSize, path, 0, fileSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [&fileSize, this](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -639,7 +642,10 @@ namespace AZ::IO path.InitFromAbsolutePath(m_dummyFilepath); request->CreateRead(nullptr, buffer, unalignedSize + 4, path, unalignedOffset, unalignedSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [unalignedOffset, unalignedSize, this](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -784,7 +790,10 @@ namespace AZ::IO requests[i] = m_context->GetNewInternalRequest(); requests[i]->CreateRead(nullptr, buffers[i].get(), chunkSize, path, i * chunkSize, chunkSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [chunkSize, i](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -970,7 +979,10 @@ namespace AZ::IO i * chunkSize )); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [numChunks, &numCallbacks, &waitForReads](FileRequestHandle request) + AZ_POP_DISABLE_WARNING { IStreamer* streamer = Interface::Get(); if (streamer) @@ -1038,7 +1050,10 @@ namespace AZ::IO i * chunkSize )); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [numChunks, &waitForReads, &waitForSingleRead, &numReadCallbacks]([[maybe_unused]] FileRequestHandle request) + AZ_POP_DISABLE_WARNING { numReadCallbacks++; if (numReadCallbacks == 1) @@ -1059,7 +1074,10 @@ namespace AZ::IO for (size_t i = 0; i < numChunks; ++i) { cancels.push_back(m_streamer->Cancel(requests[numChunks - i - 1])); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [&numCancelCallbacks, &waitForCancels, numChunks](FileRequestHandle request) + AZ_POP_DISABLE_WARNING { auto result = Interface::Get()->GetRequestStatus(request); EXPECT_EQ(result, IStreamerTypes::RequestStatus::Completed); diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index 68821ba3f9..dc4bc40e5b 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -363,7 +363,10 @@ namespace AZ { constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" }; size_t visitIndex{}; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token) + AZ_POP_DISABLE_WARNING { if (visitIndex > visitTokens.size()) { @@ -389,7 +392,10 @@ namespace AZ { constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" }; size_t visitIndex = visitTokens.size() - 1; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token) + AZ_POP_DISABLE_WARNING { if (visitIndex > visitTokens.size()) { diff --git a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 407ab1d21f..2dc32d14d5 100644 --- a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -569,11 +569,12 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunused-lambda-capture") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(refScheme); - AZ_UNUSED(NumEntities); ValidateEntityReferences(refScheme, NumEntities, entities); }; @@ -591,11 +592,12 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunused-lambda-capture") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(refScheme); - AZ_UNUSED(NumEntities); ValidateEntityReferences(refScheme, NumEntities, entities); }; @@ -720,11 +722,12 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunused-lambda-capture") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(refScheme); - AZ_UNUSED(NumEntities); ValidateEntityReferences(refScheme, NumEntities, entities); }; diff --git a/Code/Framework/AzTest/AzTest/AzTest.cpp b/Code/Framework/AzTest/AzTest/AzTest.cpp index 3b809d2c96..eede87b29e 100644 --- a/Code/Framework/AzTest/AzTest/AzTest.cpp +++ b/Code/Framework/AzTest/AzTest/AzTest.cpp @@ -90,13 +90,6 @@ namespace AZ } } - //! Filter out integration tests from the test run - void excludeIntegTests() - { - AddExcludeFilter("INTEG_*"); - AddExcludeFilter("Integ_*"); - } - void ApplyGlobalParameters(int* argc, char** argv) { // this is a hook that can be used to apply any other global non-google parameters @@ -160,7 +153,6 @@ namespace AZ } ::testing::InitGoogleMock(&argc, argv); - AZ::Test::excludeIntegTests(); AZ::Test::ApplyGlobalParameters(&argc, argv); AZ::Test::printUnusedParametersWarning(argc, argv); AZ::Test::addTestEnvironments(m_envs); @@ -281,7 +273,6 @@ namespace AZ } } - AZ::Test::excludeIntegTests(); AZ::Test::printUnusedParametersWarning(argc, argv); return RUN_ALL_TESTS(); diff --git a/Code/Framework/AzTest/AzTest/AzTest.h b/Code/Framework/AzTest/AzTest/AzTest.h index 352db1a0b5..4b038cabd4 100644 --- a/Code/Framework/AzTest/AzTest/AzTest.h +++ b/Code/Framework/AzTest/AzTest/AzTest.h @@ -104,7 +104,6 @@ namespace AZ void addTestEnvironment(ITestEnvironment* env); void addTestEnvironments(std::vector envs); - void excludeIntegTests(); //! A hook that can be used to read any other misc parameters and remove them before google sees them. //! Note that this modifies argc and argv to delete the parameters it consumes. @@ -266,7 +265,6 @@ namespace AZ ::testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); \ listeners.Append(new AZ::Test::OutputEventListener); \ } \ - AZ::Test::excludeIntegTests(); \ AZ::Test::ApplyGlobalParameters(&argc, argv); \ AZ::Test::printUnusedParametersWarning(argc, argv); \ AZ::Test::addTestEnvironments({TEST_ENV}); \ diff --git a/Code/Framework/GridMate/Tests/Carrier.cpp b/Code/Framework/GridMate/Tests/Carrier.cpp index 5b18a80221..29550d8b68 100644 --- a/Code/Framework/GridMate/Tests/Carrier.cpp +++ b/Code/Framework/GridMate/Tests/Carrier.cpp @@ -333,7 +333,7 @@ namespace UnitTest }; template - class Integ_CarrierAsyncHandshakeTestTemplate + class CarrierAsyncHandshakeTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -761,7 +761,7 @@ namespace UnitTest }; template - class Integ_CarrierDisconnectDetectionTestTemplate + class CarrierDisconnectDetectionTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -846,7 +846,7 @@ namespace UnitTest * Sends reliable messages across different channels to each other */ template - class Integ_CarrierMultiChannelTestTemplate + class CarrierMultiChannelTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -950,7 +950,7 @@ namespace UnitTest * Stress tests multiple simultaneous Carriers */ template - class Integ_CarrierMultiStressTestTemplate + class CarrierMultiStressTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -977,7 +977,7 @@ namespace UnitTest public: void run() { - AZ_TracePrintf("GridMate", "Integ_CarrierMultiStressTest\n\n"); + AZ_TracePrintf("GridMate", "CarrierMultiStressTest\n\n"); // initialize transport const int k_numChannels = 1; @@ -1108,7 +1108,7 @@ namespace UnitTest /*** Congestion control back pressure test */ template - class Integ_CarrierBackpressureTestTemplate + class CarrierBackpressureTestTemplate : public GridMateMPTestFixture , protected SocketProvider , public CarrierEventBus::Handler @@ -1380,7 +1380,7 @@ namespace UnitTest }; template - class Integ_CarrierACKTestTemplate + class CarrierACKTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -1544,13 +1544,13 @@ namespace UnitTest //Create specific tests using CarrierBasicTest = CarrierBasicTestTemplate<>; using CarrierTest = CarrierTestTemplate<>; - using Integ_CarrierDisconnectDetectionTest = Integ_CarrierDisconnectDetectionTestTemplate<>; - using Integ_CarrierAsyncHandshakeTest = Integ_CarrierAsyncHandshakeTestTemplate<>; - using Integ_CarrierStressTest = CarrierStressTestTemplate<>; - using Integ_CarrierMultiChannelTest = Integ_CarrierMultiChannelTestTemplate<>; - using Integ_CarrierMultiStressTest = Integ_CarrierMultiStressTestTemplate<>; - using Integ_CarrierBackpressureTest = Integ_CarrierBackpressureTestTemplate<>; - using Integ_CarrierACKTest = Integ_CarrierACKTestTemplate<>; + using DISABLED_CarrierDisconnectDetectionTest = CarrierDisconnectDetectionTestTemplate<>; + using DISABLED_CarrierAsyncHandshakeTest = CarrierAsyncHandshakeTestTemplate<>; + using DISABLED_CarrierStressTest = CarrierStressTestTemplate<>; + using DISABLED_CarrierMultiChannelTest = CarrierMultiChannelTestTemplate<>; + using DISABLED_CarrierMultiStressTest = CarrierMultiStressTestTemplate<>; + using DISABLED_CarrierBackpressureTest = CarrierBackpressureTestTemplate<>; + using DISABLED_CarrierACKTest = CarrierACKTestTemplate<>; #if AZ_TRAIT_GRIDMATE_TEST_WITH_SECURE_SOCKET_DRIVER @@ -1658,20 +1658,20 @@ namespace UnitTest using SecureProviderBadHost = SecureDriverProvider>; using SecureProviderBadBoth = SecureDriverProvider, SecureSocketHandshakeDrop>; - using Integ_CarrierSecureSocketHandshakeTestClient = CarrierBasicTestTemplate; - using Integ_CarrierSecureSocketHandshakeTestHost = CarrierBasicTestTemplate; - using Integ_CarrierSecureSocketHandshakeTestBoth = CarrierBasicTestTemplate; + using DISABLED_CarrierSecureSocketHandshakeTestClient = CarrierBasicTestTemplate; + using DISABLED_CarrierSecureSocketHandshakeTestHost = CarrierBasicTestTemplate; + using DISABLED_CarrierSecureSocketHandshakeTestBoth = CarrierBasicTestTemplate; //Create secure socket variants of tests using CarrierBasicTestSecure = CarrierBasicTestTemplate>; using CarrierTestSecure = CarrierTestTemplate>; - using Integ_CarrierDisconnectDetectionTestSecure = Integ_CarrierDisconnectDetectionTestTemplate>; - using Integ_CarrierAsyncHandshakeTestSecure = Integ_CarrierAsyncHandshakeTestTemplate>; - using Integ_CarrierStressTestSecure = CarrierStressTestTemplate>; - using Integ_CarrierMultiChannelTestSecure = Integ_CarrierMultiChannelTestTemplate>; - using Integ_CarrierMultiStressTestSecure = Integ_CarrierMultiStressTestTemplate>; - using Integ_CarrierBackpressureTestSecure = Integ_CarrierBackpressureTestTemplate>; - using Integ_CarrierACKTestSecure = Integ_CarrierACKTestTemplate>; + using DISABLED_CarrierDisconnectDetectionTestSecure = CarrierDisconnectDetectionTestTemplate>; + using DISABLED_CarrierAsyncHandshakeTestSecure = CarrierAsyncHandshakeTestTemplate>; + using DISABLED_CarrierStressTestSecure = CarrierStressTestTemplate>; + using DISABLED_CarrierMultiChannelTestSecure = CarrierMultiChannelTestTemplate>; + using DISABLED_CarrierMultiStressTestSecure = CarrierMultiStressTestTemplate>; + using DISABLED_CarrierBackpressureTestSecure = CarrierBackpressureTestTemplate>; + using DISABLED_CarrierACKTestSecure = CarrierACKTestTemplate>; #endif } @@ -1720,30 +1720,30 @@ GM_TEST_SUITE(CarrierSuite) GM_TEST(CarrierBasicTest) GM_TEST(CarrierTest) #endif //AZ_TRAIT_GRIDMATE_UNIT_TEST_DISABLE_CARRIER_SESSION_TESTS -GM_TEST(Integ_CarrierAsyncHandshakeTest) +GM_TEST(DISABLED_CarrierAsyncHandshakeTest) #if !defined(AZ_DEBUG_BUILD) // this test is a little slow for debug -GM_TEST(Integ_CarrierStressTest) -GM_TEST(Integ_CarrierMultiStressTest) +GM_TEST(DISABLED_CarrierStressTest) +GM_TEST(DISABLED_CarrierMultiStressTest) #endif -GM_TEST(Integ_CarrierMultiChannelTest) -GM_TEST(Integ_CarrierBackpressureTest) -GM_TEST(Integ_CarrierACKTest) +GM_TEST(DISABLED_CarrierMultiChannelTest) +GM_TEST(DISABLED_CarrierBackpressureTest) +GM_TEST(DISABLED_CarrierACKTest) #if AZ_TRAIT_GRIDMATE_TEST_WITH_SECURE_SOCKET_DRIVER -GM_TEST(CarrierBasicTestSecure) -GM_TEST(Integ_CarrierSecureSocketHandshakeTestClient) -GM_TEST(Integ_CarrierSecureSocketHandshakeTestHost) -GM_TEST(Integ_CarrierSecureSocketHandshakeTestBoth) +GM_TEST(DISABLED_CarrierBasicTestSecure) +GM_TEST(DISABLED_CarrierSecureSocketHandshakeTestClient) +GM_TEST(DISABLED_CarrierSecureSocketHandshakeTestHost) +GM_TEST(DISABLED_CarrierSecureSocketHandshakeTestBoth) GM_TEST(CarrierTestSecure) -GM_TEST(Integ_CarrierAsyncHandshakeTestSecure) +GM_TEST(DISABLED_CarrierAsyncHandshakeTestSecure) #if !defined(AZ_DEBUG_BUILD) // this test is a little slow for debug -GM_TEST(Integ_CarrierStressTestSecure) -GM_TEST(Integ_CarrierMultiStressTestSecure) +GM_TEST(DISABLED_CarrierStressTestSecure) +GM_TEST(DISABLED_CarrierMultiStressTestSecure) #endif -GM_TEST(Integ_CarrierMultiChannelTestSecure) -GM_TEST(Integ_CarrierBackpressureTestSecure) -GM_TEST(Integ_CarrierACKTestSecure) +GM_TEST(DISABLED_CarrierMultiChannelTestSecure) +GM_TEST(DISABLED_CarrierBackpressureTestSecure) +GM_TEST(DISABLED_CarrierACKTestSecure) #endif diff --git a/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp b/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp index 8ec3ad540f..dd0d6f1b2b 100644 --- a/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp +++ b/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp @@ -172,7 +172,7 @@ public: namespace UnitTest { - class Integ_CarrierStreamBasicTest + class DISABLED_CarrierStreamBasicTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -330,7 +330,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamAsyncHandshakeTest + class DISABLED_CarrierStreamAsyncHandshakeTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -462,7 +462,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamStressTest + class CarrierStreamStressTest : public GridMateMPTestFixture , protected SocketDriverSupplier , public ::testing::Test @@ -470,7 +470,7 @@ namespace UnitTest public: }; - TEST_F(Integ_CarrierStreamStressTest, Stress_Test) + TEST_F(CarrierStreamStressTest, DISABLED_Stress_Test) { CarrierStreamCallbacksHandler clientCB, serverCB; UnitTest::TestCarrierDesc serverCarrierDesc, clientCarrierDesc; @@ -581,7 +581,7 @@ namespace UnitTest ////////////////////////////////////////////////////////////////////////// } - class Integ_CarrierStreamTest + class DISABLED_CarrierStreamTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -783,7 +783,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamDisconnectDetectionTest + class DISABLED_CarrierStreamDisconnectDetectionTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -873,7 +873,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamMultiChannelTest + class DISABLED_CarrierStreamMultiChannelTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -999,8 +999,8 @@ namespace UnitTest } GM_TEST_SUITE(CarrierStreamSuite) - GM_TEST(Integ_CarrierStreamBasicTest) - GM_TEST(Integ_CarrierStreamTest) - GM_TEST(Integ_CarrierStreamAsyncHandshakeTest) - GM_TEST(Integ_CarrierStreamMultiChannelTest) + GM_TEST(DISABLED_CarrierStreamBasicTest) + GM_TEST(DISABLED_CarrierStreamTest) + GM_TEST(DISABLED_CarrierStreamAsyncHandshakeTest) + GM_TEST(DISABLED_CarrierStreamMultiChannelTest) GM_TEST_SUITE_END() diff --git a/Code/Framework/GridMate/Tests/Replica.cpp b/Code/Framework/GridMate/Tests/Replica.cpp index 83a3a1f5a1..5fef135347 100644 --- a/Code/Framework/GridMate/Tests/Replica.cpp +++ b/Code/Framework/GridMate/Tests/Replica.cpp @@ -6,7 +6,6 @@ * */ #include "Tests.h" -#include "TestProfiler.h" #include @@ -1888,12 +1887,12 @@ protected: }; //----------------------------------------------------------------------------- -class Integ_ReplicaGMTest +class ReplicaGMTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test {}; -TEST_F(Integ_ReplicaGMTest, ReplicaTest) +TEST_F(ReplicaGMTest, DISABLED_ReplicaTest) { ReplicaChunkDescriptorTable::Get().RegisterChunkType(); ReplicaChunkDescriptorTable::Get().RegisterChunkType(); @@ -2157,7 +2156,7 @@ TEST_F(Integ_ReplicaGMTest, ReplicaTest) } } -class Integ_ForcedReplicaMigrationTest +class ForcedReplicaMigrationTest : public UnitTest::GridMateMPTestFixture , public ReplicaMgrCallbackBus::Handler , public MigratableReplica::MigratableReplicaDebugMsgs::EBus::Handler @@ -2186,8 +2185,8 @@ class Integ_ForcedReplicaMigrationTest } public: - Integ_ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } - ~Integ_ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } + ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } + ~ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } enum @@ -2205,11 +2204,11 @@ public: AZStd::unordered_map m_replicaOwnership; }; -const int Integ_ForcedReplicaMigrationTest::k_frameTimePerNodeMs; -const int Integ_ForcedReplicaMigrationTest::k_numFramesToRun; -const int Integ_ForcedReplicaMigrationTest::k_hostSendRateMs; +const int ForcedReplicaMigrationTest::k_frameTimePerNodeMs; +const int ForcedReplicaMigrationTest::k_numFramesToRun; +const int ForcedReplicaMigrationTest::k_hostSendRateMs; -TEST_F(Integ_ForcedReplicaMigrationTest, ForcedReplicaMigrationTest) +TEST_F(ForcedReplicaMigrationTest, DISABLED_ForcedReplicaMigrationTest) { ReplicaChunkDescriptorTable::Get().RegisterChunkType(); ReplicaChunkDescriptorTable::Get().RegisterChunkType(); @@ -2360,7 +2359,7 @@ TEST_F(Integ_ForcedReplicaMigrationTest, ForcedReplicaMigrationTest) MigratableReplica::MigratableReplicaDebugMsgs::EBus::Handler::BusDisconnect(); } -class Integ_ReplicaMigrationRequestTest +class ReplicaMigrationRequestTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { @@ -2516,7 +2515,7 @@ public: static const int k_hostSendTimeMs = k_frameTimePerNodeMs * TotalNodes * 4; // limiting host send rate to be x4 times slower than tick }; -TEST_F(Integ_ReplicaMigrationRequestTest, ReplicaMigrationRequestTest) +TEST_F(ReplicaMigrationRequestTest, DISABLED_ReplicaMigrationRequestTest) { /* Topology: @@ -2837,11 +2836,11 @@ TEST_F(Integ_ReplicaMigrationRequestTest, ReplicaMigrationRequestTest) } } -const int Integ_ReplicaMigrationRequestTest::k_frameTimePerNodeMs; -const int Integ_ReplicaMigrationRequestTest::k_hostSendTimeMs; +const int ReplicaMigrationRequestTest::k_frameTimePerNodeMs; +const int ReplicaMigrationRequestTest::k_hostSendTimeMs; -class Integ_PeerRejoinTest +class PeerRejoinTest : public UnitTest::GridMateMPTestFixture , public ReplicaMgrCallbackBus::Handler , public ::testing::Test @@ -2860,11 +2859,11 @@ class Integ_PeerRejoinTest } public: - Integ_PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } - ~Integ_PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } + PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } + ~PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } }; -TEST_F(Integ_PeerRejoinTest, PeerRejoinTest) +TEST_F(PeerRejoinTest, DISABLED_PeerRejoinTest) { ReplicaChunkDescriptorTable::Get().RegisterChunkType(); ReplicaChunkDescriptorTable::Get().RegisterChunkType(); @@ -3011,7 +3010,7 @@ TEST_F(Integ_PeerRejoinTest, PeerRejoinTest) } } -class Integ_ReplicationSecurityOptionsTest +class ReplicationSecurityOptionsTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { @@ -3156,7 +3155,7 @@ public: using TestChunkPtr = AZStd::intrusive_ptr ; }; -TEST_F(Integ_ReplicationSecurityOptionsTest, ReplicationSecurityOptionsTest) +TEST_F(ReplicationSecurityOptionsTest, DISABLED_ReplicationSecurityOptionsTest) { AZ_TracePrintf("GridMate", "\n"); @@ -3356,7 +3355,7 @@ TEST_F(Integ_ReplicationSecurityOptionsTest, ReplicationSecurityOptionsTest) Replica update time (msec): avg=4.94, min=1, max=9 (peers=40, replicas=16000, freq=10%, samples=4000) Replica update time (msec): avg=8.05, min=6, max=15 (peers=40, replicas=16000, freq=100%, samples=4000) */ -class Integ_ReplicaStressTest +class DISABLED_ReplicaStressTest : public UnitTest::GridMateMPTestFixture { public: @@ -3388,7 +3387,7 @@ public: static const int BASE_PORT = 44270; // TODO: Reduce the size or disable the test for platforms which can't allocate 2 GiB - Integ_ReplicaStressTest() + DISABLED_ReplicaStressTest() : UnitTest::GridMateMPTestFixture(2000u * 1024u * 1024u) {} @@ -3516,33 +3515,33 @@ public: virtual void RunStressTests(MPSession* sessions, vector >& replicas) { // testing 3 cases & waiting for system to settle in between - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); Wait(sessions, replicas, 50, FRAME_TIME); - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.0); // no replicas are dirty - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 1, FRAME_TIME, 1.0); // single burst dirty replicas Wait(sessions, replicas, 2, FRAME_TIME); - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.1); // 10% of replicas are marked dirty every frame - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 1.0); // every replica is marked dirty every frame - TestProfiler::PrintProfilingTotal("GridMate"); - TestProfiler::PrintProfilingSelf("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingSelf("GridMate"); - TestProfiler::StopProfiling(); + //TestProfiler::StopProfiling(); } virtual void MarkChanging(vector >& replicas, double freq) @@ -3623,8 +3622,8 @@ public: Replica update time (msec): avg=2.01, min=1, max=5 (peers=40, replicas=16000, freq=10%, samples=4000) Replica update time (msec): avg=4.61, min=3, max=10 (peers=40, replicas=16000, freq=50%, samples=4000) */ -class Integ_ReplicaStableStressTest - : public Integ_ReplicaStressTest +class DISABLED_ReplicaStableStressTest + : public DISABLED_ReplicaStressTest { public: @@ -3636,21 +3635,21 @@ public: void RunStressTests(MPSession* sessions, vector >& replicas) override { - Integ_ReplicaStressTest::MarkChanging(replicas, 0.1); // picks 10% of replicas + DISABLED_ReplicaStressTest::MarkChanging(replicas, 0.1); // picks 10% of replicas Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.1); - TestProfiler::PrintProfilingTotal("GridMate"); - TestProfiler::PrintProfilingSelf("GridMate"); + /*TestProfiler::PrintProfilingTotal("GridMate"); + TestProfiler::PrintProfilingSelf("GridMate");*/ - Integ_ReplicaStressTest::MarkChanging(replicas, 0.5); // picks 50% of replicas + DISABLED_ReplicaStressTest::MarkChanging(replicas, 0.5); // picks 50% of replicas Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.5); - TestProfiler::PrintProfilingTotal("GridMate"); + /*TestProfiler::PrintProfilingTotal("GridMate"); TestProfiler::PrintProfilingSelf("GridMate"); - TestProfiler::StopProfiling(); + TestProfiler::StopProfiling();*/ } }; @@ -3666,7 +3665,7 @@ public: * expected |none |brst | capped |under cap |brst | capped | * */ -class Integ_ReplicaBandiwdthTest +class DISABLED_ReplicaBandiwdthTest : public UnitTest::GridMateMPTestFixture { public: @@ -3944,9 +3943,9 @@ GM_TEST_SUITE(ReplicaSuite) GM_TEST(InterpolatorTest) #if !defined(AZ_DEBUG_BUILD) // these tests are a little slow for debug -GM_TEST(Integ_ReplicaBandiwdthTest) -GM_TEST(Integ_ReplicaStressTest) -GM_TEST(Integ_ReplicaStableStressTest) +GM_TEST(DISABLED_ReplicaBandiwdthTest) +GM_TEST(DISABLED_ReplicaStressTest) +GM_TEST(DISABLED_ReplicaStableStressTest) #endif GM_TEST_SUITE_END() diff --git a/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp b/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp index f6f88d2dff..86f9f4605b 100644 --- a/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp +++ b/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp @@ -457,13 +457,13 @@ namespace ReplicaBehavior { Completed, }; - class Integ_SimpleBehaviorTest + class SimpleBehaviorTest : public UnitTest::GridMateMPTestFixture { public: //GM_CLASS_ALLOCATOR(SimpleBehaviorTest); - Integ_SimpleBehaviorTest() + SimpleBehaviorTest() : m_sessionCount(0) { } virtual int GetNumSessions() { return 0; } @@ -654,11 +654,11 @@ namespace ReplicaBehavior { * * This is a simple sanity check to ensure the logic sends the update when it's necessary. */ - class Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData - : public Integ_SimpleBehaviorTest + class Replica_DontSendDataSets_WithNoDiffFromCtorData + : public SimpleBehaviorTest { public: - Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData() + Replica_DontSendDataSets_WithNoDiffFromCtorData() : m_replicaIdDefault(InvalidReplicaId), m_replicaIdModified(InvalidReplicaId) { } @@ -774,9 +774,9 @@ namespace ReplicaBehavior { FilteredHook m_driller; }; - TEST(Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData, Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData) + TEST(Replica_DontSendDataSets_WithNoDiffFromCtorData, DISABLED_Replica_DontSendDataSets_WithNoDiffFromCtorData) { - Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData tester; + Replica_DontSendDataSets_WithNoDiffFromCtorData tester; tester.run(); } @@ -784,11 +784,11 @@ namespace ReplicaBehavior { * This test checks the actual size of the replica as marshalled in the binary payload. * The assessment of the payload size is done using driller EBus. */ - class Integ_ReplicaDefaultDataSetDriller - : public Integ_SimpleBehaviorTest + class ReplicaDefaultDataSetDriller + : public SimpleBehaviorTest { public: - Integ_ReplicaDefaultDataSetDriller() + ReplicaDefaultDataSetDriller() : m_replicaId(InvalidReplicaId) { } @@ -815,7 +815,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_ReplicaDefaultDataSetDriller() override + ~ReplicaDefaultDataSetDriller() override { m_driller.BusDisconnect(); } @@ -880,11 +880,11 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - const int Integ_ReplicaDefaultDataSetDriller::NonDefaultValue; + const int ReplicaDefaultDataSetDriller::NonDefaultValue; - TEST(Integ_ReplicaDefaultDataSetDriller, Integ_ReplicaDefaultDataSetDriller) + TEST(ReplicaDefaultDataSetDriller, DISABLED_ReplicaDefaultDataSetDriller) { - Integ_ReplicaDefaultDataSetDriller tester; + ReplicaDefaultDataSetDriller tester; tester.run(); } @@ -892,11 +892,11 @@ namespace ReplicaBehavior { * This test checks the actual size of the replica as marshalled in the binary payload. * The assessment of the payload size is done using driller EBus. */ - class Integ_Replica_ComparePackingBoolsVsU8 - : public Integ_SimpleBehaviorTest + class Replica_ComparePackingBoolsVsU8 + : public SimpleBehaviorTest { public: - Integ_Replica_ComparePackingBoolsVsU8() + Replica_ComparePackingBoolsVsU8() : m_replicaBoolsId(InvalidReplicaId) , m_replicaU8Id(InvalidReplicaId) { @@ -928,7 +928,7 @@ namespace ReplicaBehavior { m_replicaU8Id = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica2); } - ~Integ_Replica_ComparePackingBoolsVsU8() override + ~Replica_ComparePackingBoolsVsU8() override { m_driller.BusDisconnect(); } @@ -1020,17 +1020,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaU8Id; }; - TEST(Integ_Replica_ComparePackingBoolsVsU8, Integ_Replica_ComparePackingBoolsVsU8) + TEST(Replica_ComparePackingBoolsVsU8, DISABLED_Replica_ComparePackingBoolsVsU8) { - Integ_Replica_ComparePackingBoolsVsU8 tester; + Replica_ComparePackingBoolsVsU8 tester; tester.run(); } - class Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary - : public Integ_SimpleBehaviorTest + class CheckDataSetStreamIsntWrittenMoreThanNecessary + : public SimpleBehaviorTest { public: - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary() + CheckDataSetStreamIsntWrittenMoreThanNecessary() : m_replicaId(InvalidReplicaId) { } @@ -1057,7 +1057,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary() override + ~CheckDataSetStreamIsntWrittenMoreThanNecessary() override { m_driller.BusDisconnect(); } @@ -1117,17 +1117,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary, Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary) + TEST(CheckDataSetStreamIsntWrittenMoreThanNecessary, DISABLED_CheckDataSetStreamIsntWrittenMoreThanNecessary) { - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary tester; + CheckDataSetStreamIsntWrittenMoreThanNecessary tester; tester.run(); } - class Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty - : public Integ_SimpleBehaviorTest + class CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty + : public SimpleBehaviorTest { public: - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() + CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() : m_replicaId(InvalidReplicaId) { } @@ -1154,7 +1154,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() override + ~CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() override { m_driller.BusDisconnect(); } @@ -1213,17 +1213,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty, Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty) + TEST(CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty, DISABLED_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty) { - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty tester; + CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty tester; tester.run(); } - class Integ_CheckReplicaIsntSentWithNoChanges - : public Integ_SimpleBehaviorTest + class CheckReplicaIsntSentWithNoChanges + : public SimpleBehaviorTest { public: - Integ_CheckReplicaIsntSentWithNoChanges() + CheckReplicaIsntSentWithNoChanges() : m_replicaId(InvalidReplicaId) { } @@ -1248,7 +1248,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckReplicaIsntSentWithNoChanges() override + ~CheckReplicaIsntSentWithNoChanges() override { m_driller.BusDisconnect(); } @@ -1323,17 +1323,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckReplicaIsntSentWithNoChanges, Integ_CheckReplicaIsntSentWithNoChanges) + TEST(CheckReplicaIsntSentWithNoChanges, DISABLED_CheckReplicaIsntSentWithNoChanges) { - Integ_CheckReplicaIsntSentWithNoChanges tester; + CheckReplicaIsntSentWithNoChanges tester; tester.run(); } - class Integ_CheckEntityScriptReplicaIsntSentWithNoChanges - : public Integ_SimpleBehaviorTest + class CheckEntityScriptReplicaIsntSentWithNoChanges + : public SimpleBehaviorTest { public: - Integ_CheckEntityScriptReplicaIsntSentWithNoChanges() + CheckEntityScriptReplicaIsntSentWithNoChanges() : m_replicaId(InvalidReplicaId) { } @@ -1359,7 +1359,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckEntityScriptReplicaIsntSentWithNoChanges() override + ~CheckEntityScriptReplicaIsntSentWithNoChanges() override { m_driller.BusDisconnect(); } @@ -1410,9 +1410,9 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckEntityScriptReplicaIsntSentWithNoChanges, Integ_CheckEntityScriptReplicaIsntSentWithNoChanges) + TEST(CheckEntityScriptReplicaIsntSentWithNoChanges, DISABLED_CheckEntityScriptReplicaIsntSentWithNoChanges) { - Integ_CheckEntityScriptReplicaIsntSentWithNoChanges tester; + CheckEntityScriptReplicaIsntSentWithNoChanges tester; tester.run(); } diff --git a/Code/Framework/GridMate/Tests/ReplicaMedium.cpp b/Code/Framework/GridMate/Tests/ReplicaMedium.cpp index 61fe9d65b2..2e8d2a3a73 100644 --- a/Code/Framework/GridMate/Tests/ReplicaMedium.cpp +++ b/Code/Framework/GridMate/Tests/ReplicaMedium.cpp @@ -596,12 +596,12 @@ public: //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -class MPSession +class MPSessionMedium : public CarrierEventBus::Handler { public: - ~MPSession() override + ~MPSessionMedium() override { CarrierEventBus::Handler::BusDisconnect(); } @@ -708,14 +708,14 @@ enum class TestStatus Completed, }; -class Integ_SimpleTest +class SimpleTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { public: - //GM_CLASS_ALLOCATOR(Integ_SimpleTest); + //GM_CLASS_ALLOCATOR(SimpleTest); - Integ_SimpleTest() + SimpleTest() : m_sessionCount(0) { } virtual int GetNumSessions() { return 0; } @@ -858,15 +858,15 @@ public: } int m_sessionCount; - AZStd::array m_sessions; + AZStd::array m_sessions; AZStd::unique_ptr m_defaultSimulator; }; -class Integ_ReplicaChunkRPCExec - : public Integ_SimpleTest +class ReplicaChunkRPCExec + : public SimpleTest { public: - Integ_ReplicaChunkRPCExec() + ReplicaChunkRPCExec() : m_chunk(nullptr) , m_replicaId(0) { } @@ -893,7 +893,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaChunkRPCExec, ReplicaChunkRPCExec) +TEST_F(ReplicaChunkRPCExec, DISABLED_ReplicaChunkRPCExec) { RunTickLoop([this](int tick) -> TestStatus { @@ -1050,8 +1050,8 @@ int DestroyRPCChunk::s_afterDestroyFromPrimaryCalls = 0; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -class Integ_ReplicaDestroyedInRPC - : public Integ_SimpleTest +class ReplicaDestroyedInRPC + : public SimpleTest { public: enum @@ -1080,7 +1080,7 @@ public: ReplicaId m_repId[2]; }; -TEST_F(Integ_ReplicaDestroyedInRPC, ReplicaDestroyedInRPC) +TEST_F(ReplicaDestroyedInRPC, DISABLED_ReplicaDestroyedInRPC) { RunTickLoop([this](int tick)->TestStatus { @@ -1129,11 +1129,11 @@ TEST_F(Integ_ReplicaDestroyedInRPC, ReplicaDestroyedInRPC) }); } -class Integ_ReplicaChunkAddWhileReplicated - : public Integ_SimpleTest +class ReplicaChunkAddWhileReplicated + : public SimpleTest { public: - Integ_ReplicaChunkAddWhileReplicated() + ReplicaChunkAddWhileReplicated() : m_replica(nullptr) , m_chunk(nullptr) , m_replicaId(0) @@ -1161,7 +1161,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaChunkAddWhileReplicated, ReplicaChunkAddWhileReplicated) +TEST_F(ReplicaChunkAddWhileReplicated, DISABLED_ReplicaChunkAddWhileReplicated) { RunTickLoop([this](int tick)-> TestStatus { @@ -1203,11 +1203,11 @@ TEST_F(Integ_ReplicaChunkAddWhileReplicated, ReplicaChunkAddWhileReplicated) } -class Integ_ReplicaRPCValues - : public Integ_SimpleTest +class ReplicaRPCValues + : public SimpleTest { public: - Integ_ReplicaRPCValues() + ReplicaRPCValues() : m_replica(nullptr) , m_chunk(nullptr) , m_replicaId(0) @@ -1236,7 +1236,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaRPCValues, ReplicaRPCValues) +TEST_F(ReplicaRPCValues, DISABLED_ReplicaRPCValues) { RunTickLoop([this](int tick)-> TestStatus { @@ -1257,11 +1257,11 @@ TEST_F(Integ_ReplicaRPCValues, ReplicaRPCValues) }); } -class Integ_FullRPCValues - : public Integ_SimpleTest +class FullRPCValues + : public SimpleTest { public: - Integ_FullRPCValues() + FullRPCValues() : m_replica(nullptr) , m_chunk(nullptr) , m_replicaId(0) @@ -1290,7 +1290,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_FullRPCValues, FullRPCValues) +TEST_F(FullRPCValues, DISABLED_FullRPCValues) { RunTickLoop([this](int tick)-> TestStatus { @@ -1364,11 +1364,11 @@ TEST_F(Integ_FullRPCValues, FullRPCValues) } -class Integ_ReplicaRemoveProxy - : public Integ_SimpleTest +class ReplicaRemoveProxy + : public SimpleTest { public: - Integ_ReplicaRemoveProxy() + ReplicaRemoveProxy() : m_replica(nullptr) , m_replicaId(0) { @@ -1395,7 +1395,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaRemoveProxy, ReplicaRemoveProxy) +TEST_F(ReplicaRemoveProxy, DISABLED_ReplicaRemoveProxy) { RunTickLoop([this](int tick)-> TestStatus { @@ -1424,11 +1424,11 @@ TEST_F(Integ_ReplicaRemoveProxy, ReplicaRemoveProxy) } -class Integ_ReplicaChunkEvents - : public Integ_SimpleTest +class ReplicaChunkEvents + : public SimpleTest { public: - Integ_ReplicaChunkEvents() + ReplicaChunkEvents() : m_replicaId(InvalidReplicaId) , m_chunk(nullptr) , m_proxyChunk(nullptr) @@ -1463,7 +1463,7 @@ public: AllEventChunk::Ptr m_proxyChunk; }; -TEST_F(Integ_ReplicaChunkEvents, ReplicaChunkEvents) +TEST_F(ReplicaChunkEvents, DISABLED_ReplicaChunkEvents) { RunTickLoop([this](int tick)-> TestStatus { @@ -1501,11 +1501,11 @@ TEST_F(Integ_ReplicaChunkEvents, ReplicaChunkEvents) } -class Integ_ReplicaChunksBeyond32 - : public Integ_SimpleTest +class ReplicaChunksBeyond32 + : public SimpleTest { public: - Integ_ReplicaChunksBeyond32() + ReplicaChunksBeyond32() : m_replicaId(InvalidReplicaId) { } @@ -1537,7 +1537,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaChunksBeyond32, ReplicaChunksBeyond32) +TEST_F(ReplicaChunksBeyond32, DISABLED_ReplicaChunksBeyond32) { RunTickLoop([this](int tick)-> TestStatus { @@ -1565,11 +1565,11 @@ TEST_F(Integ_ReplicaChunksBeyond32, ReplicaChunksBeyond32) } -class Integ_ReplicaChunkEventsDeactivate - : public Integ_SimpleTest +class ReplicaChunkEventsDeactivate + : public SimpleTest { public: - Integ_ReplicaChunkEventsDeactivate() + ReplicaChunkEventsDeactivate() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -1604,7 +1604,7 @@ public: AllEventChunk::Ptr m_proxyChunk; }; -TEST_F(Integ_ReplicaChunkEventsDeactivate, ReplicaChunkEventsDeactivate) +TEST_F(ReplicaChunkEventsDeactivate, DISABLED_ReplicaChunkEventsDeactivate) { RunTickLoop([this](int tick)-> TestStatus { @@ -1649,11 +1649,11 @@ TEST_F(Integ_ReplicaChunkEventsDeactivate, ReplicaChunkEventsDeactivate) } -class Integ_ReplicaDriller - : public Integ_SimpleTest +class ReplicaDriller + : public SimpleTest { public: - Integ_ReplicaDriller() + ReplicaDriller() : m_replicaId(InvalidReplicaId) { } @@ -2007,7 +2007,7 @@ public: m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_ReplicaDriller() override + ~ReplicaDriller() override { m_driller.BusDisconnect(); } @@ -2016,7 +2016,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaDriller, ReplicaDriller) +TEST_F(ReplicaDriller, DISABLED_ReplicaDriller) { RunTickLoop([this](int tick)-> TestStatus { @@ -2082,11 +2082,11 @@ TEST_F(Integ_ReplicaDriller, ReplicaDriller) } -class Integ_DataSetChangedTest - : public Integ_SimpleTest +class DataSetChangedTest + : public SimpleTest { public: - Integ_DataSetChangedTest() + DataSetChangedTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2115,7 +2115,7 @@ public: DataSetChunk::Ptr m_chunk; }; -TEST_F(Integ_DataSetChangedTest, DataSetChangedTest) +TEST_F(DataSetChangedTest, DISABLED_DataSetChangedTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2144,11 +2144,11 @@ TEST_F(Integ_DataSetChangedTest, DataSetChangedTest) } -class Integ_CustomHandlerTest - : public Integ_SimpleTest +class CustomHandlerTest + : public SimpleTest { public: - Integ_CustomHandlerTest() + CustomHandlerTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2181,7 +2181,7 @@ public: AZStd::scoped_ptr m_proxyHandler; }; -TEST_F(Integ_CustomHandlerTest, CustomHandlerTest) +TEST_F(CustomHandlerTest, DISABLED_CustomHandlerTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2234,11 +2234,11 @@ TEST_F(Integ_CustomHandlerTest, CustomHandlerTest) } -class Integ_NonConstMarshalerTest - : public Integ_SimpleTest +class NonConstMarshalerTest + : public SimpleTest { public: - Integ_NonConstMarshalerTest() + NonConstMarshalerTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2266,7 +2266,7 @@ public: NonConstMarshalerChunk::Ptr m_chunk; }; -TEST_F(Integ_NonConstMarshalerTest, NonConstMarshalerTest) +TEST_F(NonConstMarshalerTest, DISABLED_NonConstMarshalerTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2309,11 +2309,11 @@ TEST_F(Integ_NonConstMarshalerTest, NonConstMarshalerTest) } -class Integ_SourcePeerTest - : public Integ_SimpleTest +class SourcePeerTest + : public SimpleTest { public: - Integ_SourcePeerTest() + SourcePeerTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2343,7 +2343,7 @@ public: SourcePeerChunk::Ptr m_chunk2; }; -TEST_F(Integ_SourcePeerTest, SourcePeerTest) +TEST_F(SourcePeerTest, DISABLED_SourcePeerTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2404,8 +2404,8 @@ TEST_F(Integ_SourcePeerTest, SourcePeerTest) } -class Integ_SendWithPriority - : public Integ_SimpleTest +class SendWithPriority + : public SimpleTest { public: enum @@ -2438,8 +2438,8 @@ public: { public: ReplicaDrillerHook() - : m_expectedSendValue(Integ_SendWithPriority::kNumReplicas) - , m_expectedRecvValue(Integ_SendWithPriority::kNumReplicas) + : m_expectedSendValue(SendWithPriority::kNumReplicas) + , m_expectedRecvValue(SendWithPriority::kNumReplicas) { } @@ -2495,7 +2495,7 @@ public: PriorityChunk::Ptr m_chunks[kNumReplicas]; }; -TEST_F(Integ_SendWithPriority, SendWithPriority) +TEST_F(SendWithPriority, DISABLED_SendWithPriority) { RunTickLoop([this](int tick)-> TestStatus { @@ -2511,8 +2511,8 @@ TEST_F(Integ_SendWithPriority, SendWithPriority) } -class Integ_SuspendUpdatesTest - : public Integ_SimpleTest +class SuspendUpdatesTest + : public SimpleTest { public: enum @@ -2597,7 +2597,7 @@ public: unsigned int m_numRpcCalled = 0; }; -TEST_F(Integ_SuspendUpdatesTest, SuspendUpdatesTest) +TEST_F(SuspendUpdatesTest, DISABLED_SuspendUpdatesTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2657,7 +2657,7 @@ TEST_F(Integ_SuspendUpdatesTest, SuspendUpdatesTest) } -class Integ_BasicHostChunkDescriptorTest +class BasicHostChunkDescriptorTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { @@ -2694,17 +2694,17 @@ public: static int nProxyActivations; }; }; -int Integ_BasicHostChunkDescriptorTest::HostChunk::nPrimaryActivations = 0; -int Integ_BasicHostChunkDescriptorTest::HostChunk::nProxyActivations = 0; +int BasicHostChunkDescriptorTest::HostChunk::nPrimaryActivations = 0; +int BasicHostChunkDescriptorTest::HostChunk::nProxyActivations = 0; -TEST_F(Integ_BasicHostChunkDescriptorTest, BasicHostChunkDescriptorTest) +TEST_F(BasicHostChunkDescriptorTest, DISABLED_BasicHostChunkDescriptorTest) { AZ_TracePrintf("GridMate", "\n"); // Register test chunks ReplicaChunkDescriptorTable::Get().RegisterChunkType>(); - MPSession nodes[nNodes]; + MPSessionMedium nodes[nNodes]; // initialize transport int basePort = 4427; @@ -2791,8 +2791,8 @@ TEST_F(Integ_BasicHostChunkDescriptorTest, BasicHostChunkDescriptorTest) * Create and immedietly destroy primary replica * Test that it does not result in any network sync */ -class Integ_CreateDestroyPrimary - : public Integ_SimpleTest +class CreateDestroyPrimary + : public SimpleTest , public Debug::ReplicaDrillerBus::Handler { public: @@ -2827,7 +2827,7 @@ public: } }; -TEST_F(Integ_CreateDestroyPrimary, CreateDestroyPrimary) +TEST_F(CreateDestroyPrimary, DISABLED_CreateDestroyPrimary) { RunTickLoop([this](int tick)-> TestStatus { @@ -2861,7 +2861,7 @@ TEST_F(Integ_CreateDestroyPrimary, CreateDestroyPrimary) * The ReplicaTarget will prevent sending more updates. */ class ReplicaACKfeedbackTestFixture - : public Integ_SimpleTest + : public SimpleTest { public: ReplicaACKfeedbackTestFixture() @@ -2900,7 +2900,7 @@ public: size_t m_replicaBytesSentPrev = 0; ReplicaId m_replicaId; - Integ_ReplicaDriller::ReplicaDrillerHook m_driller; + ReplicaDriller::ReplicaDrillerHook m_driller; }; TEST_F(ReplicaACKfeedbackTestFixture, ReplicaACKfeedbackTest) diff --git a/Code/Framework/GridMate/Tests/Session.cpp b/Code/Framework/GridMate/Tests/Session.cpp index d4f56871c5..c793c3d450 100644 --- a/Code/Framework/GridMate/Tests/Session.cpp +++ b/Code/Framework/GridMate/Tests/Session.cpp @@ -40,7 +40,7 @@ namespace UnitTest } } - class Integ_LANSessionMatchmakingParamsTest + class DISABLED_LANSessionMatchmakingParamsTest : public GridMateMPTestFixture , public SessionEventBus::MultiHandler { @@ -52,7 +52,7 @@ namespace UnitTest } public: - Integ_LANSessionMatchmakingParamsTest(bool useIPv6 = false) + DISABLED_LANSessionMatchmakingParamsTest(bool useIPv6 = false) : m_hostSession(nullptr) , m_clientGridMate(nullptr) { @@ -71,7 +71,7 @@ namespace UnitTest AZ_TEST_ASSERT(GridMate::LANSessionServiceBus::FindFirstHandler(m_clientGridMate) != nullptr); ////////////////////////////////////////////////////////////////////////// } - ~Integ_LANSessionMatchmakingParamsTest() override + ~DISABLED_LANSessionMatchmakingParamsTest() override { SessionEventBus::MultiHandler::BusDisconnect(m_gridMate); SessionEventBus::MultiHandler::BusDisconnect(m_clientGridMate); @@ -192,7 +192,7 @@ namespace UnitTest IGridMate* m_clientGridMate; }; - class Integ_LANSessionTest + class DISABLED_LANSessionTest : public GridMateMPTestFixture { class TestPeerInfo @@ -264,7 +264,7 @@ namespace UnitTest }; public: - Integ_LANSessionTest(bool useIPv6 = false) + DISABLED_LANSessionTest(bool useIPv6 = false) { m_driverType = useIPv6 ? Driver::BSD_AF_INET6 : Driver::BSD_AF_INET; m_doSessionParamsTest = k_numMachines > 1; @@ -290,7 +290,7 @@ namespace UnitTest AZ_TEST_ASSERT(LANSessionServiceBus::FindFirstHandler(m_peers[i].m_gridMate) != nullptr); } } - ~Integ_LANSessionTest() override + ~DISABLED_LANSessionTest() override { StopGridMateService(m_peers[0].m_gridMate); @@ -555,15 +555,15 @@ namespace UnitTest bool m_doSessionParamsTest; }; - class Integ_LANSessionTestIPv6 - : public Integ_LANSessionTest + class DISABLED_LANSessionTestIPv6 + : public DISABLED_LANSessionTest { public: - Integ_LANSessionTestIPv6() - : Integ_LANSessionTest(true) {} + DISABLED_LANSessionTestIPv6() + : DISABLED_LANSessionTest(true) {} }; - class Integ_LANMultipleSessionTest + class DISABLED_LANMultipleSessionTest : public GridMateMPTestFixture , public SessionEventBus::Handler { @@ -620,7 +620,7 @@ namespace UnitTest m_sessions[i] = nullptr; } - Integ_LANMultipleSessionTest() + DISABLED_LANMultipleSessionTest() : GridMateMPTestFixture(200 * 1024 * 1024) { ////////////////////////////////////////////////////////////////////////// @@ -645,7 +645,7 @@ namespace UnitTest } } - ~Integ_LANMultipleSessionTest() override + ~DISABLED_LANMultipleSessionTest() override { GridMate::StopGridMateService(m_gridMates[0]); @@ -799,7 +799,7 @@ namespace UnitTest * Testing session with low latency. This is special mode usually used by tools and communication channels * where we try to response instantly on messages. */ - class Integ_LANLatencySessionTest + class DISABLED_LANLatencySessionTest : public GridMateMPTestFixture , public SessionEventBus::Handler { @@ -857,7 +857,7 @@ namespace UnitTest m_sessions[i] = nullptr; } - Integ_LANLatencySessionTest() + DISABLED_LANLatencySessionTest() #ifdef AZ_TEST_LANLATENCY_ENABLE_MONSTER_BUFFER : GridMateMPTestFixture(50 * 1024 * 1024) #endif @@ -884,7 +884,7 @@ namespace UnitTest } } - ~Integ_LANLatencySessionTest() override + ~DISABLED_LANLatencySessionTest() override { StopGridMateService(m_gridMates[0]); @@ -1162,7 +1162,7 @@ namespace UnitTest * 5. After host migration we drop the new host again. (after migration we have 3 members). * Session should be fully operational at the end with 3 members left. */ - class Integ_LANSessionMigarationTestTest + class LANSessionMigarationTestTest : public SessionEventBus::Handler , public GridMateMPTestFixture { @@ -1257,7 +1257,7 @@ namespace UnitTest } } - Integ_LANSessionMigarationTestTest() + LANSessionMigarationTestTest() { ////////////////////////////////////////////////////////////////////////// // Create all grid mates @@ -1283,7 +1283,7 @@ namespace UnitTest //StartDrilling("lanmigration"); } - ~Integ_LANSessionMigarationTestTest() override + ~LANSessionMigarationTestTest() override { StopGridMateService(m_gridMates[0]); @@ -1476,7 +1476,7 @@ namespace UnitTest * 5. We join a 2 new members to the session. * Session should be fully operational at the end with 4 members in it. */ - class Integ_LANSessionMigarationTestTest2 + class LANSessionMigarationTestTest2 : public SessionEventBus::Handler , public GridMateMPTestFixture { @@ -1571,7 +1571,7 @@ namespace UnitTest } } } - Integ_LANSessionMigarationTestTest2() + LANSessionMigarationTestTest2() { ////////////////////////////////////////////////////////////////////////// // Create all grid mates @@ -1597,7 +1597,7 @@ namespace UnitTest //StartDrilling("lanmigration2"); } - ~Integ_LANSessionMigarationTestTest2() override + ~LANSessionMigarationTestTest2() override { StopGridMateService(m_gridMates[0]); @@ -1816,7 +1816,7 @@ namespace UnitTest * 3. Add 2 new joins to the original session. * Original session should remain fully operational with 4 members in it. */ - class Integ_LANSessionMigarationTestTest3 + class LANSessionMigarationTestTest3 : public SessionEventBus::Handler , public GridMateMPTestFixture { @@ -1910,7 +1910,7 @@ namespace UnitTest } } } - Integ_LANSessionMigarationTestTest3() + LANSessionMigarationTestTest3() { ////////////////////////////////////////////////////////////////////////// // Create all grid mates @@ -1936,7 +1936,7 @@ namespace UnitTest //StartDrilling("lanmigration2"); } - ~Integ_LANSessionMigarationTestTest3() override + ~LANSessionMigarationTestTest3() override { StopGridMateService(m_gridMates[0]); @@ -2122,13 +2122,13 @@ namespace UnitTest } GM_TEST_SUITE(SessionSuite) -GM_TEST(Integ_LANSessionMatchmakingParamsTest) -GM_TEST(Integ_LANSessionTest) +GM_TEST(DISABLED_LANSessionMatchmakingParamsTest) +GM_TEST(DISABLED_LANSessionTest) #if (AZ_TRAIT_GRIDMATE_TEST_SOCKET_IPV6_SUPPORT_ENABLED) -GM_TEST(Integ_LANSessionTestIPv6) +GM_TEST(DISABLED_LANSessionTestIPv6) #endif -GM_TEST(Integ_LANMultipleSessionTest) -GM_TEST(Integ_LANLatencySessionTest) +GM_TEST(DISABLED_LANMultipleSessionTest) +GM_TEST(DISABLED_LANLatencySessionTest) // Manually enabled tests (require 2+ machines and online services) //GM_TEST(LANSessionMigarationTestTest) diff --git a/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp b/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp index a7e9a7ccda..1f05520457 100644 --- a/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp +++ b/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp @@ -110,7 +110,7 @@ namespace UnitTest std::array m_buffer; }; - class Integ_StreamSecureSocketDriverTestsBindSocketEmpty + class DISABLED_StreamSecureSocketDriverTestsBindSocketEmpty : public GridMateMPTestFixture { public: @@ -134,7 +134,7 @@ namespace UnitTest } }; - class Integ_StreamSecureSocketDriverTestsConnection + class DISABLED_StreamSecureSocketDriverTestsConnection : public GridMateMPTestFixture { public: @@ -146,7 +146,7 @@ namespace UnitTest } }; - class Integ_StreamSecureSocketDriverTestsConnectionAndHelloWorld + class DISABLED_StreamSecureSocketDriverTestsConnectionAndHelloWorld : public GridMateMPTestFixture { public: @@ -190,7 +190,7 @@ namespace UnitTest } }; - class Integ_StreamSecureSocketDriverTestsPingPong + class DISABLED_StreamSecureSocketDriverTestsPingPong : public GridMateMPTestFixture { public: @@ -425,13 +425,13 @@ namespace UnitTest void BuildStateMachine() { - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_TOP), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateTop), AZ::HSM::InvalidStateId, TS_START); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_START), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateStart), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PING), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPing), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PING_GET_SERVER), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStatePingGetServer), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PONG), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPong), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PONG_GET_SERVER), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStatePongGetServer), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_IN_ERROR), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateInError), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_TOP), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateTop), AZ::HSM::InvalidStateId, TS_START); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_START), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateStart), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PING), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPing), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PING_GET_SERVER), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStatePingGetServer), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PONG), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPong), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PONG_GET_SERVER), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStatePongGetServer), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_IN_ERROR), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateInError), TS_TOP); m_stateMachine.Start(); } @@ -486,10 +486,10 @@ namespace UnitTest } GM_TEST_SUITE(StreamSecureSocketDriverTests) - GM_TEST(Integ_StreamSecureSocketDriverTestsBindSocketEmpty); - GM_TEST(Integ_StreamSecureSocketDriverTestsConnection); - GM_TEST(Integ_StreamSecureSocketDriverTestsConnectionAndHelloWorld); - GM_TEST(Integ_StreamSecureSocketDriverTestsPingPong); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsBindSocketEmpty); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsConnection); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsConnectionAndHelloWorld); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsPingPong); GM_TEST_SUITE_END() #endif // AZ_TRAIT_GRIDMATE_ENABLE_OPENSSL diff --git a/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp b/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp index f9e9395fbf..9dd22bedc7 100644 --- a/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp +++ b/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp @@ -308,7 +308,7 @@ namespace UnitTest } }; - class Integ_StreamSocketDriverTestsTooManyConnections + class DISABLED_StreamSocketDriverTestsTooManyConnections : public GridMateMPTestFixture { public: @@ -529,7 +529,7 @@ GM_TEST_SUITE(StreamSocketDriverTests) GM_TEST(StreamSocketDriverTestsSimpleLockStepConnection); GM_TEST(StreamSocketDriverTestsEstablishConnectAndSend); GM_TEST(StreamSocketDriverTestsManyRandomPackets); - GM_TEST(Integ_StreamSocketDriverTestsTooManyConnections); + GM_TEST(DISABLED_StreamSocketDriverTestsTooManyConnections); GM_TEST(StreamSocketDriverTestsClientToInvalidServer); GM_TEST(StreamSocketDriverTestsManySends); diff --git a/Code/Framework/GridMate/Tests/TestProfiler.cpp b/Code/Framework/GridMate/Tests/TestProfiler.cpp deleted file mode 100644 index 26e9312ecf..0000000000 --- a/Code/Framework/GridMate/Tests/TestProfiler.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#include "Tests.h" -#include "TestProfiler.h" - -#include -#include - -#include -#include - -using namespace GridMate; - -typedef set ProfilerSet; - -static bool CollectPerformanceCounters(const AZ::Debug::ProfilerRegister& reg, const AZStd::thread_id&, ProfilerSet& profilers, const char* systemId) -{ - if (reg.m_type != AZ::Debug::ProfilerRegister::PRT_TIME) - { - return true; - } - if (reg.m_systemId != AZ::Crc32(systemId)) - { - return true; - } - - const AZ::Debug::ProfilerRegister* profReg = ® - profilers.insert(profReg); - return true; -} - -static AZStd::string FormatString(const AZStd::string& pre, const AZStd::string& name, const AZStd::string& post, AZ::u64 time, AZ::u64 calls) -{ - AZStd::string units = "us"; - if (AZ::u64 divtime = time / 1000) - { - time = divtime; - units = "ms"; - } - return AZStd::string::format("%s%s %s %10llu%s (%llu calls)\n", pre.c_str(), name.c_str(), post.c_str(), time, units.c_str(), calls); -} - -struct TotalSortContainer -{ - TotalSortContainer(const AZ::Debug::ProfilerRegister* self = nullptr) - { - m_self = self; - } - - void Print(AZ::s32 level, const char* systemId) - { - if (m_self && level >= 0) - { - AZStd::string levelIndent; - for (AZ::s32 i = 0; i < level; i++) - { - levelIndent += (i == level - 1) ? "+---" : "| "; - } - AZStd::string name = m_self->m_name ? m_self->m_name : m_self->m_function; - AZStd::string outputTotal = FormatString(levelIndent, name, " Total:", m_self->m_timeData.m_time, m_self->m_timeData.m_calls); - AZ_Printf(systemId, outputTotal.c_str()); - - if (m_self->m_timeData.m_childrenTime || m_self->m_timeData.m_childrenCalls) - { - AZStd::string childIndent = levelIndent; - for (auto i = name.begin(); i != name.end(); ++i) - { - childIndent += " "; - } - childIndent[level * 4] = '|'; - - AZStd::string outputChild = FormatString(childIndent, "", "Child:", m_self->m_timeData.m_childrenTime, m_self->m_timeData.m_childrenCalls); - AZ_Printf(systemId, outputChild.c_str()); - - AZStd::string outputSelf = FormatString(childIndent, "", "Self :", m_self->m_timeData.m_time - m_self->m_timeData.m_childrenTime, m_self->m_timeData.m_calls); - AZ_Printf(systemId, outputSelf.c_str()); - } - } - - for (auto i = m_children.begin(); i != m_children.end(); ++i) - { - i->Print(level + 1, systemId); - } - } - - TotalSortContainer* Find(const AZ::Debug::ProfilerRegister* obj) - { - if (m_self == obj) - { - return this; - } - - for (TotalSortContainer& child : m_children) - { - TotalSortContainer* found = child.Find(obj); - if (found) - { - return found; - } - } - - return nullptr; - } - - struct TotalSorter - { - bool operator()(const TotalSortContainer& a, const TotalSortContainer& b) const - { - if (a.m_self->m_timeData.m_time == b.m_self->m_timeData.m_time) - { - return a.m_self > b.m_self; - } - return a.m_self->m_timeData.m_time > b.m_self->m_timeData.m_time; - } - }; - set m_children; - const AZ::Debug::ProfilerRegister* m_self; -}; - -void TestProfiler::StartProfiling() -{ - StopProfiling(); - - AZ::Debug::Profiler::Create(); -} - -void TestProfiler::StopProfiling() -{ - if (AZ::Debug::Profiler::IsReady()) - { - AZ::Debug::Profiler::Destroy(); - } -} - -void TestProfiler::PrintProfilingTotal(const char* systemId) -{ - if (!AZ::Debug::Profiler::IsReady()) - { - return; - } - - ProfilerSet profilers; - AZ::Debug::Profiler::Instance().ReadRegisterValues(AZStd::bind(&CollectPerformanceCounters, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::ref(profilers), systemId)); - - // Validate we wont get stuck in an infinite loop - TotalSortContainer root; - for (auto i = profilers.begin(); i != profilers.end(); ) - { - const AZ::Debug::ProfilerRegister* profile = *i; - if (profile->m_timeData.m_lastParent) - { - auto parent = profilers.find(profile->m_timeData.m_lastParent); - if (parent == profilers.end()) - { - // Error, just ignore this entry - i = profilers.erase(i); - continue; - } - } - ++i; - } - - // Put all root nodes into the final list - for (auto i = profilers.begin(); i != profilers.end(); ) - { - const AZ::Debug::ProfilerRegister* profile = *i; - if (!profile->m_timeData.m_lastParent) - { - root.m_children.insert(profile); - i = profilers.erase(i); - } - else - { - ++i; - } - } - - // Put all non-root nodes into the final list - while (!profilers.empty()) - { - for (auto i = profilers.begin(); i != profilers.end(); ) - { - const AZ::Debug::ProfilerRegister* profile = *i; - TotalSortContainer* found = root.Find(profile->m_timeData.m_lastParent); - if (found) - { - found->m_children.insert(profile); - i = profilers.erase(i); - } - else - { - ++i; - } - } - } - - AZ_Printf(systemId, "Profiling timers by total execution time:\n"); - root.Print(-1, systemId); -} - -void TestProfiler::PrintProfilingSelf(const char* systemId) -{ - if (!AZ::Debug::Profiler::IsReady()) - { - return; - } - - ProfilerSet profilers; - AZ::Debug::Profiler::Instance().ReadRegisterValues(AZStd::bind(&CollectPerformanceCounters, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::ref(profilers), systemId)); - - struct SelfSorter - { - bool operator()(const AZ::Debug::ProfilerRegister* a, const AZ::Debug::ProfilerRegister* b) const - { - auto aTime = a->m_timeData.m_time - a->m_timeData.m_childrenTime; - auto bTime = b->m_timeData.m_time - b->m_timeData.m_childrenTime; - - if (aTime == bTime) - { - return a > b; - } - return aTime > bTime; - } - }; - - set selfSorted; - for (auto& profiler : profilers) - { - selfSorted.insert(profiler); - } - - AZ_Printf(systemId, "Profiling timers by exclusive execution time:\n"); - for (auto profiler : selfSorted) - { - AZStd::string str = FormatString("", profiler->m_name ? profiler->m_name : profiler->m_function, "Self Time:", - profiler->m_timeData.m_time - profiler->m_timeData.m_childrenTime, profiler->m_timeData.m_calls); - AZ_Printf(systemId, str.c_str()); - } -} diff --git a/Code/Framework/GridMate/Tests/TestProfiler.h b/Code/Framework/GridMate/Tests/TestProfiler.h deleted file mode 100644 index 816c001645..0000000000 --- a/Code/Framework/GridMate/Tests/TestProfiler.h +++ /dev/null @@ -1,24 +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 - * - */ -#ifndef GM_TEST_PROFILER_H -#define GM_TEST_PROFILER_H - -namespace GridMate -{ - class TestProfiler - { - public: - static void StartProfiling(); - static void StopProfiling(); - - static void PrintProfilingTotal(const char* systemId); - static void PrintProfilingSelf(const char* systemId); - }; -} - -#endif diff --git a/Code/Framework/GridMate/Tests/gridmate_test_files.cmake b/Code/Framework/GridMate/Tests/gridmate_test_files.cmake index 3ff67f8eda..cf1cd087ee 100644 --- a/Code/Framework/GridMate/Tests/gridmate_test_files.cmake +++ b/Code/Framework/GridMate/Tests/gridmate_test_files.cmake @@ -12,6 +12,7 @@ set(FILES Session.cpp Serialize.cpp Certificates.cpp + Replica.cpp ReplicaSmall.cpp ReplicaMedium.cpp ReplicaBehavior.cpp diff --git a/Code/Tools/AzTestRunner/src/main.cpp b/Code/Tools/AzTestRunner/src/main.cpp index 0874efeff2..346b4e3b53 100644 --- a/Code/Tools/AzTestRunner/src/main.cpp +++ b/Code/Tools/AzTestRunner/src/main.cpp @@ -18,45 +18,35 @@ namespace AzTestRunner const int LIB_NOT_FOUND = 102; const int SYMBOL_NOT_FOUND = 103; - // note that MODULE_SKIPPED is not an error condition, but not 0 to indicate its not the - // same as successfully running tests and finding them. - const int MODULE_SKIPPED = 104; - const char* INTEG_BOOTSTRAP = "AzTestIntegBootstrap"; - //! display proper usage of the application void usage([[maybe_unused]] AZ::Test::Platform& platform) { std::stringstream ss; ss << "AzTestRunner\n" - "Runs AZ unit and integration tests. Exit code is the result from GoogleTest.\n" + "Runs AZ tests. Exit code is the result from GoogleTest.\n" "\n" "Usage:\n" - " AzTestRunner.exe (AzRunUnitTests|AzRunIntegTests) [--integ] [--wait-for-debugger] [--pause-on-completion] [google-test-args]\n" + " AzTestRunner.exe (AzRunUnitTests|AzRunBenchmarks) [--wait-for-debugger] [--pause-on-completion] [google-test-args]\n" "\n" "Options:\n" " : the module to test\n" " : the name of the aztest hook function to run in the \n" " 'AzRunUnitTests' will hook into unit tests\n" - " 'AzRunIntegTests' will hook into integration tests\n" - " --integ: tells runner to bootstrap the engine, needed for integration tests\n" - " Note: you can run unit tests with a bootstrapped engine (AzRunUnitTests --integ),\n" - " but running integration tests without a bootstrapped engine (AzRunIntegTests w/ no --integ) might not work.\n" + " 'AzRunBenchmarks' will hook into benchmark tests\n" " --wait-for-debugger: tells runner to wait for debugger to attach to process (on supported platforms)\n" " --pause-on-completion: tells the runner to pause after running the tests\n" " --quiet: disables stdout for minimal output while running tests\n" "\n" "Example:\n" - " AzTestRunner.exe CrySystem.dll AzRunUnitTests --pause-on-completion\n" - " AzTestRunner.exe CrySystem.dll AzRunIntegTests --integ\n" + " AzTestRunner.exe AzCore.Tests.dll AzRunUnitTests --pause-on-completion\n" "\n" "Exit Codes:\n" " 0 - all tests pass\n" " 1 - test failure\n" << " " << INCORRECT_USAGE << " - incorrect usage (see above)\n" << " " << LIB_NOT_FOUND << " - library/dll could not be loaded\n" - << " " << SYMBOL_NOT_FOUND << " - export symbol not found\n" - << " " << MODULE_SKIPPED << " - non-integ module was skipped (not an error)\n"; + << " " << SYMBOL_NOT_FOUND << " - export symbol not found\n"; std::cerr << ss.str() << std::endl; } @@ -82,7 +72,6 @@ namespace AzTestRunner // capture optional arguments bool waitForDebugger = false; - bool isInteg = false; bool pauseOnCompletion = false; bool quiet = false; for (int i = 0; i < argc; i++) @@ -93,12 +82,6 @@ namespace AzTestRunner AZ::Test::RemoveParameters(argc, argv, i, i); i--; } - else if (strcmp(argv[i], "--integ") == 0) - { - isInteg = true; - AZ::Test::RemoveParameters(argc, argv, i, i); - i--; - } else if (strcmp(argv[i], "--pause-on-completion") == 0) { pauseOnCompletion = true; @@ -172,47 +155,11 @@ namespace AzTestRunner if (result != 0) { module.reset(); - - if ((isInteg) && (result == SYMBOL_NOT_FOUND)) - { - // special case: It is not required to put an INTEG test inside every DLL - so if - // we failed to find the INTEG entry point in this DLL, its not an error. - // its only an error if we find it and there are no tests, or we find it and tests actually - // fail. - std::cerr << "INTEG module has no entry point and will be skipped: " << lib << std::endl; - return MODULE_SKIPPED; - } - return result; } platform.SuppressPopupWindows(); - // Grab a bootstrapper library if requested - std::shared_ptr bootstrap; - if (isInteg) - { - bootstrap = platform.GetModule(INTEG_BOOTSTRAP); - if (!bootstrap->IsValid()) - { - std::cerr << "FAILED to load bootstrapper" << std::endl; - return LIB_NOT_FOUND; - } - - // Initialize the bootstrapper - auto init = bootstrap->GetFunction("Initialize"); - if (init->IsValid()) - { - int initResult = (*init)(); - if (initResult != 0) - { - std::cerr << "Bootstrapper Initialize failed with code " << initResult << ", exiting" << std::endl; - return initResult; - } - } - } - - // run the test main function. if (testMainFunction->IsValid()) { @@ -231,22 +178,6 @@ namespace AzTestRunner // system allocator / etc. module.reset(); - // Shutdown the bootstrapper - if (bootstrap) - { - auto shutdown = bootstrap->GetFunction("Shutdown"); - if (shutdown->IsValid()) - { - int shutdownResult = (*shutdown)(); - if (shutdownResult != 0) - { - std::cerr << "Bootstrapper shutdown failed with code " << shutdownResult << ", exiting" << std::endl; - return shutdownResult; - } - } - bootstrap.reset(); - } - if (pauseOnCompletion) { AzTestRunner::pause_on_completion(); diff --git a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h index d354153f9b..0006b79628 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h +++ b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h @@ -27,7 +27,7 @@ namespace EMotionFX {} }; - class INTEG_PoseComparisonFixture + class PoseComparisonFixture : public SystemComponentFixture , public ::testing::WithParamInterface { @@ -47,8 +47,8 @@ namespace EMotionFX // This fixture exists to separate the tests that test the pose comparsion // functionality from the tests that use the pose comparison functionality // (even though it doesn't use the recording) - class INTEG_TestPoseComparisonFixture - : public INTEG_PoseComparisonFixture + class TestPoseComparisonFixture + : public PoseComparisonFixture { }; }; // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp index 27692a90ff..c704a5b114 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp @@ -154,14 +154,14 @@ namespace EMotionFX return MakeMatcher(new KeyTrackMatcher(expected, nodeName)); } - void INTEG_PoseComparisonFixture::SetUp() + void PoseComparisonFixture::SetUp() { SystemComponentFixture::SetUp(); LoadAssets(); } - void INTEG_PoseComparisonFixture::TearDown() + void PoseComparisonFixture::TearDown() { m_actorInstance->Destroy(); @@ -176,7 +176,7 @@ namespace EMotionFX SystemComponentFixture::TearDown(); } - void INTEG_PoseComparisonFixture::LoadAssets() + void PoseComparisonFixture::LoadAssets() { const AZStd::string actorPath = ResolvePath(GetParam().m_actorFile); m_actor = EMotionFX::GetImporter().LoadActor(actorPath); @@ -195,7 +195,7 @@ namespace EMotionFX m_actorInstance->SetAnimGraphInstance(AnimGraphInstance::Create(m_animGraph, m_actorInstance, m_motionSet)); } - TEST_P(INTEG_PoseComparisonFixture, Integ_TestPoses) + TEST_P(PoseComparisonFixture, TestPoses) { const AZStd::string recordingPath = ResolvePath(GetParam().m_recordingFile); Recorder* recording = EMotionFX::Recorder::LoadFromFile(recordingPath.c_str()); @@ -231,7 +231,7 @@ namespace EMotionFX recording->Destroy(); } - TEST_P(INTEG_TestPoseComparisonFixture, Integ_TestRecording) + TEST_P(TestPoseComparisonFixture, TestRecording) { // Make one recording, 10 seconds at 60 fps Recorder::RecordSettings settings; @@ -294,30 +294,30 @@ namespace EMotionFX recording->Destroy(); } - INSTANTIATE_TEST_CASE_P(Integ_TestPoses, INTEG_PoseComparisonFixture, + INSTANTIATE_TEST_CASE_P(DISABLED_TestPoses, PoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ), PoseComparisonFixtureParams ( - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" ) ) ); - INSTANTIATE_TEST_CASE_P(Integ_TestPoseComparison, INTEG_TestPoseComparisonFixture, + INSTANTIATE_TEST_CASE_P(DISABLED_TestPoseComparison, TestPoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ) ) ); diff --git a/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp b/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp index c7540d091f..48826fcf10 100644 --- a/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp +++ b/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp @@ -7,52 +7,50 @@ */ #include +#include #include #include #include #include "HttpRequestManager.h" -class Integ_HttpTest - : public ::testing::Test +class HttpTest + : public UnitTest::ScopedAllocatorSetupFixture { -public: - HttpRequestor::ManagerPtr m_httpRequestManager; +}; + +TEST_F(HttpTest, DISABLED_HttpRequesterTest) +{ + HttpRequestor::Manager httpRequestManager; // to wait for test to complete - AZStd::mutex m_requestMutex; - AZStd::condition_variable m_requestConditionVar; + AZStd::mutex requestMutex; + AZStd::condition_variable requestConditionVar; - AZStd::string resultData; - AZStd::atomic resultCode; + AZStd::string resultData = {}; + AZStd::atomic resultCode = Aws::Http::HttpResponseCode::REQUEST_NOT_MADE; - Integ_HttpTest() { - m_httpRequestManager = AZStd::make_shared(); - resultCode = Aws::Http::HttpResponseCode::REQUEST_NOT_MADE; - resultData = "{}"; - - AZStd::unique_lock lock(m_requestMutex); - m_requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(10)); + AZStd::unique_lock lock(requestMutex); + requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(10)); } - virtual ~Integ_HttpTest() - { - m_httpRequestManager.reset(); - } -}; + httpRequestManager.AddTextRequest( + HttpRequestor::TextParameters("https://httpbin.org/ip", + Aws::Http::HttpMethod::HTTP_GET, + [&resultData, &resultCode, &requestConditionVar](const AZStd::string& data, Aws::Http::HttpResponseCode code) + { + resultData = data; + resultCode = code; + requestConditionVar.notify_all(); + } + ) + ); -TEST_F(Integ_HttpTest, HttpRequesterTest) -{ - m_httpRequestManager->AddTextRequest(HttpRequestor::TextParameters("https://httpbin.org/ip", Aws::Http::HttpMethod::HTTP_GET, [this](const AZStd::string & data, Aws::Http::HttpResponseCode code) { - resultData = data; - resultCode = code; - m_requestConditionVar.notify_all(); - })); - - AZStd::unique_lock lock(m_requestMutex); - m_requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(5000)); + AZStd::unique_lock lock(requestMutex); + requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(5000)); + } EXPECT_NE(Aws::Http::HttpResponseCode::REQUEST_NOT_MADE, resultCode); } diff --git a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp index 7275909908..2d3f67c112 100644 --- a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp @@ -26,12 +26,12 @@ namespace UnitTest { - class Integ_BundlingSystemComponentFixture : + class BundlingSystemComponentFixture : public ::testing::Test { public: - Integ_BundlingSystemComponentFixture() = default; + BundlingSystemComponentFixture() = default; bool TestAsset(const char* assetPath) { @@ -59,7 +59,7 @@ namespace UnitTest } }; - TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundles_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_HasBundle_LoadBundles_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -72,7 +72,7 @@ namespace UnitTest EXPECT_FALSE(TestAsset(testAssetPath)); } - TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundlesCatalogChecks_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_HasBundle_LoadBundlesCatalogChecks_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -92,7 +92,7 @@ namespace UnitTest EXPECT_FALSE(TestAsset(noCatalogAsset)); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleUnloadCheckCatalog_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SingleUnloadCheckCatalog_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -132,7 +132,7 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testDDSAsset)); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleLoadAndBundleMode_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SingleLoadAndBundleMode_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -157,7 +157,7 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testMTLAsset)); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_OpenClosePackCount_Match) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_OpenClosePackCount_Match) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -198,7 +198,7 @@ namespace UnitTest EXPECT_EQ(bundleCount, 0); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SplitPakTestWithAsset_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SplitPakTestWithAsset_Success) { // This asset lives only within LmbrCentral/Assets/Test/SplitBundleTest/splitbundle__1.pak which is a dependent bundle of splitbundle.pak const char testDDSAsset_split[] = "textures/milestone2/am_floor_tile_ddna_test.dds.7"; @@ -228,7 +228,7 @@ namespace UnitTest } // Verify that our bundles using catalogs of the same name work properly - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SharedCatalogName_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SharedCatalogName_Success) { // This bundle was built for PC but is generic and the test should work fine on other platforms // gamepropertioessmall_pc.pak has a smaller version of the gameproperties csv From d1d4bf812ef72b4e3b509d925b4e174be31678fe Mon Sep 17 00:00:00 2001 From: smurly Date: Fri, 15 Oct 2021 09:18:46 -0700 Subject: [PATCH 288/293] P0 PostFX Gradient Weight Modifier component parallel test automation (#4709) * PostFX Gradient Weight Modifiere component P0 parallel test Signed-off-by: Scott Murray * fixing some comment step numbering Signed-off-by: Scott Murray * fixing PostFX casing and method camel casing of the test function Signed-off-by: Scott Murray * changing the casing of the file name Signed-off-by: Scott Murray --- .../Atom/TestSuite_Main_Optimized.py | 4 + ...nents_PostFXGradientWeightModifierAdded.py | 179 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index 447a4ebac9..c29a391be4 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -71,5 +71,9 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module + @pytest.mark.test_case_id("C36525664") + class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py new file mode 100644 index 0000000000..d38e96739d --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py @@ -0,0 +1,179 @@ +""" +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: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + postfx_gradient_weight_creation = ( + "PostFX Gradient Weight Modifier Entity successfully created", + "PostFX Gradient Weight Modifier Entity failed to be created") + postfx_gradient_weight_component = ( + "Entity has a PostFX Gradient Weight Modifier component", + "Entity failed to find PostFX Gradient Weight Modifier component") + postfx_gradient_weight_disabled = ( + "PostFX Gradient Weight Modifier component disabled", + "PostFX Gradient Weight Modifier component was not disabled.") + postfx_layer_component = ( + "Entity has a PostFX Layer component", + "Entity did not have an PostFX Layer component") + postfx_gradient_weight_enabled = ( + "PostFX Gradient Weight Modifier component enabled", + "PostFX Gradient Weight Modifier component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): + """ + Summary: + Tests the PostFX Gradient Weight Modifier component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a PostFX Gradient Weight Modifier entity with no components. + 2) Add a PostFX Gradient Weight Modifier component to PostFX Gradient Weight Modifier entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Verify PostFX Gradient Weight Modifier component not enabled. + 6) Add PostFX Layer component since it is required by the PostFX Gradient Weight Modifier component. + 7) Verify PostFX Gradient Weight Modifier component is enabled. + 8) Enter/Exit game mode. + 9) Test IsHidden. + 10) Test IsVisible. + 11) Delete PostFX Gradient Weight Modifier entity. + 12) UNDO deletion. + 13) REDO deletion. + 14) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create a PostFX Gradient Weight Modifier entity with no components. + postfx_gradient_weight_name = "PostFX Gradient Weight Modifier" + postfx_gradient_weight_entity = EditorEntity.create_editor_entity(postfx_gradient_weight_name) + Report.critical_result(Tests.postfx_gradient_weight_creation, postfx_gradient_weight_entity.exists()) + + # 2. Add a PostFX Gradient Weight Modifier component to PostFX Gradient Weight Modifier entity. + postfx_gradient_weight_component = postfx_gradient_weight_entity.add_component(postfx_gradient_weight_name) + Report.critical_result( + Tests.postfx_gradient_weight_component, + postfx_gradient_weight_entity.has_component(postfx_gradient_weight_name)) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not postfx_gradient_weight_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, postfx_gradient_weight_entity.exists()) + + # 5. Verify PostFX Gradient Weight Modifier component not enabled. + Report.result(Tests.postfx_gradient_weight_disabled, not postfx_gradient_weight_component.is_enabled()) + + # 6. Add PostFX Layer component since it is required by the PostFX Gradient Weight Modifier component. + postfx_layer_name = "PostFX Layer" + postfx_gradient_weight_entity.add_component(postfx_layer_name) + Report.result(Tests.postfx_layer_component, postfx_gradient_weight_entity.has_component(postfx_layer_name)) + + # 7. Verify PostFX Gradient Weight Modifier component is enabled. + Report.result(Tests.postfx_gradient_weight_enabled, postfx_gradient_weight_component.is_enabled()) + + # 8. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 9. Test IsHidden. + postfx_gradient_weight_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, postfx_gradient_weight_entity.is_hidden() is True) + + # 10. Test IsVisible. + postfx_gradient_weight_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, postfx_gradient_weight_entity.is_visible() is True) + + # 11. Delete PostFX Gradient Weight Modifier entity. + postfx_gradient_weight_entity.delete() + Report.result(Tests.entity_deleted, not postfx_gradient_weight_entity.exists()) + + # 12. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, postfx_gradient_weight_entity.exists()) + + # 13. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not postfx_gradient_weight_entity.exists()) + + # 14. Look for errors or asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_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(AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity) From 721d92b4f96123adf0023cfca4bb8c9cb66aba9b Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 15 Oct 2021 11:02:12 -0700 Subject: [PATCH 289/293] adding exception handling for tests that are not going through AzTestRunner Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Tools/AssetBundler/tests/tests_main.cpp | 3 +++ .../AssetProcessor/native/tests/SourceFileRelocatorTests.cpp | 2 +- Code/Tools/AssetProcessor/native/tests/test_main.cpp | 3 +++ Code/Tools/ProjectManager/tests/main.cpp | 3 +++ Code/Tools/PythonBindingsExample/tests/TestMain.cpp | 3 +++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Code/Tools/AssetBundler/tests/tests_main.cpp b/Code/Tools/AssetBundler/tests/tests_main.cpp index 51dd0ce67c..21a6bf8a6f 100644 --- a/Code/Tools/AssetBundler/tests/tests_main.cpp +++ b/Code/Tools/AssetBundler/tests/tests_main.cpp @@ -291,6 +291,9 @@ namespace AssetBundler int main(int argc, char* argv[]) { + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + INVOKE_AZ_UNIT_TEST_MAIN(); AZ::AllocatorInstance::Create(); diff --git a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp index 4b70f94120..d7801abb3d 100644 --- a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp @@ -262,7 +262,7 @@ namespace UnitTests auto result = m_data->m_reporter->ComputeDestination(entryContainer, m_data->m_platformConfig.GetScanFolderByPath(scanFolderEntry.m_scanFolder.c_str()), source, destination, destInfo); - ASSERT_EQ(result.IsSuccess(), expectSuccess) << result.GetError().c_str(); + ASSERT_EQ(result.IsSuccess(), expectSuccess) << (!result.IsSuccess() ? result.GetError().c_str() : ""); if (expectSuccess) { diff --git a/Code/Tools/AssetProcessor/native/tests/test_main.cpp b/Code/Tools/AssetProcessor/native/tests/test_main.cpp index 57f14832aa..e0cdc8cb3c 100644 --- a/Code/Tools/AssetProcessor/native/tests/test_main.cpp +++ b/Code/Tools/AssetProcessor/native/tests/test_main.cpp @@ -29,6 +29,9 @@ int main(int argc, char* argv[]) { qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "1"); + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + // If "--unittest" is present on the command line, run unit testing // and return immediately. Otherwise, continue as normal. AZ::Test::addTestEnvironment(new BaseAssetProcessorTestEnvironment()); diff --git a/Code/Tools/ProjectManager/tests/main.cpp b/Code/Tools/ProjectManager/tests/main.cpp index 3dd2fb75df..c666b7ffd0 100644 --- a/Code/Tools/ProjectManager/tests/main.cpp +++ b/Code/Tools/ProjectManager/tests/main.cpp @@ -18,6 +18,9 @@ int runDefaultRunner(int argc, char* argv[]) int main(int argc, char* argv[]) { + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + if (argc == 1) { // if no parameters are provided, add the --unittests parameter diff --git a/Code/Tools/PythonBindingsExample/tests/TestMain.cpp b/Code/Tools/PythonBindingsExample/tests/TestMain.cpp index 7399055ca5..4c0dddecad 100644 --- a/Code/Tools/PythonBindingsExample/tests/TestMain.cpp +++ b/Code/Tools/PythonBindingsExample/tests/TestMain.cpp @@ -23,6 +23,9 @@ int runDefaultRunner(int argc, char* argv[]) int main(int argc, char* argv[]) { + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + // ran with no parameters? if (argc == 1) { From 49f339364697cba9a3c8b5a3853c34b1cdc1948f Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Fri, 15 Oct 2021 11:26:19 -0700 Subject: [PATCH 290/293] Removing unused softening boundary width controls (#4647) Signed-off-by: mrieggeramzn --- .../Shadow/DirectionalLightShadow.azsli | 76 ------- .../Atom/Features/Shadow/JitterTablePcf.azsli | 185 ------------------ .../Features/Shadow/ProjectedShadow.azsli | 35 ---- .../Atom/Features/Shadow/Shadow.azsli | 3 - .../CoreLights/ViewSrg.azsli | 3 - .../atom_feature_common_asset_files.cmake | 1 - ...irectionalLightFeatureProcessorInterface.h | 6 - .../DiskLightFeatureProcessorInterface.h | 2 - .../PointLightFeatureProcessorInterface.h | 3 - .../Atom/Feature/CoreLights/ShadowConstants.h | 1 - ...ProjectedShadowFeatureProcessorInterface.h | 2 - .../DirectionalLightFeatureProcessor.cpp | 70 +------ .../DirectionalLightFeatureProcessor.h | 7 +- .../CoreLights/DiskLightFeatureProcessor.cpp | 5 - .../CoreLights/DiskLightFeatureProcessor.h | 1 - .../Source/CoreLights/EsmShadowmapsPass.cpp | 22 --- .../Source/CoreLights/EsmShadowmapsPass.h | 10 - .../CoreLights/PointLightFeatureProcessor.cpp | 5 - .../CoreLights/PointLightFeatureProcessor.h | 1 - .../ProjectedShadowFeatureProcessor.cpp | 79 +------- .../Shadows/ProjectedShadowFeatureProcessor.h | 4 +- .../CommonFeatures/CoreLights/AreaLightBus.h | 7 - .../CoreLights/AreaLightComponentConfig.h | 1 - .../CoreLights/DirectionalLightBus.h | 9 - .../DirectionalLightComponentConfig.h | 4 - .../CoreLights/AreaLightComponentConfig.cpp | 1 - .../AreaLightComponentController.cpp | 18 -- .../CoreLights/AreaLightComponentController.h | 2 - .../DirectionalLightComponentConfig.cpp | 1 - .../DirectionalLightComponentController.cpp | 19 -- .../DirectionalLightComponentController.h | 2 - .../Source/CoreLights/DiskLightDelegate.cpp | 8 - .../Source/CoreLights/DiskLightDelegate.h | 1 - .../CoreLights/EditorAreaLightComponent.cpp | 9 - .../EditorDirectionalLightComponent.cpp | 9 - .../Source/CoreLights/LightDelegateBase.h | 1 - .../CoreLights/LightDelegateInterface.h | 2 - .../Source/CoreLights/SphereLightDelegate.cpp | 8 - .../Source/CoreLights/SphereLightDelegate.h | 1 - 39 files changed, 8 insertions(+), 616 deletions(-) delete mode 100644 Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli index dd235fcd3a..633ea85387 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli @@ -10,7 +10,6 @@ #include #include -#include "JitterTablePcf.azsli" #include "Shadow.azsli" #include "ShadowmapAtlasLib.azsli" #include "BicubicPcfFilters.azsli" @@ -82,12 +81,6 @@ class DirectionalLightShadow // result.y == true if the given coordinate is in shadow. bool2 IsShadowed(float3 shadowCoord, uint indexOfCascade); - // This checks if the point is shadowed or not for the given center coordinate and jitter. - bool IsShadowedWithJitter( - float3 jitterUnit, - float jitterDepthDiffBase, - uint jitterIndex); - // This outputs visibility ratio (from 0.0 to 1.0) of the given coordinate // from the light origin without filtering. float GetVisibilityFromLightNoFilter(); @@ -189,75 +182,6 @@ bool2 DirectionalLightShadow::IsShadowed(float3 shadowCoord, uint indexOfCascade return bool2(false, false); } -bool DirectionalLightShadow::IsShadowedWithJitter( - float3 jitterUnit, - float jitterDepthDiffBase, - uint jitterIndex) -{ - const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount; - const float4x4 worldToLightViewMatrices[ViewSrg::MaxCascadeCount] = - ViewSrg::m_directionalLightShadows[m_lightIndex].m_worldToLightViewMatrices; - const float4x4 lightViewToShadowmapMatrices[ViewSrg::MaxCascadeCount] = - ViewSrg::m_directionalLightShadows[m_lightIndex].m_lightViewToShadowmapMatrices; - const float boundaryScale = - ViewSrg::m_directionalLightShadows[m_lightIndex].m_boundaryScale; - - const float2 jitterXY = g_jitterTablePcf[jitterIndex]; - - // jitterLightView is the jittering diff vector from the lighted point on the surface - // in the light view space. It is remarked as "v_J" in the comment - // named "Calculate depth adjusting diff for jittered samples" - // just before the function GetJitterUnitVectorDepthDiffBase. - const float4 jitterLightView = float4(jitterXY, 0., 0.) * boundaryScale; - - // It checks the jittered point is lit or shadowed from the detailed cascade - // to the less detailed one. - for (uint indexOfCascade = 0; indexOfCascade < cascadeCount; ++indexOfCascade) - { - // jitterShadowmap is the jittering diff vector in the shadowmap space. - const float4 jitterShadowmap = mul(lightViewToShadowmapMatrices[indexOfCascade], jitterLightView); - - // Calculation of the jittering for Z-coordinate (light direction) is required - // to check lit/shadowed for the jittered point. - // jitterDepthDiff is the Z-coordinate of the jittering diff vector - // in the shadowmap space. - float jitterDepthDiff = 0.; - - // jitterDepthDiffBase is "1/tan(theta)" in the comment. - if (jitterDepthDiffBase != 0.) - { - // jitterUnitLightView is the unit vector in the light view space - // noted as "v_M" in the comment. - const float3 jitterUnitLightView = - normalize(mul(worldToLightViewMatrices[indexOfCascade], float4(jitterUnit, 0.)).xyz); - const float lightViewToShadowmapZScale = -lightViewToShadowmapMatrices[indexOfCascade]._m22; - // jitterDepthDiff is the "d" in the note, and it is calculated by - // d = (v_J . v_M) / tan(theta) - // in the light view space. Furthermore it have to be converted - // to the light clip space, which can be done by lightViewToShadowmapZScale. - jitterDepthDiff = - dot(jitterLightView.xyz, jitterUnitLightView) * jitterDepthDiffBase * - lightViewToShadowmapZScale; - } - // jitteredCoord is the coordinate of the jittered point in the shadowmap space. - const float3 jitteredCoord = - m_shadowCoords[indexOfCascade] + float3(jitterShadowmap.xy, jitterDepthDiff); - // Check for the jittered point is lit or shadowed. - const bool2 checkedShadowed = IsShadowed( - jitteredCoord, - indexOfCascade); - // If check is done, return the lit/shadowed flag. - // Otherwise make it pend to the next cascade. - if (checkedShadowed.x) - { - m_debugInfo.m_cascadeIndex = indexOfCascade; - return checkedShadowed.y; - } - } - m_debugInfo.m_cascadeIndex = cascadeCount; - return false; -} - float DirectionalLightShadow::GetVisibilityFromLightNoFilter() { const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli deleted file mode 100644 index 9082286758..0000000000 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli +++ /dev/null @@ -1,185 +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 - * - */ - - /* - The following is the output of - $ python3 pcf_jitter_table.py 6 g_jitterTablePcf 0 - where pcf_jitter_table.py has the following contents. - -@code -#!/usr/bin/env python3 - -import random -import sys -import math - - -""" Returns if a point in the range -[radius_min, radius_sup)*[angle_min, angle_sup) -is contained in the tuple polar coordinates. -""" -def is_point_include(radius_min, radius_sup, angle_min, angle_sup, polars): - for polar in polars: - if (radius_min <= polar[0] and polar[0] < radius_sup and - angle_min <= polar[1] and polar[1] < angle_sup): - return True - return False - - -""" Insert a randomly generated polar coordianted point in each -range [r0, r1)*[a0, a1) if there has not been such a point -in tuple coords yet, where [0, 1)*[0, 2pi) is divided -into the rad_count*agl_count ranges. -""" -def add_jitter_coords(radius_count, angle_count, polars): - radius_base = 1.0 / math.sqrt(radius_count) - for radius_index in range(radius_count): - # range of radius - radius_min = math.sqrt(radius_index) * radius_base - radius_sup = math.sqrt(radius_index + 1) * radius_base - - # randomize angle order - random_state = random.getstate() - angle_indices = list(range(angle_count)) - random.shuffle(angle_indices) - random.setstate(random_state) - - for angle_index in angle_indices: - # range of angle - angle_min = 2 * math.pi * angle_index / angle_count - angle_sup = 2 * math.pi * (angle_index + 1) / angle_count - - # if no point in the radius/angle range, add a new point - if not is_point_include(radius_min, radius_sup, - angle_min, angle_sup, - polars): - radius = radius_min + (radius_sup - radius_min) * random.random() - angle = angle_min + (angle_sup - angle_min) * random.random() - polars += [[radius, angle]] - - -""" Return a formatted string readable as an array of -orthogonal coordinated points which are in inside of the unit disk. -""" -def conv_array_string(polars): - result = "{\n" - for [radius, angle] in polars: - x = radius * math.cos(angle) - y = radius * math.sin(angle) - result += str.format(" float2({: 1.20e}, {: 1.20e}),\n", x, y) - result = result.rstrip(",\n") + "\n};\n" - return result - - -if __name__ == "__main__": - rad_size = 1 - ang_size = 1 - - if len(sys.argv) > 3: - random_seed = int(sys.argv[3]) - else: - random_seed = 0 - - if len(sys.argv) > 2: - array_name = sys.argv[2] - else: - array_name = False - - if len(sys.argv) > 1: - len_log = int(sys.argv[1]) - else: - print(" usage: {} array_len_log2 [array_file_name] [random_seed]".format(__file__)) - print(" array_len_log2 = 2 -> array length = 4") - print(" array_len_log2 = 6 -> array length = 64") - sys.exit() - - random.seed(random_seed) - coords = [] - add_jitter_coords(rad_size, ang_size, coords) - for index in range(len_log): - if index % 2 == 0: - rad_size *= 2 - else: - ang_size *= 2 - add_jitter_coords(rad_size, ang_size, coords) - - if array_name: - print(str.format("static const float2 {}[{}] =", array_name, len(coords))) - print(conv_array_string(coords)) - - @endcode - */ -#pragma once - -static const float2 g_jitterTablePcf[64] = -{ - float2( 4.21857815578105532772e-02, -8.43367430701083664601e-01), - float2(-1.66526814909220763350e-02, 2.96922406531470617352e-01), - float2(-1.06374665780382349212e-01, -3.45521852905696924552e-01), - float2( 5.42648241814168375008e-01, 7.63475573328278533936e-01), - float2(-1.55045122122251910479e-01, 5.78282315712970729216e-01), - float2( 1.01310018770242576264e-02, -6.88001749851880561870e-01), - float2(-5.41276603451248283783e-01, 5.21888233660957712168e-01), - float2(-6.69885071867917680777e-01, -6.72019666097878665134e-01), - float2( 1.22985029409499718039e-02, 4.54706838949524849713e-01), - float2( 4.00334354168925599105e-01, -6.20112671104014120949e-02), - float2( 2.32326155804074424571e-01, 5.14183027524470093184e-01), - float2(-3.26788693165450228051e-01, -6.03339478694129849323e-01), - float2( 7.72374386126136736053e-01, 1.23204314299169448432e-01), - float2(-4.45379212004159807936e-01, -6.35591042627205338178e-01), - float2( 9.86986293787213919693e-01, -5.18195017297516449806e-02), - float2(-9.09197225477999193544e-01, 1.95281945570711268356e-01), - float2( 8.78123785413316704229e-02, -2.77671865082058690055e-02), - float2( 1.93947312440399088906e-01, 4.27852204081567363825e-03), - float2(-2.06133675819526185347e-01, -1.49183652412411493771e-01), - float2(-4.11351098583102647854e-01, 2.36214692717993696158e-01), - float2( 3.50058750095615767162e-01, -3.57193658067260721989e-01), - float2(-5.54174780014121681759e-01, -2.23361040823672196698e-01), - float2(-6.29913348094886860196e-01, 1.29962593232600148729e-01), - float2( 3.96119563669521335125e-01, 4.90495219155295036906e-01), - float2( 7.26077464944819728210e-01, -3.70531027878536270426e-02), - float2(-5.50726266551596621568e-01, 6.48997654184258587762e-01), - float2(-6.98067624269093189859e-01, -3.83843898992943299842e-01), - float2( 8.72900706885875177221e-02, 8.24287559846993866941e-01), - float2( 6.65413234189638491678e-01, -5.66029707430476647367e-01), - float2(-5.97071574457786802270e-01, -6.93417220711863180327e-01), - float2( 6.09778569514949131403e-01, 6.92279483269558570946e-01), - float2(-8.10051800827623957879e-01, 5.82366304247235455627e-01), - float2(-8.77200948157437071506e-02, -1.88326609190753474499e-01), - float2( 9.79306884403889771340e-02, 1.86693151785678163046e-01), - float2( 4.60071424048798319206e-02, -1.98255149016034859510e-01), - float2(-5.37585860722621794450e-02, 3.99205315590760584366e-02), - float2( 2.18621803321778829243e-01, -3.85632280444686503795e-01), - float2(-2.98409571230789372187e-02, 4.22286693608096730390e-01), - float2( 3.58654757584850270025e-01, 2.95175871390239985548e-01), - float2(-3.85631921979480485341e-01, -3.00322047091407640096e-01), - float2( 4.49800763439369810648e-01, 3.98492182500493397068e-01), - float2(-4.97878650048238891035e-01, 2.57984038389083569776e-01), - float2(-3.12055242602567339816e-01, -4.88013525550807125697e-01), - float2( 5.87078632117718268724e-01, -6.97256834327608099322e-02), - float2( 6.23692403999373534695e-01, 3.11519734097943645779e-01), - float2( 6.64426445690903810792e-01, -2.27661844509491811950e-01), - float2(-3.24662942872471160793e-01, 5.68939932480760024447e-01), - float2(-5.31263995010459511015e-01, -4.66108719959298256619e-01), - float2( 5.10323549430644951563e-01, 5.81027848262460677731e-01), - float2( 2.82695533021593392586e-01, -7.03582425015577883620e-01), - float2(-5.98419541732174709026e-01, -4.68015982003612274198e-01), - float2(-3.95281650646674975746e-01, 6.10614720709622194050e-01), - float2( 7.87454411900813555647e-01, 1.37726315874787758053e-01), - float2(-7.36310249594224086600e-01, 4.25723821775386646049e-01), - float2( 6.48232481978769037312e-01, -5.53108138515975955585e-01), - float2(-1.88558544306507869237e-01, -7.79120748356531223067e-01), - float2(-3.78614630625567993860e-01, 7.82366459873827913007e-01), - float2(-8.48582606942172357201e-01, -3.78504015913022351381e-01), - float2( 1.91472859899175090748e-02, -9.13050020447597532325e-01), - float2( 8.08826910050883585157e-01, 4.17202663034078935489e-01), - float2(-9.27062588380768493046e-01, -2.94160352051227980130e-01), - float2( 6.67882607007592055126e-01, -6.88642020601400450808e-01), - float2(-1.59349274307943010454e-02, 9.37629353656756814317e-01), - float2( 9.86975590293644233775e-01, 1.44401793964158337014e-01) -}; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli index b91d0ce915..daed3a2921 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli @@ -13,7 +13,6 @@ #include #include #include "BicubicPcfFilters.azsli" -#include "JitterTablePcf.azsli" #include "Shadow.azsli" // ProjectedShadow calculates shadowed area projected from a light. @@ -44,11 +43,6 @@ class ProjectedShadow float GetThickness(); bool IsShadowed(float3 shadowPosition); - bool IsShadowedWithJitter( - float3 jitterUnitX, - float3 jitterUnitY, - float jitterDepthDiffBase, - uint jitterIndex); void SetShadowPosition(); float3 GetAtlasPosition(float2 texturePosition); static float UnprojectDepth(uint shadowIndex, float depthBufferValue); @@ -321,35 +315,6 @@ bool ProjectedShadow::IsShadowed(float3 shadowPosition) return false; } -bool ProjectedShadow::IsShadowedWithJitter( - float3 jitterUnitX, - float3 jitterUnitY, - float jitterDepthDiffBase, - uint jitterIndex) -{ - ViewSrg::ProjectedShadow shadow = ViewSrg::m_projectedShadows[m_shadowIndex]; - const float4x4 depthBiasMatrix = shadow.m_depthBiasMatrix; - const float boundaryScale = shadow.m_boundaryScale; - - const float2 jitterXY = g_jitterTablePcf[jitterIndex]; - - const float dist = distance(m_worldPosition, m_viewPosition); - const float boundaryRadius = dist * tan(boundaryScale); - // jitterWorldXY is the jittering diff vector from the lighted point on the surface - // in the world space. It is remarked as "v_J" in the comment - // named "Calculate depth adjusting diff for jittered samples" - // just before the function GetJitterUnitVectorDepthDiffBase. - const float3 jitterWorldXY = jitterUnitX * (jitterXY.x * boundaryRadius) + jitterUnitY * (jitterXY.y * boundaryRadius); - // The adjusting diff of depth ("d" in the comment) is calculated by - // jitterXY.y * boundaryRadius * jitterDepthDiffBase. - const float3 jitterWorldZ = m_lightDirection * (jitterXY.y * boundaryRadius * jitterDepthDiffBase); - - const float3 jitteredWorldPosition = m_worldPosition + jitterWorldXY + jitterWorldZ; - const float4 jitteredShadowmapHomogeneous = mul(depthBiasMatrix, float4(jitteredWorldPosition, 1)); - - return IsShadowed(jitteredShadowmapHomogeneous.xyz / jitteredShadowmapHomogeneous.w); -} - void ProjectedShadow::SetShadowPosition() { const float4x4 depthBiasMatrix = ViewSrg::m_projectedShadows[m_shadowIndex].m_depthBiasMatrix; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli index e05ff076cb..1fe81016cf 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli @@ -23,14 +23,11 @@ struct FilterParameter uint m_isEnabled; uint2 m_shadowmapOriginInSlice; uint m_shadowmapSize; - uint m_parameterOffset; - uint m_parameterCount; float m_lightDistanceOfCameraViewFrustum; float m_n_f_n; // n / (f - n) float m_n_f; // n - f float m_f; // f // where n: nearDepth, f: farDepth. - float2 m_padding; // explicit padding }; class Shadow diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 2065e28703..94d6f20da3 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -22,14 +22,11 @@ partial ShaderResourceGroup ViewSrg uint m_isEnabled; uint2 m_shadowmapOriginInSlice; uint m_shadowmapSize; - uint m_parameterOffset; - uint m_parameterCount; float m_lightDistanceOfCameraViewFrustum; float m_n_f_n; // n / (f - n) float m_n_f; // n - f float m_f; // f // where n: nearDepth, f: farDepth. - float2 m_padding; // explicit padding }; // Simple Point Lights diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake index 60614993b5..cf456b2e41 100644 --- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake +++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake @@ -286,7 +286,6 @@ set(FILES ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli - ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli ShaderLib/Atom/Features/Shadow/Shadow.azsli ShaderLib/Atom/Features/Shadow/ShadowmapAtlasLib.azsli diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h index 75d266cc52..769c7b95a6 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h @@ -154,12 +154,6 @@ namespace AZ //! @param count Sample Count for filtering (up to 64) virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; - //! This specifies the width of boundary between shadowed area and lit area. - //! @param handle the light handle. - //! @param width Boundary width. The shadow is gradually changed the degree of shadowed. - //! If width == 0, softening edge is disabled. Units are in meters. - virtual void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) = 0; - //! Sets whether the directional shadowmap should use receiver plane bias. //! This attempts to reduce shadow acne when using large pcf filters. virtual void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) = 0; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h index 3ab83200ae..5aa2dfb800 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h @@ -90,8 +90,6 @@ namespace AZ virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; //! Specifies filter method of shadows. virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; - //! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on the boundary. 0 disables softening. - virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0; //! Sets sample count for filtering of shadow boundary (up to 64) virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 6752ac4c52..1a5a776cdf 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -70,9 +70,6 @@ namespace AZ virtual void SetShadowBias(LightHandle handle, float bias) = 0; //! Specifies filter method of shadows. virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; - //! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on - //! the boundary. 0 disables softening. - virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0; //! Sets sample count for filtering of shadow boundary (up to 64) virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h index dbad3af21f..309331dcf5 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h @@ -42,7 +42,6 @@ namespace AZ // [GFX TODO][ATOM-2408] Make the max number of cascade modifiable at runtime. static constexpr uint16_t MaxNumberOfCascades = 4; static constexpr uint16_t MaxPcfSamplingCount = 64; - static constexpr float MaxSofteningBoundaryWidth = 0.1f; } // namespace Shadow } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h index 3d6c0c3015..46560f435d 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h @@ -54,8 +54,6 @@ namespace AZ::Render virtual void SetShadowBias(ShadowId id, float bias) = 0; //! Sets the shadow filter method virtual void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) = 0; - //! Sets the width of boundary between shadowed area and lit area. - virtual void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) = 0; //! Sets the sample count for filtering of the shadow boundary, max 64. virtual void SetFilteringSampleCount(ShadowId id, uint16_t count) = 0; //! Sets all of the shadow properites in one call diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 42cca0e57c..0a9f3480ad 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -584,15 +584,6 @@ namespace AZ m_shadowBufferNeedsUpdate = true; } - void DirectionalLightFeatureProcessor::SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) - { - for (auto& it : m_shadowData) - { - it.second.GetData(handle.GetIndex()).m_boundaryScale = boundaryWidth / 2.f; - } - m_shadowBufferNeedsUpdate = true; - } - void DirectionalLightFeatureProcessor::SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) { m_shadowProperties.GetData(handle.GetIndex()).m_isReceiverPlaneBiasEnabled = enable; @@ -1116,50 +1107,13 @@ namespace AZ for (const auto& passIt : m_esmShadowmapsPasses) { const RPI::View* cameraView = passIt.second.front()->GetRenderPipeline()->GetDefaultView().get(); - UpdateStandardDeviations(handle, cameraView); - UpdateFilterOffsetsCounts(handle, cameraView); + UpdateFilterEnabled(handle, cameraView); UpdateShadowmapPositionInAtlas(handle, cameraView); SetFilterParameterToPass(handle, cameraView); } } - void DirectionalLightFeatureProcessor::UpdateStandardDeviations(LightHandle handle, const RPI::View* cameraView) - { - if (handle != m_shadowingLightHandle) - { - return; - } - - const DirectionalLightShadowData& data = m_shadowData.at(cameraView).GetData(handle.GetIndex()); - const ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); - AZStd::fixed_vector standardDeviations; - for (size_t cascadeIndex = 0; cascadeIndex < property.m_segments.at(cameraView).size(); ++cascadeIndex) - { - const Aabb& aabb = property.m_segments.at(cameraView)[cascadeIndex].m_aabb; - const float aabbDiameter = AZStd::GetMax( - aabb.GetMax().GetX() - aabb.GetMin().GetX(), - aabb.GetMax().GetZ() - aabb.GetMin().GetZ()); - float standardDeviation = 0.f; - if (aabbDiameter > 0.f) - { - const float boundaryWidth = data.m_boundaryScale * 2.f; - const float ratioToAabbWidth = boundaryWidth / aabbDiameter; - const float widthInPixels = ratioToAabbWidth * data.m_shadowmapSize; - standardDeviation = widthInPixels / (2 * GaussianMathFilter::ReliableSectionFactor); - } - standardDeviations.push_back(standardDeviation); - } - - for (const RPI::RenderPipelineId& pipelineId : m_renderPipelineIdsForPersistentView.at(cameraView)) - { - for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses.at(pipelineId)) - { - esmPass->SetFilterParameters(standardDeviations); - } - } - } - - void DirectionalLightFeatureProcessor::UpdateFilterOffsetsCounts(LightHandle handle, const RPI::View* cameraView) + void DirectionalLightFeatureProcessor::UpdateFilterEnabled(LightHandle handle, const RPI::View* cameraView) { if (handle != m_shadowingLightHandle) { @@ -1170,29 +1124,11 @@ namespace AZ if (shadowData.m_shadowFilterMethod == aznumeric_cast(ShadowFilterMethod::Esm) || (shadowData.m_shadowFilterMethod == aznumeric_cast(ShadowFilterMethod::EsmPcf))) { - // Get array of filter counts for the camera view. - const RPI::RenderPipelineId& pipelineId = m_renderPipelineIdsForPersistentView.at(cameraView).front(); - AZ_Assert(!m_esmShadowmapsPasses.at(pipelineId).empty(), "Cannot find a EsmShadowmapsPass."); - const AZStd::array_view filterCounts = m_esmShadowmapsPasses.at(pipelineId).front()->GetFilterCounts(); - AZ_Assert(filterCounts.size() == GetCascadeCount(handle), "FilterCounts differs with cascade count."); - - // Create array of filter offsets - AZStd::vector filterOffsets; - filterOffsets.reserve(filterCounts.size()); - uint32_t filterOffset = 0; - for (const uint32_t count : filterCounts) - { - filterOffsets.push_back(filterOffset); - filterOffset += count; - } - // Write filter offsets and filter counts to ESM data for (uint16_t index = 0; index < GetCascadeCount(handle); ++index) { EsmShadowmapsPass::FilterParameter& filterParameter = m_esmParameterData.at(cameraView).GetData(index); filterParameter.m_isEnabled = true; - filterParameter.m_parameterOffset = filterOffsets[index]; - filterParameter.m_parameterCount = filterCounts[index]; } } else @@ -1202,8 +1138,6 @@ namespace AZ { EsmShadowmapsPass::FilterParameter& filterParameter = m_esmParameterData.at(cameraView).GetData(index); filterParameter.m_isEnabled = false; - filterParameter.m_parameterOffset = 0; - filterParameter.m_parameterCount = 0; } } } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h index 039f51d549..3c1ff8eabd 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h @@ -217,7 +217,6 @@ namespace AZ void SetDebugFlags(LightHandle handle, DebugDrawFlags flags) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; - void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) override; void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) override; const Data::Instance GetLightBuffer() const; @@ -278,10 +277,8 @@ namespace AZ //! This updates the parameter of Gaussian filter used in ESM. void UpdateFilterParameters(LightHandle handle); - //! This updates standard deviations for each cascade. - void UpdateStandardDeviations(LightHandle handle, const RPI::View* cameraView); - //! This updates filter offset and size for each cascade. - void UpdateFilterOffsetsCounts(LightHandle handle, const RPI::View* cameraView); + //! This updates if the filter is enabled. + void UpdateFilterEnabled(LightHandle handle, const RPI::View* cameraView); //! This updates shadowmap position(origin and size) in the atlas for each cascade. void UpdateShadowmapPositionInAtlas(LightHandle handle, const RPI::View* cameraView); //! This set filter parameters to passes which execute filtering. diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index 26e1757a5a..acf81ede32 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -322,11 +322,6 @@ namespace AZ { SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowFilterMethod, method); } - - void DiskLightFeatureProcessor::SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) - { - SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians); - } void DiskLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count) { diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index d65f587718..275712f84f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -53,7 +53,6 @@ namespace AZ void SetShadowBias(LightHandle handle, float bias) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetEsmExponent(LightHandle handle, float esmExponent) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp index 99eaa8a919..b92d538fb5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp @@ -42,28 +42,6 @@ namespace AZ return m_lightTypeName; } - void EsmShadowmapsPass::SetFilterParameters(const AZStd::array_view& standardDeviations) - { - // Set descriptor for Gaussian filters for given set of standard deviations. - MathFilterDescriptor descriptor; - descriptor.m_kind = MathFilterKind::Gaussian; - descriptor.m_gaussians.reserve(standardDeviations.size()); - for (const float standardDeviation : standardDeviations) - { - descriptor.m_gaussians.emplace_back(GaussianFilterDescriptor{ standardDeviation }); - } - - // Set filter paramter buffer along with element counts for each filter. - MathFilter::BufferWithElementCounts bufferCounts = MathFilter::FindOrCreateFilterBuffer(descriptor); - m_filterTableBuffer = bufferCounts.first; - m_filterCounts = AZStd::move(bufferCounts.second); - } - - AZStd::array_view EsmShadowmapsPass::GetFilterCounts() const - { - return m_filterCounts; - } - void EsmShadowmapsPass::SetShadowmapIndexTableBuffer(const Data::Instance& tableBuffer) { m_shadowmapIndexTableBuffer = tableBuffer; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h index 6e5e1aa311..5a9898d507 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h @@ -50,14 +50,11 @@ namespace AZ uint32_t m_isEnabled = false; AZStd::array m_shadowmapOriginInSlice = { {0, 0 } }; // shadowmap origin in the slice of the atlas. uint32_t m_shadowmapSize = static_cast(ShadowmapSize::None); // width and height of shadowmap. - uint32_t m_parameterOffset; // offset of the filter parameter. - uint32_t m_parameterCount; // element count of the filter parameter. float m_lightDistanceOfCameraViewFrustum = 0.f; float m_n_f_n = 0.f; // n / (f - n) float m_n_f = 0.f; // n - f float m_f = 0.f; // f // where n: nearDepth, f: farDepth. - AZStd::array m_padding = {{0.f, 0.f}}; // explicit padding }; virtual ~EsmShadowmapsPass() = default; @@ -65,13 +62,6 @@ namespace AZ const Name& GetLightTypeName() const; - //! This sets the standard deviations of the Gaussian filter - //! for each cascade. - void SetFilterParameters(const AZStd::array_view& standardDeviations); - - //! This returns element count of filters. - AZStd::array_view GetFilterCounts() const; - //! This sets the buffer of the table which enable to get shadowmap index //! from the coordinate in the atlas. //! Note that shadowmpa index is shader light index for a spot light diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index d3b5646e0b..dcf412c35d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -292,11 +292,6 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowFilterMethod, method); } - void PointLightFeatureProcessor::SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) - { - SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians); - } - void PointLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count) { SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index b784eb1bb5..54cb0303cc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -50,7 +50,6 @@ namespace AZ void SetShadowBias(LightHandle handle, float bias) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetEsmExponent(LightHandle handle, float esmExponent) override; void SetPointData(LightHandle handle, const PointLightData& data) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 6452b312c8..da92cc04e7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -186,17 +186,6 @@ namespace AZ::Render m_filterParameterNeedsUpdate = true; } - void ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) - { - AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowBoundaryWidthAngle()."); - - ShadowData& shadowData = m_shadowData.GetElement(id.GetIndex()); - shadowData.m_boundaryScale = boundaryWidthRadians / 2.0f; - - m_shadowmapPassNeedsUpdate = true; - m_filterParameterNeedsUpdate = true; - } - void ProjectedShadowFeatureProcessor::SetFilteringSampleCount(ShadowId id, uint16_t count) { AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetFilteringSampleCount()."); @@ -368,14 +357,13 @@ namespace AZ::Render { if (m_filterParameterNeedsUpdate) { - UpdateStandardDeviations(); - UpdateFilterOffsetsCounts(); + UpdateEsmPassEnabled(); SetFilterParameterToPass(); m_filterParameterNeedsUpdate = false; } } - void ProjectedShadowFeatureProcessor::UpdateStandardDeviations() + void ProjectedShadowFeatureProcessor::UpdateEsmPassEnabled() { if (m_esmShadowmapsPasses.empty()) { @@ -383,24 +371,7 @@ namespace AZ::Render return; } - AZStd::vector standardDeviations(m_shadowProperties.GetDataCount()); - - for (uint32_t i = 0; i < m_shadowProperties.GetDataCount(); ++i) - { - ShadowProperty& shadowProperty = m_shadowProperties.GetDataVector().at(i); - const ShadowData& shadow = m_shadowData.GetElement(shadowProperty.m_shadowId.GetIndex()); - if (!FilterMethodIsEsm(shadow)) - { - continue; - } - const FilterParameter& filter = m_shadowData.GetElement(shadowProperty.m_shadowId.GetIndex()); - const float boundaryWidthAngle = shadow.m_boundaryScale * 2.0f; - const float fieldOfView = GetMax(shadowProperty.m_desc.m_fieldOfViewYRadians, MinimumFieldOfView); - const float ratioToEntireWidth = boundaryWidthAngle / fieldOfView; - const float widthInPixels = ratioToEntireWidth * filter.m_shadowmapSize; - standardDeviations.at(i) = widthInPixels / (2.0f * GaussianMathFilter::ReliableSectionFactor); - } - if (standardDeviations.empty()) + if (m_shadowProperties.GetDataCount() == 0) { for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses) { @@ -411,50 +382,6 @@ namespace AZ::Render for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses) { esmPass->SetEnabledComputation(true); - esmPass->SetFilterParameters(standardDeviations); - } - } - - void ProjectedShadowFeatureProcessor::UpdateFilterOffsetsCounts() - { - if (m_esmShadowmapsPasses.empty()) - { - AZ_Error("ProjectedShadowFeatureProcessor", false, "Cannot find a required pass."); - return; - } - - // Get array of filter counts for the camera view. - const AZStd::array_view filterCounts = m_esmShadowmapsPasses.front()->GetFilterCounts(); - - // Create array of filter offsets. - AZStd::vector filterOffsets; - filterOffsets.reserve(filterCounts.size()); - uint32_t filterOffset = 0; - for (const uint32_t count : filterCounts) - { - filterOffsets.push_back(filterOffset); - filterOffset += count; - } - - auto& shadowProperties = m_shadowProperties.GetDataVector(); - for (uint32_t i = 0; i < shadowProperties.size(); ++i) - { - ShadowProperty& shadowProperty = shadowProperties.at(i); - const ShadowId shadowId = shadowProperty.m_shadowId; - ShadowData& shadowData = m_shadowData.GetElement(shadowId.GetIndex()); - FilterParameter& filterData = m_shadowData.GetElement(shadowId.GetIndex()); - - if (FilterMethodIsEsm(shadowData)) - { - filterData.m_parameterOffset = filterOffsets[i]; - filterData.m_parameterCount = filterCounts[i]; - } - else - { - // If filter is not required, reset offsets and counts of filter in ESM data. - filterData.m_parameterOffset = 0; - filterData.m_parameterCount = 0; - } } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index 0b266b9a40..6269166827 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -49,7 +49,6 @@ namespace AZ::Render void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override; void SetShadowBias(ShadowId id, float bias) override; void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) override; void SetFilteringSampleCount(ShadowId id, uint16_t count) override; void SetShadowProperties(ShadowId id, const ProjectedShadowDescriptor& descriptor) override; const ProjectedShadowDescriptor& GetShadowProperties(ShadowId id) override; @@ -101,8 +100,7 @@ namespace AZ::Render //! Functions to update the parameter of Gaussian filter used in ESM. void UpdateFilterParameters(); - void UpdateStandardDeviations(); - void UpdateFilterOffsetsCounts(); + void UpdateEsmPassEnabled(); void SetFilterParameterToPass(); bool FilterMethodIsEsm(const ShadowData& shadowData) const; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h index 557e6b3dd2..72c4ef97a8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h @@ -120,13 +120,6 @@ namespace AZ //! Sets the filter method of shadows. virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0; - //! Gets the width of softening boundary between shadowed area and lit area in degrees. - virtual float GetSofteningBoundaryWidthAngle() const = 0; - - //! Sets the width of softening boundary between shadowed area and lit area in degrees. - //! 0 disables softening. - virtual void SetSofteningBoundaryWidthAngle(float degrees) = 0; - //! Gets the sample count for filtering of the shadow boundary. virtual uint32_t GetFilteringSampleCount() const = 0; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h index a6d3c6fbed..c76c922385 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h @@ -59,7 +59,6 @@ namespace AZ float m_bias = 0.1f; ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256; ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None; - float m_boundaryWidthInDegrees = 0.25f; uint16_t m_filteringSampleCount = 12; float m_esmExponent = 87.0f; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h index 644856e768..a8088c63ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h @@ -153,15 +153,6 @@ namespace AZ //! @param method filter method. virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0; - //! This gets the width of boundary between shadowed area and lit area. - //! @return Boundary width. The shadow is gradually changed the degree of shadowed. - virtual float GetSofteningBoundaryWidth() const = 0; - - //! This specifies the width of boundary between shadowed area and lit area. - //! @param width Boundary width. The shadow is gradually changed the degree of shadowed. - //! If width == 0, softening edge is disabled. Units are in meters. - virtual void SetSofteningBoundaryWidth(float width) = 0; - //! This gets the sample count for filtering of the shadow boundary. //! @return Sample Count for filtering (up to 64) virtual uint32_t GetFilteringSampleCount() const = 0; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h index 0123d06275..a58acc0114 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h @@ -101,10 +101,6 @@ namespace AZ //! Method of shadow's filtering. ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None; - //! Width of the boundary between shadowed area and lit one. - //! If this is 0, edge softening is disabled. Units are in meters. - float m_boundaryWidth = 0.03f; // 3cm - //! Sample Count for filtering (from 4 to 64) //! It is used only when the pixel is predicted as on the boundary. uint16_t m_filteringSampleCount = 32; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index c7af44a28e..f0418a5024 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -36,7 +36,6 @@ namespace AZ ->Field("Shadow Bias", &AreaLightComponentConfig::m_bias) ->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize) ->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod) - ->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees) ->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount) ->Field("Esm Exponent", &AreaLightComponentConfig::m_esmExponent) ; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp index c0204ecac5..36cb2a7f5a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp @@ -74,8 +74,6 @@ namespace AZ::Render ->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize) ->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod) ->Event("SetShadowFilterMethod", &AreaLightRequestBus::Events::SetShadowFilterMethod) - ->Event("GetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::GetSofteningBoundaryWidthAngle) - ->Event("SetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::SetSofteningBoundaryWidthAngle) ->Event("GetFilteringSampleCount", &AreaLightRequestBus::Events::GetFilteringSampleCount) ->Event("SetFilteringSampleCount", &AreaLightRequestBus::Events::SetFilteringSampleCount) ->Event("GetEsmExponent", &AreaLightRequestBus::Events::GetEsmExponent) @@ -95,7 +93,6 @@ namespace AZ::Render ->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias") ->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize") ->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod") - ->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") ->VirtualProperty("EsmExponent", "GetEsmExponent", "SetEsmExponent"); ; @@ -307,7 +304,6 @@ namespace AZ::Render m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias); m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize); m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod); - m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(m_configuration.m_boundaryWidthInDegrees); m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount); m_lightShapeDelegate->SetEsmExponent(m_configuration.m_esmExponent); } @@ -506,20 +502,6 @@ namespace AZ::Render } } - float AreaLightComponentController::GetSofteningBoundaryWidthAngle() const - { - return m_configuration.m_boundaryWidthInDegrees; - } - - void AreaLightComponentController::SetSofteningBoundaryWidthAngle(float width) - { - m_configuration.m_boundaryWidthInDegrees = width; - if (m_lightShapeDelegate) - { - m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(width); - } - } - uint32_t AreaLightComponentController::GetFilteringSampleCount() const { return m_configuration.m_filteringSampleCount; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h index 3bec61551f..cc6223e7e5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h @@ -82,8 +82,6 @@ namespace AZ void SetShadowmapMaxSize(ShadowmapSize size) override; ShadowFilterMethod GetShadowFilterMethod() const override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - float GetSofteningBoundaryWidthAngle() const override; - void SetSofteningBoundaryWidthAngle(float width) override; uint32_t GetFilteringSampleCount() const override; void SetFilteringSampleCount(uint32_t count) override; float GetEsmExponent() const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp index 37d94f5ed1..9d384c2e24 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp @@ -37,7 +37,6 @@ namespace AZ ->Field("IsCascadeCorrectionEnabled", &DirectionalLightComponentConfig::m_isCascadeCorrectionEnabled) ->Field("IsDebugColoringEnabled", &DirectionalLightComponentConfig::m_isDebugColoringEnabled) ->Field("ShadowFilterMethod", &DirectionalLightComponentConfig::m_shadowFilterMethod) - ->Field("SofteningBoundaryWidth", &DirectionalLightComponentConfig::m_boundaryWidth) ->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount) ->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp index fbc1ccc35d..78558cfc85 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp @@ -80,8 +80,6 @@ namespace AZ ->Event("SetDebugColoringEnabled", &DirectionalLightRequestBus::Events::SetDebugColoringEnabled) ->Event("GetShadowFilterMethod", &DirectionalLightRequestBus::Events::GetShadowFilterMethod) ->Event("SetShadowFilterMethod", &DirectionalLightRequestBus::Events::SetShadowFilterMethod) - ->Event("GetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::GetSofteningBoundaryWidth) - ->Event("SetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::SetSofteningBoundaryWidth) ->Event("GetFilteringSampleCount", &DirectionalLightRequestBus::Events::GetFilteringSampleCount) ->Event("SetFilteringSampleCount", &DirectionalLightRequestBus::Events::SetFilteringSampleCount) ->Event("GetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::GetShadowReceiverPlaneBiasEnabled) @@ -99,7 +97,6 @@ namespace AZ ->VirtualProperty("ViewFrustumCorrectionEnabled", "GetViewFrustumCorrectionEnabled", "SetViewFrustumCorrectionEnabled") ->VirtualProperty("DebugColoringEnabled", "GetDebugColoringEnabled", "SetDebugColoringEnabled") ->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod") - ->VirtualProperty("SofteningBoundaryWidth", "GetSofteningBoundaryWidth", "SetSofteningBoundaryWidth") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") ->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled"); ; @@ -404,21 +401,6 @@ namespace AZ } } - float DirectionalLightComponentController::GetSofteningBoundaryWidth() const - { - return m_configuration.m_boundaryWidth; - } - - void DirectionalLightComponentController::SetSofteningBoundaryWidth(float width) - { - width = GetMin(Shadow::MaxSofteningBoundaryWidth, GetMax(0.f, width)); - m_configuration.m_boundaryWidth = width; - if (m_featureProcessor) - { - m_featureProcessor->SetShadowBoundaryWidth(m_lightHandle, width); - } - } - uint32_t DirectionalLightComponentController::GetFilteringSampleCount() const { return aznumeric_cast(m_configuration.m_filteringSampleCount); @@ -517,7 +499,6 @@ namespace AZ SetViewFrustumCorrectionEnabled(m_configuration.m_isCascadeCorrectionEnabled); SetDebugColoringEnabled(m_configuration.m_isDebugColoringEnabled); SetShadowFilterMethod(m_configuration.m_shadowFilterMethod); - SetSofteningBoundaryWidth(m_configuration.m_boundaryWidth); SetFilteringSampleCount(m_configuration.m_filteringSampleCount); SetShadowReceiverPlaneBiasEnabled(m_configuration.m_receiverPlaneBiasEnabled); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h index b8052bfc36..933f2705e7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h @@ -76,8 +76,6 @@ namespace AZ void SetDebugColoringEnabled(bool enabled) override; ShadowFilterMethod GetShadowFilterMethod() const override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - float GetSofteningBoundaryWidth() const override; - void SetSofteningBoundaryWidth(float width) override; uint32_t GetFilteringSampleCount() const override; void SetFilteringSampleCount(uint32_t count) override; bool GetShadowReceiverPlaneBiasEnabled() const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp index baf0cdced1..ebc79abca5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp @@ -147,14 +147,6 @@ namespace AZ::Render } } - void DiskLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) - { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); - } - } - void DiskLightDelegate::SetFilteringSampleCount(uint32_t count) { if (GetShadowsEnabled() && GetLightHandle().IsValid()) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h index e0fd16f6be..2be782c69c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h @@ -44,7 +44,6 @@ namespace AZ void SetShadowBias(float bias) override; void SetShadowmapMaxSize(ShadowmapSize size) override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(float widthInDegrees) override; void SetFilteringSampleCount(uint32_t count) override; void SetEsmExponent(float exponent) override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 954ec4cad8..1e5b2580f7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -154,15 +154,6 @@ namespace AZ ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) - ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_boundaryWidthInDegrees, "Softening boundary width", - "Width of the boundary between shadowed area and lit one. " - "Units are in degrees. " - "If this is 0, softening edge is disabled.") - ->Attribute(Edit::Attributes::Min, 0.f) - ->Attribute(Edit::Attributes::Max, 1.f) - ->Attribute(Edit::Attributes::Suffix, " deg") - ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) - ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled) ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering sample count", "This is only used when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp index 2854244f6b..69ba295e9b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp @@ -133,15 +133,6 @@ namespace AZ ->EnumAttribute(ShadowFilterMethod::Esm, "ESM") ->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_boundaryWidth, "Softening boundary width", - "Width of the boundary between shadowed area and lit one. " - "Units are in meters. " - "If this is 0, softening edge is disabled.") - ->Attribute(Edit::Attributes::Min, 0.f) - ->Attribute(Edit::Attributes::Max, 0.1f) - ->Attribute(Edit::Attributes::Suffix, " m") - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsEsmDisabled) ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count", "This is used only when the pixel is predicted as on the boundary. " "Specific to PCF and ESM+PCF.") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h index 2bd25b76a3..336c67f55d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h @@ -56,7 +56,6 @@ namespace AZ void SetShadowBias([[maybe_unused]] float bias) override {}; void SetShadowmapMaxSize([[maybe_unused]] ShadowmapSize size) override {}; void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {}; - void SetSofteningBoundaryWidthAngle([[maybe_unused]] float widthInDegrees) override {}; void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {}; void SetEsmExponent([[maybe_unused]] float esmExponent) override{}; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index 6d08971542..9bb8188898 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -75,8 +75,6 @@ namespace AZ virtual void SetShadowmapMaxSize(ShadowmapSize size) = 0; //! Sets the filter method for the shadow virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0; - //! Sets the width of boundary between shadowed area and lit area in degrees. - virtual void SetSofteningBoundaryWidthAngle(float widthInDegrees) = 0; //! Sets the sample count for filtering of the shadow boundary, max 64. virtual void SetFilteringSampleCount(uint32_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index 8853db5751..661b0c6b25 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -92,14 +92,6 @@ namespace AZ::Render } } - void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) - { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); - } - } - void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) { if (GetShadowsEnabled() && GetLightHandle().IsValid()) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index e2903b2d72..8bdee2442a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -34,7 +34,6 @@ namespace AZ void SetShadowBias(float bias) override; void SetShadowmapMaxSize(ShadowmapSize size) override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(float widthInDegrees) override; void SetFilteringSampleCount(uint32_t count) override; void SetEsmExponent(float esmExponent) override; From 693d849bd121201ab764f8d4d76e68e78746ff39 Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Fri, 15 Oct 2021 13:35:28 -0700 Subject: [PATCH 291/293] Vulkan fixes (#4710) * Disable partial Descriptor Set updates as Vk validation layer does not like that Signed-off-by: moudgils * Enable parallel encoding for Vulkan Disable partial SRG updates for Vk as the validation layer did not like that. There is a way to just updat SRG constants but that will require more work Fix a bunch of Vulkan validation errors (mostly the ones spammming each frame) Signed-off-by: moudgils * Minor feedback update Signed-off-by: moudgils --- .../RayTracing/RayTracingFeatureProcessor.cpp | 3 +- Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp | 4 +- .../Source/RHI/ShaderResourceGroupPool.cpp | 14 ++- .../Source/RHI/BufferMemoryPageAllocator.cpp | 2 +- .../Vulkan/Code/Source/RHI/CommandList.cpp | 2 +- .../RHI/Vulkan/Code/Source/RHI/Conversion.cpp | 17 +++- .../RHI/Vulkan/Code/Source/RHI/Conversion.h | 1 + .../RHI/Vulkan/Code/Source/RHI/Device.cpp | 19 +++- Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h | 6 +- .../RHI/FrameGraphExecuteGroupMerged.cpp | 2 + .../FrameGraphExecuteGroupMergedHandler.cpp | 7 +- .../Code/Source/RHI/FrameGraphExecuter.cpp | 7 +- .../Code/Source/RHI/FrameGraphExecuter.h | 2 + .../RHI/Vulkan/Code/Source/RHI/Memory.cpp | 10 ++ Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h | 1 + .../RHI/MergedShaderResourceGroupPool.h | 2 +- .../Source/RHI/ShaderResourceGroupPool.cpp | 96 ++++++++----------- 17 files changed, 117 insertions(+), 78 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index 6e78d3170c..af53fc3ce1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -507,7 +507,8 @@ namespace AZ } } - //Check if buffer view data changed from previous frame. + // Check if buffer view data changed from previous frame. + // Look into making 'm_meshBuffers != meshBuffers' faster by possibly building a crc and doing a crc check. if (m_meshBuffers.size() != meshBuffers.size() || m_meshBuffers != meshBuffers) { m_meshBuffers = meshBuffers; diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp index 9f3d21a2f1..e4e1a887b0 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp @@ -109,13 +109,11 @@ namespace AZ { if (attachment->GetFirstScopeAttachment() == nullptr) { + //We allow the rendering to continue even if an attachment is not used. AZ_Error( "FrameGraph", false, "Invalid State: attachment '%s' was added but never used!", attachment->GetId().GetCStr()); - - Clear(); - return ResultCode::InvalidOperation; } } } diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp index 70f08dec1e..eb80b038eb 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp @@ -111,13 +111,19 @@ namespace AZ { AZStd::lock_guard lock(m_groupsToCompileMutex); - AZ_Assert(!shaderResourceGroup.IsQueuedForCompile(), "Attempting to compile an SRG that's already been queued for compile. Only compile an SRG once per frame."); + bool isQueuedForCompile = shaderResourceGroup.IsQueuedForCompile(); + AZ_Warning( + "ShaderResourceGroupPool", !isQueuedForCompile, + "Attempting to compile an SRG that's already been queued for compile. Only compile an SRG once per frame."); - CalculateGroupDataDiff(shaderResourceGroup, groupData); + if (!isQueuedForCompile) + { + CalculateGroupDataDiff(shaderResourceGroup, groupData); - shaderResourceGroup.SetData(groupData); + shaderResourceGroup.SetData(groupData); - QueueForCompileNoLock(shaderResourceGroup); + QueueForCompileNoLock(shaderResourceGroup); + } } void ShaderResourceGroupPool::QueueForCompile(ShaderResourceGroup& group) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp index 07b18266f5..a1025e5501 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp @@ -55,7 +55,7 @@ namespace AZ RHI::Ptr bufferMemory; const VkMemoryPropertyFlags flags = ConvertHeapMemoryLevel(m_descriptor.m_heapMemoryLevel) | m_descriptor.m_additionalMemoryPropertyFlags; - RHI::Ptr memory = GetDevice().AllocateMemory(memoryRequirements.size, memoryRequirements.memoryTypeBits, flags); + RHI::Ptr memory = GetDevice().AllocateMemory(memoryRequirements.size, memoryRequirements.memoryTypeBits, flags, m_descriptor.m_bindFlags); if (memory) { diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp index d90f1c33d5..2620aa5f7b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp @@ -822,7 +822,7 @@ namespace AZ { RHI::ConstPtr shaderResourceGroup; const auto& srgBitset = pipelineLayout.GetAZSLBindingSlotsOfIndex(index); - AZStd::vector shaderResourceGroupList; + AZStd::fixed_vector shaderResourceGroupList; // Collect all the SRGs that are part of this descriptor set. They could be more than // 1, so we would need to merge their values before committing the descriptor set. for (uint32_t bindingSlot = 0; bindingSlot < srgBitset.size(); ++bindingSlot) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp index d5671cff05..3294b77eaa 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp @@ -696,8 +696,7 @@ namespace AZ usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; } if (RHI::CheckBitsAny(bindFlags, BindFlags::Constant)) @@ -742,12 +741,24 @@ namespace AZ if (RHI::CheckBitsAny(bindFlags, BindFlags::RayTracingShaderTable)) { - usageFlags |= VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + usageFlags |= VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; + } + + if (ShouldApplyDeviceAddressBit(bindFlags)) + { + usageFlags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; } return usageFlags; } + bool ShouldApplyDeviceAddressBit(RHI::BufferBindFlags bindFlags) + { + return RHI::CheckBitsAny( + bindFlags, + RHI::BufferBindFlags::InputAssembly | RHI::BufferBindFlags::DynamicInputAssembly | RHI::BufferBindFlags::RayTracingShaderTable); + } + VkPipelineStageFlags GetSupportedPipelineStages(RHI::PipelineStateType type) { // These stages don't need any special queue to be supported. diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h index 873b8ec2d1..b82b1a2f7c 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h @@ -82,5 +82,6 @@ namespace AZ VkImageUsageFlags ImageUsageFlagsOfFormatFeatureFlags(VkFormatFeatureFlags formatFeatureFlags); VkAccessFlags GetSupportedAccessFlags(VkPipelineStageFlags pipelineStageFlags); + bool ShouldApplyDeviceAddressBit(RHI::BufferBindFlags bindFlags); } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp index 132f9929c1..14b6c01498 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp @@ -185,6 +185,9 @@ namespace AZ VkPhysicalDeviceShaderFloat16Int8FeaturesKHR float16Int8 = {}; VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR separateDepthStencil = {}; + VkDeviceCreateInfo deviceInfo = {}; + deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + // If we are running Vulkan >= 1.2, then we must use VkPhysicalDeviceVulkan12Features instead // of VkPhysicalDeviceShaderFloat16Int8FeaturesKHR or VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR. if (majorVersion >= 1 && minorVersion >= 2) @@ -194,7 +197,14 @@ namespace AZ vulkan12Features.shaderFloat16 = physicalDevice.GetPhysicalDeviceVulkan12Features().shaderFloat16; vulkan12Features.shaderInt8 = physicalDevice.GetPhysicalDeviceVulkan12Features().shaderInt8; vulkan12Features.separateDepthStencilLayouts = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.descriptorBindingPartiallyBound = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.descriptorIndexing = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.descriptorBindingVariableDescriptorCount = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.bufferDeviceAddress = physicalDevice.GetPhysicalDeviceVulkan12Features().bufferDeviceAddress; + vulkan12Features.bufferDeviceAddressMultiDevice = physicalDevice.GetPhysicalDeviceVulkan12Features().bufferDeviceAddressMultiDevice; + vulkan12Features.runtimeDescriptorArray = physicalDevice.GetPhysicalDeviceVulkan12Features().runtimeDescriptorArray; robustness2.pNext = &vulkan12Features; + deviceInfo.pNext = &depthClipEnabled; } else { @@ -206,11 +216,11 @@ namespace AZ float16Int8.pNext = &separateDepthStencil; robustness2.pNext = &float16Int8; + + + deviceInfo.pNext = &descriptorIndexingFeatures; } - VkDeviceCreateInfo deviceInfo = {}; - deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceInfo.pNext = &descriptorIndexingFeatures; deviceInfo.flags = 0; deviceInfo.queueCreateInfoCount = static_cast(queueCreationInfo.size()); deviceInfo.pQueueCreateInfos = queueCreationInfo.data(); @@ -740,7 +750,7 @@ namespace AZ vkGetPhysicalDeviceQueueFamilyProperties(nativePhysicalDevice, &queueFamilyCount, m_queueFamilyProperties.data()); } - RHI::Ptr Device::AllocateMemory(uint64_t sizeInBytes, const uint32_t memoryTypeMask, const VkMemoryPropertyFlags flags) + RHI::Ptr Device::AllocateMemory(uint64_t sizeInBytes, const uint32_t memoryTypeMask, const VkMemoryPropertyFlags flags, const RHI::BufferBindFlags bufferBindFlags) { const auto& physicalDevice = static_cast(GetPhysicalDevice()); const VkPhysicalDeviceMemoryProperties& memProp = physicalDevice.GetMemoryProperties(); @@ -770,6 +780,7 @@ namespace AZ RHI::CheckBitsAll(memoryTypesToUseMask, memoryTypeBit)) { memoryDesc.m_memoryTypeIndex = memoryIndex; + memoryDesc.m_bufferBindFlags = bufferBindFlags; auto result = memory->Init(*this, memoryDesc); if (result == RHI::ResultCode::Success) { diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h index 9c21103929..44c1e20a06 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h @@ -100,7 +100,11 @@ namespace AZ RHI::Ptr AcquireCommandList(uint32_t familyQueueIndex, VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY); RHI::Ptr AcquireCommandList(RHI::HardwareQueueClass queueClass, VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY); - RHI::Ptr AllocateMemory(uint64_t sizeInBytes, const uint32_t memoryTypeMask, const VkMemoryPropertyFlags flags); + RHI::Ptr AllocateMemory( + uint64_t sizeInBytes, + const uint32_t memoryTypeMask, + const VkMemoryPropertyFlags flags, + const RHI::BufferBindFlags bufferBindFlags = RHI::BufferBindFlags::None); uint32_t GetCurrentFrameIndex() const; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp index 5314fc2aa1..84b6cafa7d 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp @@ -59,7 +59,9 @@ namespace AZ void FrameGraphExecuteGroupMerged::BeginInternal() { + m_commandList = AcquireCommandList(VK_COMMAND_BUFFER_LEVEL_PRIMARY); m_commandList->BeginCommandBuffer(); + m_workRequest.m_commandList = m_commandList; } void FrameGraphExecuteGroupMerged::EndInternal() diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp index 90e6d63044..1bcdd17ab6 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp @@ -41,9 +41,7 @@ namespace AZ RETURN_RESULT_IF_UNSUCCESSFUL(result); } - // Set the command list and renderpass contexts. - m_primaryCommandList = device.AcquireCommandList(m_hardwareQueueClass); - group->SetPrimaryCommandList(*m_primaryCommandList); + // Set the renderpass contexts. group->SetRenderPasscontexts(m_renderPassContexts); return RHI::ResultCode::Success; @@ -54,7 +52,8 @@ namespace AZ AZ_Assert(m_executeGroups.size() == 1, "Too many execute groups when initializing context"); FrameGraphExecuteGroupBase* group = static_cast(m_executeGroups.back()); AddWorkRequest(group->GetWorkRequest()); - m_workRequest.m_commandList = m_primaryCommandList; + //Merged handler will only have one commandlist. + m_workRequest.m_commandList = group->GetCommandLists()[0]; } } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp index e91b158629..7165b5c305 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp @@ -31,7 +31,12 @@ namespace AZ { return static_cast(Base::GetDevice()); } - + + FrameGraphExecuter::FrameGraphExecuter() + { + SetJobPolicy(RHI::JobPolicy::Parallel); + } + RHI::ResultCode FrameGraphExecuter::InitInternal(const RHI::FrameGraphExecuterDescriptor& descriptor) { const RHI::ConstPtr rhiPlatformLimitsDescriptor = descriptor.m_platformLimitsDescriptor; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h index 20f9f19a6a..8fc54ca0a6 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h @@ -35,6 +35,8 @@ namespace AZ Device& GetDevice() const; private: + FrameGraphExecuter(); + ////////////////////////////////////////////////////////////////////////// // RHI::FrameGraphExecuter RHI::ResultCode InitInternal(const RHI::FrameGraphExecuterDescriptor& descriptor) override; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp index a316a5eacb..bc10ba6dd9 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp @@ -7,6 +7,7 @@ */ #include #include +#include #include #include #include @@ -31,6 +32,15 @@ namespace AZ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = descriptor.m_sizeInBytes; allocInfo.memoryTypeIndex = descriptor.m_memoryTypeIndex; + + VkMemoryAllocateFlagsInfo memAllocInfo{}; + if (ShouldApplyDeviceAddressBit(descriptor.m_bufferBindFlags)) + { + memAllocInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; + } + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + + allocInfo.pNext = &memAllocInfo; VkDeviceMemory deviceMemory; VkResult vkResult = vkAllocateMemory(device.GetNativeDevice(), &allocInfo, nullptr, &deviceMemory); AZ_Error( diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h index 56726a82f6..bfed64d3a0 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h @@ -37,6 +37,7 @@ namespace AZ { VkDeviceSize m_sizeInBytes = 0; uint32_t m_memoryTypeIndex = 0; + RHI::BufferBindFlags m_bufferBindFlags = RHI::BufferBindFlags::None; }; ~Memory() = default; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h index b011ddcab4..7c21f21ce7 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h @@ -38,7 +38,7 @@ namespace AZ static RHI::Ptr Create(); - using ShaderResourceGroupList = AZStd::vector; + using ShaderResourceGroupList = AZStd::fixed_vector; //! Finds or create a new instance of a MergedShaderResourceGroup. //! @param shaderResourceGroupList The list of ShaderResourceGroups that are being merged. MergedShaderResourceGroup* FindOrCreate(const ShaderResourceGroupList& shaderResourceGroupList); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp index 59dbaf4377..b2772d716e 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp @@ -115,77 +115,65 @@ namespace AZ const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout(); - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask))) + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex) { - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex) - { - const RHI::ShaderInputBufferIndex index(groupIndex); - auto bufViews = groupData.GetBufferViewArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView); - descriptorSet.UpdateBufferViews(layoutIndex, bufViews); - } + const RHI::ShaderInputBufferIndex index(groupIndex); + auto bufViews = groupData.GetBufferViewArray(index); + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView); + descriptorSet.UpdateBufferViews(layoutIndex, bufViews); } - - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask))) + + auto const& shaderImageList = layout->GetShaderInputListForImages(); + for (uint32_t groupIndex = 0; groupIndex < static_cast(shaderImageList.size()); ++groupIndex) { - auto const& shaderImageList = layout->GetShaderInputListForImages(); - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImages().size()); ++groupIndex) - { - const RHI::ShaderInputImageIndex index(groupIndex); - auto imgViews = groupData.GetImageViewArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView); - descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type); - } + const RHI::ShaderInputImageIndex index(groupIndex); + auto imgViews = groupData.GetImageViewArray(index); + uint32_t layoutIndex = + m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView); + descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type); } + - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask))) + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex) { - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex) + const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex); + auto bufViews = groupData.GetBufferViewUnboundedArray(index); + if (bufViews.empty()) { - const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex); - auto bufViews = groupData.GetBufferViewUnboundedArray(index); - if (bufViews.empty()) - { - // skip empty unbounded arrays - continue; - } - - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray); - descriptorSet.UpdateBufferViews(layoutIndex, bufViews); + // skip empty unbounded arrays + continue; } - } - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask))) + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray); + descriptorSet.UpdateBufferViews(layoutIndex, bufViews); + } + + auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays(); + for (uint32_t groupIndex = 0; groupIndex < static_cast(shaderImageUnboundeArrayList.size()); ++groupIndex) { - auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays(); - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImageUnboundedArrays().size()); ++groupIndex) + const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex); + auto imgViews = groupData.GetImageViewUnboundedArray(index); + if (imgViews.empty()) { - const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex); - auto imgViews = groupData.GetImageViewUnboundedArray(index); - if (imgViews.empty()) - { - // skip empty unbounded arrays - continue; - } - - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray); - descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type); + // skip empty unbounded arrays + continue; } - } - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask))) + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray); + descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type); + } + + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex) { - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex) - { - const RHI::ShaderInputSamplerIndex index(groupIndex); - auto samplerArray = groupData.GetSamplerArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler); - descriptorSet.UpdateSamplers(layoutIndex, samplerArray); - } + const RHI::ShaderInputSamplerIndex index(groupIndex); + auto samplerArray = groupData.GetSamplerArray(index); + uint32_t layoutIndex = + m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler); + descriptorSet.UpdateSamplers(layoutIndex, samplerArray); } auto constantData = groupData.GetConstantData(); - if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask))) + if (!constantData.empty()) { descriptorSet.UpdateConstantData(constantData); } From dd47e1aa4e88486c25c7a6fc839434914bcd778e Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri, 15 Oct 2021 15:50:41 -0500 Subject: [PATCH 292/293] Add EditorPrefabComponent to procedural prefab container entity (#4727) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp index 884c463bff..9d0d0547ae 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include namespace AzToolsFramework::Prefab @@ -72,6 +72,7 @@ namespace AzToolsFramework::Prefab entities, commonRoot, &topLevelEntities); auto containerEntity = AZStd::make_unique(); + containerEntity->CreateComponent(); for (AZ::Entity* entity : topLevelEntities) { From 4c733d3f4c5e15c5c1fcfb9332763c265e16de24 Mon Sep 17 00:00:00 2001 From: Yaakuro Date: Sat, 9 Oct 2021 01:34:32 +0200 Subject: [PATCH 293/293] Add basic mouse device implementation and fullscreen handling to GNU/Linux. Signed-off-by: Yaakuro --- .../Editor/Core/QtEditorApplication_linux.cpp | 10 +- .../Common/Xcb/AzFramework/XcbEventHandler.h | 6 +- .../Xcb/AzFramework/XcbInputDeviceMouse.cpp | 652 ++++++++++++++++++ .../Xcb/AzFramework/XcbInputDeviceMouse.h | 193 ++++++ .../Xcb/AzFramework/XcbNativeWindow.cpp | 328 ++++++--- .../Common/Xcb/AzFramework/XcbNativeWindow.h | 53 +- .../Common/Xcb/azframework_xcb_files.cmake | 2 + .../Devices/Mouse/InputDeviceMouse_Linux.cpp | 27 + .../Platform/Linux/platform_linux.cmake | 2 + .../Platform/Linux/platform_linux_files.cmake | 2 +- 10 files changed, 1177 insertions(+), 98 deletions(-) create mode 100644 Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.cpp create mode 100644 Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h create mode 100644 Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp diff --git a/Code/Editor/Core/QtEditorApplication_linux.cpp b/Code/Editor/Core/QtEditorApplication_linux.cpp index 2fd4ef629e..5491134170 100644 --- a/Code/Editor/Core/QtEditorApplication_linux.cpp +++ b/Code/Editor/Core/QtEditorApplication_linux.cpp @@ -19,10 +19,16 @@ namespace Editor if (GetIEditor()->IsInGameMode()) { #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB - AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast(message)); + // We need to handle RAW Input events in a separate loop. This is a workaround to enable XInput2 RAW Inputs using Editor mode. + // TODO To have this call here might be not be perfect. + AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::PollSpecialEvents); + + // Now handle the rest of the events. + AzFramework::XcbEventHandlerBus::Broadcast( + &AzFramework::XcbEventHandler::HandleXcbEvent, static_cast(message)); #endif return true; } return false; } -} +} // namespace Editor diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h index c6307755a7..251342093a 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h @@ -23,10 +23,12 @@ namespace AzFramework virtual ~XcbEventHandler() = default; virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0; + + // ATTN This is used as a workaround for RAW Input events when using the Editor. + virtual void PollSpecialEvents(){}; }; - class XcbEventHandlerBusTraits - : public AZ::EBusTraits + class XcbEventHandlerBusTraits : public AZ::EBusTraits { public: ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.cpp new file mode 100644 index 0000000000..56f21e6533 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.cpp @@ -0,0 +1,652 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AzFramework +{ + xcb_window_t GetSystemCursorFocusWindow() + { + void* systemCursorFocusWindow = nullptr; + AzFramework::InputSystemCursorConstraintRequestBus::BroadcastResult( + systemCursorFocusWindow, &AzFramework::InputSystemCursorConstraintRequests::GetSystemCursorConstraintWindow); + + if (!systemCursorFocusWindow) + { + return XCB_NONE; + } + + // TODO Clang compile error because cast .... loses information. On GNU/Linux HWND is void* and on 64-bit + // machines its obviously 64 bit but we receive the window id from m_renderOverlay.winId() which is xcb_window_t 32-bit. + + return static_cast(reinterpret_cast(systemCursorFocusWindow)); + } + + xcb_connection_t* XcbInputDeviceMouse::s_xcbConnection = nullptr; + xcb_screen_t* XcbInputDeviceMouse::s_xcbScreen = nullptr; + bool XcbInputDeviceMouse::m_xfixesInitialized = false; + bool XcbInputDeviceMouse::m_xInputInitialized = false; + + XcbInputDeviceMouse::XcbInputDeviceMouse(InputDeviceMouse& inputDevice) + : InputDeviceMouse::Implementation(inputDevice) + , m_systemCursorState(SystemCursorState::Unknown) + , m_systemCursorPositionNormalized(0.5f, 0.5f) + , m_prevConstraintWindow(XCB_NONE) + , m_focusWindow(XCB_NONE) + , m_cursorShown(true) + { + XcbEventHandlerBus::Handler::BusConnect(); + + SetSystemCursorState(SystemCursorState::Unknown); + } + + XcbInputDeviceMouse::~XcbInputDeviceMouse() + { + XcbEventHandlerBus::Handler::BusDisconnect(); + + SetSystemCursorState(SystemCursorState::Unknown); + } + + InputDeviceMouse::Implementation* XcbInputDeviceMouse::Create(InputDeviceMouse& inputDevice) + { + auto* interface = AzFramework::XcbConnectionManagerInterface::Get(); + if (!interface) + { + AZ_Warning("XcbInput", false, "XCB interface not available"); + return nullptr; + } + + s_xcbConnection = AzFramework::XcbConnectionManagerInterface::Get()->GetXcbConnection(); + if (!s_xcbConnection) + { + AZ_Warning("XcbInput", false, "XCB connection not available"); + return nullptr; + } + + const xcb_setup_t* xcbSetup = xcb_get_setup(s_xcbConnection); + s_xcbScreen = xcb_setup_roots_iterator(xcbSetup).data; + if (!s_xcbScreen) + { + AZ_Warning("XcbInput", false, "XCB screen not available"); + return nullptr; + } + + // Initialize XFixes extension which we use to create pointer barriers. + if (!InitializeXFixes()) + { + AZ_Warning("XcbInput", false, "XCB XFixes initialization failed"); + return nullptr; + } + + // Initialize XInput extension which is used to get RAW Input events. + if (!InitializeXInput()) + { + AZ_Warning("XcbInput", false, "XCB XInput initialization failed"); + return nullptr; + } + + return aznew XcbInputDeviceMouse(inputDevice); + } + + bool XcbInputDeviceMouse::IsConnected() const + { + return true; + } + + void XcbInputDeviceMouse::CreateBarriers(xcb_window_t window, bool create) + { + // Don't create any barriers if we are debugging. This will cause artifacts but better then + // a confined cursor during debugging. + if (AZ::Debug::Trace::IsDebuggerPresent()) + { + AZ_Warning("XcbInput", false, "Debugger running. Barriers will not be created."); + return; + } + + if (create) + { + // Destroy barriers if they are active already. + if (!m_activeBarriers.empty()) + { + for (const auto& barrier : m_activeBarriers) + { + xcb_xfixes_delete_pointer_barrier_checked(s_xcbConnection, barrier.id); + } + + m_activeBarriers.clear(); + } + + // Get window information. + const XcbStdFreePtr xcbGeometryReply{ xcb_get_geometry_reply( + s_xcbConnection, xcb_get_geometry(s_xcbConnection, window), NULL) }; + + if (!xcbGeometryReply) + { + return; + } + + const xcb_translate_coordinates_cookie_t translate_coord = + xcb_translate_coordinates(s_xcbConnection, window, s_xcbScreen->root, 0, 0); + + const XcbStdFreePtr xkbTranslateCoordReply{ xcb_translate_coordinates_reply( + s_xcbConnection, translate_coord, NULL) }; + + if (!xkbTranslateCoordReply) + { + return; + } + + const int16_t x0 = xkbTranslateCoordReply->dst_x < 0 ? 0 : xkbTranslateCoordReply->dst_x; + const int16_t y0 = xkbTranslateCoordReply->dst_y < 0 ? 0 : xkbTranslateCoordReply->dst_y; + const int16_t x1 = xkbTranslateCoordReply->dst_x + xcbGeometryReply->width; + const int16_t y1 = xkbTranslateCoordReply->dst_y + xcbGeometryReply->height; + + // ATTN For whatever reason, when making an exact rectangle the pointer will escape the top right corner in some cases. Adding + // an offset to the lines so that they cross each other prevents that. + const int16_t offset = 30; + + // Create the left barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_POSITIVE_X, x0, Clamp(y0 - offset), + x0, Clamp(y1 + offset) }); + + // Create the right barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_NEGATIVE_X, x1, Clamp(y0 - offset), + x1, Clamp(y1 + offset) }); + + // Create the top barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_POSITIVE_Y, Clamp(x0 - offset), y0, + Clamp(x1 + offset), y0 }); + + // Create the bottom barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_NEGATIVE_Y, Clamp(x0 - offset), y1, + Clamp(x1 + offset), y1 }); + + // Create the xfixes barriers. + for (const auto& barrier : m_activeBarriers) + { + xcb_void_cookie_t cookie = xcb_xfixes_create_pointer_barrier_checked( + s_xcbConnection, barrier.id, window, barrier.x0, barrier.y0, barrier.x1, barrier.y1, barrier.direction, 0, NULL); + const XcbStdFreePtr xkbError{ xcb_request_check(s_xcbConnection, cookie) }; + + AZ_Warning( + "XcbInput", !xkbError, "XFixes, failed to create barrier %d at (%d %d %d %d)", barrier.id, barrier.x0, barrier.y0, + barrier.x1, barrier.y1); + } + } + else + { + for (const auto& barrier : m_activeBarriers) + { + xcb_xfixes_delete_pointer_barrier_checked(s_xcbConnection, barrier.id); + } + + m_activeBarriers.clear(); + } + + xcb_flush(s_xcbConnection); + } + + bool XcbInputDeviceMouse::InitializeXFixes() + { + m_xfixesInitialized = false; + + // We don't have to free query_extension_reply according to xcb documentation. + const xcb_query_extension_reply_t* query_extension_reply = xcb_get_extension_data(s_xcbConnection, &xcb_xfixes_id); + if (!query_extension_reply || !query_extension_reply->present) + { + return m_xfixesInitialized; + } + + const xcb_xfixes_query_version_cookie_t query_cookie = xcb_xfixes_query_version(s_xcbConnection, 5, 0); + + xcb_generic_error_t* error = NULL; + const XcbStdFreePtr xkbQueryRequestReply{ xcb_xfixes_query_version_reply( + s_xcbConnection, query_cookie, &error) }; + + if (!xkbQueryRequestReply || error) + { + if (error) + { + AZ_Warning("XcbInput", false, "Retrieving XFixes version failed : Error code %d", error->error_code); + free(error); + } + return m_xfixesInitialized; + } + else if (xkbQueryRequestReply->major_version < 5) + { + AZ_Warning("XcbInput", false, "XFixes version fails the minimum version check (%d<5)", xkbQueryRequestReply->major_version); + return m_xfixesInitialized; + } + + m_xfixesInitialized = true; + + return m_xfixesInitialized; + } + + bool XcbInputDeviceMouse::InitializeXInput() + { + m_xInputInitialized = false; + + // We don't have to free query_extension_reply according to xcb documentation. + const xcb_query_extension_reply_t* query_extension_reply = xcb_get_extension_data(s_xcbConnection, &xcb_input_id); + if (!query_extension_reply || !query_extension_reply->present) + { + return m_xInputInitialized; + } + + const xcb_input_xi_query_version_cookie_t query_version_cookie = xcb_input_xi_query_version(s_xcbConnection, 2, 2); + + xcb_generic_error_t* error = NULL; + const XcbStdFreePtr xkbQueryRequestReply{ xcb_input_xi_query_version_reply( + s_xcbConnection, query_version_cookie, &error) }; + + if (!xkbQueryRequestReply || error) + { + if (error) + { + AZ_Warning("XcbInput", false, "Retrieving XInput version failed : Error code %d", error->error_code); + free(error); + } + return m_xInputInitialized; + } + else if (xkbQueryRequestReply->major_version < 2) + { + AZ_Warning("XcbInput", false, "XInput version fails the minimum version check (%d<5)", xkbQueryRequestReply->major_version); + return m_xInputInitialized; + } + + m_xInputInitialized = true; + + return m_xInputInitialized; + } + + void XcbInputDeviceMouse::SetEnableXInput(bool enable) + { + struct + { + xcb_input_event_mask_t head; + int mask; + } mask; + + mask.head.deviceid = XCB_INPUT_DEVICE_ALL; + mask.head.mask_len = 1; + + if (enable) + { + mask.mask = XCB_INPUT_XI_EVENT_MASK_RAW_MOTION | XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_PRESS | + XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_RELEASE | XCB_INPUT_XI_EVENT_MASK_MOTION | XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS | + XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE; + } + else + { + mask.mask = XCB_NONE; + } + + xcb_input_xi_select_events(s_xcbConnection, s_xcbScreen->root, 1, &mask.head); + + xcb_flush(s_xcbConnection); + } + + void XcbInputDeviceMouse::SetSystemCursorState(SystemCursorState systemCursorState) + { + if (systemCursorState != m_systemCursorState) + { + m_systemCursorState = systemCursorState; + + m_focusWindow = GetSystemCursorFocusWindow(); + + HandleCursorState(m_focusWindow, systemCursorState); + } + } + + void XcbInputDeviceMouse::HandleCursorState(xcb_window_t window, SystemCursorState systemCursorState) + { + bool confined = false, cursorShown = true; + switch (systemCursorState) + { + case SystemCursorState::ConstrainedAndHidden: + { + //!< Constrained to the application's main window and hidden + confined = true; + cursorShown = false; + } + break; + case SystemCursorState::ConstrainedAndVisible: + { + //!< Constrained to the application's main window and visible + confined = true; + } + break; + case SystemCursorState::UnconstrainedAndHidden: + { + //!< Free to move outside the main window but hidden while inside + cursorShown = false; + } + break; + case SystemCursorState::UnconstrainedAndVisible: + { + //!< Free to move outside the application's main window and visible + } + case SystemCursorState::Unknown: + default: + break; + } + + // ATTN GetSystemCursorFocusWindow when getting out of the play in editor will return XCB_NONE + // We need however the window id to reset the cursor. + if (XCB_NONE == window && (confined || cursorShown)) + { + // Reuse the previous window to reset states. + window = m_prevConstraintWindow; + m_prevConstraintWindow = XCB_NONE; + } + else + { + // Remember the window we used to modify cursor and barrier states. + m_prevConstraintWindow = window; + } + + SetEnableXInput(!cursorShown); + + CreateBarriers(window, confined); + ShowCursor(window, cursorShown); + } + + SystemCursorState XcbInputDeviceMouse::GetSystemCursorState() const + { + return m_systemCursorState; + } + + void XcbInputDeviceMouse::SetSystemCursorPositionNormalizedInternal(xcb_window_t window, AZ::Vector2 positionNormalized) + { + // TODO Basically not done at all. Added only the basic functions needed. + const XcbStdFreePtr xkbGeometryReply{ xcb_get_geometry_reply( + s_xcbConnection, xcb_get_geometry(s_xcbConnection, window), NULL) }; + + if (!xkbGeometryReply) + { + return; + } + + const int16_t x = static_cast(positionNormalized.GetX() * xkbGeometryReply->width); + const int16_t y = static_cast(positionNormalized.GetY() * xkbGeometryReply->height); + + xcb_warp_pointer(s_xcbConnection, XCB_NONE, window, 0, 0, 0, 0, x, y); + + xcb_flush(s_xcbConnection); + } + + void XcbInputDeviceMouse::SetSystemCursorPositionNormalized(AZ::Vector2 positionNormalized) + { + const xcb_window_t window = GetSystemCursorFocusWindow(); + if (XCB_NONE == window) + { + return; + } + + SetSystemCursorPositionNormalizedInternal(window, positionNormalized); + } + + AZ::Vector2 XcbInputDeviceMouse::GetSystemCursorPositionNormalizedInternal(xcb_window_t window) const + { + AZ::Vector2 position = AZ::Vector2::CreateZero(); + + const xcb_query_pointer_cookie_t pointer = xcb_query_pointer(s_xcbConnection, window); + + const XcbStdFreePtr xkbQueryPointerReply{ xcb_query_pointer_reply(s_xcbConnection, pointer, NULL) }; + + if (!xkbQueryPointerReply) + { + return position; + } + + const XcbStdFreePtr xkbGeometryReply{ xcb_get_geometry_reply( + s_xcbConnection, xcb_get_geometry(s_xcbConnection, window), NULL) }; + + if (!xkbGeometryReply) + { + return position; + } + + AZ_Assert(xkbGeometryReply->width != 0, "xkbGeometry response width must be non-zero. (%d)", xkbGeometryReply->width); + const float normalizedCursorPostionX = static_cast(xkbQueryPointerReply->win_x) / xkbGeometryReply->width; + + AZ_Assert(xkbGeometryReply->height != 0, "xkbGeometry response height must be non-zero. (%d)", xkbGeometryReply->height); + const float normalizedCursorPostionY = static_cast(xkbQueryPointerReply->win_y) / xkbGeometryReply->height; + + position = AZ::Vector2(normalizedCursorPostionX, normalizedCursorPostionY); + + return position; + } + + AZ::Vector2 XcbInputDeviceMouse::GetSystemCursorPositionNormalized() const + { + const xcb_window_t window = GetSystemCursorFocusWindow(); + if (XCB_NONE == window) + { + return AZ::Vector2::CreateZero(); + } + + return GetSystemCursorPositionNormalizedInternal(window); + } + + void XcbInputDeviceMouse::TickInputDevice() + { + ProcessRawEventQueues(); + } + + void XcbInputDeviceMouse::ShowCursor(xcb_window_t window, bool show) + { + xcb_void_cookie_t cookie; + if (show) + { + cookie = xcb_xfixes_show_cursor_checked(s_xcbConnection, window); + } + else + { + cookie = xcb_xfixes_hide_cursor_checked(s_xcbConnection, window); + } + + const XcbStdFreePtr xkbError{ xcb_request_check(s_xcbConnection, cookie) }; + + if (xkbError) + { + AZ_Warning("XcbInput", false, "ShowCursor failed: %d", xkbError->error_code); + + return; + } + + // ATTN In the following part we will when cursor gets hidden store the position of the cursor in screen space + // not window space. We use that to re-position when showing the cursor again. Is this the correct + // behavior? + + const bool cursorWasHidden = !m_cursorShown; + m_cursorShown = show; + if (!m_cursorShown) + { + m_cursorHiddenPosition = GetSystemCursorPositionNormalizedInternal(s_xcbScreen->root); + + SetSystemCursorPositionNormalized(AZ::Vector2(0.5f, 0.5f)); + } + else if (cursorWasHidden) + { + SetSystemCursorPositionNormalizedInternal(s_xcbScreen->root, m_cursorHiddenPosition); + } + + xcb_flush(s_xcbConnection); + } + + void XcbInputDeviceMouse::HandleButtonPressEvents(uint32_t detail, bool pressed) + { + bool isWheel; + float wheelDirection; + const auto* button = InputChannelFromMouseEvent(detail, isWheel, wheelDirection); + if (button) + { + QueueRawButtonEvent(*button, pressed); + } + if (isWheel) + { + float axisValue = MAX_XI_WHEEL_SENSITIVITY * wheelDirection; + QueueRawMovementEvent(InputDeviceMouse::Movement::Z, axisValue); + } + } + + void XcbInputDeviceMouse::HandlePointerMotionEvents(const xcb_generic_event_t* event) + { + const xcb_input_motion_event_t* mouseMotionEvent = reinterpret_cast(event); + + m_systemCursorPosition[0] = mouseMotionEvent->event_x; + m_systemCursorPosition[1] = mouseMotionEvent->event_y; + } + + void XcbInputDeviceMouse::HandleRawInputEvents(const xcb_ge_generic_event_t* event) + { + const xcb_ge_generic_event_t* genericEvent = reinterpret_cast(event); + switch (genericEvent->event_type) + { + case XCB_INPUT_RAW_BUTTON_PRESS: + { + const xcb_input_raw_button_press_event_t* mouseButtonEvent = + reinterpret_cast(event); + HandleButtonPressEvents(mouseButtonEvent->detail, true); + } + break; + case XCB_INPUT_RAW_BUTTON_RELEASE: + { + const xcb_input_raw_button_release_event_t* mouseButtonEvent = + reinterpret_cast(event); + HandleButtonPressEvents(mouseButtonEvent->detail, false); + } + break; + case XCB_INPUT_RAW_MOTION: + { + const xcb_input_raw_motion_event_t* mouseMotionEvent = reinterpret_cast(event); + + int axisLen = xcb_input_raw_button_press_axisvalues_length(mouseMotionEvent); + const xcb_input_fp3232_t* axisvalues = xcb_input_raw_button_press_axisvalues_raw(mouseMotionEvent); + for (int i = 0; i < axisLen; ++i) + { + const float axisValue = fp3232ToFloat(axisvalues[i]); + + switch (i) + { + case 0: + QueueRawMovementEvent(InputDeviceMouse::Movement::X, axisValue); + break; + case 1: + QueueRawMovementEvent(InputDeviceMouse::Movement::Y, axisValue); + break; + } + } + } + break; + } + } + + void XcbInputDeviceMouse::PollSpecialEvents() + { + while (xcb_generic_event_t* genericEvent = xcb_poll_for_queued_event(s_xcbConnection)) + { + // TODO Is the following correct? If we are showing the cursor, don't poll RAW Input events. + switch (genericEvent->response_type & ~0x80) + { + case XCB_GE_GENERIC: + { + const xcb_ge_generic_event_t* geGenericEvent = reinterpret_cast(genericEvent); + + // Only handle raw inputs if we have focus. + // Handle Raw Input events first. + if ((geGenericEvent->event_type == XCB_INPUT_RAW_BUTTON_PRESS) || + (geGenericEvent->event_type == XCB_INPUT_RAW_BUTTON_RELEASE) || + (geGenericEvent->event_type == XCB_INPUT_RAW_MOTION)) + { + HandleRawInputEvents(geGenericEvent); + + free(genericEvent); + } + } + break; + } + } + } + + void XcbInputDeviceMouse::HandleXcbEvent(xcb_generic_event_t* event) + { + switch (event->response_type & ~0x80) + { + // QT5 is using by default XInput which means we do need to check for XCB_GE_GENERIC event to parse all mouse related events. + case XCB_GE_GENERIC: + { + const xcb_ge_generic_event_t* genericEvent = reinterpret_cast(event); + + // Handling RAW Inputs here works in GameMode but not in Editor mode because QT is + // not handling RAW input events and passing to. + if (!m_cursorShown) + { + // Handle Raw Input events first. + if ((genericEvent->event_type == XCB_INPUT_RAW_BUTTON_PRESS) || + (genericEvent->event_type == XCB_INPUT_RAW_BUTTON_RELEASE) || (genericEvent->event_type == XCB_INPUT_RAW_MOTION)) + { + HandleRawInputEvents(genericEvent); + } + } + else + { + switch (genericEvent->event_type) + { + case XCB_INPUT_BUTTON_PRESS: + { + const xcb_input_button_press_event_t* mouseButtonEvent = + reinterpret_cast(genericEvent); + HandleButtonPressEvents(mouseButtonEvent->detail, true); + } + break; + case XCB_INPUT_BUTTON_RELEASE: + { + const xcb_input_button_release_event_t* mouseButtonEvent = + reinterpret_cast(genericEvent); + HandleButtonPressEvents(mouseButtonEvent->detail, false); + } + break; + case XCB_INPUT_MOTION: + { + HandlePointerMotionEvents(event); + } + break; + } + } + } + break; + case XCB_FOCUS_IN: + { + const xcb_focus_in_event_t* focusInEvent = reinterpret_cast(event); + if (m_focusWindow != focusInEvent->event) + { + m_focusWindow = focusInEvent->event; + HandleCursorState(m_focusWindow, m_systemCursorState); + } + } + break; + case XCB_FOCUS_OUT: + { + const xcb_focus_out_event_t* focusOutEvent = reinterpret_cast(event); + HandleCursorState(focusOutEvent->event, SystemCursorState::UnconstrainedAndVisible); + + ProcessRawEventQueues(); + ResetInputChannelStates(); + + m_focusWindow = XCB_NONE; + } + break; + } + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h new file mode 100644 index 0000000000..106d204ca9 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +#include +#include + +// The maximum number of raw input axis this mouse device supports. +constexpr uint32_t MAX_XI_RAW_AXIS = 2; + +// The sensitivity of the wheel. +constexpr float MAX_XI_WHEEL_SENSITIVITY = 140.0f; + +namespace AzFramework +{ + class XcbInputDeviceMouse + : public InputDeviceMouse::Implementation + , public XcbEventHandlerBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(XcbInputDeviceMouse, AZ::SystemAllocator, 0); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Constructor + //! \param[in] inputDevice Reference to the input device being implemented + XcbInputDeviceMouse(InputDeviceMouse& inputDevice); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Destructor + virtual ~XcbInputDeviceMouse(); + + static XcbInputDeviceMouse::Implementation* Create(InputDeviceMouse& inputDevice); + + protected: + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::IsConnected + bool IsConnected() const override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::SetSystemCursorState + void SetSystemCursorState(SystemCursorState systemCursorState) override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::GetSystemCursorState + SystemCursorState GetSystemCursorState() const override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::SetSystemCursorPositionNormalized + void SetSystemCursorPositionNormalized(AZ::Vector2 positionNormalized) override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::GetSystemCursorPositionNormalized + AZ::Vector2 GetSystemCursorPositionNormalized() const override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::TickInputDevice + void TickInputDevice() override; + + //! This method is called by the Editor to accommodate some events with the Editor. Never called in Game mode. + void PollSpecialEvents() override; + + //! Handle X11 events. + void HandleXcbEvent(xcb_generic_event_t* event) override; + + //! Initialize XFixes extension. Used for barriers. + static bool InitializeXFixes(); + + //! Initialize XInput extension. Used for raw input during confinement and showing/hiding the cursor. + static bool InitializeXInput(); + + //! Enables/Disables XInput Raw Input events. + void SetEnableXInput(bool enable); + + //! Create barriers. + void CreateBarriers(xcb_window_t window, bool create); + + //! Helper function. + void SystemCursorStateToLogic(SystemCursorState systemCursorState, bool& confined, bool& cursorShown); + + //! Shows/Hides the cursor. + void ShowCursor(xcb_window_t window, bool show); + + //! Get the normalized cursor position. The coordinates returned are relative to the specified window. + AZ::Vector2 GetSystemCursorPositionNormalizedInternal(xcb_window_t window) const; + + //! Set the normalized cursor position. The normalized position will be relative to the specified window. + void SetSystemCursorPositionNormalizedInternal(xcb_window_t window, AZ::Vector2 positionNormalized); + + //! Handle button press/release events. + void HandleButtonPressEvents(uint32_t detail, bool pressed); + + //! Handle motion notify events. + void HandlePointerMotionEvents(const xcb_generic_event_t* event); + + //! Will set cursor states and confinement modes. + void HandleCursorState(xcb_window_t window, SystemCursorState systemCursorState); + + //! Will handle all raw input events. + void HandleRawInputEvents(const xcb_ge_generic_event_t* event); + + //! Convert XInput fp1616 to float. + inline float fp1616ToFloat(xcb_input_fp1616_t value) const + { + return static_cast((value >> 16) + (value & 0xffff) / 0xffff); + } + + //! Convert XInput fp3232 to float. + inline float fp3232ToFloat(xcb_input_fp3232_t value) const + { + return static_cast(value.integral) + static_cast(value.frac / (float)(1ull << 32)); + } + + const InputChannelId* InputChannelFromMouseEvent(xcb_button_t button, bool& isWheel, float& direction) const + { + isWheel = false; + direction = 1.0f; + switch (button) + { + case XCB_BUTTON_INDEX_1: + return &InputDeviceMouse::Button::Left; + case XCB_BUTTON_INDEX_2: + return &InputDeviceMouse::Button::Right; + case XCB_BUTTON_INDEX_3: + return &InputDeviceMouse::Button::Middle; + case XCB_BUTTON_INDEX_4: + isWheel = true; + direction = 1.0f; + break; + case XCB_BUTTON_INDEX_5: + isWheel = true; + direction = -1.0f; + break; + default: + break; + } + + return nullptr; + } + + // Barriers work only with positive values. We clamp here to zero. + inline int16_t Clamp(int16_t value) const + { + return value < 0 ? 0 : value; + } + + private: + //! The current system cursor state + SystemCursorState m_systemCursorState; + + //! The cursor position before it got hidden. + AZ::Vector2 m_cursorHiddenPosition; + + AZ::Vector2 m_systemCursorPositionNormalized; + uint32_t m_systemCursorPosition[MAX_XI_RAW_AXIS]; + + static xcb_connection_t* s_xcbConnection; + static xcb_screen_t* s_xcbScreen; + + //! Will be true if the xfixes extension could be initialized. + static bool m_xfixesInitialized; + + //! Will be true if the xinput2 extension could be initialized. + static bool m_xInputInitialized; + + //! The window that had focus + xcb_window_t m_prevConstraintWindow; + + //! The current window that has focus + xcb_window_t m_focusWindow; + + //! Will be true if the cursor is shown else false. + bool m_cursorShown; + + struct XFixesBarrierProperty + { + xcb_xfixes_barrier_t id; + uint32_t direction; + int16_t x0, y0, x1, y1; + }; + + //! Array that holds barrier information used to confine the cursor. + std::vector m_activeBarriers; + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp index 43f7e7140f..af5b3af3d8 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp @@ -8,25 +8,31 @@ #include #include -#include #include #include +#include #include namespace AzFramework { [[maybe_unused]] const char XcbErrorWindow[] = "XcbNativeWindow"; - static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages - static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified - static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event + static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages + static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified + static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event + +#define _NET_WM_STATE_REMOVE 0l +#define _NET_WM_STATE_ADD 1l +#define _NET_WM_STATE_TOGGLE 2l //////////////////////////////////////////////////////////////////////////////////////////////// - XcbNativeWindow::XcbNativeWindow() + XcbNativeWindow::XcbNativeWindow() : NativeWindow::Implementation() + , m_xcbConnection(nullptr) + , m_xcbRootScreen(nullptr) + , m_xcbWindow(XCB_NONE) { - if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get(); - xcbConnectionManager != nullptr) + if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get(); xcbConnectionManager != nullptr) { m_xcbConnection = xcbConnectionManager->GetXcbConnection(); } @@ -34,89 +40,184 @@ namespace AzFramework } //////////////////////////////////////////////////////////////////////////////////////////////// - XcbNativeWindow::~XcbNativeWindow() = default; + XcbNativeWindow::~XcbNativeWindow() + { + if (XCB_NONE != m_xcbWindow) + { + xcb_destroy_window(m_xcbConnection, m_xcbWindow); + } + } //////////////////////////////////////////////////////////////////////////////////////////////// - void XcbNativeWindow::InitWindow(const AZStd::string& title, - const WindowGeometry& geometry, - const WindowStyleMasks& styleMasks) + void XcbNativeWindow::InitWindow(const AZStd::string& title, const WindowGeometry& geometry, const WindowStyleMasks& styleMasks) { - // Get the parent window + // Get the parent window const xcb_setup_t* xcbSetup = xcb_get_setup(m_xcbConnection); - xcb_screen_t* xcbRootScreen = xcb_setup_roots_iterator(xcbSetup).data; - xcb_window_t xcbParentWindow = xcbRootScreen->root; + m_xcbRootScreen = xcb_setup_roots_iterator(xcbSetup).data; + xcb_window_t xcbParentWindow = m_xcbRootScreen->root; // Create an XCB window from the connection m_xcbWindow = xcb_generate_id(m_xcbConnection); uint16_t borderWidth = 0; const uint32_t mask = styleMasks.m_platformAgnosticStyleMask; - if ((mask & WindowStyleMasks::WINDOW_STYLE_BORDERED) || - (mask & WindowStyleMasks::WINDOW_STYLE_RESIZEABLE)) + if ((mask & WindowStyleMasks::WINDOW_STYLE_BORDERED) || (mask & WindowStyleMasks::WINDOW_STYLE_RESIZEABLE)) { borderWidth = s_DefaultXcbWindowBorderWidth; } uint32_t eventMask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; - - const uint32_t interestedEvents = - XCB_EVENT_MASK_STRUCTURE_NOTIFY - | XCB_EVENT_MASK_BUTTON_PRESS - | XCB_EVENT_MASK_BUTTON_RELEASE - | XCB_EVENT_MASK_KEY_PRESS - | XCB_EVENT_MASK_KEY_RELEASE - | XCB_EVENT_MASK_POINTER_MOTION - ; - uint32_t valueList[] = { xcbRootScreen->black_pixel, - interestedEvents }; + + const uint32_t interestedEvents = XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE; + uint32_t valueList[] = { m_xcbRootScreen->black_pixel, interestedEvents }; xcb_void_cookie_t xcbCheckResult; - xcbCheckResult = xcb_create_window_checked(m_xcbConnection, - XCB_COPY_FROM_PARENT, - m_xcbWindow, - xcbParentWindow, - aznumeric_cast(geometry.m_posX), - aznumeric_cast(geometry.m_posY), - aznumeric_cast(geometry.m_width), - aznumeric_cast(geometry.m_height), - borderWidth, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcbRootScreen->root_visual, - eventMask, - valueList); + xcbCheckResult = xcb_create_window_checked( + m_xcbConnection, XCB_COPY_FROM_PARENT, m_xcbWindow, xcbParentWindow, aznumeric_cast(geometry.m_posX), + aznumeric_cast(geometry.m_posY), aznumeric_cast(geometry.m_width), aznumeric_cast(geometry.m_height), + borderWidth, XCB_WINDOW_CLASS_INPUT_OUTPUT, m_xcbRootScreen->root_visual, eventMask, valueList); AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to create xcb window."); SetWindowTitle(title); - // Setup the window close event - const static char* wmProtocolString = "WM_PROTOCOLS"; - - xcb_intern_atom_cookie_t cookieProtocol = xcb_intern_atom(m_xcbConnection, 1, strlen(wmProtocolString), wmProtocolString); - xcb_intern_atom_reply_t* replyProtocol = xcb_intern_atom_reply(m_xcbConnection, cookieProtocol, nullptr); - AZ_Error(XcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString); - m_xcbAtomProtocols = replyProtocol->atom; - - const static char* wmDeleteWindowString = "WM_DELETE_WINDOW"; - xcb_intern_atom_cookie_t cookieDeleteWindow = xcb_intern_atom(m_xcbConnection, 0, strlen(wmDeleteWindowString), wmDeleteWindowString); - xcb_intern_atom_reply_t* replyDeleteWindow = xcb_intern_atom_reply(m_xcbConnection, cookieDeleteWindow, nullptr); - AZ_Error(XcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString); - m_xcbAtomDeleteWindow = replyDeleteWindow->atom; - - xcbCheckResult = xcb_change_property_checked(m_xcbConnection, - XCB_PROP_MODE_REPLACE, - m_xcbWindow, - m_xcbAtomProtocols, - XCB_ATOM_ATOM, - s_XcbFormatDataSize, - 1, - &m_xcbAtomDeleteWindow); - - AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to change the xcb atom property for WM_CLOSE event"); - + m_posX = geometry.m_posX; + m_posY = geometry.m_posY; m_width = geometry.m_width; m_height = geometry.m_height; + + InitializeAtoms(); + + xcb_client_message_event_t event; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = _NET_REQUEST_FRAME_EXTENTS; + event.window = m_xcbWindow; + event.format = 32; + event.sequence = 0; + event.data.data32[0] = 0l; + event.data.data32[1] = 0l; + event.data.data32[2] = 0l; + event.data.data32[3] = 0l; + event.data.data32[4] = 0l; + xcbCheckResult = xcb_send_event( + m_xcbConnection, 1, m_xcbRootScreen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)&event); + AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set _NET_REQUEST_FRAME_EXTENTS"); + + // The WM will be able to kill the application if it gets unresponsive. + int32_t pid = getpid(); + xcb_change_property(m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid); + + xcb_flush(m_xcbConnection); + } + + xcb_atom_t XcbNativeWindow::GetAtom(const char* atomName) + { + xcb_intern_atom_cookie_t intern_atom_cookie = xcb_intern_atom(m_xcbConnection, 0, strlen(atomName), atomName); + XcbStdFreePtr xkbinternAtom{ xcb_intern_atom_reply(m_xcbConnection, intern_atom_cookie, NULL) }; + + if (!xkbinternAtom) + { + AZ_Error(XcbErrorWindow, xkbinternAtom != nullptr, "Unable to query xcb '%s' atom", atomName); + return XCB_NONE; + } + + return xkbinternAtom->atom; + } + + int XcbNativeWindow::SetAtom(xcb_window_t window, xcb_atom_t atom, xcb_atom_t type, size_t len, void* data) + { + xcb_void_cookie_t cookie = xcb_change_property_checked(m_xcbConnection, XCB_PROP_MODE_REPLACE, window, atom, type, 32, len, data); + XcbStdFreePtr xkbError{ xcb_request_check(m_xcbConnection, cookie) }; + + if (!xkbError) + { + return 0; + } + + return xkbError->error_code; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + void XcbNativeWindow::InitializeAtoms() + { + AZStd::vector Atoms; + + _NET_ACTIVE_WINDOW = GetAtom("_NET_ACTIVE_WINDOW"); + _NET_WM_BYPASS_COMPOSITOR = GetAtom("_NET_WM_BYPASS_COMPOSITOR"); + + // --------------------------------------------------------------------- + // Handle all WM Protocols atoms. + // + + WM_PROTOCOLS = GetAtom("WM_PROTOCOLS"); + + // This atom is used to close a window. Emitted when user clicks the close button. + WM_DELETE_WINDOW = GetAtom("WM_DELETE_WINDOW"); + + Atoms.push_back(WM_DELETE_WINDOW); + + xcb_change_property( + m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, WM_PROTOCOLS, XCB_ATOM_ATOM, 32, Atoms.size(), Atoms.data()); + + xcb_flush(m_xcbConnection); + + // --------------------------------------------------------------------- + // Handle all WM State atoms. + // + + _NET_WM_STATE = GetAtom("_NET_WM_STATE"); + _NET_WM_STATE_FULLSCREEN = GetAtom("_NET_WM_STATE_FULLSCREEN"); + _NET_WM_STATE_MAXIMIZED_VERT = GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"); + _NET_WM_STATE_MAXIMIZED_HORZ = GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"); + _NET_MOVERESIZE_WINDOW = GetAtom("_NET_MOVERESIZE_WINDOW"); + _NET_REQUEST_FRAME_EXTENTS = GetAtom("_NET_REQUEST_FRAME_EXTENTS"); + _NET_FRAME_EXTENTS = GetAtom("_NET_FRAME_EXTENTS"); + _NET_WM_PID = GetAtom("_NET_WM_PID"); + } + + void XcbNativeWindow::GetWMStates() + { + xcb_get_property_cookie_t cookie = xcb_get_property(m_xcbConnection, 0, m_xcbWindow, _NET_WM_STATE, XCB_ATOM_ATOM, 0, 1024); + + xcb_generic_error_t* error = nullptr; + XcbStdFreePtr xkbGetPropertyReply{ xcb_get_property_reply(m_xcbConnection, cookie, &error) }; + + if (!xkbGetPropertyReply || error || !((xkbGetPropertyReply->format == 32) && (xkbGetPropertyReply->type == XCB_ATOM_ATOM))) + { + AZ_Warning("ApplicationLinux", false, "Acquiring _NET_WM_STATE information from the WM failed."); + + if (error) + { + AZ_TracePrintf("Error", "Error code %d", error->error_code); + free(error); + } + return; + } + + m_fullscreenState = false; + m_horizontalyMaximized = false; + m_verticallyMaximized = false; + + const xcb_atom_t* states = static_cast(xcb_get_property_value(xkbGetPropertyReply.get())); + for (int i = 0; i < xkbGetPropertyReply->length; i++) + { + if (states[i] == _NET_WM_STATE_FULLSCREEN) + { + m_fullscreenState = true; + } + else if (states[i] == _NET_WM_STATE_MAXIMIZED_HORZ) + { + m_horizontalyMaximized = true; + } + else if (states[i] == _NET_WM_STATE_MAXIMIZED_VERT) + { + m_verticallyMaximized = true; + } + } } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -146,7 +247,7 @@ namespace AzFramework xcb_flush(m_xcbConnection); } XcbEventHandlerBus::Handler::BusDisconnect(); - } + } //////////////////////////////////////////////////////////////////////////////////////////////// NativeWindowHandle XcbNativeWindow::GetWindowHandle() const @@ -158,14 +259,9 @@ namespace AzFramework void XcbNativeWindow::SetWindowTitle(const AZStd::string& title) { xcb_void_cookie_t xcbCheckResult; - xcbCheckResult = xcb_change_property(m_xcbConnection, - XCB_PROP_MODE_REPLACE, - m_xcbWindow, - XCB_ATOM_WM_NAME, - XCB_ATOM_STRING, - 8, - static_cast(title.size()), - title.c_str()); + xcbCheckResult = xcb_change_property( + m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, static_cast(title.size()), + title.c_str()); AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set window title."); } @@ -175,7 +271,7 @@ namespace AzFramework const uint32_t values[] = { clientAreaSize.m_width, clientAreaSize.m_height }; xcb_configure_window(m_xcbConnection, m_xcbWindow, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); - + m_width = clientAreaSize.m_width; m_height = clientAreaSize.m_height; } @@ -185,16 +281,77 @@ namespace AzFramework { // [GFX TODO][GHI - 2678] // Using 60 for now until proper support is added + return 60; } + bool XcbNativeWindow::GetFullScreenState() const + { + return m_fullscreenState; + } + + void XcbNativeWindow::SetFullScreenState(bool fullScreenState) + { + // TODO This is a pretty basic full-screen implementation using WM's _NET_WM_STATE_FULLSCREEN state. + // Do we have to provide also the old way? + + GetWMStates(); + + xcb_client_message_event_t event; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = _NET_WM_STATE; + event.window = m_xcbWindow; + event.format = 32; + event.sequence = 0; + event.data.data32[0] = fullScreenState ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + event.data.data32[1] = _NET_WM_STATE_FULLSCREEN; + event.data.data32[2] = 0; + event.data.data32[3] = 1; + event.data.data32[4] = 0; + xcb_void_cookie_t xcbCheckResult = xcb_send_event( + m_xcbConnection, 1, m_xcbRootScreen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)&event); + AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set _NET_WM_STATE_FULLSCREEN"); + + // Also try to disable/enable the compositor if possible. Might help in some cases. + const long _NET_WM_BYPASS_COMPOSITOR_HINT_ON = m_fullscreenState ? 1 : 0; + SetAtom(m_xcbWindow, _NET_WM_BYPASS_COMPOSITOR, XCB_ATOM_CARDINAL, 32, (char*)&_NET_WM_BYPASS_COMPOSITOR_HINT_ON); + + if (!fullScreenState) + { + if (m_horizontalyMaximized || m_verticallyMaximized) + { + printf("Remove maximized state.\n"); + xcb_client_message_event_t event; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = _NET_WM_STATE; + event.window = m_xcbWindow; + event.format = 32; + event.sequence = 0; + event.data.data32[0] = _NET_WM_STATE_MAXIMIZED_VERT; + event.data.data32[1] = _NET_WM_STATE_MAXIMIZED_HORZ; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + xcb_void_cookie_t xcbCheckResult = xcb_send_event( + m_xcbConnection, 1, m_xcbRootScreen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)&event); + AZ_Assert( + ValidateXcbResult(xcbCheckResult), "Failed to remove _NET_WM_STATE_MAXIMIZED_VERT | _NET_WM_STATE_MAXIMIZED_HORZ"); + } + } + + xcb_flush(m_xcbConnection); + m_fullscreenState = fullScreenState; + } + //////////////////////////////////////////////////////////////////////////////////////////////// bool XcbNativeWindow::ValidateXcbResult(xcb_void_cookie_t cookie) { bool result = true; if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie)) { - AZ_TracePrintf("Error","Error code %d", error->error_code); + AZ_TracePrintf("Error", "Error code %d", error->error_code); result = false; } return result; @@ -205,20 +362,20 @@ namespace AzFramework { switch (event->response_type & s_XcbResponseTypeMask) { - case XCB_CONFIGURE_NOTIFY: + case XCB_CONFIGURE_NOTIFY: { xcb_configure_notify_event_t* cne = reinterpret_cast(event); - WindowSizeChanged(aznumeric_cast(cne->width), - aznumeric_cast(cne->height)); - + if ((cne->width != m_width) || (cne->height != m_height)) + { + WindowSizeChanged(aznumeric_cast(cne->width), aznumeric_cast(cne->height)); + } break; } - case XCB_CLIENT_MESSAGE: + case XCB_CLIENT_MESSAGE: { xcb_client_message_event_t* cme = reinterpret_cast(event); - if ((cme->type == m_xcbAtomProtocols) && - (cme->format == s_XcbFormatDataSize) && - (cme->data.data32[0] == m_xcbAtomDeleteWindow)) + + if ((cme->type == WM_PROTOCOLS) && (cme->format == s_XcbFormatDataSize) && (cme->data.data32[0] == WM_DELETE_WINDOW)) { Deactivate(); @@ -239,7 +396,8 @@ namespace AzFramework if (m_activated) { - WindowNotificationBus::Event(reinterpret_cast(m_xcbWindow), &WindowNotificationBus::Events::OnWindowResized, width, height); + WindowNotificationBus::Event( + reinterpret_cast(m_xcbWindow), &WindowNotificationBus::Events::OnWindowResized, width, height); } } } diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h index 36737e24e8..38462dcb08 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h @@ -27,15 +27,16 @@ namespace AzFramework //////////////////////////////////////////////////////////////////////////////////////////// // NativeWindow::Implementation - void InitWindow(const AZStd::string& title, - const WindowGeometry& geometry, - const WindowStyleMasks& styleMasks) override; + void InitWindow(const AZStd::string& title, const WindowGeometry& geometry, const WindowStyleMasks& styleMasks) override; void Activate() override; void Deactivate() override; NativeWindowHandle GetWindowHandle() const override; void SetWindowTitle(const AZStd::string& title) override; void ResizeClientArea(WindowSize clientAreaSize) override; - uint32_t GetDisplayRefreshRate() const override; + uint32_t GetDisplayRefreshRate() const override; + + bool GetFullScreenState() const override; + void SetFullScreenState(bool fullScreenState) override; //////////////////////////////////////////////////////////////////////////////////////////// // XcbEventHandlerBus::Handler @@ -44,10 +45,46 @@ namespace AzFramework private: bool ValidateXcbResult(xcb_void_cookie_t cookie); void WindowSizeChanged(const uint32_t width, const uint32_t height); + int SetAtom(xcb_window_t window, xcb_atom_t atom, xcb_atom_t type, size_t len, void* data); + + // Initialize one atom. + xcb_atom_t GetAtom(const char* atomName); + + // Initialize all used atoms. + void InitializeAtoms(); + void GetWMStates(); + + xcb_connection_t* m_xcbConnection = nullptr; + xcb_screen_t* m_xcbRootScreen = nullptr; + xcb_window_t m_xcbWindow = 0; + int32_t m_posX; + int32_t m_posY; + bool m_fullscreenState = false; + bool m_horizontalyMaximized = false; + bool m_verticallyMaximized = false; - xcb_connection_t* m_xcbConnection = nullptr; - xcb_window_t m_xcbWindow = 0; - xcb_atom_t m_xcbAtomProtocols; - xcb_atom_t m_xcbAtomDeleteWindow; + // Use exact atom names for easy readability and usage. + xcb_atom_t WM_PROTOCOLS; + xcb_atom_t WM_DELETE_WINDOW; + // This atom is used to activate a window. + xcb_atom_t _NET_ACTIVE_WINDOW; + // This atom is use to bypass a compositor. Used during fullscreen mode. + xcb_atom_t _NET_WM_BYPASS_COMPOSITOR; + // This atom is used to change the state of a window using the WM. + xcb_atom_t _NET_WM_STATE; + // This atom is used to enable/disable fullscreen mode of a window. + xcb_atom_t _NET_WM_STATE_FULLSCREEN; + // This atom is used to extend the window to max vertically. + xcb_atom_t _NET_WM_STATE_MAXIMIZED_VERT; + // This atom is used to extend the window to max horizontally. + xcb_atom_t _NET_WM_STATE_MAXIMIZED_HORZ; + // This atom is used to position and resize a window. + xcb_atom_t _NET_MOVERESIZE_WINDOW; + // This atom is used to request the extent of the window. + xcb_atom_t _NET_REQUEST_FRAME_EXTENTS; + // This atom is used to identify the reply event for _NET_REQUEST_FRAME_EXTENTS + xcb_atom_t _NET_FRAME_EXTENTS; + // This atom is used to allow WM to kill app if not responsive anymore + xcb_atom_t _NET_WM_PID; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake b/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake index 68de710fa1..48afccc0d0 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake @@ -12,6 +12,8 @@ set(FILES AzFramework/XcbConnectionManager.h AzFramework/XcbInputDeviceKeyboard.cpp AzFramework/XcbInputDeviceKeyboard.h + AzFramework/XcbInputDeviceMouse.cpp + AzFramework/XcbInputDeviceMouse.h AzFramework/XcbInterface.h AzFramework/XcbNativeWindow.cpp AzFramework/XcbNativeWindow.h diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp new file mode 100644 index 0000000000..e2c3c2d575 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp @@ -0,0 +1,27 @@ +/* + * 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_LINUX_WINDOW_MANAGER_XCB +#include +#endif + +namespace AzFramework +{ + InputDeviceMouse::Implementation* InputDeviceMouse::Implementation::Create(InputDeviceMouse& inputDevice) + { +#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB + return XcbInputDeviceMouse::Create(inputDevice); +#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND +#error "Linux Window Manager Wayland not supported." + return nullptr; +#else +#error "Linux Window Manager not recognized." + return nullptr; +#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake b/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake index b08c3b310d..66211c6085 100644 --- a/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake +++ b/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake @@ -22,8 +22,10 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb") PRIVATE 3rdParty::X11::xcb 3rdParty::X11::xcb_xkb + 3rdParty::X11::xcb_xfixes 3rdParty::X11::xkbcommon 3rdParty::X11::xkbcommon_X11 + xcb-xinput ) elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland") diff --git a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake index 4f06aa5c57..206563fdda 100644 --- a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake @@ -22,8 +22,8 @@ set(FILES AzFramework/Windowing/NativeWindow_Linux.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp + AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp - ../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp AzFramework/Input/User/LocalUserId_Platform.h ../Common/Default/AzFramework/Input/User/LocalUserId_Default.h