Merge branch 'stabilization/2110' into Prism/DeleteUpdateGemsUI
This commit is contained in:
@@ -62164,7 +62164,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_NAME">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_TOOLTIP</source>
|
||||
@@ -62202,7 +62202,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_NAME">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityId</translation>
|
||||
</message>
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_TOOLTIP</source>
|
||||
@@ -81852,7 +81852,7 @@ The element is removed from its current parent and added as a child of the new p
|
||||
<message id="HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_NAME">
|
||||
<source>HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_TOOLTIP">
|
||||
<source>HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_TOOLTIP</source>
|
||||
@@ -89198,7 +89198,7 @@ The element is removed from its current parent and added as a child of the new p
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_NAME">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_TOOLTIP</source>
|
||||
@@ -89236,7 +89236,7 @@ The element is removed from its current parent and added as a child of the new p
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_NAME">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_TOOLTIP</source>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/XcbConnectionManager.h>
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option")
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
AZ_CVAR(
|
||||
bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
bool, ed_useNewAssetBrowserTableView, true, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"Use the new AssetBrowser TableView for searching assets.");
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
|
||||
+3
-1
@@ -606,6 +606,7 @@ namespace AzToolsFramework
|
||||
|
||||
AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect(
|
||||
AzToolsFramework::GetEntityContextId());
|
||||
ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId());
|
||||
}
|
||||
|
||||
EntityPropertyEditor::~EntityPropertyEditor()
|
||||
@@ -618,7 +619,8 @@ namespace AzToolsFramework
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
ViewportEditorModeNotificationsBus::Handler::BusDisconnect();
|
||||
|
||||
for (auto& entityId : m_overrideSelectedEntityIds)
|
||||
{
|
||||
DisconnectFromEntityBuses(entityId);
|
||||
|
||||
@@ -243,7 +243,7 @@ void AssetProcessorManagerTest::SetUp()
|
||||
m_mockApplicationManager->BusConnect();
|
||||
|
||||
m_assetProcessorManager.reset(new AssetProcessorManager_Test(m_config.get()));
|
||||
m_assertAbsorber.Clear();
|
||||
m_errorAbsorber->Clear();
|
||||
|
||||
m_isIdling = false;
|
||||
|
||||
@@ -334,9 +334,9 @@ TEST_F(AssetProcessorManagerTest, UnitTestForGettingJobInfoBySourceUUIDSuccess)
|
||||
EXPECT_STRCASEEQ(relFileName.toUtf8().data(), response.m_jobList[0].m_sourceFile.c_str());
|
||||
EXPECT_STRCASEEQ(tempPath.filePath("subfolder1").toUtf8().data(), response.m_jobList[0].m_watchFolder.c_str());
|
||||
|
||||
ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
|
||||
ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
|
||||
ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
|
||||
}
|
||||
|
||||
TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToDatabase)
|
||||
@@ -388,9 +388,9 @@ TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToD
|
||||
ASSERT_EQ(response.m_jobList[0].m_warningCount, 11);
|
||||
ASSERT_EQ(response.m_jobList[0].m_errorCount, 22);
|
||||
|
||||
ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
|
||||
ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
|
||||
ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1312,8 +1312,8 @@ void PathDependencyTest::SetUp()
|
||||
|
||||
void PathDependencyTest::TearDown()
|
||||
{
|
||||
ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
|
||||
ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
|
||||
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
|
||||
|
||||
AssetProcessorManagerTest::TearDown();
|
||||
}
|
||||
@@ -1617,7 +1617,7 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
|
||||
mainFile.m_products.push_back(productAssetId);
|
||||
|
||||
// tell the APM that the asset has been processed and allow it to bubble through its event queue:
|
||||
m_assertAbsorber.Clear();
|
||||
m_errorAbsorber->Clear();
|
||||
m_assetProcessorManager->AssetProcessed(jobDetails.m_jobEntry, processJobResponse);
|
||||
ASSERT_TRUE(BlockUntilIdle(5000));
|
||||
|
||||
@@ -1627,8 +1627,8 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
|
||||
ASSERT_TRUE(dependencyContainer.empty());
|
||||
|
||||
// We are testing 2 different dependencies, so we should get 2 warnings
|
||||
ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 2);
|
||||
m_assertAbsorber.Clear();
|
||||
ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 2);
|
||||
m_errorAbsorber->Clear();
|
||||
}
|
||||
|
||||
// This test shows the process of deferring resolution of a path dependency works.
|
||||
@@ -1945,8 +1945,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludePathsExisting_ResolveCorr
|
||||
);
|
||||
|
||||
// Test asset PrimaryFile1 has 4 conflict dependencies
|
||||
ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 4);
|
||||
m_assertAbsorber.Clear();
|
||||
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 4);
|
||||
m_errorAbsorber->Clear();
|
||||
}
|
||||
|
||||
TEST_F(PathDependencyTest, WildcardDependencies_Deferred_ResolveCorrectly)
|
||||
@@ -2093,8 +2093,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludedPathDeferred_ResolveCorr
|
||||
// Test asset PrimaryFile1 has 4 conflict dependencies
|
||||
// After test assets dep2 and dep3 are processed,
|
||||
// another 2 errors will be raised because of the confliction
|
||||
ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 6);
|
||||
m_assertAbsorber.Clear();
|
||||
ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 6);
|
||||
m_errorAbsorber->Clear();
|
||||
}
|
||||
|
||||
void PathDependencyTest::RunWildcardTest(bool useCorrectDatabaseSeparator, AssetBuilderSDK::ProductPathDependencyType pathDependencyType, bool buildDependenciesFirst)
|
||||
|
||||
@@ -58,7 +58,6 @@ protected:
|
||||
AZStd::unique_ptr<AssetProcessorManager_Test> m_assetProcessorManager;
|
||||
AZStd::unique_ptr<AssetProcessor::MockApplicationManager> m_mockApplicationManager;
|
||||
AZStd::unique_ptr<AssetProcessor::PlatformConfiguration> m_config;
|
||||
UnitTestUtils::AssertAbsorber m_assertAbsorber; // absorb asserts/warnings/errors so that the unit test output is not cluttered
|
||||
QString m_gameName;
|
||||
QDir m_normalizedCacheRootDir;
|
||||
AZStd::atomic_bool m_isIdling;
|
||||
|
||||
@@ -41,9 +41,11 @@ namespace O3DE::ProjectManager
|
||||
void DownloadController::AddGemDownload(const QString& gemName)
|
||||
{
|
||||
m_gemNames.push_back(gemName);
|
||||
emit GemDownloadAdded(gemName);
|
||||
|
||||
if (m_gemNames.size() == 1)
|
||||
{
|
||||
m_worker->SetGemToDownload(m_gemNames[0], false);
|
||||
m_worker->SetGemToDownload(m_gemNames.front(), false);
|
||||
m_workerThread.start();
|
||||
}
|
||||
}
|
||||
@@ -62,6 +64,7 @@ namespace O3DE::ProjectManager
|
||||
else
|
||||
{
|
||||
m_gemNames.erase(findResult);
|
||||
emit GemDownloadRemoved(gemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +72,7 @@ namespace O3DE::ProjectManager
|
||||
void DownloadController::UpdateUIProgress(int progress)
|
||||
{
|
||||
m_lastProgress = progress;
|
||||
emit GemDownloadProgress(progress);
|
||||
emit GemDownloadProgress(m_gemNames.front(), progress);
|
||||
}
|
||||
|
||||
void DownloadController::HandleResults(const QString& result)
|
||||
|
||||
@@ -59,7 +59,9 @@ namespace O3DE::ProjectManager
|
||||
signals:
|
||||
void StartGemDownload(const QString& gemName);
|
||||
void Done(const QString& gemName, bool success = true);
|
||||
void GemDownloadProgress(int percentage);
|
||||
void GemDownloadAdded(const QString& gemName);
|
||||
void GemDownloadRemoved(const QString& gemName);
|
||||
void GemDownloadProgress(const QString& gemName, int percentage);
|
||||
|
||||
private:
|
||||
DownloadWorker* m_worker;
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace O3DE::ProjectManager
|
||||
m_layout->setMargin(5);
|
||||
m_layout->setAlignment(Qt::AlignTop);
|
||||
setLayout(m_layout);
|
||||
setMinimumHeight(400);
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
|
||||
@@ -119,6 +120,12 @@ namespace O3DE::ProjectManager
|
||||
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
|
||||
}
|
||||
|
||||
CartOverlayWidget::~CartOverlayWidget()
|
||||
{
|
||||
// disconnect from all download controller signals
|
||||
disconnect(m_downloadController, nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
void CartOverlayWidget::CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices)
|
||||
{
|
||||
QWidget* widget = new QWidget();
|
||||
@@ -162,13 +169,13 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void CartOverlayWidget::CreateDownloadSection()
|
||||
{
|
||||
QWidget* widget = new QWidget();
|
||||
widget->setFixedWidth(s_width);
|
||||
m_layout->addWidget(widget);
|
||||
m_downloadSectionWidget = new QWidget();
|
||||
m_downloadSectionWidget->setFixedWidth(s_width);
|
||||
m_layout->addWidget(m_downloadSectionWidget);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
widget->setLayout(layout);
|
||||
m_downloadSectionWidget->setLayout(layout);
|
||||
|
||||
QLabel* titleLabel = new QLabel();
|
||||
titleLabel->setObjectName("GemCatalogCartOverlaySectionLabel");
|
||||
@@ -187,88 +194,121 @@ namespace O3DE::ProjectManager
|
||||
QLabel* processingQueueLabel = new QLabel("Processing Queue");
|
||||
gemDownloadLayout->addWidget(processingQueueLabel);
|
||||
|
||||
QWidget* downloadingItemWidget = new QWidget();
|
||||
downloadingItemWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG");
|
||||
gemDownloadLayout->addWidget(downloadingItemWidget);
|
||||
m_downloadingListWidget = new QWidget();
|
||||
m_downloadingListWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG");
|
||||
gemDownloadLayout->addWidget(m_downloadingListWidget);
|
||||
QVBoxLayout* downloadingItemLayout = new QVBoxLayout();
|
||||
downloadingItemLayout->setAlignment(Qt::AlignTop);
|
||||
downloadingItemWidget->setLayout(downloadingItemLayout);
|
||||
m_downloadingListWidget->setLayout(downloadingItemLayout);
|
||||
|
||||
auto update = [=](int downloadProgress)
|
||||
QLabel* downloadsInProgessLabel = new QLabel("");
|
||||
downloadsInProgessLabel->setObjectName("NumDownloadsInProgressLabel");
|
||||
downloadingItemLayout->addWidget(downloadsInProgessLabel);
|
||||
|
||||
if (m_downloadController->IsDownloadQueueEmpty())
|
||||
{
|
||||
if (m_downloadController->IsDownloadQueueEmpty())
|
||||
{
|
||||
widget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
widget->setUpdatesEnabled(false);
|
||||
// remove items
|
||||
QLayoutItem* layoutItem = nullptr;
|
||||
while ((layoutItem = downloadingItemLayout->takeAt(0)) != nullptr)
|
||||
{
|
||||
if (layoutItem->layout())
|
||||
{
|
||||
// Gem info row
|
||||
QLayoutItem* rowLayoutItem = nullptr;
|
||||
while ((rowLayoutItem = layoutItem->layout()->takeAt(0)) != nullptr)
|
||||
{
|
||||
rowLayoutItem->widget()->deleteLater();
|
||||
}
|
||||
layoutItem->layout()->deleteLater();
|
||||
}
|
||||
if (layoutItem->widget())
|
||||
{
|
||||
layoutItem->widget()->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
// Setup gem download rows
|
||||
const AZStd::vector<QString>& downloadQueue = m_downloadController->GetDownloadQueue();
|
||||
|
||||
QLabel* downloadsInProgessLabel = new QLabel("");
|
||||
downloadsInProgessLabel->setText(
|
||||
QString("%1 %2").arg(downloadQueue.size()).arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress...")));
|
||||
downloadingItemLayout->addWidget(downloadsInProgessLabel);
|
||||
|
||||
for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber)
|
||||
{
|
||||
QHBoxLayout* nameProgressLayout = new QHBoxLayout();
|
||||
|
||||
const QString& gemName = downloadQueue[downloadingGemNumber];
|
||||
TagWidget* newTag = new TagWidget({gemName, gemName});
|
||||
nameProgressLayout->addWidget(newTag);
|
||||
|
||||
QLabel* progress = new QLabel(downloadingGemNumber == 0? QString("%1%").arg(downloadProgress) : tr("Queued"));
|
||||
nameProgressLayout->addWidget(progress);
|
||||
|
||||
QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
nameProgressLayout->addSpacerItem(spacer);
|
||||
|
||||
QLabel* cancelText = new QLabel(QString("<a href=\"%1\">Cancel</a>").arg(gemName));
|
||||
cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
|
||||
connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated);
|
||||
nameProgressLayout->addWidget(cancelText);
|
||||
downloadingItemLayout->addLayout(nameProgressLayout);
|
||||
|
||||
QProgressBar* downloadProgessBar = new QProgressBar();
|
||||
downloadingItemLayout->addWidget(downloadProgessBar);
|
||||
downloadProgessBar->setValue(downloadingGemNumber == 0 ? downloadProgress : 0);
|
||||
}
|
||||
|
||||
widget->setUpdatesEnabled(true);
|
||||
widget->show();
|
||||
}
|
||||
};
|
||||
|
||||
auto downloadEnded = [=](const QString& /*gemName*/, bool /*success*/)
|
||||
m_downloadSectionWidget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
update(0); // update the list to remove the gem that has finished
|
||||
};
|
||||
// Setup gem download rows for gems that are already in the queue
|
||||
const AZStd::vector<QString>& downloadQueue = m_downloadController->GetDownloadQueue();
|
||||
|
||||
for (const QString& gemName : downloadQueue)
|
||||
{
|
||||
GemDownloadAdded(gemName);
|
||||
}
|
||||
}
|
||||
|
||||
// connect to download controller data changed
|
||||
connect(m_downloadController, &DownloadController::GemDownloadProgress, this, update);
|
||||
connect(m_downloadController, &DownloadController::Done, this, downloadEnded);
|
||||
update(0);
|
||||
connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &CartOverlayWidget::GemDownloadAdded);
|
||||
connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &CartOverlayWidget::GemDownloadRemoved);
|
||||
connect(m_downloadController, &DownloadController::GemDownloadProgress, this, &CartOverlayWidget::GemDownloadProgress);
|
||||
connect(m_downloadController, &DownloadController::Done, this, &CartOverlayWidget::GemDownloadComplete);
|
||||
}
|
||||
|
||||
void CartOverlayWidget::GemDownloadAdded(const QString& gemName)
|
||||
{
|
||||
// Containing widget for the current download item
|
||||
QWidget* newGemDownloadWidget = new QWidget();
|
||||
newGemDownloadWidget->setObjectName(gemName);
|
||||
QVBoxLayout* downloadingGemLayout = new QVBoxLayout(newGemDownloadWidget);
|
||||
newGemDownloadWidget->setLayout(downloadingGemLayout);
|
||||
|
||||
// Gem name, progress string, cancel
|
||||
QHBoxLayout* nameProgressLayout = new QHBoxLayout(newGemDownloadWidget);
|
||||
TagWidget* newTag = new TagWidget({gemName, gemName}, newGemDownloadWidget);
|
||||
nameProgressLayout->addWidget(newTag);
|
||||
QLabel* progress = new QLabel(tr("Queued"), newGemDownloadWidget);
|
||||
progress->setObjectName("DownloadProgressLabel");
|
||||
nameProgressLayout->addWidget(progress);
|
||||
nameProgressLayout->addStretch();
|
||||
QLabel* cancelText = new QLabel(tr("<a href=\"%1\">Cancel</a>").arg(gemName), newGemDownloadWidget);
|
||||
cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
|
||||
connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated);
|
||||
nameProgressLayout->addWidget(cancelText);
|
||||
downloadingGemLayout->addLayout(nameProgressLayout);
|
||||
|
||||
// Progress bar
|
||||
QProgressBar* downloadProgessBar = new QProgressBar(newGemDownloadWidget);
|
||||
downloadProgessBar->setObjectName("DownloadProgressBar");
|
||||
downloadingGemLayout->addWidget(downloadProgessBar);
|
||||
downloadProgessBar->setValue(0);
|
||||
|
||||
m_downloadingListWidget->layout()->addWidget(newGemDownloadWidget);
|
||||
|
||||
const AZStd::vector<QString>& downloadQueue = m_downloadController->GetDownloadQueue();
|
||||
QLabel* numDownloads = m_downloadingListWidget->findChild<QLabel*>("NumDownloadsInProgressLabel");
|
||||
numDownloads->setText(QString("%1 %2")
|
||||
.arg(downloadQueue.size())
|
||||
.arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress...")));
|
||||
|
||||
m_downloadingListWidget->show();
|
||||
}
|
||||
|
||||
void CartOverlayWidget::GemDownloadRemoved(const QString& gemName)
|
||||
{
|
||||
QWidget* gemToRemove = m_downloadingListWidget->findChild<QWidget*>(gemName);
|
||||
if (gemToRemove)
|
||||
{
|
||||
gemToRemove->deleteLater();
|
||||
}
|
||||
|
||||
if (m_downloadController->IsDownloadQueueEmpty())
|
||||
{
|
||||
m_downloadSectionWidget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t downloadQueueSize = m_downloadController->GetDownloadQueue().size();
|
||||
QLabel* numDownloads = m_downloadingListWidget->findChild<QLabel*>("NumDownloadsInProgressLabel");
|
||||
numDownloads->setText(QString("%1 %2")
|
||||
.arg(downloadQueueSize)
|
||||
.arg(downloadQueueSize == 1 ? tr("download in progress...") : tr("downloads in progress...")));
|
||||
}
|
||||
}
|
||||
|
||||
void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int percentage)
|
||||
{
|
||||
QWidget* gemToUpdate = m_downloadingListWidget->findChild<QWidget*>(gemName);
|
||||
if (gemToUpdate)
|
||||
{
|
||||
QLabel* progressLabel = gemToUpdate->findChild<QLabel*>("DownloadProgressLabel");
|
||||
if (progressLabel)
|
||||
{
|
||||
progressLabel->setText(QString("%1%").arg(percentage));
|
||||
}
|
||||
QProgressBar* progressBar = gemToUpdate->findChild<QProgressBar*>("DownloadProgressBar");
|
||||
if (progressBar)
|
||||
{
|
||||
progressBar->setValue(percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CartOverlayWidget::GemDownloadComplete(const QString& gemName, bool /*success*/)
|
||||
{
|
||||
GemDownloadRemoved(gemName); // update the list to remove the gem that has finished
|
||||
}
|
||||
|
||||
QVector<Tag> CartOverlayWidget::GetTagsFromModelIndices(const QVector<QModelIndex>& gems) const
|
||||
|
||||
@@ -34,6 +34,13 @@ namespace O3DE::ProjectManager
|
||||
|
||||
public:
|
||||
CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr);
|
||||
~CartOverlayWidget();
|
||||
|
||||
public slots:
|
||||
void GemDownloadAdded(const QString& gemName);
|
||||
void GemDownloadRemoved(const QString& gemName);
|
||||
void GemDownloadProgress(const QString& gemName, int percentage);
|
||||
void GemDownloadComplete(const QString& gemName, bool success);
|
||||
|
||||
private:
|
||||
QVector<Tag> GetTagsFromModelIndices(const QVector<QModelIndex>& gems) const;
|
||||
@@ -47,6 +54,9 @@ namespace O3DE::ProjectManager
|
||||
GemModel* m_gemModel = nullptr;
|
||||
DownloadController* m_downloadController = nullptr;
|
||||
|
||||
QWidget* m_downloadSectionWidget = nullptr;
|
||||
QWidget* m_downloadingListWidget = nullptr;
|
||||
|
||||
inline constexpr static int s_width = 240;
|
||||
};
|
||||
|
||||
|
||||
@@ -268,6 +268,7 @@ namespace O3DE::ProjectManager
|
||||
if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded)
|
||||
{
|
||||
m_downloadController->AddGemDownload(GemModel::GetName(modelIndex));
|
||||
GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +221,6 @@ namespace O3DE::ProjectManager
|
||||
ResetGemStatusFilter();
|
||||
ResetGemOriginFilter();
|
||||
ResetTypeFilter();
|
||||
ResetPlatformFilter();
|
||||
ResetFeatureFilter();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
float m_padding;
|
||||
bool m_useReflectionProbe;
|
||||
bool m_useParallaxCorrection;
|
||||
float m_exposure;
|
||||
};
|
||||
|
||||
ReflectionProbeData m_reflectionProbeData;
|
||||
|
||||
@@ -85,12 +85,12 @@ void ApplyIBL(Surface surface, inout LightingData lightingData)
|
||||
|
||||
if(useIbl)
|
||||
{
|
||||
float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure);
|
||||
float globalIblExposure = pow(2.0, SceneSrg::m_iblExposure);
|
||||
|
||||
if(useDiffuseIbl)
|
||||
{
|
||||
float3 iblDiffuse = GetIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse);
|
||||
lightingData.diffuseLighting += (iblDiffuse * iblExposureFactor * lightingData.diffuseAmbientOcclusion);
|
||||
lightingData.diffuseLighting += (iblDiffuse * globalIblExposure * lightingData.diffuseAmbientOcclusion);
|
||||
}
|
||||
|
||||
if(useSpecularIbl)
|
||||
@@ -116,7 +116,8 @@ void ApplyIBL(Surface surface, inout LightingData lightingData)
|
||||
iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular;
|
||||
}
|
||||
|
||||
lightingData.specularLighting += (iblSpecular * iblExposureFactor);
|
||||
float exposure = ObjectSrg::m_reflectionProbeData.m_useReflectionProbe ? pow(2.0, ObjectSrg::m_reflectionProbeData.m_exposure) : globalIblExposure;
|
||||
lightingData.specularLighting += (iblSpecular * exposure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
float m_padding;
|
||||
bool m_useReflectionProbe;
|
||||
bool m_useParallaxCorrection;
|
||||
float m_exposure;
|
||||
};
|
||||
|
||||
ReflectionProbeData m_reflectionProbeData;
|
||||
|
||||
@@ -81,7 +81,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
|
||||
}
|
||||
|
||||
// apply exposure setting
|
||||
specular *= pow(2.0, SceneSrg::m_iblExposure);
|
||||
specular *= pow(2.0, ObjectSrg::m_exposure);
|
||||
|
||||
PSOutput OUT;
|
||||
OUT.m_color = float4(specular, 1.0f);
|
||||
|
||||
+1
@@ -17,6 +17,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
float3 m_outerObbHalfLengths;
|
||||
float3 m_innerObbHalfLengths;
|
||||
bool m_useParallaxCorrection;
|
||||
float m_exposure;
|
||||
TextureCube m_reflectionCubeMap;
|
||||
|
||||
float4x4 GetWorldMatrix()
|
||||
|
||||
@@ -104,7 +104,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
|
||||
blendWeight /= max(1.0f, blendWeightAllProbes);
|
||||
|
||||
// apply exposure setting
|
||||
specular *= pow(2.0, SceneSrg::m_iblExposure);
|
||||
specular *= pow(2.0, ObjectSrg::m_exposure);
|
||||
|
||||
// apply blend weight for additive blending
|
||||
specular *= blendWeight;
|
||||
|
||||
+2
@@ -39,6 +39,8 @@ namespace AZ
|
||||
bool IsCubeMapReferenced(const AZStd::string& relativePath) override;
|
||||
bool IsValidProbeHandle(const ReflectionProbeHandle& probe) const override { return (probe.get() != nullptr); }
|
||||
void ShowProbeVisualization(const ReflectionProbeHandle& probe, bool showVisualization) override;
|
||||
void SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) override;
|
||||
void SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) override;
|
||||
|
||||
// FeatureProcessor overrides
|
||||
void Activate() override;
|
||||
|
||||
+2
@@ -50,6 +50,8 @@ namespace AZ
|
||||
virtual bool IsCubeMapReferenced(const AZStd::string& relativePath) = 0;
|
||||
virtual bool IsValidProbeHandle(const ReflectionProbeHandle& probe) const = 0;
|
||||
virtual void ShowProbeVisualization(const ReflectionProbeHandle& probe, bool showVisualization) = 0;
|
||||
virtual void SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) = 0;
|
||||
virtual void SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) = 0;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -1178,6 +1178,9 @@ namespace AZ
|
||||
AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection"));
|
||||
AZ_Error("MeshDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
|
||||
|
||||
AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure"));
|
||||
AZ_Error("MeshDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
|
||||
|
||||
// retrieve probe cubemap index
|
||||
Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap");
|
||||
RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = m_shaderResourceGroup->FindShaderInputImageIndex(reflectionCubeMapImageName);
|
||||
@@ -1198,6 +1201,7 @@ namespace AZ
|
||||
m_shaderResourceGroup->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths());
|
||||
m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, true);
|
||||
m_shaderResourceGroup->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection());
|
||||
m_shaderResourceGroup->SetConstant(exposureConstantIndex, reflectionProbes[0]->GetRenderExposure());
|
||||
|
||||
m_shaderResourceGroup->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage());
|
||||
}
|
||||
|
||||
@@ -46,7 +46,11 @@ namespace AZ
|
||||
|
||||
void BlendColorGradingLutsPass::InitializeShaderVariant()
|
||||
{
|
||||
AZ_Assert(m_shader != nullptr, "BlendColorGradingLutsPass %s has a null shader when calling InitializeShaderVariant.", GetPathName().GetCStr());
|
||||
if (m_shader == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "BlendColorGradingLutsPass %s has a null shader when calling InitializeShaderVariant.", GetPathName().GetCStr());
|
||||
return;
|
||||
}
|
||||
|
||||
// Total variations is MaxBlendLuts plus one for the fallback case that none of the LUTs are found,
|
||||
// and hence zero LUTs are blended resulting in an identity LUT.
|
||||
|
||||
@@ -120,15 +120,17 @@ namespace AZ
|
||||
m_scene->RemoveRenderPipeline(m_environmentCubeMapPipelineId);
|
||||
m_environmentCubeMapPass = nullptr;
|
||||
|
||||
// restore exposure
|
||||
sceneSrg->SetConstant(m_iblExposureConstantIndex, m_previousExposure);
|
||||
// restore exposures
|
||||
sceneSrg->SetConstant(m_globalIblExposureConstantIndex, m_previousGlobalIblExposure);
|
||||
sceneSrg->SetConstant(m_skyBoxExposureConstantIndex, m_previousSkyBoxExposure);
|
||||
|
||||
m_buildingCubeMap = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set exposure to 0.0 while baking the cubemap
|
||||
sceneSrg->SetConstant(m_iblExposureConstantIndex, 0.0f);
|
||||
// set exposures to the user specified value while baking the cubemap
|
||||
sceneSrg->SetConstant(m_globalIblExposureConstantIndex, m_bakeExposure);
|
||||
sceneSrg->SetConstant(m_skyBoxExposureConstantIndex, m_bakeExposure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +164,7 @@ namespace AZ
|
||||
m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths());
|
||||
m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths());
|
||||
m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection);
|
||||
m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure);
|
||||
m_renderOuterSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage);
|
||||
m_renderOuterSrg->Compile();
|
||||
|
||||
@@ -172,6 +175,7 @@ namespace AZ
|
||||
m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths());
|
||||
m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths());
|
||||
m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection);
|
||||
m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure);
|
||||
m_renderInnerSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage);
|
||||
m_renderInnerSrg->Compile();
|
||||
|
||||
@@ -303,9 +307,10 @@ namespace AZ
|
||||
const RPI::Ptr<RPI::ParentPass>& rootPass = environmentCubeMapPipeline->GetRootPass();
|
||||
rootPass->AddChild(m_environmentCubeMapPass);
|
||||
|
||||
// store the current IBL exposure value
|
||||
// store the current IBL exposure values
|
||||
Data::Instance<RPI::ShaderResourceGroup> sceneSrg = m_scene->GetShaderResourceGroup();
|
||||
m_previousExposure = sceneSrg->GetConstant<float>(m_iblExposureConstantIndex);
|
||||
m_previousGlobalIblExposure = sceneSrg->GetConstant<float>(m_globalIblExposureConstantIndex);
|
||||
m_previousSkyBoxExposure = sceneSrg->GetConstant<float>(m_skyBoxExposureConstantIndex);
|
||||
|
||||
m_scene->AddRenderPipeline(environmentCubeMapPipeline);
|
||||
}
|
||||
@@ -326,6 +331,17 @@ namespace AZ
|
||||
m_meshFeatureProcessor->SetVisible(m_visualizationMeshHandle, showVisualization);
|
||||
}
|
||||
|
||||
void ReflectionProbe::SetRenderExposure(float renderExposure)
|
||||
{
|
||||
m_renderExposure = renderExposure;
|
||||
m_updateSrg = true;
|
||||
}
|
||||
|
||||
void ReflectionProbe::SetBakeExposure(float bakeExposure)
|
||||
{
|
||||
m_bakeExposure = bakeExposure;
|
||||
}
|
||||
|
||||
const RHI::DrawPacket* ReflectionProbe::BuildDrawPacket(
|
||||
const Data::Instance<RPI::ShaderResourceGroup>& srg,
|
||||
const RPI::Ptr<RPI::PipelineStateForDraw>& pipelineState,
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace AZ
|
||||
RHI::ShaderInputNameIndex m_outerObbHalfLengthsRenderConstantIndex = "m_outerObbHalfLengths";
|
||||
RHI::ShaderInputNameIndex m_innerObbHalfLengthsRenderConstantIndex = "m_innerObbHalfLengths";
|
||||
RHI::ShaderInputNameIndex m_useParallaxCorrectionRenderConstantIndex = "m_useParallaxCorrection";
|
||||
RHI::ShaderInputNameIndex m_exposureConstantIndex = "m_exposure";
|
||||
RHI::ShaderInputNameIndex m_reflectionCubeMapRenderImageIndex = "m_reflectionCubeMap";
|
||||
};
|
||||
|
||||
@@ -106,6 +107,14 @@ namespace AZ
|
||||
// enables or disables rendering of the visualization sphere
|
||||
void ShowVisualization(bool showVisualization);
|
||||
|
||||
// the exposure to use when rendering meshes with this probe's cubemap
|
||||
void SetRenderExposure(float renderExposure);
|
||||
float GetRenderExposure() const { return m_renderExposure; }
|
||||
|
||||
// the exposure to use when baking the probe cubemap
|
||||
void SetBakeExposure(float bakeExposure);
|
||||
float GetBakeExposure() const { return m_bakeExposure; }
|
||||
|
||||
private:
|
||||
|
||||
AZ_DISABLE_COPY_MOVE(ReflectionProbe);
|
||||
@@ -157,6 +166,8 @@ namespace AZ
|
||||
RHI::ConstPtr<RHI::DrawPacket> m_blendWeightDrawPacket;
|
||||
RHI::ConstPtr<RHI::DrawPacket> m_renderOuterDrawPacket;
|
||||
RHI::ConstPtr<RHI::DrawPacket> m_renderInnerDrawPacket;
|
||||
float m_renderExposure = 0.0f;
|
||||
float m_bakeExposure = 0.0f;
|
||||
bool m_updateSrg = false;
|
||||
|
||||
const RHI::DrawItemSortKey InvalidSortKey = static_cast<RHI::DrawItemSortKey>(-1);
|
||||
@@ -169,8 +180,10 @@ namespace AZ
|
||||
RPI::Ptr<RPI::EnvironmentCubeMapPass> m_environmentCubeMapPass = nullptr;
|
||||
RPI::RenderPipelineId m_environmentCubeMapPipelineId;
|
||||
BuildCubeMapCallback m_callback;
|
||||
RHI::ShaderInputNameIndex m_iblExposureConstantIndex = "m_iblExposure";
|
||||
float m_previousExposure = 0.0f;
|
||||
RHI::ShaderInputNameIndex m_globalIblExposureConstantIndex = "m_iblExposure";
|
||||
RHI::ShaderInputNameIndex m_skyBoxExposureConstantIndex = "m_cubemapExposure";
|
||||
float m_previousGlobalIblExposure = 0.0f;
|
||||
float m_previousSkyBoxExposure = 0.0f;
|
||||
bool m_buildingCubeMap = false;
|
||||
};
|
||||
|
||||
|
||||
+18
-1
@@ -283,6 +283,18 @@ namespace AZ
|
||||
probe->ShowVisualization(showVisualization);
|
||||
}
|
||||
|
||||
void ReflectionProbeFeatureProcessor::SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure)
|
||||
{
|
||||
AZ_Assert(probe.get(), "SetRenderExposure called with an invalid handle");
|
||||
probe->SetRenderExposure(renderExposure);
|
||||
}
|
||||
|
||||
void ReflectionProbeFeatureProcessor::SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure)
|
||||
{
|
||||
AZ_Assert(probe.get(), "SetBakeExposure called with an invalid handle");
|
||||
probe->SetBakeExposure(bakeExposure);
|
||||
}
|
||||
|
||||
void ReflectionProbeFeatureProcessor::FindReflectionProbes(const Vector3& position, ReflectionProbeVector& reflectionProbes)
|
||||
{
|
||||
reflectionProbes.clear();
|
||||
@@ -431,7 +443,12 @@ namespace AZ
|
||||
{
|
||||
// load shader
|
||||
shader = RPI::LoadCriticalShader(filePath);
|
||||
AZ_Error("ReflectionProbeFeatureProcessor", shader, "Failed to find asset for shader [%s]", filePath);
|
||||
|
||||
if (shader == nullptr)
|
||||
{
|
||||
AZ_Error("ReflectionProbeFeatureProcessor", false, "Failed to find asset for shader [%s]", filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// store drawlist tag
|
||||
drawListTag = shader->GetDrawListTag();
|
||||
|
||||
@@ -75,6 +75,9 @@ namespace AZ
|
||||
//! Return True if the swap chain prefers exclusive full screen mode and a transition happened, false otherwise.
|
||||
virtual bool SetExclusiveFullScreenState([[maybe_unused]]bool fullScreenState) { return false; }
|
||||
|
||||
//! Recreate the swapchain if it becomes invalid during presenting. This should happen at the end of the frame
|
||||
//! due to images being used as attachments in the frame graph.
|
||||
virtual void ProcessRecreation() {};
|
||||
protected:
|
||||
SwapChain();
|
||||
|
||||
@@ -98,6 +101,14 @@ namespace AZ
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Shutdown and clear all the images.
|
||||
void ShutdownImages();
|
||||
|
||||
//! Initialized all the images.
|
||||
ResultCode InitImages();
|
||||
|
||||
//! Flag indicating if swapchain recreation is needed at the end of the frame.
|
||||
bool m_pendingRecreation = false;
|
||||
private:
|
||||
|
||||
bool ValidateDescriptor(const SwapChainDescriptor& descriptor) const;
|
||||
|
||||
@@ -134,7 +134,6 @@ namespace AZ
|
||||
m_scopeAttachmentLookup.clear();
|
||||
m_imageAttachments.clear();
|
||||
m_bufferAttachments.clear();
|
||||
m_swapChainAttachments.clear();
|
||||
m_importedImageAttachments.clear();
|
||||
m_importedBufferAttachments.clear();
|
||||
m_transientImageAttachments.clear();
|
||||
@@ -153,6 +152,13 @@ namespace AZ
|
||||
delete attachment;
|
||||
}
|
||||
m_attachments.clear();
|
||||
|
||||
for (auto swapchainAttachment : m_swapChainAttachments)
|
||||
{
|
||||
swapchainAttachment->GetSwapChain()->ProcessRecreation();
|
||||
}
|
||||
|
||||
m_swapChainAttachments.clear();
|
||||
}
|
||||
|
||||
ImageDescriptor FrameGraphAttachmentDatabase::GetImageDescriptor(const AttachmentId& attachmentId) const
|
||||
|
||||
@@ -58,43 +58,68 @@ namespace AZ
|
||||
// Overwrite descriptor dimensions with the native ones (the ones assigned by the platform) returned by InitInternal.
|
||||
m_descriptor.m_dimensions = nativeDimensions;
|
||||
|
||||
m_images.reserve(m_descriptor.m_dimensions.m_imageCount);
|
||||
resultCode = InitImages();
|
||||
}
|
||||
|
||||
for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx)
|
||||
{
|
||||
m_images.emplace_back(RHI::Factory::Get().CreateImage());
|
||||
}
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
InitImageRequest request;
|
||||
void SwapChain::ShutdownImages()
|
||||
{
|
||||
// Shutdown existing set of images.
|
||||
uint32_t imageSize = aznumeric_cast<uint32_t>(m_images.size());
|
||||
for (uint32_t imageIdx = 0; imageIdx < imageSize; ++imageIdx)
|
||||
{
|
||||
m_images[imageIdx]->Shutdown();
|
||||
}
|
||||
|
||||
RHI::ImageDescriptor& imageDescriptor = request.m_descriptor;
|
||||
imageDescriptor.m_dimension = RHI::ImageDimension::Image2D;
|
||||
imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color;
|
||||
imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth;
|
||||
imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight;
|
||||
imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat;
|
||||
m_images.clear();
|
||||
}
|
||||
|
||||
for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx)
|
||||
{
|
||||
request.m_image = m_images[imageIdx].get();
|
||||
request.m_imageIndex = imageIdx;
|
||||
ResultCode SwapChain::InitImages()
|
||||
{
|
||||
ResultCode resultCode = ResultCode::Success;
|
||||
|
||||
resultCode = ImagePoolBase::InitImage(
|
||||
request.m_image,
|
||||
imageDescriptor,
|
||||
[this, &request]()
|
||||
m_images.reserve(m_descriptor.m_dimensions.m_imageCount);
|
||||
|
||||
// If the new display mode has more buffers, add them.
|
||||
for (uint32_t i = 0; i < m_descriptor.m_dimensions.m_imageCount; ++i)
|
||||
{
|
||||
m_images.emplace_back(RHI::Factory::Get().CreateImage());
|
||||
}
|
||||
|
||||
InitImageRequest request;
|
||||
|
||||
RHI::ImageDescriptor& imageDescriptor = request.m_descriptor;
|
||||
imageDescriptor.m_dimension = RHI::ImageDimension::Image2D;
|
||||
imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color;
|
||||
imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth;
|
||||
imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight;
|
||||
imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat;
|
||||
|
||||
for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx)
|
||||
{
|
||||
request.m_image = m_images[imageIdx].get();
|
||||
request.m_imageIndex = imageIdx;
|
||||
|
||||
resultCode = ImagePoolBase::InitImage(
|
||||
request.m_image, imageDescriptor,
|
||||
[this, &request]()
|
||||
{
|
||||
return InitImageInternal(request);
|
||||
});
|
||||
|
||||
if (resultCode != ResultCode::Success)
|
||||
{
|
||||
Shutdown();
|
||||
break;
|
||||
}
|
||||
if (resultCode != ResultCode::Success)
|
||||
{
|
||||
AZ_Error("Swapchain", false, "Failed to initialize images.");
|
||||
Shutdown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the current index back to 0 so we match the platform swap chain.
|
||||
m_currentImageIndex = 0;
|
||||
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
@@ -105,63 +130,15 @@ namespace AZ
|
||||
}
|
||||
|
||||
ResultCode SwapChain::Resize(const RHI::SwapChainDimensions& dimensions)
|
||||
{
|
||||
// Shutdown existing set of images.
|
||||
for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx)
|
||||
{
|
||||
m_images[imageIdx]->Shutdown();
|
||||
}
|
||||
{
|
||||
ShutdownImages();
|
||||
|
||||
SwapChainDimensions nativeDimensions = dimensions;
|
||||
ResultCode resultCode = ResizeInternal(dimensions, &nativeDimensions);
|
||||
if (resultCode == ResultCode::Success)
|
||||
{
|
||||
m_descriptor.m_dimensions = nativeDimensions;
|
||||
m_images.reserve(m_descriptor.m_dimensions.m_imageCount);
|
||||
|
||||
// If the new display mode has more buffers, add them.
|
||||
while (m_images.size() < static_cast<size_t>(m_descriptor.m_dimensions.m_imageCount))
|
||||
{
|
||||
m_images.emplace_back(RHI::Factory::Get().CreateImage());
|
||||
}
|
||||
|
||||
// If it has fewer, trim down.
|
||||
while (m_images.size() > static_cast<size_t>(m_descriptor.m_dimensions.m_imageCount))
|
||||
{
|
||||
m_images.pop_back();
|
||||
}
|
||||
|
||||
InitImageRequest request;
|
||||
|
||||
RHI::ImageDescriptor& imageDescriptor = request.m_descriptor;
|
||||
imageDescriptor.m_dimension = RHI::ImageDimension::Image2D;
|
||||
imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color;
|
||||
imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth;
|
||||
imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight;
|
||||
imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat;
|
||||
|
||||
for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx)
|
||||
{
|
||||
request.m_image = m_images[imageIdx].get();
|
||||
request.m_imageIndex = imageIdx;
|
||||
|
||||
resultCode = ImagePoolBase::InitImage(
|
||||
request.m_image,
|
||||
imageDescriptor,
|
||||
[this, &request]()
|
||||
{
|
||||
return InitImageInternal(request);
|
||||
});
|
||||
|
||||
if (resultCode != ResultCode::Success)
|
||||
{
|
||||
Shutdown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the current index back to 0 so we match the platform swap chain.
|
||||
m_currentImageIndex = 0;
|
||||
resultCode = InitImages();
|
||||
}
|
||||
|
||||
return resultCode;
|
||||
@@ -188,7 +165,7 @@ namespace AZ
|
||||
|
||||
uint32_t SwapChain::GetImageCount() const
|
||||
{
|
||||
return static_cast<uint32_t>(m_images.size());
|
||||
return aznumeric_cast<uint32_t>(m_images.size());
|
||||
}
|
||||
|
||||
uint32_t SwapChain::GetCurrentImageIndex() const
|
||||
@@ -209,8 +186,18 @@ namespace AZ
|
||||
void SwapChain::Present()
|
||||
{
|
||||
AZ_TRACE_METHOD();
|
||||
m_currentImageIndex = PresentInternal();
|
||||
AZ_Assert(m_currentImageIndex < m_images.size(), "Invalid image index");
|
||||
// Due to swapchain recreation, the images are refreshed.
|
||||
// There is no need to present swapchain for this frame.
|
||||
const uint32_t imageCount = aznumeric_cast<uint32_t>(m_images.size());
|
||||
if (imageCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentImageIndex = PresentInternal();
|
||||
AZ_Assert(m_currentImageIndex < imageCount, "Invalid image index");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,19 @@ namespace AZ
|
||||
m_swapChainBarrier.m_isValid = true;
|
||||
}
|
||||
|
||||
void SwapChain::ProcessRecreation()
|
||||
{
|
||||
if (m_pendingRecreation)
|
||||
{
|
||||
ShutdownImages();
|
||||
InvalidateNativeSwapChain();
|
||||
CreateSwapchain();
|
||||
InitImages();
|
||||
|
||||
m_pendingRecreation = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SwapChain::SetVerticalSyncIntervalInternal(uint32_t previousVsyncInterval)
|
||||
{
|
||||
if (GetDescriptor().m_verticalSyncInterval == 0 || previousVsyncInterval == 0)
|
||||
@@ -231,8 +244,7 @@ namespace AZ
|
||||
// VK_SUBOPTIMAL_KHR is treated as success, but we better update the surface info as well.
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
{
|
||||
InvalidateNativeSwapChain();
|
||||
CreateSwapchain();
|
||||
m_pendingRecreation = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -246,18 +258,16 @@ namespace AZ
|
||||
}
|
||||
};
|
||||
|
||||
m_presentationQueue->QueueCommand(AZStd::move(presentCommand));
|
||||
|
||||
uint32_t acquiredImageIndex = GetCurrentImageIndex();
|
||||
RHI::ResultCode result = AcquireNewImage(&acquiredImageIndex);
|
||||
if (result == RHI::ResultCode::Fail)
|
||||
{
|
||||
InvalidateNativeSwapChain();
|
||||
CreateSwapchain();
|
||||
m_pendingRecreation = true;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_presentationQueue->QueueCommand(AZStd::move(presentCommand));
|
||||
return acquiredImageIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace AZ
|
||||
|
||||
void QueueBarrier(const VkPipelineStageFlags src, const VkPipelineStageFlags dst, const VkImageMemoryBarrier& imageBarrier);
|
||||
|
||||
void ProcessRecreation() override;
|
||||
private:
|
||||
SwapChain() = default;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace AZ
|
||||
static constexpr const char UvGroupName[] = "uvSets";
|
||||
|
||||
class MaterialAsset;
|
||||
class MaterialAssetCreator;
|
||||
|
||||
//! This is a simple data structure for serializing in/out material source files.
|
||||
class MaterialSourceData final
|
||||
@@ -78,15 +79,33 @@ namespace AZ
|
||||
|
||||
//! Creates a MaterialAsset from the MaterialSourceData content.
|
||||
//! @param assetId ID for the MaterialAsset
|
||||
//! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for resolving file-relative paths.
|
||||
//! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for
|
||||
//! resolving file-relative paths.
|
||||
//! @param elevateWarnings Indicates whether to treat warnings as errors
|
||||
//! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file
|
||||
Outcome<Data::Asset<MaterialAsset>> CreateMaterialAsset(
|
||||
Data::AssetId assetId,
|
||||
AZStd::string_view materialSourceFilePath = "",
|
||||
bool elevateWarnings = true,
|
||||
bool includeMaterialPropertyNames = true
|
||||
) const;
|
||||
bool includeMaterialPropertyNames = true) const;
|
||||
|
||||
//! Creates a MaterialAsset from the MaterialSourceData content.
|
||||
//! @param assetId ID for the MaterialAsset
|
||||
//! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for
|
||||
//! resolving file-relative paths.
|
||||
//! @param elevateWarnings Indicates whether to treat warnings as errors
|
||||
//! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file
|
||||
//! @param sourceDependencies if not null, will be populated with a set of all of the loaded material and material type paths
|
||||
Outcome<Data::Asset<MaterialAsset>> CreateMaterialAssetFromSourceData(
|
||||
Data::AssetId assetId,
|
||||
AZStd::string_view materialSourceFilePath = "",
|
||||
bool elevateWarnings = true,
|
||||
bool includeMaterialPropertyNames = true,
|
||||
AZStd::unordered_set<AZStd::string>* sourceDependencies = nullptr) const;
|
||||
|
||||
private:
|
||||
void ApplyPropertiesToAssetCreator(
|
||||
AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const;
|
||||
};
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -97,8 +97,7 @@ namespace AZ
|
||||
// SystemTickBus::OnTick
|
||||
void OnSystemTick() override;
|
||||
|
||||
// Fill system time and game time information for simulation or rendering
|
||||
void FillTickTimeInfo();
|
||||
float GetCurrentTime();
|
||||
|
||||
// The set of core asset handlers registered by the system.
|
||||
AZStd::vector<AZStd::unique_ptr<Data::AssetHandler>> m_assetHandlers;
|
||||
@@ -124,7 +123,8 @@ namespace AZ
|
||||
// The job policy used for feature processor's rendering prepare
|
||||
RHI::JobPolicy m_prepareRenderJobPolicy = RHI::JobPolicy::Parallel;
|
||||
|
||||
TickTimeInfo m_tickTime;
|
||||
ScriptTimePoint m_startTime;
|
||||
float m_currentSimulationTime = 0.0f;
|
||||
|
||||
RPISystemDescriptor m_descriptor;
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace AZ
|
||||
namespace RPI
|
||||
{
|
||||
class Scene;
|
||||
struct TickTimeInfo;
|
||||
class ShaderResourceGroup;
|
||||
class AnyAsset;
|
||||
class WindowContext;
|
||||
@@ -203,7 +202,7 @@ namespace AZ
|
||||
void OnRemovedFromScene(Scene* scene);
|
||||
|
||||
// Called when this pipeline is about to be rendered
|
||||
void OnStartFrame(const TickTimeInfo& tick);
|
||||
void OnStartFrame(float time);
|
||||
|
||||
// Called when the rendering of current frame is finished.
|
||||
void OnFrameEnd();
|
||||
|
||||
@@ -48,14 +48,6 @@ namespace AZ
|
||||
// Callback function to modify values of a ShaderResourceGroup
|
||||
using ShaderResourceGroupCallback = AZStd::function<void(ShaderResourceGroup*)>;
|
||||
|
||||
//! A structure for ticks which contains system time and game time.
|
||||
struct TickTimeInfo
|
||||
{
|
||||
float m_currentGameTime;
|
||||
float m_gameDeltaTime = 0;
|
||||
};
|
||||
|
||||
|
||||
class Scene final
|
||||
: public SceneRequestBus::Handler
|
||||
{
|
||||
@@ -179,12 +171,14 @@ namespace AZ
|
||||
|
||||
// Cpu simulation which runs all active FeatureProcessor Simulate() functions.
|
||||
// @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's simulation.
|
||||
void Simulate(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy);
|
||||
// @param simulationTime the number of seconds since the application started
|
||||
void Simulate(RHI::JobPolicy jobPolicy, float simulationTime);
|
||||
|
||||
// Collect DrawPackets from FeatureProcessors
|
||||
// @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's
|
||||
// PrepareRender.
|
||||
void PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy);
|
||||
// @param simulationTime the number of seconds since the application started; this is the same time value that was passed to Simulate()
|
||||
void PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime);
|
||||
|
||||
// Function called when the current frame is finished rendering.
|
||||
void OnFrameEnd();
|
||||
@@ -267,6 +261,7 @@ namespace AZ
|
||||
// Registry which allocates draw filter tag for RenderPipeline
|
||||
RHI::Ptr<RHI::DrawFilterTagRegistry> m_drawFilterTagRegistry;
|
||||
|
||||
RHI::ShaderInputConstantIndex m_timeInputIndex;
|
||||
float m_simulationTime;
|
||||
};
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace AZ
|
||||
|
||||
ResetIssueCounts(); // Because the asset creator can be used multiple times
|
||||
|
||||
m_asset = Data::AssetManager::Instance().CreateAsset<AssetDataT>(assetId, AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
m_asset = Data::Asset<AssetDataT>(assetId, aznew AssetDataT, AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
m_beginCalled = true;
|
||||
|
||||
if (!m_asset)
|
||||
@@ -138,6 +138,7 @@ namespace AZ
|
||||
}
|
||||
else
|
||||
{
|
||||
Data::AssetManager::Instance().AssignAssetData(m_asset);
|
||||
result = AZStd::move(m_asset);
|
||||
success = true;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,10 @@ namespace AZ
|
||||
}
|
||||
else if (!m_luaSourceFile.empty())
|
||||
{
|
||||
auto loadOutcome = RPI::AssetUtils::LoadAsset<ScriptAsset>(materialTypeSourceFilePath, m_luaSourceFile);
|
||||
// The sub ID for script assets must be explicit.
|
||||
// LUA source files output a compiled as well as an uncompiled asset, sub Ids of 1 and 2.
|
||||
auto loadOutcome =
|
||||
RPI::AssetUtils::LoadAsset<ScriptAsset>(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId);
|
||||
if (!loadOutcome)
|
||||
{
|
||||
AZ_Error("LuaMaterialFunctorSourceData", false, "Could not load script file '%s'", m_luaSourceFile.c_str());
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAssetCreator.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
|
||||
@@ -126,7 +127,8 @@ namespace AZ
|
||||
return changesWereApplied ? ApplyVersionUpdatesResult::UpdatesApplied : ApplyVersionUpdatesResult::NoUpdates;
|
||||
}
|
||||
|
||||
Outcome<Data::Asset<MaterialAsset> > MaterialSourceData::CreateMaterialAsset(Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
|
||||
Outcome<Data::Asset<MaterialAsset>> MaterialSourceData::CreateMaterialAsset(
|
||||
Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const
|
||||
{
|
||||
MaterialAssetCreator materialAssetCreator;
|
||||
materialAssetCreator.SetElevateWarnings(elevateWarnings);
|
||||
@@ -172,66 +174,7 @@ namespace AZ
|
||||
materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames);
|
||||
}
|
||||
|
||||
for (auto& group : m_properties)
|
||||
{
|
||||
for (auto& property : group.second)
|
||||
{
|
||||
MaterialPropertyId propertyId{ group.first, property.first };
|
||||
if (!property.second.m_value.IsValid())
|
||||
{
|
||||
AZ_Warning("Material source data", false, "Source data for material property value is invalid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex = materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName());
|
||||
if (propertyIndex.IsValid())
|
||||
{
|
||||
const MaterialPropertyDescriptor* propertyDescriptor = materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex);
|
||||
switch (propertyDescriptor->GetDataType())
|
||||
{
|
||||
case MaterialPropertyDataType::Image:
|
||||
{
|
||||
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
|
||||
|
||||
if (imageAssetResult.IsSuccess())
|
||||
{
|
||||
auto& imageAsset = imageAssetResult.GetValue();
|
||||
// Load referenced images when load material
|
||||
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.second.m_value.GetValue<AZStd::string>().data());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MaterialPropertyDataType::Enum:
|
||||
{
|
||||
AZ::Name enumName = AZ::Name(property.second.m_value.GetValue<AZStd::string>());
|
||||
uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
|
||||
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
|
||||
{
|
||||
materialAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportWarning("Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath);
|
||||
|
||||
Data::Asset<MaterialAsset> material;
|
||||
if (materialAssetCreator.End(material))
|
||||
@@ -244,5 +187,183 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
Outcome<Data::Asset<MaterialAsset>> MaterialSourceData::CreateMaterialAssetFromSourceData(
|
||||
Data::AssetId assetId,
|
||||
AZStd::string_view materialSourceFilePath,
|
||||
bool elevateWarnings,
|
||||
bool includeMaterialPropertyNames,
|
||||
AZStd::unordered_set<AZStd::string>* sourceDependencies) const
|
||||
{
|
||||
const auto materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType);
|
||||
const auto materialTypeAssetId = AssetUtils::MakeAssetId(materialTypeSourcePath, 0);
|
||||
if (!materialTypeAssetId.IsSuccess())
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "Failed to create material type asset ID: '%s'.", materialTypeSourcePath.c_str());
|
||||
return Failure();
|
||||
}
|
||||
|
||||
MaterialTypeSourceData materialTypeSourceData;
|
||||
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData))
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "Failed to load MaterialTypeSourceData: '%s'.", materialTypeSourcePath.c_str());
|
||||
return Failure();
|
||||
}
|
||||
|
||||
materialTypeSourceData.ResolveUvEnums();
|
||||
|
||||
const auto materialTypeAsset =
|
||||
materialTypeSourceData.CreateMaterialTypeAsset(materialTypeAssetId.GetValue(), materialTypeSourcePath, elevateWarnings);
|
||||
if (!materialTypeAsset.IsSuccess())
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "Failed to create material type asset from source data: '%s'.", materialTypeSourcePath.c_str());
|
||||
return Failure();
|
||||
}
|
||||
|
||||
// Track all of the material and material type assets loaded while trying to create a material asset from source data. This will
|
||||
// be used for evaluating circular dependencies and returned for external monitoring or other use.
|
||||
AZStd::unordered_set<AZStd::string> dependencies;
|
||||
dependencies.insert(materialSourceFilePath);
|
||||
dependencies.insert(materialTypeSourcePath);
|
||||
|
||||
// Load and build a stack of MaterialSourceData from all of the parent materials in the hierarchy. Properties from the source
|
||||
// data will be applied in reverse to the asset creator.
|
||||
AZStd::vector<MaterialSourceData> parentSourceDataStack;
|
||||
|
||||
AZStd::string parentSourceRelPath = m_parentMaterial;
|
||||
AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath);
|
||||
while (!parentSourceRelPath.empty())
|
||||
{
|
||||
if (!dependencies.insert(parentSourceAbsPath).second)
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath.data(), parentSourceAbsPath.c_str());
|
||||
return Failure();
|
||||
}
|
||||
|
||||
MaterialSourceData parentSourceData;
|
||||
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData))
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "Failed to load MaterialSourceData for parent material: '%s'.", parentSourceAbsPath.c_str());
|
||||
return Failure();
|
||||
}
|
||||
|
||||
// Make sure that all materials in the hierarchy share the same material type
|
||||
const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0);
|
||||
if (!parentTypeAssetId)
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "Parent material asset ID wasn't found: '%s'.", parentSourceAbsPath.c_str());
|
||||
return Failure();
|
||||
}
|
||||
|
||||
if (parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue())
|
||||
{
|
||||
AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type.");
|
||||
return Failure();
|
||||
}
|
||||
|
||||
// Get the location of the next parent material and push the source data onto the stack
|
||||
parentSourceRelPath = parentSourceData.m_parentMaterial;
|
||||
parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath);
|
||||
parentSourceDataStack.emplace_back(AZStd::move(parentSourceData));
|
||||
}
|
||||
|
||||
// Create the material asset from all the previously loaded source data
|
||||
MaterialAssetCreator materialAssetCreator;
|
||||
materialAssetCreator.SetElevateWarnings(elevateWarnings);
|
||||
materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames);
|
||||
|
||||
while (!parentSourceDataStack.empty())
|
||||
{
|
||||
parentSourceDataStack.back().ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath);
|
||||
parentSourceDataStack.pop_back();
|
||||
}
|
||||
|
||||
ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath);
|
||||
|
||||
Data::Asset<MaterialAsset> material;
|
||||
if (materialAssetCreator.End(material))
|
||||
{
|
||||
if (sourceDependencies)
|
||||
{
|
||||
sourceDependencies->insert(dependencies.begin(), dependencies.end());
|
||||
}
|
||||
|
||||
return Success(material);
|
||||
}
|
||||
|
||||
return Failure();
|
||||
}
|
||||
|
||||
void MaterialSourceData::ApplyPropertiesToAssetCreator(
|
||||
AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const
|
||||
{
|
||||
for (auto& group : m_properties)
|
||||
{
|
||||
for (auto& property : group.second)
|
||||
{
|
||||
MaterialPropertyId propertyId{ group.first, property.first };
|
||||
if (!property.second.m_value.IsValid())
|
||||
{
|
||||
AZ_Warning("Material source data", false, "Source data for material property value is invalid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex =
|
||||
materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName());
|
||||
if (propertyIndex.IsValid())
|
||||
{
|
||||
const MaterialPropertyDescriptor* propertyDescriptor =
|
||||
materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex);
|
||||
switch (propertyDescriptor->GetDataType())
|
||||
{
|
||||
case MaterialPropertyDataType::Image:
|
||||
{
|
||||
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(
|
||||
materialSourceFilePath, property.second.m_value.GetValue<AZStd::string>());
|
||||
|
||||
if (imageAssetResult.IsSuccess())
|
||||
{
|
||||
auto& imageAsset = imageAssetResult.GetValue();
|
||||
// Load referenced images when load material
|
||||
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportError(
|
||||
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
|
||||
property.second.m_value.GetValue<AZStd::string>().data());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MaterialPropertyDataType::Enum:
|
||||
{
|
||||
AZ::Name enumName = AZ::Name(property.second.m_value.GetValue<AZStd::string>());
|
||||
uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName);
|
||||
if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue)
|
||||
{
|
||||
materialAssetCreator.ReportError(
|
||||
"Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr());
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.ReportWarning(
|
||||
"Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -393,11 +393,12 @@ namespace AZ
|
||||
for (const ShaderVariantReferenceData& shaderRef : m_shaderCollection)
|
||||
{
|
||||
const auto& shaderFile = shaderRef.m_shaderFilePath;
|
||||
const auto& shaderAsset = AssetUtils::LoadAsset<ShaderAsset>(materialTypeSourceFilePath, shaderFile, 0);
|
||||
auto shaderAssetResult = AssetUtils::LoadAsset<ShaderAsset>(materialTypeSourceFilePath, shaderFile, 0);
|
||||
|
||||
if (shaderAsset)
|
||||
if (shaderAssetResult)
|
||||
{
|
||||
auto optionsLayout = shaderAsset.GetValue()->GetShaderOptionGroupLayout();
|
||||
auto shaderAsset = shaderAssetResult.GetValue();
|
||||
auto optionsLayout = shaderAsset->GetShaderOptionGroupLayout();
|
||||
ShaderOptionGroup options{ optionsLayout };
|
||||
for (auto& iter : shaderRef.m_shaderOptionValues)
|
||||
{
|
||||
@@ -408,12 +409,11 @@ namespace AZ
|
||||
}
|
||||
|
||||
materialTypeAssetCreator.AddShader(
|
||||
shaderAsset.GetValue(), options.GetShaderVariantId(),
|
||||
shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString<AZ::Name>() : shaderRef.m_shaderTag
|
||||
);
|
||||
shaderAsset, options.GetShaderVariantId(),
|
||||
shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString<AZ::Name>() : shaderRef.m_shaderTag);
|
||||
|
||||
// Gather UV names
|
||||
const ShaderInputContract& shaderInputContract = shaderAsset.GetValue()->GetInputContract();
|
||||
const ShaderInputContract& shaderInputContract = shaderAsset->GetInputContract();
|
||||
for (const ShaderInputContract::StreamChannelInfo& channel : shaderInputContract.m_streamChannels)
|
||||
{
|
||||
const RHI::ShaderSemantic& semantic = channel.m_semantic;
|
||||
@@ -493,15 +493,19 @@ namespace AZ
|
||||
{
|
||||
case MaterialPropertyDataType::Image:
|
||||
{
|
||||
Outcome<Data::Asset<ImageAsset>> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property.m_value.GetValue<AZStd::string>());
|
||||
auto imageAssetResult = MaterialUtils::GetImageAssetReference(
|
||||
materialTypeSourceFilePath, property.m_value.GetValue<AZStd::string>());
|
||||
|
||||
if (imageAssetResult.IsSuccess())
|
||||
if (imageAssetResult)
|
||||
{
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAssetResult.GetValue());
|
||||
auto imageAsset = imageAssetResult.GetValue();
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.m_value.GetValue<AZStd::string>().data());
|
||||
materialTypeAssetCreator.ReportError(
|
||||
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
|
||||
property.m_value.GetValue<AZStd::string>().data());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -136,6 +136,12 @@ namespace AZ
|
||||
RHI::DrawLinear draw = RHI::DrawLinear();
|
||||
draw.m_vertexCount = 3;
|
||||
|
||||
if (m_shader == nullptr)
|
||||
{
|
||||
AZ_Error("PassSystem", false, "[FullscreenTrianglePass]: Shader not loaded!");
|
||||
return;
|
||||
}
|
||||
|
||||
RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
|
||||
|
||||
// [GFX TODO][ATOM-872] The pass should be able to drive the shader variant
|
||||
|
||||
@@ -268,21 +268,23 @@ namespace AZ
|
||||
|
||||
AssetInitBus::Broadcast(&AssetInitBus::Events::PostLoadInit);
|
||||
|
||||
// Update tick time info
|
||||
FillTickTimeInfo();
|
||||
m_currentSimulationTime = GetCurrentTime();
|
||||
|
||||
for (auto& scene : m_scenes)
|
||||
{
|
||||
scene->Simulate(m_tickTime, m_simulationJobPolicy);
|
||||
scene->Simulate(m_simulationJobPolicy, m_currentSimulationTime);
|
||||
}
|
||||
}
|
||||
|
||||
void RPISystem::FillTickTimeInfo()
|
||||
float RPISystem::GetCurrentTime()
|
||||
{
|
||||
AZ::TickRequestBus::BroadcastResult(m_tickTime.m_gameDeltaTime, &AZ::TickRequestBus::Events::GetTickDeltaTime);
|
||||
ScriptTimePoint currentTime;
|
||||
AZ::TickRequestBus::BroadcastResult(currentTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
|
||||
m_tickTime.m_currentGameTime = static_cast<float>(currentTime.GetSeconds());
|
||||
ScriptTimePoint timeAtCurrentTick;
|
||||
AZ::TickRequestBus::BroadcastResult(timeAtCurrentTick, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
|
||||
|
||||
// We subtract the start time to maximize precision of the time value, since we will be converting it to a float.
|
||||
double currentTime = timeAtCurrentTick.GetSeconds() - m_startTime.GetSeconds();
|
||||
|
||||
return aznumeric_cast<float>(currentTime);
|
||||
}
|
||||
|
||||
void RPISystem::RenderTick()
|
||||
@@ -301,7 +303,7 @@ namespace AZ
|
||||
// [GFX TODO] We may parallel scenes' prepare render.
|
||||
for (auto& scenePtr : m_scenes)
|
||||
{
|
||||
scenePtr->PrepareRender(m_tickTime, m_prepareRenderJobPolicy);
|
||||
scenePtr->PrepareRender(m_prepareRenderJobPolicy, m_currentSimulationTime);
|
||||
}
|
||||
|
||||
m_rhiSystem.FrameUpdate(
|
||||
|
||||
@@ -375,7 +375,7 @@ namespace AZ
|
||||
m_scene->RemoveRenderPipeline(m_nameId);
|
||||
}
|
||||
|
||||
void RenderPipeline::OnStartFrame([[maybe_unused]] const TickTimeInfo& tick)
|
||||
void RenderPipeline::OnStartFrame([[maybe_unused]] float time)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace AZ
|
||||
{
|
||||
auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs();
|
||||
scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName());
|
||||
|
||||
// Set value for constants defined in SceneTimeSrg.azsli
|
||||
scene->m_timeInputIndex = scene->m_srg->FindShaderInputConstantIndex(Name{ "m_time" });
|
||||
}
|
||||
|
||||
scene->m_name = sceneDescriptor.m_nameId;
|
||||
@@ -410,11 +413,11 @@ namespace AZ
|
||||
//[GFX TODO]: the completion job should start here
|
||||
}
|
||||
|
||||
void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
|
||||
void Scene::Simulate(RHI::JobPolicy jobPolicy, float simulationTime)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(RPI, "Scene: Simulate");
|
||||
|
||||
m_simulationTime = tickInfo.m_currentGameTime;
|
||||
m_simulationTime = simulationTime;
|
||||
|
||||
// If previous simulation job wasn't done, wait for it to finish.
|
||||
if (m_taskGraphActive)
|
||||
@@ -483,11 +486,9 @@ namespace AZ
|
||||
{
|
||||
if (m_srg)
|
||||
{
|
||||
// Set value for constants defined in SceneTimeSrg.azsli
|
||||
RHI::ShaderInputConstantIndex timeIndex = m_srg->FindShaderInputConstantIndex(Name{ "m_time" });
|
||||
if (timeIndex.IsValid())
|
||||
if (m_timeInputIndex.IsValid())
|
||||
{
|
||||
m_srg->SetConstant(timeIndex, m_simulationTime);
|
||||
m_srg->SetConstant(m_timeInputIndex, m_simulationTime);
|
||||
}
|
||||
|
||||
// signal any handlers to update values for their partial scene srg
|
||||
@@ -620,7 +621,7 @@ namespace AZ
|
||||
WaitAndCleanCompletionJob(finalizeDrawListsCompletion);
|
||||
}
|
||||
|
||||
void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
|
||||
void Scene::PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender");
|
||||
|
||||
@@ -644,7 +645,7 @@ namespace AZ
|
||||
if (pipeline->NeedsRender())
|
||||
{
|
||||
activePipelines.push_back(pipeline);
|
||||
pipeline->OnStartFrame(tickInfo);
|
||||
pipeline->OnStartFrame(simulationTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +188,10 @@ namespace AZ
|
||||
void MaterialTypeAsset::SetReady()
|
||||
{
|
||||
m_status = AssetStatus::Ready;
|
||||
|
||||
// If this was created dynamically using MaterialTypeAssetCreator (which is what calls SetReady()),
|
||||
// we need to connect to the AssetBus for reloads.
|
||||
PostLoadInit();
|
||||
}
|
||||
|
||||
bool MaterialTypeAsset::PostLoadInit()
|
||||
|
||||
@@ -126,8 +126,8 @@ namespace AZ
|
||||
}
|
||||
|
||||
ShaderCollection::Item::Item()
|
||||
: m_renderStatesOverlay(RHI::GetInvalidRenderStates())
|
||||
{
|
||||
m_renderStatesOverlay = RHI::GetInvalidRenderStates();
|
||||
}
|
||||
|
||||
ShaderCollection::Item& ShaderCollection::operator[](size_t i)
|
||||
@@ -156,7 +156,8 @@ namespace AZ
|
||||
}
|
||||
|
||||
ShaderCollection::Item::Item(const Data::Asset<ShaderAsset>& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
|
||||
: m_shaderAsset(shaderAsset)
|
||||
: m_renderStatesOverlay(RHI::GetInvalidRenderStates())
|
||||
, m_shaderAsset(shaderAsset)
|
||||
, m_shaderVariantId(variantId)
|
||||
, m_shaderTag(shaderTag)
|
||||
, m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
|
||||
@@ -164,7 +165,8 @@ namespace AZ
|
||||
}
|
||||
|
||||
ShaderCollection::Item::Item(Data::Asset<ShaderAsset>&& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
|
||||
: m_shaderAsset(AZStd::move(shaderAsset))
|
||||
: m_renderStatesOverlay(RHI::GetInvalidRenderStates())
|
||||
, m_shaderAsset(AZStd::move(shaderAsset))
|
||||
, m_shaderVariantId(variantId)
|
||||
, m_shaderTag(shaderTag)
|
||||
, m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
|
||||
|
||||
+3
-4
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"subsurfaceScattering": {
|
||||
"enableSubsurfaceScattering": true,
|
||||
"influenceMap": "Objects/Lucy/Lucy_thickness.tif",
|
||||
"influenceMap": "TestData/Textures/checker8x8_gray_512.png",
|
||||
"scatterDistance": 15.0,
|
||||
"subsurfaceScatterFactor": 0.4300000071525574,
|
||||
"thicknessMap": "Objects/Lucy/Lucy_thickness.tif",
|
||||
@@ -47,8 +47,7 @@
|
||||
0.3182879388332367,
|
||||
0.16388189792633058,
|
||||
1.0
|
||||
],
|
||||
"useInfluenceMap": false
|
||||
]
|
||||
},
|
||||
"wrinkleLayers": {
|
||||
"baseColorMap1": "TestData/Textures/cc0/Lava004_1K_Color.jpg",
|
||||
@@ -61,4 +60,4 @@
|
||||
"normalMap2": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_normal.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-6
@@ -159,7 +159,7 @@ namespace AtomToolsFramework
|
||||
|
||||
void AtomToolsDocumentSystemComponent::OnDocumentExternallyModified(const AZ::Uuid& documentId)
|
||||
{
|
||||
m_documentIdsToReopen.insert(documentId);
|
||||
m_documentIdsWithExternalChanges.insert(documentId);
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
@@ -168,7 +168,7 @@ namespace AtomToolsFramework
|
||||
|
||||
void AtomToolsDocumentSystemComponent::OnDocumentDependencyModified(const AZ::Uuid& documentId)
|
||||
{
|
||||
m_documentIdsToReopen.insert(documentId);
|
||||
m_documentIdsWithDependencyChanges.insert(documentId);
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
@@ -177,7 +177,7 @@ namespace AtomToolsFramework
|
||||
|
||||
void AtomToolsDocumentSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
for (const AZ::Uuid& documentId : m_documentIdsToReopen)
|
||||
for (const AZ::Uuid& documentId : m_documentIdsWithExternalChanges)
|
||||
{
|
||||
AZStd::string documentPath;
|
||||
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
@@ -191,6 +191,8 @@ namespace AtomToolsFramework
|
||||
continue;
|
||||
}
|
||||
|
||||
m_documentIdsWithDependencyChanges.erase(documentId);
|
||||
|
||||
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
|
||||
|
||||
bool openResult = false;
|
||||
@@ -204,7 +206,7 @@ namespace AtomToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
for (const AZ::Uuid& documentId : m_documentIdsToReopen)
|
||||
for (const AZ::Uuid& documentId : m_documentIdsWithDependencyChanges)
|
||||
{
|
||||
AZStd::string documentPath;
|
||||
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
|
||||
@@ -231,8 +233,8 @@ namespace AtomToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
m_documentIdsToReopen.clear();
|
||||
m_documentIdsToReopen.clear();
|
||||
m_documentIdsWithDependencyChanges.clear();
|
||||
m_documentIdsWithExternalChanges.clear();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -85,8 +85,8 @@ namespace AtomToolsFramework
|
||||
AZStd::intrusive_ptr<AtomToolsDocumentSystemSettings> m_settings;
|
||||
AZStd::function<AtomToolsDocument*()> m_documentCreator;
|
||||
AZStd::unordered_map<AZ::Uuid, AZStd::shared_ptr<AtomToolsDocument>> m_documentMap;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsToRebuild;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsToReopen;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsWithExternalChanges;
|
||||
AZStd::unordered_set<AZ::Uuid> m_documentIdsWithDependencyChanges;
|
||||
const size_t m_maxMessageBoxLineCount = 15;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
|
||||
@@ -567,26 +567,26 @@ namespace MaterialEditor
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialDocument::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID)
|
||||
void MaterialDocument::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid sourceUUID)
|
||||
{
|
||||
if (m_sourceAssetId.m_guid == sourceUUID)
|
||||
auto sourcePath = AZ::RPI::AssetUtils::ResolvePathReference(scanFolder, relativePath);
|
||||
|
||||
if (m_absolutePath == sourcePath)
|
||||
{
|
||||
// ignore notifications caused by saving the open document
|
||||
if (!m_saveTriggeredInternally)
|
||||
{
|
||||
AZ_TracePrintf("MaterialDocument", "Material document changed externally: '%s'.\n", m_absolutePath.c_str());
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
|
||||
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id);
|
||||
}
|
||||
m_saveTriggeredInternally = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialDocument::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (m_dependentAssetIds.find(asset->GetId()) != m_dependentAssetIds.end())
|
||||
else if (m_sourceDependencies.find(sourcePath) != m_sourceDependencies.end())
|
||||
{
|
||||
AZ_TracePrintf("MaterialDocument", "Material document dependency changed: '%s'.\n", m_absolutePath.c_str());
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id);
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
|
||||
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +655,6 @@ namespace MaterialEditor
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sourceAssetId = sourceAssetInfo.m_assetId;
|
||||
m_relativePath = sourceAssetInfo.m_relativePath;
|
||||
if (!AzFramework::StringFunc::Path::Normalize(m_relativePath))
|
||||
{
|
||||
@@ -722,14 +721,15 @@ namespace MaterialEditor
|
||||
// we can create the asset dynamically from the source data.
|
||||
// Long term, the material document should not be concerned with assets at all. The viewport window should be the
|
||||
// only thing concerned with assets or instances.
|
||||
auto createResult = m_materialSourceData.CreateMaterialAsset(Uuid::CreateRandom(), m_absolutePath, true);
|
||||
if (!createResult)
|
||||
auto materialAssetResult =
|
||||
m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true, true, &m_sourceDependencies);
|
||||
if (!materialAssetResult)
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material asset could not be created from source data: '%s'.", m_absolutePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_materialAsset = createResult.GetValue();
|
||||
m_materialAsset = materialAssetResult.GetValue();
|
||||
if (!m_materialAsset.IsReady())
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material asset is not ready: '%s'.", m_absolutePath.c_str());
|
||||
@@ -743,28 +743,35 @@ namespace MaterialEditor
|
||||
return false;
|
||||
}
|
||||
|
||||
// track material type asset to notify when dependencies change
|
||||
m_dependentAssetIds.insert(materialTypeAsset->GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(materialTypeAsset->GetId());
|
||||
|
||||
AZStd::array_view<AZ::RPI::MaterialPropertyValue> parentPropertyValues = materialTypeAsset->GetDefaultPropertyValues();
|
||||
AZ::Data::Asset<MaterialAsset> parentMaterialAsset;
|
||||
if (!m_materialSourceData.m_parentMaterial.empty())
|
||||
{
|
||||
// There is a parent for this material
|
||||
auto parentMaterialResult = AssetUtils::LoadAsset<MaterialAsset>(m_absolutePath, m_materialSourceData.m_parentMaterial);
|
||||
if (!parentMaterialResult)
|
||||
AZ::RPI::MaterialSourceData parentMaterialSourceData;
|
||||
const auto parentMaterialFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial);
|
||||
if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialFilePath, parentMaterialSourceData))
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Parent material asset could not be loaded: '%s'.", m_materialSourceData.m_parentMaterial.c_str());
|
||||
AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", parentMaterialFilePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
parentMaterialAsset = parentMaterialResult.GetValue();
|
||||
parentPropertyValues = parentMaterialAsset->GetPropertyValues();
|
||||
const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(parentMaterialFilePath, 0);
|
||||
if (!parentMaterialAssetIdResult)
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", parentMaterialFilePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// track parent material asset to notify when dependencies change
|
||||
m_dependentAssetIds.insert(parentMaterialAsset->GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(parentMaterialAsset->GetId());
|
||||
auto parentMaterialAssetResult = parentMaterialSourceData.CreateMaterialAssetFromSourceData(
|
||||
parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true);
|
||||
if (!parentMaterialAssetResult)
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
parentMaterialAsset = parentMaterialAssetResult.GetValue();
|
||||
parentPropertyValues = parentMaterialAsset->GetPropertyValues();
|
||||
}
|
||||
|
||||
// Creating a material from a material asset will fail if a texture is referenced but not loaded
|
||||
@@ -913,15 +920,13 @@ namespace MaterialEditor
|
||||
void MaterialDocument::Clear()
|
||||
{
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect();
|
||||
AzToolsFramework::AssetSystemBus::Handler::BusDisconnect();
|
||||
|
||||
m_materialAsset = {};
|
||||
m_materialInstance = {};
|
||||
m_absolutePath.clear();
|
||||
m_relativePath.clear();
|
||||
m_sourceAssetId = {};
|
||||
m_dependentAssetIds.clear();
|
||||
m_sourceDependencies.clear();
|
||||
m_saveTriggeredInternally = {};
|
||||
m_compilePending = {};
|
||||
m_properties.clear();
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace MaterialEditor
|
||||
: public AtomToolsFramework::AtomToolsDocument
|
||||
, public MaterialDocumentRequestBus::Handler
|
||||
, private AZ::TickBus::Handler
|
||||
, private AZ::Data::AssetBus::MultiHandler
|
||||
, private AzToolsFramework::AssetSystemBus::Handler
|
||||
{
|
||||
public:
|
||||
@@ -105,11 +104,6 @@ namespace MaterialEditor
|
||||
void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Data::AssetBus::Router overrides...
|
||||
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const;
|
||||
|
||||
bool OpenInternal(AZStd::string_view loadPath);
|
||||
@@ -137,11 +131,8 @@ namespace MaterialEditor
|
||||
// Material instance being edited
|
||||
AZ::Data::Instance<AZ::RPI::Material> m_materialInstance;
|
||||
|
||||
// Asset used to open document
|
||||
AZ::Data::AssetId m_sourceAssetId;
|
||||
|
||||
// Set of assets that can trigger a document reload
|
||||
AZStd::unordered_set<AZ::Data::AssetId> m_dependentAssetIds;
|
||||
AZStd::unordered_set<AZStd::string> m_sourceDependencies;
|
||||
|
||||
// Track if document saved itself last to skip external modification notification
|
||||
bool m_saveTriggeredInternally = false;
|
||||
|
||||
+20
@@ -40,6 +40,7 @@ namespace AZ
|
||||
->Field("bakedCubeMapQualityLevel", &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel)
|
||||
->Field("bakedCubeMapRelativePath", &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath)
|
||||
->Field("authoredCubeMapAsset", &EditorReflectionProbeComponent::m_authoredCubeMapAsset)
|
||||
->Field("bakeExposure", &EditorReflectionProbeComponent::m_bakeExposure)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
@@ -62,6 +63,13 @@ namespace AZ
|
||||
->Attribute(AZ::Edit::Attributes::ButtonText, "Bake Reflection Probe")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::BakeReflectionProbe)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting)
|
||||
->DataElement(AZ::Edit::UIHandlers::Slider, &EditorReflectionProbeComponent::m_bakeExposure, "Bake Exposure", "Exposure to use when baking the cubemap")
|
||||
->Attribute(AZ::Edit::Attributes::SoftMin, -16.0f)
|
||||
->Attribute(AZ::Edit::Attributes::SoftMax, 16.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Min, -20.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 20.0f)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnBakeExposureChanged)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting)
|
||||
->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap")
|
||||
@@ -111,6 +119,11 @@ namespace AZ
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &ReflectionProbeComponentConfig::m_showVisualization, "Show Visualization", "Show the reflection probe visualization sphere")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->DataElement(AZ::Edit::UIHandlers::Slider, &ReflectionProbeComponentConfig::m_renderExposure, "Exposure", "Exposure to use when rendering meshes with the cubemap")
|
||||
->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f)
|
||||
->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Min, -20.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 20.0f)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -275,6 +288,13 @@ namespace AZ
|
||||
return AZ::Edit::PropertyRefreshLevels::None;
|
||||
}
|
||||
|
||||
AZ::u32 EditorReflectionProbeComponent::OnBakeExposureChanged()
|
||||
{
|
||||
m_controller.SetBakeExposure(m_bakeExposure);
|
||||
|
||||
return AZ::Edit::PropertyRefreshLevels::None;
|
||||
}
|
||||
|
||||
AZ::u32 EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting()
|
||||
{
|
||||
// controls specific to baked cubemaps call this to determine their visibility
|
||||
|
||||
+2
@@ -55,6 +55,7 @@ namespace AZ
|
||||
// change notifications
|
||||
AZ::u32 OnUseBakedCubemapChanged();
|
||||
AZ::u32 OnAuthoredCubemapChanged();
|
||||
AZ::u32 OnBakeExposureChanged();
|
||||
|
||||
// retrieves visibility for baked or authored cubemap controls
|
||||
AZ::u32 GetBakedCubemapVisibilitySetting();
|
||||
@@ -77,6 +78,7 @@ namespace AZ
|
||||
AZStd::string m_bakedCubeMapRelativePath;
|
||||
Data::Asset<RPI::StreamingImageAsset> m_bakedCubeMapAsset;
|
||||
Data::Asset<RPI::StreamingImageAsset> m_authoredCubeMapAsset;
|
||||
float m_bakeExposure = 0.0f;
|
||||
|
||||
// flag indicating if a cubemap bake is currently in progress
|
||||
AZStd::atomic_bool m_bakeInProgress = false;
|
||||
|
||||
+17
-2
@@ -35,7 +35,7 @@ namespace AZ
|
||||
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<ReflectionProbeComponentConfig>()
|
||||
->Version(0)
|
||||
->Version(1)
|
||||
->Field("OuterHeight", &ReflectionProbeComponentConfig::m_outerHeight)
|
||||
->Field("OuterLength", &ReflectionProbeComponentConfig::m_outerLength)
|
||||
->Field("OuterWidth", &ReflectionProbeComponentConfig::m_outerWidth)
|
||||
@@ -49,7 +49,9 @@ namespace AZ
|
||||
->Field("AuthoredCubeMapAsset", &ReflectionProbeComponentConfig::m_authoredCubeMapAsset)
|
||||
->Field("EntityId", &ReflectionProbeComponentConfig::m_entityId)
|
||||
->Field("UseParallaxCorrection", &ReflectionProbeComponentConfig::m_useParallaxCorrection)
|
||||
->Field("ShowVisualization", &ReflectionProbeComponentConfig::m_showVisualization);
|
||||
->Field("ShowVisualization", &ReflectionProbeComponentConfig::m_showVisualization)
|
||||
->Field("RenderExposure", &ReflectionProbeComponentConfig::m_renderExposure)
|
||||
->Field("BakeExposure", &ReflectionProbeComponentConfig::m_bakeExposure);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +159,9 @@ namespace AZ
|
||||
cubeMapAsset.QueueLoad();
|
||||
Data::AssetBus::MultiHandler::BusConnect(cubeMapAsset.GetId());
|
||||
}
|
||||
|
||||
// set cubemap render exposure
|
||||
m_featureProcessor->SetRenderExposure(m_handle, m_configuration.m_renderExposure);
|
||||
}
|
||||
|
||||
void ReflectionProbeComponentController::Deactivate()
|
||||
@@ -284,6 +289,16 @@ namespace AZ
|
||||
m_configuration.m_innerHeight = AZStd::min(m_configuration.m_innerHeight, m_configuration.m_outerHeight);
|
||||
}
|
||||
|
||||
void ReflectionProbeComponentController::SetBakeExposure(float bakeExposure)
|
||||
{
|
||||
if (!m_featureProcessor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_featureProcessor->SetBakeExposure(m_handle, bakeExposure);
|
||||
}
|
||||
|
||||
void ReflectionProbeComponentController::BakeReflectionProbe(BuildCubeMapCallback callback, const AZStd::string& relativePath)
|
||||
{
|
||||
if (!m_featureProcessor)
|
||||
|
||||
+6
@@ -68,6 +68,9 @@ namespace AZ
|
||||
Data::Asset<RPI::StreamingImageAsset> m_bakedCubeMapAsset;
|
||||
Data::Asset<RPI::StreamingImageAsset> m_authoredCubeMapAsset;
|
||||
AZ::u64 m_entityId{ EntityId::InvalidEntityId };
|
||||
|
||||
float m_renderExposure = 0.0f;
|
||||
float m_bakeExposure = 0.0f;
|
||||
};
|
||||
|
||||
class ReflectionProbeComponentController final
|
||||
@@ -99,6 +102,9 @@ namespace AZ
|
||||
// returns the outer extent Aabb for this reflection
|
||||
AZ::Aabb GetAabb() const;
|
||||
|
||||
// set the exposure to use when baking the cubemap
|
||||
void SetBakeExposure(float bakeExposure);
|
||||
|
||||
// initiate the reflection probe bake, invokes callback when complete
|
||||
void BakeReflectionProbe(BuildCubeMapCallback callback, const AZStd::string& relativePath);
|
||||
|
||||
|
||||
@@ -257,6 +257,7 @@ BOOL CUiAnimViewDialog::OnInitDialog()
|
||||
m_wndSplitter->addWidget(m_wndDopeSheet);
|
||||
m_wndSplitter->setStretchFactor(0, 1);
|
||||
m_wndSplitter->setStretchFactor(1, 10);
|
||||
m_wndSplitter->setChildrenCollapsible(false);
|
||||
l->addWidget(m_wndSplitter);
|
||||
w->setLayout(l);
|
||||
setCentralWidget(w);
|
||||
@@ -283,6 +284,11 @@ BOOL CUiAnimViewDialog::OnInitDialog()
|
||||
m_wndCurveEditorDock->setVisible(false);
|
||||
m_wndCurveEditorDock->setEnabled(false);
|
||||
|
||||
// In order to prevent the track editor view from collapsing and becoming invisible, we use the
|
||||
// minimum size of the curve editor for the track editor as well. Since both editors use the same
|
||||
// view widget in the UI animation editor when not in 'Both' mode, the sizes can be identical.
|
||||
m_wndDopeSheet->setMinimumSize(m_wndCurveEditor->minimumSizeHint());
|
||||
|
||||
InitSequences();
|
||||
|
||||
m_lazyInitDone = false;
|
||||
|
||||
@@ -56,6 +56,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||
float m_padding;
|
||||
bool m_useReflectionProbe;
|
||||
bool m_useParallaxCorrection;
|
||||
float m_exposure;
|
||||
};
|
||||
|
||||
ReflectionProbeData m_reflectionProbeData;
|
||||
|
||||
+5
-5
@@ -74,7 +74,7 @@ namespace Terrain
|
||||
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &TerrainSurfaceMaterialsListConfig::m_surfaceMaterials,
|
||||
"Gradient to Material Mappings", "Maps surfaces to materials.");
|
||||
"Material Mappings", "Maps surfaces to materials.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ namespace Terrain
|
||||
{
|
||||
surfaceMaterialMapping.m_active = false;
|
||||
surfaceMaterialMapping.m_materialAsset.QueueLoad();
|
||||
AZ::Data::AssetBus::Handler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace Terrain
|
||||
{
|
||||
if (surfaceMaterialMapping.m_materialAsset.GetId().IsValid())
|
||||
{
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_materialAsset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect(surfaceMaterialMapping.m_materialAsset.GetId());
|
||||
surfaceMaterialMapping.m_materialAsset.Release();
|
||||
surfaceMaterialMapping.m_materialInstance.reset();
|
||||
surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId();
|
||||
@@ -202,7 +202,7 @@ namespace Terrain
|
||||
// Don't disconnect from the AssetBus if this material is mapped more than once.
|
||||
if (CountMaterialIDInstances(surfaceMaterialMapping.m_activeMaterialAssetId) == 1)
|
||||
{
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId);
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId);
|
||||
}
|
||||
|
||||
surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId();
|
||||
@@ -238,7 +238,7 @@ namespace Terrain
|
||||
// All materials have been deactivated, stop listening for requests and notifications.
|
||||
m_cachedAabb = AZ::Aabb::CreateNull();
|
||||
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect();
|
||||
TerrainAreaMaterialRequestBus::Handler::BusConnect(GetEntityId());
|
||||
TerrainAreaMaterialRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ namespace Terrain
|
||||
class TerrainSurfaceMaterialsListComponent
|
||||
: public AZ::Component
|
||||
, private TerrainAreaMaterialRequestBus::Handler
|
||||
, private AZ::Data::AssetBus::Handler
|
||||
, private AZ::Data::AssetBus::MultiHandler
|
||||
, private LmbrCentral::ShapeComponentNotificationsBus::Handler
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -6,15 +6,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
|
||||
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||
|
||||
#include <Components/TerrainLayerSpawnerComponent.h>
|
||||
#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <Terrain/MockTerrain.h>
|
||||
#include <MockAxisAlignedBoxShapeComponent.h>
|
||||
@@ -23,21 +21,12 @@ using ::testing::NiceMock;
|
||||
using ::testing::AtLeast;
|
||||
using ::testing::_;
|
||||
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::AtLeast;
|
||||
using ::testing::_;
|
||||
|
||||
class LayerSpawnerComponentTest
|
||||
: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
AZ::ComponentApplication m_app;
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> m_entity;
|
||||
Terrain::TerrainLayerSpawnerComponent* m_layerSpawnerComponent;
|
||||
UnitTest::MockAxisAlignedBoxShapeComponent* m_shapeComponent;
|
||||
AZStd::unique_ptr<NiceMock<UnitTest::MockTerrainSystemService>> m_terrainSystem;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
@@ -50,78 +39,86 @@ protected:
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_entity.reset();
|
||||
m_terrainSystem.reset();
|
||||
m_app.Destroy();
|
||||
}
|
||||
|
||||
void CreateEntity()
|
||||
AZStd::unique_ptr<AZ::Entity> CreateEntity()
|
||||
{
|
||||
m_entity = AZStd::make_unique<AZ::Entity>();
|
||||
m_entity->Init();
|
||||
auto entity = AZStd::make_unique<AZ::Entity>();
|
||||
entity->Init();
|
||||
|
||||
ASSERT_TRUE(m_entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
void AddLayerSpawnerAndShapeComponentToEntity()
|
||||
Terrain::TerrainLayerSpawnerComponent* AddLayerSpawnerToEntity(AZ::Entity* entity, const Terrain::TerrainLayerSpawnerConfig& config)
|
||||
{
|
||||
AddLayerSpawnerAndShapeComponentToEntity(Terrain::TerrainLayerSpawnerConfig());
|
||||
auto layerSpawnerComponent = entity->CreateComponent<Terrain::TerrainLayerSpawnerComponent>(config);
|
||||
m_app.RegisterComponentDescriptor(layerSpawnerComponent->CreateDescriptor());
|
||||
|
||||
return layerSpawnerComponent;
|
||||
}
|
||||
|
||||
void AddLayerSpawnerAndShapeComponentToEntity(const Terrain::TerrainLayerSpawnerConfig& config)
|
||||
UnitTest::MockAxisAlignedBoxShapeComponent* AddShapeComponentToEntity(AZ::Entity* entity)
|
||||
{
|
||||
m_layerSpawnerComponent = m_entity->CreateComponent<Terrain::TerrainLayerSpawnerComponent>(config);
|
||||
m_app.RegisterComponentDescriptor(m_layerSpawnerComponent->CreateDescriptor());
|
||||
UnitTest::MockAxisAlignedBoxShapeComponent* shapeComponent = entity->CreateComponent<UnitTest::MockAxisAlignedBoxShapeComponent>();
|
||||
m_app.RegisterComponentDescriptor(shapeComponent->CreateDescriptor());
|
||||
|
||||
m_shapeComponent = m_entity->CreateComponent<UnitTest::MockAxisAlignedBoxShapeComponent>();
|
||||
m_app.RegisterComponentDescriptor(m_shapeComponent->CreateDescriptor());
|
||||
|
||||
ASSERT_TRUE(m_layerSpawnerComponent);
|
||||
ASSERT_TRUE(m_shapeComponent);
|
||||
}
|
||||
|
||||
void CreateMockTerrainSystem()
|
||||
{
|
||||
m_terrainSystem = AZStd::make_unique<NiceMock<UnitTest::MockTerrainSystemService>>();
|
||||
return shapeComponent;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, ActivatEntityActivateSuccess)
|
||||
TEST_F(LayerSpawnerComponentTest, ActivateEntityWithoutShapeFails)
|
||||
{
|
||||
CreateEntity();
|
||||
AddLayerSpawnerAndShapeComponentToEntity();
|
||||
auto entity = CreateEntity();
|
||||
|
||||
m_entity->Activate();
|
||||
EXPECT_EQ(m_entity->GetState(), AZ::Entity::State::Active);
|
||||
|
||||
m_entity->Deactivate();
|
||||
AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig());
|
||||
|
||||
const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails();
|
||||
EXPECT_FALSE(sortOutcome.IsSuccess());
|
||||
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, ActivateEntityActivateSuccess)
|
||||
{
|
||||
auto entity = CreateEntity();
|
||||
|
||||
AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig());
|
||||
AddShapeComponentToEntity(entity.get());
|
||||
|
||||
entity->Activate();
|
||||
EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
|
||||
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, LayerSpawnerDefaultValuesCorrect)
|
||||
{
|
||||
CreateEntity();
|
||||
AddLayerSpawnerAndShapeComponentToEntity();
|
||||
auto entity = CreateEntity();
|
||||
AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig());
|
||||
AddShapeComponentToEntity(entity.get());
|
||||
|
||||
m_entity->Activate();
|
||||
entity->Activate();
|
||||
|
||||
AZ::u32 priority = 999, layer = 999;
|
||||
Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority);
|
||||
Terrain::TerrainSpawnerRequestBus::Event(entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority);
|
||||
|
||||
EXPECT_EQ(0, priority);
|
||||
EXPECT_EQ(1, layer);
|
||||
|
||||
bool useGroundPlane = false;
|
||||
|
||||
Terrain::TerrainSpawnerRequestBus::EventResult(useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane);
|
||||
Terrain::TerrainSpawnerRequestBus::EventResult(
|
||||
useGroundPlane, entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane);
|
||||
|
||||
EXPECT_TRUE(useGroundPlane);
|
||||
|
||||
m_entity->Deactivate();
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect)
|
||||
{
|
||||
CreateEntity();
|
||||
auto entity = CreateEntity();
|
||||
|
||||
constexpr static AZ::u32 testPriority = 15;
|
||||
constexpr static AZ::u32 testLayer = 0;
|
||||
@@ -131,12 +128,13 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect)
|
||||
config.m_priority = testPriority;
|
||||
config.m_useGroundPlane = false;
|
||||
|
||||
AddLayerSpawnerAndShapeComponentToEntity(config);
|
||||
AddLayerSpawnerToEntity(entity.get(), config);
|
||||
AddShapeComponentToEntity(entity.get());
|
||||
|
||||
m_entity->Activate();
|
||||
entity->Activate();
|
||||
|
||||
AZ::u32 priority = 999, layer = 999;
|
||||
Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority);
|
||||
Terrain::TerrainSpawnerRequestBus::Event(entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority);
|
||||
|
||||
EXPECT_EQ(testPriority, priority);
|
||||
EXPECT_EQ(testLayer, layer);
|
||||
@@ -144,82 +142,86 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect)
|
||||
bool useGroundPlane = true;
|
||||
|
||||
Terrain::TerrainSpawnerRequestBus::EventResult(
|
||||
useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane);
|
||||
useGroundPlane, entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane);
|
||||
|
||||
EXPECT_FALSE(useGroundPlane);
|
||||
|
||||
m_entity->Deactivate();
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, LayerSpawnerRegisterAreaUpdatesTerrainSystem)
|
||||
{
|
||||
CreateEntity();
|
||||
auto entity = CreateEntity();
|
||||
|
||||
CreateMockTerrainSystem();
|
||||
NiceMock<UnitTest::MockTerrainSystemService> terrainSystem;
|
||||
|
||||
// The Activate call should register the area.
|
||||
EXPECT_CALL(*m_terrainSystem, RegisterArea(_)).Times(1);
|
||||
EXPECT_CALL(terrainSystem, RegisterArea(_)).Times(1);
|
||||
|
||||
AddLayerSpawnerAndShapeComponentToEntity();
|
||||
AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig());
|
||||
AddShapeComponentToEntity(entity.get());
|
||||
|
||||
m_entity->Activate();
|
||||
entity->Activate();
|
||||
|
||||
m_entity->Deactivate();
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, LayerSpawnerUnregisterAreaUpdatesTerrainSystem)
|
||||
{
|
||||
CreateEntity();
|
||||
auto entity = CreateEntity();
|
||||
|
||||
CreateMockTerrainSystem();
|
||||
NiceMock<UnitTest::MockTerrainSystemService> terrainSystem;
|
||||
|
||||
// The Deactivate call should unregister the area.
|
||||
EXPECT_CALL(*m_terrainSystem, UnregisterArea(_)).Times(1);
|
||||
EXPECT_CALL(terrainSystem, UnregisterArea(_)).Times(1);
|
||||
|
||||
AddLayerSpawnerAndShapeComponentToEntity();
|
||||
AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig());
|
||||
AddShapeComponentToEntity(entity.get());
|
||||
|
||||
m_entity->Activate();
|
||||
entity->Activate();
|
||||
|
||||
m_entity->Deactivate();
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, LayerSpawnerTransformChangedUpdatesTerrainSystem)
|
||||
{
|
||||
CreateEntity();
|
||||
auto entity = CreateEntity();
|
||||
|
||||
CreateMockTerrainSystem();
|
||||
NiceMock<UnitTest::MockTerrainSystemService> terrainSystem;
|
||||
|
||||
// The TransformChanged call should refresh the area.
|
||||
EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1);
|
||||
EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(1);
|
||||
|
||||
AddLayerSpawnerAndShapeComponentToEntity();
|
||||
AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig());
|
||||
AddShapeComponentToEntity(entity.get());
|
||||
|
||||
m_entity->Activate();
|
||||
entity->Activate();
|
||||
|
||||
// The component gets transform change notifications via the shape bus.
|
||||
LmbrCentral::ShapeComponentNotificationsBus::Event(
|
||||
m_entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged,
|
||||
entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged,
|
||||
LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::TransformChanged);
|
||||
|
||||
m_entity->Deactivate();
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
TEST_F(LayerSpawnerComponentTest, LayerSpawnerShapeChangedUpdatesTerrainSystem)
|
||||
{
|
||||
CreateEntity();
|
||||
auto entity = CreateEntity();
|
||||
|
||||
CreateMockTerrainSystem();
|
||||
NiceMock<UnitTest::MockTerrainSystemService> terrainSystem;
|
||||
|
||||
// The ShapeChanged call should refresh the area.
|
||||
EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1);
|
||||
EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(1);
|
||||
|
||||
AddLayerSpawnerAndShapeComponentToEntity();
|
||||
AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig());
|
||||
AddShapeComponentToEntity(entity.get());
|
||||
|
||||
m_entity->Activate();
|
||||
entity->Activate();
|
||||
|
||||
LmbrCentral::ShapeComponentNotificationsBus::Event(
|
||||
m_entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged,
|
||||
LmbrCentral::ShapeComponentNotificationsBus::Event(
|
||||
entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged,
|
||||
LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged);
|
||||
|
||||
m_entity->Deactivate();
|
||||
entity.reset();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"Amazon": {
|
||||
"AzCore": {
|
||||
"Bootstrap": {
|
||||
// The first time an application is launched on MacOS, each
|
||||
// dynamic library is inspected by the OS before being loaded.
|
||||
// This can take a while on some Macs.
|
||||
"launch_ap_timeout": 300
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
BUILD_DEPENDENCIES
|
||||
PUBLIC
|
||||
Gem::${Name}.Editor.Static
|
||||
RUNTIME_DEPENDENCIES
|
||||
Gem::QtForPython.Editor
|
||||
)
|
||||
|
||||
# By default, we will specify that the above target ${Name} would be used by
|
||||
|
||||
@@ -13,5 +13,8 @@
|
||||
"${Name}"
|
||||
],
|
||||
"icon_path": "preview.png",
|
||||
"requirements": ""
|
||||
"requirements": "",
|
||||
"dependencies": [
|
||||
"QtForPython"
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+43
-6
@@ -16,7 +16,7 @@ EMPTY_JSON = readJSON text: '{}'
|
||||
ENGINE_REPOSITORY_NAME = 'o3de'
|
||||
|
||||
// Branches with build snapshots
|
||||
BUILD_SNAPSHOTS = ['development', 'stabilization/2106']
|
||||
BUILD_SNAPSHOTS = ['development', 'stabilization/2110']
|
||||
|
||||
// Build snapshots with empty snapshot (for use with 'SNAPSHOT' pipeline paramater)
|
||||
BUILD_SNAPSHOTS_WITH_EMPTY = BUILD_SNAPSHOTS + ''
|
||||
@@ -102,6 +102,10 @@ def IsJobEnabled(branchName, buildTypeMap, pipelineName, platformName) {
|
||||
}
|
||||
}
|
||||
|
||||
def IsAPLogUpload(branchName, jobName) {
|
||||
return !IsPullRequest(branchName) && jobName.toLowerCase().contains('asset') && env.AP_LOGS_S3_BUCKET
|
||||
}
|
||||
|
||||
def GetRunningPipelineName(JENKINS_JOB_NAME) {
|
||||
// If the job name has an underscore
|
||||
def job_parts = JENKINS_JOB_NAME.tokenize('/')[0].tokenize('_')
|
||||
@@ -267,7 +271,7 @@ def CheckoutRepo(boolean disableSubmodules = false) {
|
||||
palRm('commitdate')
|
||||
}
|
||||
|
||||
def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) {
|
||||
def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) {
|
||||
unstash name: 'incremental_build_script'
|
||||
|
||||
def pythonCmd = ''
|
||||
@@ -277,9 +281,7 @@ def HandleDriveMount(String snapshot, String repositoryName, String projectName,
|
||||
if(recreateVolume) {
|
||||
palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action delete --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Deleting volume', winSlashReplacement=false)
|
||||
}
|
||||
timeout(5) {
|
||||
palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --snapshot ${snapshot} --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume', winSlashReplacement=false)
|
||||
}
|
||||
palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --snapshot ${snapshot} --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume', winSlashReplacement=false)
|
||||
|
||||
if(env.IS_UNIX) {
|
||||
sh label: 'Setting volume\'s ownership',
|
||||
@@ -431,6 +433,27 @@ def ExportTestScreenshots(Map options, String branchName, String platformName, S
|
||||
}
|
||||
}
|
||||
|
||||
def UploadAPLogs(Map options, String branchName, String platformName, String jobName, String workspace, Map params) {
|
||||
dir("${workspace}/${ENGINE_REPOSITORY_NAME}") {
|
||||
projects = params.CMAKE_LY_PROJECTS.split(",")
|
||||
projects.each{ project ->
|
||||
def apLogsPath = "${project}/user/log"
|
||||
def s3UploadScriptPath = "scripts/build/tools/upload_to_s3.py"
|
||||
if(env.IS_UNIX) {
|
||||
pythonPath = "${options.PYTHON_DIR}/python.sh"
|
||||
}
|
||||
else {
|
||||
pythonPath = "${options.PYTHON_DIR}/python.cmd"
|
||||
}
|
||||
def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " +
|
||||
"--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " +
|
||||
"--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${platformName}/${jobName} " +
|
||||
'--extra_args {\\"ACL\\":\\"bucket-owner-full-control\\"}'
|
||||
palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def PostBuildCommonSteps(String workspace, boolean mount = true) {
|
||||
echo 'Starting post-build common steps...'
|
||||
|
||||
@@ -494,6 +517,14 @@ def CreateExportTestScreenshotsStage(Map pipelineConfig, String branchName, Stri
|
||||
}
|
||||
}
|
||||
|
||||
def CreateUploadAPLogsStage(Map pipelineConfig, String branchName, String platformName, String jobName, String workspace, Map params) {
|
||||
return {
|
||||
stage("${jobName}_upload_ap_logs") {
|
||||
UploadAPLogs(pipelineConfig, branchName, platformName, jobName, workspace, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def CreateTeardownStage(Map environmentVars) {
|
||||
return {
|
||||
stage('Teardown') {
|
||||
@@ -518,9 +549,11 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar
|
||||
CreateSetupStage(pipelineConfig, snapshot, repositoryName, projectName, pipelineName, branchName, platform.key, build_job.key, envVars, onlyMountEBSVolume).call()
|
||||
|
||||
if(build_job.value.steps) { //this is a pipe with many steps so create all the build stages
|
||||
pipelineEnvVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
|
||||
build_job.value.steps.each { build_step ->
|
||||
build_job_name = build_step
|
||||
envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
|
||||
// This addition of maps makes it that the right operand will override entries if they overlap with the left operand
|
||||
envVars = pipelineEnvVars + GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
|
||||
try {
|
||||
CreateBuildStage(pipelineConfig, platform.key, build_step, envVars).call()
|
||||
}
|
||||
@@ -543,6 +576,9 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar
|
||||
error "Node disconnected during build: ${e}" // Error raised to retry stage on a new node
|
||||
}
|
||||
}
|
||||
if (IsAPLogUpload(branchName, build_job_name)) {
|
||||
CreateUploadAPLogsStage(pipelineConfig, branchName, platform.key, build_job_name, envVars['WORKSPACE'], platform.value.build_types[build_job_name].PARAMETERS).call()
|
||||
}
|
||||
// All other errors will be raised outside the retry block
|
||||
currentResult = envVars['ON_FAILURE_MARK'] ?: 'FAILURE'
|
||||
currentException = e.toString()
|
||||
@@ -770,6 +806,7 @@ try {
|
||||
platform.value.build_types.each { build_job ->
|
||||
if (IsJobEnabled(branchName, build_job, pipelineName, platform.key)) { // User can filter jobs, jobs are tagged by pipeline
|
||||
def envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName)
|
||||
envVars['JENKINS_JOB_NAME'] = env.JOB_NAME // Save original Jenkins job name to JENKINS_JOB_NAME
|
||||
envVars['JOB_NAME'] = "${branchName}_${platform.key}_${build_job.key}" // backwards compatibility, some scripts rely on this
|
||||
someBuildHappened = true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user