Merge pull request #7120 from aws-lumberyard-dev/cgalvan/gitflow_220124_o3de_main
Merged `stabilization/2111RTE` to `main`
This commit is contained in:
@@ -3,19 +3,19 @@
|
||||
"AssetProcessor": {
|
||||
"Settings": {
|
||||
"Exclude PythonTest Benchmark Settings Assets": {
|
||||
"pattern": ".*\\\\/PythonTests\\\\/.*benchmarksettings"
|
||||
"pattern": "(^|.+/)PythonTests/.*benchmarksettings"
|
||||
},
|
||||
"Exclude fbx_tests": {
|
||||
"pattern": ".*\\\\/fbx_tests\\\\/assets\\\\/.*"
|
||||
"pattern": "(^|.+/)fbx_tests/assets(/.+)$"
|
||||
},
|
||||
"Exclude wwise_bank_dependency_tests": {
|
||||
"pattern": ".*\\\\/wwise_bank_dependency_tests\\\\/assets\\\\/.*"
|
||||
"pattern": "(^|.+/)wwise_bank_dependency_tests/assets(/.+)$"
|
||||
},
|
||||
"Exclude AssetProcessorTestAssets": {
|
||||
"pattern": ".*\\\\/asset_processor_tests\\\\/assets\\\\/.*"
|
||||
"pattern": "(^|.+/)asset_processor_tests/assets(/.+)$"
|
||||
},
|
||||
"Exclude Restricted AssetProcessorTestAssets": {
|
||||
"pattern": ".*\\\\/asset_processor_tests\\\\/restricted\\\\/.*"
|
||||
"pattern": "(^|.+/)asset_processor_tests/restricted(/.+)$"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,25 +229,35 @@ void CViewportTitleDlg::SetupHelpersButton()
|
||||
|
||||
void CViewportTitleDlg::SetupOverflowMenu()
|
||||
{
|
||||
// Setup the overflow menu
|
||||
QMenu* overFlowMenu = new QMenu(this);
|
||||
// setup the overflow menu
|
||||
auto overflowMenu = new QMenu(this);
|
||||
|
||||
m_audioMuteAction = new QAction("Mute Audio", overFlowMenu);
|
||||
m_audioMuteAction = new QAction("Mute Audio", overflowMenu);
|
||||
connect(m_audioMuteAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedMuteAudio);
|
||||
overFlowMenu->addAction(m_audioMuteAction);
|
||||
overflowMenu->addAction(m_audioMuteAction);
|
||||
|
||||
m_enableVRAction = new QAction("Enable VR Preview", overFlowMenu);
|
||||
m_enableVRAction = new QAction("Enable VR Preview", overflowMenu);
|
||||
connect(m_enableVRAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedEnableVR);
|
||||
overFlowMenu->addAction(m_enableVRAction);
|
||||
overflowMenu->addAction(m_enableVRAction);
|
||||
|
||||
overFlowMenu->addSeparator();
|
||||
overflowMenu->addSeparator();
|
||||
|
||||
m_enableGridSnappingAction = new QAction("Enable Grid Snapping", overFlowMenu);
|
||||
m_enableGridSnappingAction = new QAction("Enable Grid Snapping", overflowMenu);
|
||||
connect(m_enableGridSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnGridSnappingToggled);
|
||||
m_enableGridSnappingAction->setCheckable(true);
|
||||
overFlowMenu->addAction(m_enableGridSnappingAction);
|
||||
overflowMenu->addAction(m_enableGridSnappingAction);
|
||||
|
||||
m_gridSizeActionWidget = new QWidgetAction(overFlowMenu);
|
||||
m_enableGridVisualizationAction = new QAction("Show Grid", overflowMenu);
|
||||
connect(
|
||||
m_enableGridVisualizationAction, &QAction::triggered,
|
||||
[]
|
||||
{
|
||||
SandboxEditor::SetShowingGrid(!SandboxEditor::ShowingGrid());
|
||||
});
|
||||
m_enableGridVisualizationAction->setCheckable(true);
|
||||
overflowMenu->addAction(m_enableGridVisualizationAction);
|
||||
|
||||
m_gridSizeActionWidget = new QWidgetAction(overflowMenu);
|
||||
m_gridSpinBox = new AzQtComponents::DoubleSpinBox();
|
||||
m_gridSpinBox->setValue(SandboxEditor::GridSnappingSize());
|
||||
m_gridSpinBox->setMinimum(1e-2f);
|
||||
@@ -257,31 +267,31 @@ void CViewportTitleDlg::SetupOverflowMenu()
|
||||
m_gridSpinBox, QOverload<double>::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &CViewportTitleDlg::OnGridSpinBoxChanged);
|
||||
|
||||
m_gridSizeActionWidget->setDefaultWidget(m_gridSpinBox);
|
||||
overFlowMenu->addAction(m_gridSizeActionWidget);
|
||||
overflowMenu->addAction(m_gridSizeActionWidget);
|
||||
|
||||
overFlowMenu->addSeparator();
|
||||
overflowMenu->addSeparator();
|
||||
|
||||
m_enableAngleSnappingAction = new QAction("Enable Angle Snapping", overFlowMenu);
|
||||
m_enableAngleSnappingAction = new QAction("Enable Angle Snapping", overflowMenu);
|
||||
connect(m_enableAngleSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnAngleSnappingToggled);
|
||||
m_enableAngleSnappingAction->setCheckable(true);
|
||||
overFlowMenu->addAction(m_enableAngleSnappingAction);
|
||||
overflowMenu->addAction(m_enableAngleSnappingAction);
|
||||
|
||||
m_angleSizeActionWidget = new QWidgetAction(overFlowMenu);
|
||||
m_angleSizeActionWidget = new QWidgetAction(overflowMenu);
|
||||
m_angleSpinBox = new AzQtComponents::DoubleSpinBox();
|
||||
m_angleSpinBox->setValue(SandboxEditor::AngleSnappingSize());
|
||||
m_angleSpinBox->setMinimum(1e-2f);
|
||||
m_angleSpinBox->setToolTip(tr("Angle Snapping"));
|
||||
m_angleSpinBox->setToolTip(tr("Angle size"));
|
||||
|
||||
QObject::connect(
|
||||
m_angleSpinBox, QOverload<double>::of(&AzQtComponents::DoubleSpinBox::valueChanged), this,
|
||||
&CViewportTitleDlg::OnAngleSpinBoxChanged);
|
||||
|
||||
m_angleSizeActionWidget->setDefaultWidget(m_angleSpinBox);
|
||||
overFlowMenu->addAction(m_angleSizeActionWidget);
|
||||
overflowMenu->addAction(m_angleSizeActionWidget);
|
||||
|
||||
m_ui->m_overflowBtn->setMenu(overFlowMenu);
|
||||
m_ui->m_overflowBtn->setMenu(overflowMenu);
|
||||
m_ui->m_overflowBtn->setPopupMode(QToolButton::InstantPopup);
|
||||
connect(overFlowMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::UpdateOverFlowMenuState);
|
||||
connect(overflowMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::UpdateOverFlowMenuState);
|
||||
|
||||
UpdateMuteActionText();
|
||||
}
|
||||
@@ -1004,31 +1014,36 @@ void CViewportTitleDlg::OnAngleSnappingToggled()
|
||||
MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->trigger();
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::OnGridSpinBoxChanged(double value)
|
||||
void CViewportTitleDlg::OnGridSpinBoxChanged(const double value)
|
||||
{
|
||||
SandboxEditor::SetGridSnappingSize(static_cast<float>(value));
|
||||
SandboxEditor::SetGridSnappingSize(aznumeric_cast<float>(value));
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::OnAngleSpinBoxChanged(double value)
|
||||
void CViewportTitleDlg::OnAngleSpinBoxChanged(const double value)
|
||||
{
|
||||
SandboxEditor::SetAngleSnappingSize(static_cast<float>(value));
|
||||
SandboxEditor::SetAngleSnappingSize(aznumeric_cast<float>(value));
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::UpdateOverFlowMenuState()
|
||||
{
|
||||
bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->isChecked();
|
||||
const bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->isChecked();
|
||||
{
|
||||
QSignalBlocker signalBlocker(m_enableGridSnappingAction);
|
||||
m_enableGridSnappingAction->setChecked(gridSnappingActive);
|
||||
}
|
||||
m_gridSizeActionWidget->setEnabled(gridSnappingActive);
|
||||
|
||||
bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked();
|
||||
const bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked();
|
||||
{
|
||||
QSignalBlocker signalBlocker(m_enableAngleSnappingAction);
|
||||
m_enableAngleSnappingAction->setChecked(angleSnappingActive);
|
||||
}
|
||||
m_angleSizeActionWidget->setEnabled(angleSnappingActive);
|
||||
|
||||
{
|
||||
QSignalBlocker signalBlocker(m_enableGridVisualizationAction);
|
||||
m_enableGridVisualizationAction->setChecked(SandboxEditor::ShowingGrid());
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
|
||||
@@ -171,6 +171,7 @@ protected:
|
||||
QAction* m_enableVRAction = nullptr;
|
||||
QAction* m_enableGridSnappingAction = nullptr;
|
||||
QAction* m_enableAngleSnappingAction = nullptr;
|
||||
QAction* m_enableGridVisualizationAction = nullptr;
|
||||
QComboBox* m_cameraSpeed = nullptr;
|
||||
AzQtComponents::DoubleSpinBox* m_gridSpinBox = nullptr;
|
||||
AzQtComponents::DoubleSpinBox* m_angleSpinBox = nullptr;
|
||||
@@ -184,7 +185,7 @@ protected:
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! A component to reflect scriptable commands for the Editor
|
||||
//! A component to reflect scriptable commands for the Editor.
|
||||
class ViewportTitleDlgPythonFuncsHandler
|
||||
: public AZ::Component
|
||||
{
|
||||
|
||||
@@ -3408,7 +3408,14 @@ LUA_API const Node* lua_getDummyNode()
|
||||
const BehaviorParameter* arg = method->GetArgument(iArg);
|
||||
BehaviorClass* argClass = nullptr;
|
||||
LuaLoadFromStack fromStack = FromLuaStack(context, arg, argClass);
|
||||
AZ_Assert(fromStack, "Argument %s for Method %s doesn't have support to be converted to Lua!", arg->m_name, method->m_name.c_str());
|
||||
AZ_Assert(fromStack,
|
||||
"The argument type: %s for method: %s is not serialized and/or reflected for scripting.\n"
|
||||
"Make sure %s is added to the SerializeContext and reflected to the BehaviorContext\n"
|
||||
"For example, verify these two exist and are being called in a Reflect function:\n"
|
||||
"serializeContext->Class<%s>();\n"
|
||||
"behaviorContext->Class<%s>();\n"
|
||||
"%s will not be available for scripting unless these requirements are met."
|
||||
, arg->m_name, method->m_name.c_str(), arg->m_name, arg->m_name, arg->m_name, method->m_name.c_str());
|
||||
|
||||
m_fromLua.push_back(AZStd::make_pair(fromStack, argClass));
|
||||
}
|
||||
@@ -5066,13 +5073,26 @@ LUA_API const Node* lua_getDummyNode()
|
||||
// Check all constructors if they have use ScriptDataContext and if so choose this one
|
||||
if (!customConstructorMethod)
|
||||
{
|
||||
int overrideIndex = -1;
|
||||
AZ::AttributeReader(nullptr, FindAttribute
|
||||
( Script::Attributes::DefaultConstructorOverrideIndex, behaviorClass->m_attributes)).Read<int>(overrideIndex);
|
||||
|
||||
int methodIndex = 0;
|
||||
for (BehaviorMethod* method : behaviorClass->m_constructors)
|
||||
{
|
||||
if (methodIndex == overrideIndex)
|
||||
{
|
||||
customConstructorMethod = method;
|
||||
break;
|
||||
}
|
||||
|
||||
if (method->GetNumArguments() && method->GetArgument(method->GetNumArguments() - 1)->m_typeId == AZ::AzTypeInfo<ScriptDataContext>::Uuid())
|
||||
{
|
||||
customConstructorMethod = method;
|
||||
break;
|
||||
}
|
||||
|
||||
++methodIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace AZ
|
||||
static constexpr AZ::Crc32 ClassNameOverride = AZ_CRC_CE("ScriptClassNameOverride"); ///< Provide a custom name for script reflection, that doesn't match the behavior Context name
|
||||
static constexpr AZ::Crc32 MethodOverride = AZ_CRC_CE("ScriptFunctionOverride"); ///< Use a custom function in the attribute instead of the function
|
||||
static constexpr AZ::Crc32 ConstructorOverride = AZ_CRC_CE("ConstructorOverride"); ///< You can provide a custom constructor to be called when created from Lua script
|
||||
static constexpr AZ::Crc32 DefaultConstructorOverrideIndex = AZ_CRC_CE("DefaultConstructorOverrideIndex"); ///< Use a different class constructor as the default constructor in Lua
|
||||
static constexpr AZ::Crc32 EventHandlerCreationFunction = AZ_CRC_CE("EventHandlerCreationFunction"); ///< helps create a handler for any script target so that script functions can be used for AZ::Event signals
|
||||
static constexpr AZ::Crc32 GenericConstructorOverride = AZ_CRC_CE("GenericConstructorOverride"); ///< You can provide a custom constructor to be called when creating a script
|
||||
static constexpr AZ::Crc32 ReaderWriterOverride = AZ_CRC_CE("ReaderWriterOverride"); ///< paired with \ref ScriptContext::CustomReaderWriter allows you to customize read/write to Lua VM
|
||||
|
||||
@@ -133,6 +133,8 @@ namespace AZ
|
||||
const static AZ::Crc32 AllowClearAsset = AZ_CRC("AllowClearAsset", 0x24827182);
|
||||
// Show the name of the asset that was produced from the source asset
|
||||
const static AZ::Crc32 ShowProductAssetFileName = AZ_CRC("ShowProductAssetFileName");
|
||||
//! Regular expression pattern filter for source files
|
||||
const static AZ::Crc32 SourceAssetFilterPattern = AZ_CRC_CE("SourceAssetFilterPattern");
|
||||
|
||||
//! Component icon attributes
|
||||
const static AZ::Crc32 Icon = AZ_CRC("Icon", 0x659429db);
|
||||
|
||||
@@ -204,6 +204,22 @@ namespace AZ
|
||||
// BaseJsonSerializer
|
||||
//
|
||||
|
||||
JsonSerializationResult::Result BaseJsonSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context)
|
||||
{
|
||||
JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::ReadField);
|
||||
result.Combine(ContinueLoading(outputValue, outputValueTypeId, inputValue, context, ContinuationFlags::IgnoreTypeSerializer));
|
||||
return context.Report(result, "Ignoring custom serialization during load");
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result BaseJsonSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context)
|
||||
{
|
||||
JsonSerializationResult::ResultCode result(JsonSerializationResult::Tasks::WriteValue);
|
||||
result.Combine(ContinueStoring(outputValue, inputValue, defaultValue, valueTypeId, context, ContinuationFlags::IgnoreTypeSerializer));
|
||||
return context.Report(result, "Ignoring custom serialization during store");
|
||||
}
|
||||
|
||||
BaseJsonSerializer::OperationFlags BaseJsonSerializer::GetOperationsFlags() const
|
||||
{
|
||||
return OperationFlags::None;
|
||||
|
||||
@@ -180,13 +180,16 @@ namespace AZ
|
||||
|
||||
//! Transforms the data from the rapidjson Value to outputValue, if the conversion is possible and supported.
|
||||
//! The serializer is responsible for casting to the proper type and safely writing to the outputValue memory.
|
||||
//! \note The default implementation is to load the object ignoring a custom serializers for the type, which allows for custom serializers
|
||||
//! to modify the object after all default loading has occurred.
|
||||
virtual JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) = 0;
|
||||
JsonDeserializerContext& context);
|
||||
|
||||
//! Write the input value to a rapidjson value if the default value is not null and doesn't match the input value, otherwise
|
||||
//! an error is returned and sets the rapidjson value to a null value.
|
||||
//! \note The default implementation is to store the object ignoring custom serializers.
|
||||
virtual JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) = 0;
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context);
|
||||
|
||||
//! Returns the operation flags which tells the Json Serialization how this custom json serializer can be used.
|
||||
virtual OperationFlags GetOperationsFlags() const;
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace AZ
|
||||
{
|
||||
// Not using InsertTypeId here to avoid needing to create the temporary value and swap it in that call.
|
||||
node.AddMember(rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier),
|
||||
StoreTypeName(classData, context), context.GetJsonAllocator());
|
||||
StoreTypeName(classData, classData.m_typeId, context), context.GetJsonAllocator());
|
||||
result = ResultCode(Tasks::WriteValue, Outcomes::Success);
|
||||
}
|
||||
return result.Combine(StoreClass(node, object, defaultObject, classData, context));
|
||||
@@ -531,7 +531,7 @@ namespace AZ
|
||||
return ResolvePointerResult::ContinueProcessing;
|
||||
}
|
||||
|
||||
rapidjson::Value JsonSerializer::StoreTypeName(const SerializeContext::ClassData& classData, JsonSerializerContext& context)
|
||||
rapidjson::Value JsonSerializer::StoreTypeName(const SerializeContext::ClassData& classData, const Uuid& typeId, JsonSerializerContext& context)
|
||||
{
|
||||
rapidjson::Value result;
|
||||
AZStd::vector<Uuid> ids = context.GetSerializeContext()->FindClassId(Crc32(classData.m_name));
|
||||
@@ -544,7 +544,7 @@ namespace AZ
|
||||
// Only write the Uuid for the class if there are multiple classes sharing the same name.
|
||||
// In this case it wouldn't be enough to determine which class needs to be used. The
|
||||
// class name is still added as a comment for be friendlier for users to read.
|
||||
AZStd::string fullName = classData.m_typeId.ToString<AZStd::string>();
|
||||
AZStd::string fullName = typeId.ToString<AZStd::string>();
|
||||
fullName += ' ';
|
||||
fullName += classData.m_name;
|
||||
result.SetString(fullName.c_str(), aznumeric_caster(fullName.size()), context.GetJsonAllocator());
|
||||
@@ -560,7 +560,7 @@ namespace AZ
|
||||
const SerializeContext::ClassData* data = context.GetSerializeContext()->FindClassData(typeId);
|
||||
if (data)
|
||||
{
|
||||
output = JsonSerializer::StoreTypeName(*data, context);
|
||||
output = JsonSerializer::StoreTypeName(*data, typeId, context);
|
||||
return context.Report(Tasks::WriteValue, Outcomes::Success, "Type id successfully stored to json value.");
|
||||
}
|
||||
else
|
||||
@@ -580,7 +580,7 @@ namespace AZ
|
||||
{
|
||||
rapidjson::Value insertedObject(rapidjson::kObjectType);
|
||||
insertedObject.AddMember(
|
||||
rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier), StoreTypeName(classData, context),
|
||||
rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier), StoreTypeName(classData, classData.m_typeId, context),
|
||||
context.GetJsonAllocator());
|
||||
|
||||
for (auto& element : output.GetObject())
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace AZ
|
||||
const void*& object, const void*& defaultObject, AZStd::any& defaultObjectStorage,
|
||||
const SerializeContext::ClassData*& elementClassData, const AZ::IRttiHelper& rtti, JsonSerializerContext& context);
|
||||
|
||||
static rapidjson::Value StoreTypeName(const SerializeContext::ClassData& classData, JsonSerializerContext& context);
|
||||
static rapidjson::Value StoreTypeName(const SerializeContext::ClassData& classData, const Uuid& typeId, JsonSerializerContext& context);
|
||||
static JsonSerializationResult::ResultCode StoreTypeName(rapidjson::Value& output,
|
||||
const Uuid& typeId, JsonSerializerContext& context);
|
||||
|
||||
|
||||
@@ -165,13 +165,12 @@ namespace AZ::Utils
|
||||
}
|
||||
|
||||
Container fileContent;
|
||||
fileContent.resize(length);
|
||||
fileContent.resize_no_construct(length);
|
||||
AZ::IO::SizeType bytesRead = file.Read(length, fileContent.data());
|
||||
file.Close();
|
||||
|
||||
// Resize again just in case bytesRead is less than length for some reason
|
||||
fileContent.resize(bytesRead);
|
||||
|
||||
fileContent.resize_no_construct(bytesRead);
|
||||
return AZ::Success(AZStd::move(fileContent));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,72 @@
|
||||
#include <Tests/Serialization/Json/JsonSerializationTests.h>
|
||||
#include <Tests/Serialization/Json/TestCases_Classes.h>
|
||||
#include <Tests/Serialization/Json/TestCases_Pointers.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
template<typename T>
|
||||
struct SerializeGenericTypeInfo<JsonSerializationTests::TemplatedClass<T>>
|
||||
{
|
||||
using ThisType = JsonSerializationTests::TemplatedClass<T>;
|
||||
|
||||
class GenericTemplatedClassInfo : public GenericClassInfo
|
||||
{
|
||||
public:
|
||||
GenericTemplatedClassInfo()
|
||||
: m_classData{ SerializeContext::ClassData::Create<ThisType>(
|
||||
"TemplatedClass", "{CA4ADF74-66E7-4D16-B4AC-F71278C60EC7}", nullptr, nullptr) }
|
||||
{
|
||||
}
|
||||
|
||||
SerializeContext::ClassData* GetClassData() override
|
||||
{
|
||||
return &m_classData;
|
||||
}
|
||||
|
||||
size_t GetNumTemplatedArguments() override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const Uuid& GetSpecializedTypeId() const override
|
||||
{
|
||||
return m_classData.m_typeId;
|
||||
}
|
||||
|
||||
const Uuid& GetGenericTypeId() const override
|
||||
{
|
||||
return m_classData.m_typeId;
|
||||
}
|
||||
|
||||
const Uuid& GetTemplatedTypeId(size_t element) override
|
||||
{
|
||||
(void)element;
|
||||
return SerializeGenericTypeInfo<T>::GetClassTypeId();
|
||||
}
|
||||
|
||||
void Reflect(SerializeContext* serializeContext) override
|
||||
{
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->RegisterGenericClassInfo(
|
||||
GetSpecializedTypeId(), this, &AZ::AnyTypeInfoConcept<Data::Asset<Data::AssetData>>::CreateAny);
|
||||
serializeContext->RegisterGenericClassInfo(
|
||||
azrtti_typeid<ThisType>(), this,
|
||||
&AZ::AnyTypeInfoConcept<ThisType>::CreateAny);
|
||||
}
|
||||
}
|
||||
|
||||
SerializeContext::ClassData m_classData;
|
||||
};
|
||||
|
||||
using ClassInfoType = GenericTemplatedClassInfo;
|
||||
static ClassInfoType* GetGenericInfo()
|
||||
{
|
||||
return GetCurrentSerializeContextModule().CreateGenericClassInfo<ThisType>();
|
||||
}
|
||||
};
|
||||
} // namespace AZ
|
||||
|
||||
namespace JsonSerializationTests
|
||||
{
|
||||
@@ -286,4 +352,32 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(Processing::Halted, result.GetProcessing());
|
||||
EXPECT_EQ(Outcomes::Unknown, result.GetOutcome());
|
||||
}
|
||||
|
||||
TEST_F(JsonSerializationTests, StoreTypeId_TemplatedType_StoresUuidWithName)
|
||||
{
|
||||
using namespace AZ;
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
m_serializeContext->RegisterGenericType<TemplatedClass<A::Inherited>>();
|
||||
m_serializeContext->RegisterGenericType<TemplatedClass<BaseClass>>();
|
||||
|
||||
Uuid input = azrtti_typeid<TemplatedClass<A::Inherited>>();
|
||||
ResultCode result = JsonSerialization::StoreTypeId(
|
||||
*m_jsonDocument, m_jsonDocument->GetAllocator(), input, AZStd::string_view{}, *m_serializationSettings);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
|
||||
AZStd::string expected =
|
||||
AZStd::string::format(R"("%s TemplatedClass")", azrtti_typeid<TemplatedClass<A::Inherited>>().ToString<AZStd::string>().c_str());
|
||||
Expect_DocStrEq(expected.c_str(), false);
|
||||
|
||||
input = azrtti_typeid<TemplatedClass<BaseClass>>();
|
||||
result = JsonSerialization::StoreTypeId(
|
||||
*m_jsonDocument, m_jsonDocument->GetAllocator(), input, AZStd::string_view{}, *m_serializationSettings);
|
||||
|
||||
expected =
|
||||
AZStd::string::format(R"("%s TemplatedClass")", azrtti_typeid<TemplatedClass<BaseClass>>().ToString<AZStd::string>().c_str());
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq(expected.c_str(), false);
|
||||
}
|
||||
} // namespace JsonSerializationTests
|
||||
|
||||
+27
-2
@@ -9,9 +9,27 @@
|
||||
#include <AzToolsFramework/Application/EditorEntityManager.h>
|
||||
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
static bool AreEntitiesValidForDuplication(const EntityIdList& entityIds)
|
||||
{
|
||||
for (AZ::EntityId entityId : entityIds)
|
||||
{
|
||||
if (GetEntityById(entityId) == nullptr)
|
||||
{
|
||||
AZ_Error(
|
||||
"Entity", false,
|
||||
"Entity with id '%llu' is not found. This can happen when you try to duplicate the entity before it is created. Please "
|
||||
"ensure entities are created before trying to duplicate them.",
|
||||
static_cast<AZ::u64>(entityId));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorEntityManager::Start()
|
||||
{
|
||||
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
|
||||
@@ -62,7 +80,11 @@ namespace AzToolsFramework
|
||||
EntityIdList selectedEntities;
|
||||
ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities);
|
||||
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(selectedEntities);
|
||||
if (AreEntitiesValidForDuplication(selectedEntities))
|
||||
{
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(selectedEntities);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EditorEntityManager::DuplicateEntityById(AZ::EntityId entityId)
|
||||
@@ -72,7 +94,10 @@ namespace AzToolsFramework
|
||||
|
||||
void EditorEntityManager::DuplicateEntities(const EntityIdList& entities)
|
||||
{
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(entities);
|
||||
if (AreEntitiesValidForDuplication(entities))
|
||||
{
|
||||
m_prefabPublicInterface->DuplicateEntitiesInInstance(entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,5 +34,4 @@ namespace AzToolsFramework
|
||||
private:
|
||||
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+12
@@ -99,6 +99,18 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
if (selection.GetSelectedAssetIds().empty())
|
||||
{
|
||||
for (auto& filePath : selection.GetSelectedFilePaths())
|
||||
{
|
||||
if (!filePath.empty())
|
||||
{
|
||||
selectedAsset = true;
|
||||
m_ui->m_assetBrowserTreeViewWidget->SelectFileAtPath(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedAsset)
|
||||
{
|
||||
m_ui->m_assetBrowserTreeViewWidget->SelectFolder(selection.GetDefaultDirectory());
|
||||
|
||||
+60
-9
@@ -10,18 +10,24 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/EBusFindAssetTypeByName.h>
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
|
||||
#include <QRegExp>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
#endif
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
namespace
|
||||
{
|
||||
FilterConstType ProductsNoFoldersFilter()
|
||||
FilterConstType EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType entryType = AssetBrowserEntry::AssetEntryType::Product)
|
||||
{
|
||||
EntryTypeFilter* productFilter = new EntryTypeFilter();
|
||||
productFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Product);
|
||||
EntryTypeFilter* entryTypeFilter = new EntryTypeFilter();
|
||||
entryTypeFilter->SetEntryType(entryType);
|
||||
// in case entry is a source or folder, it may still contain relevant product
|
||||
productFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
|
||||
entryTypeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
|
||||
|
||||
EntryTypeFilter* foldersFilter = new EntryTypeFilter();
|
||||
foldersFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Folder);
|
||||
@@ -30,7 +36,7 @@ namespace AzToolsFramework
|
||||
noFoldersFilter->SetFilter(FilterConstType(foldersFilter));
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
|
||||
compFilter->AddFilter(FilterConstType(productFilter));
|
||||
compFilter->AddFilter(FilterConstType(entryTypeFilter));
|
||||
compFilter->AddFilter(FilterConstType(noFoldersFilter));
|
||||
|
||||
return FilterConstType(compFilter);
|
||||
@@ -79,15 +85,39 @@ namespace AzToolsFramework
|
||||
|
||||
void AssetSelectionModel::SetSelectedAssetIds(const AZStd::vector<AZ::Data::AssetId>& selectedAssetIds)
|
||||
{
|
||||
m_selectedFilePaths.clear();
|
||||
|
||||
m_selectedAssetIds = selectedAssetIds;
|
||||
}
|
||||
|
||||
void AssetSelectionModel::SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId)
|
||||
{
|
||||
m_selectedFilePaths.clear();
|
||||
|
||||
m_selectedAssetIds.clear();
|
||||
m_selectedAssetIds.push_back(selectedAssetId);
|
||||
}
|
||||
|
||||
const AZStd::vector<AZStd::string>& AssetSelectionModel::GetSelectedFilePaths() const
|
||||
{
|
||||
return m_selectedFilePaths;
|
||||
}
|
||||
|
||||
void AssetSelectionModel::SetSelectedFilePaths(const AZStd::vector<AZStd::string>& selectedFilePaths)
|
||||
{
|
||||
m_selectedAssetIds.clear();
|
||||
|
||||
m_selectedFilePaths = selectedFilePaths;
|
||||
}
|
||||
|
||||
void AssetSelectionModel::SetSelectedFilePath(const AZStd::string& selectedFilePath)
|
||||
{
|
||||
m_selectedAssetIds.clear();
|
||||
|
||||
m_selectedFilePaths.clear();
|
||||
m_selectedFilePaths.push_back(selectedFilePath);
|
||||
}
|
||||
|
||||
void AssetSelectionModel::SetDefaultDirectory(AZStd::string_view defaultDirectory)
|
||||
{
|
||||
m_defaultDirectory = defaultDirectory;
|
||||
@@ -136,7 +166,7 @@ namespace AzToolsFramework
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
|
||||
compFilter->AddFilter(assetTypeFilterPtr);
|
||||
compFilter->AddFilter(ProductsNoFoldersFilter());
|
||||
compFilter->AddFilter(EntryTypeNoFoldersFilter());
|
||||
|
||||
selection.SetSelectionFilter(FilterConstType(compFilter));
|
||||
selection.SetMultiselect(multiselect);
|
||||
@@ -169,7 +199,7 @@ namespace AzToolsFramework
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
|
||||
compFilter->AddFilter(anyAssetTypeFilterPtr);
|
||||
compFilter->AddFilter(ProductsNoFoldersFilter());
|
||||
compFilter->AddFilter(EntryTypeNoFoldersFilter());
|
||||
|
||||
selection.SetSelectionFilter(FilterConstType(compFilter));
|
||||
selection.SetMultiselect(multiselect);
|
||||
@@ -190,7 +220,28 @@ namespace AzToolsFramework
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
|
||||
compFilter->AddFilter(assetGroupFilterPtr);
|
||||
compFilter->AddFilter(ProductsNoFoldersFilter());
|
||||
compFilter->AddFilter(EntryTypeNoFoldersFilter());
|
||||
|
||||
selection.SetSelectionFilter(FilterConstType(compFilter));
|
||||
selection.SetMultiselect(multiselect);
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
AssetSelectionModel AssetSelectionModel::SourceAssetTypeSelection(const QString& pattern, bool multiselect)
|
||||
{
|
||||
AssetSelectionModel selection;
|
||||
|
||||
RegExpFilter* patternFilter = new RegExpFilter();
|
||||
patternFilter->SetFilterPattern(pattern);
|
||||
patternFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
|
||||
auto patternFilterPtr = FilterConstType(patternFilter);
|
||||
|
||||
selection.SetDisplayFilter(patternFilterPtr);
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::AND);
|
||||
compFilter->AddFilter(patternFilterPtr);
|
||||
compFilter->AddFilter(EntryTypeNoFoldersFilter(AssetBrowserEntry::AssetEntryType::Source));
|
||||
|
||||
selection.SetSelectionFilter(FilterConstType(compFilter));
|
||||
selection.SetMultiselect(multiselect);
|
||||
@@ -204,7 +255,7 @@ namespace AzToolsFramework
|
||||
|
||||
CompositeFilter* compFilter = new CompositeFilter(CompositeFilter::LogicOperatorType::OR);
|
||||
selection.SetDisplayFilter(FilterConstType(compFilter));
|
||||
selection.SetSelectionFilter(ProductsNoFoldersFilter());
|
||||
selection.SetSelectionFilter(EntryTypeNoFoldersFilter());
|
||||
selection.SetMultiselect(multiselect);
|
||||
|
||||
return selection;
|
||||
|
||||
+10
-1
@@ -44,6 +44,10 @@ namespace AzToolsFramework
|
||||
void SetSelectedAssetIds(const AZStd::vector<AZ::Data::AssetId>& selectedAssetIds);
|
||||
void SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId);
|
||||
|
||||
const AZStd::vector<AZStd::string>& GetSelectedFilePaths() const;
|
||||
void SetSelectedFilePaths(const AZStd::vector<AZStd::string>& selectedFilePaths);
|
||||
void SetSelectedFilePath(const AZStd::string& selectedFilePath);
|
||||
|
||||
void SetDefaultDirectory(AZStd::string_view defaultDirectory);
|
||||
AZStd::string_view GetDefaultDirectory() const;
|
||||
|
||||
@@ -60,6 +64,7 @@ namespace AzToolsFramework
|
||||
static AssetSelectionModel AssetTypeSelection(const char* assetTypeName, bool multiselect = false);
|
||||
static AssetSelectionModel AssetTypesSelection(const AZStd::vector<AZ::Data::AssetType>& assetTypes, bool multiselect = false);
|
||||
static AssetSelectionModel AssetGroupSelection(const char* group, bool multiselect = false);
|
||||
static AssetSelectionModel SourceAssetTypeSelection(const QString& pattern, bool multiselect = false);
|
||||
static AssetSelectionModel EverythingSelection(bool multiselect = false);
|
||||
|
||||
private:
|
||||
@@ -68,8 +73,12 @@ namespace AzToolsFramework
|
||||
// some entries like folder should always be displayed, but not always selectable, thus 2 separate filters
|
||||
FilterConstType m_selectionFilter;
|
||||
FilterConstType m_displayFilter;
|
||||
|
||||
|
||||
//! Selection can be based on asset ids (for products), or file paths (for sources)
|
||||
//! These are mututally exclusive
|
||||
AZStd::vector<AZ::Data::AssetId> m_selectedAssetIds;
|
||||
AZStd::vector<AZStd::string> m_selectedFilePaths;
|
||||
|
||||
AZStd::vector<const AssetBrowserEntry*> m_results;
|
||||
AZStd::string m_defaultDirectory;
|
||||
|
||||
|
||||
@@ -251,6 +251,40 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// RegExpFilter
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
RegExpFilter::RegExpFilter()
|
||||
: m_filterPattern("")
|
||||
{
|
||||
}
|
||||
|
||||
void RegExpFilter::SetFilterPattern(const QString& filterPattern)
|
||||
{
|
||||
m_filterPattern = filterPattern;
|
||||
Q_EMIT updatedSignal();
|
||||
}
|
||||
|
||||
QString RegExpFilter::GetNameInternal() const
|
||||
{
|
||||
return m_filterPattern;
|
||||
}
|
||||
|
||||
bool RegExpFilter::MatchInternal(const AssetBrowserEntry* entry) const
|
||||
{
|
||||
// no filter pattern matches any asset
|
||||
if (m_filterPattern.isEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// entry's name matches regular expression pattern
|
||||
QRegExp regExp(m_filterPattern);
|
||||
regExp.setPatternSyntax(QRegExp::Wildcard);
|
||||
|
||||
return regExp.exactMatch(entry->GetDisplayName());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AssetTypeFilter
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -115,6 +115,28 @@ namespace AzToolsFramework
|
||||
QString m_filterString;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// RegExpFilter
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//! RegExpFilter filters assets based on a regular expression pattern
|
||||
class RegExpFilter
|
||||
: public AssetBrowserEntryFilter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RegExpFilter();
|
||||
~RegExpFilter() override = default;
|
||||
|
||||
void SetFilterPattern(const QString& filterPattern);
|
||||
|
||||
protected:
|
||||
QString GetNameInternal() const override;
|
||||
bool MatchInternal(const AssetBrowserEntry* entry) const override;
|
||||
|
||||
private:
|
||||
QString m_filterPattern;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AssetTypeFilter
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1158,7 +1158,8 @@ namespace AzToolsFramework
|
||||
// Select the duplicated entities/instances
|
||||
auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances");
|
||||
selectionUndo->SetParent(undoBatch.GetUndoBatch());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds);
|
||||
ToolsApplicationRequestBus::Broadcast(
|
||||
&ToolsApplicationRequestBus::Events::SetSelectedEntities, duplicatedEntityAndInstanceIds);
|
||||
}
|
||||
|
||||
return AZ::Success(AZStd::move(duplicatedEntityAndInstanceIds));
|
||||
|
||||
+11
-9
@@ -860,18 +860,20 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
bool isDuringUndoRedo = false;
|
||||
EBUS_EVENT_RESULT(isDuringUndoRedo, AzToolsFramework::ToolsApplicationRequests::Bus, IsDuringUndoRedo);
|
||||
if (!isDuringUndoRedo)
|
||||
bool suppressTransformChangedEvent = m_suppressTransformChangedEvent;
|
||||
// temporarily disable calling OnTransformChanged, because CheckApplyCachedWorldTransform is not guaranteed
|
||||
// to call it when m_cachedWorldTransform is identity. We send it manually later.
|
||||
m_suppressTransformChangedEvent = false;
|
||||
// When parent comes online, compute local TM from world TM.
|
||||
CheckApplyCachedWorldTransform(parentTransform->GetWorldTM());
|
||||
if (!m_initialized)
|
||||
{
|
||||
// When parent comes online, compute local TM from world TM.
|
||||
CheckApplyCachedWorldTransform(parentTransform->GetWorldTM());
|
||||
}
|
||||
else
|
||||
{
|
||||
// During undo operations, just apply our local TM.
|
||||
m_initialized = true;
|
||||
// If this is the first time this entity is being activated, manually compute OnTransformChanged
|
||||
// this can occur when either the entity first created or undo/redo command is performed
|
||||
OnTransformChanged(AZ::Transform::Identity(), parentTransform->GetWorldTM());
|
||||
}
|
||||
m_suppressTransformChangedEvent = suppressTransformChangedEvent;
|
||||
|
||||
auto& parentChildIds = GetParentTransformComponent()->m_childrenEntityIds;
|
||||
if (parentChildIds.end() == AZStd::find(parentChildIds.begin(), parentChildIds.end(), GetEntityId()))
|
||||
|
||||
@@ -242,6 +242,9 @@ namespace AzToolsFramework
|
||||
// element is used rather than a data element.
|
||||
bool m_addNonUniformScaleButton = false;
|
||||
|
||||
// Used to check whether entity was just created vs manually reactivated. Set true after OnEntityActivated is called the first time.
|
||||
bool m_initialized = false;
|
||||
|
||||
// Deprecated
|
||||
AZ::InterpolationMode m_interpolatePosition;
|
||||
AZ::InterpolationMode m_interpolateRotation;
|
||||
|
||||
+22
-6
@@ -39,7 +39,12 @@ namespace AzToolsFramework
|
||||
typeFilter->SetAssetType(filterType);
|
||||
typeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
|
||||
|
||||
m_assetBrowserFilterModel->SetFilter(FilterConstType(typeFilter));
|
||||
SetFilter(FilterConstType(typeFilter));
|
||||
}
|
||||
|
||||
void AssetCompleterModel::SetFilter(FilterConstType filter)
|
||||
{
|
||||
m_assetBrowserFilterModel->SetFilter(filter);
|
||||
|
||||
RefreshAssetList();
|
||||
}
|
||||
@@ -120,9 +125,6 @@ namespace AzToolsFramework
|
||||
int rows = m_assetBrowserFilterModel->rowCount(index);
|
||||
if (rows == 0)
|
||||
{
|
||||
if (index != QModelIndex()) {
|
||||
AZ_Error("AssetCompleterModel", false, "No children detected in FetchResources()");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,7 +133,7 @@ namespace AzToolsFramework
|
||||
QModelIndex childIndex = m_assetBrowserFilterModel->index(i, 0, index);
|
||||
AssetBrowserEntry* childEntry = GetAssetEntry(m_assetBrowserFilterModel->mapToSource(childIndex));
|
||||
|
||||
if (childEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Product)
|
||||
if (childEntry->GetEntryType() == m_entryType)
|
||||
{
|
||||
ProductAssetBrowserEntry* productEntry = static_cast<ProductAssetBrowserEntry*>(childEntry);
|
||||
AZStd::string assetName;
|
||||
@@ -167,7 +169,6 @@ namespace AzToolsFramework
|
||||
return m_assets[index.row()].m_displayName;
|
||||
}
|
||||
|
||||
|
||||
const AZ::Data::AssetId AssetCompleterModel::GetAssetIdFromIndex(const QModelIndex& index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
@@ -177,4 +178,19 @@ namespace AzToolsFramework
|
||||
|
||||
return m_assets[index.row()].m_assetId;
|
||||
}
|
||||
|
||||
const AZStd::string_view AssetCompleterModel::GetPathFromIndex(const QModelIndex& index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return m_assets[index.row()].m_path;
|
||||
}
|
||||
|
||||
void AssetCompleterModel::SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType)
|
||||
{
|
||||
m_entryType = entryType;
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -32,6 +32,7 @@ namespace AzToolsFramework
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
void SetFilter(AZ::Data::AssetType filterType);
|
||||
void SetFilter(FilterConstType filter);
|
||||
void RefreshAssetList();
|
||||
void SearchStringHighlight(QString searchString);
|
||||
|
||||
@@ -39,6 +40,9 @@ namespace AzToolsFramework
|
||||
|
||||
const AZStd::string_view GetNameFromIndex(const QModelIndex& index);
|
||||
const AZ::Data::AssetId GetAssetIdFromIndex(const QModelIndex& index);
|
||||
const AZStd::string_view GetPathFromIndex(const QModelIndex& index);
|
||||
|
||||
void SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType);
|
||||
|
||||
private:
|
||||
struct AssetItem
|
||||
@@ -57,6 +61,8 @@ namespace AzToolsFramework
|
||||
AZStd::vector<AssetItem> m_assets;
|
||||
//! String that will be highlighted in the suggestions
|
||||
QString m_highlightString;
|
||||
|
||||
AssetBrowserEntry::AssetEntryType m_entryType = AssetBrowserEntry::AssetEntryType::Product;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+8
-3
@@ -1288,7 +1288,7 @@ namespace AzToolsFramework
|
||||
return newCtrl;
|
||||
}
|
||||
|
||||
void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName)
|
||||
void AssetPropertyHandlerDefault::ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
(void)debugName;
|
||||
|
||||
@@ -1487,6 +1487,11 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void AssetPropertyHandlerDefault::ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName)
|
||||
{
|
||||
ConsumeAttributeInternal(GUI, attrib, attrValue, debugName);
|
||||
}
|
||||
|
||||
void AssetPropertyHandlerDefault::WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node)
|
||||
{
|
||||
(void)index;
|
||||
@@ -1629,8 +1634,8 @@ namespace AzToolsFramework
|
||||
|
||||
void RegisterAssetPropertyHandler()
|
||||
{
|
||||
EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AssetPropertyHandlerDefault());
|
||||
EBUS_EVENT(PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault());
|
||||
PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew AssetPropertyHandlerDefault());
|
||||
PropertyTypeRegistrationMessages::Bus::Broadcast(&PropertyTypeRegistrationMessages::RegisterPropertyType, aznew SimpleAssetPropertyHandlerDefault());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -175,10 +175,11 @@ namespace AzToolsFramework
|
||||
virtual void SetFolderSelection(const AZStd::string& /* folderPath */) {}
|
||||
virtual void ClearAssetInternal();
|
||||
|
||||
void ConfigureAutocompleter();
|
||||
virtual void ConfigureAutocompleter();
|
||||
void RefreshAutocompleter();
|
||||
void EnableAutocompleter();
|
||||
void DisableAutocompleter();
|
||||
const QModelIndex GetSourceIndex(const QModelIndex& index);
|
||||
|
||||
void HandleFieldClear();
|
||||
AZStd::string AddDefaultSuffix(const AZStd::string& filename);
|
||||
@@ -235,20 +236,19 @@ namespace AzToolsFramework
|
||||
void SetSelectedAssetID(const AZ::Data::AssetId& newID, const AZ::Data::AssetType& newType);
|
||||
void SetCurrentAssetHint(const AZStd::string& hint);
|
||||
void SetDefaultAssetID(const AZ::Data::AssetId& defaultID);
|
||||
void PopupAssetPicker();
|
||||
virtual void PopupAssetPicker();
|
||||
void OnClearButtonClicked();
|
||||
void UpdateAssetDisplay();
|
||||
void OnLineEditFocus(bool focus);
|
||||
virtual void OnEditButtonClicked();
|
||||
void OnThumbnailClicked();
|
||||
void OnCompletionModelReset();
|
||||
void OnAutocomplete(const QModelIndex& index);
|
||||
virtual void OnAutocomplete(const QModelIndex& index);
|
||||
void OnTextChange(const QString& text);
|
||||
void OnReturnPressed();
|
||||
void ShowContextMenu(const QPoint& pos);
|
||||
|
||||
private:
|
||||
const QModelIndex GetSourceIndex(const QModelIndex& index);
|
||||
void UpdateThumbnail();
|
||||
};
|
||||
|
||||
@@ -270,7 +270,8 @@ namespace AzToolsFramework
|
||||
virtual void UpdateWidgetInternalTabbing(PropertyAssetCtrl* widget) override { widget->UpdateTabOrder(); }
|
||||
|
||||
virtual QWidget* CreateGUI(QWidget* pParent) override;
|
||||
virtual void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
static void ConsumeAttributeInternal(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName);
|
||||
void ConsumeAttribute(PropertyAssetCtrl* GUI, AZ::u32 attrib, PropertyAttributeReader* attrValue, const char* debugName) override;
|
||||
virtual void WriteGUIValuesIntoProperty(size_t index, PropertyAssetCtrl* GUI, property_t& instance, InstanceDataNode* node) override;
|
||||
virtual bool ReadValuesIntoGUI(size_t index, PropertyAssetCtrl* GUI, const property_t& instance, InstanceDataNode* node) override;
|
||||
};
|
||||
|
||||
+3
-4
@@ -3534,10 +3534,9 @@ namespace AzToolsFramework
|
||||
debugDisplay.SetLineWidth(1.0f);
|
||||
|
||||
const float labelOffset = ed_viewportGizmoAxisLabelOffset;
|
||||
const float screenScale = GetScreenDisplayScaling(viewportId);
|
||||
const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
|
||||
const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
|
||||
const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
|
||||
const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize;
|
||||
const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize;
|
||||
const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize;
|
||||
|
||||
// draw the label of of each axis for the gizmo
|
||||
const float labelSize = ed_viewportGizmoAxisLabelSize;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <Prefab/PrefabTestComponent.h>
|
||||
#include <Prefab/PrefabTestDomUtils.h>
|
||||
|
||||
@@ -50,6 +52,15 @@ namespace UnitTest
|
||||
|
||||
GetApplication()->RegisterComponentDescriptor(PrefabTestComponent::CreateDescriptor());
|
||||
GetApplication()->RegisterComponentDescriptor(PrefabTestComponentWithUnReflectedTypeMember::CreateDescriptor());
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
m_undoStack, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetUndoStack);
|
||||
AZ_Assert(m_undoStack, "Failed to look up undo stack from tools application");
|
||||
}
|
||||
|
||||
void PrefabTestFixture::TearDownEditorFixtureImpl()
|
||||
{
|
||||
m_undoStack = nullptr;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<ToolsTestApplication> PrefabTestFixture::CreateTestApplication()
|
||||
@@ -57,7 +68,20 @@ namespace UnitTest
|
||||
return AZStd::make_unique<PrefabTestToolsApplication>("PrefabTestApplication");
|
||||
}
|
||||
|
||||
AZ::Entity* PrefabTestFixture::CreateEntity(const char* entityName, const bool shouldActivate)
|
||||
void PrefabTestFixture::CreateRootPrefab()
|
||||
{
|
||||
auto entityOwnershipService = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
|
||||
ASSERT_TRUE(entityOwnershipService != nullptr);
|
||||
entityOwnershipService->CreateNewLevelPrefab("UnitTestRoot.prefab", "");
|
||||
auto rootEntityReference = entityOwnershipService->GetRootPrefabInstance()->get().GetContainerEntity();
|
||||
ASSERT_TRUE(rootEntityReference.has_value());
|
||||
auto& rootEntity = rootEntityReference->get();
|
||||
rootEntity.Deactivate();
|
||||
rootEntity.CreateComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
rootEntity.Activate();
|
||||
}
|
||||
|
||||
AZ::Entity* PrefabTestFixture::CreateEntity(AZStd::string entityName, const bool shouldActivate)
|
||||
{
|
||||
// Circumvent the EntityContext system and generate a new entity with a transformcomponent
|
||||
AZ::Entity* newEntity = aznew AZ::Entity(entityName);
|
||||
@@ -71,8 +95,43 @@ namespace UnitTest
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
AZ::EntityId PrefabTestFixture::CreateEntityUnderRootPrefab(AZStd::string name, AZ::EntityId parentId)
|
||||
{
|
||||
auto createResult = m_prefabPublicInterface->CreateEntity(parentId, AZ::Vector3());
|
||||
AZ_Assert(createResult.IsSuccess(), "Failed to create entity: %s", createResult.GetError().c_str());
|
||||
AZ::EntityId entityId = createResult.GetValue();
|
||||
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
|
||||
|
||||
entity->Deactivate();
|
||||
|
||||
entity->SetName(name);
|
||||
|
||||
// Normally, in invalid parent ID should automatically parent us to the root prefab, but currently in the unit test
|
||||
// environment entities aren't created with a default transform component, so CreateEntity won't correctly parent.
|
||||
// We get the actual target parent ID here, then create our missing transform component.
|
||||
if (!parentId.IsValid())
|
||||
{
|
||||
auto prefabEditorEntityOwnershipInterface = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
|
||||
parentId = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance()->get().GetContainerEntityId();
|
||||
}
|
||||
|
||||
auto transform = aznew AzToolsFramework::Components::TransformComponent;
|
||||
transform->SetParent(parentId);
|
||||
entity->AddComponent(transform);
|
||||
|
||||
entity->Activate();
|
||||
|
||||
// Update our undo cache entry to include the rename / reparent as one atomic operation.
|
||||
m_prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_undoStack->GetTop());
|
||||
m_prefabSystemComponent->OnSystemTick();
|
||||
|
||||
return entityId;
|
||||
}
|
||||
|
||||
void PrefabTestFixture::CompareInstances(const AzToolsFramework::Prefab::Instance& instanceA,
|
||||
const AzToolsFramework::Prefab::Instance& instanceB, bool shouldCompareLinkIds, bool shouldCompareContainerEntities)
|
||||
const AzToolsFramework::Prefab::Instance& instanceB, bool shouldCompareLinkIds, bool shouldCompareContainerEntities)
|
||||
{
|
||||
AzToolsFramework::Prefab::TemplateId templateAId = instanceA.GetTemplateId();
|
||||
AzToolsFramework::Prefab::TemplateId templateBId = instanceB.GetTemplateId();
|
||||
@@ -125,4 +184,22 @@ namespace UnitTest
|
||||
EXPECT_EQ(entityInInstance->GetState(), AZ::Entity::State::Active);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabTestFixture::ProcessDeferredUpdates()
|
||||
{
|
||||
// Force a prefab propagation for updates that are deferred to the next tick.
|
||||
m_prefabSystemComponent->OnSystemTick();
|
||||
}
|
||||
|
||||
void PrefabTestFixture::Undo()
|
||||
{
|
||||
m_undoStack->Undo();
|
||||
ProcessDeferredUpdates();
|
||||
}
|
||||
|
||||
void PrefabTestFixture::Redo()
|
||||
{
|
||||
m_undoStack->Redo();
|
||||
ProcessDeferredUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,13 @@ namespace UnitTest
|
||||
inline static const char* CarPrefabMockFilePath = "SomePathToCar";
|
||||
|
||||
void SetUpEditorFixtureImpl() override;
|
||||
void TearDownEditorFixtureImpl() override;
|
||||
|
||||
AZStd::unique_ptr<ToolsTestApplication> CreateTestApplication() override;
|
||||
|
||||
AZ::Entity* CreateEntity(const char* entityName, const bool shouldActivate = true);
|
||||
void CreateRootPrefab();
|
||||
AZ::Entity* CreateEntity(AZStd::string entityName, const bool shouldActivate = true);
|
||||
AZ::EntityId CreateEntityUnderRootPrefab(AZStd::string name, AZ::EntityId parentId = AZ::EntityId());
|
||||
|
||||
void CompareInstances(const Instance& instanceA, const Instance& instanceB, bool shouldCompareLinkIds = true,
|
||||
bool shouldCompareContainerEntities = true);
|
||||
@@ -62,10 +65,20 @@ namespace UnitTest
|
||||
//! Validates that all entities within a prefab instance are in 'Active' state.
|
||||
void ValidateInstanceEntitiesActive(Instance& instance);
|
||||
|
||||
// Kicks off any updates scheduled for the next tick
|
||||
virtual void ProcessDeferredUpdates();
|
||||
|
||||
// Performs an undo operation and ensures the tick-scheduled updates happen
|
||||
void Undo();
|
||||
|
||||
// Performs a redo operation and ensures the tick-scheduled updates happen
|
||||
void Redo();
|
||||
|
||||
PrefabSystemComponent* m_prefabSystemComponent = nullptr;
|
||||
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
|
||||
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
|
||||
InstanceUpdateExecutorInterface* m_instanceUpdateExecutorInterface = nullptr;
|
||||
InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr;
|
||||
AzToolsFramework::UndoSystem::UndoStack* m_undoStack = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <Prefab/PrefabTestFixture.h>
|
||||
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
|
||||
@@ -1063,4 +1066,67 @@ R"DELIMITER(<ObjectStream version="1">
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fixture provides a root prefab with Transform component and listens for TransformNotificationBus.
|
||||
class TransformComponentActivationTest
|
||||
: public PrefabTestFixture
|
||||
, public TransformNotificationBus::Handler
|
||||
{
|
||||
protected:
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
PrefabTestFixture::SetUpEditorFixtureImpl();
|
||||
|
||||
CreateRootPrefab();
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
{
|
||||
BusDisconnect();
|
||||
|
||||
PrefabTestFixture::TearDownEditorFixtureImpl();
|
||||
}
|
||||
|
||||
void OnTransformChanged(const Transform& /*local*/, const Transform& /*world*/) override
|
||||
{
|
||||
m_transformUpdated = true;
|
||||
}
|
||||
|
||||
void MoveEntity(AZ::EntityId entityId)
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Move Entity");
|
||||
TransformBus::Event(entityId, &TransformInterface::SetWorldTranslation, Vector3(1.f, 0.f, 0.f));
|
||||
}
|
||||
|
||||
bool m_transformUpdated = false;
|
||||
};
|
||||
|
||||
TEST_F(TransformComponentActivationTest, TransformChangedEventIsSentWhenEntityIsActivatedViaUndoRedo)
|
||||
{
|
||||
AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity");
|
||||
MoveEntity(entityId);
|
||||
BusConnect(entityId);
|
||||
|
||||
// verify that undoing/redoing move operations fires TransformChanged event
|
||||
Undo();
|
||||
EXPECT_TRUE(m_transformUpdated);
|
||||
m_transformUpdated = false;
|
||||
|
||||
Redo();
|
||||
EXPECT_TRUE(m_transformUpdated);
|
||||
m_transformUpdated = false;
|
||||
}
|
||||
|
||||
TEST_F(TransformComponentActivationTest, TransformChangedEventIsNotSentWhenEntityIsDeactivatedAndActivated)
|
||||
{
|
||||
AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity");
|
||||
BusConnect(entityId);
|
||||
|
||||
// verify that simply activating/deactivating an entity does not fire TransformChanged event
|
||||
Entity* entity = nullptr;
|
||||
ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
|
||||
entity->Deactivate();
|
||||
entity->Activate();
|
||||
EXPECT_FALSE(m_transformUpdated);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -37,16 +37,11 @@ namespace UnitTest
|
||||
m_model->Initialize();
|
||||
m_modelTester =
|
||||
AZStd::make_unique<QAbstractItemModelTester>(m_model.get(), QAbstractItemModelTester::FailureReportingMode::Fatal);
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
m_undoStack, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetUndoStack);
|
||||
AZ_Assert(m_undoStack, "Failed to look up undo stack from tools application");
|
||||
|
||||
|
||||
// Create a new root prefab - the synthetic "NewLevel.prefab" that comes in by default isn't suitable for outliner tests
|
||||
// because it's created before the EditorEntityModel that our EntityOutlinerListModel subscribes to, and we want to
|
||||
// recreate it as part of the fixture regardless.
|
||||
auto entityOwnershipService = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
|
||||
entityOwnershipService->CreateNewLevelPrefab("UnitTestRoot.prefab", "");
|
||||
CreateRootPrefab();
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
@@ -56,45 +51,7 @@ namespace UnitTest
|
||||
m_model.reset();
|
||||
PrefabTestFixture::TearDownEditorFixtureImpl();
|
||||
}
|
||||
|
||||
// Creates an entity with a given name as one undoable operation
|
||||
// Parents to parentId, or the root prefab container entity if parentId is invalid
|
||||
AZ::EntityId CreateNamedEntity(AZStd::string name, AZ::EntityId parentId = AZ::EntityId())
|
||||
{
|
||||
auto createResult = m_prefabPublicInterface->CreateEntity(parentId, AZ::Vector3());
|
||||
AZ_Assert(createResult.IsSuccess(), "Failed to create entity: %s", createResult.GetError().c_str());
|
||||
AZ::EntityId entityId = createResult.GetValue();
|
||||
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
|
||||
|
||||
entity->Deactivate();
|
||||
|
||||
entity->SetName(name);
|
||||
|
||||
// Normally, in invalid parent ID should automatically parent us to the root prefab, but currently in the unit test
|
||||
// environment entities aren't created with a default transform component, so CreateEntity won't correctly parent.
|
||||
// We get the actual target parent ID here, then create our missing transform component.
|
||||
if (!parentId.IsValid())
|
||||
{
|
||||
auto prefabEditorEntityOwnershipInterface = AZ::Interface<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::Get();
|
||||
parentId = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance()->get().GetContainerEntityId();
|
||||
}
|
||||
|
||||
auto transform = aznew AzToolsFramework::Components::TransformComponent;
|
||||
transform->SetParent(parentId);
|
||||
entity->AddComponent(transform);
|
||||
|
||||
entity->Activate();
|
||||
|
||||
// Update our undo cache entry to include the rename / reparent as one atomic operation.
|
||||
m_prefabPublicInterface->GenerateUndoNodesForEntityChangeAndUpdateCache(entityId, m_undoStack->GetTop());
|
||||
|
||||
ProcessDeferredUpdates();
|
||||
|
||||
return entityId;
|
||||
}
|
||||
|
||||
|
||||
// Helper to visualize debug state
|
||||
void PrintModel()
|
||||
{
|
||||
@@ -125,32 +82,16 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
// Kicks off any updates scheduled for the next tick
|
||||
void ProcessDeferredUpdates()
|
||||
void ProcessDeferredUpdates() override
|
||||
{
|
||||
// Force a prefab propagation for updates that are deferred to the next tick.
|
||||
m_prefabSystemComponent->OnSystemTick();
|
||||
PrefabTestFixture::ProcessDeferredUpdates();
|
||||
|
||||
// Ensure the model process its entity update queue
|
||||
m_model->ProcessEntityUpdates();
|
||||
}
|
||||
|
||||
// Performs an undo operation and ensures the tick-scheduled updates happen
|
||||
void Undo()
|
||||
{
|
||||
m_undoStack->Undo();
|
||||
ProcessDeferredUpdates();
|
||||
}
|
||||
|
||||
// Performs a redo operation and ensures the tick-scheduled updates happen
|
||||
void Redo()
|
||||
{
|
||||
m_undoStack->Redo();
|
||||
ProcessDeferredUpdates();
|
||||
}
|
||||
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::EntityOutlinerListModel> m_model;
|
||||
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTester;
|
||||
AzToolsFramework::UndoSystem::UndoStack* m_undoStack = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(EntityOutlinerTest, TestCreateFlatHierarchyUndoAndRedoWorks)
|
||||
@@ -159,7 +100,7 @@ namespace UnitTest
|
||||
|
||||
for (size_t i = 0; i < entityCount; ++i)
|
||||
{
|
||||
CreateNamedEntity(AZStd::string::format("Entity%zu", i));
|
||||
CreateEntityUnderRootPrefab(AZStd::string::format("Entity%zu", i));
|
||||
EXPECT_EQ(m_model->rowCount(GetRootIndex()), i + 1);
|
||||
}
|
||||
|
||||
@@ -195,7 +136,7 @@ namespace UnitTest
|
||||
AZ::EntityId parentId;
|
||||
for (int i = 0; i < depth; i++)
|
||||
{
|
||||
parentId = CreateNamedEntity(AZStd::string::format("EntityDepth%i", i), parentId);
|
||||
parentId = CreateEntityUnderRootPrefab(AZStd::string::format("EntityDepth%i", i), parentId);
|
||||
EXPECT_EQ(modelDepth(), i + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -283,7 +283,7 @@ namespace AssetProcessor
|
||||
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
config.AddExcludeRecognizer(excludeRecogniser);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace AssetProcessor
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
// we are excluding all the files in the folder but not the folder itself
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser);
|
||||
m_assetScanner.get()->StartScan();
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace AssetProcessor
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
// we are excluding the complete folder here
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser);
|
||||
m_assetScanner.get()->StartScan();
|
||||
|
||||
|
||||
+2
@@ -413,6 +413,8 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes)
|
||||
auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular");
|
||||
ASSERT_TRUE(configRoot);
|
||||
UnitTestPlatformConfiguration config;
|
||||
|
||||
config.AddScanFolder(ScanFolderInfo("blahblah", "Blah ScanFolder", "sf2", true, true), true);
|
||||
m_absorber.Clear();
|
||||
ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false));
|
||||
ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0);
|
||||
|
||||
@@ -347,7 +347,7 @@ namespace AssetProcessor
|
||||
|
||||
ExcludeAssetRecognizer excludeRecogniser;
|
||||
excludeRecogniser.m_name = "backup";
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex);
|
||||
config.AddExcludeRecognizer(excludeRecogniser);
|
||||
|
||||
AssetProcessorManager_Test apm(&config); // note, this will 'push' the scan folders in to the db.
|
||||
@@ -1791,13 +1791,8 @@ namespace AssetProcessor
|
||||
UNIT_TEST_EXPECT_TRUE((newfingerprintForPCAfterVersionChange != fingerprintForPC) || (newfingerprintForPCAfterVersionChange != newfingerprintForPC));//Fingerprints should be different
|
||||
UNIT_TEST_EXPECT_TRUE((newfingerprintForANDROIDAfterVersionChange != fingerprintForANDROID) || (newfingerprintForANDROIDAfterVersionChange != newfingerprintForANDROID));//Fingerprints should be different
|
||||
|
||||
//------Test for Files which are excluded
|
||||
processResults.clear();
|
||||
absolutePath = AssetUtilities::NormalizeFilePath(tempPath.absoluteFilePath("subfolder3/savebackup/test.txt"));
|
||||
QMetaObject::invokeMethod(&apm, "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absolutePath));
|
||||
UNIT_TEST_EXPECT_FALSE(BlockUntil(idling, 3000)); //Processing a file that will be excluded should not cause assetprocessor manager to emit the onBecameIdle signal because its state should not change
|
||||
UNIT_TEST_EXPECT_TRUE(processResults.size() == 0);
|
||||
|
||||
|
||||
// ------------- Test querying asset status -------------------
|
||||
{
|
||||
absolutePath = tempPath.absoluteFilePath("subfolder2/folder/ship.tiff");
|
||||
|
||||
@@ -1633,13 +1633,18 @@ namespace AssetProcessor
|
||||
|
||||
bool AssetProcessor::PlatformConfiguration::IsFileExcluded(QString fileName) const
|
||||
{
|
||||
for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
|
||||
QString relPath, scanFolderName;
|
||||
if (ConvertToRelativePath(fileName, relPath, scanFolderName))
|
||||
{
|
||||
if (excludeRecognizer.m_patternMatcher.MatchesPath(fileName.toUtf8().constData()))
|
||||
for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers)
|
||||
{
|
||||
return true;
|
||||
if (excludeRecognizer.m_patternMatcher.MatchesPath(relPath.toUtf8().constData()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -50,10 +50,10 @@
|
||||
"order": 6000
|
||||
},
|
||||
"Exclude HoldFiles": {
|
||||
"pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*"
|
||||
"pattern": "(^|.+/)Levels/.*_hold(/.*)?$"
|
||||
},
|
||||
"Exclude TempFiles": {
|
||||
"pattern": ".*\\\\/\\\\$tmp[0-9]*_.*"
|
||||
"pattern": "(^|.+/)\\\\$tmp[0-9]*_.*"
|
||||
},
|
||||
"RC i_caf": {
|
||||
"glob": "*.i_caf",
|
||||
|
||||
+2
-2
@@ -74,10 +74,10 @@
|
||||
"include": "test"
|
||||
},
|
||||
"Exclude HoldFiles": {
|
||||
"pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*"
|
||||
"pattern": "(^|.+/)Levels/.*_hold(/.*)?$"
|
||||
},
|
||||
"Exclude TempFiles": {
|
||||
"pattern": ".*\\\\/\\\\$tmp[0-9]*_.*"
|
||||
"pattern": "(^|.+/)\\\\$tmp[0-9]*_.*"
|
||||
},
|
||||
"RC i_caf": {
|
||||
"glob": "*.i_caf",
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace O3DE::ProjectManager
|
||||
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
|
||||
|
||||
return AZ::Success(QStringList{ ProjectCMakeCommand,
|
||||
"-G", "Visual Studio 16 2019",
|
||||
"-B", targetBuildPath,
|
||||
"-S", m_projectInfo.m_path,
|
||||
QString("-DLY_3RDPARTY_PATH=").append(thirdPartyPath),
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace O3DE::ProjectManager
|
||||
if (vsWhereFile.exists() && vsWhereFile.isFile())
|
||||
{
|
||||
QStringList vsWhereBaseArguments = QStringList{"-version",
|
||||
"16.9.2",
|
||||
"[16.9.2,17)",
|
||||
"-latest",
|
||||
"-requires",
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"};
|
||||
@@ -106,10 +106,8 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
|
||||
return AZ::Failure(QObject::tr("Visual Studio 2019 version 16.9.2 or higher not found.<br><br>"
|
||||
"Visual Studio 2019 is required to build this project."
|
||||
" Install any edition of <a href='https://visualstudio.microsoft.com/downloads/'>Visual Studio 2019</a>"
|
||||
" or update to a newer version before proceeding to the next step."
|
||||
" While installing configure Visual Studio with these <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#visual-studio-configuration'>workloads</a>."));
|
||||
"A compatible version of Visual Studio is required to build this project.<br>"
|
||||
"Refer to the <a href='https://o3de.org/docs/welcome-guide/requirements/#microsoft-visual-studio'>Visual Studio requirements</a> for more information."));
|
||||
}
|
||||
|
||||
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -111,6 +112,11 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
if (!RegisterEngine(interactive))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const AZ::CommandLine* commandLine = GetCommandLine();
|
||||
AZ_Assert(commandLine, "Failed to get command line");
|
||||
|
||||
@@ -165,6 +171,85 @@ namespace O3DE::ProjectManager
|
||||
return m_entity != nullptr;
|
||||
}
|
||||
|
||||
bool Application::RegisterEngine(bool interactive)
|
||||
{
|
||||
// get this engine's info
|
||||
auto engineInfoOutcome = m_pythonBindings->GetEngineInfo();
|
||||
if (!engineInfoOutcome)
|
||||
{
|
||||
if (interactive)
|
||||
{
|
||||
QMessageBox::critical(nullptr,
|
||||
QObject::tr("Failed to get engine info"),
|
||||
QObject::tr("A valid engine.json could not be found or loaded. "
|
||||
"Please verify a valid engine.json file exists in %1")
|
||||
.arg(GetEngineRoot()));
|
||||
}
|
||||
|
||||
AZ_Error("Project Manager", false, "Failed to get engine info");
|
||||
return false;
|
||||
}
|
||||
|
||||
EngineInfo engineInfo = engineInfoOutcome.GetValue();
|
||||
if (engineInfo.m_registered)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if an engine with this name is already registered and has a valid engine.json
|
||||
auto existingEngineResult = m_pythonBindings->GetEngineInfo(engineInfo.m_name);
|
||||
if (existingEngineResult)
|
||||
{
|
||||
if (!interactive)
|
||||
{
|
||||
AZ_Error("Project Manager", false, "An engine with the name %s is already registered with the path %s",
|
||||
engineInfo.m_name.toUtf8().constData(), engineInfo.m_path.toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the updated engine name unless the user wants to cancel
|
||||
bool okPressed = false;
|
||||
const EngineInfo& otherEngineInfo = existingEngineResult.GetValue();
|
||||
|
||||
engineInfo.m_name = QInputDialog::getText(nullptr,
|
||||
QObject::tr("Engine '%1' already registered").arg(engineInfo.m_name),
|
||||
QObject::tr("An engine named '%1' is already registered.<br /><br />"
|
||||
"<b>Current path</b><br />%2<br/><br />"
|
||||
"<b>New path</b><br />%3<br /><br />"
|
||||
"Press 'OK' to force registration, or provide a new engine name below.<br />"
|
||||
"Alternatively, press `Cancel` to close the Project Manager and resolve the issue manually.")
|
||||
.arg(engineInfo.m_name, otherEngineInfo.m_path, engineInfo.m_path),
|
||||
QLineEdit::Normal,
|
||||
engineInfo.m_name,
|
||||
&okPressed);
|
||||
|
||||
if (!okPressed)
|
||||
{
|
||||
// user elected not to change the name or force registration
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// always force register in case there is an engine registered in o3de_manifest.json, but
|
||||
// the engine.json is missing or corrupt in which case GetEngineInfo() fails
|
||||
constexpr bool forceRegistration = true;
|
||||
auto registerOutcome = m_pythonBindings->SetEngineInfo(engineInfo, forceRegistration);
|
||||
if (!registerOutcome)
|
||||
{
|
||||
if (interactive)
|
||||
{
|
||||
ProjectUtils::DisplayDetailedError(QObject::tr("Failed to register engine"), registerOutcome);
|
||||
}
|
||||
|
||||
AZ_Error("Project Manager", false, "Failed to register engine %s : %s",
|
||||
engineInfo.m_path.toUtf8().constData(), registerOutcome.GetError().first.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::TearDown()
|
||||
{
|
||||
if (m_entity)
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
private:
|
||||
bool InitLog(const char* logName);
|
||||
bool RegisterEngine(bool interactive);
|
||||
|
||||
AZStd::unique_ptr<PythonBindings> m_pythonBindings;
|
||||
QSharedPointer<QCoreApplication> m_app;
|
||||
|
||||
@@ -25,13 +25,16 @@ namespace O3DE::ProjectManager
|
||||
QString m_name;
|
||||
QString m_thirdPartyPath;
|
||||
|
||||
// from o3de_manifest.json
|
||||
QString m_path;
|
||||
|
||||
// from o3de_manifest.json
|
||||
QString m_defaultProjectsFolder;
|
||||
QString m_defaultGemsFolder;
|
||||
QString m_defaultTemplatesFolder;
|
||||
QString m_defaultRestrictedFolder;
|
||||
|
||||
bool m_registered = false;
|
||||
|
||||
bool IsValid() const;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <FormFolderBrowseEditWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <PathValidator.h>
|
||||
#include <ProjectUtils.h>
|
||||
#include <AzQtComponents/Utilities/DesktopUtilities.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
@@ -114,10 +115,10 @@ namespace O3DE::ProjectManager
|
||||
engineInfo.m_defaultGemsFolder = m_defaultGems->lineEdit()->text();
|
||||
engineInfo.m_defaultTemplatesFolder = m_defaultProjectTemplates->lineEdit()->text();
|
||||
|
||||
bool result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo);
|
||||
auto result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Engine Settings"), tr("Failed to save engine settings."));
|
||||
ProjectUtils::DisplayDetailedError(tr("Failed to save engine settings"), result, this);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <GemRepo/GemRepoInspector.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
#include <ProjectUtils.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
@@ -92,8 +93,7 @@ namespace O3DE::ProjectManager
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Outcome < void,
|
||||
AZStd::pair<AZStd::string, AZStd::string>> addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri);
|
||||
auto addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri);
|
||||
if (addGemRepoResult.IsSuccess())
|
||||
{
|
||||
Reinit();
|
||||
@@ -102,20 +102,7 @@ namespace O3DE::ProjectManager
|
||||
else
|
||||
{
|
||||
QString failureMessage = tr("Failed to add gem repo: %1.").arg(repoUri);
|
||||
if (!addGemRepoResult.GetError().second.empty())
|
||||
{
|
||||
QMessageBox addRepoError;
|
||||
addRepoError.setIcon(QMessageBox::Critical);
|
||||
addRepoError.setWindowTitle(failureMessage);
|
||||
addRepoError.setText(addGemRepoResult.GetError().first.c_str());
|
||||
addRepoError.setDetailedText(addGemRepoResult.GetError().second.c_str());
|
||||
addRepoError.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, failureMessage, addGemRepoResult.GetError().first.c_str());
|
||||
}
|
||||
|
||||
ProjectUtils::DisplayDetailedError(failureMessage, addGemRepoResult, this);
|
||||
AZ_Error("Project Manager", false, failureMessage.toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,5 +659,24 @@ namespace O3DE::ProjectManager
|
||||
return AZ::Success(QString(projectBuildPath.c_str()));
|
||||
}
|
||||
|
||||
void DisplayDetailedError(const QString& title, const AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>>& outcome, QWidget* parent)
|
||||
{
|
||||
const AZStd::string& generalError = outcome.GetError().first;
|
||||
const AZStd::string& detailedError = outcome.GetError().second;
|
||||
|
||||
if (!detailedError.empty())
|
||||
{
|
||||
QMessageBox errorDialog(parent);
|
||||
errorDialog.setIcon(QMessageBox::Critical);
|
||||
errorDialog.setWindowTitle(title);
|
||||
errorDialog.setText(generalError.c_str());
|
||||
errorDialog.setDetailedText(detailedError.c_str());
|
||||
errorDialog.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(parent, title, generalError.c_str());
|
||||
}
|
||||
}
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -98,5 +98,14 @@ namespace O3DE::ProjectManager
|
||||
*/
|
||||
AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath);
|
||||
|
||||
|
||||
/**
|
||||
* Display a dialog with general and detailed sections for the given AZ::Outcome
|
||||
* @param title Dialog title
|
||||
* @param outcome The AZ::Outcome with general and detailed error messages
|
||||
* @param parent Optional QWidget parent
|
||||
*/
|
||||
void DisplayDetailedError(const QString& title, const AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>>& outcome, QWidget* parent = nullptr);
|
||||
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -312,6 +312,7 @@ namespace O3DE::ProjectManager
|
||||
m_register = pybind11::module::import("o3de.register");
|
||||
m_manifest = pybind11::module::import("o3de.manifest");
|
||||
m_engineTemplate = pybind11::module::import("o3de.engine_template");
|
||||
m_engineProperties = pybind11::module::import("o3de.engine_properties");
|
||||
m_enableGemProject = pybind11::module::import("o3de.enable_gem");
|
||||
m_disableGemProject = pybind11::module::import("o3de.disable_gem");
|
||||
m_editProjectProperties = pybind11::module::import("o3de.project_properties");
|
||||
@@ -319,9 +320,6 @@ namespace O3DE::ProjectManager
|
||||
m_repo = pybind11::module::import("o3de.repo");
|
||||
m_pathlib = pybind11::module::import("pathlib");
|
||||
|
||||
// make sure the engine is registered
|
||||
RegisterThisEngine();
|
||||
|
||||
m_pythonStarted = !PyErr_Occurred();
|
||||
return m_pythonStarted;
|
||||
}
|
||||
@@ -346,36 +344,6 @@ namespace O3DE::ProjectManager
|
||||
return !PyErr_Occurred();
|
||||
}
|
||||
|
||||
bool PythonBindings::RegisterThisEngine()
|
||||
{
|
||||
bool registrationResult = true; // already registered is considered successful
|
||||
bool pythonResult = ExecuteWithLock(
|
||||
[&]
|
||||
{
|
||||
// check current engine path against all other registered engines
|
||||
// to see if we are already registered
|
||||
auto allEngines = m_manifest.attr("get_engines")();
|
||||
if (pybind11::isinstance<pybind11::list>(allEngines))
|
||||
{
|
||||
for (auto engine : allEngines)
|
||||
{
|
||||
AZ::IO::FixedMaxPath enginePath(Py_To_String(engine));
|
||||
if (enginePath.Compare(m_enginePath) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto result = m_register.attr("register")(QString_To_Py_Path(QString(m_enginePath.c_str())));
|
||||
registrationResult = (result.cast<int>() == 0);
|
||||
});
|
||||
|
||||
bool finalResult = (registrationResult && pythonResult);
|
||||
AZ_Assert(finalResult, "Registration of this engine failed!");
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> PythonBindings::ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback)
|
||||
{
|
||||
if (!Py_IsInitialized())
|
||||
@@ -407,16 +375,22 @@ namespace O3DE::ProjectManager
|
||||
return ExecuteWithLockErrorHandling(executionCallback).IsSuccess();
|
||||
}
|
||||
|
||||
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
|
||||
EngineInfo PythonBindings::EngineInfoFromPath(pybind11::handle enginePath)
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
auto enginePath = m_manifest.attr("get_this_engine_path")();
|
||||
try
|
||||
{
|
||||
auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath);
|
||||
if (pybind11::isinstance<pybind11::dict>(engineData))
|
||||
{
|
||||
engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0");
|
||||
engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE");
|
||||
engineInfo.m_path = Py_To_String(enginePath);
|
||||
}
|
||||
|
||||
auto o3deData = m_manifest.attr("load_o3de_manifest")();
|
||||
if (pybind11::isinstance<pybind11::dict>(o3deData))
|
||||
{
|
||||
engineInfo.m_path = Py_To_String(enginePath);
|
||||
auto defaultGemsFolder = m_manifest.attr("get_o3de_gems_folder")();
|
||||
engineInfo.m_defaultGemsFolder = Py_To_String_Optional(o3deData, "default_gems_folder", Py_To_String(defaultGemsFolder));
|
||||
|
||||
@@ -433,19 +407,62 @@ namespace O3DE::ProjectManager
|
||||
engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData, "default_third_party_folder", Py_To_String(defaultThirdPartyFolder));
|
||||
}
|
||||
|
||||
auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath);
|
||||
if (pybind11::isinstance<pybind11::dict>(engineData))
|
||||
// check if engine path is registered
|
||||
auto allEngines = m_manifest.attr("get_engines")();
|
||||
if (pybind11::isinstance<pybind11::list>(allEngines))
|
||||
{
|
||||
try
|
||||
const AZ::IO::FixedMaxPath enginePathFixed(Py_To_String(enginePath));
|
||||
for (auto engine : allEngines)
|
||||
{
|
||||
engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0");
|
||||
engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE");
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath));
|
||||
AZ::IO::FixedMaxPath otherEnginePath(Py_To_String(engine));
|
||||
if (otherEnginePath.Compare(enginePathFixed) == 0)
|
||||
{
|
||||
engineInfo.m_registered = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath));
|
||||
}
|
||||
return engineInfo;
|
||||
}
|
||||
|
||||
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
|
||||
bool result = ExecuteWithLock([&] {
|
||||
auto enginePath = m_manifest.attr("get_this_engine_path")();
|
||||
engineInfo = EngineInfoFromPath(enginePath);
|
||||
});
|
||||
|
||||
if (!result || !engineInfo.IsValid())
|
||||
{
|
||||
return AZ::Failure();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Success(AZStd::move(engineInfo));
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo(const QString& engineName)
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
auto enginePathResult = m_manifest.attr("get_registered")(QString_To_Py_String(engineName));
|
||||
|
||||
// if a valid registered object is not found None is returned
|
||||
if (!pybind11::isinstance<pybind11::none>(enginePathResult))
|
||||
{
|
||||
engineInfo = EngineInfoFromPath(enginePathResult);
|
||||
|
||||
// it is possible an engine is registered in o3de_manifest.json but the engine.json is
|
||||
// missing or corrupt in which case we do not consider it a registered engine
|
||||
}
|
||||
});
|
||||
|
||||
if (!result || !engineInfo.IsValid())
|
||||
@@ -458,10 +475,32 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo)
|
||||
IPythonBindings::DetailedOutcome PythonBindings::SetEngineInfo(const EngineInfo& engineInfo, bool force)
|
||||
{
|
||||
bool result = ExecuteWithLock([&] {
|
||||
auto registrationResult = m_register.attr("register")(
|
||||
bool registrationSuccess = false;
|
||||
bool pythonSuccess = ExecuteWithLock([&] {
|
||||
|
||||
EngineInfo currentEngine = EngineInfoFromPath(QString_To_Py_Path(engineInfo.m_path));
|
||||
|
||||
// be kind to source control and avoid needlessly updating engine.json
|
||||
if (currentEngine.IsValid() &&
|
||||
(currentEngine.m_name.compare(engineInfo.m_name) != 0 || currentEngine.m_version.compare(engineInfo.m_version) != 0))
|
||||
{
|
||||
auto enginePropsResult = m_engineProperties.attr("edit_engine_props")(
|
||||
QString_To_Py_Path(engineInfo.m_path),
|
||||
pybind11::none(), // existing engine_name
|
||||
QString_To_Py_String(engineInfo.m_name),
|
||||
QString_To_Py_String(engineInfo.m_version)
|
||||
);
|
||||
|
||||
if (enginePropsResult.cast<int>() != 0)
|
||||
{
|
||||
// do not proceed with registration
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto result = m_register.attr("register")(
|
||||
QString_To_Py_Path(engineInfo.m_path),
|
||||
pybind11::none(), // project_path
|
||||
pybind11::none(), // gem_path
|
||||
@@ -474,16 +513,22 @@ namespace O3DE::ProjectManager
|
||||
QString_To_Py_Path(engineInfo.m_defaultGemsFolder),
|
||||
QString_To_Py_Path(engineInfo.m_defaultTemplatesFolder),
|
||||
pybind11::none(), // default_restricted_folder
|
||||
QString_To_Py_Path(engineInfo.m_thirdPartyPath)
|
||||
);
|
||||
QString_To_Py_Path(engineInfo.m_thirdPartyPath),
|
||||
pybind11::none(), // external_subdir_engine_path
|
||||
pybind11::none(), // external_subdir_project_path
|
||||
false, // remove
|
||||
force
|
||||
);
|
||||
|
||||
if (registrationResult.cast<int>() != 0)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
registrationSuccess = result.cast<int>() == 0;
|
||||
});
|
||||
|
||||
return result;
|
||||
if (pythonSuccess && registrationSuccess)
|
||||
{
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
return AZ::Failure<ErrorPair>(GetErrorPair());
|
||||
}
|
||||
|
||||
AZ::Outcome<GemInfo> PythonBindings::GetGemInfo(const QString& path, const QString& projectPath)
|
||||
@@ -1064,7 +1109,7 @@ namespace O3DE::ProjectManager
|
||||
return result && refreshResult;
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> PythonBindings::AddGemRepo(const QString& repoUri)
|
||||
IPythonBindings::DetailedOutcome PythonBindings::AddGemRepo(const QString& repoUri)
|
||||
{
|
||||
bool registrationResult = false;
|
||||
bool result = ExecuteWithLock(
|
||||
@@ -1080,7 +1125,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
if (!result || !registrationResult)
|
||||
{
|
||||
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(GetSimpleDetailedErrorPair());
|
||||
return AZ::Failure<IPythonBindings::ErrorPair>(GetErrorPair());
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
@@ -1170,13 +1215,10 @@ namespace O3DE::ProjectManager
|
||||
return gemRepoInfo;
|
||||
}
|
||||
|
||||
//#define MOCK_GEM_REPO_INFO true
|
||||
|
||||
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> PythonBindings::GetAllGemRepoInfos()
|
||||
{
|
||||
QVector<GemRepoInfo> gemRepos;
|
||||
|
||||
#ifndef MOCK_GEM_REPO_INFO
|
||||
auto result = ExecuteWithLockErrorHandling(
|
||||
[&]
|
||||
{
|
||||
@@ -1189,18 +1231,6 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
#else
|
||||
GemRepoInfo mockJohnRepo("JohnCreates", "John Smith", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true);
|
||||
mockJohnRepo.m_summary = "John's Summary. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitudin dapibus urna";
|
||||
mockJohnRepo.m_repoUri = "https://github.com/o3de/o3de";
|
||||
mockJohnRepo.m_additionalInfo = "John's additional info. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitu.";
|
||||
gemRepos.push_back(mockJohnRepo);
|
||||
|
||||
GemRepoInfo mockJaneRepo("JanesGems", "Jane Doe", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false);
|
||||
mockJaneRepo.m_summary = "Jane's Summary.";
|
||||
mockJaneRepo.m_repoUri = "https://github.com/o3de/o3de.org";
|
||||
gemRepos.push_back(mockJaneRepo);
|
||||
#endif // MOCK_GEM_REPO_INFO
|
||||
|
||||
std::sort(gemRepos.begin(), gemRepos.end());
|
||||
return AZ::Success(AZStd::move(gemRepos));
|
||||
@@ -1261,7 +1291,7 @@ namespace O3DE::ProjectManager
|
||||
return AZ::Success(AZStd::move(gemInfos));
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> PythonBindings::DownloadGem(
|
||||
IPythonBindings::DetailedOutcome PythonBindings::DownloadGem(
|
||||
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force)
|
||||
{
|
||||
// This process is currently limited to download a single gem at a time.
|
||||
@@ -1290,12 +1320,12 @@ namespace O3DE::ProjectManager
|
||||
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
AZStd::pair<AZStd::string, AZStd::string> pythonRunError(result.GetError(), result.GetError());
|
||||
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(AZStd::move(pythonRunError));
|
||||
IPythonBindings::ErrorPair pythonRunError(result.GetError(), result.GetError());
|
||||
return AZ::Failure<IPythonBindings::ErrorPair>(AZStd::move(pythonRunError));
|
||||
}
|
||||
else if (!downloadSucceeded)
|
||||
{
|
||||
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(GetSimpleDetailedErrorPair());
|
||||
return AZ::Failure<IPythonBindings::ErrorPair>(GetErrorPair());
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
@@ -1322,13 +1352,13 @@ namespace O3DE::ProjectManager
|
||||
return result && updateAvaliableResult;
|
||||
}
|
||||
|
||||
AZStd::pair<AZStd::string, AZStd::string> PythonBindings::GetSimpleDetailedErrorPair()
|
||||
IPythonBindings::ErrorPair PythonBindings::GetErrorPair()
|
||||
{
|
||||
AZStd::string detailedString = m_pythonErrorStrings.size() == 1
|
||||
? ""
|
||||
: AZStd::accumulate(m_pythonErrorStrings.begin(), m_pythonErrorStrings.end(), AZStd::string(""));
|
||||
|
||||
return AZStd::pair<AZStd::string, AZStd::string>(m_pythonErrorStrings.front(), detailedString);
|
||||
return IPythonBindings::ErrorPair(m_pythonErrorStrings.front(), detailedString);
|
||||
}
|
||||
|
||||
void PythonBindings::AddErrorString(AZStd::string errorString)
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// Engine
|
||||
AZ::Outcome<EngineInfo> GetEngineInfo() override;
|
||||
bool SetEngineInfo(const EngineInfo& engineInfo) override;
|
||||
AZ::Outcome<EngineInfo> GetEngineInfo(const QString& engineName) override;
|
||||
DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) override;
|
||||
|
||||
// Gem
|
||||
AZ::Outcome<GemInfo> GetGemInfo(const QString& path, const QString& projectPath = {}) override;
|
||||
@@ -62,12 +63,12 @@ namespace O3DE::ProjectManager
|
||||
// Gem Repos
|
||||
AZ::Outcome<void, AZStd::string> RefreshGemRepo(const QString& repoUri) override;
|
||||
bool RefreshAllGemRepos() override;
|
||||
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> AddGemRepo(const QString& repoUri) override;
|
||||
DetailedOutcome AddGemRepo(const QString& repoUri) override;
|
||||
bool RemoveGemRepo(const QString& repoUri) override;
|
||||
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetGemInfosForRepo(const QString& repoUri) override;
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetGemInfosForAllRepos() override;
|
||||
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> DownloadGem(
|
||||
DetailedOutcome DownloadGem(
|
||||
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force = false) override;
|
||||
void CancelDownload() override;
|
||||
bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) override;
|
||||
@@ -80,14 +81,14 @@ namespace O3DE::ProjectManager
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback);
|
||||
bool ExecuteWithLock(AZStd::function<void()> executionCallback);
|
||||
EngineInfo EngineInfoFromPath(pybind11::handle enginePath);
|
||||
GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
|
||||
GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri);
|
||||
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
|
||||
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
|
||||
AZ::Outcome<void, AZStd::string> GemRegistration(const QString& gemPath, const QString& projectPath, bool remove = false);
|
||||
bool RegisterThisEngine();
|
||||
bool StopPython();
|
||||
AZStd::pair<AZStd::string, AZStd::string> GetSimpleDetailedErrorPair();
|
||||
IPythonBindings::ErrorPair GetErrorPair();
|
||||
|
||||
|
||||
bool m_pythonStarted = false;
|
||||
@@ -96,6 +97,7 @@ namespace O3DE::ProjectManager
|
||||
AZStd::recursive_mutex m_lock;
|
||||
|
||||
pybind11::handle m_engineTemplate;
|
||||
pybind11::handle m_engineProperties;
|
||||
pybind11::handle m_cmake;
|
||||
pybind11::handle m_register;
|
||||
pybind11::handle m_manifest;
|
||||
|
||||
@@ -31,6 +31,10 @@ namespace O3DE::ProjectManager
|
||||
IPythonBindings() = default;
|
||||
virtual ~IPythonBindings() = default;
|
||||
|
||||
//! First string in pair is general error, second is detailed
|
||||
using ErrorPair = AZStd::pair<AZStd::string, AZStd::string>;
|
||||
using DetailedOutcome = AZ::Outcome<void, ErrorPair>;
|
||||
|
||||
/**
|
||||
* Get whether Python was started or not. All Python functionality will fail if Python
|
||||
* failed to start.
|
||||
@@ -49,17 +53,25 @@ namespace O3DE::ProjectManager
|
||||
// Engine
|
||||
|
||||
/**
|
||||
* Get info about the engine
|
||||
* Get info about the current engine
|
||||
* @return an outcome with EngineInfo on success
|
||||
*/
|
||||
virtual AZ::Outcome<EngineInfo> GetEngineInfo() = 0;
|
||||
|
||||
/**
|
||||
* Set info about the engine
|
||||
* @param engineInfo an EngineInfo object
|
||||
* Get info about an engine by name
|
||||
* @param engineName The name of the engine to get info about
|
||||
* @return an outcome with EngineInfo on success
|
||||
*/
|
||||
virtual bool SetEngineInfo(const EngineInfo& engineInfo) = 0;
|
||||
virtual AZ::Outcome<EngineInfo> GetEngineInfo(const QString& engineName) = 0;
|
||||
|
||||
/**
|
||||
* Set info about the engine
|
||||
* @param force True to force registration even if an engine with the same name is already registered
|
||||
* @param engineInfo an EngineInfo object
|
||||
* @return a detailed error outcome on failure.
|
||||
*/
|
||||
virtual DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) = 0;
|
||||
|
||||
// Gems
|
||||
|
||||
@@ -202,7 +214,7 @@ namespace O3DE::ProjectManager
|
||||
* @param repoUri the absolute filesystem path or url to the gem repo.
|
||||
* @return an outcome with a pair of string error and detailed messages on failure.
|
||||
*/
|
||||
virtual AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> AddGemRepo(const QString& repoUri) = 0;
|
||||
virtual DetailedOutcome AddGemRepo(const QString& repoUri) = 0;
|
||||
|
||||
/**
|
||||
* Unregisters this gem repo with the current engine.
|
||||
@@ -237,7 +249,7 @@ namespace O3DE::ProjectManager
|
||||
* @param force should we forcibly overwrite the old version of the gem.
|
||||
* @return an outcome with a pair of string error and detailed messages on failure.
|
||||
*/
|
||||
virtual AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> DownloadGem(
|
||||
virtual DetailedOutcome DownloadGem(
|
||||
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force = false) = 0;
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}",
|
||||
"Name": "AlbedoWithGenericAlpha",
|
||||
"RGB_Weight": "CIEXYZ",
|
||||
"PixelFormat": "ASTC_4x4",
|
||||
"PixelFormat": "BC3",
|
||||
"MipMapSetting": {
|
||||
"MipGenType": "Box"
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace ImageProcessingAtom
|
||||
};
|
||||
|
||||
bool IsASTCFormat(EPixelFormat fmt);
|
||||
bool IsHDRFormat(EPixelFormat fmt);
|
||||
} // namespace ImageProcessingAtom
|
||||
|
||||
namespace AZ
|
||||
|
||||
+12
-2
@@ -620,6 +620,7 @@ namespace ImageProcessingAtom
|
||||
{
|
||||
PresetName emptyPreset;
|
||||
|
||||
|
||||
//get file mask of this image file
|
||||
AZStd::string fileMask = GetFileMask(imageFilePath);
|
||||
|
||||
@@ -636,8 +637,17 @@ namespace ImageProcessingAtom
|
||||
}
|
||||
|
||||
if (outPreset == emptyPreset)
|
||||
{
|
||||
outPreset = m_defaultPreset;
|
||||
{
|
||||
auto image = IImageObjectPtr(LoadImageFromFile(imageFilePath));
|
||||
if (image->GetAlphaContent() == EAlphaContent::eAlphaContent_Absent
|
||||
|| image->GetAlphaContent() == EAlphaContent::eAlphaContent_OnlyWhite)
|
||||
{
|
||||
outPreset = m_defaultPreset;
|
||||
}
|
||||
else
|
||||
{
|
||||
outPreset = m_defaultPresetAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
return outPreset;
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace ImageProcessingAtom
|
||||
return true;
|
||||
}
|
||||
|
||||
astcenc_profile GetAstcProfile(bool isSrgb, EPixelFormat pixelFormat)
|
||||
astcenc_profile GetAstcProfile(bool isSrgb, bool isHDR)
|
||||
{
|
||||
// select profile depends on LDR or HDR, SRGB or Linear
|
||||
// ASTCENC_PRF_LDR
|
||||
@@ -86,8 +86,6 @@ namespace ImageProcessingAtom
|
||||
// ASTCENC_PRF_HDR_RGB_LDR_A
|
||||
// ASTCENC_PRF_HDR
|
||||
|
||||
auto formatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(pixelFormat);
|
||||
bool isHDR = formatInfo->eSampleType == ESampleType::eSampleType_Half || formatInfo->eSampleType == ESampleType::eSampleType_Float;
|
||||
astcenc_profile profile;
|
||||
if (isHDR)
|
||||
{
|
||||
@@ -170,7 +168,7 @@ namespace ImageProcessingAtom
|
||||
auto dstFormatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(fmtDst);
|
||||
|
||||
const float quality = GetAstcCompressQuality(compressOption->compressQuality);
|
||||
const astcenc_profile profile = GetAstcProfile(srcImage->HasImageFlags(EIF_SRGBRead), fmtSrc);
|
||||
const astcenc_profile profile = GetAstcProfile(srcImage->HasImageFlags(EIF_SRGBRead), srcImage->HasImageFlags(EIF_HDR));
|
||||
|
||||
astcenc_config config;
|
||||
astcenc_error status;
|
||||
@@ -182,10 +180,12 @@ namespace ImageProcessingAtom
|
||||
// Create a context based on the configuration
|
||||
astcenc_context* context;
|
||||
AZ::u32 blockCount = ((srcImage->GetWidth(0)+ dstFormatInfo->blockWidth-1)/dstFormatInfo->blockWidth) * ((srcImage->GetHeight(0) + dstFormatInfo->blockHeight-1)/dstFormatInfo->blockHeight);
|
||||
AZ::u32 threadCount = AZStd::min(AZStd::thread::hardware_concurrency(), blockCount);
|
||||
AZ::u32 threadCount = AZStd::min(AZStd::thread::hardware_concurrency()/2, blockCount);
|
||||
status = astcenc_context_alloc(&config, threadCount, &context);
|
||||
AZ_Assert( status == ASTCENC_SUCCESS, "ERROR: Codec context alloc failed: %s\n", astcenc_get_error_string(status));
|
||||
|
||||
AZ::Job* currentJob = AZ::JobContext::GetGlobalContext()->GetJobManager().GetCurrentJob();
|
||||
|
||||
const astcenc_type dataType =GetAstcDataType(fmtSrc);
|
||||
|
||||
// Compress the image for each mips
|
||||
@@ -209,29 +209,65 @@ namespace ImageProcessingAtom
|
||||
dstImage->GetImagePointer(mip, dstMem, dstPitch);
|
||||
AZ::u32 dataSize = dstImage->GetMipBufSize(mip);
|
||||
|
||||
// Create jobs for each compression thread
|
||||
auto completionJob = aznew AZ::JobCompletion();
|
||||
for (AZ::u32 threadIdx = 0; threadIdx < threadCount; threadIdx++)
|
||||
if (threadCount == 1)
|
||||
{
|
||||
const auto jobLambda = [&status, context, &image, &swizzle, dstMem, dataSize, threadIdx]()
|
||||
astcenc_error error = astcenc_compress_image(context, &image, &swizzle, dstMem, dataSize, 0);
|
||||
if (error != ASTCENC_SUCCESS)
|
||||
{
|
||||
status = error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::JobCompletion* completionJob = nullptr;
|
||||
if (!currentJob)
|
||||
{
|
||||
completionJob = aznew AZ::JobCompletion();
|
||||
}
|
||||
// Create jobs for each compression thread
|
||||
for (AZ::u32 threadIdx = 0; threadIdx < threadCount; threadIdx++)
|
||||
{
|
||||
const auto jobLambda = [&status, context, &image, &swizzle, dstMem, dataSize, threadIdx]()
|
||||
{
|
||||
astcenc_error error = astcenc_compress_image(context, &image, &swizzle, dstMem, dataSize, threadIdx);
|
||||
if (error != ASTCENC_SUCCESS)
|
||||
{
|
||||
status = error;
|
||||
}
|
||||
};
|
||||
|
||||
AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes
|
||||
|
||||
// adds this job as child to current job if there is a current job
|
||||
// otherwise adds it as a dependent for the complete job
|
||||
if (currentJob)
|
||||
{
|
||||
currentJob->StartAsChild(simulationJob);
|
||||
}
|
||||
else
|
||||
{
|
||||
simulationJob->SetDependent(completionJob);
|
||||
simulationJob->Start();
|
||||
}
|
||||
|
||||
astcenc_error error = astcenc_compress_image(context, &image, &swizzle, dstMem, dataSize, threadIdx);
|
||||
if (error != ASTCENC_SUCCESS)
|
||||
{
|
||||
status = error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (currentJob)
|
||||
{
|
||||
currentJob->WaitForChildren();
|
||||
}
|
||||
|
||||
AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes
|
||||
simulationJob->SetDependent(completionJob);
|
||||
simulationJob->Start();
|
||||
}
|
||||
|
||||
if (completionJob)
|
||||
{
|
||||
completionJob->StartAndWaitForCompletion();
|
||||
delete completionJob;
|
||||
completionJob = nullptr;
|
||||
if (completionJob)
|
||||
{
|
||||
completionJob->StartAndWaitForCompletion();
|
||||
delete completionJob;
|
||||
completionJob = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != ASTCENC_SUCCESS)
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace ImageProcessingAtom
|
||||
builderDescriptor.m_busId = azrtti_typeid<ImageBuilderWorker>();
|
||||
builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
builderDescriptor.m_version = 26; // [ATOM-15086]
|
||||
builderDescriptor.m_version = 27; // [ATOM-16958]
|
||||
builderDescriptor.m_analysisFingerprint = ImageProcessingAtom::BuilderSettingManager::Instance()->GetAnalysisFingerprint();
|
||||
m_imageBuilder.BusConnect(builderDescriptor.m_busId);
|
||||
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
|
||||
@@ -221,18 +221,19 @@ namespace ImageProcessingAtom
|
||||
m_isShuttingDown = true;
|
||||
}
|
||||
|
||||
PresetName GetImagePreset(const AZStd::string& filepath)
|
||||
PresetName GetImagePreset(const AZStd::string& imageFileFullPath)
|
||||
{
|
||||
// first let preset from asset info
|
||||
TextureSettings textureSettings;
|
||||
StringOutcome output = TextureSettings::LoadTextureSetting(filepath, textureSettings);
|
||||
AZStd::string settingFilePath = imageFileFullPath + TextureSettings::ExtensionName;
|
||||
TextureSettings::LoadTextureSetting(settingFilePath, textureSettings);
|
||||
|
||||
if (!textureSettings.m_preset.IsEmpty())
|
||||
{
|
||||
return textureSettings.m_preset;
|
||||
}
|
||||
|
||||
return BuilderSettingManager::Instance()->GetSuggestedPreset(filepath);
|
||||
return BuilderSettingManager::Instance()->GetSuggestedPreset(imageFileFullPath);
|
||||
}
|
||||
|
||||
void HandlePresetDependency(PresetName presetName, AZStd::vector<AssetBuilderSDK::SourceFileDependency>& sourceDependencyList)
|
||||
@@ -283,6 +284,10 @@ namespace ImageProcessingAtom
|
||||
return;
|
||||
}
|
||||
|
||||
// Full path of the image file
|
||||
AZStd::string fullPath;
|
||||
AzFramework::StringFunc::Path::Join(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, true, true);
|
||||
|
||||
// Get the extension of the file
|
||||
AZStd::string ext;
|
||||
AzFramework::StringFunc::Path::GetExtension(request.m_sourceFile.c_str(), ext, false);
|
||||
@@ -305,13 +310,12 @@ namespace ImageProcessingAtom
|
||||
// add source dependency for .assetinfo file
|
||||
AssetBuilderSDK::SourceFileDependency sourceFileDependency;
|
||||
sourceFileDependency.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute;
|
||||
sourceFileDependency.m_sourceFileDependencyPath = request.m_sourceFile;
|
||||
AZ::StringFunc::Path::ReplaceExtension(sourceFileDependency.m_sourceFileDependencyPath, TextureSettings::ExtensionName);
|
||||
sourceFileDependency.m_sourceFileDependencyPath = fullPath + TextureSettings::ExtensionName;
|
||||
response.m_sourceFileDependencyList.push_back(sourceFileDependency);
|
||||
|
||||
// add source dependencies for .preset files
|
||||
// Get the preset for this file
|
||||
auto presetName = GetImagePreset(request.m_sourceFile);
|
||||
// Get the preset for this file
|
||||
auto presetName = GetImagePreset(fullPath.c_str());
|
||||
HandlePresetDependency(presetName, response.m_sourceFileDependencyList);
|
||||
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include <ImageLoader/ImageLoaders.h>
|
||||
#include <Processing/ImageFlags.h>
|
||||
#include <Atom/ImageProcessing/ImageObject.h>
|
||||
// warning C4251: class QT_Type needs to have dll-interface to be used by clients of class 'QT_Type'
|
||||
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option")
|
||||
@@ -26,21 +27,31 @@ namespace ImageProcessingAtom
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IImageObject* loadedImage = nullptr;
|
||||
if (TIFFLoader::IsExtensionSupported(ext.toUtf8()))
|
||||
{
|
||||
return TIFFLoader::LoadImageFromTIFF(filename);
|
||||
loadedImage = TIFFLoader::LoadImageFromTIFF(filename);
|
||||
}
|
||||
else if (DdsLoader::IsExtensionSupported(ext.toUtf8()))
|
||||
{
|
||||
return DdsLoader::LoadImageFromFile(filename);
|
||||
loadedImage = DdsLoader::LoadImageFromFile(filename);
|
||||
}
|
||||
else if (QtImageLoader::IsExtensionSupported(ext.toUtf8()))
|
||||
{
|
||||
return QtImageLoader::LoadImageFromFile(filename);
|
||||
loadedImage = QtImageLoader::LoadImageFromFile(filename);
|
||||
}
|
||||
else if (ExrLoader::IsExtensionSupported(ext.toUtf8()))
|
||||
{
|
||||
return ExrLoader::LoadImageFromFile(filename);
|
||||
loadedImage = ExrLoader::LoadImageFromFile(filename);
|
||||
}
|
||||
|
||||
if (loadedImage)
|
||||
{
|
||||
if (IsHDRFormat(loadedImage->GetPixelFormat()))
|
||||
{
|
||||
loadedImage->AddImageFlags(EIF_HDR);
|
||||
}
|
||||
return loadedImage;
|
||||
}
|
||||
|
||||
AZ_Warning("ImageProcessing", false, "No proper image loader to load file: %s", filename.c_str());
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace ImageProcessingAtom
|
||||
}
|
||||
|
||||
m_image->Get()->Swizzle(swizzle.c_str());
|
||||
if (!m_input->m_presetSetting.m_discardAlpha)
|
||||
if (m_input->m_presetSetting.m_discardAlpha)
|
||||
{
|
||||
m_alphaContent = EAlphaContent::eAlphaContent_Absent;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace ImageProcessingAtom
|
||||
const static AZ::u32 EIF_Decal = 0x4; // this is usually set through the preset
|
||||
const static AZ::u32 EIF_Greyscale = 0x8; // hint for the engine (e.g. greyscale light beams can be applied to shadow mask), can be for DXT1 because compression artfacts don't count as color
|
||||
const static AZ::u32 EIF_SupressEngineReduce = 0x10; // info for the engine: don't reduce texture resolution on this texture
|
||||
const static AZ::u32 EIF_UNUSED_BIT = 0x40; // Free to use
|
||||
const static AZ::u32 EIF_HDR = 0x40; // the image contains HDR data
|
||||
const static AZ::u32 EIF_AttachedAlpha = 0x400; // deprecated: info for the engine: it's a texture with attached alpha channel
|
||||
const static AZ::u32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear)
|
||||
const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized
|
||||
|
||||
@@ -52,6 +52,24 @@ namespace ImageProcessingAtom
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsHDRFormat(EPixelFormat fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case ePixelFormat_BC6UH:
|
||||
case ePixelFormat_R9G9B9E5:
|
||||
case ePixelFormat_R32G32B32A32F:
|
||||
case ePixelFormat_R32G32F:
|
||||
case ePixelFormat_R32F:
|
||||
case ePixelFormat_R16G16B16A16F:
|
||||
case ePixelFormat_R16G16F:
|
||||
case ePixelFormat_R16F:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PixelFormatInfo::PixelFormatInfo(
|
||||
uint32_t a_bitsPerPixel,
|
||||
uint32_t a_Channels,
|
||||
|
||||
@@ -16,7 +16,9 @@ namespace AZ
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialAssignmentSerializer, AZ::SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Load(
|
||||
void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
void* outputValue,
|
||||
[[maybe_unused]] const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult;
|
||||
@@ -62,6 +64,7 @@ namespace AZ
|
||||
LoadAny<AZ::Color>(propertyValue, inputPropertyPair.value, context, result) ||
|
||||
LoadAny<AZStd::string>(propertyValue, inputPropertyPair.value, context, result) ||
|
||||
LoadAny<AZ::Data::AssetId>(propertyValue, inputPropertyPair.value, context, result) ||
|
||||
LoadAny<AZ::Data::Asset<AZ::Data::AssetData>>(propertyValue, inputPropertyPair.value, context, result) ||
|
||||
LoadAny<AZ::Data::Asset<AZ::RPI::ImageAsset>>(propertyValue, inputPropertyPair.value, context, result) ||
|
||||
LoadAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(propertyValue, inputPropertyPair.value, context, result))
|
||||
{
|
||||
@@ -78,7 +81,10 @@ namespace AZ
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Store(
|
||||
rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId,
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
const void* defaultValue,
|
||||
[[maybe_unused]] const Uuid& valueTypeId,
|
||||
JsonSerializerContext& context)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
@@ -138,9 +144,9 @@ namespace AZ
|
||||
StoreAny<AZ::Color>(propertyValue, outputPropertyValue, context, result) ||
|
||||
StoreAny<AZStd::string>(propertyValue, outputPropertyValue, context, result) ||
|
||||
StoreAny<AZ::Data::AssetId>(propertyValue, outputPropertyValue, context, result) ||
|
||||
StoreAny<AZ::Data::Asset<AZ::Data::AssetData>>(propertyValue, outputPropertyValue, context, result) ||
|
||||
StoreAny<AZ::Data::Asset<AZ::RPI::ImageAsset>>(propertyValue, outputPropertyValue, context, result) ||
|
||||
StoreAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(
|
||||
propertyValue, outputPropertyValue, context, result))
|
||||
StoreAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(propertyValue, outputPropertyValue, context, result))
|
||||
{
|
||||
outputPropertyValueContainer.AddMember(
|
||||
rapidjson::Value::StringRefType(propertyName.GetCStr()), outputPropertyValue,
|
||||
@@ -164,7 +170,9 @@ namespace AZ
|
||||
|
||||
template<typename T>
|
||||
bool JsonMaterialAssignmentSerializer::LoadAny(
|
||||
AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
|
||||
AZStd::any& propertyValue,
|
||||
const rapidjson::Value& inputPropertyValue,
|
||||
AZ::JsonDeserializerContext& context,
|
||||
AZ::JsonSerializationResult::ResultCode& result)
|
||||
{
|
||||
if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type"))
|
||||
@@ -187,7 +195,9 @@ namespace AZ
|
||||
|
||||
template<typename T>
|
||||
bool JsonMaterialAssignmentSerializer::StoreAny(
|
||||
const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
|
||||
const AZStd::any& propertyValue,
|
||||
rapidjson::Value& outputPropertyValue,
|
||||
AZ::JsonSerializerContext& context,
|
||||
AZ::JsonSerializationResult::ResultCode& result)
|
||||
{
|
||||
if (propertyValue.is<T>())
|
||||
@@ -199,7 +209,7 @@ namespace AZ
|
||||
result.Combine(StoreTypeId(typeValue, azrtti_typeid<T>(), context));
|
||||
outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator());
|
||||
|
||||
T value = AZStd::any_cast<T>(propertyValue);
|
||||
const T& value = AZStd::any_cast<T>(propertyValue);
|
||||
result.Combine(
|
||||
ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid<T>(), context));
|
||||
return true;
|
||||
|
||||
@@ -25,21 +25,31 @@ namespace AZ
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
JsonSerializationResult::Result Load(
|
||||
void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
void* outputValue,
|
||||
const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) override;
|
||||
|
||||
JsonSerializationResult::Result Store(
|
||||
rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId,
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
const void* defaultValue,
|
||||
const Uuid& valueTypeId,
|
||||
JsonSerializerContext& context) override;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
bool LoadAny(
|
||||
AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
|
||||
AZStd::any& propertyValue,
|
||||
const rapidjson::Value& inputPropertyValue,
|
||||
AZ::JsonDeserializerContext& context,
|
||||
AZ::JsonSerializationResult::ResultCode& result);
|
||||
|
||||
template<typename T>
|
||||
bool StoreAny(
|
||||
const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
|
||||
const AZStd::any& propertyValue,
|
||||
rapidjson::Value& outputPropertyValue,
|
||||
AZ::JsonSerializerContext& context,
|
||||
AZ::JsonSerializationResult::ResultCode& result);
|
||||
};
|
||||
} // namespace Render
|
||||
|
||||
@@ -204,23 +204,19 @@ namespace AZ
|
||||
{
|
||||
ShaderResourceGroup& group = static_cast<ShaderResourceGroup&>(groupBase);
|
||||
auto& device = static_cast<Device&>(GetDevice());
|
||||
group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax;
|
||||
|
||||
if (!groupData.IsAnyResourceTypeUpdated())
|
||||
{
|
||||
return RHI::ResultCode::Success;
|
||||
}
|
||||
|
||||
if (m_constantBufferSize &&
|
||||
groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask)))
|
||||
group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax;
|
||||
if (m_constantBufferSize)
|
||||
{
|
||||
memcpy(group.GetCompiledData().m_cpuConstantAddress, groupData.GetConstantData().data(), groupData.GetConstantData().size());
|
||||
}
|
||||
|
||||
if (m_viewsDescriptorTableSize &&
|
||||
groupData.IsResourceTypeEnabledForCompilation(
|
||||
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask) |
|
||||
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask)))
|
||||
if (m_viewsDescriptorTableSize)
|
||||
{
|
||||
//Lazy initialization for cbv/srv/uav Descriptor Tables
|
||||
if (!group.m_viewsDescriptorTable.IsValid())
|
||||
@@ -245,17 +241,12 @@ namespace AZ
|
||||
UpdateViewsDescriptorTable(descriptorTable, groupData);
|
||||
}
|
||||
|
||||
if (m_unboundedArrayCount &&
|
||||
groupData.IsResourceTypeEnabledForCompilation(
|
||||
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask) |
|
||||
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask)))
|
||||
if (m_unboundedArrayCount)
|
||||
{
|
||||
UpdateUnboundedArrayDescriptorTables(group, groupData);
|
||||
}
|
||||
|
||||
if (m_samplersDescriptorTableSize &&
|
||||
groupData.IsResourceTypeEnabledForCompilation(
|
||||
static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask)))
|
||||
if (m_samplersDescriptorTableSize)
|
||||
{
|
||||
const DescriptorTable descriptorTable(
|
||||
group.m_samplersDescriptorTable.GetOffset() + group.m_compiledDataIndex * m_samplersDescriptorTableSize,
|
||||
|
||||
@@ -61,10 +61,19 @@ namespace AZ
|
||||
|
||||
NSError* error = nil;
|
||||
id<MTLLibrary> lib = nil;
|
||||
|
||||
|
||||
bool loadFromByteCode = false;
|
||||
|
||||
// MacOS Big Sur (11.16.x) has issue loading some shader's byte code when GPUCapture(Metal) is on.
|
||||
// Only enable it for Monterey (12.x)
|
||||
if(@available(iOS 14.0, macOS 12.0, *))
|
||||
{
|
||||
loadFromByteCode = true;
|
||||
}
|
||||
|
||||
const uint8_t* shaderByteCode = reinterpret_cast<const uint8_t*>(shaderFunction->GetByteCode().data());
|
||||
const int byteCodeLength = shaderFunction->GetByteCode().size();
|
||||
if(byteCodeLength > 0 )
|
||||
if(byteCodeLength > 0 && loadFromByteCode)
|
||||
{
|
||||
dispatch_data_t dispatchByteCodeData = dispatch_data_create(shaderByteCode, byteCodeLength, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
|
||||
lib = [mtlDevice newLibraryWithData:dispatchByteCodeData error:&error];
|
||||
@@ -74,7 +83,7 @@ namespace AZ
|
||||
//In case byte code was not generated try to create the lib with source code
|
||||
MTLCompileOptions* compileOptions = [MTLCompileOptions alloc];
|
||||
compileOptions.fastMathEnabled = YES;
|
||||
compileOptions.languageVersion = MTLLanguageVersion2_0;
|
||||
compileOptions.languageVersion = MTLLanguageVersion2_2;
|
||||
lib = [mtlDevice newLibraryWithSource:source
|
||||
options:compileOptions
|
||||
error:&error];
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
#include <RHI/ArgumentBuffer.h>
|
||||
#include <RHI/Conversions.h>
|
||||
#include <RHI/Device.h>
|
||||
@@ -62,57 +61,48 @@ namespace AZ
|
||||
RHI::ResultCode ShaderResourceGroupPool::CompileGroupInternal(RHI::ShaderResourceGroup& groupBase, const RHI::ShaderResourceGroupData& groupData)
|
||||
{
|
||||
ShaderResourceGroup& group = static_cast<ShaderResourceGroup&>(groupBase);
|
||||
group.UpdateCompiledDataIndex();
|
||||
|
||||
if (!groupData.IsAnyResourceTypeUpdated())
|
||||
{
|
||||
return RHI::ResultCode::Success;
|
||||
}
|
||||
|
||||
group.UpdateCompiledDataIndex();
|
||||
ArgumentBuffer& argBuffer = *group.m_compiledArgBuffers[group.m_compiledDataIndex];
|
||||
argBuffer.ClearResourceTracking();
|
||||
|
||||
auto constantData = groupData.GetConstantData();
|
||||
if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask)))
|
||||
if (!constantData.empty())
|
||||
{
|
||||
argBuffer.UpdateConstantBufferViews(groupData.GetConstantData());
|
||||
}
|
||||
|
||||
const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout();
|
||||
uint32_t shaderInputIndex = 0;
|
||||
if (groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask)))
|
||||
for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages())
|
||||
{
|
||||
for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages())
|
||||
{
|
||||
const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex);
|
||||
AZStd::array_view<RHI::ConstPtr<RHI::ImageView>> imageViews = groupData.GetImageViewArray(imageInputIndex);
|
||||
argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews);
|
||||
++shaderInputIndex;
|
||||
}
|
||||
const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex);
|
||||
AZStd::array_view<RHI::ConstPtr<RHI::ImageView>> imageViews = groupData.GetImageViewArray(imageInputIndex);
|
||||
argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews);
|
||||
++shaderInputIndex;
|
||||
}
|
||||
|
||||
if (groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask)))
|
||||
shaderInputIndex = 0;
|
||||
for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers())
|
||||
{
|
||||
shaderInputIndex = 0;
|
||||
for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers())
|
||||
{
|
||||
const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex);
|
||||
AZStd::array_view<RHI::SamplerState> samplerStates = groupData.GetSamplerArray(samplerInputIndex);
|
||||
argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates);
|
||||
++shaderInputIndex;
|
||||
}
|
||||
const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex);
|
||||
AZStd::array_view<RHI::SamplerState> samplerStates = groupData.GetSamplerArray(samplerInputIndex);
|
||||
argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates);
|
||||
++shaderInputIndex;
|
||||
}
|
||||
|
||||
if (groupData.IsResourceTypeEnabledForCompilation(static_cast<uint32_t>(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask)))
|
||||
shaderInputIndex = 0;
|
||||
for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers())
|
||||
{
|
||||
shaderInputIndex = 0;
|
||||
for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers())
|
||||
{
|
||||
const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex);
|
||||
AZStd::array_view<RHI::ConstPtr<RHI::BufferView>> bufferViews = groupData.GetBufferViewArray(bufferInputIndex);
|
||||
argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews);
|
||||
++shaderInputIndex;
|
||||
}
|
||||
const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex);
|
||||
AZStd::array_view<RHI::ConstPtr<RHI::BufferView>> bufferViews = groupData.GetBufferViewArray(bufferInputIndex);
|
||||
argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews);
|
||||
++shaderInputIndex;
|
||||
}
|
||||
|
||||
return RHI::ResultCode::Success;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/std/parallel/lock.h>
|
||||
#include <RHI/Buffer.h>
|
||||
#include <RHI/BufferView.h>
|
||||
@@ -688,8 +689,8 @@ namespace AZ
|
||||
if (interval != InvalidInterval)
|
||||
{
|
||||
uint32_t numBuffers = interval.m_max - interval.m_min + 1;
|
||||
AZStd::vector<VkBuffer> nativeBuffers(numBuffers, VK_NULL_HANDLE);
|
||||
AZStd::vector<VkDeviceSize> offsets(numBuffers, 0);
|
||||
AZStd::fixed_vector<VkBuffer, RHI::Limits::Pipeline::StreamCountMax> nativeBuffers(numBuffers, VK_NULL_HANDLE);
|
||||
AZStd::fixed_vector<VkDeviceSize, RHI::Limits::Pipeline::StreamCountMax> offsets(numBuffers, 0);
|
||||
for (uint32_t i = 0; i < numBuffers; ++i)
|
||||
{
|
||||
const RHI::StreamBufferView& bufferView = streams[i + interval.m_min];
|
||||
|
||||
@@ -104,13 +104,13 @@ namespace AZ
|
||||
RHI::ResultCode ShaderResourceGroupPool::CompileGroupInternal(RHI::ShaderResourceGroup& groupBase, const RHI::ShaderResourceGroupData& groupData)
|
||||
{
|
||||
auto& group = static_cast<ShaderResourceGroup&>(groupBase);
|
||||
group.UpdateCompiledDataIndex(m_currentIteration);
|
||||
|
||||
if (!groupData.IsAnyResourceTypeUpdated())
|
||||
{
|
||||
return RHI::ResultCode::Success;
|
||||
}
|
||||
|
||||
group.UpdateCompiledDataIndex(m_currentIteration);
|
||||
DescriptorSet& descriptorSet = *group.m_compiledData[group.GetCompileDataIndex()];
|
||||
|
||||
const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout();
|
||||
|
||||
@@ -33,11 +33,13 @@ namespace AtomToolsFramework
|
||||
{
|
||||
if (value.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
|
||||
{
|
||||
const AZ::Data::Asset<AZ::RPI::ImageAsset>& imageAsset = value.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
|
||||
return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(
|
||||
imageAsset.GetId(),
|
||||
azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
|
||||
imageAsset.GetHint()));
|
||||
const auto& imageAsset = value.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
|
||||
return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(imageAsset.GetId(), azrtti_typeid<AZ::RPI::StreamingImageAsset>(), imageAsset.GetHint()));
|
||||
}
|
||||
else if (value.Is<AZ::Data::Instance<AZ::RPI::Image>>())
|
||||
{
|
||||
const auto& image = value.GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
|
||||
return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(image->GetAssetId(), azrtti_typeid<AZ::RPI::StreamingImageAsset>()));
|
||||
}
|
||||
|
||||
return AZ::RPI::MaterialPropertyValue::ToAny(value);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Sample Gems, Block source folders
|
||||
// ------------------------------------------------------------------------------
|
||||
"Exclude Work In Progress Folders": {
|
||||
"pattern": ".*\\\\/.[Ss]rc\\\\/.*"
|
||||
"pattern": "(^|.+/).[Ss]rc(/.*)?$"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1362,8 +1362,9 @@ namespace AZ::AtomBridge
|
||||
// if 2d draw need to project pos to screen first
|
||||
AzFramework::TextDrawParameters params;
|
||||
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
|
||||
const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor();
|
||||
params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works
|
||||
params.m_position = AZ::Vector3(x, y, 1.0f);
|
||||
params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f);
|
||||
params.m_color = m_rendState.m_color;
|
||||
params.m_scale = AZ::Vector2(size);
|
||||
params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment
|
||||
|
||||
+33
@@ -104,6 +104,7 @@ namespace AZ
|
||||
MaterialComponentController::MaterialComponentController(const MaterialComponentConfig& config)
|
||||
: m_configuration(config)
|
||||
{
|
||||
ConvertAssetsForSerialization();
|
||||
}
|
||||
|
||||
void MaterialComponentController::Activate(EntityId entityId)
|
||||
@@ -135,6 +136,7 @@ namespace AZ
|
||||
void MaterialComponentController::SetConfiguration(const MaterialComponentConfig& config)
|
||||
{
|
||||
m_configuration = config;
|
||||
ConvertAssetsForSerialization();
|
||||
}
|
||||
|
||||
const MaterialComponentConfig& MaterialComponentController::GetConfiguration() const
|
||||
@@ -338,6 +340,7 @@ namespace AZ
|
||||
// before LoadMaterials() is called [LYN-2249]
|
||||
auto temp = m_configuration.m_materials;
|
||||
m_configuration.m_materials = materials;
|
||||
ConvertAssetsForSerialization();
|
||||
LoadMaterials();
|
||||
}
|
||||
|
||||
@@ -489,6 +492,7 @@ namespace AZ
|
||||
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
|
||||
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
|
||||
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
|
||||
ConvertAssetsForSerialization();
|
||||
|
||||
if (materialAssignment.RequiresLoading())
|
||||
{
|
||||
@@ -586,6 +590,7 @@ namespace AZ
|
||||
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
|
||||
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
|
||||
materialAssignment.m_propertyOverrides = propertyOverrides;
|
||||
ConvertAssetsForSerialization();
|
||||
|
||||
if (materialAssignment.RequiresLoading())
|
||||
{
|
||||
@@ -667,5 +672,33 @@ namespace AZ
|
||||
TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialComponentController::ConvertAssetsForSerialization()
|
||||
{
|
||||
for (auto& materialAssignmentPair : m_configuration.m_materials)
|
||||
{
|
||||
MaterialAssignment& materialAssignment = materialAssignmentPair.second;
|
||||
for (auto& propertyPair : materialAssignment.m_propertyOverrides)
|
||||
{
|
||||
auto& value = propertyPair.second;
|
||||
if (value.is<AZ::Data::Asset<AZ::Data::AssetData>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Asset<AZ::Data::AssetData>>(value).GetId();
|
||||
}
|
||||
else if (value.is<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(value).GetId();
|
||||
}
|
||||
else if (value.is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::ImageAsset>>(value).GetId();
|
||||
}
|
||||
else if (value.is<AZ::Data::Instance<AZ::RPI::Image>>())
|
||||
{
|
||||
value = AZStd::any_cast<AZ::Data::Instance<AZ::RPI::Image>>(value)->GetAssetId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+5
@@ -99,6 +99,11 @@ namespace AZ
|
||||
//! Queue material instance recreation notifiucations until tick
|
||||
void QueueMaterialUpdateNotification();
|
||||
|
||||
//! Converts property overrides storing image asset references into asset IDs. This addresses a problem where image property
|
||||
//! overrides are lost during prefab serialization and patching. This suboptimal function will be removed once the underlying
|
||||
//! problem is resolved.
|
||||
void ConvertAssetsForSerialization();
|
||||
|
||||
EntityId m_entityId;
|
||||
MaterialComponentConfig m_configuration;
|
||||
AZStd::unordered_set<MaterialAssignmentId> m_materialsWithDirtyProperties;
|
||||
|
||||
+11
-1
@@ -11,6 +11,9 @@
|
||||
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <Atom/RPI.Public/ViewportContextManager.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -199,7 +202,14 @@ namespace AZ
|
||||
}
|
||||
|
||||
const char* LutAttachment = "LutOutput";
|
||||
const AZStd::vector<AZStd::string> LutGenerationPassHierarchy{ "LutGenerationPass" };
|
||||
auto renderPipelineName = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get()
|
||||
->GetDefaultViewportContext()
|
||||
->GetCurrentPipeline()
|
||||
->GetId();
|
||||
const AZStd::vector<AZStd::string> LutGenerationPassHierarchy{
|
||||
renderPipelineName.GetCStr(),
|
||||
"LutGenerationPass"
|
||||
};
|
||||
|
||||
char resolvedOutputFilePath[AZ_MAX_PATH_LEN] = { 0 };
|
||||
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(m_currentTiffFilePath.c_str(), resolvedOutputFilePath, AZ_MAX_PATH_LEN);
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
"AssetProcessor": {
|
||||
"Settings": {
|
||||
"Exclude AudioProject": {
|
||||
"pattern": ".*\\\\/Sounds\\\\/.+_project.*"
|
||||
"pattern": "(^|.+/)Sounds/.+_project.*"
|
||||
},
|
||||
"Exclude AudioTemp": {
|
||||
"pattern": ".*\\\\/Sounds\\\\/.+\\\\.(txt|xml|dat)"
|
||||
"pattern": "(^|.+/)Sounds/.+\\\\.(txt|xml|dat)"
|
||||
},
|
||||
"RC audio": {
|
||||
"pattern": ".*\\\\.(wav|pcm)",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"RC blastmaterial": {
|
||||
"glob": "*.blastmaterial",
|
||||
"params": "copy",
|
||||
"critical": true,
|
||||
"productAssetType": "{55F38C86-0767-4E7F-830A-A4BF624BE4DA}"
|
||||
},
|
||||
"RC blastconfiguration": {
|
||||
|
||||
+26
-18
@@ -91,17 +91,19 @@ namespace GraphCanvas
|
||||
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetTitle(const AZStd::string& title)
|
||||
void GeneralNodeTitleComponent::SetDetails(const AZStd::string& title, const AZStd::string& subtitle)
|
||||
{
|
||||
m_title.SetFallback(title);
|
||||
m_title = title;
|
||||
m_subTitle = subtitle;
|
||||
|
||||
if (m_generalNodeTitleWidget)
|
||||
{
|
||||
m_generalNodeTitleWidget->SetTitle(title);
|
||||
m_generalNodeTitleWidget->SetDetails(title, subtitle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetTranslationKeyedTitle(const TranslationKeyedString& title)
|
||||
void GeneralNodeTitleComponent::SetTitle(const AZStd::string& title)
|
||||
{
|
||||
m_title = title;
|
||||
|
||||
@@ -113,20 +115,10 @@ namespace GraphCanvas
|
||||
|
||||
AZStd::string GeneralNodeTitleComponent::GetTitle() const
|
||||
{
|
||||
return m_title.GetDisplayString();
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetSubTitle(const AZStd::string& subtitle)
|
||||
{
|
||||
m_subTitle.SetFallback(subtitle);
|
||||
|
||||
if (m_generalNodeTitleWidget)
|
||||
{
|
||||
m_generalNodeTitleWidget->SetSubTitle(subtitle);
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralNodeTitleComponent::SetTranslationKeyedSubTitle(const TranslationKeyedString& subtitle)
|
||||
{
|
||||
m_subTitle = subtitle;
|
||||
|
||||
@@ -138,7 +130,7 @@ namespace GraphCanvas
|
||||
|
||||
AZStd::string GeneralNodeTitleComponent::GetSubTitle() const
|
||||
{
|
||||
return m_subTitle.GetDisplayString();
|
||||
return m_subTitle;
|
||||
}
|
||||
|
||||
QGraphicsWidget* GeneralNodeTitleComponent::GetGraphicsWidget()
|
||||
@@ -270,7 +262,23 @@ namespace GraphCanvas
|
||||
SceneNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void GeneralNodeTitleGraphicsWidget::SetTitle(const TranslationKeyedString& title)
|
||||
void GeneralNodeTitleGraphicsWidget::SetDetails(const AZStd::string& title, const AZStd::string& subtitle)
|
||||
{
|
||||
bool updateLayout = false;
|
||||
if (m_titleWidget)
|
||||
{
|
||||
m_titleWidget->SetLabel(title);
|
||||
updateLayout = true;
|
||||
}
|
||||
|
||||
if (m_subTitleWidget)
|
||||
{
|
||||
m_subTitleWidget->SetLabel(subtitle);
|
||||
updateLayout = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralNodeTitleGraphicsWidget::SetTitle(const AZStd::string& title)
|
||||
{
|
||||
if (m_titleWidget)
|
||||
{
|
||||
@@ -279,7 +287,7 @@ namespace GraphCanvas
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralNodeTitleGraphicsWidget::SetSubTitle(const TranslationKeyedString& subtitle)
|
||||
void GeneralNodeTitleGraphicsWidget::SetSubTitle(const AZStd::string& subtitle)
|
||||
{
|
||||
if (m_subTitleWidget)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <GraphCanvas/Components/StyleBus.h>
|
||||
#include <GraphCanvas/Components/VisualBus.h>
|
||||
#include <GraphCanvas/Types/EntitySaveData.h>
|
||||
#include <GraphCanvas/Types/TranslationTypes.h>
|
||||
#include <Widgets/GraphCanvasLabel.h>
|
||||
|
||||
namespace GraphCanvas
|
||||
@@ -68,12 +67,11 @@ namespace GraphCanvas
|
||||
////
|
||||
|
||||
// NodeTitleRequestBus
|
||||
void SetDetails(const AZStd::string& title, const AZStd::string& subtitle) override;
|
||||
void SetTitle(const AZStd::string& title) override;
|
||||
void SetTranslationKeyedTitle(const TranslationKeyedString& title) override;
|
||||
AZStd::string GetTitle() const override;
|
||||
|
||||
void SetSubTitle(const AZStd::string& subtitle) override;
|
||||
void SetTranslationKeyedSubTitle(const TranslationKeyedString& subtitle) override;
|
||||
AZStd::string GetSubTitle() const override;
|
||||
|
||||
QGraphicsWidget* GetGraphicsWidget() override;
|
||||
@@ -96,8 +94,8 @@ namespace GraphCanvas
|
||||
private:
|
||||
GeneralNodeTitleComponent(const GeneralNodeTitleComponent&) = delete;
|
||||
|
||||
TranslationKeyedString m_title;
|
||||
TranslationKeyedString m_subTitle;
|
||||
AZStd::string m_title;
|
||||
AZStd::string m_subTitle;
|
||||
|
||||
AZStd::string m_basePalette;
|
||||
|
||||
@@ -123,9 +121,10 @@ namespace GraphCanvas
|
||||
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
|
||||
void SetTitle(const TranslationKeyedString& title);
|
||||
void SetSubTitle(const TranslationKeyedString& subtitle);
|
||||
|
||||
void SetDetails(const AZStd::string& title, const AZStd::string& subtitle);
|
||||
void SetTitle(const AZStd::string& title);
|
||||
void SetSubTitle(const AZStd::string& subtitle);
|
||||
|
||||
void SetPaletteOverride(AZStd::string_view paletteOverride);
|
||||
void SetPaletteOverride(const AZ::Uuid& uuid);
|
||||
|
||||
@@ -1007,20 +1007,16 @@ namespace GraphCanvas
|
||||
{
|
||||
if (!configuration.m_name.empty())
|
||||
{
|
||||
cloneConfiguration->m_name.Clear();
|
||||
cloneConfiguration->m_name.SetFallback(configuration.m_name);
|
||||
cloneConfiguration->m_name = configuration.m_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::string nodeTitle;
|
||||
NodeTitleRequestBus::EventResult(nodeTitle, configuration.m_targetEndpoint.GetNodeId(), &NodeTitleRequests::GetTitle);
|
||||
|
||||
AZStd::string displayName = AZStd::string::format("%s:%s", nodeTitle.c_str(), cloneConfiguration->m_name.GetDisplayString().c_str());
|
||||
AZStd::string displayName = AZStd::string::format("%s:%s", nodeTitle.c_str(), cloneConfiguration->m_name.c_str());
|
||||
|
||||
// Gain some context. Lost the ability to refresh the strings.
|
||||
// Should be fixable once we get an actual use case for this setup.
|
||||
cloneConfiguration->m_name.Clear();
|
||||
cloneConfiguration->m_name.SetFallback(displayName);
|
||||
cloneConfiguration->m_name = displayName;
|
||||
}
|
||||
|
||||
AZ::Entity* slotEntity = nullptr;
|
||||
|
||||
@@ -315,12 +315,6 @@ namespace GraphCanvas
|
||||
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
|
||||
}
|
||||
|
||||
void NodeComponent::SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip)
|
||||
{
|
||||
m_configuration.SetTooltip(tooltip.GetDisplayString());
|
||||
NodeNotificationBus::Event(GetEntityId(), &NodeNotifications::OnTooltipChanged, m_configuration.GetTooltip());
|
||||
}
|
||||
|
||||
void NodeComponent::AddSlot(const AZ::EntityId& slotId)
|
||||
{
|
||||
AZ_Assert(slotId.IsValid(), "Slot entity (ID: %s) is not valid!", slotId.ToString().data());
|
||||
|
||||
@@ -106,7 +106,6 @@ namespace GraphCanvas
|
||||
|
||||
// NodeRequestBus
|
||||
void SetTooltip(const AZStd::string& tooltip) override;
|
||||
void SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip) override;
|
||||
const AZStd::string GetTooltip() const override { return m_configuration.GetTooltip(); }
|
||||
|
||||
void SetShowInOutliner(bool showInOutliner) override { m_configuration.SetShowInOutliner(showInOutliner); }
|
||||
|
||||
@@ -669,6 +669,7 @@ namespace GraphCanvas
|
||||
{
|
||||
GeometryNotificationBus::Handler::BusDisconnect();
|
||||
SceneNotificationBus::Handler::BusDisconnect();
|
||||
AZ::SystemTickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void GestureSceneHelper::TrackElement(const AZ::EntityId& elementId)
|
||||
|
||||
@@ -337,12 +337,9 @@ namespace GraphCanvas
|
||||
{
|
||||
m_connectionType = slotRequests->GetConnectionType();
|
||||
|
||||
TranslationKeyedString slotName = slotRequests->GetTranslationKeyedName();
|
||||
m_slotText->SetLabel(slotRequests->GetName());
|
||||
|
||||
m_slotText->SetLabel(slotName);
|
||||
|
||||
TranslationKeyedString toolTip = slotRequests->GetTranslationKeyedTooltip();
|
||||
OnTooltipChanged(toolTip);
|
||||
OnTooltipChanged(slotRequests->GetTooltip());
|
||||
|
||||
const SlotConfiguration& configuration = slotRequests->GetSlotConfiguration();
|
||||
|
||||
@@ -393,12 +390,12 @@ namespace GraphCanvas
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void DataSlotLayout::OnNameChanged(const TranslationKeyedString& name)
|
||||
void DataSlotLayout::OnNameChanged(const AZStd::string& name)
|
||||
{
|
||||
m_slotText->SetLabel(name);
|
||||
}
|
||||
|
||||
void DataSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void DataSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
AZ::Uuid dataType;
|
||||
DataSlotRequestBus::EventResult(dataType, m_owner.GetEntityId(), &DataSlotRequests::GetDataTypeId);
|
||||
@@ -406,7 +403,7 @@ namespace GraphCanvas
|
||||
AZStd::string typeString;
|
||||
GraphModelRequestBus::EventResult(typeString, GetSceneId(), &GraphModelRequests::GetDataTypeString, dataType);
|
||||
|
||||
AZStd::string displayText = tooltip.GetDisplayString();
|
||||
AZStd::string displayText = tooltip;
|
||||
|
||||
if (!typeString.empty())
|
||||
{
|
||||
@@ -486,7 +483,7 @@ namespace GraphCanvas
|
||||
if (!iconPath.empty())
|
||||
{
|
||||
m_textDecoration = new GraphCanvasLabel();
|
||||
m_textDecoration->SetLabel(iconPath, "", "");
|
||||
m_textDecoration->SetLabel(iconPath);
|
||||
m_textDecoration->setToolTip(toolTip.c_str());
|
||||
|
||||
ApplyTextStyle(m_textDecoration);
|
||||
|
||||
@@ -120,8 +120,8 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnNameChanged(const TranslationKeyedString&) override;
|
||||
void OnTooltipChanged(const TranslationKeyedString&) override;
|
||||
void OnNameChanged(const AZStd::string&) override;
|
||||
void OnTooltipChanged(const AZStd::string&) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
+7
-14
@@ -58,13 +58,8 @@ namespace GraphCanvas
|
||||
{
|
||||
m_connectionType = slotRequests->GetConnectionType();
|
||||
|
||||
TranslationKeyedString slotName = slotRequests->GetTranslationKeyedName();
|
||||
|
||||
m_slotText->SetLabel(slotName);
|
||||
|
||||
TranslationKeyedString toolTip = slotRequests->GetTranslationKeyedTooltip();
|
||||
|
||||
OnTooltipChanged(toolTip);
|
||||
m_slotText->SetLabel(slotRequests->GetName());
|
||||
OnTooltipChanged(slotRequests->GetTooltip());
|
||||
|
||||
const SlotConfiguration& configuration = slotRequests->GetSlotConfiguration();
|
||||
|
||||
@@ -88,17 +83,15 @@ namespace GraphCanvas
|
||||
OnStyleChanged();
|
||||
}
|
||||
|
||||
void ExecutionSlotLayout::OnNameChanged(const TranslationKeyedString& name)
|
||||
void ExecutionSlotLayout::OnNameChanged(const AZStd::string& name)
|
||||
{
|
||||
m_slotText->SetLabel(name);
|
||||
}
|
||||
|
||||
void ExecutionSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void ExecutionSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
AZStd::string displayText = tooltip.GetDisplayString();
|
||||
|
||||
m_slotConnectionPin->setToolTip(displayText.c_str());
|
||||
m_slotText->setToolTip(displayText.c_str());
|
||||
m_slotConnectionPin->setToolTip(tooltip.c_str());
|
||||
m_slotText->setToolTip(tooltip.c_str());
|
||||
}
|
||||
|
||||
void ExecutionSlotLayout::OnStyleChanged()
|
||||
@@ -132,7 +125,7 @@ namespace GraphCanvas
|
||||
if (!textDecoration.empty())
|
||||
{
|
||||
m_textDecoration = new GraphCanvasLabel();
|
||||
m_textDecoration->SetLabel(textDecoration, "", "");
|
||||
m_textDecoration->SetLabel(textDecoration);
|
||||
m_textDecoration->setToolTip(toolTip.c_str());
|
||||
|
||||
ApplyTextStyle(m_textDecoration);
|
||||
|
||||
+2
-2
@@ -46,8 +46,8 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnNameChanged(const TranslationKeyedString& name) override;
|
||||
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
|
||||
void OnNameChanged(const AZStd::string& name) override;
|
||||
void OnTooltipChanged(const AZStd::string& tooltip) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
+8
-10
@@ -119,13 +119,13 @@ namespace GraphCanvas
|
||||
{
|
||||
SlotRequestBus::EventResult(m_connectionType, m_owner.GetEntityId(), &SlotRequests::GetConnectionType);
|
||||
|
||||
TranslationKeyedString slotName;
|
||||
SlotRequestBus::EventResult(slotName, m_owner.GetEntityId(), &SlotRequests::GetTranslationKeyedName);
|
||||
AZStd::string slotName;
|
||||
SlotRequestBus::EventResult(slotName, m_owner.GetEntityId(), &SlotRequests::GetName);
|
||||
|
||||
m_slotText->SetLabel(slotName);
|
||||
|
||||
TranslationKeyedString toolTip;
|
||||
SlotRequestBus::EventResult(toolTip, m_owner.GetEntityId(), &SlotRequests::GetTranslationKeyedTooltip);
|
||||
AZStd::string toolTip;
|
||||
SlotRequestBus::EventResult(toolTip, m_owner.GetEntityId(), &SlotRequests::GetTooltip);
|
||||
|
||||
OnTooltipChanged(toolTip);
|
||||
|
||||
@@ -151,17 +151,15 @@ namespace GraphCanvas
|
||||
OnStyleChanged();
|
||||
}
|
||||
|
||||
void ExtenderSlotLayout::OnNameChanged(const TranslationKeyedString& name)
|
||||
void ExtenderSlotLayout::OnNameChanged(const AZStd::string& name)
|
||||
{
|
||||
m_slotText->SetLabel(name);
|
||||
}
|
||||
|
||||
void ExtenderSlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void ExtenderSlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
AZStd::string displayText = tooltip.GetDisplayString();
|
||||
|
||||
m_slotConnectionPin->setToolTip(displayText.c_str());
|
||||
m_slotText->setToolTip(displayText.c_str());
|
||||
m_slotConnectionPin->setToolTip(tooltip.c_str());
|
||||
m_slotText->setToolTip(tooltip.c_str());
|
||||
}
|
||||
|
||||
void ExtenderSlotLayout::OnStyleChanged()
|
||||
|
||||
+2
-2
@@ -48,8 +48,8 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnNameChanged(const TranslationKeyedString& name) override;
|
||||
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
|
||||
void OnNameChanged(const AZStd::string& name) override;
|
||||
void OnTooltipChanged(const AZStd::string& tooltip) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
+3
-3
@@ -90,10 +90,10 @@ namespace GraphCanvas
|
||||
TryAndSetupSlot();
|
||||
}
|
||||
|
||||
void PropertySlotLayout::OnTooltipChanged(const TranslationKeyedString& tooltip)
|
||||
void PropertySlotLayout::OnTooltipChanged(const AZStd::string& tooltip)
|
||||
{
|
||||
m_slotText->setToolTip(Tools::qStringFromUtf8(tooltip.GetDisplayString()));
|
||||
m_nodePropertyDisplay->setToolTip(Tools::qStringFromUtf8(tooltip.GetDisplayString()));
|
||||
m_slotText->setToolTip(Tools::qStringFromUtf8(tooltip));
|
||||
m_nodePropertyDisplay->setToolTip(Tools::qStringFromUtf8(tooltip));
|
||||
}
|
||||
|
||||
void PropertySlotLayout::OnStyleChanged()
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ namespace GraphCanvas
|
||||
// SlotNotificationBus
|
||||
void OnRegisteredToNode(const AZ::EntityId& nodeId) override;
|
||||
|
||||
void OnTooltipChanged(const TranslationKeyedString& tooltip) override;
|
||||
void OnTooltipChanged(const AZStd::string& tooltip) override;
|
||||
////
|
||||
|
||||
// StyleNotificationBus
|
||||
|
||||
@@ -91,14 +91,6 @@ namespace GraphCanvas
|
||||
|
||||
void SlotComponent::Activate()
|
||||
{
|
||||
SetTranslationKeyedName(m_slotConfiguration.m_name);
|
||||
|
||||
// Default tooltip.
|
||||
if (m_slotConfiguration.m_tooltip.empty())
|
||||
{
|
||||
SetTranslationKeyedTooltip(m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
SlotRequestBus::Handler::BusConnect(GetEntityId());
|
||||
SceneMemberRequestBus::Handler::BusConnect(GetEntityId());
|
||||
}
|
||||
@@ -171,24 +163,6 @@ namespace GraphCanvas
|
||||
}
|
||||
|
||||
void SlotComponent::SetName(const AZStd::string& name)
|
||||
{
|
||||
if (name == m_slotConfiguration.m_name.GetDisplayString())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_slotConfiguration.m_name.SetFallback(name);
|
||||
|
||||
// Default tooltip.
|
||||
if (m_slotConfiguration.m_tooltip.empty())
|
||||
{
|
||||
m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
|
||||
}
|
||||
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
void SlotComponent::SetTranslationKeyedName(const TranslationKeyedString& name)
|
||||
{
|
||||
if (name == m_slotConfiguration.m_name)
|
||||
{
|
||||
@@ -206,25 +180,22 @@ namespace GraphCanvas
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
void SlotComponent::SetTooltip(const AZStd::string& tooltip)
|
||||
void SlotComponent::SetDetails(const AZStd::string& name, const AZStd::string& tooltip)
|
||||
{
|
||||
if (tooltip == m_slotConfiguration.m_tooltip.GetDisplayString())
|
||||
if (name != m_slotConfiguration.m_name)
|
||||
{
|
||||
return;
|
||||
m_slotConfiguration.m_name = name;
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
|
||||
}
|
||||
|
||||
m_slotConfiguration.m_tooltip.SetFallback(tooltip);
|
||||
|
||||
// Default tooltip.
|
||||
if (m_slotConfiguration.m_tooltip.empty())
|
||||
if (tooltip != m_slotConfiguration.m_tooltip)
|
||||
{
|
||||
m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
|
||||
m_slotConfiguration.m_tooltip = tooltip;
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
|
||||
}
|
||||
|
||||
SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
|
||||
}
|
||||
|
||||
void SlotComponent::SetTranslationKeyedTooltip(const TranslationKeyedString& tooltip)
|
||||
void SlotComponent::SetTooltip(const AZStd::string& tooltip)
|
||||
{
|
||||
if (tooltip == m_slotConfiguration.m_tooltip)
|
||||
{
|
||||
@@ -521,8 +492,8 @@ namespace GraphCanvas
|
||||
{
|
||||
slotConfiguration.m_connectionType = GetConnectionType();
|
||||
|
||||
slotConfiguration.m_name = GetTranslationKeyedName();
|
||||
slotConfiguration.m_tooltip = GetTranslationKeyedTooltip();
|
||||
slotConfiguration.m_name = m_slotConfiguration.m_name;
|
||||
slotConfiguration.m_tooltip = m_slotConfiguration.m_tooltip;
|
||||
|
||||
slotConfiguration.m_slotGroup = GetSlotGroup();
|
||||
}
|
||||
|
||||
@@ -74,18 +74,14 @@ namespace GraphCanvas
|
||||
|
||||
Endpoint GetEndpoint() const override;
|
||||
|
||||
const AZStd::string GetName() const override { return m_slotConfiguration.m_name.GetDisplayString(); }
|
||||
const AZStd::string GetName() const override { return m_slotConfiguration.m_name; }
|
||||
void SetName(const AZStd::string& name) override;
|
||||
|
||||
TranslationKeyedString GetTranslationKeyedName() const override { return m_slotConfiguration.m_name; }
|
||||
void SetTranslationKeyedName(const TranslationKeyedString&) override;
|
||||
void SetDetails(const AZStd::string& name, const AZStd::string& tooltip) override;
|
||||
|
||||
const AZStd::string GetTooltip() const override { return m_slotConfiguration.m_tooltip.GetDisplayString(); }
|
||||
const AZStd::string GetTooltip() const override { return m_slotConfiguration.m_tooltip; }
|
||||
void SetTooltip(const AZStd::string& tooltip) override;
|
||||
|
||||
TranslationKeyedString GetTranslationKeyedTooltip() const override { return m_slotConfiguration.m_tooltip; }
|
||||
void SetTranslationKeyedTooltip(const TranslationKeyedString&) override;
|
||||
|
||||
void DisplayProposedConnection(const AZ::EntityId& connectionId, const Endpoint& endpoint) override;
|
||||
void RemoveProposedConnection(const AZ::EntityId& connectionId, const Endpoint& endpoint) override;
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
#include <GraphCanvas/Types/ConstructPresets.h>
|
||||
#include <GraphCanvas/Types/EntitySaveData.h>
|
||||
#include <GraphCanvas/Types/TranslationTypes.h>
|
||||
|
||||
#include <GraphCanvas/Widgets/GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h>
|
||||
#include <GraphCanvas/Widgets/GraphCanvasMimeEvent.h>
|
||||
@@ -140,7 +139,6 @@ namespace GraphCanvas
|
||||
Styling::DefaultSelector::Reflect(serializeContext);
|
||||
Styling::CompoundSelector::Reflect(serializeContext);
|
||||
Styling::NestedSelector::Reflect(serializeContext);
|
||||
TranslationKeyedString::Reflect(serializeContext);
|
||||
Styling::Style::Reflect(serializeContext);
|
||||
AssetEditorUserSettings::Reflect(serializeContext);
|
||||
}
|
||||
@@ -218,6 +216,9 @@ namespace GraphCanvas
|
||||
|
||||
AzToolsFramework::ToolsAssetSystemBus::Broadcast(&AzToolsFramework::ToolsAssetSystemRequests::RegisterSourceAssetType, azrtti_typeid<TranslationAsset>(), TranslationAsset::GetFileFilter());
|
||||
m_translationAssetWorker.Activate();
|
||||
|
||||
m_assetHandler = AZStd::make_unique<TranslationAssetHandler>();
|
||||
m_assetHandler->Register();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,15 +377,27 @@ namespace GraphCanvas
|
||||
// Find any TranslationAsset files that may have translation database key/values
|
||||
AZ::Data::AssetCatalogRequests::AssetEnumerationCB collectAssetsCb = [this](const AZ::Data::AssetId assetId, const AZ::Data::AssetInfo& assetInfo)
|
||||
{
|
||||
const auto assetType = azrtti_typeid<TranslationAsset>();
|
||||
if (assetInfo.m_assetType == assetType)
|
||||
if (AZ::StringFunc::EndsWith(assetInfo.m_relativePath, ".names", false))
|
||||
{
|
||||
m_translationAssets.push_back(assetId);
|
||||
}
|
||||
};
|
||||
|
||||
m_translationAssets.clear();
|
||||
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, collectAssetsCb, postEnumerateCb);
|
||||
}
|
||||
|
||||
void GraphCanvasSystemComponent::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId);
|
||||
if (assetInfo.m_assetType == azrtti_typeid<TranslationAsset>())
|
||||
{
|
||||
GraphCanvas::TranslationRequestBus::Broadcast(&GraphCanvas::TranslationRequests::Restore);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphCanvasSystemComponent::UnregisterAssetHandler()
|
||||
{
|
||||
if (m_assetHandler)
|
||||
@@ -405,7 +418,7 @@ namespace GraphCanvas
|
||||
for (const AZ::Data::AssetId& assetId : m_translationAssets)
|
||||
{
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(assetId);
|
||||
AZ::Data::AssetManager::Instance().GetAsset<TranslationAsset>(assetId, AZ::Data::AssetLoadBehavior::Default);
|
||||
AZ::Data::AssetManager::Instance().GetAsset<TranslationAsset>(assetId, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,10 @@ namespace GraphCanvas
|
||||
AZ::EntityId CreateVirtualChild(const AZ::EntityId& real, const AZStd::string& virtualChildElement) const override;
|
||||
////
|
||||
|
||||
// AzFramework::AssetCatalogEventBus::Handler
|
||||
void OnCatalogLoaded(const char* /*catalogFile*/) override;
|
||||
void OnCatalogAssetChanged(const AZ::Data::AssetId&) override;
|
||||
////
|
||||
|
||||
AZStd::unique_ptr<TranslationAssetHandler> m_assetHandler;
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace GraphCanvas
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str());
|
||||
AZ_Warning("TranslationAsset", false, "Serialization of the TranslationFormat failed for: %s", asset.GetHint().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,14 +59,14 @@ namespace GraphCanvas
|
||||
//!
|
||||
//! Requirements:
|
||||
//! - Must have a top level array called "entries"
|
||||
//! - Must provide a "key" element for any entry added
|
||||
//! - Must provide a "base" element for any entry added
|
||||
//!
|
||||
//! Example:
|
||||
//!
|
||||
//! {
|
||||
//! "entries": [
|
||||
//! {
|
||||
//! "key": "Globals",
|
||||
//! "base": "Globals",
|
||||
//! "details": {
|
||||
//! "name": "My Name",
|
||||
//! "tooltip": "My Tooltip"
|
||||
@@ -90,21 +90,21 @@ namespace GraphCanvas
|
||||
//! Globals.details.somearray.0.name
|
||||
//! Globals.details.somearray.1.name
|
||||
//!
|
||||
//! There is one important aspect however, if an element in an array has a "key" value, the value of this key
|
||||
//! There is one important aspect however, if an element in an array has a "base" value, the value of this key
|
||||
//! will replace the index. This is useful when the index and/or ordering of an entry is not relevant or may
|
||||
//! change.
|
||||
//!
|
||||
//! "somearray": [ {
|
||||
//! "name": "First one"
|
||||
//! "key": "a_key"
|
||||
//! "base": "a_key"
|
||||
//! }, {
|
||||
//! "name": "Second one",
|
||||
//! "key": "b_key"
|
||||
//! "base": "b_key"
|
||||
//! } ]
|
||||
//!
|
||||
//! Globals.details.somearray.0.key == "a_key"
|
||||
//! Globals.details.somearray.0.base == "a_key"
|
||||
//! Globals.details.somearray.0.name == "First one"
|
||||
//! Globals.details.somearray.1.key == "b_key"
|
||||
//! Globals.details.somearray.1.base == "b_key"
|
||||
//! Globals.details.somearray.1.name == "Second one"
|
||||
//!
|
||||
class TranslationAssetHandler
|
||||
|
||||
@@ -30,16 +30,7 @@ namespace GraphCanvas
|
||||
void TranslationAssetWorker::Activate()
|
||||
{
|
||||
// Use AssetCatalog service to register ScriptCanvas asset type and extension
|
||||
AZ::Data::AssetType assetType(azrtti_typeid<TranslationAsset>());
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddAssetType, assetType);
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::EnableCatalogForAsset, assetType);
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, TranslationAsset::GetFileFilter());
|
||||
|
||||
m_assetHandler = AZStd::make_unique<TranslationAssetHandler>();
|
||||
if (!AZ::Data::AssetManager::Instance().GetHandler(assetType))
|
||||
{
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(m_assetHandler.get(), assetType);
|
||||
}
|
||||
|
||||
AssetBuilderSDK::AssetBuilderCommandBus::Handler::BusConnect(GetUUID());
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
|
||||
#include "TranslationAsset.h"
|
||||
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
|
||||
namespace GraphCanvas
|
||||
{
|
||||
namespace Translation
|
||||
@@ -88,10 +90,16 @@ namespace GraphCanvas
|
||||
static AZStd::string Sanitize(const AZStd::string& text)
|
||||
{
|
||||
AZStd::string result = text;
|
||||
AZ::StringFunc::Replace(result, "*", "x");
|
||||
AZ::StringFunc::Replace(result, "(", "_");
|
||||
AZ::StringFunc::Replace(result, ")", "_");
|
||||
AZ::StringFunc::Replace(result, "{", "_");
|
||||
AZ::StringFunc::Replace(result, "}", "_");
|
||||
AZ::StringFunc::Replace(result, ":", "_");
|
||||
AZ::StringFunc::Replace(result, "<", "_");
|
||||
AZ::StringFunc::Replace(result, ",", "_");
|
||||
AZ::StringFunc::Replace(result, ">", " ");
|
||||
AZ::StringFunc::Replace(result, "/", "");
|
||||
AZ::StringFunc::Strip(result, " ");
|
||||
AZ::StringFunc::Path::Normalize(result);
|
||||
return result;
|
||||
@@ -117,32 +125,32 @@ namespace GraphCanvas
|
||||
virtual bool HasKey(const AZStd::string& /*key*/) { return false; }
|
||||
|
||||
//! Returns the text value for a given key
|
||||
virtual const char* Get(const AZStd::string& /*key*/) { return nullptr; }
|
||||
virtual bool Get(const AZStd::string& /*key*/, AZStd::string& /*value*/) { return false; }
|
||||
|
||||
struct Details
|
||||
{
|
||||
AZStd::string Name;
|
||||
AZStd::string Tooltip;
|
||||
AZStd::string Category;
|
||||
AZStd::string Subtitle;
|
||||
AZStd::string m_name;
|
||||
AZStd::string m_tooltip;
|
||||
AZStd::string m_category;
|
||||
AZStd::string m_subtitle;
|
||||
|
||||
bool Valid = false;
|
||||
bool m_valid = false;
|
||||
|
||||
Details() = default;
|
||||
|
||||
Details(const Details& rhs)
|
||||
{
|
||||
Name = rhs.Name;
|
||||
Tooltip = rhs.Tooltip;
|
||||
Subtitle = rhs.Subtitle;
|
||||
Category = rhs.Category;
|
||||
Valid = rhs.Valid;
|
||||
m_name = rhs.m_name;
|
||||
m_tooltip = rhs.m_tooltip;
|
||||
m_category = rhs.m_category;
|
||||
m_subtitle = rhs.m_subtitle;
|
||||
m_valid = rhs.m_valid;
|
||||
}
|
||||
|
||||
Details(const char* name, const char* tooltip, const char* subtitle, const char* category)
|
||||
: Name(name), Tooltip(tooltip), Subtitle(subtitle), Category(category)
|
||||
: m_name(name), m_tooltip(tooltip), m_subtitle(subtitle), m_category(category)
|
||||
{
|
||||
Valid = !Name.empty();
|
||||
m_valid = !m_name.empty();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -150,7 +158,7 @@ namespace GraphCanvas
|
||||
virtual bool Add(const TranslationFormat& /*translationFormat*/) { return false; }
|
||||
|
||||
//! Get the details associated with a given key (assumes they are within a "details" object)
|
||||
virtual Details GetDetails(const AZStd::string& /*key*/) { return Details(); }
|
||||
virtual Details GetDetails(const AZStd::string& /*key*/, const Details& /*fallbackDetails*/) { return Details(); }
|
||||
|
||||
//! Generates the source JSON assets for all reflected elements
|
||||
virtual void GenerateSourceAssets() {}
|
||||
|
||||
@@ -104,35 +104,49 @@ namespace GraphCanvas
|
||||
return m_database.find(key) != m_database.end();
|
||||
}
|
||||
|
||||
GraphCanvas::TranslationRequests::Details TranslationDatabase::GetDetails(const AZStd::string& key)
|
||||
GraphCanvas::TranslationRequests::Details TranslationDatabase::GetDetails(const AZStd::string& key, const Details& fallbackDetails)
|
||||
{
|
||||
const char* name = Get(key + ".name");
|
||||
const char* tooltip = Get(key + ".tooltip");
|
||||
const char* subtitle = Get(key + ".subtitle");
|
||||
const char* category = Get(key + ".category");
|
||||
|
||||
static bool s_traceMissingItems = true;
|
||||
if (s_traceMissingItems)
|
||||
Details details;
|
||||
if (!Get(key + ".name", details.m_name))
|
||||
{
|
||||
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (name) not found for key: %s", key.c_str()).c_str());
|
||||
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (tooltip) not found for key: %s", key.c_str()).c_str());
|
||||
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (subtitle) not found for key: %s", key.c_str()).c_str());
|
||||
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value (category) not found for key: %s", key.c_str()).c_str());
|
||||
details.m_name = fallbackDetails.m_name;
|
||||
}
|
||||
|
||||
return Details(name ? name : "", tooltip ? tooltip : "", subtitle ? subtitle : "", category ? category : "");
|
||||
if (!Get(key + ".tooltip", details.m_tooltip))
|
||||
{
|
||||
details.m_tooltip = fallbackDetails.m_tooltip;
|
||||
}
|
||||
|
||||
if (!Get(key + ".subtitle", details.m_subtitle))
|
||||
{
|
||||
details.m_subtitle = fallbackDetails.m_subtitle;
|
||||
}
|
||||
|
||||
if (!Get(key + ".category", details.m_category))
|
||||
{
|
||||
details.m_category = fallbackDetails.m_category;
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
const char* TranslationDatabase::Get(const AZStd::string& key)
|
||||
bool TranslationDatabase::Get(const AZStd::string& key, AZStd::string& value)
|
||||
{
|
||||
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_mutex);
|
||||
|
||||
if (m_database.find(key) != m_database.end())
|
||||
{
|
||||
return m_database[key].c_str();
|
||||
value = m_database[key];
|
||||
return true;
|
||||
}
|
||||
|
||||
return "";
|
||||
static bool s_traceMissingItems = false;
|
||||
if (s_traceMissingItems)
|
||||
{
|
||||
AZ_TracePrintf("GraphCanvas", AZStd::string::format("Value not found for key: %s", key.c_str()).c_str());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TranslationDatabase::Add(const TranslationFormat& format)
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace GraphCanvas
|
||||
|
||||
bool HasKey(const AZStd::string& key) override;
|
||||
|
||||
TranslationRequests::Details GetDetails(const AZStd::string& key) override;
|
||||
TranslationRequests::Details GetDetails(const AZStd::string& key, const Details& value) override;
|
||||
|
||||
const char* Get(const AZStd::string& key) override;
|
||||
bool Get(const AZStd::string& key, AZStd::string& value) override;
|
||||
|
||||
bool Add(const TranslationFormat& format) override;
|
||||
|
||||
|
||||
@@ -11,17 +11,6 @@
|
||||
|
||||
namespace GraphCanvas
|
||||
{
|
||||
namespace Schema
|
||||
{
|
||||
namespace Field
|
||||
{
|
||||
static constexpr char key[] = "key";
|
||||
static constexpr char context[] = "context";
|
||||
static constexpr char variant[] = "variant";
|
||||
static constexpr char entries[] = "entries";
|
||||
}
|
||||
}
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(TranslationFormatSerializer, AZ::SystemAllocator, 0);
|
||||
|
||||
void AddEntryToDatabase(const AZStd::string& baseKey, const AZStd::string& name, const rapidjson::Value& it, TranslationFormat* translationFormat)
|
||||
@@ -35,8 +24,10 @@ namespace GraphCanvas
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::string existingValue = translationFormat->m_database[finalKey.c_str()];
|
||||
|
||||
// There is a name collision
|
||||
AZStd::string error = AZStd::string::format("Unable to store key: %s with value: %s because that key already exists", finalKey.c_str(), it.GetString());
|
||||
AZStd::string error = AZStd::string::format("Unable to store key: %s with value: %s because that key already exists with value: %s (proposed: %s)", finalKey.c_str(), it.GetString(), existingValue.c_str(), it.GetString());
|
||||
AZ_Error("TranslationSerializer", false, error.c_str());
|
||||
}
|
||||
}
|
||||
@@ -74,8 +65,7 @@ namespace GraphCanvas
|
||||
const rapidjson::Value& array = it;
|
||||
for (rapidjson::SizeType i = 0; i < array.Size(); ++i)
|
||||
{
|
||||
// so, here, I need to go in and if there is a "key" member within the object, then I need to use that,
|
||||
// if there isn't, I can use the %d
|
||||
// if there is a "base" member within the object, then use it, otherwise use the index
|
||||
if (array[i].IsObject())
|
||||
{
|
||||
if (array[i].HasMember(Schema::Field::key))
|
||||
@@ -156,7 +146,7 @@ namespace GraphCanvas
|
||||
AZStd::string baseKey = contextStr;
|
||||
if (keyStr.empty())
|
||||
{
|
||||
AZ_Error("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str());
|
||||
AZ_Warning("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str());
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Every entry in the Translation data must have a key");
|
||||
}
|
||||
|
||||
|
||||
@@ -23,4 +23,15 @@ namespace GraphCanvas
|
||||
AZ::JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue,
|
||||
const void* defaultValue, const AZ::Uuid& valueTypeId, AZ::JsonSerializerContext& context) override;
|
||||
};
|
||||
|
||||
namespace Schema
|
||||
{
|
||||
namespace Field
|
||||
{
|
||||
inline constexpr char key[] = "base";
|
||||
inline constexpr char context[] = "context";
|
||||
inline constexpr char variant[] = "variant";
|
||||
inline constexpr char entries[] = "entries";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user