diff --git a/Assets/Editor/UI/releaseTranslations.py b/Assets/Editor/UI/releaseTranslations.py
deleted file mode 100755
index 9ab0345d98..0000000000
--- a/Assets/Editor/UI/releaseTranslations.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
-# its licensors.
-#
-# For complete copyright and license terms please see the LICENSE at the root of this
-# distribution (the "License"). All use of this software is governed by the License,
-# or, if provided, by the license below or the license accompanying this file. Do not
-# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#
-import os
-
-os.chdir('qml')
-startDir = os.getcwd()
-
-# since it's a .exe file it will only work on windows, but we may as well
-# construct the path in a platform-independent way.
-lreleaseCmd = os.path.join(startDir, '..', '..', '..',
- 'Code', 'SDKs', 'Qt', 'x64', 'bin', 'lrelease.exe ')
-
-print(startDir)
-
-# Korean, Japanese and Simplified Chinese
-targetLanguages = ['ko', 'ja', 'zh_CN']
-
-for lang in targetLanguages:
- os.chdir(startDir)
- tgtLang = '-target-language ' + lang
- os.system(lreleaseCmd + 'this_' + lang + '.ts')
-
- for fileName in os.listdir():
- if not fileName.endswith(".ts"):
- continue
-
- os.system(lreleaseCmd + ' ' + fileName)
-
- print(('Finished processing: ' + fileName))
diff --git a/AutomatedTesting/Config/aws_resource_mappings.json b/AutomatedTesting/Config/default_aws_resource_mappings.json
similarity index 100%
rename from AutomatedTesting/Config/aws_resource_mappings.json
rename to AutomatedTesting/Config/default_aws_resource_mappings.json
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
index 511d9b3ecd..d8fd8b145a 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
@@ -112,7 +112,7 @@ def remove_file(file_path: str) -> None:
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['AWS/Metrics'])
@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME])
-@pytest.mark.parametrize('resource_mappings_filename', ['aws_resource_mappings.json'])
+@pytest.mark.parametrize('resource_mappings_filename', ['default_aws_resource_mappings.json'])
@pytest.mark.parametrize('profile_name', ['AWSAutomationTest'])
@pytest.mark.parametrize('region_name', ['us-west-2'])
@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests'])
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_anonymous_credentials.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_anonymous_credentials.py
index f8aa5b85eb..a477e89821 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_anonymous_credentials.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_anonymous_credentials.py
@@ -36,7 +36,7 @@ logger = logging.getLogger(__name__)
@pytest.mark.usefixtures('cdk')
@pytest.mark.parametrize('feature_name', [AWS_CLIENT_AUTH_FEATURE_NAME])
@pytest.mark.usefixtures('resource_mappings')
-@pytest.mark.parametrize('resource_mappings_filename', ['aws_resource_mappings.json'])
+@pytest.mark.parametrize('resource_mappings_filename', ['default_aws_resource_mappings.json'])
@pytest.mark.usefixtures('aws_utils')
@pytest.mark.parametrize('region_name', ['us-west-2'])
@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests'])
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_password_signin.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_password_signin.py
index 28b17fdeee..a0bcf56b0d 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_password_signin.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/test_password_signin.py
@@ -35,7 +35,7 @@ logger = logging.getLogger(__name__)
@pytest.mark.usefixtures('cdk')
@pytest.mark.parametrize('feature_name', [AWS_CLIENT_AUTH_FEATURE_NAME])
@pytest.mark.usefixtures('resource_mappings')
-@pytest.mark.parametrize('resource_mappings_filename', ['aws_resource_mappings.json'])
+@pytest.mark.parametrize('resource_mappings_filename', ['default_aws_resource_mappings.json'])
@pytest.mark.usefixtures('aws_utils')
@pytest.mark.parametrize('region_name', ['us-west-2'])
@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests'])
diff --git a/AutomatedTesting/Registry/awscoreconfiguration.setreg b/AutomatedTesting/Registry/awscoreconfiguration.setreg
index b7c60b0fb9..1927909328 100644
--- a/AutomatedTesting/Registry/awscoreconfiguration.setreg
+++ b/AutomatedTesting/Registry/awscoreconfiguration.setreg
@@ -4,7 +4,7 @@
"AWSCore":
{
"ProfileName": "AWSAutomationTest",
- "ResourceMappingConfigFileName": "aws_resource_mappings.json"
+ "ResourceMappingConfigFileName": "default_aws_resource_mappings.json"
}
}
}
\ No newline at end of file
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
index 33acfa9e1b..014a098a91 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
@@ -31,5 +31,6 @@
CarrotArrowDown.svg
Summary.svg
WindowClose.svg
+ Warning.svg
diff --git a/Code/Tools/ProjectManager/Resources/Warning.svg b/Code/Tools/ProjectManager/Resources/Warning.svg
new file mode 100644
index 0000000000..28f7bc5f42
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Warning.svg
@@ -0,0 +1,5 @@
+
diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
index 0e3a4ba95d..93f8895079 100644
--- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
@@ -206,7 +206,11 @@ namespace O3DE::ProjectManager
PythonBindingsInterface::Get()->AddProject(projectInfo.m_path);
#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
- m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path);
+ if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path))
+ {
+ QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template."));
+ return;
+ }
#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
projectInfo.m_needsBuild = true;
diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
index cf597745ea..4efa9d1d0f 100644
--- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
@@ -16,7 +16,7 @@
#include
#include
#include
-#include
+#include
#include
#include
@@ -46,28 +46,28 @@ namespace O3DE::ProjectManager
m_engineVersion->lineEdit()->setReadOnly(true);
layout->addWidget(m_engineVersion);
- m_thirdParty = new FormBrowseEditWidget(tr("3rd Party Software Folder"), engineInfo.m_thirdPartyPath, this);
+ m_thirdParty = new FormFolderBrowseEditWidget(tr("3rd Party Software Folder"), engineInfo.m_thirdPartyPath, this);
m_thirdParty->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
m_thirdParty->lineEdit()->setReadOnly(true);
m_thirdParty->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
connect(m_thirdParty->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged);
layout->addWidget(m_thirdParty);
- m_defaultProjects = new FormBrowseEditWidget(tr("Default Projects Folder"), engineInfo.m_defaultProjectsFolder, this);
+ m_defaultProjects = new FormFolderBrowseEditWidget(tr("Default Projects Folder"), engineInfo.m_defaultProjectsFolder, this);
m_defaultProjects->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
m_defaultProjects->lineEdit()->setReadOnly(true);
m_defaultProjects->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
connect(m_defaultProjects->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged);
layout->addWidget(m_defaultProjects);
- m_defaultGems = new FormBrowseEditWidget(tr("Default Gems Folder"), engineInfo.m_defaultGemsFolder, this);
+ m_defaultGems = new FormFolderBrowseEditWidget(tr("Default Gems Folder"), engineInfo.m_defaultGemsFolder, this);
m_defaultGems->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
m_defaultGems->lineEdit()->setReadOnly(true);
m_defaultGems->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
connect(m_defaultGems->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged);
layout->addWidget(m_defaultGems);
- m_defaultProjectTemplates = new FormBrowseEditWidget(tr("Default Project Templates Folder"), engineInfo.m_defaultTemplatesFolder, this);
+ m_defaultProjectTemplates = new FormFolderBrowseEditWidget(tr("Default Project Templates Folder"), engineInfo.m_defaultTemplatesFolder, this);
m_defaultProjectTemplates->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
m_defaultProjectTemplates->lineEdit()->setReadOnly(true);
m_defaultProjectTemplates->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp
index c30d6a7b30..9a2227cf4a 100644
--- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp
+++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp
@@ -11,13 +11,9 @@
*/
#include
-#include
+
#include
#include
-#include
-#include
-#include
-#include
namespace O3DE::ProjectManager
{
@@ -30,20 +26,4 @@ namespace O3DE::ProjectManager
connect(browseButton, &QPushButton::pressed, this, &FormBrowseEditWidget::HandleBrowseButton);
m_frameLayout->addWidget(browseButton);
}
-
- void FormBrowseEditWidget::HandleBrowseButton()
- {
- QString defaultPath = m_lineEdit->text();
- if (defaultPath.isEmpty())
- {
- defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
- }
-
- QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath));
- if (!directory.isEmpty())
- {
- m_lineEdit->setText(directory);
- }
-
- }
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h
index 887fc29dd9..1eba97654b 100644
--- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h
+++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h
@@ -27,7 +27,7 @@ namespace O3DE::ProjectManager
explicit FormBrowseEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr);
~FormBrowseEditWidget() = default;
- private slots:
- void HandleBrowseButton();
+ protected slots:
+ virtual void HandleBrowseButton() = 0;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.cpp
new file mode 100644
index 0000000000..2c4cad5adb
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.cpp
@@ -0,0 +1,42 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ FormFolderBrowseEditWidget::FormFolderBrowseEditWidget(const QString& labelText, const QString& valueText, QWidget* parent)
+ : FormBrowseEditWidget(labelText, valueText, parent)
+ {
+ }
+
+ void FormFolderBrowseEditWidget::HandleBrowseButton()
+ {
+ QString defaultPath = m_lineEdit->text();
+ if (defaultPath.isEmpty())
+ {
+ defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+ }
+
+ QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath));
+ if (!directory.isEmpty())
+ {
+ m_lineEdit->setText(directory);
+ }
+
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.h
new file mode 100644
index 0000000000..a99fe3b5c2
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/FormFolderBrowseEditWidget.h
@@ -0,0 +1,33 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ class FormFolderBrowseEditWidget
+ : public FormBrowseEditWidget
+ {
+ Q_OBJECT
+
+ public:
+ explicit FormFolderBrowseEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr);
+ ~FormFolderBrowseEditWidget() = default;
+
+ protected:
+ void HandleBrowseButton() override;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.cpp
new file mode 100644
index 0000000000..5bb9d61dd6
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.cpp
@@ -0,0 +1,35 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include
+#include
+
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ FormImageBrowseEditWidget::FormImageBrowseEditWidget(const QString& labelText, const QString& valueText, QWidget* parent)
+ : FormBrowseEditWidget(labelText, valueText, parent)
+ {
+ }
+
+ void FormImageBrowseEditWidget::HandleBrowseButton()
+ {
+ QString file = QDir::toNativeSeparators(QFileDialog::getOpenFileName(
+ this, tr("Select Image"), m_lineEdit->text(), tr("PNG (*.png)")));
+ if (!file.isEmpty())
+ {
+ m_lineEdit->setText(file);
+ }
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.h
new file mode 100644
index 0000000000..e01e9254f8
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/FormImageBrowseEditWidget.h
@@ -0,0 +1,33 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ class FormImageBrowseEditWidget
+ : public FormBrowseEditWidget
+ {
+ Q_OBJECT
+
+ public:
+ explicit FormImageBrowseEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr);
+ ~FormImageBrowseEditWidget() = default;
+
+ protected:
+ void HandleBrowseButton() override;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
index 2c92af4e51..763c9dfb75 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -144,12 +145,23 @@ namespace O3DE::ProjectManager
}
}
- void GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath)
+ bool GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath)
{
IPythonBindings* pythonBindings = PythonBindingsInterface::Get();
QVector toBeAdded = m_gemModel->GatherGemsToBeAdded();
QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved();
+ if (m_gemModel->DoGemsToBeAddedHaveRequirements())
+ {
+ GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, toBeAdded, this);
+ confirmRequirementsDialog->exec();
+
+ if (confirmRequirementsDialog->GetButtonResult() != QDialogButtonBox::ApplyRole)
+ {
+ return false;
+ }
+ }
+
for (const QModelIndex& modelIndex : toBeAdded)
{
const QString gemPath = GemModel::GetPath(modelIndex);
@@ -158,6 +170,8 @@ namespace O3DE::ProjectManager
{
QMessageBox::critical(nullptr, "Operation failed",
QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str()));
+
+ return false;
}
}
@@ -169,8 +183,12 @@ namespace O3DE::ProjectManager
{
QMessageBox::critical(nullptr, "Operation failed",
QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str()));
+
+ return false;
}
}
+
+ return true;
}
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
index f5092e837a..fc771d9168 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
@@ -33,7 +33,7 @@ namespace O3DE::ProjectManager
ProjectManagerScreen GetScreenEnum() override;
void ReinitForProject(const QString& projectPath, bool isNewProject);
- void EnableDisableGemsForProject(const QString& projectPath);
+ bool EnableDisableGemsForProject(const QString& projectPath);
private:
void FillModel(const QString& projectPath, bool isNewProject);
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
index 722783ece1..f99e9689f3 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
@@ -73,6 +73,7 @@ namespace O3DE::ProjectManager
Platforms m_platforms;
Types m_types; //! Asset and/or Code and/or Tool
QStringList m_features;
+ QString m_requirement;
QString m_directoryLink;
QString m_documentationLink;
QString m_version = "Unknown Version";
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
index 3ecc18231e..119ec68d3a 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -70,6 +71,22 @@ namespace O3DE::ProjectManager
m_directoryLinkLabel->SetUrl(m_model->GetDirectoryLink(modelIndex));
m_documentationLinkLabel->SetUrl(m_model->GetDocLink(modelIndex));
+ if (m_model->HasRequirement(modelIndex))
+ {
+ m_reqirementsIconLabel->show();
+ m_reqirementsTitleLabel->show();
+ m_reqirementsTextLabel->show();
+
+ m_reqirementsTitleLabel->setText("Requirement");
+ m_reqirementsTextLabel->setText(m_model->GetRequirement(modelIndex));
+ }
+ else
+ {
+ m_reqirementsIconLabel->hide();
+ m_reqirementsTitleLabel->hide();
+ m_reqirementsTextLabel->hide();
+ }
+
// Depending and conflicting gems
m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex));
m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGemNames(modelIndex));
@@ -134,6 +151,28 @@ namespace O3DE::ProjectManager
m_mainLayout->addSpacing(10);
+ // Requirements
+ m_reqirementsTitleLabel = GemInspector::CreateStyledLabel(m_mainLayout, 16, s_headerColor);
+
+ QHBoxLayout* requrementsLayout = new QHBoxLayout();
+ requrementsLayout->setAlignment(Qt::AlignTop);
+ requrementsLayout->setMargin(0);
+ requrementsLayout->setSpacing(0);
+
+ m_reqirementsIconLabel = new QLabel();
+ m_reqirementsIconLabel->setPixmap(QIcon(":/Warning.svg").pixmap(24, 24));
+ requrementsLayout->addWidget(m_reqirementsIconLabel);
+
+ m_reqirementsTextLabel = GemInspector::CreateStyledLabel(requrementsLayout, 10, s_textColor);
+ m_reqirementsTextLabel->setWordWrap(true);
+
+ QSpacerItem* reqirementsSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding);
+ requrementsLayout->addSpacerItem(reqirementsSpacer);
+
+ m_mainLayout->addLayout(requrementsLayout);
+
+ m_mainLayout->addSpacing(20);
+
// Depending and conflicting gems
m_dependingGems = new GemsSubWidget();
m_mainLayout->addWidget(m_dependingGems);
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
index 69c065c81e..4363ea3bc1 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
@@ -76,6 +76,11 @@ namespace O3DE::ProjectManager
LinkLabel* m_directoryLinkLabel = nullptr;
LinkLabel* m_documentationLinkLabel = nullptr;
+ // Requirements
+ QLabel* m_reqirementsTitleLabel = nullptr;
+ QLabel* m_reqirementsIconLabel = nullptr;
+ QLabel* m_reqirementsTextLabel = nullptr;
+
// Depending and conflicting gems
GemsSubWidget* m_dependingGems = nullptr;
GemsSubWidget* m_conflictingGems = nullptr;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
index 03787de7e8..6529e4cf3d 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
@@ -11,7 +11,7 @@
*/
#include
-#include "GemModel.h"
+#include
#include
#include
#include
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
index 48f173ec3f..a155d9ece0 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
@@ -62,7 +62,7 @@ namespace O3DE::ProjectManager
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
inline constexpr static qreal s_buttonFontSize = 10.0;
- private:
+ protected:
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;
@@ -71,6 +71,7 @@ namespace O3DE::ProjectManager
QAbstractItemModel* m_model = nullptr;
+ private:
// Platform icons
void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath);
inline constexpr static int s_platformIconSize = 12;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp
index 2838277696..575c09db05 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp
@@ -10,11 +10,9 @@
*
*/
-#include "GemListView.h"
-#include "GemItemDelegate.h"
+#include
+#include
#include
-#include
-#include
namespace O3DE::ProjectManager
{
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h
index 178de2395f..5f1a018b9f 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h
@@ -13,7 +13,6 @@
#pragma once
#if !defined(Q_MOC_RUN)
-#include "GemInfo.h"
#include
#include
#include
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
index 5dc40723c9..7d9d86e3a7 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
@@ -49,6 +49,7 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize);
item->setData(gemInfo.m_features, RoleFeatures);
item->setData(gemInfo.m_path, RolePath);
+ item->setData(gemInfo.m_requirement, RoleRequirement);
appendRow(item);
@@ -183,6 +184,11 @@ namespace O3DE::ProjectManager
return modelIndex.data(RolePath).toString();
}
+ QString GemModel::GetRequirement(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleRequirement).toString();
+ }
+
bool GemModel::IsAdded(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleIsAdded).toBool();
@@ -208,6 +214,24 @@ namespace O3DE::ProjectManager
return (modelIndex.data(RoleWasPreviouslyAdded).toBool() && !modelIndex.data(RoleIsAdded).toBool());
}
+ bool GemModel::HasRequirement(const QModelIndex& modelIndex)
+ {
+ return !modelIndex.data(RoleRequirement).toString().isEmpty();
+ }
+
+ bool GemModel::DoGemsToBeAddedHaveRequirements() const
+ {
+ for (int row = 0; row < rowCount(); ++row)
+ {
+ const QModelIndex modelIndex = index(row, 0);
+ if (NeedsToBeAdded(modelIndex) && HasRequirement(modelIndex))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
QVector GemModel::GatherGemsToBeAdded() const
{
QVector result;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
index 2e05472cdf..301053a9bf 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
@@ -53,12 +53,16 @@ namespace O3DE::ProjectManager
static int GetBinarySizeInKB(const QModelIndex& modelIndex);
static QStringList GetFeatures(const QModelIndex& modelIndex);
static QString GetPath(const QModelIndex& modelIndex);
+ static QString GetRequirement(const QModelIndex& modelIndex);
static bool IsAdded(const QModelIndex& modelIndex);
static void SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded);
static void SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded);
static bool NeedsToBeAdded(const QModelIndex& modelIndex);
static bool NeedsToBeRemoved(const QModelIndex& modelIndex);
+ static bool HasRequirement(const QModelIndex& modelIndex);
+
+ bool DoGemsToBeAddedHaveRequirements() const;
QVector GatherGemsToBeAdded() const;
QVector GatherGemsToBeRemoved() const;
@@ -84,7 +88,8 @@ namespace O3DE::ProjectManager
RoleBinarySize,
RoleFeatures,
RoleTypes,
- RolePath
+ RolePath,
+ RoleRequirement
};
QHash m_nameToIndexMap;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp
new file mode 100644
index 0000000000..07024a799b
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp
@@ -0,0 +1,93 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementDelegate::GemRequirementDelegate(QAbstractItemModel* model, QObject* parent)
+ : GemItemDelegate(model, parent)
+ {
+ }
+
+ void GemRequirementDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
+ {
+ if (!modelIndex.isValid())
+ {
+ return;
+ }
+
+ QStyleOptionViewItem options(option);
+ initStyleOption(&options, modelIndex);
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ QRect fullRect, itemRect, contentRect;
+ CalcRects(options, fullRect, itemRect, contentRect);
+
+ QFont standardFont(options.font);
+ standardFont.setPixelSize(s_fontSize);
+ QFontMetrics standardFontMetrics(standardFont);
+
+ painter->save();
+ painter->setClipping(true);
+ painter->setClipRect(fullRect);
+ painter->setFont(options.font);
+
+ // Draw background
+ painter->fillRect(fullRect, m_backgroundColor);
+
+ // Draw item background
+ const QColor itemBackgroundColor = m_itemBackgroundColor;
+ painter->fillRect(itemRect, itemBackgroundColor);
+
+ // Gem name
+ QString gemName = GemModel::GetName(modelIndex);
+ QFont gemNameFont(options.font);
+ const int firstColumnMaxTextWidth = s_summaryStartX - 30;
+ gemName = QFontMetrics(gemNameFont).elidedText(gemName, Qt::TextElideMode::ElideRight, firstColumnMaxTextWidth);
+ gemNameFont.setPixelSize(s_gemNameFontSize);
+ gemNameFont.setBold(true);
+ QRect gemNameRect = GetTextRect(gemNameFont, gemName, s_gemNameFontSize);
+ gemNameRect.moveTo(contentRect.left(), contentRect.center().y() - s_gemNameFontSize);
+
+ painter->setFont(gemNameFont);
+ painter->setPen(m_textColor);
+ 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 QString requirement = GemModel::GetRequirement(modelIndex);
+ painter->drawText(requirementRect, Qt::AlignLeft | Qt::TextWordWrap, requirement);
+
+ painter->restore();
+ }
+
+ 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;
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h
new file mode 100644
index 0000000000..b221dcb8fe
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h
@@ -0,0 +1,37 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+
+namespace O3DE::ProjectManager
+{
+ class GemRequirementDelegate
+ : public GemItemDelegate
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRequirementDelegate(QAbstractItemModel* model, QObject* parent = nullptr);
+ ~GemRequirementDelegate() = default;
+
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
+ bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
+
+ const QColor m_backgroundColor = QColor("#444444"); // Outside of the actual gem item
+ const QColor m_itemBackgroundColor = QColor("#393939"); // Background color of the gem item
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp
new file mode 100644
index 0000000000..ad0e64b1ca
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp
@@ -0,0 +1,92 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementDialog::GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, QWidget* parent)
+ : QDialog(parent)
+ {
+ setWindowTitle(tr("Manual setup is required"));
+ setModal(true);
+
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setMargin(0);
+ vLayout->setContentsMargins(25, 10, 25, 10);
+ vLayout->setSizeConstraint(QLayout::SetFixedSize);
+ setLayout(vLayout);
+
+ QHBoxLayout* instructionLayout = new QHBoxLayout();
+ instructionLayout->setMargin(0);
+
+ QLabel* instructionIconLabel = new QLabel();
+ instructionIconLabel->setPixmap(QIcon(":/Warning.svg").pixmap(32, 32));
+ instructionLayout->addWidget(instructionIconLabel);
+
+ instructionLayout->addSpacing(10);
+
+ QLabel* instructionLabel = new QLabel(tr("The following Gem(s) require manual setup before the project can be built successfully."));
+ instructionLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ instructionLayout->addWidget(instructionLabel);
+
+ QSpacerItem* instructionSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ instructionLayout->addSpacerItem(instructionSpacer);
+
+ vLayout->addLayout(instructionLayout);
+
+ vLayout->addSpacing(20);
+
+ GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, gemsToAdd, this);
+
+ GemRequirementListView* m_gemListView = new GemRequirementListView(proxModel, proxModel->GetSelectionModel(), this);
+ vLayout->addWidget(m_gemListView);
+
+ QDialogButtonBox* dialogButtons = new QDialogButtonBox();
+ dialogButtons->setObjectName("footer");
+ vLayout->addWidget(dialogButtons);
+
+ QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
+ cancelButton->setProperty("secondary", true);
+ QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::ApplyRole);
+
+ connect(cancelButton, &QPushButton::clicked, this, &GemRequirementDialog::CancelButtonPressed);
+ connect(continueButton, &QPushButton::clicked, this, &GemRequirementDialog::ContinueButtonPressed);
+ }
+
+ 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
new file mode 100644
index 0000000000..4295c5d586
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h
@@ -0,0 +1,41 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(GemModel)
+
+ class GemRequirementDialog
+ : public QDialog
+ {
+ Q_OBJECT // AUTOMOC
+ public:
+ explicit GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, 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
new file mode 100644
index 0000000000..120ec63313
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp
@@ -0,0 +1,51 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, QObject* parent)
+ : QSortFilterProxyModel(parent)
+ , m_sourceModel(sourceModel)
+ , m_addedGems(addedGems)
+ {
+ setSourceModel(sourceModel);
+ m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent);
+ }
+
+ bool GemRequirementFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
+ {
+ // 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;
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h
new file mode 100644
index 0000000000..a891d63d0c
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h
@@ -0,0 +1,44 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(GemModel)
+
+ class GemRequirementFilterProxyModel
+ : public QSortFilterProxyModel
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, 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
new file mode 100644
index 0000000000..a86ae876c2
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp
@@ -0,0 +1,30 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRequirementListView::GemRequirementListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
+ : QListView(parent)
+ {
+ setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+
+ setStyleSheet("background-color: #444444;");
+
+ setModel(model);
+ setSelectionModel(selectionModel);
+ setItemDelegate(new GemRequirementDelegate(model, this));
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/StaticMeshMotionVector.azsl b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.h
similarity index 52%
rename from Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/StaticMeshMotionVector.azsl
rename to Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.h
index 11bc528f3b..25b2837e30 100644
--- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/StaticMeshMotionVector.azsl
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.h
@@ -10,23 +10,23 @@
*
*/
-#include "./MeshMotionVectorCommon.azsli"
+#pragma once
-struct VSInput
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#include
+#endif
+
+namespace O3DE::ProjectManager
{
- float3 m_position : POSITION;
-};
-
-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));
- OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_position, 1.0)).xyz;
-
- return OUT;
-}
-
-
+ class GemRequirementListView
+ : public QListView
+ {
+ Q_OBJECT // AUTOMOC
+ public:
+ explicit GemRequirementListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr);
+ ~GemRequirementListView() = default;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp
index 5faa6cb8bd..efe34f6fa6 100644
--- a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp
@@ -12,8 +12,8 @@
#include
#include
-#include
#include
+#include
#include
#include
#include
diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp
index 8cdab93c6a..62f879963f 100644
--- a/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp
@@ -11,6 +11,7 @@
*/
#include
+#include
#include
#include
@@ -30,8 +31,6 @@ namespace O3DE::ProjectManager
{
// 10 Minutes
constexpr int MaxBuildTimeMSecs = 600000;
- static const QString BuildPathPostfix = "windows_vs2019";
- static const QString ErrorLogPathPostfix = "CMakeFiles/CMakeProjectBuildError.log";
ProjectBuilderWorker::ProjectBuilderWorker(const ProjectInfo& projectInfo)
: QObject()
@@ -83,7 +82,7 @@ namespace O3DE::ProjectManager
QStringList
{
"-B",
- QDir(m_projectInfo.m_path).filePath(BuildPathPostfix),
+ QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
"-S",
m_projectInfo.m_path,
"-G",
@@ -123,7 +122,7 @@ namespace O3DE::ProjectManager
QStringList
{
"--build",
- QDir(m_projectInfo.m_path).filePath(BuildPathPostfix),
+ QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
"--target",
m_projectInfo.m_projectName + ".GameLauncher",
"Editor",
@@ -159,8 +158,8 @@ namespace O3DE::ProjectManager
QString ProjectBuilderWorker::LogFilePath() const
{
QDir logFilePath(m_projectInfo.m_path);
- logFilePath.cd(BuildPathPostfix);
- return logFilePath.filePath(ErrorLogPathPostfix);
+ logFilePath.cd(ProjectBuildPathPostfix);
+ return logFilePath.filePath(ProjectBuildErrorLogPathPostfix);
}
void ProjectBuilderWorker::WriteErrorLog(const QString& log)
diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
index 3bde0a310d..aaf87fd9cf 100644
--- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
@@ -11,6 +11,7 @@
*/
#include
+#include
#include
#include
@@ -22,12 +23,11 @@
#include
#include
#include
+#include
+#include
namespace O3DE::ProjectManager
{
- inline constexpr static int s_projectImageWidth = 210;
- inline constexpr static int s_projectImageHeight = 280;
-
LabelButton::LabelButton(QWidget* parent)
: QLabel(parent)
{
@@ -92,11 +92,6 @@ namespace O3DE::ProjectManager
: QFrame(parent)
, m_projectInfo(projectInfo)
{
- if (m_projectInfo.m_imagePath.isEmpty())
- {
- m_projectInfo.m_imagePath = ":/DefaultProjectImage.png";
- }
-
BaseSetup();
if (processing)
{
@@ -118,20 +113,25 @@ namespace O3DE::ProjectManager
setLayout(vLayout);
m_projectImageLabel = new LabelButton(this);
- m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight);
+ m_projectImageLabel->setFixedSize(ProjectPreviewImageWidth, ProjectPreviewImageHeight);
m_projectImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); });
vLayout->addWidget(m_projectImageLabel);
- m_projectImageLabel->setPixmap(
- QPixmap(m_projectInfo.m_imagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding));
+ QString projectPreviewPath = QDir(m_projectInfo.m_path).filePath(m_projectInfo.m_iconPath);
+ QFileInfo doesPreviewExist(projectPreviewPath);
+ if (!doesPreviewExist.exists() || !doesPreviewExist.isFile())
+ {
+ projectPreviewPath = ":/DefaultProjectImage.png";
+ }
+ m_projectImageLabel->setPixmap(QPixmap(projectPreviewPath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding));
m_projectFooter = new QFrame(this);
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->setContentsMargins(0, 0, 0, 0);
m_projectFooter->setLayout(hLayout);
{
- QLabel* projectNameLabel = new QLabel(m_projectInfo.m_displayName, this);
+ QLabel* projectNameLabel = new QLabel(m_projectInfo.GetProjectDisplayName(), this);
hLayout->addWidget(projectNameLabel);
}
diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp
index 99649cbfdf..e7d8a6d0e7 100644
--- a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp
@@ -10,33 +10,74 @@
*
*/
-#include "ProjectInfo.h"
+#include
+#include
+
+#include
namespace O3DE::ProjectManager
{
- ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
- const QString& origin, const QString& summary, const QString& imagePath, const QString& backgroundImagePath,
+ ProjectInfo::ProjectInfo(
+ const QString& path,
+ const QString& projectName,
+ const QString& displayName,
+ const QString& origin,
+ const QString& summary,
+ const QString& iconPath,
+ const QString& newPreviewImagePath,
+ const QString& newBackgroundImagePath,
bool needsBuild)
: m_path(path)
, m_projectName(projectName)
, m_displayName(displayName)
, m_origin(origin)
, m_summary(summary)
- , m_imagePath(imagePath)
- , m_backgroundImagePath(backgroundImagePath)
+ , m_iconPath(iconPath)
+ , m_newPreviewImagePath(newPreviewImagePath)
+ , m_newBackgroundImagePath(newBackgroundImagePath)
, m_needsBuild(needsBuild)
{
}
- bool ProjectInfo::operator==(const ProjectInfo& rhs)
+ bool ProjectInfo::operator==(const ProjectInfo& rhs) const
{
- return m_path == rhs.m_path
- && m_projectName == rhs.m_projectName
- && m_imagePath == rhs.m_imagePath
- && m_backgroundImagePath == rhs.m_backgroundImagePath;
+ if (m_path != rhs.m_path)
+ {
+ return false;
+ }
+ if (m_projectName != rhs.m_projectName)
+ {
+ return false;
+ }
+ if (m_displayName != rhs.m_displayName)
+ {
+ return false;
+ }
+ if (m_origin != rhs.m_origin)
+ {
+ return false;
+ }
+ if (m_summary != rhs.m_summary)
+ {
+ return false;
+ }
+ if (m_iconPath != rhs.m_iconPath)
+ {
+ return false;
+ }
+ if (m_newPreviewImagePath != rhs.m_newPreviewImagePath)
+ {
+ return false;
+ }
+ if (m_newBackgroundImagePath != rhs.m_newBackgroundImagePath)
+ {
+ return false;
+ }
+
+ return true;
}
- bool ProjectInfo::operator!=(const ProjectInfo& rhs)
+ bool ProjectInfo::operator!=(const ProjectInfo& rhs) const
{
return !operator==(rhs);
}
@@ -45,4 +86,16 @@ namespace O3DE::ProjectManager
{
return !m_path.isEmpty() && !m_projectName.isEmpty();
}
+
+ const QString& ProjectInfo::GetProjectDisplayName() const
+ {
+ if (!m_displayName.isEmpty())
+ {
+ return m_displayName;
+ }
+ else
+ {
+ return m_projectName;
+ }
+ }
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h
index 184916a514..72f64408f4 100644
--- a/Code/Tools/ProjectManager/Source/ProjectInfo.h
+++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h
@@ -31,14 +31,16 @@ namespace O3DE::ProjectManager
const QString& displayName,
const QString& origin,
const QString& summary,
- const QString& imagePath,
- const QString& backgroundImagePath,
+ const QString& iconPath,
+ const QString& newPreviewImagePath,
+ const QString& newBackgroundImagePath,
bool needsBuild);
- bool operator==(const ProjectInfo& rhs);
- bool operator!=(const ProjectInfo& rhs);
+ bool operator==(const ProjectInfo& rhs) const;
+ bool operator!=(const ProjectInfo& rhs) const;
bool IsValid() const;
+ const QString& GetProjectDisplayName() const;
// from o3de_manifest.json and o3de_projects.json
QString m_path;
@@ -48,14 +50,14 @@ namespace O3DE::ProjectManager
QString m_displayName;
QString m_origin;
QString m_summary;
+ QString m_iconPath;
QStringList m_userTags;
- // Used on projects home screen
- QString m_imagePath;
- QString m_backgroundImagePath;
+ // Used as temp variable for replace images
+ QString m_newPreviewImagePath;
+ QString m_newBackgroundImagePath;
// Used in project creation
-
bool m_needsBuild = false; //! Does this project need to be built
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h
new file mode 100644
index 0000000000..eafab28a60
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h
@@ -0,0 +1,24 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+#pragma once
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ inline constexpr static int ProjectPreviewImageWidth = 210;
+ inline constexpr static int ProjectPreviewImageHeight = 280;
+
+ static const QString ProjectBuildPathPostfix = "Windows_VS2019";
+ static const QString ProjectBuildErrorLogPathPostfix = "CMakeFiles/CMakeProjectBuildError.log";
+ static const QString ProjectPreviewImagePath = "preview.png";
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp
index b198724353..9dbbf26aa4 100644
--- a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp
@@ -11,7 +11,7 @@
*/
#include
-#include
+#include
#include
#include
#include
@@ -47,7 +47,7 @@ namespace O3DE::ProjectManager
connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::ValidateProjectName);
m_verticalLayout->addWidget(m_projectName);
- m_projectPath = new FormBrowseEditWidget(tr("Project Location"), "", this);
+ m_projectPath = new FormFolderBrowseEditWidget(tr("Project Location"), "", this);
m_projectPath->lineEdit()->setReadOnly(true);
connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::Validate);
m_verticalLayout->addWidget(m_projectPath);
diff --git a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h
index 0d75bbbc64..1b1f03051d 100644
--- a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h
+++ b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h
@@ -32,9 +32,9 @@ namespace O3DE::ProjectManager
~ProjectSettingsScreen() = default;
ProjectManagerScreen GetScreenEnum() override;
- ProjectInfo GetProjectInfo();
+ virtual ProjectInfo GetProjectInfo();
- bool Validate();
+ virtual bool Validate();
protected slots:
virtual bool ValidateProjectName();
diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp
index 3e2b3c13e1..91e7f0a719 100644
--- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp
@@ -29,11 +29,8 @@ namespace O3DE::ProjectManager
if (!QDir(path).isEmpty())
{
QMessageBox::StandardButton warningResult = QMessageBox::warning(
- parent,
- QObject::tr("Overwrite Directory"),
- QObject::tr("Directory is not empty! Are you sure you want to overwrite it?"),
- QMessageBox::No | QMessageBox::Yes
- );
+ parent, QObject::tr("Overwrite Directory"),
+ QObject::tr("Directory is not empty! Are you sure you want to overwrite it?"), QMessageBox::No | QMessageBox::Yes);
if (warningResult != QMessageBox::Yes)
{
@@ -53,14 +50,13 @@ namespace O3DE::ProjectManager
{
if (ancestor == descendent)
{
- return false;
+ return true;
}
descendent.cdUp();
- }
- while (!descendent.isRoot());
+ } while (!descendent.isRoot());
- return true;
+ return false;
}
static bool CopyDirectory(const QString& origPath, const QString& newPath)
@@ -138,7 +134,7 @@ namespace O3DE::ProjectManager
bool CopyProject(const QString& origPath, const QString& newPath)
{
// Disallow copying from or into subdirectory
- if (!IsDirectoryDescedent(origPath, newPath) || !IsDirectoryDescedent(newPath, origPath))
+ if (IsDirectoryDescedent(origPath, newPath) || IsDirectoryDescedent(newPath, origPath))
{
return false;
}
@@ -173,20 +169,66 @@ namespace O3DE::ProjectManager
return false;
}
- bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent)
+ bool MoveProject(QString origPath, QString newPath, QWidget* parent, bool ignoreRegister)
{
- if (!WarnDirectoryOverwrite(newPath, parent) || !UnregisterProject(origPath))
+ origPath = QDir::toNativeSeparators(origPath);
+ newPath = QDir::toNativeSeparators(newPath);
+
+ if (!WarnDirectoryOverwrite(newPath, parent) || (!ignoreRegister && !UnregisterProject(origPath)))
{
return false;
}
- QDir directory;
- if (directory.rename(origPath, newPath))
+ QDir newDirectory(newPath);
+ if (!newDirectory.removeRecursively())
{
- return directory.rename(origPath, newPath);
+ return false;
+ }
+ if (!newDirectory.rename(origPath, newPath))
+ {
+ // Likely failed because trying to move to another partition, try copying
+ if (!CopyProject(origPath, newPath))
+ {
+ return false;
+ }
+
+ DeleteProjectFiles(origPath, true);
}
- if (!RegisterProject(newPath))
+ if (!ignoreRegister && !RegisterProject(newPath))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool ReplaceFile(const QString& origFile, const QString& newFile, QWidget* parent, bool interactive)
+ {
+ QFileInfo original(origFile);
+ if (original.exists())
+ {
+ if (interactive)
+ {
+ QMessageBox::StandardButton warningResult = QMessageBox::warning(
+ parent,
+ QObject::tr("Overwrite File?"),
+ QObject::tr("Replacing this will overwrite the current file on disk. Are you sure?"),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (warningResult == QMessageBox::No)
+ {
+ return false;
+ }
+ }
+
+ if (!QFile::remove(origFile))
+ {
+ return false;
+ }
+ }
+
+ if (!QFile::copy(newFile, origFile))
{
return false;
}
diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h
index 9c711ad187..2fa1258e8f 100644
--- a/Code/Tools/ProjectManager/Source/ProjectUtils.h
+++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h
@@ -24,7 +24,9 @@ namespace O3DE::ProjectManager
bool CopyProjectDialog(const QString& origPath, QWidget* parent = nullptr);
bool CopyProject(const QString& origPath, const QString& newPath);
bool DeleteProjectFiles(const QString& path, bool force = false);
- bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent = nullptr);
+ bool MoveProject(QString origPath, QString newPath, QWidget* parent = nullptr, bool ignoreRegister = false);
+
+ bool ReplaceFile(const QString& origFile, const QString& newFile, QWidget* parent = nullptr, bool interactive = true);
bool IsVS2019Installed();
diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp
index 6633558406..d0534c1e76 100644
--- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp
@@ -12,6 +12,7 @@
#include
+#include
#include
#include
#include
@@ -35,7 +36,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -218,16 +218,7 @@ namespace O3DE::ProjectManager
ProjectButton* ProjectsScreen::CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing)
{
- ProjectButton* projectButton;
-
- QString projectPreviewPath = project.m_path + m_projectPreviewImagePath;
- QFileInfo doesPreviewExist(projectPreviewPath);
- if (doesPreviewExist.exists() && doesPreviewExist.isFile())
- {
- project.m_imagePath = projectPreviewPath;
- }
-
- projectButton = new ProjectButton(project, this, processing);
+ ProjectButton* projectButton = new ProjectButton(project, this, processing);
flowLayout->addWidget(projectButton);
@@ -438,7 +429,7 @@ namespace O3DE::ProjectManager
{
QMessageBox::information(this,
tr("Project Should be rebuilt."),
- projectInfo.m_projectName + tr(" project likely needs to be rebuilt."));
+ projectInfo.GetProjectDisplayName() + tr(" project likely needs to be rebuilt."));
}
}
@@ -499,8 +490,8 @@ namespace O3DE::ProjectManager
{
QMessageBox::StandardButton buildProject = QMessageBox::information(
this,
- tr("Building \"%1\"").arg(projectInfo.m_projectName),
- tr("Ready to build \"%1\"?").arg(projectInfo.m_projectName),
+ tr("Building \"%1\"").arg(projectInfo.GetProjectDisplayName()),
+ tr("Ready to build \"%1\"?").arg(projectInfo.GetProjectDisplayName()),
QMessageBox::No | QMessageBox::Yes);
if (buildProject == QMessageBox::Yes)
diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.h b/Code/Tools/ProjectManager/Source/ProjectsScreen.h
index bc28d4ef30..b86c2b0240 100644
--- a/Code/Tools/ProjectManager/Source/ProjectsScreen.h
+++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.h
@@ -80,8 +80,6 @@ namespace O3DE::ProjectManager
QQueue m_buildQueue;
ProjectBuilderController* m_currentBuilder = nullptr;
- const QString m_projectPreviewImagePath = "/preview.png";
-
inline constexpr static int s_contentMargins = 80;
inline constexpr static int s_spacerSize = 20;
};
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index 0e00319b6b..db376fb195 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -12,6 +12,7 @@
#include
+#include
// Qt defines slots, which interferes with the use here.
#pragma push_macro("slots")
@@ -660,6 +661,7 @@ namespace O3DE::ProjectManager
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
gemInfo.m_summary = Py_To_String_Optional(data, "Summary", "");
gemInfo.m_version = Py_To_String_Optional(data, "Version", "");
+ gemInfo.m_requirement = Py_To_String_Optional(data, "Requirements", "");
if (data.contains("Tags"))
{
@@ -693,6 +695,7 @@ namespace O3DE::ProjectManager
projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName);
projectInfo.m_origin = Py_To_String_Optional(projectData, "origin", projectInfo.m_origin);
projectInfo.m_summary = Py_To_String_Optional(projectData, "summary", projectInfo.m_summary);
+ projectInfo.m_iconPath = Py_To_String_Optional(projectData, "icon", ProjectPreviewImagePath);
if (projectData.contains("user_tags"))
{
for (auto tag : projectData["user_tags"])
@@ -786,7 +789,7 @@ namespace O3DE::ProjectManager
pybind11::str(projectInfo.m_origin.toStdString()), // new_origin
pybind11::str(projectInfo.m_displayName.toStdString()), // new_display
pybind11::str(projectInfo.m_summary.toStdString()), // new_summary
- pybind11::str(projectInfo.m_imagePath.toStdString()), // new_icon
+ pybind11::str(projectInfo.m_iconPath.toStdString()), // new_icon
pybind11::none(), // add_tags not used
pybind11::none(), // remove_tags not used
pybind11::list(pybind11::cast(newTags))); // replace_tags
diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
index 409c51315d..e51d9e4996 100644
--- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
@@ -11,6 +11,7 @@
*/
#include
+#include
#include
#include
#include
@@ -24,6 +25,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -101,8 +103,11 @@ namespace O3DE::ProjectManager
void UpdateProjectCtrl::HandleGemsButton()
{
- m_stack->setCurrentWidget(m_gemCatalogScreen);
- Update();
+ if (UpdateProjectSettings(true))
+ {
+ m_stack->setCurrentWidget(m_gemCatalogScreen);
+ Update();
+ }
}
void UpdateProjectCtrl::HandleBackButton()
@@ -114,7 +119,10 @@ namespace O3DE::ProjectManager
}
else
{
- emit GotoPreviousScreenRequest();
+ if (UpdateProjectSettings(true))
+ {
+ emit GotoPreviousScreenRequest();
+ }
}
}
@@ -124,44 +132,19 @@ namespace O3DE::ProjectManager
if (m_stack->currentIndex() == ScreenOrder::Settings && m_updateSettingsScreen)
{
- if (m_updateSettingsScreen)
+ if (!UpdateProjectSettings())
{
- if (!m_updateSettingsScreen->Validate())
- {
- QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings"));
- return;
- }
-
- ProjectInfo newProjectSettings = m_updateSettingsScreen->GetProjectInfo();
-
- // Update project if settings changed
- if (m_projectInfo != newProjectSettings)
- {
- auto result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings);
- if (!result.IsSuccess())
- {
- QMessageBox::critical(this, tr("Project update failed"), tr(result.GetError().c_str()));
- return;
- }
- }
-
- // Check if project path has changed and move it
- if (newProjectSettings.m_path != m_projectInfo.m_path)
- {
- if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path))
- {
- QMessageBox::critical(this, tr("Project move failed"), tr("Failed to move project."));
- return;
- }
- }
-
- m_projectInfo = newProjectSettings;
+ return;
}
}
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.
- m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
+ if (!m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path))
+ {
+ QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for project."));
+ return;
+ }
shouldRebuild = true;
}
@@ -190,14 +173,15 @@ namespace O3DE::ProjectManager
{
if (m_stack->currentIndex() == ScreenOrder::Gems)
{
- m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName));
+
+ m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName()));
m_header->setSubTitle(QString(tr("Configure Gems")));
- m_nextButton->setText(tr("Finalize"));
+ m_nextButton->setText(tr("Save"));
}
else
{
m_header->setTitle("");
- m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName));
+ m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName()));
m_nextButton->setText(tr("Save"));
}
}
@@ -207,4 +191,70 @@ namespace O3DE::ProjectManager
m_updateSettingsScreen->SetProjectInfo(m_projectInfo);
}
+ bool UpdateProjectCtrl::UpdateProjectSettings(bool shouldConfirm)
+ {
+ AZ_Assert(m_updateSettingsScreen, "Update settings screen is nullptr.")
+
+ ProjectInfo newProjectSettings = m_updateSettingsScreen->GetProjectInfo();
+
+ if (m_projectInfo != newProjectSettings)
+ {
+ if (shouldConfirm)
+ {
+ QMessageBox::StandardButton warningResult = QMessageBox::warning(
+ this,
+ QObject::tr("Unsaved Changes!"),
+ QObject::tr("Would you like to save your changes to project settings?"),
+ QMessageBox::No | QMessageBox::Yes
+ );
+
+ if (warningResult == QMessageBox::No)
+ {
+ return true;
+ }
+ }
+
+ if (!m_updateSettingsScreen->Validate())
+ {
+ QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings"));
+ return false;
+ }
+
+ // Update project if settings changed
+ {
+ auto result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings);
+ if (!result.IsSuccess())
+ {
+ QMessageBox::critical(this, tr("Project update failed"), tr(result.GetError().c_str()));
+ return false;
+ }
+ }
+
+ // Check if project path has changed and move it
+ if (newProjectSettings.m_path != m_projectInfo.m_path)
+ {
+ if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path))
+ {
+ QMessageBox::critical(this, tr("Project move failed"), tr("Failed to move project."));
+ return false;
+ }
+ }
+
+ if (!newProjectSettings.m_newPreviewImagePath.isEmpty())
+ {
+ if (!ProjectUtils::ReplaceFile(
+ QDir(newProjectSettings.m_path).filePath(newProjectSettings.m_iconPath), newProjectSettings.m_newPreviewImagePath))
+ {
+ QMessageBox::critical(this, tr("File replace failed"), tr("Failed to replace project preview image."));
+ return false;
+ }
+ m_updateSettingsScreen->ResetProjectPreviewPath();
+ }
+
+ m_projectInfo = newProjectSettings;
+ }
+
+ return true;
+ }
+
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h
index 231bfb8f19..b8b57c0c20 100644
--- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h
+++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h
@@ -46,6 +46,7 @@ namespace O3DE::ProjectManager
private:
void Update();
void UpdateSettingsScreen();
+ bool UpdateProjectSettings(bool shouldConfirm = false);
enum ScreenOrder
{
diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp
index c29be3c7fd..f7be7e84c3 100644
--- a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp
@@ -11,17 +11,43 @@
*/
#include
-#include
+#include
+#include
#include
+#include
#include
#include
+#include
+#include
namespace O3DE::ProjectManager
{
UpdateProjectSettingsScreen::UpdateProjectSettingsScreen(QWidget* parent)
: ProjectSettingsScreen(parent)
+ , m_userChangedPreview(false)
{
+ m_projectPreview = new FormImageBrowseEditWidget(tr("Project Preview"), "", this);
+ m_projectPreview->lineEdit()->setReadOnly(true);
+ connect(m_projectPreview->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::Validate);
+ connect(m_projectPreview->lineEdit(), &QLineEdit::textChanged, this, &UpdateProjectSettingsScreen::PreviewPathChanged);
+ connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &UpdateProjectSettingsScreen::UpdateProjectPreviewPath);
+ m_verticalLayout->addWidget(m_projectPreview);
+
+ QVBoxLayout* previewExtrasLayout = new QVBoxLayout(this);
+ previewExtrasLayout->setAlignment(Qt::AlignLeft);
+ previewExtrasLayout->setContentsMargins(50, 0, 0, 0);
+
+ QLabel* projectPreviewLabel = new QLabel(tr("Select an image (PNG). Minimum %1 x %2 pixels.")
+ .arg(QString::number(ProjectPreviewImageWidth), QString::number(ProjectPreviewImageHeight)));
+ previewExtrasLayout->addWidget(projectPreviewLabel);
+
+ m_projectPreviewImage = new QLabel(this);
+ m_projectPreviewImage->setFixedSize(ProjectPreviewImageWidth, ProjectPreviewImageHeight);
+ m_projectPreviewImage->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ previewExtrasLayout->addWidget(m_projectPreviewImage);
+
+ m_verticalLayout->addLayout(previewExtrasLayout);
}
ProjectManagerScreen UpdateProjectSettingsScreen::GetScreenEnum()
@@ -29,10 +55,58 @@ namespace O3DE::ProjectManager
return ProjectManagerScreen::UpdateProjectSettings;
}
+ ProjectInfo UpdateProjectSettingsScreen::GetProjectInfo()
+ {
+ m_projectInfo.m_displayName = m_projectName->lineEdit()->text();
+ m_projectInfo.m_path = m_projectPath->lineEdit()->text();
+
+ if (m_userChangedPreview)
+ {
+ m_projectInfo.m_iconPath = ProjectPreviewImagePath;
+ m_projectInfo.m_newPreviewImagePath = m_projectPreview->lineEdit()->text();
+ }
+ return m_projectInfo;
+ }
+
void UpdateProjectSettingsScreen::SetProjectInfo(const ProjectInfo& projectInfo)
{
- m_projectName->lineEdit()->setText(projectInfo.m_projectName);
+ m_projectInfo = projectInfo;
+
+ m_projectName->lineEdit()->setText(projectInfo.GetProjectDisplayName());
+
m_projectPath->lineEdit()->setText(projectInfo.m_path);
+ UpdateProjectPreviewPath();
+ }
+
+ void UpdateProjectSettingsScreen::UpdateProjectPreviewPath()
+ {
+ if (!m_userChangedPreview)
+ {
+ m_projectPreview->lineEdit()->setText(QDir(m_projectPath->lineEdit()->text()).filePath(m_projectInfo.m_iconPath));
+ // Setting the text sets m_userChangedPreview to true
+ // Set it back to false because it should only be true when changed by user
+ m_userChangedPreview = false;
+ }
+ }
+
+ bool UpdateProjectSettingsScreen::Validate()
+ {
+ return ProjectSettingsScreen::Validate() && ValidateProjectPreview();
+ }
+
+ void UpdateProjectSettingsScreen::ResetProjectPreviewPath()
+ {
+ m_userChangedPreview = false;
+ UpdateProjectPreviewPath();
+ }
+
+ void UpdateProjectSettingsScreen::PreviewPathChanged()
+ {
+ m_userChangedPreview = true;
+
+ // Update with latest image
+ m_projectPreviewImage->setPixmap(
+ QPixmap(m_projectPreview->lineEdit()->text()).scaled(m_projectPreviewImage->size(), Qt::KeepAspectRatioByExpanding));
}
bool UpdateProjectSettingsScreen::ValidateProjectPath()
@@ -48,4 +122,39 @@ namespace O3DE::ProjectManager
return projectPathIsValid;
}
+ bool UpdateProjectSettingsScreen::ValidateProjectPreview()
+ {
+ bool projectPreviewIsValid = true;
+
+ if (m_projectPreview->lineEdit()->text().isEmpty())
+ {
+ projectPreviewIsValid = false;
+ m_projectPreview->setErrorLabelText(tr("Please select a file."));
+ }
+ else
+ {
+ if (m_userChangedPreview)
+ {
+ QFileInfo previewFile(m_projectPreview->lineEdit()->text());
+ if (!previewFile.exists() || !previewFile.isFile())
+ {
+ projectPreviewIsValid = false;
+ m_projectPreview->setErrorLabelText(tr("Please select a valid png file."));
+ }
+ else
+ {
+ QString fileType = previewFile.completeSuffix().toLower();
+ if (fileType != "png")
+ {
+ projectPreviewIsValid = false;
+ m_projectPreview->setErrorLabelText(tr("Please select a png image."));
+ }
+ }
+ }
+ }
+
+ m_projectPreview->setErrorLabelVisible(!projectPreviewIsValid);
+ return projectPreviewIsValid;
+ }
+
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h
index 95bbceb9c6..1961648b5b 100644
--- a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h
+++ b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h
@@ -15,6 +15,8 @@
#include
#endif
+QT_FORWARD_DECLARE_CLASS(QLabel)
+
namespace O3DE::ProjectManager
{
class UpdateProjectSettingsScreen
@@ -25,10 +27,26 @@ namespace O3DE::ProjectManager
~UpdateProjectSettingsScreen() = default;
ProjectManagerScreen GetScreenEnum() override;
+ ProjectInfo GetProjectInfo() override;
void SetProjectInfo(const ProjectInfo& projectInfo);
+ bool Validate() override;
+
+ void ResetProjectPreviewPath();
+
+ public slots:
+ void UpdateProjectPreviewPath();
+ void PreviewPathChanged();
+
protected:
bool ValidateProjectPath() override;
+ virtual bool ValidateProjectPreview();
+
+ FormBrowseEditWidget* m_projectPreview;
+ QLabel* m_projectPreviewImage;
+
+ ProjectInfo m_projectInfo;
+ bool m_userChangedPreview; //! Did the user change the project preview path
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake
index 587b5907bb..7eaeed0b96 100644
--- a/Code/Tools/ProjectManager/project_manager_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_files.cmake
@@ -13,6 +13,7 @@
set(FILES
Source/Application.h
Source/Application.cpp
+ Source/ProjectManagerDefs.h
Source/ScreenDefs.h
Source/ScreenFactory.h
Source/ScreenFactory.cpp
@@ -25,6 +26,10 @@ set(FILES
Source/FormLineEditWidget.cpp
Source/FormBrowseEditWidget.h
Source/FormBrowseEditWidget.cpp
+ Source/FormFolderBrowseEditWidget.h
+ Source/FormFolderBrowseEditWidget.cpp
+ Source/FormImageBrowseEditWidget.h
+ Source/FormImageBrowseEditWidget.cpp
Source/PathValidator.h
Source/PathValidator.cpp
Source/ProjectManagerWindow.h
@@ -82,6 +87,14 @@ set(FILES
Source/GemCatalog/GemListHeaderWidget.cpp
Source/GemCatalog/GemModel.h
Source/GemCatalog/GemModel.cpp
+ Source/GemCatalog/GemRequirementDialog.h
+ Source/GemCatalog/GemRequirementDialog.cpp
+ Source/GemCatalog/GemRequirementDelegate.h
+ Source/GemCatalog/GemRequirementDelegate.cpp
+ Source/GemCatalog/GemRequirementFilterProxyModel.h
+ Source/GemCatalog/GemRequirementFilterProxyModel.cpp
+ Source/GemCatalog/GemRequirementListView.h
+ Source/GemCatalog/GemRequirementListView.cpp
Source/GemCatalog/GemSortFilterProxyModel.h
Source/GemCatalog/GemSortFilterProxyModel.cpp
)
diff --git a/Code/Tools/ProjectManager/project_manager_tests_files.cmake b/Code/Tools/ProjectManager/project_manager_tests_files.cmake
index e1e84a43a7..e340469bcc 100644
--- a/Code/Tools/ProjectManager/project_manager_tests_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_tests_files.cmake
@@ -14,4 +14,5 @@ set(FILES
Resources/ProjectManager.qss
tests/ApplicationTests.cpp
tests/main.cpp
+ tests/UtilsTests.cpp
)
diff --git a/Code/Tools/ProjectManager/tests/UtilsTests.cpp b/Code/Tools/ProjectManager/tests/UtilsTests.cpp
new file mode 100644
index 0000000000..e248d37bee
--- /dev/null
+++ b/Code/Tools/ProjectManager/tests/UtilsTests.cpp
@@ -0,0 +1,120 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ namespace ProjectUtils
+ {
+ class ProjectManagerUtilsTests
+ : public ::UnitTest::ScopedAllocatorSetupFixture
+ {
+ public:
+ ProjectManagerUtilsTests()
+ {
+ m_application = AZStd::make_unique();
+ m_application->Init(false);
+
+ QDir dir;
+ dir.mkdir("ProjectA");
+ dir.mkdir("ProjectB");
+
+ QFile origFile("ProjectA/origFile.txt");
+ if (origFile.open(QIODevice::ReadWrite))
+ {
+ QTextStream stream(&origFile);
+ stream << "orig" << Qt::endl;
+ origFile.close();
+ }
+
+ QFile replaceFile("ProjectA/replaceFile.txt");
+ if (replaceFile.open(QIODevice::ReadWrite))
+ {
+ QTextStream stream(&replaceFile);
+ stream << "replace" << Qt::endl;
+ replaceFile.close();
+ }
+ }
+
+ ~ProjectManagerUtilsTests()
+ {
+ QDir dirA("ProjectA");
+ dirA.removeRecursively();
+
+ QDir dirB("ProjectB");
+ dirB.removeRecursively();
+
+ m_application.reset();
+ }
+
+ AZStd::unique_ptr m_application;
+ };
+
+#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
+ TEST_F(ProjectManagerUtilsTests, DISABLED_MoveProject_Succeeds)
+#else
+ TEST_F(ProjectManagerUtilsTests, MoveProject_Succeeds)
+#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
+ {
+ EXPECT_TRUE(MoveProject(
+ QDir::currentPath() + QDir::separator() + "ProjectA",
+ QDir::currentPath() + QDir::separator() + "ProjectB",
+ nullptr, true));
+
+ QFileInfo origFile("ProjectA/origFile.txt");
+ EXPECT_TRUE(!origFile.exists());
+
+ QFileInfo replaceFile("ProjectA/replaceFile.txt");
+ EXPECT_TRUE(!replaceFile.exists());
+
+ QFileInfo origFileMoved("ProjectB/origFile.txt");
+ EXPECT_TRUE(origFileMoved.exists() && origFileMoved.isFile());
+
+ QFileInfo replaceFileMoved("ProjectB/replaceFile.txt");
+ EXPECT_TRUE(replaceFileMoved.exists() && replaceFileMoved.isFile());
+ }
+
+#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
+ TEST_F(ProjectManagerUtilsTests, DISABLED_ReplaceFile_Succeeds)
+#else
+ TEST_F(ProjectManagerUtilsTests, ReplaceFile_Succeeds)
+#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
+ {
+ EXPECT_TRUE(ReplaceFile("ProjectA/origFile.txt", "ProjectA/replaceFile.txt", nullptr, false));
+
+ QFile origFile("ProjectA/origFile.txt");
+ if (origFile.open(QIODevice::ReadOnly))
+ {
+ QTextStream stream(&origFile);
+ QString line = stream.readLine();
+ EXPECT_EQ(line, "replace");
+
+ origFile.close();
+ }
+ else
+ {
+ FAIL();
+ }
+ }
+ } // namespace ProjectUtils
+} // namespace O3DE::ProjectManager
diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp
index 74865c0044..20f5bf68cc 100644
--- a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp
+++ b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp
@@ -146,12 +146,12 @@ namespace AWSClientAuth
void AWSCognitoAuthenticationProvider::DeviceCodeGrantSignInAsync()
{
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
void AWSCognitoAuthenticationProvider::DeviceCodeGrantConfirmSignInAsync()
{
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
void AWSCognitoAuthenticationProvider::RefreshTokensAsync()
diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp
index d4d2d0d67b..fe8c526a11 100644
--- a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp
+++ b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp
@@ -53,7 +53,7 @@ namespace AWSClientAuth
if (!m_settingsRegistry->MergeSettingsFile(resolvedPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch))
{
- AZ_Error("AuthenticationProviderManager", true, "Error merging settings registry for path: %s", resolvedPath.data());
+ AZ_Error("AuthenticationProviderManager", false, "Error merging settings registry for path: %s", resolvedPath.data());
return false;
}
@@ -199,7 +199,7 @@ namespace AWSClientAuth
{
return enumValue.value();
}
- AZ_Warning("AuthenticationProviderManager", true, "Incorrect string value for enum: %s", name.c_str());
+ AZ_Warning("AuthenticationProviderManager", false, "Incorrect string value for enum: %s", name.c_str());
return ProviderNameEnum::None;
}
diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp
index 7762b3919b..efabaf5fc1 100644
--- a/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp
+++ b/Gems/AWSClientAuth/Code/Source/Authentication/GoogleAuthenticationProvider.cpp
@@ -39,7 +39,7 @@ namespace AWSClientAuth
{
if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), GoogleSettingsPath))
{
- AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get Google settings object for path %s", GoogleSettingsPath);
+ AZ_Warning("AWSCognitoAuthenticationProvider", false, "Failed to get Google settings object for path %s", GoogleSettingsPath);
return false;
}
return true;
@@ -49,21 +49,21 @@ namespace AWSClientAuth
{
AZ_UNUSED(username);
AZ_UNUSED(password);
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
void GoogleAuthenticationProvider::PasswordGrantMultiFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
AZ_UNUSED(username);
AZ_UNUSED(password);
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
void GoogleAuthenticationProvider::PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& username, const AZStd::string& confirmationCode)
{
AZ_UNUSED(username);
AZ_UNUSED(confirmationCode);
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
// Call Google authentication provider device code end point.
diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp
index a86e01a58e..f43611f2c0 100644
--- a/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp
+++ b/Gems/AWSClientAuth/Code/Source/Authentication/LWAAuthenticationProvider.cpp
@@ -38,7 +38,7 @@ namespace AWSClientAuth
{
if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), LwaSettingsPath))
{
- AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get login with Amazon settings object for path %s", LwaSettingsPath);
+ AZ_Warning("AWSCognitoAuthenticationProvider", false, "Failed to get login with Amazon settings object for path %s", LwaSettingsPath);
return false;
}
return true;
@@ -48,21 +48,21 @@ namespace AWSClientAuth
{
AZ_UNUSED(username);
AZ_UNUSED(password);
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
void LWAAuthenticationProvider::PasswordGrantMultiFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
AZ_UNUSED(username);
AZ_UNUSED(password);
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
void LWAAuthenticationProvider::PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& username, const AZStd::string& confirmationCode)
{
AZ_UNUSED(username);
AZ_UNUSED(confirmationCode);
- AZ_Assert(true, "Not supported");
+ AZ_Assert(false, "Not supported");
}
// Call LWA authentication provider device code end point.
diff --git a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp
index 5e2c07bdbb..1cae2bd0b1 100644
--- a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp
+++ b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp
@@ -149,7 +149,7 @@ namespace AWSClientAuth
}
else
{
- AZ_Warning("AWSCognitoAuthorizationController", true, "No logins found. Fetching anonymous/unauthenticated credentials");
+ AZ_Warning("AWSCognitoAuthorizationController", false, "No logins found. Fetching anonymous/unauthenticated credentials");
}
AZ::JobContext* jobContext = nullptr;
@@ -277,7 +277,7 @@ namespace AWSClientAuth
// Check anonymous credentials as they are optional settings in Cognito Identity pool.
if (!m_cognitoCachingAnonymousCredentialsProvider->GetAWSCredentials().IsEmpty())
{
- AZ_Warning("AWSCognitoAuthorizationCredentialHandler", true, "No logins found. Using Anonymous credential provider");
+ AZ_Warning("AWSCognitoAuthorizationCredentialHandler", false, "No logins found. Using Anonymous credential provider");
return m_cognitoCachingAnonymousCredentialsProvider;
}
diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp
index 7673840299..6aef72af7e 100644
--- a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp
+++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp
@@ -257,5 +257,5 @@ TEST_F(AuthenticationProviderManagerScriptCanvasTest, Initialize_Fail_InvalidPat
{
AZ_TEST_START_TRACE_SUPPRESSION;
ASSERT_FALSE(m_mockController->Initialize(m_enabledProviderNames, ""));
- AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+ AZ_TEST_STOP_TRACE_SUPPRESSION(2);
}
diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp
index 4b5bdfb841..ce91e29a1a 100644
--- a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp
+++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp
@@ -256,5 +256,5 @@ TEST_F(AuthenticationProviderManagerTest, Initialize_Fail_InvalidPath)
{
AZ_TEST_START_TRACE_SUPPRESSION;
ASSERT_FALSE(m_mockController->Initialize(m_enabledProviderNames, ""));
- AZ_TEST_STOP_TRACE_SUPPRESSION(1);
+ AZ_TEST_STOP_TRACE_SUPPRESSION(2);
}
diff --git a/Gems/AWSClientAuth/cdk/README.md b/Gems/AWSClientAuth/cdk/README.md
index 4fe668cb9d..3bc2b59fc1 100644
--- a/Gems/AWSClientAuth/cdk/README.md
+++ b/Gems/AWSClientAuth/cdk/README.md
@@ -51,6 +51,13 @@ To add additional dependencies, for example other CDK libraries, just add
them to your requirements.txt file and rerun the `..\..\..\Lumberyard\python\pip.cmd install -r .\Gems\AWSClientAuth\cdk\requirements.txt`
command.
+
+## Update Authorization Permissions
+To give permissions to call AWS resources, please update CognitoIdentityPoolRole class with correct policy statements.
+
+An example IAM permission policy is provided to grant both authenticated and unauthenticated the permission to list S3 buckets in the project.
+However, it is expected that developers replace these permissions with those required by your users to use your resources.
+
## Useful commands
* `cdk ls` list all stacks in the app
diff --git a/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py b/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py
index 3a2e413617..52df897db9 100755
--- a/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py
+++ b/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py
@@ -53,14 +53,17 @@ class CognitoIdentityPoolRole:
}
}, assume_role_action='sts:AssumeRoleWithWebIdentity'))
- # basic permissions
+ # The above role is created for developers to add custom permissions that they need to provide authorized
+ # clients. Developers should update the policy statements below to add their required permissions.
+ # As an example s3:ListBuckets permissions are provided.
+ # Note: There must be at least one policy statement here.
stack_statement = iam.PolicyStatement(
actions=[
's3:ListBuckets'
],
effect=iam.Effect.ALLOW,
resources=[
- '*'
+ f'arn:aws:s3:::{project_name}/*'
],
sid=name_utils.format_aws_resource_sid(feature_name, project_name, iam.PolicyStatement.__name__)
)
diff --git a/Gems/AWSClientAuth/cdk/auth/cognito_user_pool_sms_role.py b/Gems/AWSClientAuth/cdk/auth/cognito_user_pool_sms_role.py
index 286b439a76..c4a442f481 100755
--- a/Gems/AWSClientAuth/cdk/auth/cognito_user_pool_sms_role.py
+++ b/Gems/AWSClientAuth/cdk/auth/cognito_user_pool_sms_role.py
@@ -32,12 +32,18 @@ class CognitoUserPoolSMSRole:
name_utils.format_aws_resource_id(feature_name, project_name, env, iam.Role.__name__),
description='Role permissions used by Cognito user pool to send sms',
assumed_by=iam.ServicePrincipal("cognito-idp.amazonaws.com"),
+ # Deny all others and then allow only for the current sms role.
inline_policies={
'SNSRoleInlinePolicy':
iam.PolicyDocument(
statements=[
+ # SMS role will be used by CognitoIDP tp allow to publish to SNS topic owned by CognitoIDP
+ # team to push a sms.
+ # Need to use * as the resource name used by CognitoIDP principal service is unknown.
iam.PolicyStatement(
- actions=["sns:Publish"], resources=["*"]
+ effect=iam.Effect.ALLOW,
+ actions=['sns:Publish'],
+ resources=['*']
)
]
)
diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp
index 7114b50906..7697b7820b 100644
--- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp
+++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp
@@ -72,22 +72,43 @@ namespace AZ
static constexpr uint32_t ShaderVariantJobVariantParam = 3;
static constexpr uint32_t ShouldExitEarlyFromProcessJobParam = 4;
- static void AddShaderAssetJobDependency(
- AssetBuilderSDK::JobDescriptor& jobDescriptor,
- const AssetBuilderSDK::PlatformInfo& platformInfo,
- const AZStd::string& shaderVariantListFilePath,
- const AZStd::string& shaderFilePath)
+ //! Adds source file dependencies for every place a referenced file may appear, and detects if one of
+ //! those possible paths resolves to the expected file.
+ //! @param currentFilePath - the full path to the file being processed
+ //! @param referencedParentPath - the path to a reference file, which may be relative to the @currentFilePath, or may be a full asset path.
+ //! @param sourceFileDependencies - new source file dependencies will be added to this list
+ //! @param foundSourceFile - if one of the source file dependencies is found, the highest priority one will be indicated here, otherwise this will be empty.
+ //! @return true if the referenced file was found and @foundSourceFile was set
+ bool LocateReferencedSourceFile(
+ AZStd::string_view currentFilePath, AZStd::string_view referencedParentPath,
+ AZStd::vector& sourceFileDependencies,
+ AZStd::string& foundSourceFile)
{
- AZStd::vector possibleDependencies = AZ::RPI::AssetUtils::GetPossibleDepenencyPaths(shaderVariantListFilePath, shaderFilePath);
+ foundSourceFile.clear();
+
+ bool found = false;
+
+ AZStd::vector possibleDependencies = RPI::AssetUtils::GetPossibleDepenencyPaths(currentFilePath, referencedParentPath);
for (auto& file : possibleDependencies)
{
- AssetBuilderSDK::JobDependency jobDependency;
- jobDependency.m_jobKey = ShaderAssetBuilder::ShaderAssetBuilderJobKey;
- jobDependency.m_platformIdentifier = platformInfo.m_identifier;
- jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order;
- jobDependency.m_sourceFile.m_sourceFileDependencyPath = file;
- jobDescriptor.m_jobDependencyList.push_back(jobDependency);
+ AssetBuilderSDK::SourceFileDependency sourceFileDependency;
+ sourceFileDependency.m_sourceFileDependencyPath = file;
+ sourceFileDependencies.push_back(sourceFileDependency);
+
+ if (!found)
+ {
+ AZ::Data::AssetInfo sourceInfo;
+ AZStd::string watchFolder;
+ AzToolsFramework::AssetSystemRequestBus::BroadcastResult(found, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, file.c_str(), sourceInfo, watchFolder);
+
+ if (found)
+ {
+ foundSourceFile = file;
+ }
+ }
}
+
+ return found;
}
//! Returns true if @sourceFileFullPath starts with a valid asset processor scan folder, false otherwise.
@@ -334,6 +355,9 @@ namespace AZ
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
return;
}
+
+ AZStd::string foundShaderFile;
+ LocateReferencedSourceFile(variantListFullPath, shaderVariantList.m_shaderFilePath, response.m_sourceFileDependencyList, foundShaderFile);
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
{
@@ -349,8 +373,16 @@ namespace AZ
jobDescriptor.m_jobKey = GetShaderVariantTreeAssetJobKey();
jobDescriptor.SetPlatformIdentifier(info.m_identifier.data());
-
- AddShaderAssetJobDependency(jobDescriptor, info, variantListFullPath, shaderVariantList.m_shaderFilePath);
+
+ if (!foundShaderFile.empty())
+ {
+ AssetBuilderSDK::JobDependency jobDependency;
+ jobDependency.m_jobKey = ShaderAssetBuilder::ShaderAssetBuilderJobKey;
+ jobDependency.m_platformIdentifier = info.m_identifier;
+ jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order;
+ jobDependency.m_sourceFile.m_sourceFileDependencyPath = foundShaderFile;
+ jobDescriptor.m_jobDependencyList.push_back(jobDependency);
+ }
jobDescriptor.m_jobParameters.emplace(ShaderSourceFilePathJobParam, shaderSourceFileFullPath);
diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp
index a7721c84a2..9a3eda055e 100644
--- a/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp
+++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/SrgLayoutBuilder.cpp
@@ -203,6 +203,16 @@ namespace AZ
// queue up AzslBuilder dependencies:
for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces)
{
+ const bool isAzsli = AzFramework::StringFunc::Path::IsExtension(fullPath.c_str(), "azsli");
+ if (isAzsli)
+ {
+ auto skipCheck = ShaderBuilderUtility::ShouldSkipFileForSrgProcessing(SrgLayoutBuilderName, fullPath);
+ if (skipCheck != ShaderBuilderUtility::SrgSkipFileResult::ContinueProcess)
+ {
+ continue;
+ }
+ }
+
AddAzslBuilderJobDependency(jobDescriptor, info.m_identifier, shaderPlatformInterface->GetAPIName().GetCStr(), fullPath);
}
response.m_createJobOutputs.push_back(jobDescriptor);
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
index c635f94d56..a71fc65e2a 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
@@ -1465,14 +1465,9 @@
"file": "./EnhancedPBR_DepthPass_WithPS.shader",
"tag": "DepthPass_WithPS"
},
- // [GFX TODO][ATOM-4726] Use an "isSkinnedMesh" external material property and a functor that enables/disables the appropriate motion-vector shader
{
- "file": "Shaders/MotionVector/StaticMeshMotionVector.shader",
- "tag": "StaticMeshMotionVector"
- },
- {
- "file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader",
- "tag": "SkinnedMeshMotionVector"
+ "file": "Shaders/MotionVector/MeshMotionVector.shader",
+ "tag": "MeshMotionVector"
},
// Used by the light culling system to produce accurate depth bounds for this object when it uses blended transparency
{
@@ -1669,4 +1664,3 @@
"UV1": "Unwrapped"
}
}
-
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype
index dfe2fad60f..fe86576cf8 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype
@@ -980,14 +980,9 @@
"file": "Shaders/Depth/DepthPass.shader",
"tag": "DepthPass"
},
- // [GFX TODO][ATOM-4726] Use an "isSkinnedMesh" external material property and a functor that enables/disables the appropriate motion-vector shader
{
- "file": "Shaders/MotionVector/StaticMeshMotionVector.shader",
- "tag": "StaticMeshMotionVector"
- },
- {
- "file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader",
- "tag": "SkinnedMeshMotionVector"
+ "file": "Shaders/MotionVector/MeshMotionVector.shader",
+ "tag": "MeshMotionVector"
}
],
"functors": [
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
index d9a21e7662..bccb530eb4 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
@@ -2632,14 +2632,9 @@
"file": "./StandardMultilayerPBR_DepthPass_WithPS.shader",
"tag": "DepthPass_WithPS"
},
- // [GFX TODO][ATOM-4726] Use an "isSkinnedMesh" external material property and a functor that enables/disables the appropriate motion-vector shader
{
- "file": "Shaders/MotionVector/StaticMeshMotionVector.shader",
- "tag": "StaticMeshMotionVector"
- },
- {
- "file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader",
- "tag": "SkinnedMeshMotionVector"
+ "file": "Shaders/MotionVector/MeshMotionVector.shader",
+ "tag": "MeshMotionVector"
}
],
"functors": [
@@ -3103,4 +3098,3 @@
"UV1": "Unwrapped"
}
}
-
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
index fd2c74dae0..93220973df 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
@@ -1030,14 +1030,9 @@
"file": "./StandardPBR_DepthPass_WithPS.shader",
"tag": "DepthPass_WithPS"
},
- // [GFX TODO][ATOM-4726] Use an "isSkinnedMesh" external material property and a functor that enables/disables the appropriate motion-vector shader
{
- "file": "Shaders/MotionVector/StaticMeshMotionVector.shader",
- "tag": "StaticMeshMotionVector"
- },
- {
- "file": "Shaders/MotionVector/SkinnedMeshMotionVector.shader",
- "tag": "SkinnedMeshMotionVector"
+ "file": "Shaders/MotionVector/MeshMotionVector.shader",
+ "tag": "MeshMotionVector"
},
// Used by the light culling system to produce accurate depth bounds for this object when it uses blended transparency
{
@@ -1187,4 +1182,3 @@
"UV1": "Unwrapped"
}
}
-
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 893df85e3e..03d00d21f9 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
@@ -427,6 +427,7 @@ float DirectionalLightShadow::SamplePcfBicubic()
shadowCoord.y >= 0. && shadowCoord.y * size < size - PixelMargin &&
shadowCoord.z < 1. - DepthMargin)
{
+ m_debugInfo.m_cascadeIndex = indexOfCascade;
return SamplePcfBicubic(shadowCoord, indexOfCascade);
}
}
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.azsl
new file mode 100644
index 0000000000..3fb3fc0fd8
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.azsl
@@ -0,0 +1,86 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#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;
+
+ 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/StaticMeshMotionVector.shader b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.shader
similarity index 89%
rename from Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/StaticMeshMotionVector.shader
rename to Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.shader
index 0d580b1b10..c585060f3d 100644
--- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/StaticMeshMotionVector.shader
+++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVector.shader
@@ -1,5 +1,5 @@
{
- "Source" : "StaticMeshMotionVector",
+ "Source" : "MeshMotionVector",
"DepthStencilState" : {
"Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" }
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli
deleted file mode 100644
index ff2758af87..0000000000
--- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
-* its licensors.
-*
-* For complete copyright and license terms please see the LICENSE at the root of this
-* distribution (the "License"). All use of this software is governed by the License,
-* or, if provided, by the license below or the license accompanying this file. Do not
-* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-*
-*/
-
-#include
-#include
-
-#include
-#include
-
-struct VSOutput
-{
- float4 m_position : SV_Position;
- float3 m_worldPos : TEXCOORD0;
- float3 m_worldPosPrev: TEXCOORD1;
-};
-
-struct PSOutput
-{
- float2 m_motion : SV_Target0;
-};
-
-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/SkinnedMeshMotionVector.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/SkinnedMeshMotionVector.azsl
deleted file mode 100644
index dcbba22b2a..0000000000
--- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/SkinnedMeshMotionVector.azsl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
-* its licensors.
-*
-* For complete copyright and license terms please see the LICENSE at the root of this
-* distribution (the "License"). All use of this software is governed by the License,
-* or, if provided, by the license below or the license accompanying this file. Do not
-* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-*
-*/
-
-#include "./MeshMotionVectorCommon.azsli"
-
-struct VSInput
-{
- float3 m_position : POSITION;
- // Vertex position of last frame to capture small scale motion due to vertex animation
- float3 m_prevPosition : POSITIONT;
-};
-
-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));
- OUT.m_worldPosPrev = mul(SceneSrg::GetObjectToWorldMatrixPrev(ObjectSrg::m_objectId), float4(IN.m_prevPosition, 1.0)).xyz;
-
- return OUT;
-}
-
-
-
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/SkinnedMeshMotionVector.shader b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/SkinnedMeshMotionVector.shader
deleted file mode 100644
index 66d2fd88c5..0000000000
--- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/SkinnedMeshMotionVector.shader
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "Source" : "SkinnedMeshMotionVector",
-
- "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/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake
index 3dfabc586a..6a2721d4af 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
@@ -354,11 +354,8 @@ set(FILES
Shaders/MorphTargets/MorphTargetSRG.azsli
Shaders/MotionVector/CameraMotionVector.azsl
Shaders/MotionVector/CameraMotionVector.shader
- Shaders/MotionVector/MeshMotionVectorCommon.azsli
- Shaders/MotionVector/SkinnedMeshMotionVector.azsl
- Shaders/MotionVector/SkinnedMeshMotionVector.shader
- Shaders/MotionVector/StaticMeshMotionVector.azsl
- Shaders/MotionVector/StaticMeshMotionVector.shader
+ Shaders/MotionVector/MeshMotionVector.azsl
+ Shaders/MotionVector/MeshMotionVector.shader
Shaders/PostProcessing/AcesOutputTransformLut.azsl
Shaders/PostProcessing/AcesOutputTransformLut.shader
Shaders/PostProcessing/ApplyShaperLookupTable.azsl
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
index f1156cfe37..391a60a68d 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
@@ -72,7 +72,6 @@ namespace AZ
void UpdateDrawPackets(bool forceUpdate = false);
void BuildCullable();
void UpdateCullBounds(const TransformServiceFeatureProcessor* transformService);
- void SelectMotionVectorShader(Data::Instance material);
void UpdateObjectSrg();
bool MaterialRequiresForwardPassIblSpecular(Data::Instance material) const;
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
index d5a6ac1c3e..7cf9ab9685 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
@@ -32,7 +32,6 @@ namespace AZ
using RequiresCloneCallback = AZStd::function& modelAsset)>;
Data::Asset m_modelAsset;
- bool m_isSkinnedMeshWithMotion = false;
bool m_isRayTracingEnabled = true;
bool m_useForwardPassIblSpecular = false;
RequiresCloneCallback m_requiresCloneCallback = {};
diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
index f51defc0f3..7867faf02a 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
@@ -158,11 +158,6 @@ namespace AZ
MeshHandle meshDataHandle = m_meshData.emplace();
meshDataHandle->m_descriptor = descriptor;
-
- // Always disable ray tracing flag on skinned meshes
- // [GFX TODO][ATOM-13067] Enable raytracing on skinned meshes
- meshDataHandle->m_descriptor.m_isRayTracingEnabled &= !descriptor.m_isSkinnedMeshWithMotion;
-
meshDataHandle->m_scene = GetParentScene();
meshDataHandle->m_materialAssignments = materials;
meshDataHandle->m_objectId = m_transformService->ReserveObjectId();
@@ -665,8 +660,6 @@ namespace AZ
}
}
- SelectMotionVectorShader(material);
-
// setup the mesh draw packet
RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, m_shaderResourceGroup, materialAssignment.m_matModUvOverrides);
@@ -1091,29 +1084,6 @@ namespace AZ
m_cullBoundsNeedsUpdate = false;
}
- void MeshDataInstance::SelectMotionVectorShader(Data::Instance material)
- {
- // Two motion vector shaders are defined in the material for static mesh (only animated by transform matrix)
- // and skinned mesh (per vertex animation) respectively, it's because they have different input signatures
- // (skinned mesh needs two streaming channels while static mesh only needs one) that cannot be addressed by shader option
- // itself. Therefore this function is used to pick one to use and disable the other one depending on the type of the mesh
- // so it won't cause errors due to missing input streaming channel.
-
- //[GFX TODO][ATOM-4726] Replace this with a "isSkinnedMesh" external material property and a functor that enables/disables the appropriate shader
- for (auto& shaderItem : material->GetShaderCollection())
- {
- if (shaderItem.GetShaderAsset()->GetName() == Name{ "StaticMeshMotionVector" } && m_descriptor.m_isSkinnedMeshWithMotion)
- {
- shaderItem.SetEnabled(false);
- }
-
- if (shaderItem.GetShaderAsset()->GetName() == Name{ "SkinnedMeshMotionVector" } && (!m_descriptor.m_isSkinnedMeshWithMotion))
- {
- shaderItem.SetEnabled(false);
- }
- }
- }
-
void MeshDataInstance::UpdateObjectSrg()
{
if (!m_shaderResourceGroup)
diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp
index 2d4b6ee85f..690a2d63c2 100644
--- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp
@@ -47,8 +47,12 @@ namespace AZ
m_updateSrg = true;
}
- params.m_viewportState = RHI::Viewport(0, static_cast(m_imageSize.m_width), 0, static_cast(m_imageSize.m_height));
- params.m_scissorState = RHI::Scissor(0, 0, m_imageSize.m_width, m_imageSize.m_height);
+ float inverseScale = 1.0f / m_outputScale;
+ uint32_t outputWidth = m_imageSize.m_width * inverseScale;
+ uint32_t outputHeight = m_imageSize.m_height * inverseScale;
+
+ params.m_viewportState = RHI::Viewport(0, static_cast(outputWidth), 0, static_cast(outputHeight));
+ params.m_scissorState = RHI::Scissor(0, 0, outputWidth, outputHeight);
FullscreenTrianglePass::FrameBeginInternal(params);
}
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 554d20dede..4db2187551 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
@@ -66,6 +66,7 @@ namespace AZ
//! it's possible that b.json could be found in either MyGem/Assets/Foo/Bar/a.json or in MyGem/Assets/Bar/a.json.
//! @param originatingSourceFilePath Path to a file that references referencedSourceFilePath. May be absolute or relative to asset-root.
//! @param referencedSourceFilePath The referenced path as it appears in the originating file. May be relative to the originating file location or relative to asset-root.
+ //! @return the list of possible paths, ordered from highest priority to lowest priority
AZStd::vector GetPossibleDepenencyPaths(const AZStd::string& originatingSourceFilePath, const AZStd::string& referencedSourceFilePath);
// Definitions...
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h
index fa1bb57166..6cffe4a47d 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h
@@ -105,7 +105,6 @@ namespace AZ
ChangeId GetCurrentChangeId() const;
//! Return the set of shaders to be run by this material.
- ShaderCollection& GetShaderCollection();
const ShaderCollection& GetShaderCollection() const;
//! Attempts to set the value of a system-level shader option that is controlled by this material.
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp
index d31b6b3802..d52bba2482 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Material/MaterialBuilder.cpp
@@ -67,16 +67,41 @@ namespace AZ
BusDisconnect();
}
- void AddPossibleJobDependencies(const char* jobKey, AZStd::string_view currentFilePath, AZStd::string_view referencedParentPath, AZStd::vector& jobDependencies)
+ //! Adds all relevant dependencies for a referenced source file, considering that the path might be relative to the original file location or a full asset path.
+ //! This will usually include multiple source dependencies and a single job dependency, but will include only source dependencies if the file is not found.
+ //! Note the AssetBuilderSDK::JobDependency::m_platformIdentifier will not be set by this function. The calling code must set this value before passing back
+ //! to the AssetBuilderSDK::CreateJobsResponse.
+ void AddPossibleDependencies(
+ AZStd::string_view currentFilePath, AZStd::string_view referencedParentPath,
+ AZStd::vector& sourceFileDependencies,
+ const char* jobKey, AZStd::vector& jobDependencies)
{
- AZStd::vector possibleDependencies = AssetUtils::GetPossibleDepenencyPaths(currentFilePath, referencedParentPath);
+ bool dependencyFileFound = false;
+
+ AZStd::vector possibleDependencies = RPI::AssetUtils::GetPossibleDepenencyPaths(currentFilePath, referencedParentPath);
for (auto& file : possibleDependencies)
{
- AssetBuilderSDK::JobDependency jobDependency;
- jobDependency.m_jobKey = jobKey;
- jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order;
- jobDependency.m_sourceFile.m_sourceFileDependencyPath = file;
- jobDependencies.push_back(jobDependency);
+ AssetBuilderSDK::SourceFileDependency sourceFileDependency;
+ sourceFileDependency.m_sourceFileDependencyPath = file;
+ sourceFileDependencies.push_back(sourceFileDependency);
+
+ // The first path found is the highest priority, and will have a job dependency, as this is the one
+ // the builder will actually use
+ if (!dependencyFileFound)
+ {
+ AZ::Data::AssetInfo sourceInfo;
+ AZStd::string watchFolder;
+ AzToolsFramework::AssetSystemRequestBus::BroadcastResult(dependencyFileFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, file.c_str(), sourceInfo, watchFolder);
+
+ if (dependencyFileFound)
+ {
+ AssetBuilderSDK::JobDependency jobDependency;
+ jobDependency.m_jobKey = jobKey;
+ jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order;
+ jobDependency.m_sourceFile.m_sourceFileDependencyPath = file;
+ jobDependencies.push_back(jobDependency);
+ }
+ }
}
}
@@ -123,7 +148,7 @@ namespace AZ
// We'll build up this one JobDescriptor and reuse it to register each of the platforms
AssetBuilderSDK::JobDescriptor outputJobDescriptor;
outputJobDescriptor.m_jobKey = JobKey;
-
+
// Load the file so we can detect and report dependencies.
// If the file is a .materialtype, report dependencies on the .shader files.
// If the file is a .material, report a dependency on the .materialtype and parent .material file
@@ -152,7 +177,9 @@ namespace AZ
for (auto& shader : materialTypeSourceData.GetValue().m_shaderCollection)
{
- AddPossibleJobDependencies("Shader Asset", request.m_sourceFile, shader.m_shaderFilePath, outputJobDescriptor.m_jobDependencyList);
+ AddPossibleDependencies(request.m_sourceFile, shader.m_shaderFilePath,
+ response.m_sourceFileDependencyList, "Shader Asset",
+ outputJobDescriptor.m_jobDependencyList);
}
for (auto& functor : materialTypeSourceData.GetValue().m_materialFunctorSourceData)
@@ -161,7 +188,9 @@ namespace AZ
for (const MaterialFunctorSourceData::AssetDependency& dependency : dependencies)
{
- AddPossibleJobDependencies(dependency.m_jobKey.c_str(), request.m_sourceFile, dependency.m_sourceFilePath, outputJobDescriptor.m_jobDependencyList);
+ AddPossibleDependencies(request.m_sourceFile, dependency.m_sourceFilePath,
+ response.m_sourceFileDependencyList,
+ dependency.m_jobKey.c_str(), outputJobDescriptor.m_jobDependencyList);
}
}
}
@@ -196,7 +225,9 @@ namespace AZ
// Register dependency on the parent material source file so we can load it and use it's data to build this variant material.
// Note, we don't need a direct dependency on the material type because the parent material will depend on it.
- AddPossibleJobDependencies(JobKey, request.m_sourceFile, parentMaterialPath, outputJobDescriptor.m_jobDependencyList);
+ AddPossibleDependencies(request.m_sourceFile, parentMaterialPath,
+ response.m_sourceFileDependencyList,
+ JobKey, outputJobDescriptor.m_jobDependencyList);
}
}
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Common/AssetUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Common/AssetUtils.cpp
index 32cffc771a..8fa0094a53 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Common/AssetUtils.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Common/AssetUtils.cpp
@@ -109,31 +109,16 @@ namespace AZ
AZStd::vector GetPossibleDepenencyPaths(const AZStd::string& originatingSourceFilePath, const AZStd::string& referencedSourceFilePath)
{
- // We potentially add the parent dependency as both a direct path and a relative path rather than use AssetUtils::ResolvePathReference
- // because there is no guarantee that the Asset Processor has seen the parent file yet (which ResolvePathReference requires).
- // In that case, we have to add both possible locations because we don't know where it will show up.
-
AZStd::vector results;
- // The first dependency we add is using the referencedSourceFilePath as a relative path. This gives relative paths priority over asset-root paths.
+ // Use the referencedSourceFilePath as a relative path starting at originatingSourceFilePath
AZStd::string combinedPath = originatingSourceFilePath;
AzFramework::StringFunc::Path::StripFullName(combinedPath);
AzFramework::StringFunc::Path::Join(combinedPath.c_str(), referencedSourceFilePath.c_str(), combinedPath);
results.push_back(combinedPath);
- // If the parent file exists at the relative path, then there is no need to report a dependency on the asset-root path.
- bool assetFound = false;
- AZ::Data::AssetInfo sourceInfo;
- AZStd::string watchFolder;
- AzToolsFramework::AssetSystemRequestBus::BroadcastResult(assetFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, combinedPath.c_str(), sourceInfo, watchFolder);
-
- if (!assetFound)
- {
- // The parent file wasn't found at the relative path, so we need a dependency on the asset-root path in case the file
- // exists there. Note, we still keep the relative path dependency above because we don't know whether it's missing because
- // it doesn't exist, or just because the AP hasn't found it yet.
- results.push_back(referencedSourceFilePath);
- }
+ // Use the referencedSourceFilePath as a standard asset path
+ results.push_back(referencedSourceFilePath);
return results;
}
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp
index 3302190156..3f376ccf25 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp
@@ -164,11 +164,6 @@ namespace AZ
Data::AssetBus::Handler::BusDisconnect();
}
- ShaderCollection& Material::GetShaderCollection()
- {
- return m_shaderCollection;
- }
-
const ShaderCollection& Material::GetShaderCollection() const
{
return m_shaderCollection;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp
index 67a6fcaa5b..5c76b084b1 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp
@@ -24,6 +24,7 @@
#include
#include
+#include
namespace AZ
{
@@ -181,19 +182,15 @@ namespace AZ
RHI::Size targetImageSize = outputAttachment->m_descriptor.m_image.m_size;
- m_viewportState = params.m_viewportState;
- if (m_viewportState.IsNull())
- {
- // compute viewport from target attachment
- m_viewportState = RHI::Viewport(0, static_cast(targetImageSize.m_width), 0, static_cast(targetImageSize.m_height));
- }
+ m_viewportState.m_minX = 0.0f;
+ m_viewportState.m_minY = 0.0f;
+ m_viewportState.m_maxX = AZStd::min(static_cast(params.m_viewportState.m_maxX), targetImageSize.m_width);
+ m_viewportState.m_maxY = AZStd::min(static_cast(params.m_viewportState.m_maxY), targetImageSize.m_height);
- m_scissorState = params.m_scissorState;
- if (m_scissorState.IsNull())
- {
- // compute scissor from target attachment
- m_scissorState = RHI::Scissor(0, 0, targetImageSize.m_width, targetImageSize.m_height);
- }
+ m_scissorState.m_minX = 0.0f;
+ m_scissorState.m_minY = 0.0f;
+ m_scissorState.m_maxX = AZStd::min(static_cast(params.m_scissorState.m_maxX), targetImageSize.m_width);
+ m_scissorState.m_maxY = AZStd::min(static_cast(params.m_scissorState.m_maxY), targetImageSize.m_height);
RenderPass::FrameBeginInternal(params);
}
diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp
index f4d4144796..29dee12489 100644
--- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp
+++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp
@@ -628,7 +628,10 @@ namespace AZ
{
MeshHandleDescriptor meshDescriptor;
meshDescriptor.m_modelAsset = m_skinnedMeshInstance->m_model->GetModelAsset();
- meshDescriptor.m_isSkinnedMeshWithMotion = true;
+
+ // [GFX TODO][ATOM-13067] Enable raytracing on skinned meshes
+ meshDescriptor.m_isRayTracingEnabled = false;
+
m_meshHandle = AZStd::make_shared(
m_meshFeatureProcessor->AcquireMesh(meshDescriptor, materials));
}
diff --git a/Gems/LmbrCentral/Code/CMakeLists.txt b/Gems/LmbrCentral/Code/CMakeLists.txt
index 4d03d30923..588502954d 100644
--- a/Gems/LmbrCentral/Code/CMakeLists.txt
+++ b/Gems/LmbrCentral/Code/CMakeLists.txt
@@ -104,7 +104,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target_files(
TARGETS LmbrCentral.Editor
- FILES ${QT_LRELEASE_EXECUTABLE}
+ FILES ${lrelease_files}
)
# by default, load the above "Gem::LmbrCentral.Editor" module in dev tools
diff --git a/Gems/LmbrCentral/Code/Platform/Linux/lrelease_linux.cmake b/Gems/LmbrCentral/Code/Platform/Linux/lrelease_linux.cmake
index 41eaf4a47a..70fbecf851 100644
--- a/Gems/LmbrCentral/Code/Platform/Linux/lrelease_linux.cmake
+++ b/Gems/LmbrCentral/Code/Platform/Linux/lrelease_linux.cmake
@@ -17,3 +17,7 @@ add_custom_command(TARGET LmbrCentral.Editor POST_BUILD
COMMENT "Patching lrelease..."
VERBATIM
)
+
+set(lrelease_files
+ ${QT_LRELEASE_EXECUTABLE}
+)
diff --git a/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake b/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake
index 4d5680a30d..53fcdfa02a 100644
--- a/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake
+++ b/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake
@@ -8,3 +8,7 @@
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
+
+set(lrelease_files
+ ${QT_LRELEASE_EXECUTABLE}
+)
diff --git a/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake b/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake
index 4d5680a30d..dda1715d76 100644
--- a/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake
+++ b/Gems/LmbrCentral/Code/Platform/Windows/lrelease_windows.cmake
@@ -8,3 +8,8 @@
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
+
+set(lrelease_files
+ ${QT_LRELEASE_EXECUTABLE}
+ ${QT_PATH}/bin/Qt5Core.dll # this is a dependency of lrelease. Even in debug we use the release version
+)