Merge branch 'stabilization/2106' into cpack/stabilization/2106

This commit is contained in:
scottr
2021-06-15 07:36:48 -07:00
67 changed files with 1038 additions and 202 deletions
@@ -175,4 +175,11 @@ namespace AZ::Utils
path /= ".o3de";
return path.Native();
}
AZ::IO::FixedMaxPathString GetO3deLogsDirectory()
{
AZ::IO::FixedMaxPath path = GetO3deManifestDirectory();
path /= "Logs";
return path.Native();
}
}
@@ -97,6 +97,9 @@ namespace AZ
//! Retrieves the full path where the manifest file lives, i.e. "<userhome>/.o3de/o3de_manifest.json"
AZ::IO::FixedMaxPathString GetEngineManifestPath();
//! Retrieves the full directory to the O3DE logs directory, i.e. "<userhome>/.o3de/Logs"
AZ::IO::FixedMaxPathString GetO3deLogsDirectory();
//! Retrieves the App root path to use on the current platform
//! If the optional is not engaged the AppRootPath should be calculated based
//! on the location of the bootstrap.cfg file
+1 -1
View File
@@ -2891,7 +2891,7 @@ void CCryEditApp::OpenProjectManager(const AZStd::string& screen)
{
// provide the current project path for in case we want to update the project
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
const AZStd::string commandLineOptions = AZStd::string::format(" --screen %s --project_path %s", screen.c_str(), projectPath.c_str());
const AZStd::string commandLineOptions = AZStd::string::format(" --screen %s --project-path %s", screen.c_str(), projectPath.c_str());
bool launchSuccess = AzFramework::ProjectManager::LaunchProjectManager(commandLineOptions);
if (!launchSuccess)
{
+15 -5
View File
@@ -514,18 +514,28 @@ void EditorViewportWidget::Update()
// Disable rendering to avoid recursion into Update()
PushDisableRendering();
//get debug display interface for the viewport
AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, GetViewportId());
AZ_Assert(debugDisplayBus, "Invalid DebugDisplayRequestBus.");
AzFramework::DebugDisplayRequests* debugDisplay =
AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
// draw debug visualizations
if (m_debugDisplay)
if (debugDisplay)
{
const AZ::u32 prevState = m_debugDisplay->GetState();
m_debugDisplay->SetState(
const AZ::u32 prevState = debugDisplay->GetState();
debugDisplay->SetState(
e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeBack | e_DepthWriteOn | e_DepthTestOn);
AzFramework::EntityDebugDisplayEventBus::Broadcast(
&AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport,
AzFramework::ViewportInfo{ GetViewportId() }, *m_debugDisplay);
AzFramework::ViewportInfo{ GetViewportId() }, *debugDisplay);
m_debugDisplay->SetState(prevState);
debugDisplay->SetState(prevState);
}
QtViewport::Update();
+58 -5
View File
@@ -20,12 +20,11 @@ if (NOT python_package_name)
message(WARNING "Python was not found in the package assocation list. Did someone call ly_associate_package(xxxxxxx Python) ?")
endif()
ly_add_target(
NAME ProjectManager APPLICATION
OUTPUT_NAME o3de
NAME ProjectManager.Static STATIC
NAMESPACE AZ
AUTOMOC
AUTORCC
FILES_CMAKE
project_manager_files.cmake
Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
@@ -47,6 +46,60 @@ ly_add_target(
3rdParty::pybind11
AZ::AzCore
AZ::AzFramework
AZ::AzToolsFramework
AZ::AzQtComponents
)
)
ly_add_target(
NAME ProjectManager APPLICATION
OUTPUT_NAME o3de
NAMESPACE AZ
AUTORCC
FILES_CMAKE
project_manager_app_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
BUILD_DEPENDENCIES
PRIVATE
3rdParty::Qt::Core
3rdParty::Qt::Concurrent
3rdParty::Qt::Widgets
3rdParty::Python
3rdParty::pybind11
AZ::AzCore
AZ::AzFramework
AZ::AzQtComponents
AZ::ProjectManager.Static
)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME ProjectManager.Tests EXECUTABLE
NAMESPACE AZ
AUTORCC
FILES_CMAKE
project_manager_tests_files.cmake
Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}_tests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
Platform/${PAL_PLATFORM_NAME}
BUILD_DEPENDENCIES
PRIVATE
3rdParty::Qt::Core
3rdParty::Qt::Concurrent
3rdParty::Qt::Widgets
3rdParty::Python
3rdParty::pybind11
AZ::AzTest
AZ::AzFramework
AZ::AzFrameworkTestShared
AZ::ProjectManager.Static
)
ly_add_googletest(
NAME AZ::ProjectManager.Tests
TEST_COMMAND $<TARGET_FILE:AZ::ProjectManager.Tests> --unittest
)
endif()
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
ProjectManager_Test_Traits_Platform.h
ProjectManager_Test_Traits_Linux.h
)
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS true
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <ProjectManager_Test_Traits_Linux.h>
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
ProjectManager_Test_Traits_Platform.h
ProjectManager_Test_Traits_Mac.h
)
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS false
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <ProjectManager_Test_Traits_Mac.h>
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
ProjectManager_Test_Traits_Platform.h
ProjectManager_Test_Traits_Windows.h
)
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <ProjectManager_Test_Traits_Windows.h>
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS false
@@ -7,6 +7,11 @@ QMainWindow {
margin:0;
}
#ScreensCtrl {
min-width:1200px;
min-height:800px;
}
QPushButton:focus {
outline: none;
border:1px solid #1e70eb;
@@ -0,0 +1,186 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Application.h>
#include <ProjectUtils.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Utils/Utils.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzFramework/Logging/LoggingComponent.h>
#include <AzQtComponents/Utilities/HandleDpiAwareness.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
#include <QApplication>
#include <QDir>
#include <QMessageBox>
namespace O3DE::ProjectManager
{
Application::~Application()
{
TearDown();
}
bool Application::Init(bool interactive)
{
constexpr const char* applicationName { "O3DE" };
QApplication::setOrganizationName(applicationName);
QApplication::setOrganizationDomain("o3de.org");
QCoreApplication::setApplicationName(applicationName);
QCoreApplication::setApplicationVersion("1.0");
// Use the LogComponent for non-dev logging log
RegisterComponentDescriptor(AzFramework::LogComponent::CreateDescriptor());
// set the log alias to .o3de/Logs instead of the default user/logs
AZ::IO::FixedMaxPath path = AZ::Utils::GetO3deLogsDirectory();
// DevWriteStorage is where the event log is written during development
m_settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::FilePathKey_DevWriteStorage, path.LexicallyNormal().Native());
// Save event logs to .o3de/Logs/eventlogger/EventLogO3DE.azsl
m_settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::BuildTargetNameKey, applicationName);
Start(AzFramework::Application::Descriptor());
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware);
// Create the actual Qt Application - this needs to happen before using QMessageBox
m_app.reset(new QApplication(*GetArgC(), *GetArgV()));
if(!InitLog(applicationName))
{
AZ_Warning("ProjectManager", false, "Failed to init logging");
}
m_pythonBindings = AZStd::make_unique<PythonBindings>(GetEngineRoot());
if (!m_pythonBindings || !m_pythonBindings->PythonStarted())
{
if (interactive)
{
QMessageBox::critical(nullptr, QObject::tr("Failed to start Python"),
QObject::tr("This tool requires an O3DE engine with a Python runtime, "
"but either Python is missing or mis-configured. Please rename "
"your python/runtime folder to python/runtime_bak, then run "
"python/get_python.bat to restore the Python runtime folder."));
}
return false;
}
const AZ::CommandLine* commandLine = GetCommandLine();
AZ_Assert(commandLine, "Failed to get command line");
ProjectManagerScreen startScreen = ProjectManagerScreen::Projects;
if (size_t screenSwitchCount = commandLine->GetNumSwitchValues("screen"); screenSwitchCount > 0)
{
QString screenOption = commandLine->GetSwitchValue("screen", screenSwitchCount - 1).c_str();
ProjectManagerScreen screen = ProjectUtils::GetProjectManagerScreen(screenOption);
if (screen != ProjectManagerScreen::Invalid)
{
startScreen = screen;
}
}
AZ::IO::FixedMaxPath projectPath;
if (size_t projectSwitchCount = commandLine->GetNumSwitchValues("project-path"); projectSwitchCount > 0)
{
projectPath = commandLine->GetSwitchValue("project-path", projectSwitchCount - 1).c_str();
}
m_mainWindow.reset(new ProjectManagerWindow(nullptr, projectPath, startScreen));
return true;
}
bool Application::InitLog(const char* logName)
{
if (!m_entity)
{
// override the log alias to the O3de Logs directory instead of the default project user/Logs folder
AZ::IO::FixedMaxPath path = AZ::Utils::GetO3deLogsDirectory();
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
AZ_Assert(fileIO, "Failed to get FileIOBase instance");
fileIO->SetAlias("@log@", path.LexicallyNormal().Native().c_str());
// this entity exists because we need a home for LogComponent
// and cannot use the system entity because we need to be able to call SetLogFileBaseName
// so the log will be named O3DE.log
m_entity = aznew AZ::Entity("Application Entity");
if (m_entity)
{
AzFramework::LogComponent* logger = aznew AzFramework::LogComponent();
AZ_Assert(logger, "Failed to create LogComponent");
logger->SetLogFileBaseName(logName);
m_entity->AddComponent(logger);
m_entity->Init();
m_entity->Activate();
}
}
return m_entity != nullptr;
}
void Application::TearDown()
{
if (m_entity)
{
m_entity->Deactivate();
delete m_entity;
m_entity = nullptr;
}
m_pythonBindings.reset();
m_mainWindow.reset();
m_app.reset();
}
bool Application::Run()
{
// Set up the Style Manager
AzQtComponents::StyleManager styleManager(qApp);
styleManager.initialize(qApp, GetEngineRoot());
// setup stylesheets and hot reloading
AZ::IO::FixedMaxPath engineRoot(GetEngineRoot());
QDir rootDir(engineRoot.c_str());
const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/ProjectManager/Resources");
const auto qrcPath = QStringLiteral(":/ProjectManager/style");
AzQtComponents::StyleManager::addSearchPaths("style", pathOnDisk, qrcPath, engineRoot);
// set stylesheet after creating the main window or their styles won't get updated
AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:ProjectManager.qss"));
// the decoration wrapper is intended to remember window positioning and sizing
auto wrapper = new AzQtComponents::WindowDecorationWrapper();
wrapper->setGuest(m_mainWindow.data());
wrapper->show();
m_mainWindow->show();
qApp->setQuitOnLastWindowClosed(true);
// Run the application
return qApp->exec();
}
}
@@ -0,0 +1,48 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzFramework/Application/Application.h>
#include <QCoreApplication>
#include <PythonBindings.h>
#include <ProjectManagerWindow.h>
#endif
namespace AZ
{
class Entity;
}
namespace O3DE::ProjectManager
{
class Application
: public AzFramework::Application
{
public:
using AzFramework::Application::Application;
virtual ~Application();
bool Init(bool interactive = true);
bool Run();
void TearDown();
private:
bool InitLog(const char* logName);
AZStd::unique_ptr<PythonBindings> m_pythonBindings;
QSharedPointer<QCoreApplication> m_app;
QSharedPointer<ProjectManagerWindow> m_mainWindow;
AZ::Entity* m_entity = nullptr;
};
}
@@ -25,7 +25,7 @@ namespace O3DE::ProjectManager
EngineSettingsScreen::EngineSettingsScreen(QWidget* parent)
: ScreenWidget(parent)
{
auto* layout = new QVBoxLayout(this);
auto* layout = new QVBoxLayout();
layout->setAlignment(Qt::AlignTop);
setObjectName("engineSettingsScreen");
@@ -82,6 +82,8 @@ namespace O3DE::ProjectManager
m_headerWidget->ReinitForProject();
connect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter);
// Select the first entry after everything got correctly sized
QTimer::singleShot(200, [=]{
QModelIndex firstModelIndex = m_gemListView->model()->index(0,0);
@@ -26,6 +26,7 @@ namespace O3DE::ProjectManager
const QVector<QString>& elementNames,
const QVector<int>& elementCounts,
bool showAllLessButton,
bool collapsed,
int defaultShowCount,
QWidget* parent)
: QWidget(parent)
@@ -40,6 +41,7 @@ namespace O3DE::ProjectManager
QHBoxLayout* collapseLayout = new QHBoxLayout();
m_collapseButton = new QPushButton();
m_collapseButton->setCheckable(true);
m_collapseButton->setChecked(collapsed);
m_collapseButton->setFlat(true);
m_collapseButton->setFocusPolicy(Qt::NoFocus);
m_collapseButton->setFixedWidth(s_collapseButtonSize);
@@ -178,6 +180,11 @@ namespace O3DE::ProjectManager
return m_buttonGroup;
}
bool FilterCategoryWidget::IsCollapsed()
{
return m_collapseButton->isChecked();
}
GemFilterWidget::GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent)
: QScrollArea(parent)
, m_filterProxyModel(filterProxyModel)
@@ -193,20 +200,106 @@ namespace O3DE::ProjectManager
QWidget* mainWidget = new QWidget();
setWidget(mainWidget);
m_mainLayout = new QVBoxLayout();
m_mainLayout->setAlignment(Qt::AlignTop);
mainWidget->setLayout(m_mainLayout);
QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->setAlignment(Qt::AlignTop);
mainWidget->setLayout(mainLayout);
QLabel* filterByLabel = new QLabel("Filter by");
filterByLabel->setStyleSheet("font-size: 16px;");
m_mainLayout->addWidget(filterByLabel);
mainLayout->addWidget(filterByLabel);
QWidget* filterSection = new QWidget(this);
mainLayout->addWidget(filterSection);
m_filterLayout = new QVBoxLayout();
m_filterLayout->setAlignment(Qt::AlignTop);
m_filterLayout->setContentsMargins(0, 0, 0, 0);
filterSection->setLayout(m_filterLayout);
ResetGemStatusFilter();
AddGemOriginFilter();
AddTypeFilter();
AddPlatformFilter();
AddFeatureFilter();
}
void GemFilterWidget::ResetGemStatusFilter()
{
QVector<QString> elementNames;
QVector<int> elementCounts;
const int totalGems = m_gemModel->rowCount();
const int selectedGemTotal = m_gemModel->TotalAddedGems();
elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Unselected));
elementCounts.push_back(totalGems - selectedGemTotal);
elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Selected));
elementCounts.push_back(selectedGemTotal);
bool wasCollapsed = false;
if (m_statusFilter)
{
wasCollapsed = m_statusFilter->IsCollapsed();
}
FilterCategoryWidget* filterWidget =
new FilterCategoryWidget("Status", elementNames, elementCounts, /*showAllLessButton=*/false, /*collapsed*/wasCollapsed);
if (m_statusFilter)
{
m_filterLayout->replaceWidget(m_statusFilter, filterWidget);
}
else
{
m_filterLayout->addWidget(filterWidget);
}
m_statusFilter->deleteLater();
m_statusFilter = filterWidget;
const GemSortFilterProxyModel::GemStatus currentFilterState = m_filterProxyModel->GetGemStatus();
const QList<QAbstractButton*> buttons = m_statusFilter->GetButtonGroup()->buttons();
for (int statusFilterIndex = 0; statusFilterIndex < buttons.size(); ++statusFilterIndex)
{
const GemSortFilterProxyModel::GemStatus gemStatus = static_cast<GemSortFilterProxyModel::GemStatus>(statusFilterIndex);
QAbstractButton* button = buttons[statusFilterIndex];
if (static_cast<GemSortFilterProxyModel::GemStatus>(statusFilterIndex) == currentFilterState)
{
button->setChecked(true);
}
connect(
button, &QAbstractButton::toggled, this,
[=](bool checked)
{
GemSortFilterProxyModel::GemStatus filterStatus = m_filterProxyModel->GetGemStatus();
if (checked)
{
if (filterStatus == GemSortFilterProxyModel::GemStatus::NoFilter)
{
filterStatus = gemStatus;
}
else
{
filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter;
}
}
else
{
if (filterStatus != gemStatus)
{
filterStatus = static_cast<GemSortFilterProxyModel::GemStatus>(!gemStatus);
}
else
{
filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter;
}
}
m_filterProxyModel->SetGemStatus(filterStatus);
});
}
}
void GemFilterWidget::AddGemOriginFilter()
{
QVector<QString> elementNames;
@@ -233,7 +326,7 @@ namespace O3DE::ProjectManager
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Provider", elementNames, elementCounts, /*showAllLessButton=*/false);
m_mainLayout->addWidget(filterWidget);
m_filterLayout->addWidget(filterWidget);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
@@ -283,7 +376,7 @@ namespace O3DE::ProjectManager
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Type", elementNames, elementCounts, /*showAllLessButton=*/false);
m_mainLayout->addWidget(filterWidget);
m_filterLayout->addWidget(filterWidget);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
@@ -333,7 +426,7 @@ namespace O3DE::ProjectManager
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Supported Platforms", elementNames, elementCounts, /*showAllLessButton=*/false);
m_mainLayout->addWidget(filterWidget);
m_filterLayout->addWidget(filterWidget);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
@@ -388,8 +481,8 @@ namespace O3DE::ProjectManager
}
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Features", elementNames, elementCounts,
/*showAllLessButton=*/true, /*defaultShowCount=*/5);
m_mainLayout->addWidget(filterWidget);
/*showAllLessButton=*/true, false, /*defaultShowCount=*/5);
m_filterLayout->addWidget(filterWidget);
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
for (int i = 0; i < buttons.size(); ++i)
@@ -37,11 +37,14 @@ namespace O3DE::ProjectManager
const QVector<QString>& elementNames,
const QVector<int>& elementCounts,
bool showAllLessButton = true,
bool collapsed = false,
int defaultShowCount = 4,
QWidget* parent = nullptr);
QButtonGroup* GetButtonGroup();
bool IsCollapsed();
private:
void UpdateCollapseState();
void UpdateSeeMoreLess();
@@ -66,14 +69,18 @@ namespace O3DE::ProjectManager
explicit GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr);
~GemFilterWidget() = default;
public slots:
void ResetGemStatusFilter();
private:
void AddGemOriginFilter();
void AddTypeFilter();
void AddPlatformFilter();
void AddFeatureFilter();
QVBoxLayout* m_mainLayout = nullptr;
QVBoxLayout* m_filterLayout = nullptr;
GemModel* m_gemModel = nullptr;
GemSortFilterProxyModel* m_filterProxyModel = nullptr;
FilterCategoryWidget* m_statusFilter = nullptr;
};
} // namespace O3DE::ProjectManager
@@ -204,7 +204,6 @@ namespace O3DE::ProjectManager
painter->save();
const QRect buttonRect = CalcButtonRect(contentRect);
QPoint circleCenter;
QString buttonText;
const bool isAdded = GemModel::IsAdded(modelIndex);
if (isAdded)
@@ -213,34 +212,15 @@ namespace O3DE::ProjectManager
painter->setPen(m_buttonEnabledColor);
circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
buttonText = "Added";
}
else
{
circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius, 1);
buttonText = "Get";
}
// Rounded rect
painter->drawRoundedRect(buttonRect, s_buttonBorderRadius, s_buttonBorderRadius);
// Text
QFont font;
QRect textRect = GetTextRect(font, buttonText, s_buttonFontSize);
if (isAdded)
{
textRect = QRect(buttonRect.left(), buttonRect.top(), buttonRect.width() - s_buttonCircleRadius * 2.0, buttonRect.height());
}
else
{
textRect = QRect(buttonRect.left() + s_buttonCircleRadius * 2.0, buttonRect.top(), buttonRect.width() - s_buttonCircleRadius * 2.0, buttonRect.height());
}
font.setPixelSize(s_buttonFontSize);
painter->setFont(font);
painter->setPen(m_textColor);
painter->drawText(textRect, Qt::AlignCenter, buttonText);
// Circle
painter->setBrush(m_textColor);
painter->drawEllipse(circleCenter, s_buttonCircleRadius, s_buttonCircleRadius);
@@ -15,6 +15,7 @@
#include <QStandardItemModel>
#include <QLabel>
#include <QVBoxLayout>
#include <QSpacerItem>
namespace O3DE::ProjectManager
{
@@ -74,6 +75,15 @@ namespace O3DE::ProjectManager
gemSummaryLabel->setStyleSheet("font-size: 12px;");
columnHeaderLayout->addWidget(gemSummaryLabel);
QSpacerItem* horizontalSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
columnHeaderLayout->addSpacerItem(horizontalSpacer);
QLabel* gemSelectedLabel = new QLabel(tr("Selected"));
gemSelectedLabel->setStyleSheet("font-size: 12px;");
columnHeaderLayout->addWidget(gemSelectedLabel);
columnHeaderLayout->addSpacing(60);
vLayout->addLayout(columnHeaderLayout);
}
} // namespace O3DE::ProjectManager
@@ -235,4 +235,19 @@ namespace O3DE::ProjectManager
}
return result;
}
int GemModel::TotalAddedGems() const
{
int result = 0;
for (int row = 0; row < rowCount(); ++row)
{
const QModelIndex modelIndex = index(row, 0);
if (IsAdded(modelIndex))
{
++result;
}
}
return result;
}
} // namespace O3DE::ProjectManager
@@ -63,6 +63,8 @@ namespace O3DE::ProjectManager
QVector<QModelIndex> GatherGemsToBeAdded() const;
QVector<QModelIndex> GatherGemsToBeRemoved() const;
int TotalAddedGems() const;
private:
enum UserRole
{
@@ -37,6 +37,16 @@ namespace O3DE::ProjectManager
return false;
}
// Gem status
if (m_gemStatusFilter != GemStatus::NoFilter)
{
const GemStatus sourceGemStatus = static_cast<GemStatus>(GemModel::IsAdded(sourceIndex));
if (m_gemStatusFilter != sourceGemStatus)
{
return false;
}
}
// Gem origins
if (m_gemOriginFilter)
{
@@ -125,6 +135,19 @@ namespace O3DE::ProjectManager
return true;
}
QString GemSortFilterProxyModel::GetGemStatusString(GemStatus status)
{
switch (status)
{
case Unselected:
return "Unselected";
case Selected:
return "Selected";
default:
return "<Unknown Gem Status>";
}
}
void GemSortFilterProxyModel::InvalidateFilter()
{
invalidate();
@@ -29,8 +29,17 @@ namespace O3DE::ProjectManager
Q_OBJECT // AUTOMOC
public:
enum GemStatus
{
NoFilter = -1,
Unselected,
Selected
};
GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr);
static QString GetGemStatusString(GemStatus status);
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
GemModel* GetSourceModel() const { return m_sourceModel; }
@@ -38,6 +47,9 @@ namespace O3DE::ProjectManager
void SetSearchString(const QString& searchString) { m_searchString = searchString; InvalidateFilter(); }
GemStatus GetGemStatus() const { return m_gemStatusFilter; }
void SetGemStatus(GemStatus gemStatus) { m_gemStatusFilter = gemStatus; InvalidateFilter(); }
GemInfo::GemOrigins GetGemOrigins() const { return m_gemOriginFilter; }
void SetGemOrigins(const GemInfo::GemOrigins& gemOrigins) { m_gemOriginFilter = gemOrigins; InvalidateFilter(); }
@@ -61,6 +73,7 @@ namespace O3DE::ProjectManager
AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr;
QString m_searchString;
GemStatus m_gemStatusFilter = GemStatus::NoFilter;
GemInfo::GemOrigins m_gemOriginFilter = {};
GemInfo::Platforms m_platformFilter = {};
GemInfo::Types m_typeFilter = {};
@@ -33,7 +33,7 @@ namespace O3DE::ProjectManager
{
setObjectName("labelButton");
QVBoxLayout* vLayout = new QVBoxLayout(this);
QVBoxLayout* vLayout = new QVBoxLayout();
vLayout->setContentsMargins(0, 0, 0, 0);
vLayout->setSpacing(5);
@@ -13,21 +13,11 @@
#include <ProjectManagerWindow.h>
#include <ScreensCtrl.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/Path/Path.h>
#include <AzFramework/CommandLine/CommandLine.h>
#include <AzFramework/Application/Application.h>
#include <QDir>
namespace O3DE::ProjectManager
{
ProjectManagerWindow::ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath, const AZ::IO::PathView& projectPath, ProjectManagerScreen startScreen)
ProjectManagerWindow::ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& projectPath, ProjectManagerScreen startScreen)
: QMainWindow(parent)
{
m_pythonBindings = AZStd::make_unique<PythonBindings>(engineRootPath);
setWindowTitle(tr("O3DE Project Manager"));
ScreensCtrl* screensCtrl = new ScreensCtrl();
@@ -44,15 +34,6 @@ namespace O3DE::ProjectManager
setCentralWidget(screensCtrl);
// setup stylesheets and hot reloading
QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast<int>(engineRootPath.Native().size()));
const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/ProjectManager/Resources");
const auto qrcPath = QStringLiteral(":/ProjectManager/style");
AzQtComponents::StyleManager::addSearchPaths("style", pathOnDisk, qrcPath, engineRootPath);
// set stylesheet after creating the screens or their styles won't get updated
AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("style:ProjectManager.qss"));
// always push the projects screen first so we have something to come back to
if (startScreen != ProjectManagerScreen::Projects)
{
@@ -66,10 +47,4 @@ namespace O3DE::ProjectManager
emit screensCtrl->NotifyCurrentProject(path);
}
}
ProjectManagerWindow::~ProjectManagerWindow()
{
m_pythonBindings.reset();
}
} // namespace O3DE::ProjectManager
@@ -13,7 +13,7 @@
#if !defined(Q_MOC_RUN)
#include <QMainWindow>
#include <PythonBindings.h>
#include <AzCore/IO/Path/Path.h>
#include <ScreenDefs.h>
#endif
@@ -25,12 +25,8 @@ namespace O3DE::ProjectManager
Q_OBJECT
public:
explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath, const AZ::IO::PathView& projectPath,
explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& projectPath,
ProjectManagerScreen startScreen = ProjectManagerScreen::Projects);
~ProjectManagerWindow();
private:
AZStd::unique_ptr<PythonBindings> m_pythonBindings;
};
} // namespace O3DE::ProjectManager
@@ -37,7 +37,7 @@ namespace O3DE::ProjectManager
// if we don't set this in a frame (just use a sub-layout) all the content will align incorrectly horizontally
QFrame* projectSettingsFrame = new QFrame(this);
projectSettingsFrame->setObjectName("projectSettings");
m_verticalLayout = new QVBoxLayout(this);
m_verticalLayout = new QVBoxLayout();
// you cannot remove content margins in qss
m_verticalLayout->setContentsMargins(0, 0, 0, 0);
@@ -85,7 +85,7 @@ namespace O3DE::ProjectManager
QFrame* frame = new QFrame(this);
frame->setObjectName("firstTimeContent");
{
QVBoxLayout* layout = new QVBoxLayout(this);
QVBoxLayout* layout = new QVBoxLayout();
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignTop);
frame->setLayout(layout);
@@ -100,7 +100,7 @@ namespace O3DE::ProjectManager
"available by downloading our sample project."));
layout->addWidget(introLabel);
QHBoxLayout* buttonLayout = new QHBoxLayout(this);
QHBoxLayout* buttonLayout = new QHBoxLayout();
buttonLayout->setAlignment(Qt::AlignLeft);
buttonLayout->setSpacing(s_spacerSize);
@@ -226,7 +226,7 @@ namespace O3DE::ProjectManager
PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath)
: m_enginePath(enginePath)
{
StartPython();
m_pythonStarted = StartPython();
}
PythonBindings::~PythonBindings()
@@ -234,6 +234,11 @@ namespace O3DE::ProjectManager
StopPython();
}
bool PythonBindings::PythonStarted()
{
return m_pythonStarted && Py_IsInitialized();
}
bool PythonBindings::StartPython()
{
if (Py_IsInitialized())
@@ -246,7 +251,7 @@ namespace O3DE::ProjectManager
AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, m_enginePath.c_str());
if (!AZ::IO::SystemFile::Exists(pyBasePath.c_str()))
{
AZ_Assert(false, "Python home path must exist. path:%s", pyBasePath.c_str());
AZ_Error("python", false, "Python home path does not exist: %s", pyBasePath.c_str());
return false;
}
@@ -351,6 +356,11 @@ namespace O3DE::ProjectManager
AZ::Outcome<void, AZStd::string> PythonBindings::ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback)
{
if (!Py_IsInitialized())
{
return AZ::Failure<AZStd::string>("Python is not initialized");
}
AZStd::lock_guard<decltype(m_lock)> lock(m_lock);
pybind11::gil_scoped_release release;
pybind11::gil_scoped_acquire acquire;
@@ -34,6 +34,8 @@ namespace O3DE::ProjectManager
~PythonBindings() override;
// PythonBindings overrides
bool PythonStarted() override;
// Engine
AZ::Outcome<EngineInfo> GetEngineInfo() override;
bool SetEngineInfo(const EngineInfo& engineInfo) override;
@@ -70,6 +72,8 @@ namespace O3DE::ProjectManager
bool StopPython();
bool m_pythonStarted = false;
AZ::IO::FixedMaxPath m_enginePath;
pybind11::handle m_engineTemplate;
AZStd::recursive_mutex m_lock;
@@ -34,6 +34,12 @@ namespace O3DE::ProjectManager
IPythonBindings() = default;
virtual ~IPythonBindings() = default;
/**
* Get whether Python was started or not. All Python functionality will fail if Python
* failed to start.
* @return true if Python was started successfully, false on failure
*/
virtual bool PythonStarted() = 0;
// Engine
@@ -189,11 +189,13 @@ namespace O3DE::ProjectManager
{
if (m_stack->currentIndex() == ScreenOrder::Gems)
{
m_header->setSubTitle(QString(tr("Configure Gems for \"%1\"")).arg(m_projectInfo.m_projectName));
m_nextButton->setText(tr("Confirm"));
m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName));
m_header->setSubTitle(QString(tr("Configure Gems")));
m_nextButton->setText(tr("Finalize"));
}
else
{
m_header->setTitle("");
m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName));
m_nextButton->setText(tr("Save"));
}
+14 -73
View File
@@ -10,85 +10,26 @@
*
*/
#include <AzQtComponents/Utilities/HandleDpiAwareness.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/IO/Path/Path.h>
#include <AzFramework/CommandLine/CommandLine.h>
#include <ProjectManagerWindow.h>
#include <ProjectUtils.h>
#include <QApplication>
#include <QCoreApplication>
#include <QGuiApplication>
using namespace O3DE::ProjectManager;
#include <AzQtComponents/Utilities/QtPluginPaths.h>
#include <Application.h>
int main(int argc, char* argv[])
{
QApplication::setOrganizationName("O3DE");
QApplication::setOrganizationDomain("o3de.org");
QCoreApplication::setApplicationName("ProjectManager");
QCoreApplication::setApplicationVersion("1.0");
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware);
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
int runSuccess = 0;
// Call before using any Qt, or the app may not be able to locate Qt libs
AzQtComponents::PrepareQtPaths();
O3DE::ProjectManager::Application application(&argc, &argv);
if (!application.Init())
{
QApplication app(argc, argv);
// Need to use settings registry to get EngineRootFolder
AZ::IO::FixedMaxPath engineRootPath;
{
AZ::ComponentApplication componentApplication;
auto settingsRegistry = AZ::SettingsRegistry::Get();
settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
}
AzQtComponents::StyleManager styleManager(&app);
styleManager.initialize(&app, engineRootPath);
// Get the initial start screen if one is provided via command line
constexpr char optionPrefix[] = "--";
AZ::CommandLine commandLine(optionPrefix);
commandLine.Parse(argc, argv);
ProjectManagerScreen startScreen = ProjectManagerScreen::Projects;
if(commandLine.HasSwitch("screen"))
{
QString screenOption = commandLine.GetSwitchValue("screen", 0).c_str();
ProjectManagerScreen screen = ProjectUtils::GetProjectManagerScreen(screenOption);
if (screen != ProjectManagerScreen::Invalid)
{
startScreen = screen;
}
}
AZ::IO::FixedMaxPath projectPath;
if (commandLine.HasSwitch("project-path"))
{
projectPath = commandLine.GetSwitchValue("project-path", 0).c_str();
}
ProjectManagerWindow window(nullptr, engineRootPath, projectPath, startScreen);
window.show();
// somethings is preventing us from moving the window to the center of the
// primary screen - likely an Az style or component helper
constexpr int width = 1200;
constexpr int height = 800;
window.resize(width, height);
runSuccess = app.exec();
AZ_Error("ProjectManager", false, "Failed to initialize");
runSuccess = 1;
}
else
{
runSuccess = application.Run() ? 0 : 1;
}
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
return runSuccess;
}
@@ -0,0 +1,17 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Resources/ProjectManager.rc
Resources/ProjectManager.qrc
Resources/ProjectManager.qss
Source/main.cpp
)
@@ -1,4 +1,5 @@
#
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
@@ -10,10 +11,8 @@
#
set(FILES
Resources/ProjectManager.rc
Resources/ProjectManager.qrc
Resources/ProjectManager.qss
Source/main.cpp
Source/Application.h
Source/Application.cpp
Source/ScreenDefs.h
Source/ScreenFactory.h
Source/ScreenFactory.cpp
@@ -0,0 +1,17 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Resources/ProjectManager.qrc
Resources/ProjectManager.qss
tests/ApplicationTests.cpp
tests/main.cpp
)
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <Application.h>
#include <ProjectManager_Test_Traits_Platform.h>
namespace O3DE::ProjectManager
{
class ProjectManagerApplicationTests
: public ::UnitTest::ScopedAllocatorSetupFixture
{
public:
ProjectManagerApplicationTests()
{
m_application = AZStd::make_unique<ProjectManager::Application>();
}
~ProjectManagerApplicationTests()
{
m_application.reset();
}
AZStd::unique_ptr<ProjectManager::Application> m_application;
};
#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
TEST_F(ProjectManagerApplicationTests, DISABLED_Application_Init_Succeeds)
#else
TEST_F(ProjectManagerApplicationTests, Application_Init_Succeeds)
#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
{
// we don't want to interact with actual GUI or display it
EXPECT_TRUE(m_application->Init(/*interactive=*/false));
}
}
+35
View File
@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzTest/AzTest.h>
DECLARE_AZ_UNIT_TEST_MAIN();
int runDefaultRunner(int argc, char* argv[])
{
INVOKE_AZ_UNIT_TEST_MAIN(nullptr)
return 0;
}
int main(int argc, char* argv[])
{
if (argc == 1)
{
// if no parameters are provided, add the --unittests parameter
constexpr int defaultArgc = 2;
char unittest_arg[] = "--unittests"; // Conversion from string literal to char* is not allowed per ISO C++11
char* defaultArgv[defaultArgc] = { argv[0], unittest_arg };
return runDefaultRunner(defaultArgc, defaultArgv);
}
INVOKE_AZ_UNIT_TEST_MAIN(nullptr);
return 0;
}
@@ -46,22 +46,69 @@ namespace AZ
serializeContext->Class<AssImpTransformImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
void GetAllBones(const aiScene* scene, AZStd::unordered_map<AZStd::string, const aiBone*>& boneLookup)
{
for (unsigned meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex)
{
const aiMesh* mesh = scene->mMeshes[meshIndex];
for (unsigned boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
{
const aiBone* bone = mesh->mBones[boneIndex];
boneLookup[bone->mName.C_Str()] = bone;
}
}
}
Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "transform");
const aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (currentNode == scene->mRootNode || IsPivotNode(currentNode->mName))
{
return Events::ProcessingResult::Ignored;
}
aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode);
AZStd::unordered_map<AZStd::string, const aiBone*> boneLookup;
GetAllBones(scene, boneLookup);
auto boneIterator = boneLookup.find(currentNode->mName.C_Str());
const bool isBone = boneIterator != boneLookup.end();
aiMatrix4x4 combinedTransform;
if (isBone)
{
auto parentNode = currentNode->mParent;
aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix;
aiMatrix4x4 parentOffset {};
auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str());
if (parentNode && parentBoneIterator != boneLookup.end())
{
const auto& parentBone = parentBoneIterator->second;
parentOffset = parentBone->mOffsetMatrix;
}
auto inverseOffset = offsetMatrix;
inverseOffset.Inverse();
combinedTransform = parentOffset * inverseOffset;
}
else
{
combinedTransform = GetConcatenatedLocalTransform(currentNode);
}
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
context.m_sourceSceneSystem.ConvertUnit(localTransform);
@@ -105,9 +152,7 @@ namespace AZ
}
else
{
bool addedData = context.m_scene.GetGraph().SetContent(
context.m_currentGraphPosition,
transformData);
bool addedData = context.m_scene.GetGraph().SetContent(context.m_currentGraphPosition, transformData);
AZ_Error(SceneAPI::Utilities::ErrorWindow, addedData, "Failed to add node data");
return addedData ? Events::ProcessingResult::Success : Events::ProcessingResult::Failure;
@@ -69,13 +69,14 @@ namespace AZ
// aiProcess_JoinIdenticalVertices is not enabled because O3DE has a mesh optimizer that also does this,
// this flag is disabled to keep AssImp output similar to FBX SDK to reduce downstream bugs for the initial AssImp release.
// There's currently a minimum of properties and flags set to maximize compatibility with the existing node graph.
// aiProcess_LimitBoneWeights is not enabled because it will remove bones which are not associated with a mesh.
// This results in the loss of the offset matrix data for nodes without a mesh which is required for the Transform Importer.
m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false);
m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, false);
m_sceneFileName = fileName;
m_assImpScene = m_importer.ReadFile(fileName,
aiProcess_Triangulate //Triangulates all faces of all meshes
| aiProcess_LimitBoneWeights //Limits the number of bones that can affect a vertex to a maximum value
//dropping the least important and re-normalizing
| aiProcess_GenNormals); //Generate normals for meshes
#if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
@@ -24,9 +24,9 @@
},
"ImageDescriptor": {
"Format": "R16G16B16A16_FLOAT",
"MipLevels": "8",
"SharedQueueMask": "Graphics"
}
},
"GenerateFullMipChain": true
}
],
"Connections": [
@@ -5,7 +5,7 @@
"ClassData": {
"PassTemplate": {
"Name": "ReflectionScreenSpaceCompositePassTemplate",
"PassClass": "FullScreenTriangle",
"PassClass": "ReflectionScreenSpaceCompositePass",
"Slots": [
{
"Name": "TraceInput",
@@ -37,6 +37,9 @@ ShaderResourceGroup PassSrg : SRG_PerPass
AddressV = Clamp;
AddressW = Clamp;
};
// the max roughness mip level for sampling the previous frame image
uint m_maxMipLevel;
}
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
@@ -69,10 +72,6 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
float4 positionWS = mul(ViewSrg::m_viewProjectionInverseMatrix, projectedPos);
positionWS /= positionWS.w;
//float4 positionVS = mul(ViewSrg::m_projectionMatrixInverse, projectedPos);
//positionVS /= positionVS.w;
//float4 positionWS = mul(ViewSrg::m_viewMatrixInverse, positionVS);
// compute ray from camera to surface position
float3 cameraToPositionWS = normalize(positionWS.xyz - ViewSrg::m_worldPosition);
@@ -103,8 +102,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
// compute the roughness mip to use in the previous frame image
// remap the roughness mip into a lower range to more closely match the material roughness values
const float MaxRoughness = 0.5f;
const float MaxRoughnessMip = 7;
float mip = saturate(roughness / MaxRoughness) * MaxRoughnessMip;
float mip = saturate(roughness / MaxRoughness) * PassSrg::m_maxMipLevel;
// sample reflection value from the roughness mip
float4 reflectionColor = float4(PassSrg::m_previousFrame.SampleLevel(PassSrg::LinearSampler, tracePrevUV, mip).rgb, 1.0f);
@@ -103,6 +103,7 @@
#include <DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.h>
#include <ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h>
#include <ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h>
#include <OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h>
@@ -283,6 +284,7 @@ namespace AZ
// Add Reflection passes
passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurPass"), &Render::ReflectionScreenSpaceBlurPass::Create);
passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurChildPass"), &Render::ReflectionScreenSpaceBlurChildPass::Create);
passSystem->AddPassCreator(Name("ReflectionScreenSpaceCompositePass"), &Render::ReflectionScreenSpaceCompositePass::Create);
passSystem->AddPassCreator(Name("ReflectionCopyFrameBufferPass"), &Render::ReflectionCopyFrameBufferPass::Create);
// Add RayTracing pas
@@ -37,6 +37,9 @@ namespace AZ
//! to store the previous frame image
Data::Instance<RPI::AttachmentImage>& GetFrameBufferImageAttachment() { return m_frameBufferImageAttachment; }
//! Returns the number of mip levels in the blur
uint32_t GetNumBlurMips() const { return m_numBlurMips; }
private:
explicit ReflectionScreenSpaceBlurPass(const RPI::PassDescriptor& descriptor);
@@ -0,0 +1,58 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "ReflectionScreenSpaceCompositePass.h"
#include "ReflectionScreenSpaceBlurPass.h"
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
namespace AZ
{
namespace Render
{
RPI::Ptr<ReflectionScreenSpaceCompositePass> ReflectionScreenSpaceCompositePass::Create(const RPI::PassDescriptor& descriptor)
{
RPI::Ptr<ReflectionScreenSpaceCompositePass> pass = aznew ReflectionScreenSpaceCompositePass(descriptor);
return AZStd::move(pass);
}
ReflectionScreenSpaceCompositePass::ReflectionScreenSpaceCompositePass(const RPI::PassDescriptor& descriptor)
: RPI::FullscreenTrianglePass(descriptor)
{
}
void ReflectionScreenSpaceCompositePass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context)
{
if (!m_shaderResourceGroup)
{
return;
}
RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass"));
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (!passes.empty())
{
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front());
// compute the max mip level based on the available mips in the previous frame image, and capping it
// to stay within a range that has reasonable data
const uint32_t MaxNumRoughnessMips = 8;
uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1;
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel"));
m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel);
}
FullscreenTrianglePass::CompileResources(context);
}
} // namespace RPI
} // namespace AZ
@@ -0,0 +1,43 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <Atom/RPI.Public/Pass/Pass.h>
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Shader/Shader.h>
namespace AZ
{
namespace Render
{
//! This pass composites the screenspace reflection trace onto the reflection buffer.
class ReflectionScreenSpaceCompositePass
: public RPI::FullscreenTrianglePass
{
AZ_RPI_PASS(ReflectionScreenSpaceCompositePass);
public:
AZ_RTTI(Render::ReflectionScreenSpaceCompositePass, "{88739CC9-C3F1-413A-A527-9916C697D93A}", FullscreenTrianglePass);
AZ_CLASS_ALLOCATOR(Render::ReflectionScreenSpaceCompositePass, SystemAllocator, 0);
//! Creates a new pass without a PassTemplate
static RPI::Ptr<ReflectionScreenSpaceCompositePass> Create(const RPI::PassDescriptor& descriptor);
private:
explicit ReflectionScreenSpaceCompositePass(const RPI::PassDescriptor& descriptor);
// Pass Overrides...
void CompileResources(const RHI::FrameGraphCompileContext& context) override;
};
} // namespace RPI
} // namespace AZ
@@ -629,6 +629,11 @@ namespace AZ
Data::Asset<RPI::ModelLodAsset> lodAsset;
modelLodCreator.End(lodAsset);
if (!lodAsset.IsReady())
{
// [GFX TODO] During mesh reload the modelLodCreator could report errors and result in the lodAsset not ready.
return nullptr;
}
modelCreator.AddLodAsset(AZStd::move(lodAsset));
lodIndex++;
@@ -267,6 +267,8 @@ set(FILES
Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h
Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp
Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.h
Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp
Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h
Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp
Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h
Source/ScreenSpace/DeferredFogSettings.cpp
@@ -57,6 +57,20 @@ namespace AZ
}
#endif
}
//! Prints a generic message at the appropriate indent level.
template<typename ... Args>
static void Printf([[maybe_unused]] const char* format, [[maybe_unused]] Args... args)
{
#ifdef AZ_ENABLE_SHADER_RELOAD_DEBUG_TRACKER
if (IsEnabled())
{
const AZStd::string message = AZStd::string::format(format, args...);
AZ_TracePrintf("ShaderReloadDebug", "%*s %s \n", s_indent, "", message.c_str());
}
#endif
}
//! Use this utility to call BeginSection(), and automatically call EndSection() when the object goes out of scope.
class ScopedSection final
@@ -97,6 +97,7 @@ namespace AZ
ShaderReloadNotificationBus::MultiHandler::BusDisconnect();
for (auto& shaderItem : m_shaderCollection)
{
ShaderReloadDebugTracker::Printf("(Material has ShaderAsset %p)", shaderItem.GetShaderAsset().Get());
ShaderReloadNotificationBus::MultiHandler::BusConnect(shaderItem.GetShaderAsset().GetId());
}
@@ -226,7 +227,7 @@ namespace AZ
// AssetBus overrides...
void Material::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnAssetReloaded %s", this, asset.GetHint().c_str());
Data::Asset<MaterialAsset> newMaterialAsset = { asset.GetAs<MaterialAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
@@ -241,7 +242,7 @@ namespace AZ
// MaterialReloadNotificationBus overrides...
void Material::OnMaterialAssetReinitialized(const Data::Asset<MaterialAsset>& materialAsset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnMaterialAssetReinitialized %s", materialAsset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnMaterialAssetReinitialized %s", this, materialAsset.GetHint().c_str());
OnAssetReloaded(materialAsset);
}
@@ -249,7 +250,7 @@ namespace AZ
// ShaderReloadNotificationBus overrides...
void Material::OnShaderReinitialized([[maybe_unused]] const Shader& shader)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnShaderReinitialized %s", shader.GetAsset().GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderReinitialized %s", this, shader.GetAsset().GetHint().c_str());
// Note that it might not be strictly necessary to reinitialize the entire material, we might be able to get away with
// just bumping the m_currentChangeId or some other minor updates. But it's pretty hard to know what exactly needs to be
// updated to correctly handle the reload, so it's safer to just reinitialize the whole material.
@@ -260,7 +261,7 @@ namespace AZ
{
// TODO: I think we should make Shader handle OnShaderAssetReinitialized and treat it just like the shader reloaded.
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnShaderAssetReinitialized %s", shaderAsset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderAssetReinitialized %s", this, shaderAsset.GetHint().c_str());
// Note that it might not be strictly necessary to reinitialize the entire material, we might be able to get away with
// just bumping the m_currentChangeId or some other minor updates. But it's pretty hard to know what exactly needs to be
// updated to correctly handle the reload, so it's safer to just reinitialize the whole material.
@@ -269,7 +270,7 @@ namespace AZ
void Material::OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& /*shaderVariantId*/, ShaderVariantStableId shaderVariantStableId)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Material::OnShaderVariantReinitialized %s variant %u", shader.GetAsset().GetHint().c_str(), shaderVariantStableId.GetIndex());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderVariantReinitialized %s variant %u", this, shader.GetAsset().GetHint().c_str(), shaderVariantStableId.GetIndex());
// Note that it would be better to check the shaderVariantId to see if that variant is relevant to this particular material before reinitializing it.
// There could be hundreds or even thousands of variants for a shader, but only one of those variants will be used by any given material. So we could
@@ -132,7 +132,7 @@ namespace AZ
// AssetBus overrides
void Shader::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("Shader::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Shader::OnAssetReloaded %s", this, asset.GetHint().c_str());
if (asset->GetId() == m_asset->GetId())
{
@@ -119,7 +119,7 @@ namespace AZ
void MaterialAsset::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("MaterialAsset::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->MaterialAsset::OnAssetReloaded %s", this, asset.GetHint().c_str());
Data::Asset<MaterialTypeAsset> newMaterialTypeAsset = { asset.GetAs<MaterialTypeAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
@@ -130,7 +130,7 @@ namespace AZ
void MaterialTypeAsset::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("MaterialTypeAsset::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->MaterialTypeAsset::OnAssetReloaded %s", this, asset.GetHint().c_str());
// The order of asset reloads is non-deterministic. If the MaterialTypeAsset reloads before these
// dependency assets, this will make sure the MaterialTypeAsset gets the latest ones when they reload.
@@ -381,7 +381,7 @@ namespace AZ
// AssetBus overrides...
void ShaderAsset::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("ShaderAsset::OnAssetReloaded %s", asset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderAsset::OnAssetReloaded %s", this, asset.GetHint().c_str());
Data::Asset<ShaderVariantAsset> shaderVariantAsset = { asset.GetAs<ShaderVariantAsset>(), AZ::Data::AssetLoadBehavior::PreLoad };
AZ_Assert(shaderVariantAsset->GetStableId() == RootShaderVariantStableId,
@@ -396,7 +396,7 @@ namespace AZ
/// ShaderVariantFinderNotificationBus overrides
void ShaderAsset::OnShaderVariantTreeAssetReady(Data::Asset<ShaderVariantTreeAsset> shaderVariantTreeAsset, bool isError)
{
ShaderReloadDebugTracker::ScopedSection reloadSection("ShaderAsset::OnShaderVariantTreeAssetReady %s", shaderVariantTreeAsset.GetHint().c_str());
ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderAsset::OnShaderVariantTreeAssetReady %s", this, shaderVariantTreeAsset.GetHint().c_str());
AZStd::unique_lock<decltype(m_variantTreeMutex)> lock(m_variantTreeMutex);
if (isError)
@@ -14,13 +14,14 @@
},
"clearCoat": {
"enable": true,
"normalMap": "EngineAssets/Textures/perlinNoiseNormal_ddn.tif"
"normalMap": "EngineAssets/Textures/perlinNoiseNormal_ddn.tif",
"normalStrength": 0.10000000149011612
},
"general": {
"applySpecularAA": true
},
"metallic": {
"factor": 0.5
"factor": 0.10000000149011612
},
"normal": {
"factor": 0.05000000074505806,
@@ -31,6 +32,9 @@
},
"roughness": {
"factor": 0.0
},
"specularF0": {
"enableMultiScatterCompensation": true
}
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
"Gem"
],
"user_tags": [
"AtomConent"
"AtomContent"
],
"icon_path": "preview.png"
}
@@ -112,13 +112,13 @@ namespace AZ
->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShutters, "Enable shutters", "Restrict the light to a specific beam angle depending on shape.")
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::ShuttersMustBeEnabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_innerShutterAngleDegrees, "Inner angle", "The inner angle of the shutters where the light beam begins to be occluded.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 180.0f)
->Attribute(Edit::Attributes::Min, 0.5f)
->Attribute(Edit::Attributes::Max, 90.0f)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled)
->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_outerShutterAngleDegrees, "Outer angle", "The outer angle of the shutters where the light beam is completely occluded.")
->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 180.0f)
->Attribute(Edit::Attributes::Min, 0.5f)
->Attribute(Edit::Attributes::Max, 90.0f)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled)
@@ -311,7 +311,8 @@ namespace AZ
Data::Asset<RPI::ModelAsset> modelAsset = actor->GetMeshAsset();
if (!modelAsset.IsReady())
{
AZ_Error("CreateSkinnedMeshInputFromActor", false, "Attempting to create skinned mesh input buffers for an actor that doesn't have a loaded model.");
AZ_Warning("CreateSkinnedMeshInputFromActor", false, "Check if the actor has a mesh added. Right click the source file in the asset browser, click edit settings, "
"and navigate to the Meshes tab. Add a mesh if it's missing.");
return nullptr;
}
@@ -456,9 +456,8 @@ namespace AZ
void AtomActorInstance::Create()
{
Destroy();
m_skinnedMeshInputBuffers = GetRenderActor()->FindOrCreateSkinnedMeshInputBuffers();
AZ_Error("AtomActorInstance", m_skinnedMeshInputBuffers, "Failed to get SkinnedMeshInputBuffers from Actor.");
AZ_Warning("AtomActorInstance", m_skinnedMeshInputBuffers, "Failed to create SkinnedMeshInputBuffers from Actor. It is likely that this actor doesn't have any meshes");
if (m_skinnedMeshInputBuffers)
{
m_boneTransforms = CreateBoneTransformBufferFromActorInstance(m_actorInstance, GetSkinningMethod());
@@ -69,10 +69,16 @@ proj.launch-config = {loc('../../SDK/Atom/Scripts/Python/DCC_Materials/maya_mate
loc('../../azpy/__init__.py'): ('custom',
(u'',
'launch-oobMrvXFf1SwtYBg')),
loc('../../azpy/constants.py'): ('custom',
(u'',
'launch-GeaM41WYMGA1sEfm')),
loc('../../azpy/env_base.py'): ('project',
(u'',
'launch-GeaM41WYMGA1sEfm')),
loc('../../azpy/maya/callbacks/node_message_callback_handler.py'): ('c'\
'ustom',
(u'',
'launch-GeaM41WYMGA1sEfm')),
loc('../../config.py'): ('custom',
(u'',
'launch-GeaM41WYMGA1sEfm'))}
@@ -165,12 +165,14 @@ def get_current_project():
bootstrap_box = None
try:
bootstrap_box = Box.from_json(filename=PATH_USER_O3DE_BOOTSTRAP,
bootstrap_box = Box.from_json(filename=str(Path(PATH_USER_O3DE_BOOTSTRAP).resolve()),
encoding="utf-8",
errors="strict",
object_pairs_hook=OrderedDict)
except FileExistsError as e:
_LOGGER.error('File does not exist: {}'.format(PATH_USER_O3DE_BOOTSTRAP))
except Exception as e:
# this file runs in py2.7 for Maya 2020, FileExistsError is not defined
_LOGGER.error('FileExistsError: {}'.format(PATH_USER_O3DE_BOOTSTRAP))
_LOGGER.error('exception is: {}'.format(e))
if bootstrap_box:
# this seems fairly hard coded - what if the data changes?
@@ -226,7 +226,18 @@ TAG_DEFAULT_PY = str('Launch_pyBASE.bat')
FILENAME_DEFAULT_CONFIG = str('DCCSI_config.json')
# new o3de related paths
PATH_USER_O3DE = str('{home}\\{o3de}').format(home=expanduser("~"),
# os.path.expanduser("~") returns different values in py2.7 vs 3
PATH_USER_HOME = expanduser("~")
_LOGGER.debug('user home: {}'.format(PATH_USER_HOME))
# special case, make sure didn't return <user>\documents
parts = os.path.split(PATH_USER_HOME)
if str(parts[1].lower()) == 'documents':
PATH_USER_HOME = parts[0]
_LOGGER.debug('user home CORRECTED: {}'.format(PATH_USER_HOME))
PATH_USER_O3DE = str('{home}\\{o3de}').format(home=PATH_USER_HOME,
o3de=TAG_O3DE_FOLDER)
PATH_USER_O3DE_REGISTRY = str('{0}\\Registry').format(PATH_USER_O3DE)
PATH_USER_O3DE_BOOTSTRAP = str('{reg}\\{file}').format(reg=PATH_USER_O3DE_REGISTRY,