Merge branch 'stabilization/2106' into LYN-4507
This commit is contained in:
@@ -22,7 +22,9 @@ AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option")
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
// AzCore
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
|
||||
// AzFramework
|
||||
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||
@@ -195,8 +197,15 @@ CEditorImpl::CEditorImpl()
|
||||
m_pAssetBrowserRequestHandler = nullptr;
|
||||
m_assetEditorRequestsHandler = nullptr;
|
||||
|
||||
AZ::IO::SystemFile::CreateDir("SessionStatus");
|
||||
QFile::setPermissions(m_crashLogFileName, QFileDevice::ReadOther | QFileDevice::WriteOther);
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath crashLogPath; settingsRegistry->Get(crashLogPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath))
|
||||
{
|
||||
crashLogPath /= m_crashLogFileName;
|
||||
AZ::IO::SystemFile::CreateDir(crashLogPath.ParentPath().FixedMaxPathString().c_str());
|
||||
QFile::setPermissions(crashLogPath.c_str(), QFileDevice::ReadOther | QFileDevice::WriteOther);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEditorImpl::Initialize()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:263e95489560dac6e5944ef3caba13e598f83ddead324b943ad7735ba015e1a9
|
||||
size 70727
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1cf8339fb51f82a68d2ab475c0476960e75a79d96d239c5b7cd272fbe4990ffe
|
||||
size 2770
|
||||
@@ -75,6 +75,21 @@ WelcomeScreenDialog::WelcomeScreenDialog(QWidget* pParent)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Set the project preview image
|
||||
QString projectPreviewPath = QDir(AZ::Utils::GetProjectPath().c_str()).filePath("preview.png");
|
||||
QFileInfo projectPreviewPathInfo(projectPreviewPath);
|
||||
if (!projectPreviewPathInfo.exists() || !projectPreviewPathInfo.isFile())
|
||||
{
|
||||
projectPreviewPath = ":/WelcomeScreenDialog/DefaultProjectImage.png";
|
||||
}
|
||||
ui->activeProjectIcon->setPixmap(
|
||||
QPixmap(projectPreviewPath).scaled(
|
||||
ui->activeProjectIcon->size(),
|
||||
Qt::KeepAspectRatioByExpanding,
|
||||
Qt::SmoothTransformation
|
||||
)
|
||||
);
|
||||
|
||||
ui->recentLevelTable->setColumnCount(3);
|
||||
ui->recentLevelTable->setMouseTracking(true);
|
||||
ui->recentLevelTable->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="WelcomeScreenDialog">
|
||||
<file>DefaultActiveProject.png</file>
|
||||
<file>DefaultProjectImage.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -158,11 +158,8 @@
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="WelcomeScreenDialog.qrc">:/WelcomeScreenDialog/DefaultActiveProject.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<set>Qt::AlignHCenter | Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -229,7 +229,6 @@ set(FILES
|
||||
res/warning16x16.ico
|
||||
res/water.bmp
|
||||
res/work_in_progress_icon.ico
|
||||
res/LegacyLogo.bmp
|
||||
res/MannFileManagerImageList.bmp
|
||||
res/infobar/CameraCollision-default.svg
|
||||
res/infobar/GotoLocation-default.svg
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:97f4004da6ec1bf07d522d6675f814e53e36923a45084ff5d7e4113e293d4fec
|
||||
size 117656
|
||||
@@ -41,7 +41,7 @@ ly_add_target(
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME AmazonQtControlGallery APPLICATION
|
||||
NAME O3DEQtControlGallery APPLICATION
|
||||
NAMESPACE AZ
|
||||
AUTOMOC
|
||||
AUTOUIC
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <AzToolsFramework/UI/UICore/QTreeViewStateSaver.hxx>
|
||||
#include <AzToolsFramework/UI/UICore/QWidgetSavedState.h>
|
||||
#include <AzToolsFramework/UI/UICore/ProgressShield.hxx>
|
||||
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
|
||||
#include <AzToolsFramework/Slice/SliceUtilities.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorInspectorComponent.h>
|
||||
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
|
||||
@@ -1589,7 +1590,13 @@ namespace AzToolsFramework
|
||||
// Multiple changes to the same entity are just split between different undo nodes.
|
||||
for (AZ::EntityId entityId : m_dirtyEntities)
|
||||
{
|
||||
prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_currentBatchUndo);
|
||||
auto outcome = prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_currentBatchUndo);
|
||||
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
QMessageBox::warning(
|
||||
AzToolsFramework::GetActiveWindow(), QString("Error"), QString(outcome.GetError().c_str()), QMessageBox::Ok, QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,21 +587,21 @@ namespace AzToolsFramework
|
||||
return AZ::Success(entityId);
|
||||
}
|
||||
|
||||
void PrefabPublicHandler::GenerateUndoNodesForEntityChangeAndUpdateCache(
|
||||
PrefabOperationResult PrefabPublicHandler::GenerateUndoNodesForEntityChangeAndUpdateCache(
|
||||
AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch)
|
||||
{
|
||||
// Create Undo node on entities if they belong to an instance
|
||||
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
||||
if (!owningInstance.has_value())
|
||||
{
|
||||
return;
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
AZ::Entity* entity = GetEntityById(entityId);
|
||||
if (!entity)
|
||||
{
|
||||
m_prefabUndoCache.PurgeCache(entityId);
|
||||
return;
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabDom beforeState;
|
||||
@@ -633,6 +633,41 @@ namespace AzToolsFramework
|
||||
(&beforeOwningInstance->get() != &afterOwningInstance->get()))
|
||||
{
|
||||
isNewParentOwnedByDifferentInstance = true;
|
||||
|
||||
// Detect loops. Assert if an instance has been reparented in such a way to generate circular dependencies.
|
||||
AZStd::vector<Instance*> instancesInvolved;
|
||||
|
||||
if (isInstanceContainerEntity)
|
||||
{
|
||||
instancesInvolved.push_back(&owningInstance->get());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Retrieve all nested instances that are part of the subtree under the current entity.
|
||||
EntityList entities;
|
||||
RetrieveAndSortPrefabEntitiesAndInstances({ entity }, beforeOwningInstance->get(), entities, instancesInvolved);
|
||||
}
|
||||
|
||||
for (Instance* instance : instancesInvolved)
|
||||
{
|
||||
const PrefabDom& templateDom =
|
||||
m_prefabSystemComponentInterface->FindTemplateDom(instance->GetTemplateId());
|
||||
AZStd::unordered_set<AZ::IO::Path> templatePaths;
|
||||
PrefabDomUtils::GetTemplateSourcePaths(templateDom, templatePaths);
|
||||
|
||||
if (IsCyclicalDependencyFound(afterOwningInstance->get(), templatePaths))
|
||||
{
|
||||
// Cancel the operation by restoring the previous parent
|
||||
AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetParent, beforeParentId);
|
||||
m_prefabUndoCache.UpdateCache(entityId);
|
||||
|
||||
// Skip the creation of an undo node
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Reparent Prefab operation aborted - Cyclical dependency detected\n(%s depends on %s).",
|
||||
instance->GetTemplateSourcePath().Native().c_str(),
|
||||
afterOwningInstance->get().GetTemplateSourcePath().Native().c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,6 +708,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_prefabUndoCache.UpdateCache(entityId);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
void PrefabPublicHandler::Internal_HandleContainerOverride(
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace AzToolsFramework
|
||||
PrefabOperationResult SavePrefab(AZ::IO::Path filePath) override;
|
||||
PrefabEntityResult CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position) override;
|
||||
|
||||
void GenerateUndoNodesForEntityChangeAndUpdateCache(AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch) override;
|
||||
PrefabOperationResult GenerateUndoNodesForEntityChangeAndUpdateCache(AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch) override;
|
||||
|
||||
bool IsInstanceContainerEntity(AZ::EntityId entityId) const override;
|
||||
bool IsLevelInstanceContainerEntity(AZ::EntityId entityId) const override;
|
||||
|
||||
@@ -79,8 +79,9 @@ namespace AzToolsFramework
|
||||
*
|
||||
* @param entityId The entity to patch.
|
||||
* @param parentUndoBatch The undo batch the undo nodes should be parented to.
|
||||
* @return Returns Success if the node was generated correctly, or an error message otherwise.
|
||||
*/
|
||||
virtual void GenerateUndoNodesForEntityChangeAndUpdateCache(
|
||||
virtual PrefabOperationResult GenerateUndoNodesForEntityChangeAndUpdateCache(
|
||||
AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch) = 0;
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,7 +84,10 @@ namespace AssetProcessor
|
||||
AssetProcessorTest::TearDown();
|
||||
}
|
||||
|
||||
void OnError([[maybe_unused]] const AZ::IO::SystemFile* file, const char* fileName, int errorCode) override
|
||||
void OnError(
|
||||
[[maybe_unused]] const AZ::IO::SystemFile* file,
|
||||
[[maybe_unused]] const char* fileName,
|
||||
[[maybe_unused]] int errorCode) override
|
||||
{
|
||||
AZ_Error("LegacyTestAdapter", false, "File error detected with %s with code %d", fileName, errorCode);
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
|
||||
set(FILES
|
||||
Python_linux.cpp
|
||||
ProjectBuilderWorker_linux.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectBuilderWorker.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
AZ::Outcome<void, QString> ProjectBuilderWorker::BuildProjectForPlatform()
|
||||
{
|
||||
QString error = tr("Automatic building on Linux not currently supported!");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -7,4 +7,5 @@
|
||||
|
||||
set(FILES
|
||||
Python_mac.cpp
|
||||
ProjectBuilderWorker_mac.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectBuilderWorker.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
AZ::Outcome<void, QString> ProjectBuilderWorker::BuildProjectForPlatform()
|
||||
{
|
||||
QString error = tr("Automatic building on MacOS not currently supported!");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -7,4 +7,5 @@
|
||||
|
||||
set(FILES
|
||||
Python_windows.cpp
|
||||
ProjectBuilderWorker_windows.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectBuilderWorker.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QTextStream>
|
||||
#include <QThread>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
AZ::Outcome<void, QString> ProjectBuilderWorker::BuildProjectForPlatform()
|
||||
{
|
||||
// Check if we are trying to cancel task
|
||||
if (QThread::currentThread()->isInterruptionRequested())
|
||||
{
|
||||
QStringToAZTracePrint(BuildCancelled);
|
||||
return AZ::Failure(BuildCancelled);
|
||||
}
|
||||
|
||||
QFile logFile(GetLogFilePath());
|
||||
if (!logFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
|
||||
{
|
||||
QString error = tr("Failed to open log file.");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
EngineInfo engineInfo;
|
||||
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString error = tr("Failed to get engine info.");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
QTextStream logStream(&logFile);
|
||||
if (QThread::currentThread()->isInterruptionRequested())
|
||||
{
|
||||
logFile.close();
|
||||
QStringToAZTracePrint(BuildCancelled);
|
||||
return AZ::Failure(BuildCancelled);
|
||||
}
|
||||
|
||||
// Show some kind of progress with very approximate estimates
|
||||
UpdateProgress(++m_progressEstimate);
|
||||
|
||||
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
|
||||
// Append cmake path to PATH incase it is missing
|
||||
QDir cmakePath(engineInfo.m_path);
|
||||
cmakePath.cd("cmake/runtime/bin");
|
||||
QString pathValue = currentEnvironment.value("PATH");
|
||||
pathValue += ";" + cmakePath.path();
|
||||
currentEnvironment.insert("PATH", pathValue);
|
||||
|
||||
m_configProjectProcess = new QProcess(this);
|
||||
m_configProjectProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
m_configProjectProcess->setWorkingDirectory(m_projectInfo.m_path);
|
||||
m_configProjectProcess->setProcessEnvironment(currentEnvironment);
|
||||
|
||||
m_configProjectProcess->start(
|
||||
"cmake",
|
||||
QStringList{ "-B", QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix), "-S", m_projectInfo.m_path, "-G",
|
||||
"Visual Studio 16", "-DLY_3RDPARTY_PATH=" + engineInfo.m_thirdPartyPath });
|
||||
|
||||
if (!m_configProjectProcess->waitForStarted())
|
||||
{
|
||||
QString error = tr("Configuring project failed to start.");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
bool containsGeneratingDone = false;
|
||||
while (m_configProjectProcess->waitForReadyRead(MaxBuildTimeMSecs))
|
||||
{
|
||||
QString configOutput = m_configProjectProcess->readAllStandardOutput();
|
||||
|
||||
if (configOutput.contains("Generating done"))
|
||||
{
|
||||
containsGeneratingDone = true;
|
||||
}
|
||||
|
||||
logStream << configOutput;
|
||||
logStream.flush();
|
||||
|
||||
UpdateProgress(qMin(++m_progressEstimate, 19));
|
||||
|
||||
if (QThread::currentThread()->isInterruptionRequested())
|
||||
{
|
||||
logFile.close();
|
||||
m_configProjectProcess->close();
|
||||
QStringToAZTracePrint(BuildCancelled);
|
||||
return AZ::Failure(BuildCancelled);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_configProjectProcess->exitCode() != 0 || !containsGeneratingDone)
|
||||
{
|
||||
QString error = tr("Configuring project failed. See log for details.");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
UpdateProgress(++m_progressEstimate);
|
||||
|
||||
m_buildProjectProcess = new QProcess(this);
|
||||
m_buildProjectProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
m_buildProjectProcess->setWorkingDirectory(m_projectInfo.m_path);
|
||||
m_buildProjectProcess->setProcessEnvironment(currentEnvironment);
|
||||
|
||||
m_buildProjectProcess->start(
|
||||
"cmake",
|
||||
QStringList{ "--build", QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix), "--target",
|
||||
m_projectInfo.m_projectName + ".GameLauncher", "Editor", "--config", "profile" });
|
||||
|
||||
if (!m_buildProjectProcess->waitForStarted())
|
||||
{
|
||||
QString error = tr("Building project failed to start.");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
// There are a lot of steps when building so estimate around 800 more steps ((100 - 20) * 10) remaining
|
||||
m_progressEstimate = 200;
|
||||
while (m_buildProjectProcess->waitForReadyRead(MaxBuildTimeMSecs))
|
||||
{
|
||||
logStream << m_buildProjectProcess->readAllStandardOutput();
|
||||
logStream.flush();
|
||||
|
||||
// Show 1% progress for every 10 steps completed
|
||||
UpdateProgress(qMin(++m_progressEstimate / 10, 99));
|
||||
|
||||
if (QThread::currentThread()->isInterruptionRequested())
|
||||
{
|
||||
// QProcess is unable to kill its child processes so we need to ask the operating system to do that for us
|
||||
QProcess killBuildProcess;
|
||||
killBuildProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
killBuildProcess.start(
|
||||
"cmd.exe", QStringList{ "/C", "taskkill", "/pid", QString::number(m_buildProjectProcess->processId()), "/f", "/t" });
|
||||
killBuildProcess.waitForFinished();
|
||||
|
||||
logStream << "Killing Project Build.";
|
||||
logStream << killBuildProcess.readAllStandardOutput();
|
||||
m_buildProjectProcess->kill();
|
||||
logFile.close();
|
||||
QStringToAZTracePrint(BuildCancelled);
|
||||
return AZ::Failure(BuildCancelled);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_configProjectProcess->exitCode() != 0)
|
||||
{
|
||||
QString error = tr("Building project failed. See log for details.");
|
||||
QStringToAZTracePrint(error);
|
||||
return AZ::Failure(error);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -131,6 +131,17 @@ namespace O3DE::ProjectManager
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::KeyPress)
|
||||
{
|
||||
auto keyEvent = static_cast<const QKeyEvent*>(event);
|
||||
if (keyEvent->key() == Qt::Key_Space)
|
||||
{
|
||||
const bool isAdded = GemModel::IsAdded(modelIndex);
|
||||
GemModel::SetIsAdded(*model, modelIndex, !isAdded);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectBuilder.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
#include <ProjectButtonWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
|
||||
//#define MOCK_BUILD_PROJECT true
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
// QProcess::waitForFinished uses -1 to indicate that the process should not timeout
|
||||
constexpr int MaxBuildTimeMSecs = -1;
|
||||
|
||||
ProjectBuilderWorker::ProjectBuilderWorker(const ProjectInfo& projectInfo)
|
||||
: QObject()
|
||||
, m_projectInfo(projectInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void ProjectBuilderWorker::BuildProject()
|
||||
{
|
||||
#ifdef MOCK_BUILD_PROJECT
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
QThread::sleep(1);
|
||||
UpdateProgress(i * 10);
|
||||
}
|
||||
Done(m_projectPath);
|
||||
#else
|
||||
EngineInfo engineInfo;
|
||||
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
emit Done(tr("Failed to get engine info."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Show some kind of progress with very approximate estimates
|
||||
UpdateProgress(1);
|
||||
|
||||
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
|
||||
// Append cmake path to PATH incase it is missing
|
||||
QDir cmakePath(engineInfo.m_path);
|
||||
cmakePath.cd("cmake/runtime/bin");
|
||||
QString pathValue = currentEnvironment.value("PATH");
|
||||
pathValue += ";" + cmakePath.path();
|
||||
currentEnvironment.insert("PATH", pathValue);
|
||||
|
||||
QProcess configProjectProcess;
|
||||
configProjectProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
configProjectProcess.setWorkingDirectory(m_projectInfo.m_path);
|
||||
configProjectProcess.setProcessEnvironment(currentEnvironment);
|
||||
|
||||
configProjectProcess.start(
|
||||
"cmake",
|
||||
QStringList
|
||||
{
|
||||
"-B",
|
||||
QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
|
||||
"-S",
|
||||
m_projectInfo.m_path,
|
||||
"-G",
|
||||
"Visual Studio 16",
|
||||
"-DLY_3RDPARTY_PATH=" + engineInfo.m_thirdPartyPath
|
||||
});
|
||||
|
||||
if (!configProjectProcess.waitForStarted())
|
||||
{
|
||||
emit Done(tr("Configuring project failed to start."));
|
||||
return;
|
||||
}
|
||||
if (!configProjectProcess.waitForFinished(MaxBuildTimeMSecs))
|
||||
{
|
||||
WriteErrorLog(configProjectProcess.readAllStandardOutput());
|
||||
emit Done(tr("Configuring project timed out. See log for details"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString configProjectOutput(configProjectProcess.readAllStandardOutput());
|
||||
if (configProjectProcess.exitCode() != 0 || !configProjectOutput.contains("Generating done"))
|
||||
{
|
||||
WriteErrorLog(configProjectOutput);
|
||||
emit Done(tr("Configuring project failed. See log for details."));
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateProgress(20);
|
||||
|
||||
QProcess buildProjectProcess;
|
||||
buildProjectProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
buildProjectProcess.setWorkingDirectory(m_projectInfo.m_path);
|
||||
buildProjectProcess.setProcessEnvironment(currentEnvironment);
|
||||
|
||||
buildProjectProcess.start(
|
||||
"cmake",
|
||||
QStringList
|
||||
{
|
||||
"--build",
|
||||
QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
|
||||
"--target",
|
||||
m_projectInfo.m_projectName + ".GameLauncher",
|
||||
"Editor",
|
||||
"--config",
|
||||
"profile"
|
||||
});
|
||||
|
||||
if (!buildProjectProcess.waitForStarted())
|
||||
{
|
||||
emit Done(tr("Building project failed to start."));
|
||||
return;
|
||||
}
|
||||
if (!buildProjectProcess.waitForFinished(MaxBuildTimeMSecs))
|
||||
{
|
||||
WriteErrorLog(configProjectProcess.readAllStandardOutput());
|
||||
emit Done(tr("Building project timed out. See log for details"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString buildProjectOutput(buildProjectProcess.readAllStandardOutput());
|
||||
if (configProjectProcess.exitCode() != 0)
|
||||
{
|
||||
WriteErrorLog(buildProjectOutput);
|
||||
emit Done(tr("Building project failed. See log for details."));
|
||||
}
|
||||
else
|
||||
{
|
||||
emit Done("");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ProjectBuilderWorker::LogFilePath() const
|
||||
{
|
||||
QDir logFilePath(m_projectInfo.m_path);
|
||||
logFilePath.cd(ProjectBuildPathPostfix);
|
||||
return logFilePath.filePath(ProjectBuildErrorLogPathPostfix);
|
||||
}
|
||||
|
||||
void ProjectBuilderWorker::WriteErrorLog(const QString& log)
|
||||
{
|
||||
QFile logFile(LogFilePath());
|
||||
// Overwrite file with truncate
|
||||
if (logFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
QTextStream output(&logFile);
|
||||
output << log;
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
ProjectBuilderController::ProjectBuilderController(const ProjectInfo& projectInfo, ProjectButton* projectButton, QWidget* parent)
|
||||
: QObject()
|
||||
, m_projectInfo(projectInfo)
|
||||
, m_projectButton(projectButton)
|
||||
, m_parent(parent)
|
||||
{
|
||||
m_worker = new ProjectBuilderWorker(m_projectInfo);
|
||||
m_worker->moveToThread(&m_workerThread);
|
||||
|
||||
connect(&m_workerThread, &QThread::finished, m_worker, &ProjectBuilderWorker::deleteLater);
|
||||
connect(&m_workerThread, &QThread::started, m_worker, &ProjectBuilderWorker::BuildProject);
|
||||
connect(m_worker, &ProjectBuilderWorker::Done, this, &ProjectBuilderController::HandleResults);
|
||||
connect(m_worker, &ProjectBuilderWorker::UpdateProgress, this, &ProjectBuilderController::UpdateUIProgress);
|
||||
}
|
||||
|
||||
ProjectBuilderController::~ProjectBuilderController()
|
||||
{
|
||||
m_workerThread.quit();
|
||||
m_workerThread.wait();
|
||||
}
|
||||
|
||||
void ProjectBuilderController::Start()
|
||||
{
|
||||
m_workerThread.start();
|
||||
UpdateUIProgress(0);
|
||||
}
|
||||
|
||||
void ProjectBuilderController::SetProjectButton(ProjectButton* projectButton)
|
||||
{
|
||||
m_projectButton = projectButton;
|
||||
}
|
||||
|
||||
QString ProjectBuilderController::GetProjectPath() const
|
||||
{
|
||||
return m_projectInfo.m_path;
|
||||
}
|
||||
|
||||
void ProjectBuilderController::UpdateUIProgress(int progress)
|
||||
{
|
||||
if (m_projectButton)
|
||||
{
|
||||
m_projectButton->SetButtonOverlayText(QString("%1 (%2%)\n\n").arg(tr("Building Project..."), QString::number(progress)));
|
||||
m_projectButton->SetProgressBarValue(progress);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBuilderController::HandleResults(const QString& result)
|
||||
{
|
||||
if (!result.isEmpty())
|
||||
{
|
||||
if (result.contains(tr("log")))
|
||||
{
|
||||
QMessageBox::StandardButton openLog = QMessageBox::critical(
|
||||
m_parent,
|
||||
tr("Project Failed to Build!"),
|
||||
result + tr("\n\nWould you like to view log?"),
|
||||
QMessageBox::No | QMessageBox::Yes);
|
||||
|
||||
if (openLog == QMessageBox::Yes)
|
||||
{
|
||||
// Open application assigned to this file type
|
||||
QDesktopServices::openUrl(QUrl("file:///" + m_worker->LogFilePath()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(m_parent, tr("Project Failed to Build!"), result);
|
||||
}
|
||||
}
|
||||
|
||||
emit Done();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectBuilderController.h>
|
||||
#include <ProjectBuilderWorker.h>
|
||||
#include <ProjectButtonWidget.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectBuilderController::ProjectBuilderController(const ProjectInfo& projectInfo, ProjectButton* projectButton, QWidget* parent)
|
||||
: QObject()
|
||||
, m_projectInfo(projectInfo)
|
||||
, m_projectButton(projectButton)
|
||||
, m_lastProgress(0)
|
||||
, m_parent(parent)
|
||||
{
|
||||
m_worker = new ProjectBuilderWorker(m_projectInfo);
|
||||
m_worker->moveToThread(&m_workerThread);
|
||||
|
||||
connect(&m_workerThread, &QThread::finished, m_worker, &ProjectBuilderWorker::deleteLater);
|
||||
connect(&m_workerThread, &QThread::started, m_worker, &ProjectBuilderWorker::BuildProject);
|
||||
connect(m_worker, &ProjectBuilderWorker::Done, this, &ProjectBuilderController::HandleResults);
|
||||
connect(m_worker, &ProjectBuilderWorker::UpdateProgress, this, &ProjectBuilderController::UpdateUIProgress);
|
||||
}
|
||||
|
||||
ProjectBuilderController::~ProjectBuilderController()
|
||||
{
|
||||
m_workerThread.requestInterruption();
|
||||
m_workerThread.quit();
|
||||
m_workerThread.wait();
|
||||
}
|
||||
|
||||
void ProjectBuilderController::Start()
|
||||
{
|
||||
m_workerThread.start();
|
||||
UpdateUIProgress(0);
|
||||
}
|
||||
|
||||
void ProjectBuilderController::SetProjectButton(ProjectButton* projectButton)
|
||||
{
|
||||
m_projectButton = projectButton;
|
||||
|
||||
if (projectButton)
|
||||
{
|
||||
projectButton->SetProjectButtonAction(tr("Cancel Build"), [this] { HandleCancel(); });
|
||||
|
||||
if (m_lastProgress != 0)
|
||||
{
|
||||
UpdateUIProgress(m_lastProgress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ProjectInfo& ProjectBuilderController::GetProjectInfo() const
|
||||
{
|
||||
return m_projectInfo;
|
||||
}
|
||||
|
||||
void ProjectBuilderController::UpdateUIProgress(int progress)
|
||||
{
|
||||
m_lastProgress = progress;
|
||||
if (m_projectButton)
|
||||
{
|
||||
m_projectButton->SetButtonOverlayText(QString("%1 (%2%)\n\n").arg(tr("Building Project..."), QString::number(progress)));
|
||||
m_projectButton->SetProgressBarValue(progress);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBuilderController::HandleResults(const QString& result)
|
||||
{
|
||||
if (!result.isEmpty())
|
||||
{
|
||||
if (result.contains(tr("log")))
|
||||
{
|
||||
QMessageBox::StandardButton openLog = QMessageBox::critical(
|
||||
m_parent,
|
||||
tr("Project Failed to Build!"),
|
||||
result + tr("\n\nWould you like to view log?"),
|
||||
QMessageBox::No | QMessageBox::Yes);
|
||||
|
||||
if (openLog == QMessageBox::Yes)
|
||||
{
|
||||
// Open application assigned to this file type
|
||||
QDesktopServices::openUrl(QUrl("file:///" + m_worker->GetLogFilePath()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(m_parent, tr("Project Failed to Build!"), result);
|
||||
}
|
||||
|
||||
emit Done(false);
|
||||
return;
|
||||
}
|
||||
|
||||
emit Done(true);
|
||||
}
|
||||
|
||||
void ProjectBuilderController::HandleCancel()
|
||||
{
|
||||
m_workerThread.quit();
|
||||
emit Done(false);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
+8
-25
@@ -12,32 +12,12 @@
|
||||
#include <QThread>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QProcess)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(ProjectButton)
|
||||
|
||||
class ProjectBuilderWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProjectBuilderWorker(const ProjectInfo& projectInfo);
|
||||
~ProjectBuilderWorker() = default;
|
||||
|
||||
QString LogFilePath() const;
|
||||
|
||||
public slots:
|
||||
void BuildProject();
|
||||
|
||||
signals:
|
||||
void UpdateProgress(int progress);
|
||||
void Done(QString result);
|
||||
|
||||
private:
|
||||
void WriteErrorLog(const QString& log);
|
||||
|
||||
ProjectInfo m_projectInfo;
|
||||
};
|
||||
QT_FORWARD_DECLARE_CLASS(ProjectBuilderWorker)
|
||||
|
||||
class ProjectBuilderController : public QObject
|
||||
{
|
||||
@@ -48,15 +28,16 @@ namespace O3DE::ProjectManager
|
||||
~ProjectBuilderController();
|
||||
|
||||
void SetProjectButton(ProjectButton* projectButton);
|
||||
QString GetProjectPath() const;
|
||||
const ProjectInfo& GetProjectInfo() const;
|
||||
|
||||
public slots:
|
||||
void Start();
|
||||
void UpdateUIProgress(int progress);
|
||||
void HandleResults(const QString& result);
|
||||
void HandleCancel();
|
||||
|
||||
signals:
|
||||
void Done();
|
||||
void Done(bool success = true);
|
||||
|
||||
private:
|
||||
ProjectInfo m_projectInfo;
|
||||
@@ -64,5 +45,7 @@ namespace O3DE::ProjectManager
|
||||
QThread m_workerThread;
|
||||
ProjectButton* m_projectButton;
|
||||
QWidget* m_parent;
|
||||
|
||||
int m_lastProgress;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectBuilderWorker.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
//#define MOCK_BUILD_PROJECT true
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
const QString ProjectBuilderWorker::BuildCancelled = ProjectBuilderWorker::tr("Build Cancelled.");
|
||||
|
||||
ProjectBuilderWorker::ProjectBuilderWorker(const ProjectInfo& projectInfo)
|
||||
: QObject()
|
||||
, m_projectInfo(projectInfo)
|
||||
, m_progressEstimate(0)
|
||||
{
|
||||
}
|
||||
|
||||
void ProjectBuilderWorker::BuildProject()
|
||||
{
|
||||
#ifdef MOCK_BUILD_PROJECT
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
QThread::sleep(1);
|
||||
UpdateProgress(i * 10);
|
||||
}
|
||||
Done("");
|
||||
#else
|
||||
auto result = BuildProjectForPlatform();
|
||||
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
emit Done();
|
||||
}
|
||||
else
|
||||
{
|
||||
emit Done(result.GetError());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ProjectBuilderWorker::GetLogFilePath() const
|
||||
{
|
||||
QDir logFilePath(m_projectInfo.m_path);
|
||||
// Make directories if they aren't on disk
|
||||
if (!logFilePath.cd(ProjectBuildPathPostfix))
|
||||
{
|
||||
logFilePath.mkpath(ProjectBuildPathPostfix);
|
||||
logFilePath.cd(ProjectBuildPathPostfix);
|
||||
|
||||
}
|
||||
if (!logFilePath.cd(ProjectBuildPathCmakeFiles))
|
||||
{
|
||||
logFilePath.mkpath(ProjectBuildPathCmakeFiles);
|
||||
logFilePath.cd(ProjectBuildPathCmakeFiles);
|
||||
}
|
||||
return logFilePath.filePath(ProjectBuildErrorLogName);
|
||||
}
|
||||
|
||||
void ProjectBuilderWorker::QStringToAZTracePrint([[maybe_unused]] const QString& error)
|
||||
{
|
||||
AZ_TracePrintf("Project Manager", error.toStdString().c_str());
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ProjectInfo.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
|
||||
#include <QObject>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QProcess)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class ProjectBuilderWorker : public QObject
|
||||
{
|
||||
// QProcess::waitForFinished uses -1 to indicate that the process should not timeout
|
||||
static constexpr int MaxBuildTimeMSecs = -1;
|
||||
// Build was cancelled
|
||||
static const QString BuildCancelled;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProjectBuilderWorker(const ProjectInfo& projectInfo);
|
||||
~ProjectBuilderWorker() = default;
|
||||
|
||||
QString GetLogFilePath() const;
|
||||
|
||||
public slots:
|
||||
void BuildProject();
|
||||
|
||||
signals:
|
||||
void UpdateProgress(int progress);
|
||||
void Done(QString result = "");
|
||||
|
||||
private:
|
||||
AZ::Outcome<void, QString> BuildProjectForPlatform();
|
||||
void QStringToAZTracePrint(const QString& error);
|
||||
|
||||
QProcess* m_configProjectProcess = nullptr;
|
||||
QProcess* m_buildProjectProcess = nullptr;
|
||||
ProjectInfo m_projectInfo;
|
||||
|
||||
int m_progressEstimate;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -40,8 +40,8 @@ namespace O3DE::ProjectManager
|
||||
m_overlayLabel->setVisible(false);
|
||||
vLayout->addWidget(m_overlayLabel);
|
||||
|
||||
m_buildButton = new QPushButton(tr("Build Project"), this);
|
||||
m_buildButton->setVisible(false);
|
||||
m_actionButton = new QPushButton(tr("Project Action"), this);
|
||||
m_actionButton->setVisible(false);
|
||||
|
||||
m_progressBar = new QProgressBar(this);
|
||||
m_progressBar->setObjectName("labelButtonProgressBar");
|
||||
@@ -78,9 +78,9 @@ namespace O3DE::ProjectManager
|
||||
return m_progressBar;
|
||||
}
|
||||
|
||||
QPushButton* LabelButton::GetBuildButton()
|
||||
QPushButton* LabelButton::GetActionButton()
|
||||
{
|
||||
return m_buildButton;
|
||||
return m_actionButton;
|
||||
}
|
||||
|
||||
ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent, bool processing)
|
||||
@@ -135,7 +135,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void ProjectButton::ProcessingSetup()
|
||||
{
|
||||
m_projectImageLabel->GetOverlayLabel()->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||
m_projectImageLabel->SetEnabled(false);
|
||||
m_projectImageLabel->SetOverlayText(tr("Processing...\n\n"));
|
||||
|
||||
@@ -146,8 +145,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void ProjectButton::ReadySetup()
|
||||
{
|
||||
connect(m_projectImageLabel->GetBuildButton(), &QPushButton::clicked, [this](){ emit BuildProject(m_projectInfo); });
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); });
|
||||
menu->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); });
|
||||
@@ -168,20 +165,40 @@ namespace O3DE::ProjectManager
|
||||
m_projectFooter->layout()->addWidget(projectMenuButton);
|
||||
}
|
||||
|
||||
void ProjectButton::SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda)
|
||||
{
|
||||
QPushButton* projectActionButton = m_projectImageLabel->GetActionButton();
|
||||
if (!m_actionButtonConnection)
|
||||
{
|
||||
QSpacerItem* buttonSpacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
m_projectImageLabel->layout()->addItem(buttonSpacer);
|
||||
m_projectImageLabel->layout()->addWidget(projectActionButton);
|
||||
projectActionButton->setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnect(m_actionButtonConnection);
|
||||
}
|
||||
|
||||
projectActionButton->setText(text);
|
||||
m_actionButtonConnection = connect(projectActionButton, &QPushButton::clicked, lambda);
|
||||
}
|
||||
|
||||
void ProjectButton::SetProjectBuildButtonAction()
|
||||
{
|
||||
SetProjectButtonAction(tr("Build Project"), [this]() { emit BuildProject(m_projectInfo); });
|
||||
}
|
||||
|
||||
void ProjectButton::BuildThisProject()
|
||||
{
|
||||
emit BuildProject(m_projectInfo);
|
||||
}
|
||||
|
||||
void ProjectButton::SetLaunchButtonEnabled(bool enabled)
|
||||
{
|
||||
m_projectImageLabel->SetEnabled(enabled);
|
||||
}
|
||||
|
||||
void ProjectButton::ShowBuildButton(bool show)
|
||||
{
|
||||
QSpacerItem* buttonSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
m_projectImageLabel->layout()->addItem(buttonSpacer);
|
||||
m_projectImageLabel->layout()->addWidget(m_projectImageLabel->GetBuildButton());
|
||||
m_projectImageLabel->GetBuildButton()->setVisible(show);
|
||||
}
|
||||
|
||||
void ProjectButton::SetButtonOverlayText(const QString& text)
|
||||
{
|
||||
m_projectImageLabel->SetOverlayText(text);
|
||||
@@ -191,4 +208,9 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
m_projectImageLabel->GetProgressBar()->setValue(progress);
|
||||
}
|
||||
|
||||
LabelButton* ProjectButton::GetLabelButton()
|
||||
{
|
||||
return m_projectImageLabel;
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ProjectInfo.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QSpacerItem>
|
||||
#include <QLayout>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QPixmap)
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
QT_FORWARD_DECLARE_CLASS(QAction)
|
||||
QT_FORWARD_DECLARE_CLASS(QProgressBar)
|
||||
|
||||
@@ -34,7 +37,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QLabel* GetOverlayLabel();
|
||||
QProgressBar* GetProgressBar();
|
||||
QPushButton* GetBuildButton();
|
||||
QPushButton* GetActionButton();
|
||||
|
||||
signals:
|
||||
void triggered();
|
||||
@@ -45,7 +48,7 @@ namespace O3DE::ProjectManager
|
||||
private:
|
||||
QLabel* m_overlayLabel;
|
||||
QProgressBar* m_progressBar;
|
||||
QPushButton* m_buildButton;
|
||||
QPushButton* m_actionButton;
|
||||
bool m_enabled = true;
|
||||
};
|
||||
|
||||
@@ -58,10 +61,13 @@ namespace O3DE::ProjectManager
|
||||
explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr, bool processing = false);
|
||||
~ProjectButton() = default;
|
||||
|
||||
void SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda);
|
||||
void SetProjectBuildButtonAction();
|
||||
|
||||
void SetLaunchButtonEnabled(bool enabled);
|
||||
void ShowBuildButton(bool show);
|
||||
void SetButtonOverlayText(const QString& text);
|
||||
void SetProgressBarValue(int progress);
|
||||
LabelButton* GetLabelButton();
|
||||
|
||||
signals:
|
||||
void OpenProject(const QString& projectName);
|
||||
@@ -75,9 +81,12 @@ namespace O3DE::ProjectManager
|
||||
void BaseSetup();
|
||||
void ProcessingSetup();
|
||||
void ReadySetup();
|
||||
void BuildThisProject();
|
||||
|
||||
ProjectInfo m_projectInfo;
|
||||
LabelButton* m_projectImageLabel;
|
||||
QFrame* m_projectFooter;
|
||||
|
||||
QMetaObject::Connection m_actionButtonConnection;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace O3DE::ProjectManager
|
||||
inline constexpr static int ProjectPreviewImageHeight = 280;
|
||||
|
||||
static const QString ProjectBuildPathPostfix = "build/windows_vs2019";
|
||||
static const QString ProjectBuildErrorLogPathPostfix = "CMakeFiles/CMakeProjectBuildError.log";
|
||||
static const QString ProjectBuildPathCmakeFiles = "CMakeFiles";
|
||||
static const QString ProjectBuildErrorLogName = "CMakeProjectBuildError.log";
|
||||
static const QString ProjectPreviewImagePath = "preview.png";
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <ProjectButtonWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <ProjectUtils.h>
|
||||
#include <ProjectBuilder.h>
|
||||
#include <ProjectBuilderController.h>
|
||||
#include <ScreensCtrl.h>
|
||||
|
||||
#include <AzQtComponents/Components/FlowLayout.h>
|
||||
@@ -43,8 +43,6 @@
|
||||
#include <QDir>
|
||||
#include <QGuiApplication>
|
||||
|
||||
//#define DISPLAY_PROJECT_DEV_DATA true
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectsScreen::ProjectsScreen(QWidget* parent)
|
||||
@@ -86,7 +84,7 @@ namespace O3DE::ProjectManager
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
frame->setLayout(layout);
|
||||
|
||||
QLabel* titleLabel = new QLabel(tr("Ready. Set. Create."), this);
|
||||
QLabel* titleLabel = new QLabel(tr("Ready? Set. Create!"), this);
|
||||
titleLabel->setObjectName("titleLabel");
|
||||
layout->addWidget(titleLabel);
|
||||
|
||||
@@ -166,43 +164,38 @@ namespace O3DE::ProjectManager
|
||||
projectsScrollArea->setWidget(scrollWidget);
|
||||
projectsScrollArea->setWidgetResizable(true);
|
||||
|
||||
#ifndef DISPLAY_PROJECT_DEV_DATA
|
||||
// Iterate once to insert building project first
|
||||
if (!buildProjectPath.isEmpty())
|
||||
QVector<ProjectInfo> nonProcessingProjects;
|
||||
buildProjectPath = QDir::fromNativeSeparators(buildProjectPath);
|
||||
for (auto& project : projectsResult.GetValue())
|
||||
{
|
||||
buildProjectPath = QDir::fromNativeSeparators(buildProjectPath);
|
||||
for (auto project : projectsResult.GetValue())
|
||||
if (projectButton && !*projectButton)
|
||||
{
|
||||
if (QDir::fromNativeSeparators(project.m_path) == buildProjectPath)
|
||||
{
|
||||
ProjectButton* buildingProjectButton = CreateProjectButton(project, flowLayout, true);
|
||||
|
||||
if (projectButton)
|
||||
{
|
||||
*projectButton = buildingProjectButton;
|
||||
}
|
||||
|
||||
break;
|
||||
*projectButton = CreateProjectButton(project, flowLayout, true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
nonProcessingProjects.append(project);
|
||||
}
|
||||
|
||||
for (auto project : projectsResult.GetValue())
|
||||
#else
|
||||
ProjectInfo project = projectsResult.GetValue().at(0);
|
||||
for (int i = 0; i < 15; i++)
|
||||
#endif
|
||||
for (auto& project : nonProcessingProjects)
|
||||
{
|
||||
// Add all other projects skipping building project
|
||||
// Safe if no building project because it is just an empty string
|
||||
if (project.m_path != buildProjectPath)
|
||||
{
|
||||
ProjectButton* projectButtonWidget = CreateProjectButton(project, flowLayout);
|
||||
ProjectButton* projectButtonWidget = CreateProjectButton(project, flowLayout);
|
||||
|
||||
if (RequiresBuildProjectIterator(project.m_path) != m_requiresBuild.end())
|
||||
{
|
||||
projectButtonWidget->ShowBuildButton(true);
|
||||
}
|
||||
if (BuildQueueContainsProject(project.m_path))
|
||||
{
|
||||
projectButtonWidget->SetProjectButtonAction(tr("Cancel Queued Build"),
|
||||
[this, project]
|
||||
{
|
||||
UnqueueBuildProject(project);
|
||||
SuggestBuildProjectMsg(project, false);
|
||||
});
|
||||
}
|
||||
else if (RequiresBuildProjectIterator(project.m_path) != m_requiresBuild.end())
|
||||
{
|
||||
projectButtonWidget->SetProjectBuildButtonAction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,9 +237,9 @@ namespace O3DE::ProjectManager
|
||||
// Make sure to update builder with latest Project Button
|
||||
if (m_currentBuilder)
|
||||
{
|
||||
ProjectButton* projectButtonPtr;
|
||||
ProjectButton* projectButtonPtr = nullptr;
|
||||
|
||||
m_projectsContent = CreateProjectsContent(m_currentBuilder->GetProjectPath(), &projectButtonPtr);
|
||||
m_projectsContent = CreateProjectsContent(m_currentBuilder->GetProjectInfo().m_path, &projectButtonPtr);
|
||||
m_currentBuilder->SetProjectButton(projectButtonPtr);
|
||||
}
|
||||
else
|
||||
@@ -414,17 +407,15 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectsScreen::SuggestBuildProject(const ProjectInfo& projectInfo)
|
||||
void ProjectsScreen::SuggestBuildProjectMsg(const ProjectInfo& projectInfo, bool showMessage)
|
||||
{
|
||||
if (projectInfo.m_needsBuild)
|
||||
if (RequiresBuildProjectIterator(projectInfo.m_path) == m_requiresBuild.end())
|
||||
{
|
||||
if (RequiresBuildProjectIterator(projectInfo.m_path) == m_requiresBuild.end())
|
||||
{
|
||||
m_requiresBuild.append(projectInfo);
|
||||
}
|
||||
ResetProjectsContent();
|
||||
m_requiresBuild.append(projectInfo);
|
||||
}
|
||||
else
|
||||
ResetProjectsContent();
|
||||
|
||||
if (showMessage)
|
||||
{
|
||||
QMessageBox::information(this,
|
||||
tr("Project Should be rebuilt."),
|
||||
@@ -432,6 +423,11 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectsScreen::SuggestBuildProject(const ProjectInfo& projectInfo)
|
||||
{
|
||||
SuggestBuildProjectMsg(projectInfo, true);
|
||||
}
|
||||
|
||||
void ProjectsScreen::QueueBuildProject(const ProjectInfo& projectInfo)
|
||||
{
|
||||
auto requiredIter = RequiresBuildProjectIterator(projectInfo.m_path);
|
||||
@@ -445,14 +441,22 @@ namespace O3DE::ProjectManager
|
||||
if (m_buildQueue.empty() && !m_currentBuilder)
|
||||
{
|
||||
StartProjectBuild(projectInfo);
|
||||
// Projects Content is already reset in fuction
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buildQueue.append(projectInfo);
|
||||
ResetProjectsContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectsScreen::UnqueueBuildProject(const ProjectInfo& projectInfo)
|
||||
{
|
||||
m_buildQueue.removeAll(projectInfo);
|
||||
ResetProjectsContent();
|
||||
}
|
||||
|
||||
void ProjectsScreen::NotifyCurrentScreen()
|
||||
{
|
||||
if (ShouldDisplayFirstTimeContent())
|
||||
@@ -488,7 +492,7 @@ namespace O3DE::ProjectManager
|
||||
return PythonBindingsInterface::Get()->RemoveInvalidProjects();
|
||||
}
|
||||
|
||||
void ProjectsScreen::StartProjectBuild(const ProjectInfo& projectInfo)
|
||||
bool ProjectsScreen::StartProjectBuild(const ProjectInfo& projectInfo)
|
||||
{
|
||||
if (ProjectUtils::IsVS2019Installed())
|
||||
{
|
||||
@@ -508,25 +512,42 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectBuildDone();
|
||||
SuggestBuildProjectMsg(projectInfo, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ProjectsScreen::ProjectBuildDone()
|
||||
void ProjectsScreen::ProjectBuildDone(bool success)
|
||||
{
|
||||
ProjectInfo currentBuilderProject;
|
||||
if (!success)
|
||||
{
|
||||
currentBuilderProject = m_currentBuilder->GetProjectInfo();
|
||||
}
|
||||
|
||||
delete m_currentBuilder;
|
||||
m_currentBuilder = nullptr;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
SuggestBuildProjectMsg(currentBuilderProject, false);
|
||||
}
|
||||
|
||||
if (!m_buildQueue.empty())
|
||||
{
|
||||
StartProjectBuild(m_buildQueue.front());
|
||||
while (!StartProjectBuild(m_buildQueue.front()) && m_buildQueue.size() > 1)
|
||||
{
|
||||
m_buildQueue.pop_front();
|
||||
}
|
||||
m_buildQueue.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetProjectsContent();
|
||||
}
|
||||
|
||||
ResetProjectsContent();
|
||||
}
|
||||
|
||||
QList<ProjectInfo>::iterator ProjectsScreen::RequiresBuildProjectIterator(const QString& projectPath)
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
protected:
|
||||
void NotifyCurrentScreen() override;
|
||||
void ProjectBuildDone();
|
||||
void SuggestBuildProjectMsg(const ProjectInfo& projectInfo, bool showMessage);
|
||||
|
||||
protected slots:
|
||||
void HandleNewProjectButton();
|
||||
@@ -50,6 +50,9 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void SuggestBuildProject(const ProjectInfo& projectInfo);
|
||||
void QueueBuildProject(const ProjectInfo& projectInfo);
|
||||
void UnqueueBuildProject(const ProjectInfo& projectInfo);
|
||||
|
||||
void ProjectBuildDone(bool success = true);
|
||||
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
@@ -61,7 +64,7 @@ namespace O3DE::ProjectManager
|
||||
bool ShouldDisplayFirstTimeContent();
|
||||
bool RemoveInvalidProjects();
|
||||
|
||||
void StartProjectBuild(const ProjectInfo& projectInfo);
|
||||
bool StartProjectBuild(const ProjectInfo& projectInfo);
|
||||
QList<ProjectInfo>::iterator RequiresBuildProjectIterator(const QString& projectPath);
|
||||
bool BuildQueueContainsProject(const QString& projectPath);
|
||||
bool WarnIfInBuildQueue(const QString& projectPath);
|
||||
|
||||
@@ -39,8 +39,10 @@ set(FILES
|
||||
Source/ProjectInfo.cpp
|
||||
Source/ProjectUtils.h
|
||||
Source/ProjectUtils.cpp
|
||||
Source/ProjectBuilder.h
|
||||
Source/ProjectBuilder.cpp
|
||||
Source/ProjectBuilderWorker.h
|
||||
Source/ProjectBuilderWorker.cpp
|
||||
Source/ProjectBuilderController.h
|
||||
Source/ProjectBuilderController.cpp
|
||||
Source/UpdateProjectSettingsScreen.h
|
||||
Source/UpdateProjectSettingsScreen.cpp
|
||||
Source/NewProjectSettingsScreen.h
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace AZ
|
||||
// AssImp only has one bitangentStream per mesh.
|
||||
bitangentStream->SetBitangentSetIndex(0);
|
||||
|
||||
bitangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
|
||||
bitangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromSourceScene);
|
||||
bitangentStream->ReserveContainerSpace(vertexCount);
|
||||
for (int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace AZ
|
||||
// AssImp only has one tangentStream per mesh.
|
||||
tangentStream->SetTangentSetIndex(0);
|
||||
|
||||
tangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
|
||||
tangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromSourceScene);
|
||||
tangentStream->ReserveContainerSpace(vertexCount);
|
||||
for (int sdkMeshIndex = 0; sdkMeshIndex < currentNode->mNumMeshes; ++sdkMeshIndex)
|
||||
{
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace AZ
|
||||
{
|
||||
enum class TangentSpace
|
||||
{
|
||||
FromFbx = 0,
|
||||
MikkT = 1,
|
||||
EMotionFX = 2
|
||||
FromSourceScene = 0,
|
||||
MikkT = 1,
|
||||
EMotionFX = 2
|
||||
};
|
||||
|
||||
enum class BitangentMethod
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace AZ
|
||||
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<MeshVertexBitangentData>()->Version(1);
|
||||
serializeContext->Class<MeshVertexBitangentData>()->Version(2);
|
||||
}
|
||||
|
||||
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
|
||||
@@ -34,7 +34,7 @@ namespace AZ
|
||||
->Method("GetBitangentSetIndex", &MeshVertexBitangentData::GetBitangentSetIndex)
|
||||
->Method("GetTangentSpace", &MeshVertexBitangentData::GetTangentSpace)
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::EMotionFX>("EMotionFX")
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::FromFbx>("FromFbx")
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::FromSourceScene>("FromSourceScene")
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::MikkT>("MikkT");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace AZ
|
||||
SCENE_DATA_API void GetDebugOutput(AZ::SceneAPI::Utilities::DebugOutput& output) const override;
|
||||
protected:
|
||||
AZStd::vector<AZ::Vector3> m_bitangents;
|
||||
AZ::SceneAPI::DataTypes::TangentSpace m_tangentSpace = AZ::SceneAPI::DataTypes::TangentSpace::FromFbx;
|
||||
AZ::SceneAPI::DataTypes::TangentSpace m_tangentSpace = AZ::SceneAPI::DataTypes::TangentSpace::FromSourceScene;
|
||||
size_t m_setIndex = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace AZ
|
||||
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<MeshVertexTangentData>()->Version(1);
|
||||
serializeContext->Class<MeshVertexTangentData>()->Version(2);
|
||||
}
|
||||
|
||||
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
|
||||
@@ -34,7 +34,7 @@ namespace AZ
|
||||
->Method("GetTangentSetIndex", &MeshVertexTangentData::GetTangentSetIndex)
|
||||
->Method("GetTangentSpace", &MeshVertexTangentData::GetTangentSpace)
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::EMotionFX>("EMotionFX")
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::FromFbx>("FromFbx")
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::FromSourceScene>("FromSourceScene")
|
||||
->Enum<(int)SceneAPI::DataTypes::TangentSpace::MikkT>("MikkT");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace AZ
|
||||
SCENE_DATA_API void GetDebugOutput(AZ::SceneAPI::Utilities::DebugOutput& output) const override;
|
||||
protected:
|
||||
AZStd::vector<AZ::Vector4> m_tangents;
|
||||
AZ::SceneAPI::DataTypes::TangentSpace m_tangentSpace = AZ::SceneAPI::DataTypes::TangentSpace::FromFbx;
|
||||
AZ::SceneAPI::DataTypes::TangentSpace m_tangentSpace = AZ::SceneAPI::DataTypes::TangentSpace::FromSourceScene;
|
||||
size_t m_setIndex = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
|
||||
serializeContext->Class<TangentsRule, DataTypes::IRule>()->Version(1)
|
||||
serializeContext->Class<TangentsRule, DataTypes::IRule>()->Version(2)
|
||||
->Field("tangentSpace", &TangentsRule::m_tangentSpace)
|
||||
->Field("bitangentMethod", &TangentsRule::m_bitangentMethod)
|
||||
->Field("normalize", &TangentsRule::m_normalize)
|
||||
@@ -156,7 +156,7 @@ namespace AZ
|
||||
->Attribute("AutoExpand", true)
|
||||
->Attribute(AZ::Edit::Attributes::NameLabelOverride, "")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &AZ::SceneAPI::SceneData::TangentsRule::m_tangentSpace, "Tangent space", "Specify the tangent space used for normal map baking. Choose 'From Fbx' to extract the tangents and bitangents directly from the Fbx file. When there is no tangents rule or the Fbx has no tangents stored inside it, the 'MikkT' option will be used with orthogonal tangents of unit length, so with the normalize option enabled, using the first UV set.")
|
||||
->EnumAttribute(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx, "From Fbx")
|
||||
->EnumAttribute(AZ::SceneAPI::DataTypes::TangentSpace::FromSourceScene, "From Source Scene")
|
||||
->EnumAttribute(AZ::SceneAPI::DataTypes::TangentSpace::MikkT, "MikkT")
|
||||
->EnumAttribute(AZ::SceneAPI::DataTypes::TangentSpace::EMotionFX, "EMotion FX")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace AZ
|
||||
auto* bitangentData = AZStd::any_cast<AZ::SceneData::GraphData::MeshVertexBitangentData>(&data);
|
||||
bitangentData->AppendBitangent(AZ::Vector3{0.12f, 0.34f, 0.56f});
|
||||
bitangentData->AppendBitangent(AZ::Vector3{0.77f, 0.88f, 0.99f});
|
||||
bitangentData->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
|
||||
bitangentData->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromSourceScene);
|
||||
bitangentData->SetBitangentSetIndex(1);
|
||||
return true;
|
||||
}
|
||||
@@ -317,7 +317,7 @@ namespace AZ
|
||||
ExpectExecute("TestExpectFloatEquals(bitangentData.y, 0.88)");
|
||||
ExpectExecute("TestExpectFloatEquals(bitangentData.z, 0.99)");
|
||||
ExpectExecute("TestExpectIntegerEquals(meshVertexBitangentData:GetBitangentSetIndex(), 1)");
|
||||
ExpectExecute("TestExpectTrue(meshVertexBitangentData:GetTangentSpace(), MeshVertexBitangentData.FromFbx)");
|
||||
ExpectExecute("TestExpectTrue(meshVertexBitangentData:GetTangentSpace(), MeshVertexBitangentData.FromSourceScene)");
|
||||
}
|
||||
|
||||
TEST_F(GrapDatahBehaviorScriptTest, SceneGraph_MeshVertexTangentData_AccessWorks)
|
||||
|
||||
Reference in New Issue
Block a user