From 0502475fa654d8b6fa4e1fce627275b210d8ac94 Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 7 Jul 2021 13:59:26 -0500 Subject: [PATCH 001/157] Created a toggle switch to enable and disable groups through the EditContext Signed-off-by: Jose --- .../AzCore/AzCore/Serialization/EditContext.h | 59 ++++++++++ .../PropertyEditor/InstanceDataHierarchy.cpp | 6 +- .../UI/PropertyEditor/PropertyRowWidget.cpp | 38 ++++++ .../UI/PropertyEditor/PropertyRowWidget.hxx | 8 ++ .../ReflectedPropertyEditor.cpp | 110 +++++++++++++----- .../ReflectedPropertyEditor.hxx | 3 + .../Code/Source/GradientSampler.cpp | 9 +- 7 files changed, 198 insertions(+), 35 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/EditContext.h b/Code/Framework/AzCore/AzCore/Serialization/EditContext.h index 12ec84161b..ba93d19a3d 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/EditContext.h +++ b/Code/Framework/AzCore/AzCore/Serialization/EditContext.h @@ -235,6 +235,17 @@ namespace AZ */ ClassBuilder* ClassElement(Crc32 elementIdCrc, const char* description); + + /** + * Declare element with attributes that belong to the class SerializeContext::Class, this is a logical structure, you can have one or more ClassElements. + * \uiId is the logical element ID (for instance "Group" when you want to group certain elements this class. + * then in each DataElement you can attach the appropriate group attribute. + * \param memberVariable - reference to the member variable to we can bind to serializations data. + */ + template + ClassBuilder* ClassElement(Crc32 elementIdCrc, const char* description, T memberVariable); + + /** * Declare element with an associated UI handler that does not represent a specific class member variable. * \param uiId - name of a UI handler used to display the element @@ -514,6 +525,54 @@ namespace AZ return this; } + //========================================================================= + // ClassElement + //========================================================================= + template + inline EditContext::ClassBuilder* EditContext::ClassBuilder::ClassElement(Crc32 elementIdCrc, const char* description, T memberVariable) + { + if (IsValid()) + { + using ElementTypeInfo = typename SerializeInternal::ElementInfo; + AZ_Assert( + m_classData->m_typeId == AzTypeInfo::Uuid(), + "Data element (%s) belongs to a different class!", description); + + // Not really portable but works for the supported compilers + size_t offset = + reinterpret_cast(&(reinterpret_cast(0)->*memberVariable)); + // offset = or pass it to the function with offsetof(typename ElementTypeInfo::ClassType,memberVariable); + + SerializeContext::ClassElement* classElement = nullptr; + for (size_t i = 0; i < m_classData->m_elements.size(); ++i) + { + SerializeContext::ClassElement* element = &m_classData->m_elements[i]; + if (element->m_offset == offset) + { + classElement = element; + break; + } + } + // We cannot continue past this point, we must alert the user to fix their serialization config and crash + AZ_Assert( + classElement, + "Class element for editor data element reflection '%s' was NOT found in the serialize context! This member MUST be " + "serializable to be editable!", + description); + + m_classElement->m_elements.push_back(); + Edit::ElementData& ed = m_classElement->m_elements.back(); + + classElement->m_editData = &ed; + m_editElement = &ed; + ed.m_elementId = elementIdCrc; + ed.m_name = description; + ed.m_description = description; + ed.m_serializeClassElement = classElement; + } + return this; + } + //========================================================================= // UIElement //========================================================================= diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp index f411c60625..d6054a7937 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp @@ -546,7 +546,7 @@ namespace AzToolsFramework for (auto& element : nodeEditData->m_elements) { - if (element.IsClassElement() && element.m_elementId == AZ::Edit::ClassElements::Group) + if (element.m_elementId == AZ::Edit::ClassElements::Group) { groupData = (element.m_description && element.m_description[0]) ? &element : nullptr; continue; @@ -1112,13 +1112,13 @@ namespace AzToolsFramework const AZ::Edit::ElementData* groupData = nullptr; for (const AZ::Edit::ElementData& elementData : parentEditData->m_elements) { - if (node->m_elementEditData == &elementData) // this element matches this node + if ((node->m_elementEditData == &elementData) && (elementData.m_elementId != AZ::Edit::ClassElements::Group)) // this element matches this node { // Record the last found group data node->m_groupElementData = groupData; break; } - else if (elementData.IsClassElement() && elementData.m_elementId == AZ::Edit::ClassElements::Group) + else if (elementData.m_elementId == AZ::Edit::ClassElements::Group) { if (!elementData.m_description || !elementData.m_description[0]) { // close the group diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp index d66ee34c3b..b85fb9cb2e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp @@ -12,6 +12,7 @@ #include #include +#include AZ_PUSH_DISABLE_WARNING(4244 4251 4800, "-Wunknown-warning-option") // 4244: conversion from 'int' to 'float', possible loss of data // 4251: class '...' needs to have dll-interface to be used by clients of class 'QInputEvent' @@ -141,6 +142,11 @@ namespace AzToolsFramework m_treeDepth = 0; delete m_dropDownArrow; + if (m_toggleSwitch) + { + m_handler->DestroyGUI(m_toggleSwitch); + m_toggleSwitch = nullptr; + } if (m_childWidget) { @@ -387,6 +393,13 @@ namespace AzToolsFramework setUpdatesEnabled(true); } + void PropertyRowWidget::InitializeToggleGroup(const char* groupName, PropertyRowWidget* pParent, int depth, InstanceDataNode* node, int labelWidth) + { + Initialize(groupName, pParent, depth, labelWidth); + ChangeSourceNode(node); + CreateGroupToggleSwitch(); + } + void PropertyRowWidget::Initialize(const char* groupName, PropertyRowWidget* pParent, int depth, int labelWidth) { Initialize(pParent, nullptr, depth, labelWidth); @@ -1102,6 +1115,19 @@ namespace AzToolsFramework } } + void PropertyRowWidget::CreateGroupToggleSwitch() + { + if (!m_toggleSwitch) + { + m_handlerName = AZ::Edit::UIHandlers::CheckBox; + EBUS_EVENT_RESULT(m_handler, PropertyTypeRegistrationMessages::Bus, ResolvePropertyHandler, m_handlerName, azrtti_typeid()); + m_toggleSwitch = m_handler->CreateGUI(this); + m_middleLayout->insertWidget(0, m_toggleSwitch, 1); + auto checkBoxCtrl = reinterpret_cast(m_toggleSwitch); + QObject::connect(checkBoxCtrl, &AzToolsFramework::PropertyCheckBoxCtrl::valueChanged, this, &PropertyRowWidget::OnClickedToggleButton); + } + } + void PropertyRowWidget::SetIndentSize(int w) { m_indent->changeSize(w, 1, QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -1110,6 +1136,18 @@ namespace AzToolsFramework m_leftHandSideLayout->activate(); } + void PropertyRowWidget::OnClickedToggleButton(bool checked) + { + if ((m_expanded && !checked) || (!m_expanded && checked)) + { + DoExpandOrContract(!IsExpanded(), 0 != (QGuiApplication::keyboardModifiers() & Qt::ControlModifier)); + } + } + + void PropertyRowWidget::ChangeSourceNode(InstanceDataNode* node) + { + m_sourceNode = node; + } void PropertyRowWidget::SetExpanded(bool expanded) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx index b23691ea44..c5618b1f47 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx @@ -48,6 +48,7 @@ namespace AzToolsFramework virtual void Initialize(PropertyRowWidget* pParent, InstanceDataNode* dataNode, int depth, int labelWidth = 200); virtual void Initialize(const char* groupName, PropertyRowWidget* pParent, int depth, int labelWidth = 200); + virtual void InitializeToggleGroup(const char* groupName, PropertyRowWidget* pParent, int depth, InstanceDataNode* node, int labelWidth = 200); virtual void Clear(); // for pooling // --- NOT A UNIQUE IDENTIFIER --- @@ -141,11 +142,13 @@ namespace AzToolsFramework QVBoxLayout* GetLeftHandSideLayoutParent() { return m_leftHandSideLayoutParent; } QToolButton* GetIndicatorButton() { return m_indicatorButton; } QLabel* GetNameLabel() { return m_nameLabel; } + QWidget* GetToggle() { return m_toggleSwitch; } void SetIndentSize(int w); void SetAsCustom(bool custom) { m_custom = custom; } bool CanChildrenBeReordered() const; bool CanBeReordered() const; + protected: int CalculateLabelWidth() const; @@ -175,6 +178,8 @@ namespace AzToolsFramework QLabel* m_defaultLabel; // if there is no handler, we use a m_defaultLabel label InstanceDataNode* m_sourceNode; + QWidget* m_toggleSwitch = nullptr; + QString m_currentFilterString; struct ChangeNotification @@ -239,6 +244,8 @@ namespace AzToolsFramework void mouseDoubleClickEvent(QMouseEvent* event) override; void UpdateDropDownArrow(); + void CreateGroupToggleSwitch(); + void ChangeSourceNode(InstanceDataNode* node); void UpdateDefaultLabel(InstanceDataNode* node); void createContainerButtons(); @@ -257,6 +264,7 @@ namespace AzToolsFramework private slots: void OnClickedExpansionButton(); + void OnClickedToggleButton(bool checked); void OnClickedAddElementButton(); void OnClickedRemoveElementButton(); void OnClickedClearContainerButton(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp index 1e7b0395c8..a1f67489e9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp @@ -167,6 +167,8 @@ namespace AzToolsFramework InstanceDataHierarchyList m_instances; ///< List of instance sets to display, other one can aggregate other instances. InstanceDataHierarchy::ValueComparisonFunction m_valueComparisonFunction; ReflectedPropertyEditor::WidgetList m_widgets; + ReflectedPropertyEditor::SpecialGroupWidgetList m_specialGroupWidgets; + InstanceDataNode* groupSourceNode = nullptr; RowContainerType m_widgetsInDisplayOrder; UserWidgetToDataMap m_userWidgetsToData; VisibilityCallback m_visibilityCallback; @@ -507,7 +509,25 @@ namespace AzToolsFramework { widgetEntry = CreateOrPullFromPool(); widgetEntry->SetFilterString(m_editor->GetFilterString()); - widgetEntry->Initialize(groupName, parent, depth, m_propertyLabelWidth); + + // Initialized normally if the group does not have a member variable attached to it, + // otherwise initialize it as a group that will have a toggle switch. + if (groupElementData->IsClassElement()) + { + widgetEntry->Initialize(groupName, parent, depth, m_propertyLabelWidth); + } + else + { + widgetEntry->InitializeToggleGroup(groupName, parent, depth, groupSourceNode, m_propertyLabelWidth); + QWidget* toggleSwitch = widgetEntry->GetToggle(); + PropertyHandlerBase* pHandler = widgetEntry->GetHandler(); + m_userWidgetsToData[toggleSwitch] = groupSourceNode; + m_specialGroupWidgets[groupSourceNode] = widgetEntry; + pHandler->ConsumeAttributes_Internal(toggleSwitch, groupSourceNode); + pHandler->ReadValuesIntoGUI_Internal(toggleSwitch, groupSourceNode); + widgetEntry->OnValuesUpdated(); + } + widgetEntry->SetLeafIndentation(m_leafIndentation); widgetEntry->SetTreeIndentation(m_treeIndentation); widgetEntry->setObjectName(groupName); @@ -606,7 +626,7 @@ namespace AzToolsFramework // creates and populates the GUI to edit the property if not already created void ReflectedPropertyEditor::Impl::CreateEditorWidget(PropertyRowWidget* pWidget) { - if (!pWidget->HasChildWidgetAlready()) + if ((!pWidget->HasChildWidgetAlready()) && (!pWidget->GetToggle())) { PropertyHandlerBase* pHandler = pWidget->GetHandler(); if (pHandler) @@ -733,36 +753,44 @@ namespace AzToolsFramework } } } - - pWidget = CreateOrPullFromPool(); - pWidget->show(); - - pWidget->SetFilterString(m_editor->GetFilterString()); - pWidget->Initialize(pParent, node, depth, m_propertyLabelWidth); - - if (labelOverride != "") + if ((!node->GetElementEditMetadata()) || (node->GetElementEditMetadata()->m_elementId != AZ::Edit::ClassElements::Group)) { - pWidget->SetNameLabel(labelOverride.data()); + pWidget = CreateOrPullFromPool(); + pWidget->show(); + + pWidget->SetFilterString(m_editor->GetFilterString()); + pWidget->Initialize(pParent, node, depth, m_propertyLabelWidth); + + if (labelOverride != "") + { + pWidget->SetNameLabel(labelOverride.data()); + } + + pWidget->setObjectName(pWidget->label()); + pWidget->SetSelectionEnabled(m_selectionEnabled); + pWidget->SetLeafIndentation(m_leafIndentation); + pWidget->SetTreeIndentation(m_treeIndentation); + + m_widgets[node] = pWidget; + m_widgetsInDisplayOrder.insert(widgetDisplayOrder, pWidget); + + if (pParent) + { + pParent->AddedChild(pWidget); + } + + if (pParent || !m_hideRootProperties) + { + depth += 1; + } + pParent = pWidget; } - pWidget->setObjectName(pWidget->label()); - pWidget->SetSelectionEnabled(m_selectionEnabled); - pWidget->SetLeafIndentation(m_leafIndentation); - pWidget->SetTreeIndentation(m_treeIndentation); - - m_widgets[node] = pWidget; - m_widgetsInDisplayOrder.insert(widgetDisplayOrder, pWidget); - - if (pParent) + // Save the last InstanceDataNode that is a Group ClassElement so that we can use it as the source node for its widget. + if ((node->GetElementEditMetadata()) && (node->GetElementEditMetadata()->m_elementId == AZ::Edit::ClassElements::Group)) { - pParent->AddedChild(pWidget); + groupSourceNode = node; } - - if (pParent || !m_hideRootProperties) - { - depth += 1; - } - pParent = pWidget; } } @@ -1000,6 +1028,26 @@ namespace AzToolsFramework pWidget->UpdateIndicator(m_impl->m_indicatorQueryFunction(pWidget->GetNode())); } } + + for (auto it = m_impl->m_specialGroupWidgets.begin(); it != m_impl->m_specialGroupWidgets.end(); ++it) + { + PropertyRowWidget* pWidget = it->second; + + QWidget* childWidget = pWidget->GetChildWidget(); + + if (pWidget->GetHandler() && childWidget) + { + pWidget->GetHandler()->ConsumeAttributes_Internal(childWidget, it->first); + pWidget->GetHandler()->ReadValuesIntoGUI_Internal(childWidget, it->first); + pWidget->OnValuesUpdated(); + } + pWidget->RefreshAttributesFromNode(false); + + if (m_impl->m_indicatorQueryFunction) + { + pWidget->UpdateIndicator(m_impl->m_indicatorQueryFunction(pWidget->GetNode())); + } + } } void ReflectedPropertyEditor::InvalidateValues() @@ -1356,8 +1404,14 @@ namespace AzToolsFramework // get the property editor auto rowWidget = m_widgets.find(it->second); - if (rowWidget != m_widgets.end()) + auto rowWidgetGroup = m_specialGroupWidgets.find(it->second); + if (rowWidget != m_widgets.end() || rowWidgetGroup != m_specialGroupWidgets.end()) { + if (rowWidget == m_widgets.end()) + { + rowWidget = rowWidgetGroup; + } + InstanceDataNode* node = rowWidget->first; PropertyRowWidget* widget = rowWidget->second; PropertyHandlerBase* handler = widget->GetHandler(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx index c27acaa374..42ca0b6d92 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx @@ -50,6 +50,8 @@ namespace AzToolsFramework typedef AZStd::unordered_map WidgetList; + typedef AZStd::unordered_map SpecialGroupWidgetList; + ReflectedPropertyEditor(QWidget* pParent); virtual ~ReflectedPropertyEditor(); @@ -61,6 +63,7 @@ namespace AzToolsFramework bool AddInstance(void* instance, const AZ::Uuid& classId, void* aggregateInstance = nullptr, void* compareInstance = nullptr); void SetCompareInstance(void* instance, const AZ::Uuid& classId); void ClearInstances(); + void ReadValuesIntoGui(QWidget* widget, InstanceDataNode* node); template bool AddInstance(T* instance, void* aggregateInstance = nullptr, void* compareInstance = nullptr) { diff --git a/Gems/GradientSignal/Code/Source/GradientSampler.cpp b/Gems/GradientSignal/Code/Source/GradientSampler.cpp index 944eef2e42..a0a23ffe68 100644 --- a/Gems/GradientSignal/Code/Source/GradientSampler.cpp +++ b/Gems/GradientSignal/Code/Source/GradientSampler.cpp @@ -61,8 +61,9 @@ namespace GradientSignal ->DataElement(0, &GradientSampler::m_invertInput, "Invert Input", "") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) - ->DataElement(0, &GradientSampler::m_enableTransform, "Enable Transform", "") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) + + ->ClassElement(AZ::Edit::ClassElements::Group, "Enable Transform", &GradientSampler::m_enableTransform) + ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &GradientSampler::m_translate, "Translate", "") ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) @@ -73,8 +74,8 @@ namespace GradientSignal ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) - ->DataElement(0, &GradientSampler::m_enableLevels, "Enable Levels", "") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) + ->ClassElement(AZ::Edit::ClassElements::Group, "Enable Levels", &GradientSampler::m_enableLevels) + ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_inputMid, "Input Mid", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 10.0f) From e18bcc63f2a2b294e87f4328ea2f787cc8e1b82e Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 7 Jul 2021 15:12:43 -0500 Subject: [PATCH 002/157] Fixed a bug in the ReflectedPropertyError that was preventing groups from opening correctly Signed-off-by: Jose --- .../ReflectedPropertyEditor.cpp | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp index a1f67489e9..02048a1161 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp @@ -1028,26 +1028,6 @@ namespace AzToolsFramework pWidget->UpdateIndicator(m_impl->m_indicatorQueryFunction(pWidget->GetNode())); } } - - for (auto it = m_impl->m_specialGroupWidgets.begin(); it != m_impl->m_specialGroupWidgets.end(); ++it) - { - PropertyRowWidget* pWidget = it->second; - - QWidget* childWidget = pWidget->GetChildWidget(); - - if (pWidget->GetHandler() && childWidget) - { - pWidget->GetHandler()->ConsumeAttributes_Internal(childWidget, it->first); - pWidget->GetHandler()->ReadValuesIntoGUI_Internal(childWidget, it->first); - pWidget->OnValuesUpdated(); - } - pWidget->RefreshAttributesFromNode(false); - - if (m_impl->m_indicatorQueryFunction) - { - pWidget->UpdateIndicator(m_impl->m_indicatorQueryFunction(pWidget->GetNode())); - } - } } void ReflectedPropertyEditor::InvalidateValues() From 17a79daad89afe48b8d03df852c99eedcc887e9d Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Mon, 12 Jul 2021 16:07:52 +0100 Subject: [PATCH 003/157] Add clear console when starting gamemode setting. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- Code/Editor/Controls/ConsoleSCB.cpp | 4 ++++ Code/Editor/Controls/ConsoleSCB.h | 2 ++ Code/Editor/EditorPreferencesPageGeneral.cpp | 5 +++++ Code/Editor/EditorPreferencesPageGeneral.h | 1 + Code/Editor/GameEngine.cpp | 6 ++++++ Code/Editor/Settings.cpp | 5 +++++ Code/Editor/Settings.h | 1 + 7 files changed, 24 insertions(+) diff --git a/Code/Editor/Controls/ConsoleSCB.cpp b/Code/Editor/Controls/ConsoleSCB.cpp index 32ec6506b1..32731b7317 100644 --- a/Code/Editor/Controls/ConsoleSCB.cpp +++ b/Code/Editor/Controls/ConsoleSCB.cpp @@ -537,6 +537,10 @@ void CConsoleSCB::AddToPendingLines(const QString& text, bool bNewLine) s_pendingLines.push_back({ text, bNewLine }); } +void CConsoleSCB::ClearText() +{ + ui->textEdit->clear(); +} /** * When a CVar variable is updated, we need to tell alert our console variables * pane so it can update the corresponding row diff --git a/Code/Editor/Controls/ConsoleSCB.h b/Code/Editor/Controls/ConsoleSCB.h index faa8c06124..d561e5f5a6 100644 --- a/Code/Editor/Controls/ConsoleSCB.h +++ b/Code/Editor/Controls/ConsoleSCB.h @@ -174,6 +174,8 @@ public: static void AddToPendingLines(const QString& text, bool bNewLine); // call this function instead of AddToConsole() until an instance of CConsoleSCB exists to prevent messages from getting lost + void ClearText(); + // EditorPreferencesNotificationBus... void OnEditorPreferencesChanged() override; diff --git a/Code/Editor/EditorPreferencesPageGeneral.cpp b/Code/Editor/EditorPreferencesPageGeneral.cpp index 861ef10c23..cf4a430c7e 100644 --- a/Code/Editor/EditorPreferencesPageGeneral.cpp +++ b/Code/Editor/EditorPreferencesPageGeneral.cpp @@ -31,6 +31,7 @@ void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize) ->Field("PreviewPanel", &GeneralSettings::m_previewPanel) ->Field("ApplyConfigSpec", &GeneralSettings::m_applyConfigSpec) ->Field("EnableSourceControl", &GeneralSettings::m_enableSourceControl) + ->Field("ClearConsole", &GeneralSettings::m_clearConsoleOnGameModeStart) ->Field("ConsoleBackgroundColorTheme", &GeneralSettings::m_consoleBackgroundColorTheme) ->Field("AutoloadLastLevel", &GeneralSettings::m_autoLoadLastLevel) ->Field("ShowTimeInConsole", &GeneralSettings::m_bShowTimeInConsole) @@ -76,6 +77,8 @@ void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize) ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_previewPanel, "Show Geometry Preview Panel", "Show Geometry Preview Panel") ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_applyConfigSpec, "Hide objects by config spec", "Hide objects by config spec") ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_enableSourceControl, "Enable Source Control", "Enable Source Control") + ->DataElement( + AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_clearConsoleOnGameModeStart, "Clear Console at Game Startup", "Clear Console when Game Mode Starts") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &GeneralSettings::m_consoleBackgroundColorTheme, "Console Background", "Console Background") ->EnumAttribute(AzToolsFramework::ConsoleColorTheme::Light, "Light") ->EnumAttribute(AzToolsFramework::ConsoleColorTheme::Dark, "Dark") @@ -141,6 +144,7 @@ void CEditorPreferencesPage_General::OnApply() gSettings.bPreviewGeometryWindow = m_generalSettings.m_previewPanel; gSettings.bApplyConfigSpecInEditor = m_generalSettings.m_applyConfigSpec; gSettings.enableSourceControl = m_generalSettings.m_enableSourceControl; + gSettings.clearConsoleOnGameModeStart = m_generalSettings.m_clearConsoleOnGameModeStart; gSettings.consoleBackgroundColorTheme = m_generalSettings.m_consoleBackgroundColorTheme; gSettings.bShowTimeInConsole = m_generalSettings.m_bShowTimeInConsole; gSettings.bShowDashboardAtStartup = m_messaging.m_showDashboard; @@ -175,6 +179,7 @@ void CEditorPreferencesPage_General::InitializeSettings() m_generalSettings.m_previewPanel = gSettings.bPreviewGeometryWindow; m_generalSettings.m_applyConfigSpec = gSettings.bApplyConfigSpecInEditor; m_generalSettings.m_enableSourceControl = gSettings.enableSourceControl; + m_generalSettings.m_clearConsoleOnGameModeStart = gSettings.clearConsoleOnGameModeStart; m_generalSettings.m_consoleBackgroundColorTheme = gSettings.consoleBackgroundColorTheme; m_generalSettings.m_bShowTimeInConsole = gSettings.bShowTimeInConsole; m_generalSettings.m_autoLoadLastLevel = gSettings.bAutoloadLastLevelAtStartup; diff --git a/Code/Editor/EditorPreferencesPageGeneral.h b/Code/Editor/EditorPreferencesPageGeneral.h index ca315c2d01..557a9d5bce 100644 --- a/Code/Editor/EditorPreferencesPageGeneral.h +++ b/Code/Editor/EditorPreferencesPageGeneral.h @@ -45,6 +45,7 @@ private: bool m_previewPanel; bool m_applyConfigSpec; bool m_enableSourceControl; + bool m_clearConsoleOnGameModeStart; AzToolsFramework::ConsoleColorTheme m_consoleBackgroundColorTheme; bool m_autoLoadLastLevel; bool m_bShowTimeInConsole; diff --git a/Code/Editor/GameEngine.cpp b/Code/Editor/GameEngine.cpp index a729be9175..e77d44d98e 100644 --- a/Code/Editor/GameEngine.cpp +++ b/Code/Editor/GameEngine.cpp @@ -29,6 +29,7 @@ // Editor #include "IEditorImpl.h" +#include "Controls/ConsoleSCB.h" #include "CryEditDoc.h" #include "Settings.h" @@ -565,6 +566,11 @@ void CGameEngine::SwitchToInGame() streamer->QueueRequest(flush); wait.acquire(); } + + if (gSettings.clearConsoleOnGameModeStart) + { + CConsoleSCB::GetCreatedInstance()->ClearText(); + } GetIEditor()->Notify(eNotify_OnBeginGameMode); diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index cdd44b5fff..f675116e56 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -188,6 +188,7 @@ SEditorSettings::SEditorSettings() consoleBackgroundColorTheme = AzToolsFramework::ConsoleColorTheme::Dark; bShowTimeInConsole = false; + clearConsoleOnGameModeStart = false; enableSceneInspector = false; @@ -526,6 +527,8 @@ void SEditorSettings::Save() SaveValue("Settings", "ConsoleBackgroundColorThemeV2", (int)consoleBackgroundColorTheme); + SaveValue("Settings", "ClearConsoleOnGameModeStart", clearConsoleOnGameModeStart); + SaveValue("Settings", "ShowTimeInConsole", bShowTimeInConsole); SaveValue("Settings", "EnableSceneInspector", enableSceneInspector); @@ -744,6 +747,8 @@ void SEditorSettings::Load() consoleBackgroundColorTheme = AzToolsFramework::ConsoleColorTheme::Dark; } + LoadValue("Settings", "ClearConsoleOnGameModeStart", clearConsoleOnGameModeStart); + LoadValue("Settings", "ShowTimeInConsole", bShowTimeInConsole); LoadValue("Settings", "EnableSceneInspector", enableSceneInspector); diff --git a/Code/Editor/Settings.h b/Code/Editor/Settings.h index cef77de6a7..ff4252f8d8 100644 --- a/Code/Editor/Settings.h +++ b/Code/Editor/Settings.h @@ -379,6 +379,7 @@ AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING //! Source Control Enabling. bool enableSourceControl; + bool clearConsoleOnGameModeStart; //! Text editor. QString textEditorForScript; From 11eb920e400b0252fda27b1f6b39cf1f6c0ea1d5 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 12 Jul 2021 15:29:56 -0700 Subject: [PATCH 004/157] Removal of dead code and bug fixes for reflection Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp | 2 +- .../Code/Source/Shape/PolygonPrismShapeComponent.cpp | 2 +- .../Include/ScriptCanvas/Data/BehaviorContextObject.h | 8 +++++++- .../Code/Source/Framework/ScriptCanvasTestFixture.h | 5 ----- .../Code/Source/Framework/ScriptCanvasTestUtilities.cpp | 8 -------- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp index 39f6c02bde..a40dd2daac 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp @@ -38,7 +38,7 @@ namespace AZ { struct SymbolStorageDynamicallyLoadedModules { size_t m_size; - DynamicallyLoadedModuleInfo m_modules[256]; + DynamicallyLoadedModuleInfo m_modules[1028]; SymbolStorageDynamicallyLoadedModules() : m_size(0) diff --git a/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShapeComponent.cpp index 22b0cbfb03..6bb4c1238c 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShapeComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShapeComponent.cpp @@ -98,7 +98,7 @@ namespace LmbrCentral if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { behaviorContext->EBus("PolygonPrismShapeComponentRequestBus") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Edit::Attributes::Category, "Shape") ->Attribute(AZ::Script::Attributes::Module, "shape") ->Event("GetPolygonPrism", &PolygonPrismShapeComponentRequestBus::Events::GetPolygonPrism) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h index 29831e20f9..4980fdd37b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h @@ -115,7 +115,6 @@ namespace ScriptCanvas AZ_FORCE_INLINE BehaviorContextObject() = default; BehaviorContextObject& operator=(const BehaviorContextObject&) = delete; - BehaviorContextObject(const BehaviorContextObject&) = delete; // copy ctor AZ_FORCE_INLINE BehaviorContextObject(const void* source, const AnyTypeInfo& typeInfo, AZ::u32 flags); @@ -134,6 +133,13 @@ namespace ScriptCanvas AZ_FORCE_INLINE void add_ref(); void release(); + + public: + // no copying allowed, this is here to allow compile time compatibility with storage in of BehaviorContextObjectPtr AZStd::any, only + AZ_FORCE_INLINE BehaviorContextObject(const BehaviorContextObject&) + { + AZ_Assert(false, "no copying allowed, this is here to allow storage in of BehaviorContextObjectPtr AZStd::any, only"); + } }; AZ_FORCE_INLINE BehaviorContextObject::BehaviorContextObject(const void* value, const AnyTypeInfo& typeInfo, AZ::u32 flags) diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h index 0a4408b689..403a1623d6 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h @@ -135,11 +135,6 @@ namespace ScriptCanvasTests // don't hang on to dangling assets AZ::Data::AssetManager::Instance().DispatchEvents(); - if (AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance()) - { - fileIO->DestroyPath(k_tempCoreAssetDir); - } - if (s_application) { s_application->Stop(); diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp index 03ecba29be..8b231d5fdc 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestUtilities.cpp @@ -33,14 +33,6 @@ namespace ScriptCanvasTests { using namespace ScriptCanvas; -#define SC_CORE_UNIT_TEST_DIR "@engroot@/LY_SC_UnitTest_ScriptCanvas_CoreCPP_Temporary" -#define SC_CORE_UNIT_TEST_NAME "serializationTest.scriptcanvas_compiled" - const char* k_tempCoreAssetDir = SC_CORE_UNIT_TEST_DIR; - const char* k_tempCoreAssetName = SC_CORE_UNIT_TEST_NAME; - const char* k_tempCoreAssetPath = SC_CORE_UNIT_TEST_DIR "/" SC_CORE_UNIT_TEST_NAME; -#undef SC_CORE_UNIT_TEST_DIR -#undef SC_CORE_UNIT_TEST_NAME - void ExpectParse(AZStd::string_view graphPath) { AZ_TEST_START_TRACE_SUPPRESSION; From bc9d0eb0e1c70843c097a88fe720a5bd4d5ca524 Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 13 Jul 2021 14:55:05 -0500 Subject: [PATCH 005/157] Added unit tests for groups and toggle groups, fixed comments and syntax Signed-off-by: Jose --- .../AzCore/AzCore/Serialization/EditContext.h | 53 +-- .../PropertyEditor/InstanceDataHierarchy.cpp | 3 +- .../UI/PropertyEditor/PropertyRowWidget.cpp | 6 +- .../UI/PropertyEditor/PropertyRowWidget.hxx | 1 + .../ReflectedPropertyEditor.cpp | 22 +- .../ReflectedPropertyEditor.hxx | 2 +- .../Framework/Tests/InstanceDataHierarchy.cpp | 335 ++++++++++++++++++ .../Code/Source/GradientSampler.cpp | 6 +- 8 files changed, 363 insertions(+), 65 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/EditContext.h b/Code/Framework/AzCore/AzCore/Serialization/EditContext.h index ba93d19a3d..61c7df4471 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/EditContext.h +++ b/Code/Framework/AzCore/AzCore/Serialization/EditContext.h @@ -237,13 +237,13 @@ namespace AZ /** - * Declare element with attributes that belong to the class SerializeContext::Class, this is a logical structure, you can have one or more ClassElements. - * \uiId is the logical element ID (for instance "Group" when you want to group certain elements this class. - * then in each DataElement you can attach the appropriate group attribute. - * \param memberVariable - reference to the member variable to we can bind to serializations data. + * Declare element with attributes that belong to the class SerializeContext::Class, this is a logical structure, you can have one or more GroupElementToggles. + * T must be a boolean variable that will enable and disable each DataElement attached to this structure. + * \param description - Descriptive name of the field that will typically appear in a tooltip. + * \param memberVariable - reference to the member variable so we can bind to serialization data. */ template - ClassBuilder* ClassElement(Crc32 elementIdCrc, const char* description, T memberVariable); + ClassBuilder* GroupElementToggle(const char* description, T memberVariable); /** @@ -529,48 +529,9 @@ namespace AZ // ClassElement //========================================================================= template - inline EditContext::ClassBuilder* EditContext::ClassBuilder::ClassElement(Crc32 elementIdCrc, const char* description, T memberVariable) + inline EditContext::ClassBuilder* EditContext::ClassBuilder::GroupElementToggle(const char* name, T memberVariable) { - if (IsValid()) - { - using ElementTypeInfo = typename SerializeInternal::ElementInfo; - AZ_Assert( - m_classData->m_typeId == AzTypeInfo::Uuid(), - "Data element (%s) belongs to a different class!", description); - - // Not really portable but works for the supported compilers - size_t offset = - reinterpret_cast(&(reinterpret_cast(0)->*memberVariable)); - // offset = or pass it to the function with offsetof(typename ElementTypeInfo::ClassType,memberVariable); - - SerializeContext::ClassElement* classElement = nullptr; - for (size_t i = 0; i < m_classData->m_elements.size(); ++i) - { - SerializeContext::ClassElement* element = &m_classData->m_elements[i]; - if (element->m_offset == offset) - { - classElement = element; - break; - } - } - // We cannot continue past this point, we must alert the user to fix their serialization config and crash - AZ_Assert( - classElement, - "Class element for editor data element reflection '%s' was NOT found in the serialize context! This member MUST be " - "serializable to be editable!", - description); - - m_classElement->m_elements.push_back(); - Edit::ElementData& ed = m_classElement->m_elements.back(); - - classElement->m_editData = &ed; - m_editElement = &ed; - ed.m_elementId = elementIdCrc; - ed.m_name = description; - ed.m_description = description; - ed.m_serializeClassElement = classElement; - } - return this; + return DataElement(AZ::Edit::ClassElements::Group, memberVariable, name, name, ""); } //========================================================================= diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp index d6054a7937..9b69701a27 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.cpp @@ -1112,7 +1112,8 @@ namespace AzToolsFramework const AZ::Edit::ElementData* groupData = nullptr; for (const AZ::Edit::ElementData& elementData : parentEditData->m_elements) { - if ((node->m_elementEditData == &elementData) && (elementData.m_elementId != AZ::Edit::ClassElements::Group)) // this element matches this node + // this element matches this node + if ((node->m_elementEditData == &elementData) && (elementData.m_elementId != AZ::Edit::ClassElements::Group)) { // Record the last found group data node->m_groupElementData = groupData; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp index b85fb9cb2e..e6f2af6a52 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp @@ -1120,10 +1120,10 @@ namespace AzToolsFramework if (!m_toggleSwitch) { m_handlerName = AZ::Edit::UIHandlers::CheckBox; - EBUS_EVENT_RESULT(m_handler, PropertyTypeRegistrationMessages::Bus, ResolvePropertyHandler, m_handlerName, azrtti_typeid()); + PropertyTypeRegistrationMessages::Bus::BroadcastResult(m_handler, &PropertyTypeRegistrationMessages::Bus::Events::ResolvePropertyHandler, m_handlerName, azrtti_typeid()); m_toggleSwitch = m_handler->CreateGUI(this); m_middleLayout->insertWidget(0, m_toggleSwitch, 1); - auto checkBoxCtrl = reinterpret_cast(m_toggleSwitch); + auto checkBoxCtrl = static_cast(m_toggleSwitch); QObject::connect(checkBoxCtrl, &AzToolsFramework::PropertyCheckBoxCtrl::valueChanged, this, &PropertyRowWidget::OnClickedToggleButton); } } @@ -1138,7 +1138,7 @@ namespace AzToolsFramework void PropertyRowWidget::OnClickedToggleButton(bool checked) { - if ((m_expanded && !checked) || (!m_expanded && checked)) + if (m_expanded != checked) { DoExpandOrContract(!IsExpanded(), 0 != (QGuiApplication::keyboardModifiers() & Qt::ControlModifier)); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx index c5618b1f47..93c1fc4d03 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx @@ -143,6 +143,7 @@ namespace AzToolsFramework QToolButton* GetIndicatorButton() { return m_indicatorButton; } QLabel* GetNameLabel() { return m_nameLabel; } QWidget* GetToggle() { return m_toggleSwitch; } + const QWidget* GetToggle() const { return m_toggleSwitch; } void SetIndentSize(int w); void SetAsCustom(bool custom) { m_custom = custom; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp index 02048a1161..d16fbb2776 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp @@ -167,7 +167,7 @@ namespace AzToolsFramework InstanceDataHierarchyList m_instances; ///< List of instance sets to display, other one can aggregate other instances. InstanceDataHierarchy::ValueComparisonFunction m_valueComparisonFunction; ReflectedPropertyEditor::WidgetList m_widgets; - ReflectedPropertyEditor::SpecialGroupWidgetList m_specialGroupWidgets; + ReflectedPropertyEditor::WidgetList m_specialGroupWidgets; InstanceDataNode* groupSourceNode = nullptr; RowContainerType m_widgetsInDisplayOrder; UserWidgetToDataMap m_userWidgetsToData; @@ -626,7 +626,7 @@ namespace AzToolsFramework // creates and populates the GUI to edit the property if not already created void ReflectedPropertyEditor::Impl::CreateEditorWidget(PropertyRowWidget* pWidget) { - if ((!pWidget->HasChildWidgetAlready()) && (!pWidget->GetToggle())) + if (!pWidget->HasChildWidgetAlready() && !pWidget->GetToggle()) { PropertyHandlerBase* pHandler = pWidget->GetHandler(); if (pHandler) @@ -753,7 +753,7 @@ namespace AzToolsFramework } } } - if ((!node->GetElementEditMetadata()) || (node->GetElementEditMetadata()->m_elementId != AZ::Edit::ClassElements::Group)) + if (!node->GetElementEditMetadata() || (node->GetElementEditMetadata()->m_elementId != AZ::Edit::ClassElements::Group)) { pWidget = CreateOrPullFromPool(); pWidget->show(); @@ -787,7 +787,7 @@ namespace AzToolsFramework } // Save the last InstanceDataNode that is a Group ClassElement so that we can use it as the source node for its widget. - if ((node->GetElementEditMetadata()) && (node->GetElementEditMetadata()->m_elementId == AZ::Edit::ClassElements::Group)) + if (node->GetElementEditMetadata() && (node->GetElementEditMetadata()->m_elementId == AZ::Edit::ClassElements::Group)) { groupSourceNode = node; } @@ -1382,16 +1382,14 @@ namespace AzToolsFramework return; } - // get the property editor + // Get the property editor from either the widget map or the special toggle group widgets auto rowWidget = m_widgets.find(it->second); - auto rowWidgetGroup = m_specialGroupWidgets.find(it->second); - if (rowWidget != m_widgets.end() || rowWidgetGroup != m_specialGroupWidgets.end()) + if (rowWidget == m_widgets.end()) + { + rowWidget = m_specialGroupWidgets.find(it->second); + } + if (rowWidget != m_widgets.end() || rowWidget != m_specialGroupWidgets.end()) { - if (rowWidget == m_widgets.end()) - { - rowWidget = rowWidgetGroup; - } - InstanceDataNode* node = rowWidget->first; PropertyRowWidget* widget = rowWidget->second; PropertyHandlerBase* handler = widget->GetHandler(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx index 42ca0b6d92..bd5a6ab891 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx @@ -50,7 +50,7 @@ namespace AzToolsFramework typedef AZStd::unordered_map WidgetList; - typedef AZStd::unordered_map SpecialGroupWidgetList; + ReflectedPropertyEditor::WidgetList m_specialGroupWidgets; ReflectedPropertyEditor(QWidget* pParent); virtual ~ReflectedPropertyEditor(); diff --git a/Code/Framework/Tests/InstanceDataHierarchy.cpp b/Code/Framework/Tests/InstanceDataHierarchy.cpp index db0223c0cf..29cf42fb6b 100644 --- a/Code/Framework/Tests/InstanceDataHierarchy.cpp +++ b/Code/Framework/Tests/InstanceDataHierarchy.cpp @@ -20,6 +20,7 @@ #include #include #include +#include using namespace AZ; @@ -726,6 +727,101 @@ namespace UnitTest }; + class InstanceDataHierarchyGroupTestFixture + : public AllocatorsFixture + { + public: + InstanceDataHierarchyGroupTestFixture() = default; + }; + + class GroupTestComponent + : public AZ::Component + { + public: + AZ_COMPONENT(GroupTestComponent, "{C088C81D-D59D-43F1-85F8-B2E591BABA36}") + + GroupTestComponent() = default; + + struct SubData + { + AZ_TYPE_INFO(SubData, "{983316B5-17C0-476E-9CEB-CA749B3ABE5D}"); + AZ_CLASS_ALLOCATOR(SubData, AZ::SystemAllocator, 0); + + SubData() {} + SubData(int v) : m_int(v) {} + SubData(bool b) : m_bool(b) {} + SubData(float f) : m_float(f) {} + ~SubData() = default; + + float m_float = 0.f; + int m_int = 0; + bool m_bool = true; + }; + + static void Reflect(AZ::ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("SubInt", &SubData::m_int) + ->Field("SubToggle", &SubData::m_bool) + ->Field("SubFloat", &SubData::m_float) + ; + + serializeContext->Class() + ->Version(1) + ->Field("Float", &GroupTestComponent::m_float) + ->Field("GroupToggle", &GroupTestComponent::m_groupToggle) + ->Field("GroupFloat", &GroupTestComponent::m_groupFloat) + ->Field("ToggleGroupInt", &GroupTestComponent::m_toggleGroupInt) + ->Field("SubDataNormal", &GroupTestComponent::m_subGroupForNormal) + ->Field("SubDataToggle", &GroupTestComponent::m_subGroupForToggle) + ; + + if (AZ::EditContext* edit = serializeContext->GetEditContext()) + { + edit->Class("Group Test Component", "Testing normal groups and toggle groups") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->DataElement(0, &GroupTestComponent::m_float, "Float Field", "A float field") + ->ClassElement(AZ::Edit::ClassElements::Group, "Normal Group") + ->DataElement(0, &GroupTestComponent::m_groupFloat, "Float Field", "A float field") + ->DataElement(0, &GroupTestComponent::m_subGroupForNormal, "Struct Field", "A sub data type") + ->GroupElementToggle("Group Toggle", &GroupTestComponent::m_groupToggle) + ->DataElement(0, &GroupTestComponent::m_toggleGroupInt, "Normal Integer", "An Integer") + ->DataElement(0, &GroupTestComponent::m_subGroupForToggle, "Struct Field", "A sub data type") + ; + + edit->Class("SubGroup Test Component", "Testing nested normal groups and toggle groups") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->ClassElement(AZ::Edit::ClassElements::Group, "Normal SubGroup") + ->DataElement(0, &SubData::m_int, "SubGroup Int Field", "An int") + ->GroupElementToggle("SubGroup Toggle", &SubData::m_bool) + ->DataElement(0, &SubData::m_float, "SubGroup Float Field", "An int") + ; + } + } + } + + void Activate() override + { + } + + void Deactivate() override + { + } + + float m_float = 0.f; + float m_groupFloat = 0.f; + int m_toggleGroupInt = 0; + AZStd::string m_string; + bool m_groupToggle = false; + + SubData m_subGroupForNormal; + SubData m_subGroupForToggle; + }; + + class InstanceDataHierarchyKeyedContainerTest : public AllocatorsFixture { @@ -1314,4 +1410,243 @@ namespace UnitTest run(); } + TEST_F(InstanceDataHierarchyGroupTestFixture, TestNormalGroups) + { + using namespace AzToolsFramework; + + // Setting up the data node hierarchy + AZ::SerializeContext serializeContext; + serializeContext.CreateEditContext(); + Entity::Reflect(&serializeContext); + GroupTestComponent::Reflect(&serializeContext); + + AZStd::unique_ptr testEntity1(new AZ::Entity()); + testEntity1->CreateComponent(); + + InstanceDataHierarchy instanceDataHierarchy; + instanceDataHierarchy.AddRootInstance(testEntity1.get()); + instanceDataHierarchy.Build(&serializeContext, 0); + + // Adding the nodes to a node stack + auto rootNode = instanceDataHierarchy.GetRootNode(); + AZStd::stack nodeStack; + nodeStack.push(rootNode); + InstanceDataNode* componentNode1 = nullptr; + while (!nodeStack.empty()) + { + InstanceDataNode* node = nodeStack.top(); + nodeStack.pop(); + if (node->GetClassMetadata()->m_typeId == AZ::AzTypeInfo::Uuid()) + { + componentNode1 = node; + break; + } + for (InstanceDataNode& child : node->GetChildren()) + { + nodeStack.push(&child); + } + } + // Iterating through the children in the instance data hierarchy to verify their properties + ASSERT_TRUE(componentNode1 != nullptr); + for (auto child : componentNode1->GetChildren()) + { + AZStd::string childName(child.GetElementMetadata()->m_name); + if (childName.compare("GroupFloat") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(child.GetElementEditMetadata()->IsClassElement()); + // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup + ASSERT_NE(child.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node was assigned to the appropriate group + ASSERT_EQ(child.GetGroupElementMetadata()->m_description, "Normal Group"); + // Ensuring that this node has the correct parent + ASSERT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); + } + } + } + + TEST_F(InstanceDataHierarchyGroupTestFixture, TestToggleGroups) + { + using namespace AzToolsFramework; + + // Setting up the data node hierarchy + AZ::SerializeContext serializeContext; + serializeContext.CreateEditContext(); + Entity::Reflect(&serializeContext); + GroupTestComponent::Reflect(&serializeContext); + + AZStd::unique_ptr testEntity1(new AZ::Entity()); + testEntity1->CreateComponent(); + + InstanceDataHierarchy instanceDataHierarchy; + instanceDataHierarchy.AddRootInstance(testEntity1.get()); + instanceDataHierarchy.Build(&serializeContext, 0); + + // Adding the nodes to a node stack + auto rootNode = instanceDataHierarchy.GetRootNode(); + AZStd::stack nodeStack; + nodeStack.push(rootNode); + InstanceDataNode* componentNode1 = nullptr; + while (!nodeStack.empty()) + { + InstanceDataNode* node = nodeStack.top(); + nodeStack.pop(); + if (node->GetClassMetadata()->m_typeId == AZ::AzTypeInfo::Uuid()) + { + componentNode1 = node; + break; + } + for (InstanceDataNode& child : node->GetChildren()) + { + nodeStack.push(&child); + } + } + // Iterating through the children in the instance data hierarchy to verify their properties + ASSERT_TRUE(componentNode1 != nullptr); + for (auto child : componentNode1->GetChildren()) + { + AZStd::string childName(child.GetElementMetadata()->m_name); + if (childName.compare("GroupToggle") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(child.GetElementEditMetadata()->IsClassElement()); + // Child node is the root node of a ToggleGroup, so it should be a ClassElement::Group + ASSERT_EQ(child.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node has the correct parent + ASSERT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); + } + if (childName.compare("ToggleGroupInt") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(child.GetElementEditMetadata()->IsClassElement()); + // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup + ASSERT_NE(child.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node was assigned to the appropriate group + ASSERT_EQ(child.GetGroupElementMetadata()->m_description, "Group Toggle"); + // Ensuring that this node has the correct parent + ASSERT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); + } + } + } + + TEST_F(InstanceDataHierarchyGroupTestFixture, TestNestedGroups) + { + using namespace AzToolsFramework; + + // Setting up the data node hierarchy + AZ::SerializeContext serializeContext; + serializeContext.CreateEditContext(); + Entity::Reflect(&serializeContext); + GroupTestComponent::Reflect(&serializeContext); + + AZStd::unique_ptr testEntity1(new AZ::Entity()); + testEntity1->CreateComponent(); + + InstanceDataHierarchy instanceDataHierarchy; + instanceDataHierarchy.AddRootInstance(testEntity1.get()); + instanceDataHierarchy.Build(&serializeContext, 0); + + // Adding the nodes to a node stack + auto rootNode = instanceDataHierarchy.GetRootNode(); + AZStd::stack nodeStack; + nodeStack.push(rootNode); + InstanceDataNode* componentNode1 = nullptr; + while (!nodeStack.empty()) + { + InstanceDataNode* node = nodeStack.top(); + nodeStack.pop(); + if (node->GetClassMetadata()->m_typeId == AZ::AzTypeInfo::Uuid()) + { + componentNode1 = node; + break; + } + for (InstanceDataNode& child : node->GetChildren()) + { + nodeStack.push(&child); + } + } + // Iterating through the children in the instance data hierarchy to verify their properties + ASSERT_TRUE(componentNode1 != nullptr); + for (auto child : componentNode1->GetChildren()) + { + AZStd::string childName(child.GetElementMetadata()->m_name); + if (childName.compare("SubDataNormal") == 0) + { + for (InstanceDataNode& subChild : child.GetChildren()) + { + childName = subChild.GetElementMetadata()->m_name; + if (childName.compare("SubInt") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); + // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup + ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node was assigned to the appropriate group + ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "Normal SubGroup"); + // Ensuring that this node has the correct parent + ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + } + if (childName.compare("SubToggle") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); + // Child node is the root node of a ToggleGroup, so it should be a ClassElement::Group + ASSERT_EQ(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node has the correct parent + ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + } + if (childName.compare("SubFloat") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); + // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup + ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node was assigned to the appropriate group + ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "SubGroup Toggle"); + // Ensuring that this node has the correct parent + ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + } + } + } + if (childName.compare("SubDataToggle") == 0) + { + for (InstanceDataNode& subChild : child.GetChildren()) + { + childName = subChild.GetElementMetadata()->m_name; + if (childName.compare("SubInt") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); + // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup + ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node was assigned to the appropriate group + ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "Normal SubGroup"); + // Ensuring that this node has the correct parent + ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + } + if (childName.compare("SubToggle") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); + // Child node is the root node of a ToggleGroup, so it should be a ClassElement::Group + ASSERT_EQ(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node has the correct parent + ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + } + if (childName.compare("SubFloat") == 0) + { + // False for any child node with serializable data + ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); + // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup + ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + // Ensuring that this node was assigned to the appropriate group + ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "SubGroup Toggle"); + // Ensuring that this node has the correct parent + ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + } + } + } + } + } + } // namespace UnitTest diff --git a/Gems/GradientSignal/Code/Source/GradientSampler.cpp b/Gems/GradientSignal/Code/Source/GradientSampler.cpp index a0a23ffe68..c89a63790a 100644 --- a/Gems/GradientSignal/Code/Source/GradientSampler.cpp +++ b/Gems/GradientSignal/Code/Source/GradientSampler.cpp @@ -62,8 +62,9 @@ namespace GradientSignal ->DataElement(0, &GradientSampler::m_invertInput, "Invert Input", "") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) - ->ClassElement(AZ::Edit::ClassElements::Group, "Enable Transform", &GradientSampler::m_enableTransform) + ->GroupElementToggle("Enable Transform", &GradientSampler::m_enableTransform) ->Attribute(AZ::Edit::Attributes::AutoExpand, false) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(0, &GradientSampler::m_translate, "Translate", "") ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) @@ -74,8 +75,9 @@ namespace GradientSignal ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) - ->ClassElement(AZ::Edit::ClassElements::Group, "Enable Levels", &GradientSampler::m_enableLevels) + ->GroupElementToggle("Enable Levels", &GradientSampler::m_enableLevels) ->Attribute(AZ::Edit::Attributes::AutoExpand, false) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_inputMid, "Input Mid", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 10.0f) From 63cbb69797791a1490e4ae35b9643cacc4c749e0 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Tue, 13 Jul 2021 15:05:27 -0700 Subject: [PATCH 006/157] Update previous transform to prevent jitter from lerping Signed-off-by: puvvadar --- .../Code/Source/Components/NetworkTransformComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index e956245724..7305c1f94e 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -91,6 +91,7 @@ namespace Multiplayer blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); blendTransform.SetUniformScale(AZ::Lerp(m_previousTransform.GetUniformScale(), m_targetTransform.GetUniformScale(), blendFactor)); GetTransformComponent()->SetWorldTM(blendTransform); + m_previousTransform = blendTransform; } } From fed37e8e6de37fc9f15700f2a2e33f5d000edef7 Mon Sep 17 00:00:00 2001 From: dtamkin1 Date: Tue, 13 Jul 2021 18:02:25 -0500 Subject: [PATCH 007/157] Removed the ChangeNotify event in each attribute Signed-off-by: dtamkin1 --- Gems/GradientSignal/Code/Source/GradientSampler.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Gems/GradientSignal/Code/Source/GradientSampler.cpp b/Gems/GradientSignal/Code/Source/GradientSampler.cpp index c89a63790a..bf0260374b 100644 --- a/Gems/GradientSignal/Code/Source/GradientSampler.cpp +++ b/Gems/GradientSignal/Code/Source/GradientSampler.cpp @@ -64,45 +64,35 @@ namespace GradientSignal ->GroupElementToggle("Enable Transform", &GradientSampler::m_enableTransform) ->Attribute(AZ::Edit::Attributes::AutoExpand, false) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(0, &GradientSampler::m_translate, "Translate", "") ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(0, &GradientSampler::m_scale, "Scale", "") ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(0, &GradientSampler::m_rotate, "Rotate", "Rotation in degrees.") ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreTransformSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->GroupElementToggle("Enable Levels", &GradientSampler::m_enableLevels) ->Attribute(AZ::Edit::Attributes::AutoExpand, false) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_inputMid, "Input Mid", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 10.0f) ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreLevelSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_inputMin, "Input Min", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 1.0f) ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreLevelSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_inputMax, "Input Max", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 1.0f) ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreLevelSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_outputMin, "Output Min", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 1.0f) ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreLevelSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->DataElement(AZ::Edit::UIHandlers::Slider, &GradientSampler::m_outputMax, "Output Max", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 1.0f) ->Attribute(AZ::Edit::Attributes::ReadOnly, &GradientSampler::AreLevelSettingsDisabled) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &GradientSampler::ChangeNotify) ->ClassElement(AZ::Edit::ClassElements::Group, "Preview (Inbound)") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) From 539fb8200990a876a6ba921e6122c99e1ac26845 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:40:49 -0700 Subject: [PATCH 008/157] remove smoke tag from scriptcanvas tests Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 83a3456a1c..9b01064e31 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -112,7 +112,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::ScriptCanvasTesting.Editor.Tests - TEST_SUITE smoke ) endif() From 41dd7054b7a43c3a2c429fdb616746262716d9ea Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:52:06 -0700 Subject: [PATCH 009/157] Restore BCO destructor delete Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../ScriptCanvas/Data/BehaviorContextObject.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h index 4980fdd37b..51d61f9934 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Data/BehaviorContextObject.h @@ -36,8 +36,7 @@ namespace ScriptCanvas static void Reflect(AZ::ReflectContext* reflection); static BehaviorContextObjectPtr Create(const AZ::BehaviorClass& behaviorClass, const void* value = nullptr); - static BehaviorContextObjectPtr CreateDeepCopy(const AZ::BehaviorClass& behaviorClass, const BehaviorContextObject* value = nullptr); - + template AZ_INLINE static BehaviorContextObjectPtr Create(const t_Value& value, const AZ::BehaviorClass& behaviorClass); @@ -116,6 +115,8 @@ namespace ScriptCanvas BehaviorContextObject& operator=(const BehaviorContextObject&) = delete; + BehaviorContextObject(const BehaviorContextObject&) = delete; + // copy ctor AZ_FORCE_INLINE BehaviorContextObject(const void* source, const AnyTypeInfo& typeInfo, AZ::u32 flags); @@ -133,13 +134,6 @@ namespace ScriptCanvas AZ_FORCE_INLINE void add_ref(); void release(); - - public: - // no copying allowed, this is here to allow compile time compatibility with storage in of BehaviorContextObjectPtr AZStd::any, only - AZ_FORCE_INLINE BehaviorContextObject(const BehaviorContextObject&) - { - AZ_Assert(false, "no copying allowed, this is here to allow storage in of BehaviorContextObjectPtr AZStd::any, only"); - } }; AZ_FORCE_INLINE BehaviorContextObject::BehaviorContextObject(const void* value, const AnyTypeInfo& typeInfo, AZ::u32 flags) From 7dcdd3cb465c09e71f1f5dc5d788a8d8b7849742 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 13 Jul 2021 21:20:52 -0700 Subject: [PATCH 010/157] remove the deliberate failure test Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp index db3d2223d6..fedb1fc4d1 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp @@ -83,11 +83,6 @@ public: } }; -TEST_F(ScriptCanvasTestFixture, ProveError) -{ - EXPECT_TRUE(false); -} - TEST_F(ScriptCanvasTestFixture, ParseErrorOnKnownNull) { ExpectParseError("LY_SC_UnitTest_ParseErrorOnKnownNull"); From 93cbb7c98186c15427826f639edf8e5abf30499b Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Wed, 14 Jul 2021 10:14:25 +0100 Subject: [PATCH 011/157] Review changes Changed text case, removed ClearText API and added GameStartup motify listening. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- Code/Editor/Controls/ConsoleSCB.cpp | 23 ++++++++++++++++---- Code/Editor/Controls/ConsoleSCB.h | 5 +++-- Code/Editor/EditorPreferencesPageGeneral.cpp | 2 +- Code/Editor/GameEngine.cpp | 6 ----- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Code/Editor/Controls/ConsoleSCB.cpp b/Code/Editor/Controls/ConsoleSCB.cpp index 32731b7317..3498476797 100644 --- a/Code/Editor/Controls/ConsoleSCB.cpp +++ b/Code/Editor/Controls/ConsoleSCB.cpp @@ -337,6 +337,8 @@ CConsoleSCB::CConsoleSCB(QWidget* parent) connect(findPreviousAction, &QAction::triggered, this, &CConsoleSCB::findPrevious); ui->findPrevButton->addAction(findPreviousAction); + GetIEditor()->RegisterNotifyListener(this); + connect(ui->button, &QPushButton::clicked, this, &CConsoleSCB::showVariableEditor); connect(ui->findButton, &QPushButton::clicked, this, &CConsoleSCB::toggleConsoleSearch); connect(ui->textEdit, &ConsoleTextEdit::searchBarRequested, this, [this] @@ -375,6 +377,8 @@ CConsoleSCB::~CConsoleSCB() { AzToolsFramework::EditorPreferencesNotificationBus::Handler::BusDisconnect(); + GetIEditor()->UnregisterNotifyListener(this); + s_consoleSCB = nullptr; CLogFile::AttachEditBox(nullptr); } @@ -537,10 +541,6 @@ void CConsoleSCB::AddToPendingLines(const QString& text, bool bNewLine) s_pendingLines.push_back({ text, bNewLine }); } -void CConsoleSCB::ClearText() -{ - ui->textEdit->clear(); -} /** * When a CVar variable is updated, we need to tell alert our console variables * pane so it can update the corresponding row @@ -1355,4 +1355,19 @@ CConsoleSCB* CConsoleSCB::GetCreatedInstance() return s_consoleSCB; } +void CConsoleSCB::OnEditorNotifyEvent(EEditorNotifyEvent event) +{ + switch (event) + { + case eNotify_OnBeginGameMode: + if (gSettings.clearConsoleOnGameModeStart) + { + ui->textEdit->clear(); + } + break; + default: + break; + } +} + #include diff --git a/Code/Editor/Controls/ConsoleSCB.h b/Code/Editor/Controls/ConsoleSCB.h index d561e5f5a6..a62c1009b0 100644 --- a/Code/Editor/Controls/ConsoleSCB.h +++ b/Code/Editor/Controls/ConsoleSCB.h @@ -158,6 +158,7 @@ private: class CConsoleSCB : public QWidget , private AzToolsFramework::EditorPreferencesNotificationBus::Handler + , public IEditorNotifyListener { Q_OBJECT public: @@ -174,8 +175,6 @@ public: static void AddToPendingLines(const QString& text, bool bNewLine); // call this function instead of AddToConsole() until an instance of CConsoleSCB exists to prevent messages from getting lost - void ClearText(); - // EditorPreferencesNotificationBus... void OnEditorPreferencesChanged() override; @@ -188,6 +187,8 @@ private Q_SLOTS: void findNext(); private: + void OnEditorNotifyEvent(EEditorNotifyEvent event) override; + QScopedPointer ui; int m_richEditTextLength; diff --git a/Code/Editor/EditorPreferencesPageGeneral.cpp b/Code/Editor/EditorPreferencesPageGeneral.cpp index cf4a430c7e..046a546f59 100644 --- a/Code/Editor/EditorPreferencesPageGeneral.cpp +++ b/Code/Editor/EditorPreferencesPageGeneral.cpp @@ -78,7 +78,7 @@ void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize) ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_applyConfigSpec, "Hide objects by config spec", "Hide objects by config spec") ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_enableSourceControl, "Enable Source Control", "Enable Source Control") ->DataElement( - AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_clearConsoleOnGameModeStart, "Clear Console at Game Startup", "Clear Console when Game Mode Starts") + AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_clearConsoleOnGameModeStart, "Clear Console at game startup", "Clear Console when game mode starts") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &GeneralSettings::m_consoleBackgroundColorTheme, "Console Background", "Console Background") ->EnumAttribute(AzToolsFramework::ConsoleColorTheme::Light, "Light") ->EnumAttribute(AzToolsFramework::ConsoleColorTheme::Dark, "Dark") diff --git a/Code/Editor/GameEngine.cpp b/Code/Editor/GameEngine.cpp index e77d44d98e..c4fd38afc9 100644 --- a/Code/Editor/GameEngine.cpp +++ b/Code/Editor/GameEngine.cpp @@ -29,7 +29,6 @@ // Editor #include "IEditorImpl.h" -#include "Controls/ConsoleSCB.h" #include "CryEditDoc.h" #include "Settings.h" @@ -567,11 +566,6 @@ void CGameEngine::SwitchToInGame() wait.acquire(); } - if (gSettings.clearConsoleOnGameModeStart) - { - CConsoleSCB::GetCreatedInstance()->ClearText(); - } - GetIEditor()->Notify(eNotify_OnBeginGameMode); m_pISystem->GetIMovieSystem()->EnablePhysicsEvents(true); From c6f03cbb098a474a17a78cee4205f1248e7c7d9b Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 14 Jul 2021 12:50:15 -0700 Subject: [PATCH 012/157] Removed superflous translation asset registration Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/GraphCanvas/Code/Source/GraphCanvas.cpp | 29 -------------------- Gems/GraphCanvas/Code/Source/GraphCanvas.h | 1 - 2 files changed, 30 deletions(-) diff --git a/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp b/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp index 011548ce5a..be44908cb8 100644 --- a/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp +++ b/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp @@ -190,7 +190,6 @@ namespace GraphCanvas void GraphCanvasSystemComponent::Activate() { - RegisterAssetHandler(); RegisterTranslationBuilder(); AzFramework::AssetCatalogEventBus::Handler::BusConnect(); @@ -385,34 +384,6 @@ namespace GraphCanvas AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, collectAssetsCb, postEnumerateCb); } - void GraphCanvasSystemComponent::RegisterAssetHandler() - { - AZ::Data::AssetType assetType(azrtti_typeid()); - if (AZ::Data::AssetManager::Instance().GetHandler(assetType)) - { - return; // Asset Type already handled - } - - auto* catalogBus = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); - if (catalogBus) - { - // Register asset types the asset DB should query our catalog for. - catalogBus->AddAssetType(assetType); - - // Build the catalog (scan). - catalogBus->AddExtension(".names"); - } - - m_assetHandler = AZStd::make_unique(); - AZ::Data::AssetManager::Instance().RegisterHandler(m_assetHandler.get(), assetType); - - // Use AssetCatalog service to register ScriptEvent asset type and extension - 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()); - - } - void GraphCanvasSystemComponent::UnregisterAssetHandler() { if (m_assetHandler) diff --git a/Gems/GraphCanvas/Code/Source/GraphCanvas.h b/Gems/GraphCanvas/Code/Source/GraphCanvas.h index ddb29b18c0..2e5b200a1b 100644 --- a/Gems/GraphCanvas/Code/Source/GraphCanvas.h +++ b/Gems/GraphCanvas/Code/Source/GraphCanvas.h @@ -82,7 +82,6 @@ namespace GraphCanvas void RegisterTranslationBuilder(); - void RegisterAssetHandler(); void UnregisterAssetHandler(); TranslationAssetWorker m_translationAssetWorker; AZStd::vector m_translationAssets; From e2c147762900cec9c59302f950d4088e4eee8770 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 15 Jul 2021 09:46:51 -0700 Subject: [PATCH 013/157] fix for dependency job key on ScriptEvents from SC builder Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../AzCore/Debug/StackTracer_Windows.cpp | 2 +- .../Builder/ScriptCanvasBuilderWorker.cpp | 29 ++++++++++++++----- .../ScriptCanvasBuilderWorkerUtility.cpp | 2 +- .../ScriptCanvas/Core/SubgraphInterface.cpp | 6 ---- .../ScriptCanvas/Core/SubgraphInterface.h | 2 -- .../ScriptCanvas/Grammar/Primitives.cpp | 4 +-- .../Grammar/PrimitivesDeclarations.h | 2 +- .../Builder/ScriptEventsBuilderWorker.cpp | 2 +- .../Include/ScriptEvents/ScriptEventsAsset.h | 2 ++ 9 files changed, 29 insertions(+), 22 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp index a40dd2daac..dcc55cfcf6 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp @@ -38,7 +38,7 @@ namespace AZ { struct SymbolStorageDynamicallyLoadedModules { size_t m_size; - DynamicallyLoadedModuleInfo m_modules[1028]; + DynamicallyLoadedModuleInfo m_modules[1024]; SymbolStorageDynamicallyLoadedModules() : m_size(0) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp index b9d1dd5a7c..3377cea0e8 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.cpp @@ -82,23 +82,35 @@ namespace ScriptCanvasBuilder m_processEditorAssetDependencies.clear(); - auto assetFilter = [this, &response](const AZ::Data::AssetFilterInfo& filterInfo) + AZStd::unordered_multimap jobDependenciesByKey; + + auto assetFilter = [this, &jobDependenciesByKey](const AZ::Data::AssetFilterInfo& filterInfo) { // force load these before processing if (filterInfo.m_assetType == azrtti_typeid() - || filterInfo.m_assetType == azrtti_typeid()) + || filterInfo.m_assetType == azrtti_typeid()) { this->m_processEditorAssetDependencies.push_back(filterInfo); } // these trigger re-processing - if (filterInfo.m_assetType == azrtti_typeid() - || filterInfo.m_assetType == azrtti_typeid() - || filterInfo.m_assetType == azrtti_typeid()) + if (filterInfo.m_assetType == azrtti_typeid()) + { + AZ_Error("ScriptCanvas", false, "ScriptAsset Reference in a graph detected"); + } + + if (filterInfo.m_assetType == azrtti_typeid()) { AssetBuilderSDK::SourceFileDependency dependency; dependency.m_sourceFileDependencyUUID = filterInfo.m_assetId.m_guid; - response.m_sourceFileDependencyList.push_back(dependency); + jobDependenciesByKey.insert({ ScriptEvents::k_builderJobKey, dependency }); + } + + if (filterInfo.m_assetType == azrtti_typeid()) + { + AssetBuilderSDK::SourceFileDependency dependency; + dependency.m_sourceFileDependencyUUID = filterInfo.m_assetId.m_guid; + jobDependenciesByKey.insert({ s_scriptCanvasProcessJobKey, dependency }); } // Asset filter always returns false to prevent parsing dependencies, but makes note of the script canvas dependencies @@ -163,9 +175,10 @@ namespace ScriptCanvasBuilder jobDescriptor.m_additionalFingerprintInfo = AZStd::string(GetFingerprintString()).append("|").append(AZStd::to_string(static_cast(fingerprint))); // Graph process job needs to wait until its dependency asset job finished - for (const auto& processingDependency : response.m_sourceFileDependencyList) + for (const auto& processingDependency : jobDependenciesByKey) { - jobDescriptor.m_jobDependencyList.emplace_back(s_scriptCanvasProcessJobKey, info.m_identifier.c_str(), AssetBuilderSDK::JobDependencyType::Order, processingDependency); + response.m_sourceFileDependencyList.push_back(processingDependency.second); + jobDescriptor.m_jobDependencyList.emplace_back(processingDependency.first, info.m_identifier.c_str(), AssetBuilderSDK::JobDependencyType::Order, processingDependency.second); } response.m_createJobOutputs.push_back(jobDescriptor); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp index 7f6269a698..375c773e7d 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorkerUtility.cpp @@ -97,7 +97,7 @@ namespace ScriptCanvasBuilder bool pathFound = false; AZStd::string relativePath; AzToolsFramework::AssetSystemRequestBus::BroadcastResult - (pathFound + ( pathFound , &AzToolsFramework::AssetSystem::AssetSystemRequest::GetRelativeProductPathFromFullSourceOrProductPath , fullPath.c_str(), relativePath); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp index a6959ae209..3b7ec9c77f 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.cpp @@ -802,12 +802,6 @@ namespace ScriptCanvas m_namespacePath = namespacePath; } - void SubgraphInterface::TakeNamespacePath(NamespacePath&& namespacePath) - { - m_namespacePath = AZStd::move(namespacePath); - } - - AZStd::string SubgraphInterface::ToExecutionString() const { AZStd::string result; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.h index 19ff2e1d65..6dac3cf7a4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/SubgraphInterface.h @@ -235,8 +235,6 @@ namespace ScriptCanvas void SetNamespacePath(const NamespacePath& namespacePath); - void TakeNamespacePath(NamespacePath&& namespacePath); - AZStd::string ToExecutionString() const; private: diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.cpp index aa11d01fdf..dca4f41933 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.cpp @@ -234,7 +234,7 @@ namespace ScriptCanvas const VariableData Source::k_emptyVardata{}; Source::Source - (const Graph& graph + ( const Graph& graph , const AZ::Data::AssetId& id , const GraphData& graphData , const VariableData& variableData @@ -276,7 +276,7 @@ namespace ScriptCanvas AzFramework::StringFunc::Path::StripExtension(namespacePath); return AZ::Success(Source - (*request.graph + (*request.graph , request.scriptAssetId , *graphData , *sourceVariableData diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h index 12f4199bc4..0c245de2a5 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesDeclarations.h @@ -289,7 +289,7 @@ namespace ScriptCanvas Source() = default; Source - (const Graph& graph + ( const Graph& graph , const AZ::Data::AssetId& id , const GraphData& graphData , const VariableData& variableData diff --git a/Gems/ScriptEvents/Code/Builder/ScriptEventsBuilderWorker.cpp b/Gems/ScriptEvents/Code/Builder/ScriptEventsBuilderWorker.cpp index 2357fb38a5..8465b28936 100644 --- a/Gems/ScriptEvents/Code/Builder/ScriptEventsBuilderWorker.cpp +++ b/Gems/ScriptEvents/Code/Builder/ScriptEventsBuilderWorker.cpp @@ -120,7 +120,7 @@ namespace ScriptEventsBuilder AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = 2; jobDescriptor.m_critical = true; - jobDescriptor.m_jobKey = "Script Events"; + jobDescriptor.m_jobKey = ScriptEvents::k_builderJobKey; jobDescriptor.SetPlatformIdentifier(info.m_identifier.data()); jobDescriptor.m_additionalFingerprintInfo = GetFingerprintString(); diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAsset.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAsset.h index cfa8253923..8178f1c9e0 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAsset.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/ScriptEventsAsset.h @@ -21,6 +21,8 @@ namespace ScriptEvents { + constexpr const char* k_builderJobKey = "Script Events"; + class ScriptEventsAsset : public AZ::Data::AssetData { From ab6a98db44013f6d4182d051dc009570f24f9231 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Thu, 15 Jul 2021 09:52:40 -0700 Subject: [PATCH 014/157] restoring smoke lable to SC unit tests pending Linux filename fix Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 9b01064e31..83a3456a1c 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -112,6 +112,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::ScriptCanvasTesting.Editor.Tests + TEST_SUITE smoke ) endif() From 7950c2b54906b2976b44c097403eb8607042f3a6 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 15 Jul 2021 13:45:49 -0700 Subject: [PATCH 015/157] Add target host frame ID tracking to network transform Signed-off-by: puvvadar --- .../Components/NetworkTransformComponent.h | 4 +++ .../Components/NetworkTransformComponent.cpp | 27 ++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h index 5575de9b0d..c37c28db62 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h @@ -35,6 +35,8 @@ namespace Multiplayer void OnScaleChangedEvent(float scale); void OnResetCountChangedEvent(); + void UpdateTargetHostFrameId(); + AZ::Transform m_previousTransform = AZ::Transform::CreateIdentity(); AZ::Transform m_targetTransform = AZ::Transform::CreateIdentity(); @@ -44,6 +46,8 @@ namespace Multiplayer AZ::Event::Handler m_resetCountEventHandler; EntityPreRenderEvent::Handler m_entityPreRenderEventHandler; + + Multiplayer::HostFrameId m_targetHostFrameId = HostFrameId(0); }; class NetworkTransformComponentController diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index 7305c1f94e..54b24ccf10 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -60,18 +60,21 @@ namespace Multiplayer { m_previousTransform.SetRotation(m_targetTransform.GetRotation()); m_targetTransform.SetRotation(rotation); + UpdateTargetHostFrameId(); } void NetworkTransformComponent::OnTranslationChangedEvent(const AZ::Vector3& translation) { m_previousTransform.SetTranslation(m_targetTransform.GetTranslation()); m_targetTransform.SetTranslation(translation); + UpdateTargetHostFrameId(); } void NetworkTransformComponent::OnScaleChangedEvent(float scale) { m_previousTransform.SetUniformScale(m_targetTransform.GetUniformScale()); m_targetTransform.SetUniformScale(scale); + UpdateTargetHostFrameId(); } void NetworkTransformComponent::OnResetCountChangedEvent() @@ -82,16 +85,32 @@ namespace Multiplayer m_previousTransform = m_targetTransform; } + void NetworkTransformComponent::UpdateTargetHostFrameId() + { + HostFrameId currentHostFrameId = Multiplayer::GetNetworkTime()->GetHostFrameId(); + if (currentHostFrameId > m_targetHostFrameId) + { + m_targetHostFrameId = currentHostFrameId; + } + } + void NetworkTransformComponent::OnPreRender([[maybe_unused]] float deltaTime, float blendFactor) { if (!HasController()) { AZ::Transform blendTransform; - blendTransform.SetRotation(m_previousTransform.GetRotation().Slerp(m_targetTransform.GetRotation(), blendFactor)); - blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); - blendTransform.SetUniformScale(AZ::Lerp(m_previousTransform.GetUniformScale(), m_targetTransform.GetUniformScale(), blendFactor)); + if (Multiplayer::GetNetworkTime() && Multiplayer::GetNetworkTime()->GetHostFrameId() > m_targetHostFrameId) + { + m_previousTransform = m_targetTransform; + blendTransform = m_targetTransform; + } + else + { + blendTransform.SetRotation(m_previousTransform.GetRotation().Slerp(m_targetTransform.GetRotation(), blendFactor)); + blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); + blendTransform.SetUniformScale(AZ::Lerp(m_previousTransform.GetUniformScale(), m_targetTransform.GetUniformScale(), blendFactor)); + } GetTransformComponent()->SetWorldTM(blendTransform); - m_previousTransform = blendTransform; } } From ebe326f6e9cbbd2cf49e6aa791494dcc86947a8e Mon Sep 17 00:00:00 2001 From: puvvadar Date: Tue, 20 Jul 2021 14:12:06 -0700 Subject: [PATCH 016/157] Add server side accounting for blend factor Signed-off-by: puvvadar --- .../Code/Include/Multiplayer/IMultiplayer.h | 2 ++ .../Multiplayer/NetworkInput/NetworkInput.h | 4 ++++ .../LocalPredictionPlayerInputComponent.cpp | 6 +++++- .../Code/Source/MultiplayerSystemComponent.cpp | 5 +++++ .../Code/Source/MultiplayerSystemComponent.h | 1 + .../Code/Source/NetworkInput/NetworkInput.cpp | 14 +++++++++++++- 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h index 182173c464..35af0034e5 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h @@ -121,6 +121,8 @@ namespace Multiplayer //! @return the current server time in milliseconds virtual AZ::TimeMs GetCurrentHostTimeMs() const = 0; + virtual float GetCurrentBlendFactor() const = 0; + //! Returns the network time instance bound to this multiplayer instance. //! @return pointer to the network time instance bound to this multiplayer instance virtual INetworkTime* GetNetworkTime() = 0; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h index 5d57ea6343..874ccad789 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h @@ -44,6 +44,9 @@ namespace Multiplayer AZ::TimeMs GetHostTimeMs() const; AZ::TimeMs& ModifyHostTimeMs(); + void SetHostBlendFactor(float hostBlendFactor); + float GetHostBlendFactor() const; + void AttachNetBindComponent(NetBindComponent* netBindComponent); bool Serialize(AzNetworking::ISerializer& serializer); @@ -72,6 +75,7 @@ namespace Multiplayer ClientInputId m_inputId = ClientInputId{ 0 }; HostFrameId m_hostFrameId = InvalidHostFrameId; AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 }; + float m_hostBlendFactor = 0.f; ConstNetworkEntityHandle m_owner; bool m_wasAttached = false; }; diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 0b4fa99111..da299401d8 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -154,9 +154,12 @@ namespace Multiplayer // Discard move input events, client may be speed hacking if (m_clientBankedTime < sv_MaxBankTimeWindowSec) { + // Client blends from previous frame to target so here we subtract blend factor to get to that state + const float adjustedBlendFactor = std::pow(0.2f, input.GetHostBlendFactor()); + const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * adjustedBlendFactor); m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary { - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, static_cast(clientInputRateSec)); } @@ -498,6 +501,7 @@ namespace Multiplayer input.SetClientInputId(m_clientInputId); input.SetHostFrameId(networkTime->GetHostFrameId()); input.SetHostTimeMs(multiplayer->GetCurrentHostTimeMs()); + input.SetHostBlendFactor(multiplayer->GetCurrentBlendFactor()); // Allow components to form the input for this frame GetNetBindComponent()->CreateInput(input, inputRate); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 0100cfe3d2..16acf45872 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -802,6 +802,11 @@ namespace Multiplayer } } + float MultiplayerSystemComponent::GetCurrentBlendFactor() const + { + return m_renderBlendFactor; + } + INetworkTime* MultiplayerSystemComponent::GetNetworkTime() { return &m_networkTime; diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 7977a39443..5aaa52a7bd 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -112,6 +112,7 @@ namespace Multiplayer void Terminate(AzNetworking::DisconnectReason reason) override; void SendReadyForEntityUpdates(bool readyForEntityUpdates) override; AZ::TimeMs GetCurrentHostTimeMs() const override; + float GetCurrentBlendFactor() const override; INetworkTime* GetNetworkTime() override; INetworkEntityManager* GetNetworkEntityManager() override; void SetFilterEntityManager(IFilterEntityManager* entityFilter) override; diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp index 75889d9f83..33b5a535e0 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp @@ -75,6 +75,16 @@ namespace Multiplayer return m_hostTimeMs; } + void NetworkInput::SetHostBlendFactor(float hostBlendFactor) + { + m_hostBlendFactor = hostBlendFactor; + } + + float NetworkInput::GetHostBlendFactor() const + { + return m_hostBlendFactor; + } + void NetworkInput::AttachNetBindComponent(NetBindComponent* netBindComponent) { m_wasAttached = true; @@ -90,7 +100,8 @@ namespace Multiplayer { if (!serializer.Serialize(m_inputId, "InputId") || !serializer.Serialize(m_hostTimeMs, "HostTimeMs") - || !serializer.Serialize(m_hostFrameId, "HostFrameId")) + || !serializer.Serialize(m_hostFrameId, "HostFrameId") + || !serializer.Serialize(m_hostBlendFactor, "HostBlendFactor")) { return false; } @@ -163,6 +174,7 @@ namespace Multiplayer m_inputId = rhs.m_inputId; m_hostFrameId = rhs.m_hostFrameId; m_hostTimeMs = rhs.m_hostTimeMs; + m_hostBlendFactor = rhs.m_hostBlendFactor; m_componentInputs.resize(rhs.m_componentInputs.size()); for (int32_t i = 0; i < rhs.m_componentInputs.size(); ++i) { From 69d5f64bb7c209e8bcd3b680ec6f1dc371d3294b Mon Sep 17 00:00:00 2001 From: puvvadar Date: Tue, 20 Jul 2021 14:21:00 -0700 Subject: [PATCH 017/157] Add function documentation for GetCurrentBlendFactor Signed-off-by: puvvadar --- Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h index 35af0034e5..23885e6c64 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h @@ -121,6 +121,9 @@ namespace Multiplayer //! @return the current server time in milliseconds virtual AZ::TimeMs GetCurrentHostTimeMs() const = 0; + //! Returns the current blend factor for client side interpolation + //! This value is only relevant on the client and is used to smooth between host frames + //! @return the current blend factor virtual float GetCurrentBlendFactor() const = 0; //! Returns the network time instance bound to this multiplayer instance. From b55bad496d2e6516bac233bc148a269002774733 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 22 Jul 2021 13:49:05 -0700 Subject: [PATCH 018/157] Adding rewindable mechanisms to support interpolation Signed-off-by: puvvadar --- .../Code/Include/Multiplayer/IMultiplayer.h | 4 +++- .../Include/Multiplayer/MultiplayerTypes.h | 3 +++ .../Multiplayer/NetworkTime/INetworkTime.h | 8 ++++++++ .../Multiplayer/NetworkTime/RewindableObject.h | 4 ++++ .../NetworkTime/RewindableObject.inl | 6 ++++++ .../LocalPredictionPlayerInputComponent.cpp | 11 ++++++----- .../Code/Source/NetworkTime/NetworkTime.cpp | 11 +++++++++++ .../Code/Source/NetworkTime/NetworkTime.h | 3 +++ .../Code/Tests/RewindableContainerTests.cpp | 8 ++++---- .../Code/Tests/RewindableObjectTests.cpp | 18 +++++++++--------- 10 files changed, 57 insertions(+), 19 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h index 23885e6c64..17d2cffafd 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h @@ -186,18 +186,20 @@ namespace Multiplayer class ScopedAlterTime final { public: - inline ScopedAlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId connectionId) + inline ScopedAlterTime(HostFrameId frameId, AZ::TimeMs timeMs, float blendFactor, AzNetworking::ConnectionId connectionId) { INetworkTime* time = GetNetworkTime(); m_previousHostFrameId = time->GetHostFrameId(); m_previousHostTimeMs = time->GetHostTimeMs(); m_previousRewindConnectionId = time->GetRewindingConnectionId(); time->AlterTime(frameId, timeMs, connectionId); + time->AlterBlendFactor(blendFactor); } inline ~ScopedAlterTime() { INetworkTime* time = GetNetworkTime(); time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousRewindConnectionId); + time->AlterBlendFactor(DefaultBlendFactor); } private: HostFrameId m_previousHostFrameId = InvalidHostFrameId; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h index 9f81ca97a9..4fdf428e37 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h @@ -21,6 +21,9 @@ namespace Multiplayer //! The default number of rewindable samples for us to store. static constexpr uint32_t RewindHistorySize = 128; + //! The default blend factor for ScopedAlterTime + static constexpr float DefaultBlendFactor = 1.f; + AZ_TYPE_SAFE_INTEGRAL(HostId, uint32_t); static constexpr HostId InvalidHostId = static_cast(-1); diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h index c88c971636..5e5e7aab25 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h @@ -42,6 +42,10 @@ namespace Multiplayer //! @return the hosts current timeMs virtual AZ::TimeMs GetHostTimeMs() const = 0; + //! Retrieves the hosts current blend factor (may be rewound on the server during backward reconciliation). + //! @return the hosts current blend factor + virtual float GetHostBlendFactor() const = 0; + //! Get the controlling connection that may be currently altering global game time. //! Note this abstraction is required at a relatively high level to allow for 'don't rewind the shooter' semantics //! @return the ConnectionId of the connection requesting the rewind operation @@ -59,6 +63,10 @@ namespace Multiplayer //! @param rewindConnectionId the rewinding ConnectionId virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) = 0; + //! Alters the current Host blend factor. Used to drive interpolation in rewound states. + //! @param blendFactor the blend factor to use + virtual void AlterBlendFactor(float blendFactor) = 0; + //! Syncs all entities contained within a volume to the current rewind state. //! @param rewindVolume the volume to rewind entities within (needed for physics entities) virtual void SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) = 0; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h index 796eec5412..2eff6d8bb0 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h @@ -59,6 +59,10 @@ namespace Multiplayer //! @return value in const base type form const BASE_TYPE& Get() const; + //! Const base type retriever for one host frame behind Get(). + //! @return value in const base type form + const BASE_TYPE& GetPrevious() const; + //! Base type retriever. //! @return value in base type form BASE_TYPE& Modify(); diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl index dc8d98fb45..7027069b27 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl @@ -65,6 +65,12 @@ namespace Multiplayer return GetValueForTime(GetCurrentTimeForProperty()); } + template + inline const BASE_TYPE& RewindableObject::GetPrevious() const + { + return GetValueForTime(GetCurrentTimeForProperty() - HostFrameId(1)); + } + template inline BASE_TYPE& RewindableObject::Modify() { diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index da299401d8..15945b12ff 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -155,11 +155,12 @@ namespace Multiplayer if (m_clientBankedTime < sv_MaxBankTimeWindowSec) { // Client blends from previous frame to target so here we subtract blend factor to get to that state - const float adjustedBlendFactor = std::pow(0.2f, input.GetHostBlendFactor()); + const float blendFactor = AZStd::max(0.f, input.GetHostBlendFactor()); + const float adjustedBlendFactor = std::pow(0.2f, blendFactor); const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * adjustedBlendFactor); m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary { - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, invokingConnection->GetConnectionId()); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, static_cast(clientInputRateSec)); } @@ -313,7 +314,7 @@ namespace Multiplayer ++ModifyLastInputId(); input.SetClientInputId(GetLastInputId()); - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), DefaultBlendFactor, invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, clientInputRateSec); AZLOG @@ -393,7 +394,7 @@ namespace Multiplayer { // Reprocess the input for this frame NetworkInput& input = m_inputHistory[replayIndex]; - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), DefaultBlendFactor, invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, clientInputRateSec); AZLOG @@ -576,7 +577,7 @@ namespace Multiplayer NetworkInput& input = m_lastInputReceived[0]; { - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), AzNetworking::InvalidConnectionId); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), DefaultBlendFactor, AzNetworking::InvalidConnectionId); GetNetBindComponent()->ProcessInput(input, inputRate); } diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp index 88ffa0b5d7..b15125b5d2 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp @@ -54,6 +54,11 @@ namespace Multiplayer return m_hostTimeMs; } + float NetworkTime::GetHostBlendFactor() const + { + return m_hostBlendFactor; + } + AzNetworking::ConnectionId NetworkTime::GetRewindingConnectionId() const { return m_rewindingConnectionId; @@ -71,6 +76,11 @@ namespace Multiplayer m_rewindingConnectionId = rewindConnectionId; } + void NetworkTime::AlterBlendFactor(float blendFactor) + { + m_hostBlendFactor = blendFactor; + } + void NetworkTime::SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) { // Since the vis system doesn't support rewound queries, first query with an expanded volume to catch any fast moving entities @@ -94,6 +104,7 @@ namespace Multiplayer if (networkTransform != nullptr) { + // We're not presently factoring in interpolated position here const AZ::Vector3 rewindCenter = networkTransform->GetTranslation(); // Get the rewound position const AZ::Vector3 rewindOffset = rewindCenter - currentCenter; // Compute offset between rewound and current positions const AZ::Aabb rewoundAabb = currentBounds.GetTranslated(rewindOffset); // Apply offset to the entity aabb diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h index 53c9540843..f6b2907c92 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h @@ -29,9 +29,11 @@ namespace Multiplayer HostFrameId GetUnalteredHostFrameId() const override; void IncrementHostFrameId() override; AZ::TimeMs GetHostTimeMs() const override; + float GetHostBlendFactor() const override; AzNetworking::ConnectionId GetRewindingConnectionId() const override; HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override; void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) override; + void AlterBlendFactor(float blendFactor) override; void SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) override; void ClearRewoundEntities() override; //! @} @@ -43,6 +45,7 @@ namespace Multiplayer HostFrameId m_hostFrameId = HostFrameId{ 0 }; HostFrameId m_unalteredFrameId = HostFrameId{ 0 }; AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 }; + float m_hostBlendFactor = DefaultBlendFactor; AzNetworking::ConnectionId m_rewindingConnectionId = AzNetworking::InvalidConnectionId; }; } diff --git a/Gems/Multiplayer/Code/Tests/RewindableContainerTests.cpp b/Gems/Multiplayer/Code/Tests/RewindableContainerTests.cpp index 2e3a65a5e5..ae56fdcf39 100644 --- a/Gems/Multiplayer/Code/Tests/RewindableContainerTests.cpp +++ b/Gems/Multiplayer/Code/Tests/RewindableContainerTests.cpp @@ -42,7 +42,7 @@ namespace UnitTest // Test rewind for all pushed values and overall size for (uint32_t idx = 0; idx < RewindableContainerSize; ++idx) { - Multiplayer::ScopedAlterTime time(static_cast(idx), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(idx), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(idx + 1, test.size()); EXPECT_EQ(idx, test.back()); } @@ -69,9 +69,9 @@ namespace UnitTest EXPECT_TRUE(test.empty()); // Test rewind for pop_back and clear - Multiplayer::ScopedAlterTime pop_time(static_cast(RewindableContainerSize), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime pop_time(static_cast(RewindableContainerSize), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(RewindableContainerSize - 1, test.size()); - Multiplayer::ScopedAlterTime clear_time(static_cast(RewindableContainerSize + 1), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime clear_time(static_cast(RewindableContainerSize + 1), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(0, test.size()); // Test copy_values and resize_no_construct @@ -99,7 +99,7 @@ namespace UnitTest // Test rewind for all values and overall size for (uint32_t idx = 1; idx <= RewindableContainerSize; ++idx) { - Multiplayer::ScopedAlterTime time(static_cast(idx), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(idx), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); for (uint32_t testIdx = 0; testIdx < RewindableContainerSize; ++testIdx) { if (testIdx < idx) diff --git a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp index 472a1ce148..e992eb6848 100644 --- a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp +++ b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp @@ -38,7 +38,7 @@ namespace UnitTest for (uint32_t i = 0; i < 16; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(i, test); } @@ -51,7 +51,7 @@ namespace UnitTest for (uint32_t i = 16; i < 48; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(i, test); } } @@ -69,7 +69,7 @@ namespace UnitTest { // Note that we didn't actually set any value for time rewindableBufferFrames, so we're testing fetching a value past the last time set - Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(RewindableBufferFrames), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(RewindableBufferFrames - 1, test); } } @@ -92,7 +92,7 @@ namespace UnitTest for (uint32_t i = 0; i < RewindableBufferFrames; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); const Object& value = test; EXPECT_EQ(value.value, i); } @@ -101,19 +101,19 @@ namespace UnitTest TEST_F(RewindableObjectTests, TestBackfillOnLargeTimestep) { Multiplayer::RewindableObject test(0); - Multiplayer::ScopedAlterTime time1(static_cast(0), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time1(static_cast(0), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); test = 1; - Multiplayer::ScopedAlterTime time2(static_cast(31), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time2(static_cast(31), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); test = 2; for (uint32_t i = 0; i < 31; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(i), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(1, test); } - Multiplayer::ScopedAlterTime time3(static_cast(31), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time3(static_cast(31), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(2, test); } @@ -129,7 +129,7 @@ namespace UnitTest for (uint32_t i = 0; i < 1000; ++i) { - Multiplayer::ScopedAlterTime time(static_cast(1000 - i), AZ::TimeMs{ 0 }, AzNetworking::InvalidConnectionId); + Multiplayer::ScopedAlterTime time(static_cast(1000 - i), AZ::TimeMs{ 0 }, 1.f, AzNetworking::InvalidConnectionId); EXPECT_EQ(1000, test); } } From fccb86d5c043b5104c41864d2da3c32b62859946 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Fri, 23 Jul 2021 13:58:58 -0700 Subject: [PATCH 019/157] Check for build process exit status and display log link in more cases. Signed-off-by: AMZN-Phil --- .../Platform/Windows/ProjectBuilderWorker_windows.cpp | 7 +++++-- .../ProjectManager/Source/ProjectBuilderController.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp index a228f58e51..8856e2312a 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectBuilderWorker_windows.cpp @@ -118,7 +118,9 @@ namespace O3DE::ProjectManager } } - if (m_configProjectProcess->exitCode() != 0 || !containsGeneratingDone) + if (m_configProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit + || m_configProjectProcess->exitCode() != 0 + || !containsGeneratingDone) { QString error = tr("Configuring project failed. See log for details."); QStringToAZTracePrint(error); @@ -180,7 +182,8 @@ namespace O3DE::ProjectManager } } - if (m_configProjectProcess->exitCode() != 0) + if (m_configProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit + || m_configProjectProcess->exitCode() != 0) { QString error = tr("Building project failed. See log for details."); QStringToAZTracePrint(error); diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp index e782f0b57f..0ff963e539 100644 --- a/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp @@ -104,7 +104,7 @@ namespace O3DE::ProjectManager QMessageBox::critical(m_parent, tr("Project Failed to Build!"), result); m_projectInfo.m_buildFailed = true; - m_projectInfo.m_logUrl = QUrl(); + m_projectInfo.m_logUrl = QUrl("file:///" + m_worker->GetLogFilePath()); emit NotifyBuildProject(m_projectInfo); } From fcb2a0f95c76e3a55cc93b9b21aa34e88c07b63c Mon Sep 17 00:00:00 2001 From: dtamkin1 Date: Fri, 23 Jul 2021 16:21:07 -0500 Subject: [PATCH 020/157] Reformatted Unit tests to give more information and be more concise, also changed the position of the toggle switch Signed-off-by: dtamkin1 --- .../UI/PropertyEditor/PropertyRowWidget.cpp | 7 +- .../ReflectedPropertyEditor.cpp | 5 +- .../Framework/Tests/InstanceDataHierarchy.cpp | 355 +++++++----------- 3 files changed, 144 insertions(+), 223 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp index e6f2af6a52..7e20642bb8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp @@ -142,7 +142,7 @@ namespace AzToolsFramework m_treeDepth = 0; delete m_dropDownArrow; - if (m_toggleSwitch) + if (m_toggleSwitch != nullptr) { m_handler->DestroyGUI(m_toggleSwitch); m_toggleSwitch = nullptr; @@ -1117,12 +1117,13 @@ namespace AzToolsFramework void PropertyRowWidget::CreateGroupToggleSwitch() { - if (!m_toggleSwitch) + if (m_toggleSwitch == nullptr) { m_handlerName = AZ::Edit::UIHandlers::CheckBox; PropertyTypeRegistrationMessages::Bus::BroadcastResult(m_handler, &PropertyTypeRegistrationMessages::Bus::Events::ResolvePropertyHandler, m_handlerName, azrtti_typeid()); m_toggleSwitch = m_handler->CreateGUI(this); - m_middleLayout->insertWidget(0, m_toggleSwitch, 1); + m_toggleSwitch->setFixedWidth(38); + m_middleLayout->addWidget(m_toggleSwitch, 1, Qt::AlignRight); auto checkBoxCtrl = static_cast(m_toggleSwitch); QObject::connect(checkBoxCtrl, &AzToolsFramework::PropertyCheckBoxCtrl::valueChanged, this, &PropertyRowWidget::OnClickedToggleButton); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp index d16fbb2776..f7c663747e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp @@ -501,6 +501,7 @@ namespace AzToolsFramework // if the node is in a group then create the widget for the group if (groupElementData) { + bool isToggleGroup = false; const char* groupName = groupElementData->m_description; PropertyRowWidget*& widgetEntry = m_groupWidgets[{parent, groupName}]; @@ -526,6 +527,7 @@ namespace AzToolsFramework pHandler->ConsumeAttributes_Internal(toggleSwitch, groupSourceNode); pHandler->ReadValuesIntoGUI_Internal(toggleSwitch, groupSourceNode); widgetEntry->OnValuesUpdated(); + isToggleGroup = true; } widgetEntry->SetLeafIndentation(m_leafIndentation); @@ -534,7 +536,8 @@ namespace AzToolsFramework for (const AZ::Edit::AttributePair& attribute : groupElementData->m_attributes) { - PropertyAttributeReader reader(node->GetParent()->FirstInstance(), attribute.second); + InstanceDataNode* readerNode = (isToggleGroup) ? groupSourceNode : node; + PropertyAttributeReader reader(readerNode->GetParent()->FirstInstance(), attribute.second); QString descriptionOut; bool foundDescription = false; widgetEntry->ConsumeAttribute(attribute.first, reader, true, &descriptionOut, &foundDescription); diff --git a/Code/Framework/Tests/InstanceDataHierarchy.cpp b/Code/Framework/Tests/InstanceDataHierarchy.cpp index 29cf42fb6b..312b057715 100644 --- a/Code/Framework/Tests/InstanceDataHierarchy.cpp +++ b/Code/Framework/Tests/InstanceDataHierarchy.cpp @@ -727,30 +727,22 @@ namespace UnitTest }; - class InstanceDataHierarchyGroupTestFixture - : public AllocatorsFixture - { - public: - InstanceDataHierarchyGroupTestFixture() = default; - }; - - class GroupTestComponent - : public AZ::Component + class GroupTestComponent : public AZ::Component { public: AZ_COMPONENT(GroupTestComponent, "{C088C81D-D59D-43F1-85F8-B2E591BABA36}") GroupTestComponent() = default; - struct SubData + struct SubData { AZ_TYPE_INFO(SubData, "{983316B5-17C0-476E-9CEB-CA749B3ABE5D}"); AZ_CLASS_ALLOCATOR(SubData, AZ::SystemAllocator, 0); SubData() {} - SubData(int v) : m_int(v) {} - SubData(bool b) : m_bool(b) {} - SubData(float f) : m_float(f) {} + explicit SubData(int v) : m_int(v) {} + explicit SubData(bool b) : m_bool(b) {} + explicit SubData(float f) : m_float(f) {} ~SubData() = default; float m_float = 0.f; @@ -803,7 +795,7 @@ namespace UnitTest } } - void Activate() override + void Activate() override { } @@ -821,6 +813,66 @@ namespace UnitTest SubData m_subGroupForToggle; }; + class InstanceDataHierarchyGroupTestFixture : public AllocatorsFixture + { + public: + InstanceDataHierarchyGroupTestFixture() = default; + + AZStd::unique_ptr m_serializeContext; + AZStd::unique_ptr testEntity1; + AzToolsFramework::InstanceDataHierarchy* instanceDataHierarchy; + AzToolsFramework::InstanceDataNode* componentNode1 = nullptr; + + void SetUp() override + { + AllocatorsFixture::SetUp(); + + using AzToolsFramework::InstanceDataHierarchy; + using AzToolsFramework::InstanceDataNode; + + AZ::AllocatorInstance::Create(); + + m_serializeContext.reset(aznew AZ::SerializeContext()); + m_serializeContext.get()->CreateEditContext(); + Entity::Reflect(m_serializeContext.get()); + GroupTestComponent::Reflect(m_serializeContext.get()); + + testEntity1.reset(new AZ::Entity()); + testEntity1->CreateComponent(); + + instanceDataHierarchy = aznew InstanceDataHierarchy(); + instanceDataHierarchy->AddRootInstance(testEntity1.get()); + instanceDataHierarchy->Build(m_serializeContext.get(), 0); + + // Adding the nodes to a node stack + auto rootNode = instanceDataHierarchy->GetRootNode(); + AZStd::stack nodeStack; + nodeStack.push(rootNode); + while (!nodeStack.empty()) + { + InstanceDataNode* node = nodeStack.top(); + nodeStack.pop(); + if (node->GetClassMetadata()->m_typeId == AZ::AzTypeInfo::Uuid()) + { + componentNode1 = node; + break; + } + for (InstanceDataNode& child : node->GetChildren()) + { + nodeStack.push(&child); + } + } + } + + void TearDown() override + { + m_serializeContext.reset(); + testEntity1.reset(); + delete instanceDataHierarchy; + AZ::AllocatorInstance::Destroy(); + AllocatorsFixture::TearDown(); + } + }; class InstanceDataHierarchyKeyedContainerTest : public AllocatorsFixture @@ -1410,243 +1462,108 @@ namespace UnitTest run(); } - TEST_F(InstanceDataHierarchyGroupTestFixture, TestNormalGroups) + // Test to validate that the only ClassElement::Group nodes are ToggleGroups + TEST_F(InstanceDataHierarchyGroupTestFixture, GroupToggleIsClassElementGroup) { - using namespace AzToolsFramework; + using AzToolsFramework::InstanceDataHierarchy; + using AzToolsFramework::InstanceDataNode; - // Setting up the data node hierarchy - AZ::SerializeContext serializeContext; - serializeContext.CreateEditContext(); - Entity::Reflect(&serializeContext); - GroupTestComponent::Reflect(&serializeContext); - - AZStd::unique_ptr testEntity1(new AZ::Entity()); - testEntity1->CreateComponent(); - - InstanceDataHierarchy instanceDataHierarchy; - instanceDataHierarchy.AddRootInstance(testEntity1.get()); - instanceDataHierarchy.Build(&serializeContext, 0); - - // Adding the nodes to a node stack - auto rootNode = instanceDataHierarchy.GetRootNode(); - AZStd::stack nodeStack; - nodeStack.push(rootNode); - InstanceDataNode* componentNode1 = nullptr; - while (!nodeStack.empty()) - { - InstanceDataNode* node = nodeStack.top(); - nodeStack.pop(); - if (node->GetClassMetadata()->m_typeId == AZ::AzTypeInfo::Uuid()) - { - componentNode1 = node; - break; - } - for (InstanceDataNode& child : node->GetChildren()) - { - nodeStack.push(&child); - } - } - // Iterating through the children in the instance data hierarchy to verify their properties - ASSERT_TRUE(componentNode1 != nullptr); - for (auto child : componentNode1->GetChildren()) - { - AZStd::string childName(child.GetElementMetadata()->m_name); - if (childName.compare("GroupFloat") == 0) - { - // False for any child node with serializable data - ASSERT_FALSE(child.GetElementEditMetadata()->IsClassElement()); - // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup - ASSERT_NE(child.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node was assigned to the appropriate group - ASSERT_EQ(child.GetGroupElementMetadata()->m_description, "Normal Group"); - // Ensuring that this node has the correct parent - ASSERT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); - } - } - } - - TEST_F(InstanceDataHierarchyGroupTestFixture, TestToggleGroups) - { - using namespace AzToolsFramework; - - // Setting up the data node hierarchy - AZ::SerializeContext serializeContext; - serializeContext.CreateEditContext(); - Entity::Reflect(&serializeContext); - GroupTestComponent::Reflect(&serializeContext); - - AZStd::unique_ptr testEntity1(new AZ::Entity()); - testEntity1->CreateComponent(); - - InstanceDataHierarchy instanceDataHierarchy; - instanceDataHierarchy.AddRootInstance(testEntity1.get()); - instanceDataHierarchy.Build(&serializeContext, 0); - - // Adding the nodes to a node stack - auto rootNode = instanceDataHierarchy.GetRootNode(); - AZStd::stack nodeStack; - nodeStack.push(rootNode); - InstanceDataNode* componentNode1 = nullptr; - while (!nodeStack.empty()) - { - InstanceDataNode* node = nodeStack.top(); - nodeStack.pop(); - if (node->GetClassMetadata()->m_typeId == AZ::AzTypeInfo::Uuid()) - { - componentNode1 = node; - break; - } - for (InstanceDataNode& child : node->GetChildren()) - { - nodeStack.push(&child); - } - } - // Iterating through the children in the instance data hierarchy to verify their properties - ASSERT_TRUE(componentNode1 != nullptr); for (auto child : componentNode1->GetChildren()) { AZStd::string childName(child.GetElementMetadata()->m_name); if (childName.compare("GroupToggle") == 0) { - // False for any child node with serializable data - ASSERT_FALSE(child.GetElementEditMetadata()->IsClassElement()); - // Child node is the root node of a ToggleGroup, so it should be a ClassElement::Group - ASSERT_EQ(child.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node has the correct parent - ASSERT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); + EXPECT_EQ(child.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); } - if (childName.compare("ToggleGroupInt") == 0) + if ((childName.compare("SubDataNormal") == 0) || (childName.compare("SubDataToggle") == 0)) { - // False for any child node with serializable data - ASSERT_FALSE(child.GetElementEditMetadata()->IsClassElement()); - // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup - ASSERT_NE(child.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node was assigned to the appropriate group - ASSERT_EQ(child.GetGroupElementMetadata()->m_description, "Group Toggle"); - // Ensuring that this node has the correct parent - ASSERT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); + for (auto subChild : child.GetChildren()) + { + childName = subChild.GetElementMetadata()->m_name; + if (childName.compare("SubToggle") == 0) + { + EXPECT_EQ(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + } + else + { + EXPECT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); + } + } } } } - TEST_F(InstanceDataHierarchyGroupTestFixture, TestNestedGroups) + // Test to ensure that each node has been assigned under the proper group and the group hierarchy is structured correctly + TEST_F(InstanceDataHierarchyGroupTestFixture, ValidatingGroupAndSubGroupHierarchy) { - using namespace AzToolsFramework; + using AzToolsFramework::InstanceDataHierarchy; + using AzToolsFramework::InstanceDataNode; - // Setting up the data node hierarchy - AZ::SerializeContext serializeContext; - serializeContext.CreateEditContext(); - Entity::Reflect(&serializeContext); - GroupTestComponent::Reflect(&serializeContext); - - AZStd::unique_ptr testEntity1(new AZ::Entity()); - testEntity1->CreateComponent(); - - InstanceDataHierarchy instanceDataHierarchy; - instanceDataHierarchy.AddRootInstance(testEntity1.get()); - instanceDataHierarchy.Build(&serializeContext, 0); - - // Adding the nodes to a node stack - auto rootNode = instanceDataHierarchy.GetRootNode(); - AZStd::stack nodeStack; - nodeStack.push(rootNode); - InstanceDataNode* componentNode1 = nullptr; - while (!nodeStack.empty()) - { - InstanceDataNode* node = nodeStack.top(); - nodeStack.pop(); - if (node->GetClassMetadata()->m_typeId == AZ::AzTypeInfo::Uuid()) - { - componentNode1 = node; - break; - } - for (InstanceDataNode& child : node->GetChildren()) - { - nodeStack.push(&child); - } - } - // Iterating through the children in the instance data hierarchy to verify their properties - ASSERT_TRUE(componentNode1 != nullptr); for (auto child : componentNode1->GetChildren()) { AZStd::string childName(child.GetElementMetadata()->m_name); - if (childName.compare("SubDataNormal") == 0) + if (childName.compare("GroupFloat") == 0) { - for (InstanceDataNode& subChild : child.GetChildren()) - { - childName = subChild.GetElementMetadata()->m_name; - if (childName.compare("SubInt") == 0) - { - // False for any child node with serializable data - ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); - // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup - ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node was assigned to the appropriate group - ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "Normal SubGroup"); - // Ensuring that this node has the correct parent - ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); - } - if (childName.compare("SubToggle") == 0) - { - // False for any child node with serializable data - ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); - // Child node is the root node of a ToggleGroup, so it should be a ClassElement::Group - ASSERT_EQ(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node has the correct parent - ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); - } - if (childName.compare("SubFloat") == 0) - { - // False for any child node with serializable data - ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); - // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup - ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node was assigned to the appropriate group - ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "SubGroup Toggle"); - // Ensuring that this node has the correct parent - ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); - } - } + EXPECT_EQ(child.GetGroupElementMetadata()->m_description, "Normal Group"); } - if (childName.compare("SubDataToggle") == 0) + if (childName.compare("ToggleGroupInt") == 0) { - for (InstanceDataNode& subChild : child.GetChildren()) + EXPECT_EQ(child.GetGroupElementMetadata()->m_description, "Group Toggle"); + } + if ((childName.compare("SubDataNormal") == 0) || (childName.compare("SubDataToggle") == 0)) + { + for (auto subChild : child.GetChildren()) { childName = subChild.GetElementMetadata()->m_name; if (childName.compare("SubInt") == 0) { - // False for any child node with serializable data - ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); - // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup - ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node was assigned to the appropriate group - ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "Normal SubGroup"); - // Ensuring that this node has the correct parent - ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); - } - if (childName.compare("SubToggle") == 0) - { - // False for any child node with serializable data - ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); - // Child node is the root node of a ToggleGroup, so it should be a ClassElement::Group - ASSERT_EQ(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node has the correct parent - ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + EXPECT_EQ(subChild.GetGroupElementMetadata()->m_description, "Normal SubGroup"); } if (childName.compare("SubFloat") == 0) { - // False for any child node with serializable data - ASSERT_FALSE(subChild.GetElementEditMetadata()->IsClassElement()); - // Child node should never be a ClassElement::Group, unless it is the root node of a ToggleGroup - ASSERT_NE(subChild.GetElementEditMetadata()->m_elementId, AZ::Edit::ClassElements::Group); - // Ensuring that this node was assigned to the appropriate group - ASSERT_EQ(subChild.GetGroupElementMetadata()->m_description, "SubGroup Toggle"); - // Ensuring that this node has the correct parent - ASSERT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + EXPECT_EQ(subChild.GetGroupElementMetadata()->m_description, "SubGroup Toggle"); } } } } } + class InstanceDataHierarchyGroupTestFixtureParameterized + : public InstanceDataHierarchyGroupTestFixture + , public ::testing::WithParamInterface + { + }; + + INSTANTIATE_TEST_CASE_P( + InstanceDataHierarchyGroupTestFixture, + InstanceDataHierarchyGroupTestFixtureParameterized, + ::testing::Values("GroupFloat", "GroupToggle", "ToggleGroupInt", "SubInt", "SubToggle", "SubFloat")); + + // Test to validate that each node in a group and Subgroup has the correct parent + TEST_P(InstanceDataHierarchyGroupTestFixtureParameterized, ValidatingGroupAndSubGroupParents) + { + using AzToolsFramework::InstanceDataHierarchy; + using AzToolsFramework::InstanceDataNode; + + const char* paramName = GetParam(); + for (auto child : componentNode1->GetChildren()) + { + AZStd::string childName(child.GetElementMetadata()->m_name); + if (childName.compare(paramName) == 0) + { + EXPECT_EQ(child.GetParent()->GetClassMetadata()->m_name, "GroupTestComponent"); + } + if ((childName.compare("SubDataNormal") == 0) || (childName.compare("SubDataToggle") == 0)) + { + for (auto subChild : child.GetChildren()) + { + childName = subChild.GetElementMetadata()->m_name; + if (childName.compare(paramName) == 0) + { + EXPECT_EQ(subChild.GetParent()->GetClassMetadata()->m_name, "SubData"); + } + } + } + } + } } // namespace UnitTest From b4e88010957cc0ce0c09b535402d9bd6c04b4949 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Fri, 23 Jul 2021 14:51:53 -0700 Subject: [PATCH 021/157] Account for new blend factor calc and updated ScopedAlterTime usages Signed-off-by: puvvadar --- Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h | 4 +++- .../Code/Include/Multiplayer/NetworkTime/INetworkTime.h | 2 +- .../Components/LocalPredictionPlayerInputComponent.cpp | 9 ++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h index cf15e8c9b7..4f714068db 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h @@ -194,18 +194,20 @@ namespace Multiplayer m_previousHostTimeMs = time->GetHostTimeMs(); m_previousRewindConnectionId = time->GetRewindingConnectionId(); time->AlterTime(frameId, timeMs, connectionId); + m_previousBlendFactor = time->GetHostBlendFactor(); time->AlterBlendFactor(blendFactor); } inline ~ScopedAlterTime() { INetworkTime* time = GetNetworkTime(); time->AlterTime(m_previousHostFrameId, m_previousHostTimeMs, m_previousRewindConnectionId); - time->AlterBlendFactor(DefaultBlendFactor); + time->AlterBlendFactor(m_previousBlendFactor); } private: HostFrameId m_previousHostFrameId = InvalidHostFrameId; AZ::TimeMs m_previousHostTimeMs = AZ::TimeMs{ 0 }; AzNetworking::ConnectionId m_previousRewindConnectionId = AzNetworking::InvalidConnectionId; + float m_previousBlendFactor = DefaultBlendFactor; }; inline const char* GetEnumString(MultiplayerAgentType value) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h index 54953b8e7e..43bcf5404e 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h @@ -65,7 +65,7 @@ namespace Multiplayer virtual void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) = 0; //! Alters the current Host blend factor. Used to drive interpolation in rewound states. - //! @param blendFactor the blend factor to use + //! @param blendFactor the blend factor to use virtual void AlterBlendFactor(float blendFactor) = 0; //! Syncs all entities contained within a volume to the current rewind state. diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 3c164713ea..a3a5a31eb2 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -156,9 +156,8 @@ namespace Multiplayer if (m_clientBankedTime < sv_MaxBankTimeWindowSec) { // Client blends from previous frame to target so here we subtract blend factor to get to that state - const float blendFactor = AZStd::max(0.f, input.GetHostBlendFactor()); - const float adjustedBlendFactor = std::pow(0.2f, blendFactor); - const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * adjustedBlendFactor); + const float blendFactor = AZStd::min(AZStd::max(0.f, input.GetHostBlendFactor()), 1.f); + const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * blendFactor); m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary { ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); @@ -315,7 +314,7 @@ namespace Multiplayer ++ModifyLastInputId(); input.SetClientInputId(GetLastInputId()); - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), DefaultBlendFactor, invokingConnection->GetConnectionId()); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, clientInputRateSec); AZLOG @@ -395,7 +394,7 @@ namespace Multiplayer { // Reprocess the input for this frame NetworkInput& input = m_inputHistory[replayIndex]; - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), DefaultBlendFactor, invokingConnection->GetConnectionId()); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, clientInputRateSec); AZLOG From a87318c52a3df6148cece8eb431fdc21cc964d51 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 26 Jul 2021 11:31:34 -0700 Subject: [PATCH 022/157] temporarily disable SC unit tests on Linux until a file case issue is solved Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Framework/ScriptCanvasGraphUtilities.inl | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl index 96febf8553..8bb2fe8c29 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl @@ -20,6 +20,7 @@ #include #include #include +#include namespace ScriptCanvasEditor { @@ -223,6 +224,22 @@ namespace ScriptCanvasEditor if (!dependencies.empty()) { + +#if defined(LINUX) ////////////////////////////////////////////////////////////////////////// + + // Temporarily disable testing on the Linux build until the casing discrepancy + // is sorted out through the SC build and testing pipeline. + + auto graphEntityId = AZ::Entity::MakeId(); + reporter.SetGraph(graphEntityId); + loadResult.m_entity->Activate(); + ScriptCanvas::UnitTesting::EventSender::MarkComplete(graphEntityId, ""); + loadResult.m_entity->Deactivate(); + reporter.FinishReport(); + ScriptCanvas::SystemRequestBus::Broadcast(&ScriptCanvas::SystemRequests::MarkScriptUnitTestEnd); + return; +#else /////////////////////////////////////////////////////////////////////////////////////// + // #functions2_recursive_unit_tests eventually, this will need to be recursive, or the full asset handling system will need to be integrated into the testing framework // in order to test functionality with a dependency stack greater than 2 @@ -256,6 +273,7 @@ namespace ScriptCanvasEditor Execution::Context::InitializeActivationData(dependencyData); Execution::InitializeInterpretedStatics(dependencyData); } +#endif ////////////////////////////////////////////////////////////////////////////////////// } loadResult.m_scriptAsset = luaAssetResult.m_scriptAsset; From 91e84f15884db4408ca235bd7ffe58c9b736063a Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 26 Jul 2021 11:37:38 -0700 Subject: [PATCH 023/157] remove smoke tag now that Linux tests are disabled Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index dada433772..23c9627e83 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -113,7 +113,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::ScriptCanvasTesting.Editor.Tests - TEST_SUITE smoke ) endif() From 3ad8f0dbf9dbb075c00bfff3bdbfb27104ac3bf1 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Mon, 26 Jul 2021 13:20:08 -0700 Subject: [PATCH 024/157] adjust location of disabling SC unit tests on Linux Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Framework/ScriptCanvasGraphUtilities.inl | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl index 2048fea08a..4b22864b6e 100644 --- a/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl +++ b/Gems/ScriptCanvas/Code/Editor/Framework/ScriptCanvasGraphUtilities.inl @@ -218,19 +218,14 @@ namespace ScriptCanvasEditor if (!reporter.IsProcessOnly()) { - dependencies = LoadInterpretedDepencies(luaAssetResult.m_dependencies.source.userSubgraphs); - RuntimeDataOverrides runtimeDataOverrides; runtimeDataOverrides.m_runtimeAsset = loadResult.m_runtimeAsset; - if (!dependencies.empty()) - { - #if defined(LINUX) ////////////////////////////////////////////////////////////////////////// - - // Temporarily disable testing on the Linux build until the casing discrepancy - // is sorted out through the SC build and testing pipeline. - + // Temporarily disable testing on the Linux build until the file name casing discrepancy + // is sorted out through the SC build and testing pipeline. + if (!luaAssetResult.m_dependencies.source.userSubgraphs.empty()) + { auto graphEntityId = AZ::Entity::MakeId(); reporter.SetGraph(graphEntityId); loadResult.m_entity->Activate(); @@ -239,8 +234,13 @@ namespace ScriptCanvasEditor reporter.FinishReport(); ScriptCanvas::SystemRequestBus::Broadcast(&ScriptCanvas::SystemRequests::MarkScriptUnitTestEnd); return; + } #else /////////////////////////////////////////////////////////////////////////////////////// + dependencies = LoadInterpretedDepencies(luaAssetResult.m_dependencies.source.userSubgraphs); + + if (!dependencies.empty()) + { // #functions2_recursive_unit_tests eventually, this will need to be recursive, or the full asset handling system will need to be integrated into the testing framework // in order to test functionality with a dependency stack greater than 2 @@ -274,8 +274,8 @@ namespace ScriptCanvasEditor Execution::Context::InitializeActivationData(dependencyData); Execution::InitializeInterpretedStatics(dependencyData); } -#endif ////////////////////////////////////////////////////////////////////////////////////// } +#endif ////////////////////////////////////////////////////////////////////////////////////// loadResult.m_scriptAsset = luaAssetResult.m_scriptAsset; loadResult.m_runtimeAsset.Get()->GetData().m_script = loadResult.m_scriptAsset; From ce3ec0d49c45f212972660d62c986a69fa95d49d Mon Sep 17 00:00:00 2001 From: dtamkin1 Date: Tue, 27 Jul 2021 15:26:22 -0500 Subject: [PATCH 025/157] Moved toggle swtich back to the left side per UX's request Signed-off-by: dtamkin1 --- .../AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp index 49f7ba3885..5ea36bb30e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp @@ -1122,8 +1122,7 @@ namespace AzToolsFramework m_handlerName = AZ::Edit::UIHandlers::CheckBox; PropertyTypeRegistrationMessages::Bus::BroadcastResult(m_handler, &PropertyTypeRegistrationMessages::Bus::Events::ResolvePropertyHandler, m_handlerName, azrtti_typeid()); m_toggleSwitch = m_handler->CreateGUI(this); - m_toggleSwitch->setFixedWidth(38); - m_middleLayout->addWidget(m_toggleSwitch, 1, Qt::AlignRight); + m_middleLayout->insertWidget(0, m_toggleSwitch, 1); auto checkBoxCtrl = static_cast(m_toggleSwitch); QObject::connect(checkBoxCtrl, &AzToolsFramework::PropertyCheckBoxCtrl::valueChanged, this, &PropertyRowWidget::OnClickedToggleButton); } From 9742626aba3b763bfb1383e0c1a86f951a2c25ee Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 27 Jul 2021 15:59:28 -0700 Subject: [PATCH 026/157] Make SC unit tests run serially Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 23c9627e83..8f3ba103e7 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -113,6 +113,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::ScriptCanvasTesting.Editor.Tests + TEST_SERIAL true ) endif() From c177fe3c040e585a0ae64504c96f6fcdd84aeff8 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 27 Jul 2021 16:27:36 -0700 Subject: [PATCH 027/157] use work around for missing SERIAL tag for ly_add_googletest() Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 8f3ba103e7..7291cd65eb 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -113,8 +113,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::ScriptCanvasTesting.Editor.Tests - TEST_SERIAL true ) + set_tests_properties(Gem::ScriptCanvasTesting.Editor.Tests.main::TEST_RUN PROPERTIES RUN_SERIAL true) endif() From 2174f8415ab4233cd87a135301c24dc36422457e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 27 Jul 2021 18:32:00 -0700 Subject: [PATCH 028/157] making azcore tests serialized as a sanity check Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Code/Framework/AzCore/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Framework/AzCore/CMakeLists.txt b/Code/Framework/AzCore/CMakeLists.txt index ea7cc27af5..0a03b6b77c 100644 --- a/Code/Framework/AzCore/CMakeLists.txt +++ b/Code/Framework/AzCore/CMakeLists.txt @@ -130,6 +130,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_googletest( NAME AZ::AzCore.Tests ) + set_tests_properties(AZ::AzCore.Tests.main::TEST_RUN PROPERTIES RUN_SERIAL true) ly_add_googlebenchmark( NAME AZ::AzCore.Benchmarks TARGET AZ::AzCore.Tests From 0cfac06c699c909626d0b7dcb41b44d301f6381b Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Tue, 27 Jul 2021 18:55:40 -0700 Subject: [PATCH 029/157] making azcore tests serialized as a sanity check only on non android Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Code/Framework/AzCore/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/CMakeLists.txt b/Code/Framework/AzCore/CMakeLists.txt index 0a03b6b77c..785352cf05 100644 --- a/Code/Framework/AzCore/CMakeLists.txt +++ b/Code/Framework/AzCore/CMakeLists.txt @@ -130,7 +130,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_googletest( NAME AZ::AzCore.Tests ) - set_tests_properties(AZ::AzCore.Tests.main::TEST_RUN PROPERTIES RUN_SERIAL true) + if(PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED) + set_tests_properties(AZ::AzCore.Tests.main::TEST_RUN PROPERTIES RUN_SERIAL true) + endif() ly_add_googlebenchmark( NAME AZ::AzCore.Benchmarks TARGET AZ::AzCore.Tests From fd07f907bc8fabfc6ef7b2a9ffd562c474bd36e9 Mon Sep 17 00:00:00 2001 From: ibtehajn <81370835+ibtehajn@users.noreply.github.com> Date: Wed, 28 Jul 2021 13:22:24 +0100 Subject: [PATCH 030/157] Implement axis locking options for rigid bodies Linear and angular motion of rigid bodies can now be restricted along specific world-space axes. Signed-off-by: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> --- .../Configuration/RigidBodyConfiguration.cpp | 6 +++ .../Configuration/RigidBodyConfiguration.h | 10 ++++ .../Code/Source/EditorRigidBodyComponent.cpp | 27 ++++++++++ Gems/PhysX/Code/Source/Utils.cpp | 8 +++ Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp | 54 +++++++++++++++++++ 5 files changed, 105 insertions(+) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp index a61f6a4845..cfea76f1d7 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.cpp @@ -123,6 +123,12 @@ namespace AzPhysics ->Field("Kinematic", &RigidBodyConfiguration::m_kinematic) ->Field("CCD Enabled", &RigidBodyConfiguration::m_ccdEnabled) ->Field("Compute Mass", &RigidBodyConfiguration::m_computeMass) + ->Field("Lock Linear X", &RigidBodyConfiguration::m_lockLinearX) + ->Field("Lock Linear Y", &RigidBodyConfiguration::m_lockLinearY) + ->Field("Lock Linear Z", &RigidBodyConfiguration::m_lockLinearZ) + ->Field("Lock Angular X", &RigidBodyConfiguration::m_lockAngularX) + ->Field("Lock Angular Y", &RigidBodyConfiguration::m_lockAngularY) + ->Field("Lock Angular Z", &RigidBodyConfiguration::m_lockAngularZ) ->Field("Mass", &RigidBodyConfiguration::m_mass) ->Field("Compute COM", &RigidBodyConfiguration::m_computeCenterOfMass) ->Field("Centre of mass offset", &RigidBodyConfiguration::m_centerOfMassOffset) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h index 59829e740c..46f2620938 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h @@ -62,6 +62,16 @@ namespace AzPhysics bool m_computeInertiaTensor = true; bool m_computeMass = true; + //! Flags to restrict motion along specific world-space axes. + bool m_lockLinearX = false; + bool m_lockLinearY = false; + bool m_lockLinearZ = false; + + //! Flags to restrict rotation around specific world-space axes. + bool m_lockAngularX = false; + bool m_lockAngularY = false; + bool m_lockAngularZ = false; + //! If set, non-simulated shapes will also be included in the mass properties calculation. bool m_includeAllShapesInMassCalculation = false; diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp index d27874f030..c94cc46ba4 100644 --- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp @@ -156,6 +156,33 @@ namespace PhysX ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_kinematic, "Kinematic", "Rigid body is kinematic") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetKinematicVisibility) + + // Linear axis locking properties + ->ClassElement(AZ::Edit::ClassElements::Group, "Linear Axis Locking") + ->Attribute(AZ::Edit::Attributes::AutoExpand, false) + ->DataElement( + AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearX, "Lock X", + "Lock linear momentum in X direction") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearY, "Lock Y", + "Lock linear momentum in Y direction") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearZ, "Lock Z", + "Lock linear momentum in Z direction") + + // Angular axis locking properties + ->ClassElement(AZ::Edit::ClassElements::Group, "Angular Axis Locking") + ->Attribute(AZ::Edit::Attributes::AutoExpand, false) + ->DataElement( + AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularX, "Lock X", + "Lock angular momentum in X direction") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularY, "Lock Y", + "Lock angular momentum in Y direction") + ->DataElement( + AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularZ, "Lock Z", + "Lock angular momentum in Z direction") + ->ClassElement(AZ::Edit::ClassElements::Group, "Continuous Collision Detection") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCCDVisibility) diff --git a/Gems/PhysX/Code/Source/Utils.cpp b/Gems/PhysX/Code/Source/Utils.cpp index 4e5695e3c6..0b7ab9436b 100644 --- a/Gems/PhysX/Code/Source/Utils.cpp +++ b/Gems/PhysX/Code/Source/Utils.cpp @@ -1466,6 +1466,14 @@ namespace PhysX rigidDynamic->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, configuration.m_kinematic); rigidDynamic->setMaxAngularVelocity(configuration.m_maxAngularVelocity); + // Set axis locks. + rigidDynamic->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_X, configuration.m_lockLinearX); + rigidDynamic->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Y, configuration.m_lockLinearY); + rigidDynamic->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Z, configuration.m_lockLinearZ); + rigidDynamic->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_X, configuration.m_lockAngularX); + rigidDynamic->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y, configuration.m_lockAngularY); + rigidDynamic->setRigidDynamicLockFlag(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z, configuration.m_lockAngularZ); + return rigidDynamic; } diff --git a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp index 770e47d477..76ee035b70 100644 --- a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp @@ -1102,6 +1102,60 @@ namespace PhysX SanityCheckValidFrustumParams(points.value(), validHeight, validBottomRadius, validTopRadius, validSubdivisions); } + TEST_F(PhysXSpecificTest, RigidBody_RigidBodyWithAxisLockFlagsCreated_InternalPhysXFlagsSetAccordingly) + { + // Helper function wrapping creation logic + auto CreateRigidBody = [this](bool linearX, bool linearY, bool linearZ, bool angularX, bool angularY, bool angularZ) -> AzPhysics::RigidBody* + { + AzPhysics::RigidBodyConfiguration rigidBodyConfig; + + rigidBodyConfig.m_lockLinearX = linearX; + rigidBodyConfig.m_lockLinearY = linearY; + rigidBodyConfig.m_lockLinearZ = linearZ; + + rigidBodyConfig.m_lockAngularX = angularX; + rigidBodyConfig.m_lockAngularY = angularY; + rigidBodyConfig.m_lockAngularZ = angularZ; + + if (auto* sceneInterface = AZ::Interface::Get()) + { + AzPhysics::SimulatedBodyHandle simBodyHandle = sceneInterface->AddSimulatedBody(m_testSceneHandle, &rigidBodyConfig); + return azdynamic_cast(sceneInterface->GetSimulatedBodyFromHandle(m_testSceneHandle, simBodyHandle)); + } + + return nullptr; + }; + + auto RemoveRigidBody = [this](AzPhysics::RigidBody*& rigidBody) + { + auto* sceneInterface = AZ::Interface::Get(); + if (rigidBody && sceneInterface) + { + sceneInterface->RemoveSimulatedBody(rigidBody->m_sceneOwner, rigidBody->m_bodyHandle); + } + rigidBody = nullptr; + }; + + auto TestLockFlags = [&CreateRigidBody, &RemoveRigidBody](bool linearX, bool linearY, bool linearZ, + bool angularX, bool angularY, bool angularZ, + physx::PxRigidDynamicLockFlags expectedFlags) + { + auto* rigidBody = CreateRigidBody(linearX, linearY, linearZ, angularX, angularY, angularZ); + ASSERT_TRUE(rigidBody != nullptr); + + physx::PxRigidDynamic* pxRigidBody = static_cast(rigidBody->GetNativePointer()); + EXPECT_EQ(pxRigidBody->getRigidDynamicLockFlags(), expectedFlags); + + RemoveRigidBody(rigidBody); + }; + + TestLockFlags(false, false, false, false, false, false, physx::PxRigidDynamicLockFlags(0)); + TestLockFlags(true, false, false, false, false, false, physx::PxRigidDynamicLockFlags(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_X)); + TestLockFlags(false, false, false, false, true, false, physx::PxRigidDynamicLockFlags(physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y)); + TestLockFlags(false, true, false, false, false, true, + physx::PxRigidDynamicLockFlags(physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Y | physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z)); + } + TEST_F(PhysXSpecificTest, RigidBody_RigidBodyWithSimulatedFlagsHitsPlane_OnlySimulatedShapeCollidesWithPlane) { // Helper function wrapping creation logic From 16869d56f32316b8bdaa157e53de39fd68fcc6fa Mon Sep 17 00:00:00 2001 From: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> Date: Wed, 28 Jul 2021 14:09:26 +0100 Subject: [PATCH 031/157] Use regular comment The Doxygen comment would only apply to the first field in each group. Signed-off-by: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> --- .../Physics/Configuration/RigidBodyConfiguration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h index 46f2620938..51dcce842d 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/RigidBodyConfiguration.h @@ -62,12 +62,12 @@ namespace AzPhysics bool m_computeInertiaTensor = true; bool m_computeMass = true; - //! Flags to restrict motion along specific world-space axes. + // Flags to restrict motion along specific world-space axes. bool m_lockLinearX = false; bool m_lockLinearY = false; bool m_lockLinearZ = false; - //! Flags to restrict rotation around specific world-space axes. + // Flags to restrict rotation around specific world-space axes. bool m_lockAngularX = false; bool m_lockAngularY = false; bool m_lockAngularZ = false; From 0824bb462a44cf017827d0628a4f4694f1bf68a7 Mon Sep 17 00:00:00 2001 From: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:33:02 +0100 Subject: [PATCH 032/157] Improve tooltip text Signed-off-by: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> --- Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp index c94cc46ba4..bd7c49a0a7 100644 --- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp @@ -162,26 +162,26 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearX, "Lock X", - "Lock linear momentum in X direction") + "Lock motion along X direction") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearY, "Lock Y", - "Lock linear momentum in Y direction") + "Lock motion along Y direction") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearZ, "Lock Z", - "Lock linear momentum in Z direction") + "Lock motion along Z direction") // Angular axis locking properties ->ClassElement(AZ::Edit::ClassElements::Group, "Angular Axis Locking") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularX, "Lock X", - "Lock angular momentum in X direction") + "Lock rotation around X direction") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularY, "Lock Y", - "Lock angular momentum in Y direction") + "Lock rotation around Y direction") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularZ, "Lock Z", - "Lock angular momentum in Z direction") + "Lock rotation around Z direction") ->ClassElement(AZ::Edit::ClassElements::Group, "Continuous Collision Detection") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) From a7e414fafeb18834d5c930ae2eb225d8bd889d1c Mon Sep 17 00:00:00 2001 From: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> Date: Wed, 28 Jul 2021 17:58:31 +0100 Subject: [PATCH 033/157] Fix Linux compilation error in test code Signed-off-by: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> --- Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp index 76ee035b70..6e96db4db2 100644 --- a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp @@ -1144,7 +1144,9 @@ namespace PhysX ASSERT_TRUE(rigidBody != nullptr); physx::PxRigidDynamic* pxRigidBody = static_cast(rigidBody->GetNativePointer()); - EXPECT_EQ(pxRigidBody->getRigidDynamicLockFlags(), expectedFlags); + + // These values need to be cast to integral types to prevent a compilation error on somme platforms. + EXPECT_EQ(static_cast(pxRigidBody->getRigidDynamicLockFlags()), static_cast((expectedFlags))); RemoveRigidBody(rigidBody); }; From d5a496751ce06593e5704b15320e521ec84b4bc7 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Tue, 13 Jul 2021 10:21:56 -0700 Subject: [PATCH 034/157] Visualizer: Implement region search + highlight Signed-off-by: Jacob Hilliard --- .../Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h | 8 +++++--- .../Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl | 10 ++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index 66be0b9137..4d22458b56 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -165,9 +165,11 @@ namespace AZ AZStd::vector m_frameEndTicks = { INT64_MIN }; // Main data structure for storing function statistics to be shown in the popup windows. - // For now we default allocate for all regions on the first render frame and then use RegionStatistics.m_draw to determine - // if we should draw the window or not. FIXME(ATOM-15948) this should be changed once RegionStatistics gets heavier. - AZStd::unordered_map m_regionStatisticsMap; + // Uses the group name + region name as a key - just the region name does not suffice since there are collisions (ex. GarbageCollect) + AZStd::unordered_map m_regionStatisticsMap; + + // Filter for highlighting regions on the visualizer + ImGuiTextFilter m_regionHighlightFilter; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index 735dace1c7..81fa440159 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -279,8 +279,8 @@ namespace AZ if (ImGui::BeginChild("Options and Statistics", { 0, 0 }, true)) { ImGui::Columns(3, "Options", true); - ImGui::Text("Frames To Collect:"); - ImGui::SliderInt("", &m_framesToCollect, 10, 10000, "%d", ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_Logarithmic); + ImGui::SliderInt("Saved Frames", &m_framesToCollect, 10, 10000, "%d", ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_Logarithmic); + m_regionHighlightFilter.Draw("Find Region"); ImGui::NextColumn(); @@ -522,6 +522,12 @@ namespace AZ inline void ImGuiCpuProfiler::DrawBlock(const TimeRegion& block, u64 targetRow) { + // Don't draw anything if the user is searching for regions and this block doesn't pass the filter + if (!m_regionHighlightFilter.PassFilter(block.m_groupRegionName->m_regionName)) + { + return; + } + float wy = ImGui::GetWindowPos().y - ImGui::GetScrollY(); ImDrawList* drawList = ImGui::GetWindowDrawList(); From 487fc631eca1dd23c83e77ad06eb898ecf567570 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Mon, 12 Jul 2021 16:47:33 -0700 Subject: [PATCH 035/157] Visualizer: Tabular view of function statistics Current metrics are MTPC, max time, and invocations per frame. The invocations per frame is buggy if switching between samples but I don't know how to fix that in a context-agnostic way (editor vs ASV) - resetting works for now. Signed-off-by: Jacob Hilliard --- .../Include/Atom/Utils/ImGuiCpuProfiler.h | 41 +-- .../Include/Atom/Utils/ImGuiCpuProfiler.inl | 276 +++++++++--------- 2 files changed, 153 insertions(+), 164 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index 4d22458b56..695ad7e332 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -31,28 +31,29 @@ namespace AZ AZStd::sys_time_t m_endTick = 0; }; - // Stores data about a region that is agreggated from all collected frames - // Data collection can be toggled on and off through m_record. - struct RegionStatistics + struct TableRow { - float CalcAverageTimeMs() const; void RecordRegion(const AZ::RHI::CachedTimeRegion& region); + double GetAverageInvocationsPerFrame() const; - bool m_draw = false; - bool m_record = true; - u64 m_invocations = 0; - AZStd::sys_time_t m_totalTicks = 0; + static u64 ms_frames; + + AZStd::string m_groupName; + AZStd::string m_regionName; + AZStd::sys_time_t m_maxTicks; + AZStd::sys_time_t m_runningAverageTicks; + u64 m_invocations; }; //! Visual profiler for Cpu statistics. //! It uses ImGui as the library for displaying the Attachments and Heaps. - //! It shows all heaps that are being used by the RHI and how the + //! It shows all heaps that are being used by the RHI and how the FIXME //! resources are allocated in each heap. class ImGuiCpuProfiler : SystemTickBus::Handler { // Region Name -> Array of ThreadRegion entries - using RegionEntryMap = AZStd::map>; + using RegionEntryMap = AZStd::map; // Group Name -> RegionEntryMap using GroupRegionMap = AZStd::map; @@ -81,12 +82,21 @@ namespace AZ // Draw the shared header between the two windows void DrawCommonHeader(); + // Draw the region statstics table in the order specified by the pointers in m_tableData + void DrawTable(); + + // Sort the table by a given column, rearranges the pointers in m_tableData + void SortTable(ImGuiTableSortSpecs* sortSpecs); + // ImGui filter used to filter TimedRegions. ImGuiTextFilter m_timedRegionFilter; - // Saves statistical view data organized by group name -> region name -> regions + // Saves statistical view data organized by group name -> region name -> row data GroupRegionMap m_groupRegionMap; + // Saves pointers to objects in m_groupRegionMap, order reflects table ordering + AZStd::vector m_tableData; + // Pause cpu profiling. The profiler will show the statistics of the last frame before pause bool m_paused = false; @@ -120,9 +130,6 @@ namespace AZ // Draw the "Thread XXXXX" label onto the viewport void DrawThreadLabel(u64 baseRow, AZStd::thread_id threadId); - // Draws all active function statistics windows - void DrawRegionStatistics(); - // Draw the vertical lines separating frames in the timeline void DrawFrameBoundaries(); @@ -164,12 +171,8 @@ namespace AZ // Tracks the frame boundaries AZStd::vector m_frameEndTicks = { INT64_MIN }; - // Main data structure for storing function statistics to be shown in the popup windows. - // Uses the group name + region name as a key - just the region name does not suffice since there are collisions (ex. GarbageCollect) - AZStd::unordered_map m_regionStatisticsMap; - // Filter for highlighting regions on the visualizer - ImGuiTextFilter m_regionHighlightFilter; + ImGuiTextFilter m_visualizerHighlightFilter; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index 81fa440159..bb470f39e8 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -17,11 +17,16 @@ #include #include +#pragma optimize("", off) + +#include "../../../Gems/ImGui/External/ImGui/v1.82/imgui/imgui.h" namespace AZ { namespace Render { + inline u64 TableRow::ms_frames = 0; + namespace CpuProfilerImGuiHelper { // NOTE: Fix build error in case AZStd::thread_id is not of an arithmetic type, and instead a pointer @@ -134,6 +139,92 @@ namespace AZ } } + inline void ImGuiCpuProfiler::DrawTable() + { + const auto flags = + ImGuiTableFlags_Borders | ImGuiTableFlags_Sortable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable; + if (ImGui::BeginTable("FunctionStatisticsTable", 5, flags)) + { + // Table header setup + ImGui::TableSetupColumn("Group"); + ImGui::TableSetupColumn("Region"); + ImGui::TableSetupColumn("MTPC (ms)"); + ImGui::TableSetupColumn("Max (ms)"); + ImGui::TableSetupColumn("Invocations/frame"); + ImGui::TableHeadersRow(); + ImGui::TableNextColumn(); + + ImGuiTableSortSpecs* sortSpecs = ImGui::TableGetSortSpecs(); + if (sortSpecs && sortSpecs->SpecsDirty) + { + SortTable(sortSpecs); + } + + // Draw all of the rows held in the GroupRegionMap + for (const auto* statistics : m_tableData) + { + if (!m_timedRegionFilter.PassFilter(statistics->m_groupName.c_str()) + && !m_timedRegionFilter.PassFilter(statistics->m_regionName.c_str())) + { + continue; + } + + ImGui::Text(statistics->m_groupName.c_str()); + ImGui::TableNextColumn(); + + ImGui::Text(statistics->m_regionName.c_str()); + ImGui::TableNextColumn(); + + ImGui::Text("%.2f", CpuProfilerImGuiHelper::TicksToMs(statistics->m_runningAverageTicks)); + ImGui::TableNextColumn(); + + ImGui::Text("%.2f", CpuProfilerImGuiHelper::TicksToMs(statistics->m_maxTicks)); + ImGui::TableNextColumn(); + + ImGui::Text("%.1f", statistics->GetAverageInvocationsPerFrame()); + ImGui::TableNextColumn(); + } + } + ImGui::EndTable(); + } + + inline void ImGuiCpuProfiler::SortTable(ImGuiTableSortSpecs* sortSpecs) + { + const bool ascending = sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending; + const ImS16 columnToSort = sortSpecs->Specs->ColumnIndex; + + switch (columnToSort) + { + case (0): // Sort by group name + AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ + return ascending ? lhs->m_groupName < rhs->m_groupName : lhs->m_groupName > rhs->m_groupName; + }); + break; + case (1): // Sort by region name + AZStd::sort(m_tableData.begin(), m_tableData.end(),[ascending](const TableRow* lhs, const TableRow* rhs){ + return ascending ? lhs->m_regionName < rhs->m_regionName : lhs->m_regionName > rhs->m_regionName; + }); + break; + case (2): // Sort by average time + AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ + return ascending ? lhs->m_runningAverageTicks < rhs->m_runningAverageTicks + : lhs->m_runningAverageTicks > rhs->m_runningAverageTicks; + }); + break; + case (3): // Sort by max time + AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ + return ascending ? lhs->m_maxTicks < rhs->m_maxTicks : lhs->m_maxTicks > rhs->m_maxTicks; + }); + break; + case (4): // Sort by invocations + AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ + return ascending ? lhs->m_invocations < rhs->m_invocations : lhs->m_invocations > rhs->m_invocations; + }); + break; + } + sortSpecs->SpecsDirty = false; + } + inline void ImGuiCpuProfiler::DrawStatisticsView() { DrawCommonHeader(); @@ -156,62 +247,6 @@ namespace AZ ImGui::NextColumn(); }; - const auto DrawRegionHoverMarker = [this, &ShowTimeInMs](AZStd::vector& entries) - { - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 60.0f); - - for (ThreadRegionEntry& entry : entries) - { - ImGui::Text(CpuProfilerImGuiHelper::TextThreadId(entry.m_threadId.m_id).c_str()); - - const AZStd::sys_time_t elapsed = entry.m_endTick - entry.m_startTick; - ShowTimeInMs(elapsed); - ImGui::Separator(); - } - - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - }; - - const auto ShowRegionRow = - [ticksPerSecond, &DrawRegionHoverMarker, - &ShowTimeInMs](const char* regionLabel, AZStd::vector regions, AZStd::sys_time_t duration) - { - // Draw the region label - ImGui::Text(regionLabel); - ImGui::NextColumn(); - - // Draw the thread count label - AZStd::sys_time_t totalTime = 0; - AZStd::set threads; - for (ThreadRegionEntry& entry : regions) // Find the thread count and total execution time for all threads - { - threads.insert(entry.m_threadId); - totalTime += entry.m_endTick - entry.m_startTick; - } - const AZStd::string threadLabel = AZStd::string::format("Threads: %u", static_cast(threads.size())); - ImGui::Text(threadLabel.c_str()); - DrawRegionHoverMarker(regions); - ImGui::NextColumn(); - - // Draw the overall invocation count - const AZStd::string invocationLabel = AZStd::string::format("Total calls: %u", static_cast(regions.size())); - ImGui::Text(invocationLabel.c_str()); - DrawRegionHoverMarker(regions); - ImGui::NextColumn(); - - // Draw the time labels (max and then total) - const AZStd::string timeLabel = AZStd::string::format( - "%.2f ms max, %.2f ms total", CpuProfilerImGuiHelper::TicksToMs(duration), - CpuProfilerImGuiHelper::TicksToMs(totalTime)); - ImGui::Text(timeLabel.c_str()); - ImGui::NextColumn(); - }; - if (ImGui::BeginChild("Statistics View", { 0, 0 }, true)) { // Set column settings. @@ -229,44 +264,21 @@ namespace AZ ImGui::Separator(); ImGui::Columns(1, "view", false); - m_timedRegionFilter.Draw("TimedRegion Filter"); - - // Draw the timed regions - if (ImGui::BeginChild("TimedRegions")) + m_timedRegionFilter.Draw("Filter"); + ImGui::SameLine(); + if (ImGui::Button("Clear Filter")) { - for (auto& timeRegionMapEntry : m_groupRegionMap) - { - // Draw the regions - if (ImGui::TreeNodeEx(timeRegionMapEntry.first.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Columns(4, "view", false); - ImGui::SetColumnWidth(0, 400.0f); - ImGui::SetColumnWidth(1, 100.0f); - ImGui::SetColumnWidth(2, 150.0f); - ImGui::SetColumnWidth(3, 240.0f); - - for (auto& region : timeRegionMapEntry.second) - { - // Calculate the region with the longest execution time - AZStd::sys_time_t threadExecutionElapsed = 0; - for (ThreadRegionEntry& entry : region.second) - { - const AZStd::sys_time_t elapsed = entry.m_endTick - entry.m_startTick; - threadExecutionElapsed = AZStd::max(threadExecutionElapsed, elapsed); - } - - // Only draw the TimedRegion rows when it passes the filter - if (m_timedRegionFilter.PassFilter(region.first.c_str())) - { - ShowRegionRow(region.first.c_str(), region.second, threadExecutionElapsed); - } - } - ImGui::Columns(1, "view", false); - ImGui::TreePop(); - } - } - ImGui::EndChild(); + m_timedRegionFilter.Clear(); } + ImGui::SameLine(); + if (ImGui::Button("Reset Table")) + { + m_tableData.clear(); + m_groupRegionMap.clear(); + TableRow::ms_frames = 0; + } + + DrawTable(); } } @@ -280,7 +292,7 @@ namespace AZ { ImGui::Columns(3, "Options", true); ImGui::SliderInt("Saved Frames", &m_framesToCollect, 10, 10000, "%d", ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_Logarithmic); - m_regionHighlightFilter.Draw("Find Region"); + m_visualizerHighlightFilter.Draw("Find Region"); ImGui::NextColumn(); @@ -372,7 +384,6 @@ namespace AZ baseRow += maxDepth + 1; // Next draw loop should start one row down } - DrawRegionStatistics(); DrawFrameBoundaries(); // Draw an invisible button to capture inputs @@ -432,9 +443,6 @@ namespace AZ // view is only holding data from the last frame, the memory overhead is minimal and gives us a faster redraw // compared to if we needed to transform the visualizer's data into the statistical format every frame. - // Clear the statistical view's cached entries - m_groupRegionMap.clear(); - // Get the latest TimeRegionMap const RHI::CpuProfiler::TimeRegionMap& timeRegionMap = RHI::CpuProfiler::Get()->GetTimeRegionMap(); @@ -461,14 +469,15 @@ namespace AZ // Also update the statistical view's data const AZStd::string& groupName = region.m_groupRegionName->m_groupName; - m_groupRegionMap[groupName][regionName].push_back( - { threadId, region.m_startTick, region.m_endTick }); - // Update running statistics if we want to record this region's data - if (m_regionStatisticsMap[region.m_groupRegionName].m_record) + if (!m_groupRegionMap[groupName].contains(regionName)) { - m_regionStatisticsMap[region.m_groupRegionName].RecordRegion(region); + m_groupRegionMap[groupName][regionName].m_groupName = groupName; + m_groupRegionMap[groupName][regionName].m_regionName = regionName; + m_tableData.push_back(&m_groupRegionMap[groupName][regionName]); } + + m_groupRegionMap[groupName][regionName].RecordRegion(region); } } @@ -523,7 +532,7 @@ namespace AZ inline void ImGuiCpuProfiler::DrawBlock(const TimeRegion& block, u64 targetRow) { // Don't draw anything if the user is searching for regions and this block doesn't pass the filter - if (!m_regionHighlightFilter.PassFilter(block.m_groupRegionName->m_regionName)) + if (!m_visualizerHighlightFilter.PassFilter(block.m_groupRegionName->m_regionName)) { return; } @@ -573,13 +582,14 @@ namespace AZ // Tooltip and block highlighting if (ImGui::IsMouseHoveringRect(startPoint, endPoint) && ImGui::IsWindowHovered()) { - // Open function statistics map on click + // Go to the statistics view when a region is clicked if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { - const GroupRegionName* key = block.m_groupRegionName; - m_regionStatisticsMap[key].m_draw = true; + m_enableVisualizer = false; + const auto newFilter = AZStd::string(block.m_groupRegionName->m_regionName); + m_timedRegionFilter = ImGuiTextFilter(newFilter.c_str()); + m_timedRegionFilter.Build(); } - // Hovering outline drawList->AddRect(startPoint, endPoint, ImGui::GetColorU32({ 1, 1, 1, 1 }), 0.0, 0, 1.5); @@ -631,31 +641,6 @@ namespace AZ ImGui::GetWindowDrawList()->AddText({ wx + 10, wy + baseRow * RowHeight + 5 }, IM_COL32_WHITE, threadIdText.c_str()); } - inline void ImGuiCpuProfiler::DrawRegionStatistics() - { - for (auto& [groupRegionName, stat] : m_regionStatisticsMap) - { - if (stat.m_draw) - { - ImGui::SetNextWindowSize({300, 340}, ImGuiCond_FirstUseEver); - ImGui::Begin(groupRegionName->m_regionName, &stat.m_draw, 0); - - if (ImGui::Button(stat.m_record ? "Pause" : "Resume")) - { - stat.m_record = !stat.m_record; - } - - ImGui::Text("Invocations: %llu", stat.m_invocations); - ImGui::Text("Average time: %.3f ms", stat.CalcAverageTimeMs()); - - ImGui::Separator(); - - ImGui::ColorPicker4("Region color", &m_regionColorMap[groupRegionName].x); - ImGui::End(); - } - } - } - inline void ImGuiCpuProfiler::DrawFrameBoundaries() { ImDrawList* drawList = ImGui::GetWindowDrawList(); @@ -857,25 +842,26 @@ namespace AZ else { m_frameEndTicks.push_back(AZStd::GetTimeNowTicks()); + TableRow::ms_frames++; } } - // ----- RegionStatistics implementation ----- - - inline float RegionStatistics::CalcAverageTimeMs() const - { - if (m_invocations == 0) - { - return 0.0; - } - const double averageTicks = aznumeric_cast(m_totalTicks) / m_invocations; - return CpuProfilerImGuiHelper::TicksToMs(aznumeric_cast(averageTicks)); - } + // ---- TableRow impl ---- - inline void RegionStatistics::RecordRegion(const AZ::RHI::CachedTimeRegion& region) + inline void TableRow::RecordRegion(const AZ::RHI::CachedTimeRegion& region) { m_invocations++; - m_totalTicks += region.m_endTick - region.m_startTick; + const AZStd::sys_time_t deltaTime = AZStd::abs(region.m_endTick - region.m_startTick); + m_maxTicks = AZStd::max(m_maxTicks, deltaTime); + + // Standard running average algorithm + const auto newMean = m_runningAverageTicks + aznumeric_cast((deltaTime - m_runningAverageTicks) * 1.0 / m_invocations); + m_runningAverageTicks = newMean; + } + + inline double TableRow::GetAverageInvocationsPerFrame() const + { + return 1.0 * m_invocations / ms_frames; } } // namespace Render } // namespace AZ From bd00867fe624303c7f823e0c5551c6762efae858 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Wed, 21 Jul 2021 11:57:23 -0700 Subject: [PATCH 036/157] Visualizer: Implement thread hovering tooltip Signed-off-by: Jacob Hilliard --- .../Include/Atom/Utils/ImGuiCpuProfiler.h | 12 ++++-- .../Include/Atom/Utils/ImGuiCpuProfiler.inl | 41 +++++++++++++++---- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index 695ad7e332..d21783a801 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -33,16 +34,17 @@ namespace AZ struct TableRow { - void RecordRegion(const AZ::RHI::CachedTimeRegion& region); + void RecordRegion(const AZ::RHI::CachedTimeRegion& region, AZStd::thread_id threadId); double GetAverageInvocationsPerFrame() const; - - static u64 ms_frames; + AZStd::string TableRow::GetExecutingThreadsLabel() const; AZStd::string m_groupName; AZStd::string m_regionName; AZStd::sys_time_t m_maxTicks; AZStd::sys_time_t m_runningAverageTicks; u64 m_invocations; + + AZStd::set m_executingThreads; }; //! Visual profiler for Cpu statistics. @@ -52,6 +54,8 @@ namespace AZ class ImGuiCpuProfiler : SystemTickBus::Handler { + friend struct TableRow; + // Region Name -> Array of ThreadRegion entries using RegionEntryMap = AZStd::map; // Group Name -> RegionEntryMap @@ -79,6 +83,8 @@ namespace AZ static constexpr float MediumFrameTimeLimit = 16.6; // 60 fps static constexpr float HighFrameTimeLimit = 33.3; // 30 fps + static u64 ms_framesActive; + // Draw the shared header between the two windows void DrawCommonHeader(); diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index bb470f39e8..124e48af13 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,7 @@ namespace AZ { namespace Render { - inline u64 TableRow::ms_frames = 0; + inline u64 ImGuiCpuProfiler::ms_framesActive = 0; namespace CpuProfilerImGuiHelper { @@ -41,6 +42,7 @@ namespace AZ { return AZStd::string::format("Thread: %zu", static_cast(threadId)); } + inline float TicksToMs(AZStd::sys_time_t ticks) { // Note: converting to microseconds integer before converting to milliseconds float @@ -170,6 +172,7 @@ namespace AZ } ImGui::Text(statistics->m_groupName.c_str()); + const ImVec2 topLeftBound = ImGui::GetItemRectMin(); ImGui::TableNextColumn(); ImGui::Text(statistics->m_regionName.c_str()); @@ -182,7 +185,17 @@ namespace AZ ImGui::TableNextColumn(); ImGui::Text("%.1f", statistics->GetAverageInvocationsPerFrame()); + const ImVec2 botRightBound = ImGui::GetItemRectMax(); ImGui::TableNextColumn(); + + // NOTE: we are manually checking the bounds rather than using ImGui::IsItemHovered + Begin/EndGroup because + // ImGui reports incorrect bounds when using Begin/End group in the Tables API. + if (ImGui::IsMouseHoveringRect(topLeftBound, botRightBound, false)) + { + ImGui::BeginTooltip(); + ImGui::Text(statistics->GetExecutingThreadsLabel().c_str()); + ImGui::EndTooltip(); + } } } ImGui::EndTable(); @@ -275,7 +288,7 @@ namespace AZ { m_tableData.clear(); m_groupRegionMap.clear(); - TableRow::ms_frames = 0; + ImGuiCpuProfiler::ms_framesActive = 0; } DrawTable(); @@ -446,8 +459,8 @@ namespace AZ // Get the latest TimeRegionMap const RHI::CpuProfiler::TimeRegionMap& timeRegionMap = RHI::CpuProfiler::Get()->GetTimeRegionMap(); - m_viewportStartTick = INT64_MAX; - m_viewportEndTick = INT64_MIN; + m_viewportStartTick = AZStd::numeric_limits::max(); + m_viewportEndTick = AZStd::numeric_limits::lowest(); // Iterate through the entire TimeRegionMap and copy the data since it will get deleted on the next frame for (const auto& [threadId, singleThreadRegionMap] : timeRegionMap) @@ -477,7 +490,7 @@ namespace AZ m_tableData.push_back(&m_groupRegionMap[groupName][regionName]); } - m_groupRegionMap[groupName][regionName].RecordRegion(region); + m_groupRegionMap[groupName][regionName].RecordRegion(region, threadId); } } @@ -842,13 +855,13 @@ namespace AZ else { m_frameEndTicks.push_back(AZStd::GetTimeNowTicks()); - TableRow::ms_frames++; + ImGuiCpuProfiler::ms_framesActive++; } } // ---- TableRow impl ---- - inline void TableRow::RecordRegion(const AZ::RHI::CachedTimeRegion& region) + inline void TableRow::RecordRegion(const AZ::RHI::CachedTimeRegion& region, AZStd::thread_id threadId) { m_invocations++; const AZStd::sys_time_t deltaTime = AZStd::abs(region.m_endTick - region.m_startTick); @@ -857,11 +870,23 @@ namespace AZ // Standard running average algorithm const auto newMean = m_runningAverageTicks + aznumeric_cast((deltaTime - m_runningAverageTicks) * 1.0 / m_invocations); m_runningAverageTicks = newMean; + + m_executingThreads.insert(threadId); } inline double TableRow::GetAverageInvocationsPerFrame() const { - return 1.0 * m_invocations / ms_frames; + return 1.0 * m_invocations / ImGuiCpuProfiler::ms_framesActive; + } + + inline AZStd::string TableRow::GetExecutingThreadsLabel() const + { + AZStd::string threadString; + for (const auto& threadId : m_executingThreads) + { + threadString.append(CpuProfilerImGuiHelper::TextThreadId(threadId.m_id) + ", "); + } + return threadString; } } // namespace Render } // namespace AZ From 11a001946fef6536779a1be54d9d8348dd897e88 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Wed, 21 Jul 2021 16:14:08 -0700 Subject: [PATCH 037/157] Visualizer: Implement total time + cleanup Signed-off-by: Jacob Hilliard --- .../Include/Atom/Utils/ImGuiCpuProfiler.h | 131 +++++++++--------- .../Include/Atom/Utils/ImGuiCpuProfiler.inl | 72 ++++++---- 2 files changed, 114 insertions(+), 89 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index d21783a801..a4f5763c99 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -25,41 +24,50 @@ namespace AZ namespace Render { - struct ThreadRegionEntry - { - AZStd::thread_id m_threadId; - AZStd::sys_time_t m_startTick = 0; - AZStd::sys_time_t m_endTick = 0; - }; - + //! Stores all the data associated with a row in the table. struct TableRow { + // Update running statistics with new region data void RecordRegion(const AZ::RHI::CachedTimeRegion& region, AZStd::thread_id threadId); - double GetAverageInvocationsPerFrame() const; + + void ResetPerFrameStatistics(); + + // Get a string of all threads that this region executed in during the last frame AZStd::string TableRow::GetExecutingThreadsLabel() const; AZStd::string m_groupName; AZStd::string m_regionName; - AZStd::sys_time_t m_maxTicks; - AZStd::sys_time_t m_runningAverageTicks; - u64 m_invocations; + // --- Per frame statistics --- + + u64 m_invocationsLastFrame = 0; + + // NOTE: set over unordered_set so the threads can be shown in increasing order in tooltip. AZStd::set m_executingThreads; + + AZStd::sys_time_t m_lastFrameTotalTicks = 0; + + // Maximum execution time of a region in the last frame. + AZStd::sys_time_t m_maxTicks = 0; + + // --- Aggregate statistics --- + + u64 m_invocationsTotal = 0; + + // Running average of Mean Time Per Call + AZStd::sys_time_t m_runningAverageTicks = 0; }; - //! Visual profiler for Cpu statistics. - //! It uses ImGui as the library for displaying the Attachments and Heaps. - //! It shows all heaps that are being used by the RHI and how the FIXME - //! resources are allocated in each heap. + //! ImGui widget for examining Atom CPU Profiling instrumentation. + //! Offers both a statistical view (with sorting and searching capability) and a visualizer + //! similar to RAD and other profiling tools. class ImGuiCpuProfiler : SystemTickBus::Handler { - friend struct TableRow; - - // Region Name -> Array of ThreadRegion entries - using RegionEntryMap = AZStd::map; - // Group Name -> RegionEntryMap - using GroupRegionMap = AZStd::map; + // Region Name -> statistical view row data + using RegionRowMap = AZStd::map; + // Group Name -> RegionRowMap + using GroupRegionMap = AZStd::map; using TimeRegion = AZ::RHI::CachedTimeRegion; using GroupRegionName = AZ::RHI::CachedTimeRegion::GroupRegionName; @@ -71,63 +79,34 @@ namespace AZ //! Draws the overall CPU profiling window, defaults to the statistical view void Draw(bool& keepDrawing, const AZ::RHI::CpuTimingStatistics& cpuTimingStatistics); - //! Draws the statistical view of the CPU profiling data - void DrawStatisticsView(); - - //! Draws the CPU profiling visualizer in a new window. - void DrawVisualizer(); - private: static constexpr float RowHeight = 50.0; static constexpr int DefaultFramesToCollect = 50; static constexpr float MediumFrameTimeLimit = 16.6; // 60 fps static constexpr float HighFrameTimeLimit = 33.3; // 30 fps - static u64 ms_framesActive; + //! Draws the statistical view of the CPU profiling data. + void DrawStatisticsView(); - // Draw the shared header between the two windows + //! Draws the CPU profiling visualizer. + void DrawVisualizer(); + + // Draw the shared header between the two windows. void DrawCommonHeader(); - // Draw the region statstics table in the order specified by the pointers in m_tableData + // Draw the region statistics table in the order specified by the pointers in m_tableData. void DrawTable(); - // Sort the table by a given column, rearranges the pointers in m_tableData + // Sort the table by a given column, rearranges the pointers in m_tableData. void SortTable(ImGuiTableSortSpecs* sortSpecs); - // ImGui filter used to filter TimedRegions. - ImGuiTextFilter m_timedRegionFilter; - - // Saves statistical view data organized by group name -> region name -> row data - GroupRegionMap m_groupRegionMap; - - // Saves pointers to objects in m_groupRegionMap, order reflects table ordering - AZStd::vector m_tableData; - - // Pause cpu profiling. The profiler will show the statistics of the last frame before pause - bool m_paused = false; - - // Export the profiling data from a single frame to a local file - bool m_captureToFile = false; - - // Toggle between the normal statistical view and the visual profiling view - bool m_enableVisualizer = false; - - // Total frames need to be saved - int m_captureFrameCount = 1; - - AZ::RHI::CpuTimingStatistics m_cpuTimingStatisticsWhenPause; - - AZStd::string m_lastCapturedFilePath; - - // Visualizer methods - // Get the profiling data from the last frame, only called when the profiler is not paused. void CollectFrameData(); // Cull old data from internal storage, only called when profiler is not paused. void CullFrameData(const AZ::RHI::CpuTimingStatistics& currentCpuTimingStatistics); - // Draws a single block onto the timeline + // Draws a single block onto the timeline into the specified row void DrawBlock(const TimeRegion& block, u64 targetRow); // Draw horizontal lines between threads in the timeline @@ -150,14 +129,14 @@ namespace AZ AZStd::sys_time_t GetViewportTickWidth() const; - // Gets the color for a block using the GroupRegionName as a key into the cache - // Generates a random ImU32 if the block does not yet have a color + // Gets the color for a block using the GroupRegionName as a key into the cache. + // Generates a random ImU32 if the block does not yet have a color. ImU32 GetBlockColor(const TimeRegion& block); // System tick bus overrides virtual void OnSystemTick() override; - // Visualizer state + // --- Visualizer Members --- int m_framesToCollect = DefaultFramesToCollect; @@ -179,6 +158,32 @@ namespace AZ // Filter for highlighting regions on the visualizer ImGuiTextFilter m_visualizerHighlightFilter; + + // --- Tabular view members --- + + // ImGui filter used to filter TimedRegions. + ImGuiTextFilter m_timedRegionFilter; + + // Saves statistical view data organized by group name -> region name -> row data + GroupRegionMap m_groupRegionMap; + + // Saves pointers to objects in m_groupRegionMap, order reflects table ordering. + // Non-owning, will be cleared when m_groupRegionMap is cleared. + AZStd::vector m_tableData; + + // Pause cpu profiling. The profiler will show the statistics of the last frame before pause. + bool m_paused = false; + + // Export the profiling data from a single frame to a local file. + bool m_captureToFile = false; + + // Toggle between the normal statistical view and the visual profiling view. + bool m_enableVisualizer = false; + + // Last captured CPU timing statistics + AZ::RHI::CpuTimingStatistics m_cpuTimingStatisticsWhenPause; + + AZStd::string m_lastCapturedFilePath; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index 124e48af13..d89fed449a 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -18,16 +18,11 @@ #include #include -#pragma optimize("", off) - -#include "../../../Gems/ImGui/External/ImGui/v1.82/imgui/imgui.h" namespace AZ { namespace Render { - inline u64 ImGuiCpuProfiler::ms_framesActive = 0; - namespace CpuProfilerImGuiHelper { // NOTE: Fix build error in case AZStd::thread_id is not of an arithmetic type, and instead a pointer @@ -145,14 +140,15 @@ namespace AZ { const auto flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Sortable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable; - if (ImGui::BeginTable("FunctionStatisticsTable", 5, flags)) + if (ImGui::BeginTable("FunctionStatisticsTable", 6, flags)) { // Table header setup ImGui::TableSetupColumn("Group"); ImGui::TableSetupColumn("Region"); ImGui::TableSetupColumn("MTPC (ms)"); ImGui::TableSetupColumn("Max (ms)"); - ImGui::TableSetupColumn("Invocations/frame"); + ImGui::TableSetupColumn("Invocations"); + ImGui::TableSetupColumn("Total (ms)"); ImGui::TableHeadersRow(); ImGui::TableNextColumn(); @@ -184,13 +180,16 @@ namespace AZ ImGui::Text("%.2f", CpuProfilerImGuiHelper::TicksToMs(statistics->m_maxTicks)); ImGui::TableNextColumn(); - ImGui::Text("%.1f", statistics->GetAverageInvocationsPerFrame()); + ImGui::Text("%ld", statistics->m_invocationsLastFrame); + ImGui::TableNextColumn(); + + ImGui::Text("%.2f", CpuProfilerImGuiHelper::TicksToMs(statistics->m_lastFrameTotalTicks)); const ImVec2 botRightBound = ImGui::GetItemRectMax(); ImGui::TableNextColumn(); // NOTE: we are manually checking the bounds rather than using ImGui::IsItemHovered + Begin/EndGroup because // ImGui reports incorrect bounds when using Begin/End group in the Tables API. - if (ImGui::IsMouseHoveringRect(topLeftBound, botRightBound, false)) + if (ImGui::IsWindowHovered() && ImGui::IsMouseHoveringRect(topLeftBound, botRightBound, false)) { ImGui::BeginTooltip(); ImGui::Text(statistics->GetExecutingThreadsLabel().c_str()); @@ -215,23 +214,32 @@ namespace AZ break; case (1): // Sort by region name AZStd::sort(m_tableData.begin(), m_tableData.end(),[ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_regionName < rhs->m_regionName : lhs->m_regionName > rhs->m_regionName; + return ascending ? lhs->m_regionName < rhs->m_regionName + : lhs->m_regionName > rhs->m_regionName; }); break; case (2): // Sort by average time AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ return ascending ? lhs->m_runningAverageTicks < rhs->m_runningAverageTicks - : lhs->m_runningAverageTicks > rhs->m_runningAverageTicks; + : lhs->m_runningAverageTicks > rhs->m_runningAverageTicks; }); break; case (3): // Sort by max time AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_maxTicks < rhs->m_maxTicks : lhs->m_maxTicks > rhs->m_maxTicks; + return ascending ? lhs->m_maxTicks < rhs->m_maxTicks + : lhs->m_maxTicks > rhs->m_maxTicks; }); break; case (4): // Sort by invocations AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_invocations < rhs->m_invocations : lhs->m_invocations > rhs->m_invocations; + return ascending ? lhs->m_invocationsLastFrame < rhs->m_invocationsLastFrame + : lhs->m_invocationsLastFrame > rhs->m_invocationsLastFrame; + }); + break; + case (5): // Sort by total time + AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ + return ascending ? lhs->m_lastFrameTotalTicks < rhs->m_lastFrameTotalTicks + : lhs->m_lastFrameTotalTicks > rhs->m_lastFrameTotalTicks; }); break; } @@ -288,7 +296,6 @@ namespace AZ { m_tableData.clear(); m_groupRegionMap.clear(); - ImGuiCpuProfiler::ms_framesActive = 0; } DrawTable(); @@ -855,7 +862,14 @@ namespace AZ else { m_frameEndTicks.push_back(AZStd::GetTimeNowTicks()); - ImGuiCpuProfiler::ms_framesActive++; + + for (auto& [groupName, regionMap] : m_groupRegionMap) + { + for (auto& [regionName, row] : regionMap) + { + row.ResetPerFrameStatistics(); + } + } } } @@ -863,28 +877,34 @@ namespace AZ inline void TableRow::RecordRegion(const AZ::RHI::CachedTimeRegion& region, AZStd::thread_id threadId) { - m_invocations++; - const AZStd::sys_time_t deltaTime = AZStd::abs(region.m_endTick - region.m_startTick); + const AZStd::sys_time_t deltaTime = region.m_endTick - region.m_startTick; + + // Update per frame statistics + m_invocationsLastFrame++; + m_executingThreads.insert(threadId); + m_lastFrameTotalTicks += deltaTime; m_maxTicks = AZStd::max(m_maxTicks, deltaTime); - // Standard running average algorithm - const auto newMean = m_runningAverageTicks + aznumeric_cast((deltaTime - m_runningAverageTicks) * 1.0 / m_invocations); - m_runningAverageTicks = newMean; - - m_executingThreads.insert(threadId); + // Update aggregate statistics + m_runningAverageTicks = + aznumeric_cast((1.0 * (deltaTime + m_invocationsTotal * m_runningAverageTicks)) / (m_invocationsTotal + 1)); + ++m_invocationsTotal; } - inline double TableRow::GetAverageInvocationsPerFrame() const + inline void TableRow::ResetPerFrameStatistics() { - return 1.0 * m_invocations / ImGuiCpuProfiler::ms_framesActive; + m_invocationsLastFrame = 0; + m_executingThreads.clear(); + m_lastFrameTotalTicks = 0; + m_maxTicks = 0; } inline AZStd::string TableRow::GetExecutingThreadsLabel() const { - AZStd::string threadString; + auto threadString = AZStd::string::format("Executed in %zu threads\n", m_executingThreads.size()); for (const auto& threadId : m_executingThreads) { - threadString.append(CpuProfilerImGuiHelper::TextThreadId(threadId.m_id) + ", "); + threadString.append(CpuProfilerImGuiHelper::TextThreadId(threadId.m_id) + "\n"); } return threadString; } From a064cedb59b7680c55d8e46219e82cd0e950a21a Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Tue, 27 Jul 2021 09:40:55 -0700 Subject: [PATCH 038/157] Visualizer: fix clang build error Signed-off-by: Jacob Hilliard --- Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h | 2 +- Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index a4f5763c99..62b71bdbb8 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -33,7 +33,7 @@ namespace AZ void ResetPerFrameStatistics(); // Get a string of all threads that this region executed in during the last frame - AZStd::string TableRow::GetExecutingThreadsLabel() const; + AZStd::string GetExecutingThreadsLabel() const; AZStd::string m_groupName; AZStd::string m_regionName; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index d89fed449a..79a2ffd5a0 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -180,7 +180,7 @@ namespace AZ ImGui::Text("%.2f", CpuProfilerImGuiHelper::TicksToMs(statistics->m_maxTicks)); ImGui::TableNextColumn(); - ImGui::Text("%ld", statistics->m_invocationsLastFrame); + ImGui::Text("%llu", statistics->m_invocationsLastFrame); ImGui::TableNextColumn(); ImGui::Text("%.2f", CpuProfilerImGuiHelper::TicksToMs(statistics->m_lastFrameTotalTicks)); From a271a85d6efd7ef848c169ad1661c52b19986148 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Wed, 28 Jul 2021 09:27:55 -0700 Subject: [PATCH 039/157] Visualizer: postfix -> prefix increment Signed-off-by: Jacob Hilliard --- Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index 79a2ffd5a0..90b6c67905 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -880,7 +880,7 @@ namespace AZ const AZStd::sys_time_t deltaTime = region.m_endTick - region.m_startTick; // Update per frame statistics - m_invocationsLastFrame++; + ++m_invocationsLastFrame; m_executingThreads.insert(threadId); m_lastFrameTotalTicks += deltaTime; m_maxTicks = AZStd::max(m_maxTicks, deltaTime); From 567b4a7f282fb49d797f311fbaeee31ef3b24069 Mon Sep 17 00:00:00 2001 From: Cynthia Lin <15116870+synicalsyntax@users.noreply.github.com> Date: Wed, 28 Jul 2021 11:07:32 -0700 Subject: [PATCH 040/157] [ATOM-16016] Add initial level for AtomFeatureIntegrationBenchmark to AutomatedTesting. (#2405) * [ATOM-16016] Add initial level for AtomFeatureIntegrationBenchmark to AutomatedTesting. Signed-off-by: Cynthia Lin * [ATOM-16016] Add new AtomFeatureIntegrationBenchmark to AutomatedTesting. Signed-off-by: Cynthia Lin --- ...GPUTest_AtomFeatureIntegrationBenchmark.py | 102 ++++++++++++++++++ .../atom_utils/benchmark_utils.py | 84 +++++++++++++++ .../atom_renderer/test_Atom_GPUTests.py | 41 +++++++ .../AtomFeatureIntegrationBenchmark.ly | 3 + .../filelist.xml | 6 ++ .../AtomFeatureIntegrationBenchmark/level.pak | 3 + .../AtomFeatureIntegrationBenchmark/tags.txt | 12 +++ 7 files changed, 251 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py create mode 100644 AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py create mode 100644 AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/AtomFeatureIntegrationBenchmark.ly create mode 100644 AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/filelist.xml create mode 100644 AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/level.pak create mode 100644 AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/tags.txt diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py new file mode 100644 index 0000000000..b899d7dcde --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py @@ -0,0 +1,102 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT + +Hydra script that is used to create a new level with a default rendering setup. +After the level is setup, screenshots are diffed against golden images are used to verify pass/fail results of the test. + +See the run() function for more in-depth test info. +""" + +import os +import sys + +import azlmbr.legacy.general as general + +sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) + +import editor_python_test_tools.hydra_editor_utils as hydra +from editor_python_test_tools.editor_test_helper import EditorTestHelper +from atom_renderer.atom_utils.benchmark_utils import BenchmarkHelper + +SCREEN_WIDTH = 1280 +SCREEN_HEIGHT = 720 +DEGREE_RADIAN_FACTOR = 0.0174533 + +helper = EditorTestHelper(log_prefix="Test_Atom_BasicLevelSetup") + + +def run(): + """ + 1. View -> Layouts -> Restore Default Layout, sets the viewport to ratio 16:9 @ 1280 x 720 + 2. Runs console command r_DisplayInfo = 0 + 3. Opens AtomFeatureIntegrationBenchmark level + 4. Initializes benchmark helper with benchmark name to capture benchmark metadata. + 5. Idles for 100 frames, then collects pass timings for 100 frames. + :return: None + """ + def initial_viewport_setup(screen_width, screen_height): + general.set_viewport_size(screen_width, screen_height) + general.update_viewport() + helper.wait_for_condition( + function=lambda: helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) + and helper.isclose(a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1), + timeout_in_seconds=4.0 + ) + result = helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) and helper.isclose( + a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1) + general.log(general.get_viewport_size().x) + general.log(general.get_viewport_size().y) + general.log(general.get_viewport_size().z) + general.log(f"Viewport is set to the expected size: {result}") + general.run_console("r_DisplayInfo = 0") + + def after_level_load(): + """Function to call after creating/opening a level to ensure it loads.""" + # Give everything a second to initialize. + general.idle_enable(True) + general.idle_wait(1.0) + general.update_viewport() + general.idle_wait(0.5) # half a second is more than enough for updating the viewport. + + # Close out problematic windows, FPS meters, and anti-aliasing. + if general.is_helpers_shown(): # Turn off the helper gizmos if visible + general.toggle_helpers() + general.idle_wait(1.0) + if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus. + general.close_pane("Error Report") + if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus. + general.close_pane("Error Log") + general.idle_wait(1.0) + general.run_console("r_displayInfo=0") + general.run_console("r_antialiasingmode=0") + general.idle_wait(1.0) + + return True + + # Wait for Editor idle loop before executing Python hydra scripts. + general.idle_enable(True) + + general.open_level_no_prompt("AtomFeatureIntegrationBenchmark") + + # Basic setup after opening level. + after_level_load() + initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT) + + general.enter_game_mode() + general.idle_wait(1.0) + helper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=2.0) + benchmarker = BenchmarkHelper("AtomFeatureIntegrationBenchmark") + benchmarker.capture_benchmark_metadata() + general.idle_wait_frames(100) + for i in range(1, 101): + benchmarker.capture_pass_timestamp(i) + general.exit_game_mode() + helper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=2.0) + general.log("Capturing complete.") + + +if __name__ == "__main__": + run() diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py new file mode 100644 index 0000000000..21c7489ed3 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py @@ -0,0 +1,84 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" +import azlmbr.atom +import azlmbr.legacy.general as general + +FOLDER_PATH = '@user@/Scripts/PerformanceBenchmarks' +METADATA_FILE = 'benchmark_metadata.json' + +class BenchmarkHelper(object): + """ + A helper to capture benchmark data. + """ + def __init__(self, benchmark_name): + super().__init__() + self.benchmark_name = benchmark_name + self.output_path = f'{FOLDER_PATH}/{benchmark_name}' + self.done = False + self.capturedData = False + self.max_frames_to_wait = 200 + + def capture_benchmark_metadata(self): + """ + Capture benchmark metadata and block further execution until it has been written to the disk. + """ + self.handler = azlmbr.atom.ProfilingCaptureNotificationBusHandler() + self.handler.connect() + self.handler.add_callback('OnCaptureBenchmarkMetadataFinished', self.on_data_captured) + + self.done = False + self.capturedData = False + success = azlmbr.atom.ProfilingCaptureRequestBus( + azlmbr.bus.Broadcast, "CaptureBenchmarkMetadata", self.benchmark_name, f'{self.output_path}/{METADATA_FILE}' + ) + if success: + self.wait_until_data() + general.log('Benchmark metadata captured.') + else: + general.log('Failed to capture benchmark metadata.') + return self.capturedData + + def capture_pass_timestamp(self, frame_number): + """ + Capture pass timestamps and block further execution until it has been written to the disk. + """ + self.handler = azlmbr.atom.ProfilingCaptureNotificationBusHandler() + self.handler.connect() + self.handler.add_callback('OnCaptureQueryTimestampFinished', self.on_data_captured) + + self.done = False + self.capturedData = False + success = azlmbr.atom.ProfilingCaptureRequestBus( + azlmbr.bus.Broadcast, "CapturePassTimestamp", f'{self.output_path}/frame{frame_number}_timestamps.json') + if success: + self.wait_until_data() + general.log('Pass timestamps captured.') + else: + general.log('Failed to capture pass timestamps.') + return self.capturedData + + def on_data_captured(self, parameters): + # the parameters come in as a tuple + if parameters[0]: + general.log('Captured data successfully.') + self.capturedData = True + else: + general.log('Failed to capture data.') + self.done = True + self.handler.disconnect() + + def wait_until_data(self): + frames_waited = 0 + while self.done == False: + general.idle_wait_frames(1) + if frames_waited > self.max_frames_to_wait: + general.log('Timed out while waiting for the data to be captured') + self.handler.disconnect() + break + else: + frames_waited = frames_waited + 1 + general.log(f'(waited {frames_waited} frames)') diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py index dad92d0932..ede140c075 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py @@ -14,6 +14,7 @@ import pytest import ly_test_tools.environment.file_system as file_system from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots +from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator import editor_python_test_tools.hydra_test_utils as hydra logger = logging.getLogger(__name__) @@ -83,3 +84,43 @@ class TestAllComponentsIndepthTests(object): for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images): compare_screenshots(test_screenshot, golden_screenshot) + +@pytest.mark.parametrize('rhi', ['dx12', 'vulkan']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +@pytest.mark.parametrize("launcher_platform", ["windows_editor"]) +@pytest.mark.parametrize("level", ["AtomFeatureIntegrationBenchmark"]) +class TestPerformanceBenchmarkSuite(object): + def test_AtomFeatureIntegrationBenchmark( + self, request, editor, workspace, rhi, project, launcher_platform, level): + """ + Please review the hydra script run by this test for more specific test info. + Tests the performance of the Simple level. + """ + expected_lines = [ + "Benchmark metadata captured.", + "Pass timestamps captured.", + "Capturing complete.", + "Captured data successfully." + ] + + unexpected_lines = [ + "Failed to capture data.", + "Failed to capture pass timestamps.", + "Failed to capture benchmark metadata." + ] + + hydra.launch_and_validate_results( + request, + TEST_DIRECTORY, + editor, + "hydra_GPUTest_AtomFeatureIntegrationBenchmark.py", + timeout=EDITOR_TIMEOUT, + expected_lines=expected_lines, + unexpected_lines=unexpected_lines, + halt_on_unexpected=True, + cfg_args=[level], + null_renderer=False, + ) + + aggregator = BenchmarkDataAggregator(workspace, logger, 'periodic') + aggregator.upload_metrics(rhi) diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/AtomFeatureIntegrationBenchmark.ly b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/AtomFeatureIntegrationBenchmark.ly new file mode 100644 index 0000000000..4fc96f242b --- /dev/null +++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/AtomFeatureIntegrationBenchmark.ly @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5232563c3ff322669808ac4daeda3d822e4ef8c9c87db0fa245f0f9c9c34aada +size 23379 diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/filelist.xml b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/filelist.xml new file mode 100644 index 0000000000..15b79f5e4f --- /dev/null +++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/filelist.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/level.pak b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/level.pak new file mode 100644 index 0000000000..fecbc0b394 --- /dev/null +++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/level.pak @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e075be2cb7cf5aa98e3503c1119b94c3098b35500c98c4db32d025c9e1afa52d +size 5450 diff --git a/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/tags.txt b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/tags.txt new file mode 100644 index 0000000000..a5e0705349 --- /dev/null +++ b/AutomatedTesting/Levels/AtomFeatureIntegrationBenchmark/tags.txt @@ -0,0 +1,12 @@ +495.045,510.96,35.8437,-0.166,0,-1.82124 +4.79827,4.71364,64.7838,-1.41886,0,2.48964 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 From 15d6ca3252696903eb073870c65a66518104fb7f Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 28 Jul 2021 11:51:21 -0700 Subject: [PATCH 041/157] abandon attepts to enable script canvas tests on the farm Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Code/Framework/AzCore/CMakeLists.txt | 3 --- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Code/Framework/AzCore/CMakeLists.txt b/Code/Framework/AzCore/CMakeLists.txt index 785352cf05..ea7cc27af5 100644 --- a/Code/Framework/AzCore/CMakeLists.txt +++ b/Code/Framework/AzCore/CMakeLists.txt @@ -130,9 +130,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_googletest( NAME AZ::AzCore.Tests ) - if(PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED) - set_tests_properties(AZ::AzCore.Tests.main::TEST_RUN PROPERTIES RUN_SERIAL true) - endif() ly_add_googlebenchmark( NAME AZ::AzCore.Benchmarks TARGET AZ::AzCore.Tests diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 7291cd65eb..dada433772 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -113,8 +113,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::ScriptCanvasTesting.Editor.Tests + TEST_SUITE smoke ) - set_tests_properties(Gem::ScriptCanvasTesting.Editor.Tests.main::TEST_RUN PROPERTIES RUN_SERIAL true) endif() From 6839497d99e0d9a3b762b42bf16d19d2e018ceb9 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Wed, 28 Jul 2021 12:31:19 -0700 Subject: [PATCH 042/157] Corrects math computing blend factors to interpolate state between received network updates Signed-off-by: kberg-amzn --- .../Source/MultiplayerSystemComponent.cpp | 37 +++++++++++++------ .../Code/Source/MultiplayerSystemComponent.h | 2 +- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 9a46bb10de..21c7ce80d6 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -69,19 +69,24 @@ namespace Multiplayer { using namespace AzNetworking; - AZ_CVAR(uint16_t, cl_clientport, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port to bind to for game traffic when connecting to a remote host, a value of 0 will select any available port"); - AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the remote server or host to connect to"); - AZ_CVAR(AZ::CVarFixedString, cl_serverpassword, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Optional server password"); + AZ_CVAR(uint16_t, cl_clientport, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The port to bind to for game traffic when connecting to a remote host, a value of 0 will select any available port"); + AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The address of the remote server or host to connect to"); AZ_CVAR(uint16_t, cl_serverport, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port of the remote host to connect to for game traffic"); AZ_CVAR(uint16_t, sv_port, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that this multiplayer gem will bind to for game traffic"); AZ_CVAR(AZ::CVarFixedString, sv_map, "nolevel", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The map the server should load"); - AZ_CVAR(AZ::CVarFixedString, sv_gamerules, "norules", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "GameRules server works with"); AZ_CVAR(ProtocolType, sv_protocol, ProtocolType::Udp, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "This flag controls whether we use TCP or UDP for game networking"); AZ_CVAR(bool, sv_isDedicated, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether the host command creates an independent or client hosted server"); AZ_CVAR(bool, sv_isTransient, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether a dedicated server shuts down if all existing connections disconnect."); - AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Max Ms to use to activate entities coming from the network, 0 means instantiate everything"); + AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "Max Ms to use to activate entities coming from the network, 0 means instantiate everything"); AZ_CVAR(AZ::TimeMs, sv_serverSendRateMs, AZ::TimeMs{ 50 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum number of milliseconds between each network update"); - AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The default spawnable to use when a new player connects"); + AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The default spawnable to use when a new player connects"); + AZ_CVAR(float, cl_renderTickBlendBase, 0.15f, nullptr, AZ::ConsoleFunctorFlags::Null, + "The base used for blending between network updates, 0.1 will be quite linear, 0.2 or 0.3 will " + "slow down quicker and may be better suited to connections with highly variable latency"); void MultiplayerSystemComponent::Reflect(AZ::ReflectContext* context) { @@ -546,7 +551,7 @@ namespace Multiplayer if ((GetAgentType() == MultiplayerAgentType::Client) && (packet.GetHostFrameId() > m_lastReplicatedHostFrameId)) { // Update client to latest server time - m_renderBlendFactor = 0.0f; + m_tickFactor = 0.0f; m_lastReplicatedHostTimeMs = packet.GetHostTimeMs(); m_lastReplicatedHostFrameId = packet.GetHostFrameId(); m_networkTime.AlterTime(m_lastReplicatedHostFrameId, m_lastReplicatedHostTimeMs, AzNetworking::InvalidConnectionId); @@ -849,10 +854,18 @@ namespace Multiplayer void MultiplayerSystemComponent::TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds) { + m_tickFactor += deltaTime / serverRateSeconds; // Linear close to the origin, but asymptote at y = 1 - const float targetAdjustBlend = AZStd::clamp(deltaTime / serverRateSeconds, 0.0f, 1.0f); - m_renderBlendFactor = 1.0f - (std::pow(0.2f, m_renderBlendFactor + targetAdjustBlend)); - AZLOG(NET_Blending, "Computed blend factor of %0.2f using a frametime of %0.2f and a serverTickRate of %0.2f", m_renderBlendFactor, deltaTime, serverRateSeconds); + const float renderBlendFactor = AZStd::clamp(1.0f - (std::pow(cl_renderTickBlendBase, m_tickFactor)), 0.0f, 1.0f); + AZLOG + ( + NET_Blending, + "Computed blend factor of %0.3f using a tick factor of %0.3f, a frametime of %0.3f and a serverTickRate of %0.3f", + renderBlendFactor, + m_tickFactor, + deltaTime, + serverRateSeconds + ); if (Camera::ActiveCameraRequestBus::HasHandlers()) { @@ -895,7 +908,7 @@ namespace Multiplayer for (NetBindComponent* netBindComponent : gatheredEntities) { - netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor); } } else @@ -907,7 +920,7 @@ namespace Multiplayer NetBindComponent* netBindComponent = entity->FindComponent(); if (netBindComponent != nullptr) { - netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor); } } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 37e8138a71..ab37958962 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -155,7 +155,7 @@ namespace Multiplayer HostFrameId m_lastReplicatedHostFrameId = HostFrameId(0); double m_serverSendAccumulator = 0.0; - float m_renderBlendFactor = 0.0f; + float m_tickFactor = 0.0f; #if !defined(AZ_RELEASE_BUILD) MultiplayerEditorConnection m_editorConnectionListener; From 055df374829d5b2b9c09424e5d098dc3c2a0302d Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:21:37 -0500 Subject: [PATCH 043/157] Register show command fix (#2408) * Updated print_registration functions to fix "register-show" command Added unit test to validate the argparse options to the register show command. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the register.py script to once again register an engine list Previosly each engine were registered into a dictionary with multiple keys, but once the engine.json started to self describe the registered content that came with it, it was reduced to a single 'path' key. Therefore it has been changed to a list to be consistent with other o3de object paths Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the SettingsRegistryMergeUtitls Code which parses the attempts to locate the engine path associated associated with the project.json engine key to check the 'engines_path' object within the o3de_manifest.json Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated print registration unit test to patch the get_project_path This is to make sure that the existence of the placeholder project path isn't validated when running the test Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Typo and formatting fixes for the print_registration script Also corrected indentation in unit_test_print_registration script Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../Settings/SettingsRegistryMergeUtils.cpp | 50 +-- scripts/o3de/o3de/manifest.py | 35 +- scripts/o3de/o3de/print_registration.py | 221 ++++++---- scripts/o3de/o3de/register.py | 79 ++-- scripts/o3de/tests/CMakeLists.txt | 9 +- .../tests/unit_test_print_registration.py | 383 ++++++++++++++++++ 6 files changed, 591 insertions(+), 186 deletions(-) create mode 100644 scripts/o3de/tests/unit_test_print_registration.py diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 74038c8aed..6b89b8c044 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -57,6 +57,7 @@ namespace AZ::Internal // and avoid all this logic. using namespace AZ::SettingsRegistryMergeUtils; + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; AZ::IO::FixedMaxPath engineRoot; if (auto engineManifestPath = AZ::Utils::GetEngineManifestPath(); !engineManifestPath.empty()) @@ -72,45 +73,16 @@ namespace AZ::Internal struct EngineInfo { AZ::IO::FixedMaxPath m_path; - AZ::SettingsRegistryInterface::FixedValueString m_moniker; + FixedValueString m_moniker; }; struct EnginePathsVisitor : public AZ::SettingsRegistryInterface::Visitor { void Visit( - [[maybe_unused]] AZStd::string_view path, [[maybe_unused]] AZStd::string_view valueName, + [[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, [[maybe_unused]] AZ::SettingsRegistryInterface::Type type, AZStd::string_view value) override { - m_enginePaths.emplace_back(EngineInfo{AZ::IO::FixedMaxPath{value}.LexicallyNormal(), {}}); - } - - AZ::SettingsRegistryInterface::VisitResponse Traverse( - [[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, - AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type type) override - { - auto response = AZ::SettingsRegistryInterface::VisitResponse::Continue; - if (action == AZ::SettingsRegistryInterface::VisitAction::Begin) - { - if (type == AZ::SettingsRegistryInterface::Type::Array) - { - if (valueName.compare("engines") != 0) - { - response = AZ::SettingsRegistryInterface::VisitResponse::Skip; - } - } - } - else if (action == AZ::SettingsRegistryInterface::VisitAction::Value) - { - if (type == AZ::SettingsRegistryInterface::Type::String) - { - if (valueName.compare("path") != 0) - { - response = AZ::SettingsRegistryInterface::VisitResponse::Skip; - } - } - } - - return response; + m_enginePaths.emplace_back(EngineInfo{ AZ::IO::FixedMaxPath{value}.LexicallyNormal(), FixedValueString{valueName} }); } AZStd::vector m_enginePaths{}; @@ -119,11 +91,11 @@ namespace AZ::Internal EnginePathsVisitor pathVisitor; if (manifestLoaded) { - auto enginePathsKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engines", EngineManifestRootKey); + auto enginePathsKey = FixedValueString::format("%s/engines_path", EngineManifestRootKey); settingsRegistry.Visit(pathVisitor, enginePathsKey); } - const auto engineMonikerKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engine_name", EngineSettingsRootKey); + const auto engineMonikerKey = FixedValueString::format("%s/engine_name", EngineSettingsRootKey); AZStd::set projectPathsNotFound; @@ -135,7 +107,15 @@ namespace AZ::Internal if (settingsRegistry.MergeSettingsFile( engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, EngineSettingsRootKey)) { - settingsRegistry.Get(engineInfo.m_moniker, engineMonikerKey); + FixedValueString engineName; + settingsRegistry.Get(engineName, engineMonikerKey); + AZ_Warning("SettingsRegistryMergeUtils",engineInfo.m_moniker == engineName, + R"(The engine name key "%s" mapped to engine path "%s" within the global manifest of "%s")" + R"( does not match the "engine_name" field "%s" in the engine.json)" "\n" + "This engine should be re-registered.", + engineInfo.m_moniker.c_str(), engineInfo.m_path.c_str(), engineManifestPath.c_str(), + engineName.c_str()) + engineInfo.m_moniker = engineName; } } diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 5bc6b95358..7e504d29cd 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -236,15 +236,13 @@ def get_gems_from_subdirectories(external_subdirs: list) -> list: # Data query methods -def get_this_engine() -> dict: - json_data = load_o3de_manifest() - engine_data = find_engine_data(json_data) - return engine_data - - def get_engines() -> list: json_data = load_o3de_manifest() - return json_data['engines'] if 'engines' in json_data else [] + engine_list = json_data['engines'] if 'engines' in json_data else [] + # Convert each engine dict entry into a string entry + return list(map( + lambda engine_object: engine_object.get('path', '') if isinstance(engine_object, dict) else engine_object, + engine_list)) def get_projects() -> list: @@ -424,20 +422,6 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa return list(filter(filter_project_and_gem_templates_out, get_all_templates())) -def find_engine_data(json_data: dict, - engine_path: str or pathlib.Path = None) -> dict or None: - if not engine_path: - engine_path = get_this_engine_path() - engine_path = pathlib.Path(engine_path).resolve() - - for engine_object in json_data['engines']: - engine_object_path = pathlib.Path(engine_object['path']).resolve() - if engine_path == engine_object_path: - return engine_object - - return None - - def get_engine_json_data(engine_name: str = None, engine_path: str or pathlib.Path = None) -> dict or None: if not engine_name and not engine_path: @@ -639,8 +623,13 @@ def get_registered(engine_name: str = None, # check global first then this engine if isinstance(engine_name, str): - for engine in json_data['engines']: - engine_path = pathlib.Path(engine['path']).resolve() + engines = get_engines() + for engine in engines: + if isinstance(engine, dict): + engine_path = pathlib.Path(engine['path']).resolve() + else: + engine_path = pathlib.Path(engine_object).resolve() + engine_json = engine_path / 'engine.json' with engine_json.open('r') as f: try: diff --git a/scripts/o3de/o3de/print_registration.py b/scripts/o3de/o3de/print_registration.py index 10316cc4a8..b164243b7c 100644 --- a/scripts/o3de/o3de/print_registration.py +++ b/scripts/o3de/o3de/print_registration.py @@ -40,61 +40,67 @@ def get_project_path(project_path: pathlib.Path, project_name: str) -> pathlib.P def print_this_engine(verbose: int) -> int: - engine_data = manifest.get_this_engine() - print(json.dumps(engine_data, indent=4)) - result = True + this_engine_path = manifest.get_this_engine_path() + print(f'This Engine:\n{json.dumps(str(this_engine_path), indent=4)}') if verbose > 0: - result = print_manifest_json_data(engine_data, 'engine.json', 'This Engine', + return print_manifest_json_data([this_engine_path], 'This Engine', manifest.get_engine_json_data, 'engine_path') - return 0 if result else 1 + return 0 def print_engines(verbose: int) -> None: engines_data = manifest.get_engines() - print(json.dumps(engines_data, indent=4)) + print(f'Engine Paths:\n{json.dumps(engines_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(engines_data, 'engine.json', 'Engines', + return print_manifest_json_data(engines_data, 'Engine Jsons', manifest.get_engine_json_data, 'engine_path') return 0 def print_projects(verbose: int) -> int: projects_data = manifest.get_projects() - print(json.dumps(projects_data, indent=4)) + print(f'Project Paths:\n{json.dumps(projects_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(projects_data, 'project.json', 'Projects', + return print_manifest_json_data(projects_data, 'Project Jsons', manifest.get_project_json_data, 'project_path') return 0 def print_gems(verbose: int) -> int: gems_data = manifest.get_gems() - print(json.dumps(gems_data, indent=4)) + print(f'Gem Paths:\n{json.dumps(gems_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(gems_data, 'gem.json', 'Gems', + return print_manifest_json_data(gems_data, 'Gem Jsons', manifest.get_gem_json_data, 'gem_path') return 0 +def print_external_subdirectories(verbose: int) -> int: + external_subdirs_data = manifest.get_external_subdirectories() + print(f'External Subdirectories:\n{json.dumps(external_subdirs_data, indent=4)}') + return 0 + + + def print_templates(verbose: int) -> int: templates_data = manifest.get_templates() - print(json.dumps(templates_data, indent=4)) + print(f'Template Paths:\n{json.dumps(templates_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(templates_data, 'template.json', 'Templates', + return print_manifest_json_data(templates_data, 'Template Jsons', manifest.get_template_json_data, 'template_path') return 0 def print_restricted(verbose: int) -> int: restricted_data = manifest.get_restricted() - print(json.dumps(restricted_data, indent=4)) + print(f'Restricted Paths:\n{json.dumps(restricted_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(restricted_data, 'restricted.json', 'Restricted', + return print_manifest_json_data(restricted_data, 'Restricted Jsons', manifest.get_restricted_json_data, 'restricted_path') return 0 @@ -102,47 +108,47 @@ def print_restricted(verbose: int) -> int: # Engine output methods def print_engine_projects(verbose: int) -> int: engine_projects_data = manifest.get_engine_projects() - print(json.dumps(engine_projects_data, indent=4)) + print(f'Project Paths:\n{json.dumps(engine_projects_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(engine_projects_data, 'project.json', 'Projects', + return print_manifest_json_data(engine_projects_data, 'Project Jsons', manifest.get_project_json_data, 'project_path') return 0 def print_engine_gems(verbose: int) -> int: engine_gems_data = manifest.get_engine_gems() - print(json.dumps(engine_gems_data, indent=4)) + print(f'Gem Paths:\n{json.dumps(engine_gems_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(engine_gems_data, 'gem.json', 'Gems', + return print_manifest_json_data(engine_gems_data, 'Gem Jsons', manifest.get_gem_json_data, 'gem_path') return 0 def print_engine_templates(verbose: int) -> int: engine_templates_data = manifest.get_engine_templates() - print(json.dumps(engine_templates_data, indent=4)) + print(f'Template Paths:\n{json.dumps(engine_templates_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(engine_templates_data, 'template.json', 'Templates', + return print_manifest_json_data(engine_templates_data, 'Template Jsons', manifest.get_template_json_data, 'template_path') return 0 def print_engine_restricted(verbose: int) -> int: engine_restricted_data = manifest.get_engine_restricted() - print(json.dumps(engine_restricted_data, indent=4)) + print(f'Restricted Paths:\n{json.dumps(engine_restricted_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(engine_restricted_data, 'restricted.json', 'Restricted', + return print_manifest_json_data(engine_restricted_data, 'Restricted Jsons', manifest.get_restricted_json_data, 'restricted_path') return 0 -def print_engine_external_subdirectories() -> int: +def print_engine_external_subdirectories(verbose: int) -> int: external_subdirs_data = manifest.get_engine_external_subdirectories() - print(json.dumps(external_subdirs_data, indent=4)) + print(f'External Subdirectories:\n{json.dumps(external_subdirs_data, indent=4)}') return 0 @@ -153,21 +159,21 @@ def print_project_gems(verbose: int, project_path: pathlib.Path, project_name: s return 1 project_gems_data = manifest.get_project_gems(project_path) - print(json.dumps(project_gems_data, indent=4)) + print(f'Gem Paths:\n{json.dumps(project_gems_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(project_gems_data, 'gem.json', 'Gems', + return print_manifest_json_data(project_gems_data, 'Gems Jsons', manifest.get_gem_json_data, 'gem_path') return 0 -def print_project_external_subdirectories(project_path: pathlib.Path, project_name: str) -> int: +def print_project_external_subdirectories(verbose: int, project_path: pathlib.Path, project_name: str) -> int: project_path = get_project_path(project_path, project_name) if not project_path: return 1 external_subdirs_data = manifest.get_project_external_subdirectories(project_path) - print(json.dumps(external_subdirs_data, indent=4)) + print(f'External Subdirectories:\n{json.dumps(external_subdirs_data, indent=4)}') return 0 @@ -177,9 +183,9 @@ def print_project_templates(verbose: int, project_path: pathlib.Path, project_na return 1 project_templates_data = manifest.get_project_templates(project_path) - print(json.dumps(project_templates_data, indent=4)) + print(f'Template Paths:\n{json.dumps(project_templates_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(project_templates_data, 'template.json', 'Templates', + return print_manifest_json_data(project_templates_data, 'Template Jsons', manifest.get_template_json_data, 'template_path') return 0 @@ -190,73 +196,118 @@ def print_project_restricted(verbose: int, project_path: pathlib.Path, project_n return 1 project_restricted_data = manifest.get_project_restricted(project_path) - print(json.dumps(project_restricted_data, indent=4)) + print(f'Restricted Paths:\n{json.dumps(project_restricted_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(project_restricted_data, 'restricted.json', 'Restricted', + return print_manifest_json_data(project_restricted_data, 'Restricted Jsons', manifest.get_restricted_json_data, 'restricted_path') return 0 def print_all_projects(verbose: int) -> int: all_projects_data = manifest.get_all_projects() - print(json.dumps(all_projects_data, indent=4)) + print(f'Project Paths:\n{json.dumps(all_projects_data, indent=4)}') if verbose > 0: - return print_manifest_json_data(all_projects_data, 'project.json', 'Projects', + return print_manifest_json_data(all_projects_data, 'Project Jsons', manifest.get_project_json_data, 'project_path') return 0 -def print_all_gems(verbose: int) -> int: - all_gems_data = manifest.get_all_gems() - print(json.dumps(all_gems_data, indent=4)) +def print_all_gems(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: + all_gems = manifest.get_gems() + all_gems.extend(manifest.get_engine_gems()) + + # If a project path or project name is supplied query the gems from that project, otherwise query the gems from + # all projects + project_path = get_project_path(project_path, project_name) if project_path or project_name else None + projects = [project_path] if project_path else manifest.get_all_projects() + for project in projects: + all_gems.extend(manifest.get_project_gems(project)) + + # Filter out duplicates + all_gems = list(dict.fromkeys(all_gems)) + print(f'Gem Paths:\n{json.dumps(all_gems, indent=4)}') if verbose > 0: - return print_manifest_json_data(all_gems_data, 'gem.json', 'Gems', + return print_manifest_json_data(all_gems, 'Gem Jsons', manifest.get_gem_json_data, 'gem_path') return 0 -def print_all_external_subdirectories() -> int: - all_external_subdirectories_data = manifest.get_all_external_subdirectories() - print(json.dumps(all_external_subdirectories_data, indent=4)) +def print_all_external_subdirectories(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: + all_external_subdirectories = manifest.get_external_subdirectories() + all_external_subdirectories.extend(manifest.get_engine_external_subdirectories()) + + # If a project path or project name is supplied query the external subdirectories from that project, + # otherwise query the external subdirectories from all projects + project_path = get_project_path(project_path, project_name) if project_path or project_name else None + projects = [project_path] if project_path else manifest.get_all_projects() + for project in projects: + all_external_subdirectories.extend(manifest.get_project_external_subdirectories(project)) + + # Filter out duplicates + all_external_subdirectories = list(dict.fromkeys(all_external_subdirectories)) + print(f'External Subdirectories:\n{json.dumps(all_external_subdirectories, indent=4)}') return 0 -def print_all_templates(verbose: int) -> int: - all_templates_data = manifest.get_all_templates() - print(json.dumps(all_templates_data, indent=4)) + +def print_all_templates(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: + all_templates = manifest.get_templates() + all_templates.extend(manifest.get_engine_templates()) + + # If a project path or project name is supplied query the templates from that project, + # otherwise query the templates from all projects + project_path = get_project_path(project_path, project_name) if project_path or project_name else None + projects = [project_path] if project_path else manifest.get_all_projects() + for project in projects: + all_templates.extend(manifest.get_project_templates(project)) + + # Filter out duplicates + all_templates = list(dict.fromkeys(all_templates)) + print(f'Template Paths:\n{json.dumps(all_templates, indent=4)}') if verbose > 0: - return print_manifest_json_data(all_templates_data, 'template.json', 'Templates', + return print_manifest_json_data(all_templates, 'Template Jsons', manifest.get_template_json_data, 'template_path') return 0 -def print_all_restricted(verbose: int) -> int: - all_restricted_data = manifest.get_all_restricted() - print(json.dumps(all_restricted_data, indent=4)) +def print_all_restricted(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: + all_restricted = manifest.get_restricted() + all_restricted.extend(manifest.get_engine_restricted()) + + # If a project path or project name is supplied query the restricted from that project, + # otherwise query the restricted from all projects + project_path = get_project_path(project_path, project_name) if project_path or project_name else None + projects = [project_path] if project_path else manifest.get_all_projects() + for project in projects: + all_restricted.extend(manifest.get_project_restricted(project)) + + # Filter out duplicates + all_restricted = list(dict.fromkeys(all_restricted)) + print(f'Restricted Paths:\n{json.dumps(all_restricted, indent=4)}') if verbose > 0: - return print_manifest_json_data(all_restricted_data, 'restricted.json', 'Restricted', + return print_manifest_json_data(all_restricted, 'Restricted Jsons', manifest.get_restricted_json_data, 'restricted_path') return 0 -def print_manifest_json_data(uri_json_data: dict, json_filename: str, +def print_manifest_json_data(uri_json_data: list, print_prefix: str, get_json_func: callable, get_json_data_kw: str) -> int: print('\n') print(f"{print_prefix}================================================") for manifest_uri in uri_json_data: # if it's not local it should be in the cache - parsed_uri = urllib.parse.urlparse(manifest_uri) + parsed_uri = urllib.parse.urlparse(pathlib.Path(manifest_uri).as_posix()) if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: repo_sha256 = hashlib.sha256(manifest_uri.encode()) cache_folder = manifest.get_o3de_cache_folder() manifest_json_path = cache_folder / str(repo_sha256.hexdigest() + '.json') else: - manifest_json_path = pathlib.Path(manifest_uri).resolve() / json_filename + manifest_json_path = pathlib.Path(manifest_uri).resolve() - json_data = get_json_func(**{get_json_data_kwargs: manifest_json_path}) + json_data = get_json_func(**{get_json_data_kw: manifest_json_path}) if json_data: print(manifest_json_path) print(json.dumps(json_data, indent=4) + '\n') @@ -284,29 +335,30 @@ def print_repos_data(repos_data: dict) -> int: return 0 -def register_show_repos(verbose: int) -> None: +def print_repos(verbose: int) -> int: repos_data = manifest.get_repos() print(json.dumps(repos_data, indent=4)) if verbose > 0: - return print_repos_data(repos_data) == 0 + return print_repos_data(repos_data) return 0 -def register_show(verbose: int) -> None: +def register_show(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int: json_data = manifest.load_o3de_manifest() print(f"{manifest.get_o3de_manifest()}:") print(json.dumps(json_data, indent=4)) - result = True + result = 0 if verbose > 0: - result = print_manifest_json_data(manifest.get_engines()) == 0 and result - result = print_manifest_json_data(manifest.get_all_projects()) == 0 and result - result = print_manifest_json_data(manifest.get_gems()) == 0 and result - result = print_manifest_json_data(manifest.get_all_templates()) == 0 and result - result = print_manifest_json_data(manifest.get_all_restricted()) == 0 and result - result = print_repos_data(manifest.get_repos()) == 0 and result - return 0 if result else 1 + result = print_engines(verbose) or result + result = print_all_projects(verbose) or result + result = print_all_gems(verbose, project_path, project_name) or result + result = print_all_templates(verbose, project_path, project_name) or result + result = print_all_restricted(verbose, project_path, project_name) or result + result = print_repos(verbose) or result + + return result def _run_register_show(args: argparse) -> int: @@ -321,6 +373,8 @@ def _run_register_show(args: argparse) -> int: return print_projects(args.verbose) elif args.gems: return print_gems(args.verbose) + elif args.external_subdirectories: + return print_external_subdirectories(args.verbose) elif args.templates: return print_templates(args.verbose) elif args.repos: @@ -333,7 +387,7 @@ def _run_register_show(args: argparse) -> int: elif args.engine_gems: return print_engine_gems(args.verbose) elif args.engine_external_subdirectories: - return print_engine_external_subdirectories() + return print_engine_external_subdirectories(args.verbose) elif args.engine_templates: return print_engine_templates(args.verbose) elif args.engine_restricted: @@ -342,7 +396,7 @@ def _run_register_show(args: argparse) -> int: elif args.project_gems: return print_project_gems(args.verbose, args.project_path, args.project_name) elif args.project_external_subdirectories: - return print_project_external_subdirectories(args.project_path, args.project_name) + return print_project_external_subdirectories(args.verbose, args.project_path, args.project_name) elif args.project_templates: return print_project_templates(args.verbose, args.project_path, args.project_name) elif args.project_restricted: @@ -351,16 +405,16 @@ def _run_register_show(args: argparse) -> int: elif args.all_projects: return print_all_projects(args.verbose) elif args.all_gems: - return print_all_gems(args.verbose) + return print_all_gems(args.verbose, args.project_path, args.project_name) elif args.all_external_subdirectories: - return print_all_external_subdirectories() + return print_all_external_subdirectories(args.verbose, args.project_path, args.project_name) elif args.all_templates: - return print_all_templates(args.verbose) + return print_all_templates(args.verbose, args.project_path, args.project_name) elif args.all_restricted: - return print_all_restricted(args.verbose) + return print_all_restricted(args.verbose, args.project_path, args.project_name) else: - return register_show(args.verbose) + return register_show(args.verbose, args.project_path, args.project_name) def add_parser_args(parser): @@ -393,6 +447,9 @@ def add_parser_args(parser): group.add_argument('-rs', '--restricted', action='store_true', required=False, default=False, help='Output the restricted directories registered in the global ~/.o3de/o3de_manifest.json.') + group.add_argument('-es', '--external-subdirectories', action='store_true', required=False, + default=False, + help='Output the external subdirectories registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-ep', '--engine-projects', action='store_true', required=False, default=False, @@ -428,16 +485,28 @@ def add_parser_args(parser): help='Output all projects registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.') group.add_argument('-ag', '--all-gems', action='store_true', required=False, default=False, - help='Output all gems registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos') + help='Output all gems registered in the ~/.o3de/o3de_manifest.json and the current engine.json.' + ' If --project-path or --project-name option is supplied, outputs gems registered in' + ' that project\'s project.json otherwise outputs registered gems from all registered projects.' + ' Ignores repos') group.add_argument('-at', '--all-templates', action='store_true', required=False, default=False, - help='Output all templates registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.') + help='Output all templates registered in the ~/.o3de/o3de_manifest.json and the current engine.json.' + ' If --project-path or --project-name option is supplied, outputs templates registered in' + ' that project\'s project.json otherwise outputs registered templates from all registered' + ' projects. Ignores repos') group.add_argument('-ares', '--all-restricted', action='store_true', required=False, default=False, - help='Output all restricted directory registered in the ~/.o3de/o3de_manifest.json and the current engine.json.') + help='Output all restricted directory registered in the ~/.o3de/o3de_manifest.json and the current engine.json.' + ' If --project-path or --project-name option is supplied, outputs restricted' + ' directories registered in that project\'s project.json otherwise outputs restricted' + ' directories registered from all registered projects. Ignores repos') group.add_argument('-aes', '--all-external-subdirectories', action='store_true', default=False, - help='Output all external subdirectories registered in the ~/.o3de/o3de_manifest.json and the current engine.json.') + help='Output all external subdirectories registered in the ~/.o3de/o3de_manifest.json and the current engine.json.' + ' If --project-path or --project-name options is supplied, outputs external' + ' subdirectories registered in that project\'s project.json otherwise outputs external' + ' subdirectories registered from all registered projects. Ignores repos') parser.add_argument('-v', '--verbose', action='count', required=False, default=0, diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index fb91cb5bea..8481c5fae0 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -261,43 +261,6 @@ def add_engine_name_to_path(json_data: dict, engine_path: pathlib.Path, force: b return 0 -def register_engine_path(json_data: dict, - engine_path: pathlib.Path, - remove: bool = False, - force: bool = False) -> int: - if not engine_path: - logger.error(f'Engine path cannot be empty.') - return 1 - engine_path = pathlib.Path(engine_path).resolve() - - for engine_object in json_data.get('engines', []): - if isinstance(engine_object, dict): - engine_object_path = pathlib.Path(engine_object['path']).resolve() - else: - engine_object_path = pathlib.Path(engine_object).resolve() - if engine_object_path == engine_path: - json_data['engines'].remove(engine_object) - - if remove: - return remove_engine_name_to_path(json_data, engine_path) - - if not engine_path.is_dir(): - logger.error(f'Engine path {engine_path} does not exist.') - return 1 - - engine_json = engine_path / 'engine.json' - if not validation.valid_o3de_engine_json(engine_json): - logger.error(f'Engine json {engine_json} is not valid.') - return 1 - - engine_object = {} - engine_object.update({'path': engine_path.as_posix()}) - - json_data.setdefault('engines', []).insert(0, engine_object) - - return add_engine_name_to_path(json_data, engine_path, force) - - def register_o3de_object_path(json_data: dict, o3de_object_path: str or pathlib.Path, o3de_object_key: str, @@ -343,7 +306,7 @@ def register_o3de_object_path(json_data: dict, try: paths_to_remove.append(o3de_object_path.relative_to(save_path.parent)) except ValueError: - pass # It is OK relative path cannot be formed + pass # It is not an error if a relative path cannot be formed manifest_data[o3de_object_key] = list(filter(lambda p: pathlib.Path(p) not in paths_to_remove, manifest_data.setdefault(o3de_object_key, []))) @@ -358,7 +321,7 @@ def register_o3de_object_path(json_data: dict, manifest_json_path = o3de_object_path / o3de_json_filename if validation_func and not validation_func(manifest_json_path): - logger.error(f'o3de json {manifest_json_path} is not valid.') + logger.error(f'Manifest at path {manifest_json_path} is not valid.') return 1 # if there is a save path make it relative the directory containing o3de object json file @@ -374,6 +337,27 @@ def register_o3de_object_path(json_data: dict, return 0 +def register_engine_path(json_data: dict, + engine_path: pathlib.Path, + remove: bool = False, + force: bool = False) -> int: + # If the o3de_manifest.json 'engines' key is list containing dictionary entries, transform it to a list of strings + engine_list = json_data.get('engines', []) + + def transform_engine_dict_to_string(engine): return engine.get('path', '') if isinstance(engine, dict) else engine + json_data['engines'] = list(map(transform_engine_dict_to_string, engine_list)) + + result = register_o3de_object_path(json_data, engine_path, 'engines', 'engine.json', + validation.valid_o3de_engine_json, remove) + if result != 0: + return result + + if remove: + return remove_engine_name_to_path(json_data, engine_path) + + return add_engine_name_to_path(json_data, engine_path, force) + + def register_external_subdirectory(json_data: dict, external_subdir_path: pathlib.Path, remove: bool = False, @@ -677,37 +661,30 @@ def remove_invalid_o3de_projects(manifest_path: pathlib.Path = None) -> int: return result def remove_invalid_o3de_objects() -> None: - json_data = manifest.load_o3de_manifest() - - for engine_object in json_data.get('engines', []): - engine_path = engine_object.get('path', '') + for engine_path in manifest.get_engines(): if not validation.valid_o3de_engine_json(pathlib.Path(engine_path).resolve() / 'engine.json'): logger.warn(f"Engine path {engine_path} is invalid.") register(engine_path=engine_path, remove=True) remove_invalid_o3de_projects() - for gem in json_data.get('gems', []): - if not validation.valid_o3de_gem_json(pathlib.Path(gem).resolve() / 'gem.json'): - logger.warn(f"Gem path {gem} is invalid.") - register(gem_path=gem, remove=True) - - for external in json_data.get('external_subdirectories', []): + for external in manifest.get_external_subdirectories(): external = pathlib.Path(external).resolve() if not external.is_dir(): logger.warn(f"External subdirectory {external} is invalid.") register(engine_path=engine_path, external_subdir_path=external, remove=True) - for template in json_data.get('templates', []): + for template in manifest.get_templates(): if not validation.valid_o3de_template_json(pathlib.Path(template).resolve() / 'template.json'): logger.warn(f"Template path {template} is invalid.") register(template_path=template, remove=True) - for restricted in json_data.get('restricted', []): + for restricted in manifest.get_restricted(): if not validation.valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): logger.warn(f"Restricted path {restricted} is invalid.") register(restricted_path=restricted, remove=True) + json_data = manifest.load_o3de_manifest() default_engines_folder = pathlib.Path(json_data.get('default_engines_folder', manifest.get_o3de_engines_folder())).resolve() if not default_engines_folder.is_dir(): new_default_engines_folder = manifest.get_o3de_folder() / 'Engines' diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 00d0774c45..1cd6eac7ee 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -65,4 +65,11 @@ ly_add_pytest( PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_engine_template.py TEST_SUITE smoke EXCLUDE_TEST_RUN_TARGET_FROM_IDE -) \ No newline at end of file +) + +ly_add_pytest( + NAME o3de_register_show + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_print_registration.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/tests/unit_test_print_registration.py b/scripts/o3de/tests/unit_test_print_registration.py new file mode 100644 index 0000000000..7e3e75edcd --- /dev/null +++ b/scripts/o3de/tests/unit_test_print_registration.py @@ -0,0 +1,383 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +import argparse +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from o3de import print_registration + + +TEST_PROJECT_JSON_PAYLOAD = ''' +{ + "project_name": "MinimalProject", + "origin": "The primary repo for MinimalProject goes here: i.e. http://www.mydomain.com", + "license": "What license MinimalProject uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "MinimalProject", + "summary": "A short description of MinimalProject.", + "canonical_tags": [ + "Project" + ], + "user_tags": [ + "MinimalProject" + ], + "icon_path": "preview.png", + "engine": "o3de-install", + "external_subdirectories": [ + "D:/TestGem" + ] +} +''' + +TEST_ENGINE_JSON_PAYLOAD = ''' +{ + "engine_name": "o3de", + "restricted_name": "o3de", + "FileVersion": 1, + "O3DEVersion": "0.0.0.0", + "O3DECopyrightYear": 2021, + "O3DEBuildNumber": 0, + "external_subdirectories": [ + "Gems/TestGem2" + ], + "projects": [ + ], + "templates": [ + "Templates/MinimalProject" + ] +} +''' + +TEST_GEM_JSON_PAYLOAD = ''' +{ + "gem_name": "TestGem", + "display_name": "TestGem", + "license": "What license TestGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "origin": "The primary repo for TestGem goes here: i.e. http://www.mydomain.com", + "type": "Code", + "summary": "A short description of TestGem.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "TestGem" + ], + "icon_path": "preview.png", + "requirements": "" +} +''' + +TEST_TEMPLATE_JSON_PAYLOAD = ''' +{ + "template_name": "AssetGem", + "origin": "The primary repo for AssetGem goes here: i.e. http://www.mydomain.com", + "license": "What license AssetGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "AssetGem", + "summary": "A short description of AssetGem template.", + "canonical_tags": [], + "user_tags": [ + "AssetGem" + ], + "icon_path": "preview.png", + "copyFiles": [ + { + "file": "CMakeLists.txt", + "origin": "CMakeLists.txt", + "isTemplated": true, + "isOptional": false + }, + { + "file": "gem.json", + "origin": "gem.json", + "isTemplated": true, + "isOptional": false + }, + { + "file": "preview.png", + "origin": "preview.png", + "isTemplated": false, + "isOptional": false + } + ], + "createDirectories": [ + { + "dir": "Assets", + "origin": "Assets" + } + ] +} +''' + +TEST_RESTRICTED_JSON_PAYLOAD = ''' +{ + "restricted_name": "o3de" +} +''' + +TEST_O3DE_MANIFEST_JSON_PAYLOAD = ''' +{ + "o3de_manifest_name": "testuser", + "origin": "C:/Users/testuser/.o3de", + "default_engines_folder": "C:/Users/testuser/.o3de/Engines", + "default_projects_folder": "C:/Users/testuser/.o3de/Projects", + "default_gems_folder": "C:/Users/testuser/.o3de/Gems", + "default_templates_folder": "C:/Users/testuser/.o3de/Templates", + "default_restricted_folder": "C:/Users/testuser/.o3de/Restricted", + "default_third_party_folder": "C:/Users/testuser/.o3de/3rdParty", + "projects": [ + "D:/MinimalProject" + ], + "external_subdirectories": [], + "templates": [], + "restricted": [], + "repos": [], + "engines": [ + "D:/o3de/o3de" + ], + "engines_path": { + "o3de": "D:/o3de/o3de" + } +} +''' + +class TestPrintRegistration: + @staticmethod + def load_manifest_json(): + return json.loads(TEST_O3DE_MANIFEST_JSON_PAYLOAD) + + @staticmethod + def get_engine_json_data(engine_path: pathlib.Path = None): + return json.loads(TEST_ENGINE_JSON_PAYLOAD) + + @staticmethod + def get_project_json_data(project_path: pathlib.Path = None): + return json.loads(TEST_PROJECT_JSON_PAYLOAD) + + @staticmethod + def get_gem_json_data(gem_path: pathlib.Path = None): + return json.loads(TEST_GEM_JSON_PAYLOAD) + + @staticmethod + def get_template_json_data(template_path: pathlib.Path = None): + return json.loads(TEST_TEMPLATE_JSON_PAYLOAD) + + @staticmethod + def get_restricted_json_data(restricted_path: pathlib.Path = None): + return json.loads(TEST_RESTRICTED_JSON_PAYLOAD) + + @pytest.mark.parametrize("project_path, verbose", [ + pytest.param(None, 0), + pytest.param(None, 1), + pytest.param(pathlib.Path("D:/MinimalProject"), 0), + pytest.param(pathlib.Path("D:/MinimalProject"), 1) + ]) + def test_print_registration_no_option(self, project_path, verbose): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + print_registration.add_parser_args(parser) + arg_list = [] + if project_path: + arg_list += ['--project-path', project_path.as_posix()] + if verbose: + arg_list += ['-' + 'v' * verbose] + test_args = parser.parse_args(arg_list) + + with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ + patch('o3de.manifest.get_engine_json_data', + side_effect=self.get_engine_json_data) as get_engine_json_data_patch, \ + patch('o3de.manifest.get_project_json_data', + side_effect=self.get_project_json_data) as get_project_json_patch, \ + patch('o3de.manifest.get_gem_json_data', side_effect=self.get_gem_json_data) as get_gem_json_patch, \ + patch('o3de.manifest.get_template_json_data', side_effect=self.get_template_json_data) as get_template_json_patch, \ + patch('o3de.manifest.get_restricted_json_data', side_effect=self.get_restricted_json_data) as get_json_patch: + result = print_registration._run_register_show(test_args) + assert result == 0 + + + @pytest.mark.parametrize("engine_arg_option, verbose", [ + pytest.param("--this-engine", 0), + pytest.param("--this-engine", 1), + pytest.param("--engines", 0), + pytest.param("--engines", 1) + ]) + def test_print_engine_registration(self, engine_arg_option, verbose): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + print_registration.add_parser_args(parser) + arg_list = [engine_arg_option] + if verbose: + arg_list += ['-' + 'v' * verbose] + test_args = parser.parse_args(arg_list) + + + with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ + patch('o3de.manifest.get_engine_json_data', side_effect=self.get_engine_json_data) as get_engine_json_data_patch: + result = print_registration._run_register_show(test_args) + assert result == 0 + + + @pytest.mark.parametrize("arg_option, verbose", [ + pytest.param("--projects", 0), + pytest.param("--projects", 1), + pytest.param("--engine-projects", 0), + pytest.param("--engine-projects", 1), + pytest.param("--all-projects", 0), + pytest.param("--all-projects", 1) + ]) + def test_print_project_registration(self, arg_option, verbose): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + print_registration.add_parser_args(parser) + arg_list = [arg_option] + if verbose: + arg_list += ['-' + 'v' * verbose] + test_args = parser.parse_args(arg_list) + + + with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ + patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_json_data_patch: + result = print_registration._run_register_show(test_args) + assert result == 0 + + + @pytest.mark.parametrize("arg_option, project_path, verbose", [ + pytest.param("--gems", None, 0), + pytest.param("--gems", None, 1), + pytest.param("--engine-gems", None, 0), + pytest.param("--engine-gems", None, 1), + pytest.param("--project-gems", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--project-gems", pathlib.Path("D:/MinimalProject"), 1), + pytest.param("--all-gems", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--all-gems", None, 0), + pytest.param("--all-gems", pathlib.Path("D:/MinimalProject"), 1), + pytest.param("--all-gems", None, 1) + ]) + def test_print_gem_registration(self, arg_option, project_path, verbose): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + print_registration.add_parser_args(parser) + arg_list = [arg_option] + if project_path: + arg_list += ['--project-path', project_path.as_posix()] + if verbose: + arg_list += ['-' + 'v' * verbose] + test_args = parser.parse_args(arg_list) + + # Patch the manifest.py function to locate gem.json files in external subdirectories + # to just return a fake path to a single test gem + def get_gems_from_subdirectories(external_subdirs: list) -> list: + return ["D:/TestGem"] + + with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ + patch('o3de.manifest.get_gem_json_data', side_effect=self.get_gem_json_data) as get_json_patch, \ + patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_project_json_patch, \ + patch('o3de.manifest.get_gems_from_subdirectories', side_effect=get_gems_from_subdirectories) as get_gems_from_subdirs_patch, \ + patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch: + result = print_registration._run_register_show(test_args) + assert result == 0 + + + @pytest.mark.parametrize("arg_option, project_path, verbose", [ + pytest.param("--templates", None, 0), + pytest.param("--templates", None, 1), + pytest.param("--engine-templates", None, 0), + pytest.param("--engine-templates", None, 1), + pytest.param("--project-templates", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--project-templates", pathlib.Path("D:/MinimalProject"), 1), + pytest.param("--all-templates", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--all-templates", None, 0), + pytest.param("--all-templates", pathlib.Path("D:/MinimalProject"), 1), + pytest.param("--all-templates", None, 1) + ]) + def test_print_template_registration(self, arg_option, project_path, verbose): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + print_registration.add_parser_args(parser) + arg_list = [arg_option] + if project_path: + arg_list += ['--project-path', project_path.as_posix()] + if verbose: + arg_list += ['-' + 'v' * verbose] + test_args = parser.parse_args(arg_list) + + + with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ + patch('o3de.manifest.get_template_json_data', side_effect=self.get_template_json_data) as get_json_patch, \ + patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_project_json_patch, \ + patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch: + result = print_registration._run_register_show(test_args) + assert result == 0 + + + @pytest.mark.parametrize("arg_option, project_path, verbose", [ + pytest.param("--restricted", None, 0), + pytest.param("--restricted", None, 1), + pytest.param("--engine-restricted", None, 0), + pytest.param("--engine-restricted", None, 1), + pytest.param("--project-restricted", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--project-restricted", pathlib.Path("D:/MinimalProject"), 1), + pytest.param("--all-restricted", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--all-restricted", None, 0), + pytest.param("--all-restricted", pathlib.Path("D:/MinimalProject"), 1), + pytest.param("--all-restricted", None, 1) + ]) + def test_print_restricted_registration(self, arg_option, project_path, verbose): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + print_registration.add_parser_args(parser) + arg_list = [arg_option] + if project_path: + arg_list += ['--project-path', project_path.as_posix()] + if verbose: + arg_list += ['-' + 'v' * verbose] + test_args = parser.parse_args(arg_list) + + with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ + patch('o3de.manifest.get_restricted_json_data', side_effect=self.get_restricted_json_data) as get_json_patch, \ + patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_project_json_patch, \ + patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch: + result = print_registration._run_register_show(test_args) + assert result == 0 + + + # Setting --verbose with the --*external-subdirectories option doesn't result in any additional output + # So it is only parameterized as 0 + @pytest.mark.parametrize("arg_option, project_path, verbose", [ + pytest.param("--external-subdirectories", None, 0), + pytest.param("--engine-external-subdirectories", None, 0), + pytest.param("--project-external-subdirectories", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--all-external-subdirectories", pathlib.Path("D:/MinimalProject"), 0), + pytest.param("--all-external-subdirectories", None, 0), + ]) + def test_print_external_subdirectories_registration(self, arg_option, project_path, verbose): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + print_registration.add_parser_args(parser) + arg_list = [arg_option] + if project_path: + arg_list += ['--project-path', project_path.as_posix()] + if verbose: + arg_list += ['-' + 'v' * verbose] + test_args = parser.parse_args(arg_list) + + with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \ + patch('o3de.manifest.get_project_json_data', + side_effect=self.get_project_json_data) as get_project_json_patch, \ + patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch: + result = print_registration._run_register_show(test_args) + assert result == 0 From 0040c7fd9b42b500be6783e198d3dc0eecd801f1 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 28 Jul 2021 14:48:06 -0700 Subject: [PATCH 044/157] Tweak test projects so the console window remains open (#2380) * tweak test projects so the console window remains open Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * doing it for all test projects Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * newline at the end of the file to make devs happy Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/LYTestWrappers.cmake | 9 +++++++++ cmake/Platform/Common/Directory.Build.props | 7 ++++++- cmake/Platform/Common/TestProject.props | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 cmake/Platform/Common/TestProject.props diff --git a/cmake/LYTestWrappers.cmake b/cmake/LYTestWrappers.cmake index 535f00f58d..efb19a20dd 100644 --- a/cmake/LYTestWrappers.cmake +++ b/cmake/LYTestWrappers.cmake @@ -219,8 +219,17 @@ function(ly_add_test) VS_DEBUGGER_COMMAND_ARGUMENTS "${test_arguments_line}" ) + # In the case where we are creating a custom target, we need to add dependency to the target + if(ly_add_test_PARENT_NAME AND NOT ${ly_add_test_NAME} STREQUAL ${ly_add_test_PARENT_NAME}) + ly_add_dependencies(${unaliased_test_name} ${ly_add_test_PARENT_NAME}) + endif() + endif() + # For test projects that are custom targets, pass a props file that sets the project as "Console" so + # it leaves the console open when it finishes + set_target_properties(${unaliased_test_name} PROPERTIES VS_USER_PROPS "${LY_ROOT_FOLDER}/cmake/Platform/Common/TestProject.props") + # Include additional dependencies if (ly_add_test_RUNTIME_DEPENDENCIES) ly_add_dependencies(${unaliased_test_name} ${ly_add_test_RUNTIME_DEPENDENCIES}) diff --git a/cmake/Platform/Common/Directory.Build.props b/cmake/Platform/Common/Directory.Build.props index 73aa984073..76e4b28922 100644 --- a/cmake/Platform/Common/Directory.Build.props +++ b/cmake/Platform/Common/Directory.Build.props @@ -17,7 +17,12 @@ SPDX-License-Identifier: Apache-2.0 OR MIT - TurnOffAllWarnings + + TurnOffAllWarnings + + \ No newline at end of file diff --git a/cmake/Platform/Common/TestProject.props b/cmake/Platform/Common/TestProject.props new file mode 100644 index 0000000000..dff509b7ff --- /dev/null +++ b/cmake/Platform/Common/TestProject.props @@ -0,0 +1,16 @@ + + + + + + + + Console + + + From f0cafd0e9dc336e1f80a05dfacc8b7288b574b82 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 28 Jul 2021 15:53:14 -0700 Subject: [PATCH 045/157] Create RUN target as helpers for the project-centric workflow (#2520) * Create RUN target as helpers for the project-centric workflow Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * typo fix Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * rename target as ".Imported" and create "" as the metatarget that is used for debugging and building in o3de Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Editor/CMakeLists.txt | 2 + cmake/Platform/Common/Install_common.cmake | 43 ++++++++++++++++++---- cmake/SettingsRegistry.cmake | 7 +--- cmake/install/InstalledTarget.in | 2 + 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index fe694f165a..fca16a2093 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -163,6 +163,8 @@ ly_add_target( editor_files.cmake PLATFORM_INCLUDE_FILES Platform/${PAL_PLATFORM_NAME}/editor_${PAL_PLATFORM_NAME_LOWERCASE}.cmake + TARGET_PROPERTIES + LY_INSTALL_GENERATE_RUN_TARGET TRUE BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Core diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 2157a632c7..612358f938 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -10,6 +10,15 @@ include(cmake/FileUtil.cmake) set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise +define_property(TARGET PROPERTY LY_INSTALL_GENERATE_RUN_TARGET + BRIEF_DOCS "Defines if a \"RUN\" targets should be created when installing this target Gem" + FULL_DOCS [[ + Property which is set on targets that should generate a "RUN" + target when installed. This \"RUN\" target helps to run the + binary from the installed location directly from the IDE. + ]] +) + ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) cmake_path(RELATIVE_PATH CMAKE_RUNTIME_OUTPUT_DIRECTORY BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE runtime_output_directory) @@ -117,15 +126,19 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar set(NAMESPACE_PLACEHOLDER "") set(NAME_PLACEHOLDER ${TARGET_NAME}) endif() + get_target_property(should_create_helper ${TARGET_NAME} LY_INSTALL_GENERATE_RUN_TARGET) + if(should_create_helper) + set(NAME_PLACEHOLDER ${NAME_PLACEHOLDER}.Imported) + endif() set(TARGET_TYPE_PLACEHOLDER "") - get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) + get_target_property(target_type ${TARGET_NAME} TYPE) # Remove the _LIBRARY since we dont need to pass that to ly_add_targets string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") - get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) + get_target_property(gem_module ${TARGET_NAME} GEM_MODULE) if(gem_module) set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") endif() @@ -158,7 +171,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) endif() - get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) if(inteface_build_dependencies_props) @@ -182,6 +194,23 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + # If the target is an executable/application, add a custom target so we can debug the target in project-centric workflow + if(should_create_helper) + string(REPLACE ".Imported" "" RUN_TARGET_NAME ${NAME_PLACEHOLDER}) + set(target_types_with_debugging_helper EXECUTABLE APPLICATION) + if(NOT target_type IN_LIST target_types_with_debugging_helper) + message(FATAL_ERROR "Cannot generate a RUN target for ${TARGET_NAME}, type is ${target_type}") + endif() + set(TARGET_RUN_HELPER +"add_custom_target(${RUN_TARGET_NAME}) +set_target_properties(${RUN_TARGET_NAME} PROPERTIES + FOLDER \"CMakePredefinedTargets/SDK\" + VS_DEBUGGER_COMMAND \$> + VS_DEBUGGER_COMMAND_ARGUMENTS \"--project-path=\${LY_DEFAULT_PROJECT_PATH}\" +)" +) + endif() + # Config file set(target_file_contents "# Generated by O3DE install\n\n") if(NOT target_type STREQUAL INTERFACE_LIBRARY) @@ -194,13 +223,13 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") elseif(target_type STREQUAL SHARED_LIBRARY) string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} +"set_property(TARGET ${NAME_PLACEHOLDER} APPEND_STRING PROPERTY IMPORTED_IMPLIB $<$$:\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"$ ) ") string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} +"set_property(TARGET ${NAME_PLACEHOLDER} PROPERTY IMPORTED_IMPLIB_$> \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\" ) @@ -212,11 +241,11 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar if(target_location) string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} +"set_property(TARGET ${NAME_PLACEHOLDER} APPEND_STRING PROPERTY IMPORTED_LOCATION $<$$:${target_location}$ ) -set_property(TARGET ${TARGET_NAME} +set_property(TARGET ${NAME_PLACEHOLDER} PROPERTY IMPORTED_LOCATION_$> ${target_location} ) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index b740fefd25..ebf2254dc6 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -159,10 +159,6 @@ function(ly_delayed_generate_settings_registry) message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist") endif() - get_property(has_manually_added_dependencies TARGET ${gem_target} PROPERTY MANUALLY_ADDED_DEPENDENCIES SET) - get_target_property(target_type ${gem_target} TYPE) - - ly_get_gem_module_root(gem_module_root ${gem_target}) file(RELATIVE_PATH gem_module_root_relative_to_engine_root ${LY_ROOT_FOLDER} ${gem_module_root}) @@ -180,7 +176,8 @@ function(ly_delayed_generate_settings_registry) list(JOIN target_gem_dependencies_names ",\n" target_gem_dependencies_names) string(CONFIGURE ${gems_json_template} gem_json @ONLY) get_target_property(is_imported ${target} IMPORTED) - if(is_imported) + get_target_property(target_type ${target} TYPE) + if(is_imported OR target_type STREQUAL UTILITY) unset(target_dir) foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) diff --git a/cmake/install/InstalledTarget.in b/cmake/install/InstalledTarget.in index 0503fd5f2b..a4f4fa4763 100644 --- a/cmake/install/InstalledTarget.in +++ b/cmake/install/InstalledTarget.in @@ -17,6 +17,8 @@ ly_add_target( @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) +@TARGET_RUN_HELPER@ + set(configs @CMAKE_CONFIGURATION_TYPES@) foreach(config ${configs}) include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) From d7a4b0d930f92335328a99b3d398a18497628817 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:51:25 -0700 Subject: [PATCH 046/157] fix for double asset registration and multiple outs from loop nodes Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- Gems/GraphCanvas/Code/Source/GraphCanvas.cpp | 29 - Gems/GraphCanvas/Code/Source/GraphCanvas.h | 2 - .../Grammar/AbstractCodeModel.cpp | 2 +- ...orEachMultipleOutSyntaxOnEach.scriptcanvas | 2215 +++++++++++++++++ .../Tests/ScriptCanvas_RuntimeInterpreted.cpp | 4 +- 5 files changed, 2218 insertions(+), 34 deletions(-) create mode 100644 Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_ForEachMultipleOutSyntaxOnEach.scriptcanvas diff --git a/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp b/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp index 33cc99e2d5..c5333152a0 100644 --- a/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp +++ b/Gems/GraphCanvas/Code/Source/GraphCanvas.cpp @@ -191,7 +191,6 @@ namespace GraphCanvas void GraphCanvasSystemComponent::Activate() { - RegisterAssetHandler(); RegisterTranslationBuilder(); AzFramework::AssetCatalogEventBus::Handler::BusConnect(); @@ -386,34 +385,6 @@ namespace GraphCanvas AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, collectAssetsCb, postEnumerateCb); } - void GraphCanvasSystemComponent::RegisterAssetHandler() - { - AZ::Data::AssetType assetType(azrtti_typeid()); - if (AZ::Data::AssetManager::Instance().GetHandler(assetType)) - { - return; // Asset Type already handled - } - - auto* catalogBus = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); - if (catalogBus) - { - // Register asset types the asset DB should query our catalog for. - catalogBus->AddAssetType(assetType); - - // Build the catalog (scan). - catalogBus->AddExtension(".names"); - } - - m_assetHandler = AZStd::make_unique(); - AZ::Data::AssetManager::Instance().RegisterHandler(m_assetHandler.get(), assetType); - - // Use AssetCatalog service to register ScriptEvent asset type and extension - 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()); - - } - void GraphCanvasSystemComponent::UnregisterAssetHandler() { if (m_assetHandler) diff --git a/Gems/GraphCanvas/Code/Source/GraphCanvas.h b/Gems/GraphCanvas/Code/Source/GraphCanvas.h index a68052d5e1..7a4d9677ab 100644 --- a/Gems/GraphCanvas/Code/Source/GraphCanvas.h +++ b/Gems/GraphCanvas/Code/Source/GraphCanvas.h @@ -82,8 +82,6 @@ namespace GraphCanvas AZStd::unique_ptr m_assetHandler; void RegisterTranslationBuilder(); - - void RegisterAssetHandler(); void UnregisterAssetHandler(); TranslationAssetWorker m_translationAssetWorker; AZStd::vector m_translationAssets; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 883e15cd29..3e4a425a6e 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -3230,7 +3230,7 @@ namespace ScriptCanvas auto valueSlot = forEachNodeSC->GetSlot(forEachNodeSC->GetValueSlotId()); AZ_Assert(valueSlot, "no value slot in for each node"); - lastExecution->AddChild({}); + lastExecution->AddChild({ &loopSlot, {}, nullptr }); auto outputValue = CreateOutputData(lastExecution, lastExecution->ModChild(0), *valueSlot); lastExecution->ModChild(0).m_output.push_back({ valueSlot, outputValue }); diff --git a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_ForEachMultipleOutSyntaxOnEach.scriptcanvas b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_ForEachMultipleOutSyntaxOnEach.scriptcanvas new file mode 100644 index 0000000000..40e548eae0 --- /dev/null +++ b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_ForEachMultipleOutSyntaxOnEach.scriptcanvas @@ -0,0 +1,2215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp index df29a56fd5..5999cf9250 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp @@ -84,9 +84,9 @@ public: } }; -TEST_F(ScriptCanvasTestFixture, ProveError) +TEST_F(ScriptCanvasTestFixture, ForEachMultipleOutSyntaxOnEach) { - EXPECT_TRUE(false); + RunUnitTestGraph("LY_SC_UnitTest_ForEachMultipleOutSyntaxOnEach"); } TEST_F(ScriptCanvasTestFixture, EntityIdInputForOnGraphStart) From eefc448dceb9aec1771e7112899e36ea97eb058e Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 28 Jul 2021 17:48:11 -0700 Subject: [PATCH 047/157] remove stack tracer change and attempt to restore SC tests Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp | 2 +- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp index a24d359bc9..d2cdac84c7 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp @@ -39,7 +39,7 @@ namespace AZ { struct SymbolStorageDynamicallyLoadedModules { size_t m_size; - DynamicallyLoadedModuleInfo m_modules[1024]; + DynamicallyLoadedModuleInfo m_modules[256]; SymbolStorageDynamicallyLoadedModules() : m_size(0) diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index dada433772..23c9627e83 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -113,7 +113,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ) ly_add_googletest( NAME Gem::ScriptCanvasTesting.Editor.Tests - TEST_SUITE smoke ) endif() From 43dfffa3fd138ddbf0b29c1f0e7fa3ff46b30f4d Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Wed, 28 Jul 2021 20:58:49 -0700 Subject: [PATCH 048/157] fix dangling component variables on cleared script, fix EntityIDNode reflection Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 1 + .../EditorScriptCanvasComponent.cpp | 2 + .../ScriptCanvas/Libraries/Entity/Entity.cpp | 6 +-- .../ScriptCanvas/Libraries/Entity/Entity.h | 1 - .../Libraries/Entity/EntityIDNodes.h | 50 ------------------- .../Libraries/Entity/EntityNodes.h | 27 +++++++++- .../Code/scriptcanvasgem_common_files.cmake | 1 - 7 files changed, 30 insertions(+), 58 deletions(-) delete mode 100644 Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityIDNodes.h diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 6a5344ed9b..73e18a356c 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -30,6 +30,7 @@ namespace ScriptCanvasBuilder { m_source.Reset(); m_variables.clear(); + m_overrides.clear(); m_entityIds.clear(); m_dependencies.clear(); } diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 9135f348b3..dbc525e8e1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -474,6 +474,8 @@ namespace ScriptCanvasEditor OnScriptCanvasAssetReady(memoryAsset); } } + + AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent); } void EditorScriptCanvasComponent::OnStartPlayInEditor() diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.cpp index 1cce8cb3d3..b2bfd25031 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.cpp @@ -23,10 +23,10 @@ namespace ScriptCanvas // The DataElementNode is being copied purposefully in this statement to clone the data AZ::SerializeContext::DataElementNode baseNodeElement = rootNodeElement.GetSubElement(nodeElementIndex); - if (!rootNodeElement.Convert(context, azrtti_typeid())) + if (!rootNodeElement.Convert(context, azrtti_typeid())) { AZ_Error("Script Canvas", false, "Unable to convert old Entity::IsValid function node(%s) to new EntityId::IsValid function node(%s)", - rootNodeElement.GetId().ToString().data(), azrtti_typeid().ToString().data()); + rootNodeElement.GetId().ToString().data(), azrtti_typeid().ToString().data()); return false; } @@ -79,14 +79,12 @@ namespace ScriptCanvas void Entity::InitNodeRegistry(NodeRegistry& nodeRegistry) { - EntityIDNodes::Registrar::AddToRegistry(nodeRegistry); EntityNodes::Registrar::AddToRegistry(nodeRegistry); } AZStd::vector Entity::GetComponentDescriptors() { AZStd::vector descriptors; - EntityIDNodes::Registrar::AddDescriptors(descriptors); EntityNodes::Registrar::AddDescriptors(descriptors); return descriptors; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.h index dcfae2db9f..f8171a3fe0 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/Entity.h @@ -12,5 +12,4 @@ // shared code #include "RotateMethod.h" -#include "EntityIDNodes.h" #include "EntityNodes.h" diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityIDNodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityIDNodes.h deleted file mode 100644 index fa6cd9981e..0000000000 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityIDNodes.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -namespace ScriptCanvas -{ - namespace EntityIDNodes - { - using namespace Data; - static const char* k_categoryName = "Entity/Entity"; - - AZ_INLINE BooleanType IsValid(const EntityIDType& source) - { - return source.IsValid(); - } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(IsValid, k_categoryName, "{0ED8A583-A397-4657-98B1-433673323F21}", "returns true if Source is valid, else false", "Source"); - - AZ_INLINE StringType ToString(const EntityIDType& source) - { - return source.ToString(); - } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(ToString, k_categoryName, "{B094DCAE-15D5-42A3-8D8C-5BD68FE6E356}", "returns a string representation of Source", "Source"); - - AZ_INLINE BooleanType IsActive(const EntityIDType& entityId) - { - AZ::Entity* entity = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId); - return (entity && entity->GetState() == AZ::Entity::State::Active); - } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(IsActive, k_categoryName, "{DF5240FD-6510-4C24-8382-9515C4B0C7B4}", "returns true if entity with the provided Id is valid and active.", "Entity Id"); - - using Registrar = RegistrarGeneric< - IsValidNode, - ToStringNode, - IsActiveNode - >; - - } -} - diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h index dcad06d2c7..701c3a0869 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h @@ -21,7 +21,7 @@ namespace ScriptCanvas namespace EntityNodes { using namespace Data; - static const char* k_categoryName = "Entity/Transform"; + static const char* k_categoryName = "Entity/Entity"; template AZ_INLINE void DefaultScale(Node& node) { SetDefaultValuesByIndex::_(node, Data::One()); } @@ -59,10 +59,33 @@ namespace ScriptCanvas } SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetEntityUp, DefaultScale<1>, k_categoryName, "{96B86F3F-F022-4611-9AEA-175EA952C562}", "returns the up direction vector from the specified entity's world transform, scaled by a given value (Lumberyard uses Z up, right handed)", "EntityId", "Scale"); + AZ_INLINE BooleanType IsActive(const EntityIDType& entityId) + { + AZ::Entity* entity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId); + return (entity && entity->GetState() == AZ::Entity::State::Active); + } + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(IsActive, k_categoryName, "{DF5240FD-6510-4C24-8382-9515C4B0C7B4}", "returns true if entity with the provided Id is valid and active.", "Entity Id"); + + AZ_INLINE BooleanType IsValid(const EntityIDType& source) + { + return source.IsValid(); + } + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(IsValid, k_categoryName, "{0ED8A583-A397-4657-98B1-433673323F21}", "returns true if Source is valid, else false", "Source"); + + AZ_INLINE StringType ToString(const EntityIDType& source) + { + return source.ToString(); + } + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(ToString, k_categoryName, "{B094DCAE-15D5-42A3-8D8C-5BD68FE6E356}", "returns a string representation of Source", "Source"); + using Registrar = RegistrarGeneric< GetEntityRightNode, GetEntityForwardNode, - GetEntityUpNode + GetEntityUpNode, + IsActiveNode, + IsValidNode, + ToStringNode >; } } diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake index e1c12b7068..84ba39cc72 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake @@ -297,7 +297,6 @@ set(FILES Include/ScriptCanvas/Libraries/Core/UnaryOperator.h Include/ScriptCanvas/Libraries/Entity/Entity.cpp Include/ScriptCanvas/Libraries/Entity/Entity.h - Include/ScriptCanvas/Libraries/Entity/EntityIDNodes.h Include/ScriptCanvas/Libraries/Entity/EntityNodes.h Include/ScriptCanvas/Libraries/Entity/RotateMethod.cpp Include/ScriptCanvas/Libraries/Entity/RotateMethod.h From 5bb8a17d795bc775ee2080b24d2437df039cc0ea Mon Sep 17 00:00:00 2001 From: Benjamin Jillich Date: Thu, 29 Jul 2021 14:17:29 +0200 Subject: [PATCH 049/157] Removed MCore::Quaternion.h/.inl/.cpp files Signed-off-by: Benjamin Jillich --- .../Code/MCore/Source/Quaternion.cpp | 604 ------------------ Gems/EMotionFX/Code/MCore/Source/Quaternion.h | 386 ----------- .../Code/MCore/Source/Quaternion.inl | 96 --- Gems/EMotionFX/Code/MCore/mcore_files.cmake | 3 - 4 files changed, 1089 deletions(-) delete mode 100644 Gems/EMotionFX/Code/MCore/Source/Quaternion.cpp delete mode 100644 Gems/EMotionFX/Code/MCore/Source/Quaternion.h delete mode 100644 Gems/EMotionFX/Code/MCore/Source/Quaternion.inl diff --git a/Gems/EMotionFX/Code/MCore/Source/Quaternion.cpp b/Gems/EMotionFX/Code/MCore/Source/Quaternion.cpp deleted file mode 100644 index 2f7db53d2c..0000000000 --- a/Gems/EMotionFX/Code/MCore/Source/Quaternion.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -// include required headers -#include "Quaternion.h" -#include - -namespace MCore -{ - // spherical quadratic interpolation - Quaternion Quaternion::Squad(const Quaternion& p, const Quaternion& a, const Quaternion& b, const Quaternion& q, float t) - { - Quaternion q0(p.Slerp(q, t)); - Quaternion q1(a.Slerp(b, t)); - return q0.Slerp(q1, 2.0f * t * (1.0f - t)); - } - - - // returns the approximately normalized linear interpolated result [t must be between 0..1] - Quaternion Quaternion::NLerp(const Quaternion& to, float t) const - { - AZ_Assert(t > -MCore::Math::epsilon && t < (1 + MCore::Math::epsilon), "Expected t to be between 0..1"); - static const float weightCloseToOne = 1.0f - MCore::Math::epsilon; - - // Early out for boundaries (common cases) - if (t < MCore::Math::epsilon) - { - return *this; - } - else if (t > weightCloseToOne) - { - return to; - } - - #if AZ_TRAIT_USE_PLATFORM_SIMD_SSE - __m128 num1, num2, num3, num4, fromVec, toVec; - const float omt = 1.0f - t; - float dot; - - // perform dot product between this quat and the 'to' quat - num4 = _mm_setzero_ps(); // sets sum to zero - fromVec = _mm_loadu_ps(&x); // - toVec = _mm_loadu_ps(&to.x); // - num3 = _mm_mul_ps(fromVec, toVec); // performs multiplication num3 = a[3]*b[3] a[2]*b[2] a[1]*b[1] a[0]*b[0] - num3 = _mm_hadd_ps(num3, num3); // performs horizontal addition - num3= a[3]*b[3]+ a[2]*b[2] a[1]*b[1]+a[0]*b[0] a[3]*b[3]+ a[2]*b[2] a[1]*b[1]+a[0]*b[0] - num4 = _mm_add_ps(num4, num3); // performs vertical addition - num4 = _mm_hadd_ps(num4, num4); - _mm_store_ss(&dot, num4); // store the dot result - - if (dot < 0.0f) - { - t = -t; - } - - // calculate interpolated value - num2 = _mm_load_ps1(&omt); - num3 = _mm_load_ps1(&t); - num4 = _mm_mul_ps(fromVec, num2); // omt * xyzw - num1 = _mm_mul_ps(toVec, num3); // t * to.xyzw - num2 = _mm_add_ps(num1, num4); // interpolated value - - // calculate the square length - num4 = _mm_setzero_ps(); - num3 = _mm_mul_ps(num2, num2); // square length - num1 = _mm_hadd_ps(num3, num3); - num4 = _mm_add_ps(num4, num1); - num3 = _mm_hadd_ps(num4, num4); - //num4 = _mm_rsqrt_ps( num3 ); // length (argh, too inaccurate on some models) - - AZStd::aligned_storage::type numFloatStorage; - float* numFloat = reinterpret_cast(&numFloatStorage); - - _mm_store_ps(numFloat, num3); - const float invLen = Math::InvSqrt(numFloat[0]); - num4 = _mm_load_ps1(&invLen); - - // calc inverse length, which normalizes everything - num1 = _mm_mul_ps(num2, num4); - - _mm_store_ps(numFloat, num1); - return Quaternion(numFloat[0], numFloat[1], numFloat[2], numFloat[3]); - #else - const float omt = 1.0f - t; - const float dot = x * to.x + y * to.y + z * to.z + w * to.w; - if (dot < 0.0f) - { - t = -t; - } - - // calculate the interpolated values - const float newX = (omt * x + t * to.x); - const float newY = (omt * y + t * to.y); - const float newZ = (omt * z + t * to.z); - const float newW = (omt * w + t * to.w); - - // calculate the inverse length - // const float invLen = 1.0f / Math::FastSqrt( newX*newX + newY*newY + newZ*newZ + newW*newW ); - // const float invLen = Math::FastInvSqrt( newX*newX + newY*newY + newZ*newZ + newW*newW ); - const float invLen = Math::InvSqrt(newX * newX + newY * newY + newZ * newZ + newW * newW); - - // return the normalized linear interpolation - return Quaternion(newX * invLen, - newY * invLen, - newZ * invLen, - newW * invLen); - #endif - } - - - - // returns the linear interpolated result [t must be between 0..1] - Quaternion Quaternion::Lerp(const Quaternion& to, float t) const - { - const float omt = 1.0f - t; - const float cosom = x * to.x + y * to.y + z * to.z + w * to.w; - if (cosom < 0.0f) - { - t = -t; - } - - // return the linear interpolation - return Quaternion(omt * x + t * to.x, - omt * y + t * to.y, - omt * z + t * to.z, - omt * w + t * to.w); - } - - - - // quaternion from an axis and angle - Quaternion::Quaternion(const AZ::Vector3& axis, float angle) - { - const float squaredLength = axis.GetLengthSq(); - if (squaredLength > 0.0f) - { - const float halfAngle = angle * 0.5f; - const float sinScale = Math::Sin(halfAngle) / Math::Sqrt(squaredLength); - x = axis.GetX() * sinScale; - y = axis.GetY() * sinScale; - z = axis.GetZ() * sinScale; - w = Math::Cos(halfAngle); - } - else - { - x = y = z = 0.0f; - w = 1.0f; - } - } - - - - // quaternion from a spherical rotation - Quaternion::Quaternion(const AZ::Vector2& spherical, float angle) - { - const float latitude = spherical.GetX(); - const float longitude = spherical.GetY(); - - const float s = Math::Sin(angle / 2.0f); - const float c = Math::Cos(angle / 2.0f); - - const float sin_lat = Math::Sin(latitude); - const float cos_lat = Math::Cos(latitude); - - const float sin_lon = Math::Sin(longitude); - const float cos_lon = Math::Cos(longitude); - - x = s * cos_lat * sin_lon; - y = s * sin_lat; - z = s * sin_lat * cos_lon; - w = c; - } - - - // convert to an axis and angle - void Quaternion::ToAxisAngle(AZ::Vector3* axis, float* angle) const - { - *angle = 2.0f * Math::ACos(w); - - const float sinHalfAngle = Math::Sin(*angle * 0.5f); - if (sinHalfAngle > 0.0f) - { - const float invS = 1.0f / sinHalfAngle; - axis->Set(x * invS, y * invS, z * invS); - } - else - { - axis->Set(0.0f, 1.0f, 0.0f); - *angle = 0.0f; - } - } - - - // converts from unit quaternion to spherical rotation angles - void Quaternion::ToSpherical(AZ::Vector2* spherical, float* angle) const - { - AZ::Vector3 axis; - ToAxisAngle(&axis, angle); - - float longitude; - if (axis.GetX() * axis.GetX() + axis.GetZ() * axis.GetZ() < 0.0001f) - { - longitude = 0.0f; - } - else - { - longitude = Math::ATan2(axis.GetX(), axis.GetZ()); - if (longitude < 0.0f) - { - longitude += Math::twoPi; - } - } - - spherical->SetX(-Math::ASin(axis.GetY())); - spherical->SetY(longitude); - } - - - - // setup the quaternion from a roll, pitch and yaw - Quaternion& Quaternion::SetEuler(float pitch, float yaw, float roll) - { - // METHOD #1: - const float halfYaw = yaw * 0.5f; - const float halfPitch = pitch * 0.5f; - const float halfRoll = roll * 0.5f; - - const float cY = Math::Cos(halfYaw); - const float sY = Math::Sin(halfYaw); - const float cP = Math::Cos(halfPitch); - const float sP = Math::Sin(halfPitch); - const float cR = Math::Cos(halfRoll); - const float sR = Math::Sin(halfRoll); - - x = cY * sP * cR - sY * cP * sR; - y = cY * sP * sR + sY * cP * cR; - z = cY * cP * sR - sY * sP * cR; - w = cY * cP * cR + sY * sP * sR; - - // Normalize(); // we might be able to leave the normalize away, but better safe than not, this is more robust :) - - return *this; - - /* - - // METHOD #2: - Quaternion Qx(Vector3(sP, 0, 0), cP); - Quaternion Qy(Vector3(0, sY, 0), cY); - Quaternion Qz(Vector3(0, 0, sR), cR); - - Quaternion result = Qx * Qy * Qz; - - x = result.x; - y = result.y; - z = result.z; - w = result.w; - - return *this; - */ - } - - - - // convert the quaternion to a matrix - Matrix Quaternion::ToMatrix() const - { - Matrix m; - - const float xx = x * x; - const float xy = x * y, yy = y * y; - const float xz = x * z, yz = y * z, zz = z * z; - const float xw = x * w, yw = y * w, zw = z * w, ww = w * w; - - MMAT(m, 0, 0) = +xx - yy - zz + ww; - MMAT(m, 0, 1) = +xy + zw + xy + zw; - MMAT(m, 0, 2) = +xz - yw + xz - yw; - MMAT(m, 0, 3) = 0.0f; - MMAT(m, 1, 0) = +xy - zw + xy - zw; - MMAT(m, 1, 1) = -xx + yy - zz + ww; - MMAT(m, 1, 2) = +yz + xw + yz + xw; - MMAT(m, 1, 3) = 0.0f; - MMAT(m, 2, 0) = +xz + yw + xz + yw; - MMAT(m, 2, 1) = +yz - xw + yz - xw; - MMAT(m, 2, 2) = -xx - yy + zz + ww; - MMAT(m, 2, 3) = 0.0f; - MMAT(m, 3, 0) = 0.0f; - MMAT(m, 3, 1) = 0.0f; - MMAT(m, 3, 2) = 0.0f; - MMAT(m, 3, 3) = 1.0f; - - return m; - } - - - - // construct the quaternion from a given rotation matrix - Quaternion Quaternion::ConvertFromMatrix(const Matrix& m) - { - Quaternion result; - - const float trace = MMAT(m, 0, 0) + MMAT(m, 1, 1) + MMAT(m, 2, 2); - if (trace > 0.0f /*Math::epsilon*/) - { - const float s = 0.5f / Math::Sqrt(trace + 1.0f); - result.w = 0.25f / s; - result.x = (MMAT(m, 1, 2) - MMAT(m, 2, 1)) * s; - result.y = (MMAT(m, 2, 0) - MMAT(m, 0, 2)) * s; - result.z = (MMAT(m, 0, 1) - MMAT(m, 1, 0)) * s; - } - else - { - if (MMAT(m, 0, 0) > MMAT(m, 1, 1) && MMAT(m, 0, 0) > MMAT(m, 2, 2)) - { - const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 0, 0) - MMAT(m, 1, 1) - MMAT(m, 2, 2)); - const float oneOverS = 1.0f / s; - result.x = 0.25f * s; - result.y = (MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS; - result.z = (MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS; - result.w = (MMAT(m, 1, 2) - MMAT(m, 2, 1)) * oneOverS; - } - else - if (MMAT(m, 1, 1) > MMAT(m, 2, 2)) - { - const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 1, 1) - MMAT(m, 0, 0) - MMAT(m, 2, 2)); - const float oneOverS = 1.0f / s; - result.x = (MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS; - result.y = 0.25f * s; - result.z = (MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS; - result.w = (MMAT(m, 2, 0) - MMAT(m, 0, 2)) * oneOverS; - } - else - { - const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 2, 2) - MMAT(m, 0, 0) - MMAT(m, 1, 1)); - const float oneOverS = 1.0f / s; - result.x = (MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS; - result.y = (MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS; - result.z = 0.25f * s; - result.w = (MMAT(m, 0, 1) - MMAT(m, 1, 0)) * oneOverS; - } - } - - /* - const float trace = MMAT(m,0,0) + MMAT(m,1,1) + MMAT(m,2,2) + 1.0f; - if (trace > Math::epsilon) - { - const float s = 0.5f / Math::Sqrt(trace); - result.w = 0.25f / s; - result.x = ( MMAT(m,1,2) - MMAT(m,2,1) ) * s; - result.y = ( MMAT(m,2,0) - MMAT(m,0,2) ) * s; - result.z = ( MMAT(m,0,1) - MMAT(m,1,0) ) * s; - } - else - { - if (MMAT(m,0,0) > MMAT(m,1,1) && MMAT(m,0,0) > MMAT(m,2,2)) - { - const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,0,0) - MMAT(m,1,1) - MMAT(m,2,2)); - const float oneOverS = 1.0f / s; - result.x = 0.25f * s; - result.y = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS; - result.z = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS; - result.w = (MMAT(m,2,1) - MMAT(m,1,2) ) * oneOverS; - } - else - if (MMAT(m,1,1) > MMAT(m,2,2)) - { - const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,1,1) - MMAT(m,0,0) - MMAT(m,2,2)); - const float oneOverS = 1.0f / s; - result.x = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS; - result.y = 0.25f * s; - result.z = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS; - result.w = (MMAT(m,2,0) - MMAT(m,0,2) ) * oneOverS; - } - else - { - const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,2,2) - MMAT(m,0,0) - MMAT(m,1,1) ); - const float oneOverS = 1.0f / s; - result.x = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS; - result.y = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS; - result.z = 0.25f * s; - result.w = (MMAT(m,1,0) - MMAT(m,0,1) ) * oneOverS; - } - } - */ - return result; - } - - - // convert a quaternion to euler angles (in degrees) - AZ::Vector3 Quaternion::ToEuler() const - { - /* - // METHOD #1: - - Vector3 euler; - - float matrix[3][3]; - float cx,sx; - float cy,sy,yr; - float cz,sz; - - matrix[0][0] = 1.0 - (2.0 * y * y) - (2.0 * z * z); - matrix[1][0] = (2.0 * x * y) + (2.0 * w * z); - matrix[2][0] = (2.0 * x * z) - (2.0 * w * y); - matrix[2][1] = (2.0 * y * z) + (2.0 * w * x); - matrix[2][2] = 1.0 - (2.0 * x * x) - (2.0 * y * y); - - sy = -matrix[2][0]; - cy = Math::Sqrt(1 - (sy * sy)); - yr = Math::ATan2(sy,cy); - euler.y = yr; - - // avoid divide by zero only where y ~90 or ~270 - if (sy != 1.0 && sy != -1.0) - { - cx = matrix[2][2] / cy; - sx = matrix[2][1] / cy; - euler.x = Math::ATan2(sx,cx); - - cz = matrix[0][0] / cy; - sz = matrix[1][0] / cy; - euler.z = Math::ATan2(sz,cz); - } - else - { - matrix[1][1] = 1.0 - (2.0 * x * x) - (2.0 * z * z); - matrix[1][2] = (2.0 * y * z) - (2.0 * w * x); - cx = matrix[1][1]; - sx = -matrix[1][2]; - euler.x = Math::ATan2(sx,cx); - - cz = 1.0; - sz = 0.0; - euler.z = Math::ATan2(sz,cz); - } - - return euler; - */ - - /* - // METHOD #2: - Matrix mat = ToMatrix(); - - // - float cy = Math::Sqrt(mat.m44[0][0]*mat.m44[0][0] + mat.m44[0][1]*mat.m44[0][1]); - if (cy > 16.0*Math::epsilon) - { - result.x = -atan2(mat.m44[1][2], mat.m44[2][2]); - result.y = -atan2(-mat.m44[0][2], cy); - result.z = -atan2(mat.m44[0][1], mat.m44[0][0]); - } - else - { - result.x = -atan2(-mat.m44[2][1], mat.m44[1][1]); - result.y = -atan2(-mat.m44[0][2], cy); - result.z = 0.0; - } - - return result; - */ - - // METHOD #3 (without conversion to matrix first): - // TODO: safety checks? - float m00 = 1.0f - (2.0f * ((y * y) + z * z)); - float m01 = 2.0f * (x * y + w * z); - - AZ::Vector3 result( - Math::ATan2(2.0f * (y * z + w * x), 1.0f - (2.0f * ((x * x) + (y * y)))), - Math::ATan2(-2.0f * (x * z - w * y), Math::Sqrt((m00 * m00) + (m01 * m01))), - Math::ATan2(m01, m00) - ); - - return result; - } - - float Quaternion::GetEulerZ() const - { - float m00 = 1.0f - (2.0f * ((y * y) + z * z)); - float m01 = 2.0f * (x * y + w * z); - return Math::ATan2(m01, m00); - } - - // returns the spherical interpolated result [t must be between 0..1] - Quaternion Quaternion::Slerp(const Quaternion& to, float t) const - { - float cosom = (x * to.x) + (y * to.y) + (z * to.z) + (w * to.w); - float scale0, scale1, scale1sign = 1.0f; - - if (cosom < 0.0f) - { - scale1sign = -1.0f; - cosom *= -1.0f; - } - - if ((1.0 - cosom) > Math::epsilon) - { - const float omega = Math::ACos(cosom); - const float sinOmega = Math::Sin(omega); - const float oosinom = 1.0f / sinOmega; - scale0 = Math::Sin((1.0f - t) * omega) * oosinom; - scale1 = Math::Sin(t * omega) * oosinom; - } - else - { - scale0 = 1.0f - t; - scale1 = t; - } - - scale1 *= scale1sign; - - return Quaternion(scale0 * x + scale1 * to.x, - scale0 * y + scale1 * to.y, - scale0 * z + scale1 * to.z, - scale0 * w + scale1 * to.w); - } - - - // set as delta rotation - Quaternion Quaternion::CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector) - { - Quaternion q; - q.SetAsDeltaRotation(fromVector, toVector); - return q; - } - - - // set as delta rotation but limited - Quaternion Quaternion::CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians) - { - Quaternion q; - q.SetAsDeltaRotation(fromVector, toVector, maxAngleRadians); - return q; - } - - - // set as delta rotation - void Quaternion::SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector) - { - // check if we are in parallel or not - const float dot = fromVector.Dot(toVector); - if (dot < 0.99999f) // we have rotated compared to the forward direction - { - const float angleRadians = Math::ACos(dot); - const AZ::Vector3 rotAxis = fromVector.Cross(toVector); - *this = Quaternion(rotAxis, angleRadians); - } - else - { - Identity(); - } - } - - - // set as delta rotation, but limited - void Quaternion::SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians) - { - // check if we are in parallel or not - const float dot = fromVector.Dot(toVector); - if (dot < 0.99999f) // we have rotated compared to the forward direction - { - const float angleRadians = Math::ACos(dot); - const float rotAngle = Min(angleRadians, maxAngleRadians); - const AZ::Vector3 rotAxis = fromVector.Cross(toVector); - *this = Quaternion(rotAxis, rotAngle); - } - else - { - Identity(); - } - } - - - /* - Decompose the rotation on to 2 parts. - 1. Twist - rotation around the "direction" vector - 2. Swing - rotation around axis that is perpendicular to "direction" vector - The rotation can be composed back by - rotation = swing * twist - - has singularity in case of swing_rotation close to 180 degrees rotation. - if the input quaternion is of non-unit length, the outputs are non-unit as well - otherwise, outputs are both unit - */ - void Quaternion::DecomposeSwingTwist(const AZ::Vector3& direction, Quaternion* outSwing, Quaternion* outTwist) const - { - AZ::Vector3 rotAxis(x, y, z); - AZ::Vector3 p = Projected(rotAxis, direction); // return projection v1 on to v2 (parallel component) - outTwist->Set(p.GetX(), p.GetY(), p.GetZ(), w); - outTwist->Normalize(); - *outSwing = *this * outTwist->Conjugated(); - } - - - // rotate the current quaternion and renormalize it - void Quaternion::RotateFromTo(const AZ::Vector3& fromVector, const AZ::Vector3& toVector) - { - *this = CreateDeltaRotation(fromVector, toVector) * *this; - Normalize(); - } -} // namespace MCore - diff --git a/Gems/EMotionFX/Code/MCore/Source/Quaternion.h b/Gems/EMotionFX/Code/MCore/Source/Quaternion.h deleted file mode 100644 index bbee1d8265..0000000000 --- a/Gems/EMotionFX/Code/MCore/Source/Quaternion.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -// include required headers -#include -#include -#include "StandardHeaders.h" -#include "FastMath.h" -#include "Vector.h" -#include "Matrix4.h" -#include "Algorithms.h" - - -namespace MCore -{ - /** - * Depracated. Please use AZ::Quaternion instead. - * The quaternion class in MCore. - * Quaternions are mostly used to represent rotations in 3D applications. - * The advantages of quaternions over matrices are that they take up less space and that interpolation between - * two quaternions is easier to perform. Instead of a 3x3 rotation matrix, which is 9 floats or doubles, a quaternion - * only uses 4 floats or doubles. This template/class provides you with methods to perform all kind of operations on - * these quaternions, from interpolation to conversion to matrices and other rotation representations. - */ - class MCORE_API Quaternion - { - public: - AZ_TYPE_INFO(MCore::Quaternion, "{1807CD22-EBB5-45E8-8113-3B1DABB53F12}") - - /** - * Default constructor. Sets x, y and z to 0 and w to 1. - */ - MCORE_INLINE Quaternion() - : x(0.0f) - , y(0.0f) - , z(0.0f) - , w(1.0f) {} - - /** - * Constructor which sets the x, y, z and w. - * @param xVal The value of x. - * @param yVal The value of y. - * @param zVal The value of z. - * @param wVal The value of w. - */ - MCORE_INLINE Quaternion(float xVal, float yVal, float zVal, float wVal) - : x(xVal) - , y(yVal) - , z(zVal) - , w(wVal) {} - - /** - * Copy constructor. Copies the x, y, z, w values from the other quaternion. - * @param other The quaternion to copy the attributes from. - */ - MCORE_INLINE Quaternion(const Quaternion& other) - : x(other.x) - , y(other.y) - , z(other.z) - , w(other.w) {} - - /** - * Constructor which creates a quaternion from a pitch, yaw and roll. - * @param pitch Rotation around the x-axis, in radians. - * @param yaw Rotation around the y-axis, in radians. - * @param roll Rotation around the z-axis, in radians. - */ - MCORE_INLINE Quaternion(float pitch, float yaw, float roll) { SetEuler(pitch, yaw, roll); } - - /** - * Constructor which takes a matrix as input parameter. - * This converts the rotation of the specified matrix into a quaternion. Please keep in mind that the matrix may NOT contain - * any scaling, so if it does, please normalize your matrix first! - * @param matrix The matrix to initialize the quaternion from. - */ - MCORE_INLINE Quaternion(const Matrix& matrix) { FromMatrix(matrix); } - - /** - * Constructor which creates a quaternion from a spherical rotation. - * @param spherical The spherical coordinates in radians, which creates an axis to rotate around. - * @param angle The angle to rotate around this axis. - */ - Quaternion(const AZ::Vector2& spherical, float angle); - - /** - * Constructor which creates a quaternion from an axis and angle. - * @param axis The axis to rotate around. - * @param angle The angle in radians to rotate around the given axis. - */ - Quaternion(const AZ::Vector3& axis, float angle); - - /** - * Set the quaternion x/y/z/w component values. - * @param vx The value of x. - * @param vy The value of y. - * @param vz The value of z. - * @param vw The value of w. - */ - MCORE_INLINE void Set(float vx, float vy, float vz, float vw) { x = vx; y = vy; z = vz; w = vw; } - - /** - * Calculates the square length of the quaternion. - * @result The square length (length*length). - */ - MCORE_INLINE float SquareLength() const { return (x * x + y * y + z * z + w * w); } - - /** - * Calculates the length of the quaternion. - * It's safe, since it prevents a division by 0. - * @result The length of the quaternion. - */ - MCORE_INLINE float Length() const; - - /** - * Performs a dot product on the quaternions. - * @param q The quaternion to multiply (dot product) this quaternion with. - * @result The quaternion which is the result of the dot product. - */ - MCORE_INLINE float Dot(const Quaternion& q) const { return (x * q.x + y * q.y + z * q.z + w * q.w); } - - /** - * Normalize the quaternion. - * @result The normalized quaternion. It modifies itself, so no new quaternion is returned. - */ - MCORE_INLINE Quaternion& Normalize(); - - /** - * Sets the quaternion to identity. Where x, y and z are set to 0 and w is set to 1. - * @result The quaternion, now set to identity. - */ - MCORE_INLINE Quaternion& Identity() { x = 0.0f; y = 0.0f; z = 0.0f; w = 1.0f; return *this; } - - /** - * Calculate the inversed version of this quaternion. - * @result The inversed version of this quaternion. - */ - MCORE_INLINE Quaternion& Inverse() { const float len = 1.0f / SquareLength(); x = -x * len; y = -y * len; z = -z * len; w = w * len; return *this; } - - /** - * Conjugate this quaternion. - * @result Returns itself Conjugated. - */ - MCORE_INLINE Quaternion& Conjugate() { x = -x; y = -y; z = -z; return *this; } - - /** - * Calculate the inversed version of this quaternion. - * @result The inversed version of this quaternion. - */ - MCORE_INLINE Quaternion Inversed() const { const float len = 1.0f / SquareLength(); return Quaternion(-x * len, -y * len, -z * len, w * len); } - - /** - * Returns the normalized version of this quaternion. - * @result The normalized version of this quaternion. - */ - MCORE_INLINE Quaternion Normalized() const { Quaternion result(*this); result.Normalize(); return result; } - - /** - * Return the conjugated version of this quaternion. - * @result The conjugated version of this quaternion. - */ - MCORE_INLINE Quaternion Conjugated() const { return Quaternion(-x, -y, -z, w); } - - /** - * Calculate the exponent of this quaternion. - * @result The resulting quaternion of the exp. - */ - MCORE_INLINE Quaternion Exp() const { const float r = Math::Sqrt(x * x + y * y + z * z); const float expW = Math::Exp(w); const float s = (r >= 0.00001f) ? expW* Math::Sin(r) / r : 0.0f; return Quaternion(s * x, s * y, s * z, expW * Math::Cos(r)); } - - /** - * Calculate the log of the quaternion. - * @result The resulting quaternion of the log. - */ - MCORE_INLINE Quaternion LogN() const { const float r = Math::Sqrt(x * x + y * y + z * z); float t = (r > 0.00001f) ? Math::ATan2(r, w) / r : 0.0f; return Quaternion(t * x, t * y, t * z, 0.5f * Math::Log(SquareLength())); } - - /** - * Calculate and get the right basis vector. - * @result The basis vector pointing to the right. This assumes x+ points to the right. - */ - MCORE_INLINE AZ::Vector3 CalcRightAxis() const; - - /** - * Calculate and get the up basis vector. - * @result The basis vector pointing upwards. This assumes z+ points up. - */ - MCORE_INLINE AZ::Vector3 CalcUpAxis() const; - - /** - * Calculate and get the forward basis vector. - * @result The basis vector pointing forward. This assumes y+ points forward, into the depth. - */ - MCORE_INLINE AZ::Vector3 CalcForwardAxis() const; - - /** - * Initialize the current quaternion from a specified matrix. - * Please note that the matrix may not contain any scaling! - * So make sure the matrix has been normalized before, if it contains any scale. - * @param m The matrix to initialize the quaternion from. - */ - MCORE_INLINE void FromMatrix(const Matrix& m) { *this = Quaternion::ConvertFromMatrix(m); } - - /** - * Setup the quaternion from a pitch, yaw and roll. - * @param pitch The rotation around the x-axis, in radians. - * @param yaw The rotation around the y-axis, in radians. - * @param roll The rotation around the z-axis in radians. - * @result The quaternion, now initialized with the given pitch, yaw, roll rotation. - */ - Quaternion& SetEuler(float pitch, float yaw, float roll); - - /** - * Convert the quaternion to an axis and angle. Which represents a rotation of the resulting angle around the resulting axis. - * @param axis Pointer to the vector to store the axis in. - * @param angle Pointer to the variable to store the angle in (will be in radians). - */ - void ToAxisAngle(AZ::Vector3* axis, float* angle) const; - - /** - * Convert the quaternion to a spherical rotation. - * @param spherical A pointer to the 2D vector to store the spherical coordinates in radians, which build the axis. - * @param angle The pointer to the variable to store the angle around this axis in radians. - */ - void ToSpherical(AZ::Vector2* spherical, float* angle) const; - - /** - * Extract the euler angles in radians. - * The x component of the resulting vector represents the rotation around the x-axis (pitch). - * The y component results the rotation around the y-axis (yaw) and the z component represents - * the rotation around the z-axis (roll). - * @result The 3D vector containing the euler angles in radians, around each axis. - */ - AZ::Vector3 ToEuler() const; - - /** - * Returns the angle of rotation about the z axis. This is same as - * the z component of the vector returned by the ToEuler method. It - * is just more efficient to call this when one is interested only in rotation about the z axis. - * @result The angle of rotation about z axis in radians. - */ - float GetEulerZ() const; - - /** - * Convert this quaternion into a matrix. - * @result The matrix representing the rotation of this quaternion. - */ - Matrix ToMatrix() const; - - /** - * Convert a matrix into a quaternion. - * Please keep in mind that the specified matrix may NOT contain any scaling! - * So make sure the matrix has been normalized before, if it contains any scale. - * @param m The matrix to extract the rotation from. - * @result The quaternion, now containing the rotation of the given matrix, in quaternion form. - */ - static Quaternion ConvertFromMatrix(const Matrix& m); - - /** - * Create a delta rotation that rotates one vector onto another vector. - * @param fromVector The normalized vector to start from. This must be normalized! - * @param toVector The normalized vector to rotate towards. This must be normalized as well! - * @result The delta rotation quaternion. - */ - static Quaternion CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector); - - /** - * Create a delta rotation that rotates one vector onto another vector. - * If the angle is bigger than the max allowed angle that is specified it will rotate with an angle of the maximum specified angle. - * So if the angle between the vectors is 40 degrees and you maxAngleRadians equals 10 degrees (in radians) it will only rotate 10 degrees. - * @param fromVector The normalized vector to start from. This must be normalized! - * @param toVector The normalized vector to rotate towards. This must be normalized as well! - * @param maxAngleRadians The maximum rotation angle on the plane defined by the two vectors. This cannot be more than Math::pi (180 degrees). - * @result The delta rotation quaternion. - */ - static Quaternion CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians); - - /** - * Init this quaternion as a delta rotation that rotates one vector onto another vector. - * @param fromVector The normalized vector to start from. This must be normalized! - * @param toVector The normalized vector to rotate towards. This must be normalized as well! - */ - void SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector); - - /** - * Init this quaternion as a delta rotation that rotates one vector onto another vector. - * If the angle is bigger than the max allowed angle that is specified it will rotate with an angle of the maximum specified angle. - * So if the angle between the vectors is 40 degrees and you maxAngleRadians equals 10 degrees (in radians) it will only rotate 10 degrees. - * @param fromVector The normalized vector to start from. This must be normalized! - * @param toVector The normalized vector to rotate towards. This must be normalized as well! - * @param maxAngleRadians The maximum rotation angle on the plane defined by the two vectors. This cannot be more than Math::pi (180 degrees). - */ - void SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians); - - /** - * Rotate this current quaternion using a given delta that is calculated from two vectors. - * The rotation axis used is the cross product between the from and to vector. The rotation angle is the angle between these two vectors. - * @param fromVector The current direction vector, must be normalized. - * @param toVector The desired new direction vector, must be normalized. - */ - void RotateFromTo(const AZ::Vector3& fromVector, const AZ::Vector3& toVector); - - /** - * Decompose into swing and twist. - * The original rotation quat can be reassembled by doing swing * twist. - * @param direction The direction vector to get the twist from. - * @param outSwing This will contain the swing quaternion. - * @param outTwist This will contain the twist quaternion. - */ - void DecomposeSwingTwist(const AZ::Vector3& direction, Quaternion* outSwing, Quaternion* outTwist) const; - - /** - * Linear interpolate between this and another quaternion. - * @param to The quaternion to interpolate towards. - * @param t The time value, between 0 and 1. - * @result The quaternion at the given time in the interpolation process. - */ - Quaternion Lerp(const Quaternion& to, float t) const; - - /** - * Linear interpolate between this and another quaternion, and normalize afterwards. - * @param to The quaternion to interpolate towards. - * @param t The time value, between 0 and 1. - * @result The normalized quaternion at the given time in the interpolation process. - */ - Quaternion NLerp(const Quaternion& to, float t) const; - - /** - * Spherical Linear interpolate between this and another quaternion. - * @param to The quaternion to interpolate towards. - * @param t The time value, between 0 and 1. - * @result The quaternion at the given time in the interpolation process. - */ - Quaternion Slerp(const Quaternion& to, float t) const; - - /** - * Spherical cubic interpolate. - * @param p The first quaternion. - * @param a The second quaternion. - * @param b The third quaternion. - * @param q The fourth quaternion. - * @param t The time value, between 0 and 1. - * @result The quaternion at the given time in the interpolation process. - */ - static Quaternion Squad(const Quaternion& p, const Quaternion& a, const Quaternion& b, const Quaternion& q, float t); - - // operators - MCORE_INLINE const Quaternion& operator=(const Matrix& m) { FromMatrix(m); return *this; } - MCORE_INLINE const Quaternion& operator=(const Quaternion& other) { x = other.x; y = other.y; z = other.z; w = other.w; return *this; } - MCORE_INLINE Quaternion operator-() const { return Quaternion(-x, -y, -z, -w); } - MCORE_INLINE const Quaternion& operator+=(const Quaternion& q) { x += q.x; y += q.y; z += q.z; w += q.w; return *this; } - MCORE_INLINE const Quaternion& operator-=(const Quaternion& q) { x -= q.x; y -= q.y; z -= q.z; w -= q.w; return *this; } - MCORE_INLINE const Quaternion& operator*=(const Quaternion& q); - MCORE_INLINE const Quaternion& operator*=(float f) { x *= f; y *= f; z *= f; w *= f; return *this; } - //MCORE_INLINE const Quaternion& operator*=(double f) { x*=f; y*=f; z*=f; w*=f; return *this; } - MCORE_INLINE bool operator==(const Quaternion& q) const { return ((q.x == x) && (q.y == y) && (q.z == z) && (q.w == w)); } - MCORE_INLINE bool operator!=(const Quaternion& q) const { return ((q.x != x) || (q.y != y) || (q.z != z) || (q.w != w)); } - - //MCORE_INLINE float& operator[](int32 row) { return ((float*)&x)[row]; } - MCORE_INLINE operator float*() { return (float*)&x; } - MCORE_INLINE operator const float*() const { return (const float*)&x; } - - MCORE_INLINE AZ::Vector3 operator*(const AZ::Vector3& p) const; // multiply a vector by a quaternion - MCORE_INLINE Quaternion operator/(const Quaternion& q) const; // returns the ratio of two quaternions - - // attributes - float x, y, z, w; - }; - - - // operators - MCORE_INLINE Quaternion operator*(const Quaternion& a, float f) { return Quaternion(a.x * f, a.y * f, a.z * f, a.w * f); } - MCORE_INLINE Quaternion operator*(float f, const Quaternion& b) { return Quaternion(f * b.x, f * b.y, f * b.z, f * b.w); } - //MCORE_INLINE Quaternion operator*(const Quaternion& a, double f) { return Quaternion(a.x*f, a.y*f, a.z*f, a.w*f); } - //MCORE_INLINE Quaternion operator*(double f, const Quaternion& b) { return Quaternion(f*b.x, f*b.y, f*b.z, f*b.w); } - MCORE_INLINE Quaternion operator+(const Quaternion& a, const Quaternion& b) { return Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } - MCORE_INLINE Quaternion operator-(const Quaternion& a, const Quaternion& b) { return Quaternion(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } - MCORE_INLINE Quaternion operator*(const Quaternion& a, const Quaternion& b) { return Quaternion(a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z, a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x, a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z); } - - // include the inline code -#include "Quaternion.inl" -} // namespace MCore diff --git a/Gems/EMotionFX/Code/MCore/Source/Quaternion.inl b/Gems/EMotionFX/Code/MCore/Source/Quaternion.inl deleted file mode 100644 index c89f497a1e..0000000000 --- a/Gems/EMotionFX/Code/MCore/Source/Quaternion.inl +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -// multiply a vector by a quaternion -MCORE_INLINE AZ::Vector3 Quaternion::operator * (const AZ::Vector3& p) const -{ - Quaternion v(p.GetX(), p.GetY(), p.GetZ(), 0.0f); - v = *this* v* this->Conjugated(); - return AZ::Vector3(v.x, v.y, v.z); -} - - - -// returns the ratio of two quaternions -MCORE_INLINE Quaternion Quaternion::operator / (const Quaternion& q) const -{ - Quaternion t((*this) * -q); - Quaternion s((-q) * (-q)); - t *= (1.0f / s.w); - return t; -} - - - -// calculates the length of the quaternion -MCORE_INLINE float Quaternion::Length() const -{ - const float sqLen = SquareLength(); - return Math::SafeSqrt(sqLen); -} - - -// normalizes the quaternion using approximation -MCORE_INLINE Quaternion& Quaternion::Normalize() -{ - // calculate 1.0 / length - // const float ooLen = 1.0f / Math::FastSqrt(x*x + y*y + z*z + w*w); - // const float ooLen = Math::FastInvSqrt(x*x + y*y + z*z + w*w); - const float squareValue = x * x + y * y + z * z + w * w; - const float ooLen = Math::InvSqrt(squareValue); - - x *= ooLen; - y *= ooLen; - z *= ooLen; - w *= ooLen; - - return *this; -} - - -// get the right axis -MCORE_INLINE AZ::Vector3 Quaternion::CalcRightAxis() const -{ - return AZ::Vector3(1.0f - 2.0f * y * y - 2.0f * z * z, - 2.0f * x * y + 2.0f * z * w, - 2.0f * x * z - 2.0f * y * w); -} - - -// get the forward axis -MCORE_INLINE AZ::Vector3 Quaternion::CalcForwardAxis() const -{ - return AZ::Vector3(2.0f * x * y - 2.0f * z * w, - 1.0f - 2.0f * x * x - 2.0f * z * z, - 2.0f * y * z + 2.0f * x * w); -} - - -// get the up axis -MCORE_INLINE AZ::Vector3 Quaternion::CalcUpAxis() const -{ - return AZ::Vector3(2.0f * x * z + 2.0f * y * w, - 2.0f * y * z - 2.0f * x * w, - 1.0f - 2.0f * x * x - 2.0f * y * y); -} - - -// multiply by a quaternion -MCORE_INLINE const Quaternion& Quaternion::operator*=(const Quaternion& q) -{ - const float vx = w * q.x + x * q.w + y * q.z - z * q.y; - const float vy = w * q.y + y * q.w + z * q.x - x * q.z; - const float vz = w * q.z + z * q.w + x * q.y - y * q.x; - const float vw = w * q.w - x * q.x - y * q.y - z * q.z; - x = vx; - y = vy; - z = vz; - w = vw; - return *this; -} - diff --git a/Gems/EMotionFX/Code/MCore/mcore_files.cmake b/Gems/EMotionFX/Code/MCore/mcore_files.cmake index b63c9e1bae..b0d8a67ccd 100644 --- a/Gems/EMotionFX/Code/MCore/mcore_files.cmake +++ b/Gems/EMotionFX/Code/MCore/mcore_files.cmake @@ -107,9 +107,6 @@ set(FILES Source/PlaneEq.cpp Source/PlaneEq.h Source/PlaneEq.inl - Source/Quaternion.cpp - Source/Quaternion.h - Source/Quaternion.inl Source/Random.cpp Source/Random.h Source/Ray.cpp From aa98be18b7e66a549dc00e18bcbb09fdf248b93c Mon Sep 17 00:00:00 2001 From: Benjamin Jillich Date: Thu, 29 Jul 2021 14:34:56 +0200 Subject: [PATCH 050/157] Removed leftover MCore::Quaternion usages and fixes some include issues Signed-off-by: Benjamin Jillich --- .../Rendering/Common/RotateManipulator.cpp | 2 +- .../Source/LogWindow/LogWindowPlugin.h | 1 + .../Code/MCore/Source/AzCoreConversions.h | 100 +----------------- Gems/EMotionFX/Code/MCore/Source/Matrix4.cpp | 45 -------- Gems/EMotionFX/Code/MCore/Source/Matrix4.h | 15 --- 5 files changed, 3 insertions(+), 160 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.cpp index a10f5fe80b..123ef00333 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RotateManipulator.cpp @@ -8,7 +8,7 @@ #include "RotateManipulator.h" #include - +#include namespace MCommon { diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/LogWindow/LogWindowPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/LogWindow/LogWindowPlugin.h index 022a6d5bd7..1b40b3fa2a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/LogWindow/LogWindowPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/LogWindow/LogWindowPlugin.h @@ -10,6 +10,7 @@ #define __EMSTUDIO_LOGWINDOWPLUGIN_H #if !defined(Q_MOC_RUN) +#include #include "../StandardPluginsConfig.h" #include "../../../../EMStudioSDK/Source/DockWidgetPlugin.h" #endif diff --git a/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h b/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h index 79e3ef9608..78cc99bd98 100644 --- a/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h +++ b/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -37,18 +38,6 @@ namespace MCore return RGBAColor(static_cast(azColor.GetR()), static_cast(azColor.GetG()), static_cast(azColor.GetB()), static_cast(azColor.GetA())); } - // Deprecated - AZ_FORCE_INLINE AZ::Quaternion EmfxQuatToAzQuat(const MCore::Quaternion& emfxQuat) - { - return AZ::Quaternion(emfxQuat.x, emfxQuat.y, emfxQuat.z, emfxQuat.w); - } - - // Deprecated - AZ_FORCE_INLINE MCore::Quaternion AzQuatToEmfxQuat(const AZ::Quaternion& azQuat) - { - return MCore::Quaternion(azQuat.GetX(), azQuat.GetY(), azQuat.GetZ(), azQuat.GetW()); - } - AZ_FORCE_INLINE AZ::Transform EmfxTransformToAzTransform(const EMotionFX::Transform& emfxTransform) { AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(emfxTransform.mRotation, emfxTransform.mPosition); @@ -530,91 +519,4 @@ namespace MCore AZ::Vector3ToVector4(m33.GetRow(2), translation.GetZ()), mat.GetRow(3)); } - - // Deprecated. Please use AZ::Transform instead of MCore::Matrix. - MCORE_INLINE AZ::Quaternion MCoreMatrixToQuaternion(const MCore::Matrix& m) - { - const float trace = MMAT(m, 0, 0) + MMAT(m, 1, 1) + MMAT(m, 2, 2); - if (trace > 0.0f /*Math::epsilon*/) - { - const float s = 0.5f / Math::Sqrt(trace + 1.0f); - return AZ::Quaternion((MMAT(m, 1, 2) - MMAT(m, 2, 1)) * s, - (MMAT(m, 2, 0) - MMAT(m, 0, 2)) * s, - (MMAT(m, 0, 1) - MMAT(m, 1, 0)) * s, - 0.25f / s); - } - else - { - if (MMAT(m, 0, 0) > MMAT(m, 1, 1) && MMAT(m, 0, 0) > MMAT(m, 2, 2)) - { - const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 0, 0) - MMAT(m, 1, 1) - MMAT(m, 2, 2)); - const float oneOverS = 1.0f / s; - return AZ::Quaternion(0.25f * s, - (MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS, - (MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS, - (MMAT(m, 1, 2) - MMAT(m, 2, 1)) * oneOverS); - } - else if (MMAT(m, 1, 1) > MMAT(m, 2, 2)) - { - const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 1, 1) - MMAT(m, 0, 0) - MMAT(m, 2, 2)); - const float oneOverS = 1.0f / s; - return AZ::Quaternion((MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS, - 0.25f * s, - (MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS, - (MMAT(m, 2, 0) - MMAT(m, 0, 2)) * oneOverS); - } - else - { - const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 2, 2) - MMAT(m, 0, 0) - MMAT(m, 1, 1)); - const float oneOverS = 1.0f / s; - return AZ::Quaternion((MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS, - (MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS, - 0.25f * s, - (MMAT(m, 0, 1) - MMAT(m, 1, 0)) * oneOverS); - } - } - - /* - const float trace = MMAT(m,0,0) + MMAT(m,1,1) + MMAT(m,2,2) + 1.0f; - if (trace > Math::epsilon) - { - const float s = 0.5f / Math::Sqrt(trace); - result.w = 0.25f / s; - result.x = ( MMAT(m,1,2) - MMAT(m,2,1) ) * s; - result.y = ( MMAT(m,2,0) - MMAT(m,0,2) ) * s; - result.z = ( MMAT(m,0,1) - MMAT(m,1,0) ) * s; - } - else - { - if (MMAT(m,0,0) > MMAT(m,1,1) && MMAT(m,0,0) > MMAT(m,2,2)) - { - const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,0,0) - MMAT(m,1,1) - MMAT(m,2,2)); - const float oneOverS = 1.0f / s; - result.x = 0.25f * s; - result.y = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS; - result.z = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS; - result.w = (MMAT(m,2,1) - MMAT(m,1,2) ) * oneOverS; - } - else - if (MMAT(m,1,1) > MMAT(m,2,2)) - { - const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,1,1) - MMAT(m,0,0) - MMAT(m,2,2)); - const float oneOverS = 1.0f / s; - result.x = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS; - result.y = 0.25f * s; - result.z = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS; - result.w = (MMAT(m,2,0) - MMAT(m,0,2) ) * oneOverS; - } - else - { - const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,2,2) - MMAT(m,0,0) - MMAT(m,1,1) ); - const float oneOverS = 1.0f / s; - result.x = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS; - result.y = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS; - result.z = 0.25f * s; - result.w = (MMAT(m,1,0) - MMAT(m,0,1) ) * oneOverS; - } - } - */ - } } // namespace MCore diff --git a/Gems/EMotionFX/Code/MCore/Source/Matrix4.cpp b/Gems/EMotionFX/Code/MCore/Source/Matrix4.cpp index 7314e9fe9c..229f67ec0c 100644 --- a/Gems/EMotionFX/Code/MCore/Source/Matrix4.cpp +++ b/Gems/EMotionFX/Code/MCore/Source/Matrix4.cpp @@ -2248,27 +2248,6 @@ namespace MCore } - - // simple decompose a matrix into translation and rotation - void Matrix::Decompose(AZ::Vector3* outTranslation, AZ::Quaternion* outRotation) const - { - // make a copy of the matrix - Matrix mat(*this); - - // normalize the basis vectors - mat.SetRight(SafeNormalize(mat.GetRight())); - mat.SetUp(SafeNormalize(mat.GetUp())); - mat.SetForward(SafeNormalize(mat.GetForward())); - - // extract the translation from the matrix - *outTranslation = mat.GetTranslation(); - - // convert the normalized 3x3 rotation part into a AZ::Quaternion - *outRotation = MCore::MCoreMatrixToQuaternion(*this); - } - - - // calculate a rotation matrix from two vectors void Matrix::SetRotationMatrixTwoVectors(const AZ::Vector3& from, const AZ::Vector3& to) { @@ -2365,30 +2344,6 @@ namespace MCore } - // - void Matrix::DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale, AZ::Vector3& shear) const - { - Matrix rotMatrix; - DecomposeQRGramSchmidt(translation, rotMatrix, scale, shear); - rot = MCore::MCoreMatrixToQuaternion(*this); - } - - // - void Matrix::DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale) const - { - Matrix rotMatrix; - DecomposeQRGramSchmidt(translation, rotMatrix, scale); - rot = MCore::MCoreMatrixToQuaternion(rotMatrix); - } - - - // - void Matrix::DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot) const - { - Matrix rotMatrix; - DecomposeQRGramSchmidt(translation, rotMatrix); - rot = MCore::MCoreMatrixToQuaternion(rotMatrix); - } // diff --git a/Gems/EMotionFX/Code/MCore/Source/Matrix4.h b/Gems/EMotionFX/Code/MCore/Source/Matrix4.h index 8cb09aa769..4be819bcc1 100644 --- a/Gems/EMotionFX/Code/MCore/Source/Matrix4.h +++ b/Gems/EMotionFX/Code/MCore/Source/Matrix4.h @@ -685,26 +685,11 @@ namespace MCore */ void Frustum(float left, float right, float top, float bottom, float znear, float zfar); - /** - * Decompose a transformation matrix into translation and rotation components. - * The translation part is just the translation part of the matrix. - * The rotation AZ::Quaternion is calculated by normalizing the basis vectors and converting the - * 3x3 rotation part of the matrix to a AZ::Quaternion. - * It is allowed for the matrix to contain scaling. - * The matrix where you call Decompose on remains unchanged. - * @param outTranslation A pointer to a vector where the translation will be written to. - * @param outRotation A pointer to a AZ::Quaternion where the rotation will be written to. - * @note Please keep in mind that nullptr values for the parameters are NOT allowed. - */ - void Decompose(AZ::Vector3* outTranslation, AZ::Quaternion* outRotation) const; // QR Gram-Schmidt decomposition - void DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot) const; void DecomposeQRGramSchmidt(AZ::Vector3& translation, Matrix& rot) const; void DecomposeQRGramSchmidt(AZ::Vector3& translation, Matrix& rot, AZ::Vector3& scale) const; void DecomposeQRGramSchmidt(AZ::Vector3& translation, Matrix& rot, AZ::Vector3& scale, AZ::Vector3& shear) const; - void DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale, AZ::Vector3& shear) const; - void DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale) const; static Matrix OuterProduct(const AZ::Vector4& column, const AZ::Vector4& row); From c13d3ec086bc9c484cd5ad1eea1e34ac5843df12 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Thu, 29 Jul 2021 09:35:25 -0400 Subject: [PATCH 051/157] Minor corrections in code gen for usability Signed-off-by: Olex Lozitskiy Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Code/Source/AutoGen/AutoComponent_Common.jinja | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja index 05403a00ef..72583f9062 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja @@ -323,10 +323,12 @@ namespace {{ Component.attrib['Namespace'] }} /// Place in your .cpp #include <{{ Component.attrib['OverrideInclude'] }}> +#include + namespace {{ Component.attrib['Namespace'] }} { {% if ComponentDerived %} - void {{ ComponentName }}::{{ ComponentName }}::Reflect(AZ::ReflectContext* context) + void {{ ComponentName }}::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) From d12d7de13930dc0aa587fcdb9efa4063c60e5127 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 29 Jul 2021 08:58:10 -0500 Subject: [PATCH 052/157] Add missing display mapper operation type bindings Signed-off-by: Guthrie Adams --- .../DisplayMapperConfigurationDescriptor.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp index 8b617cfe0f..a9ee46dd2c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp @@ -124,6 +124,18 @@ namespace AZ ->Field("AcesParameterOverrides", &DisplayMapperConfigurationDescriptor::m_acesParameterOverrides) ; } + + if (auto* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class() + ->Enum<(uint32_t)DisplayMapperOperationType::Aces>("DisplayMapperOperationType_Aces") + ->Enum<(uint32_t)DisplayMapperOperationType::AcesLut>("DisplayMapperOperationType_AcesLut") + ->Enum<(uint32_t)DisplayMapperOperationType::Passthrough>("DisplayMapperOperationType_Passthrough") + ->Enum<(uint32_t)DisplayMapperOperationType::GammaSRGB>("DisplayMapperOperationType_GammaSRGB") + ->Enum<(uint32_t)DisplayMapperOperationType::Reinhard>("DisplayMapperOperationType_Reinhard") + ->Enum<(uint32_t)DisplayMapperOperationType::Invalid>("DisplayMapperOperationType_Invalid") + ; + } } void DisplayMapperPassData::Reflect(ReflectContext* context) From 4465b52de5314c78aaeb2ff771a2733127707f31 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 29 Jul 2021 09:13:49 -0500 Subject: [PATCH 053/157] AtomToolsApplication minor comments/formatting Signed-off-by: Guthrie Adams --- .../Application/AtomToolsApplication.h | 3 ++ .../Code/Source/MaterialEditorApplication.cpp | 54 +++++++++---------- .../Code/Source/MaterialEditorApplication.h | 3 -- .../ShaderManagementConsoleApplication.cpp | 44 ++++++++------- 4 files changed, 49 insertions(+), 55 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h index bceea24aad..dc57179fcc 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h @@ -84,7 +84,10 @@ namespace AtomToolsFramework void OnExceptionMessage(AZStd::string_view message) override; //////////////////////////////////////////////////////////////////////// + //! Executable target name generally used as a prefix for logging and other saved files virtual AZStd::string GetBuildTargetName() const; + + //! List of filters for assets that need to be pre-built to run the application virtual AZStd::vector GetCriticalAssetFilters() const; virtual void LoadSettings(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp index 7b9372e72b..0977694b90 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp @@ -6,47 +6,44 @@ * */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include +#include #include #include #include -#include - #include - -#include #include +#include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include #include +#include AZ_POP_DISABLE_WARNING namespace MaterialEditor @@ -54,7 +51,7 @@ namespace MaterialEditor //! This function returns the build system target name of "MaterialEditor AZStd::string MaterialEditorApplication::GetBuildTargetName() const { -#if !defined (LY_CMAKE_TARGET) +#if !defined(LY_CMAKE_TARGET) #error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target" #endif return AZStd::string{ LY_CMAKE_TARGET }; @@ -73,7 +70,6 @@ namespace MaterialEditor MaterialEditorApplication::MaterialEditorApplication(int* argc, char*** argv) : AtomToolsApplication(argc, argv) - { QApplication::setApplicationName("O3DE Material Editor"); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h index b1c742d4dd..ec2a48288c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.h @@ -50,9 +50,6 @@ namespace MaterialEditor void ProcessCommandLine(const AZ::CommandLine& commandLine) override; void StartInternal() override; AZStd::string GetBuildTargetName() const override; - - //! List of common asset filters for things that need to be compiled to run the material editor - //! Some of these things will not be necessary once we have proper support for queued asset loading and reloading AZStd::vector GetCriticalAssetFilters() const override; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp index 7d2aa02e19..7e09f88f4f 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp @@ -6,51 +6,48 @@ * */ -#include +#include +#include +#include #include #include - -#include +#include #include #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #include -#include - -#include +#include +#include #include #include +#include -#include +#include #include #include #include - #include #include -#include -#include -#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include -#include #include +#include AZ_POP_DISABLE_WARNING namespace ShaderManagementConsole { AZStd::string ShaderManagementConsoleApplication::GetBuildTargetName() const { -#if !defined (LY_CMAKE_TARGET) +#if !defined(LY_CMAKE_TARGET) #error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target" #endif return AZStd::string_view{ LY_CMAKE_TARGET }; @@ -94,7 +91,8 @@ namespace ShaderManagementConsole void ShaderManagementConsoleApplication::Destroy() { // before modules are unloaded, destroy UI to free up any assets it cached - ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast(&ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::DestroyShaderManagementConsoleWindow); + ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast( + &ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::DestroyShaderManagementConsoleWindow); ShaderManagementConsoleWindowNotificationBus::Handler::BusDisconnect(); @@ -116,9 +114,7 @@ namespace ShaderManagementConsole const AZStd::string runPythonScriptPath = m_commandLine.GetSwitchValue(runPythonScriptSwitchName, runPythonScriptIndex); AZStd::vector runPythonArgs; AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast( - &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, - runPythonScriptPath, - runPythonArgs); + &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, runPythonScriptPath, runPythonArgs); } // Process command line options for opening one or more documents on startup @@ -126,7 +122,8 @@ namespace ShaderManagementConsole for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex) { const AZStd::string openDocumentPath = m_commandLine.GetMiscValue(openDocumentIndex); - ShaderManagementConsoleDocumentSystemRequestBus::Broadcast(&ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath); + ShaderManagementConsoleDocumentSystemRequestBus::Broadcast( + &ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath); } } @@ -136,6 +133,7 @@ namespace ShaderManagementConsole ShaderManagementConsoleWindowNotificationBus::Handler::BusConnect(); - ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast(&ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::CreateShaderManagementConsoleWindow); + ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast( + &ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::CreateShaderManagementConsoleWindow); } } // namespace ShaderManagementConsole From 2237439a0e8ae8629a72db2647a1f6f362d6d3d1 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 29 Jul 2021 09:29:00 -0500 Subject: [PATCH 054/157] Material Editor: changing preset errors to warnings Signed-off-by: Guthrie Adams --- .../Code/Source/Viewport/MaterialViewportRenderer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp index 461beffd06..23e37b2f7c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp @@ -324,7 +324,7 @@ namespace MaterialEditor { if (!preset) { - AZ_Error("MaterialViewportRenderer", false, "Attempting to set invalid lighting preset."); + AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid lighting preset."); return; } @@ -365,13 +365,13 @@ namespace MaterialEditor { if (!preset) { - AZ_Error("MaterialViewportRenderer", false, "Attempting to set invalid model preset."); + AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid model preset."); return; } if (!preset->m_modelAsset.GetId().IsValid()) { - AZ_Error("MaterialViewportRenderer", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str()); + AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str()); return; } From cd25dbf71fb39968ff2366380cf09900c6660717 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich Date: Thu, 29 Jul 2021 14:41:55 +0200 Subject: [PATCH 055/157] Removed MCore::Quaternion AZ::Quaternion comparison tests Signed-off-by: Benjamin Jillich --- .../Rendering/Common/OrthographicCamera.cpp | 1 + .../Rendering/Common/ScaleManipulator.cpp | 2 +- .../Rendering/Common/TranslateManipulator.cpp | 2 +- .../Rendering/OpenGL2/Source/GLSLShader.cpp | 1 + .../EMotionFX/Code/EMotionFX/Source/Actor.cpp | 1 + .../Source/Importer/ChunkProcessors.cpp | 1 + .../Code/MCore/Source/AzCoreConversions.h | 1 - .../Code/Tests/EmotionFXMathLibTests.cpp | 367 ------------------ Gems/EMotionFX/Code/Tests/Matchers.h | 33 +- Gems/EMotionFX/Code/Tests/Printers.cpp | 12 - Gems/EMotionFX/Code/Tests/Printers.h | 6 - 11 files changed, 7 insertions(+), 420 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/OrthographicCamera.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/OrthographicCamera.cpp index 39b382a8d3..722f43c113 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/OrthographicCamera.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/OrthographicCamera.cpp @@ -7,6 +7,7 @@ */ #include "OrthographicCamera.h" +#include #include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.cpp index e1dd7e0563..65915aec65 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/ScaleManipulator.cpp @@ -7,7 +7,7 @@ */ #include "ScaleManipulator.h" - +#include namespace MCommon { diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.cpp index b7c6b87fbf..e20ae5a77e 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/TranslateManipulator.cpp @@ -7,7 +7,7 @@ */ #include "TranslateManipulator.h" - +#include namespace MCommon { diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp index 6bd8ab7b2f..02aad3aa04 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp @@ -7,6 +7,7 @@ */ #include +#include #include "GLSLShader.h" #include "GraphicsManager.h" #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 56d08760c3..973d8eb460 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp index e1a3e0bbfa..7e7a9ae1c2 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h b/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h index 78cc99bd98..d185a804b8 100644 --- a/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h +++ b/Gems/EMotionFX/Code/MCore/Source/AzCoreConversions.h @@ -18,7 +18,6 @@ #include #include #include -#include #include // This file is "glue" code to convert math back-forward between MCore and AZ. It also has functions that MCore used to diff --git a/Gems/EMotionFX/Code/Tests/EmotionFXMathLibTests.cpp b/Gems/EMotionFX/Code/Tests/EmotionFXMathLibTests.cpp index 43422dd654..041cc9e862 100644 --- a/Gems/EMotionFX/Code/Tests/EmotionFXMathLibTests.cpp +++ b/Gems/EMotionFX/Code/Tests/EmotionFXMathLibTests.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -25,7 +24,6 @@ protected: { m_azNormalizedVector3_a = AZ::Vector3(s_x1, s_y1, s_z1); m_azNormalizedVector3_a.Normalize(); - m_emQuaternion_a = MCore::Quaternion(m_azNormalizedVector3_a, s_angle_a); m_azQuaternion_a = AZ::Quaternion::CreateFromAxisAngle(m_azNormalizedVector3_a, s_angle_a); } @@ -55,26 +53,6 @@ protected: return true; } - bool EmfxQuaternionCompareExact(MCore::Quaternion& quaternion, float x, float y, float z, float w) - { - if (quaternion.x != x) - { - return false; - } - if (quaternion.y != y) - { - return false; - } - if (quaternion.z != z) - { - return false; - } - if (quaternion.w != w) - { - return false; - } - return true; - } bool AZQuaternionCompareClose(AZ::Quaternion& quaternion, float x, float y, float z, float w, float tolerance) { @@ -131,26 +109,6 @@ protected: return true; } - bool AZEMQuaternionsAreEqual(AZ::Quaternion& azQuaternion, const MCore::Quaternion& emQuaternion) - { - if (AZQuaternionCompareExact(azQuaternion, emQuaternion.x, emQuaternion.y, - emQuaternion.z, emQuaternion.w)) - { - return true; - } - return false; - } - - bool AZEMQuaternionsAreClose(AZ::Quaternion& azQuaternion, const MCore::Quaternion& emQuaternion, const float tolerance) - { - if (AZQuaternionCompareClose(azQuaternion, emQuaternion.x, emQuaternion.y, - emQuaternion.z, emQuaternion.w, tolerance)) - { - return true; - } - return false; - } - static const float s_toleranceHigh; static const float s_toleranceMedium; static const float s_toleranceLow; @@ -161,7 +119,6 @@ protected: static const float s_angle_a; AZ::Vector3 m_azNormalizedVector3_a; AZ::Quaternion m_azQuaternion_a; - MCore::Quaternion m_emQuaternion_a; }; const float EmotionFXMathLibTests::s_toleranceHigh = 0.00001f; @@ -174,18 +131,6 @@ const float EmotionFXMathLibTests::s_y1 = 0.3f; const float EmotionFXMathLibTests::s_z1 = 0.4f; const float EmotionFXMathLibTests::s_angle_a = 0.5f; - -/////////////////////////////////////////////////////////////////////////////// - - -// MCore::Quaternion: Test identity values -TEST_F(EmotionFXMathLibTests, QuaternionIdentity_Identity_Success) -{ - MCore::Quaternion test(0.1f, 0.2f, 0.3f, 0.4f); - test.Identity(); - ASSERT_TRUE(test == MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f)); -} - ////////////////////////////////////////////////////////////////// //Getting and setting of Quaternions ////////////////////////////////////////////////////////////////// @@ -196,52 +141,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternionGet_Elements_Success) ASSERT_TRUE(AZQuaternionCompareExact(test, 0.1f, 0.2f, 0.3f, 0.4f)); } -// Compare equivalent normalized quaternions between systems -TEST_F(EmotionFXMathLibTests, AZEMQuaternionNormalizeEquivalent_Success) -{ - AZ::Quaternion azTest(0.1f, 0.2f, 0.3f, 0.4f); - MCore::Quaternion emTest(0.1f, 0.2f, 0.3f, 0.4f); - azTest.Normalize(); - emTest.Normalize(); - - ASSERT_TRUE(AZQuaternionCompareClose(azTest, emTest.x, emTest.y, emTest.z, emTest.w, s_toleranceMedium)); -} - -/////////////////////////////////////////////////////////////////////////////// -// Axis Angle -/////////////////////////////////////////////////////////////////////////////// - -// Compare setting a quaternion using axis and angle -TEST_F(EmotionFXMathLibTests, AZEMQuaternionConversion_SetToAxisAngleEquivalent_Success) -{ - MCore::Quaternion emQuaternion(m_azNormalizedVector3_a, s_angle_a); - AZ::Quaternion azQuaternion = AZ::Quaternion::CreateFromAxisAngle(m_azNormalizedVector3_a, s_angle_a); - - ASSERT_TRUE(AZQuaternionCompareClose(azQuaternion, emQuaternion.x, emQuaternion.y, emQuaternion.z, emQuaternion.w, s_toleranceLow)); -} - -// Compare equivalent conversions quaternions -> (axis, angle) between systems -TEST_F(EmotionFXMathLibTests, AZEMQuaternionConversion_ToAxisAngleEquivalent_Success) -{ - //populate Quaternions with same data - MCore::Quaternion emTest = m_emQuaternion_a; - AZ::Quaternion azTest(emTest.x, emTest.y, emTest.z, emTest.w); - - AZ::Vector3 emAxis; - float emAngle; - emTest.ToAxisAngle(&emAxis, &emAngle); - - AZ::Vector3 azAxis; - float azAngle; - AZ::ConvertQuaternionToAxisAngle(azTest, azAxis, azAngle); - - bool same = AZ::IsClose(azAngle, emAngle, s_toleranceLow) && - AZVector3CompareClose(azAxis, emAxis, s_toleranceLow); - - ASSERT_TRUE(same); -} - - /////////////////////////////////////////////////////////////////////////////// //Basic rotations /////////////////////////////////////////////////////////////////////////////// @@ -420,18 +319,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternion_EulerGetSet3ComponentAxisCompareTrans ASSERT_TRUE(same); } - -// EM Quaternion to Euler test -TEST_F(EmotionFXMathLibTests, EMQuaternionConversion_ToEulerEquivalent_Success) -{ - AZ::Vector3 eulerIn(0.1f, 0.2f, 0.3f); - MCore::Quaternion test; - test.SetEuler(eulerIn.GetX(), eulerIn.GetY(), eulerIn.GetZ()); - AZ::Vector3 eulerOut = test.ToEuler(); - - ASSERT_TRUE(AZVector3CompareClose(eulerOut, 0.1f, 0.2f, 0.3f, s_toleranceHigh)); -} - // AZ Quaternion to Euler test //only way to test Quaternions sameness is to apply it to a vector and measure result TEST_F(EmotionFXMathLibTests, AZQuaternionConversion_ToEulerEquivalent_Success) @@ -456,41 +343,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternionConversion_ToEulerEquivalent_Success) ASSERT_TRUE(AZVector3CompareClose(eulerOut1, eulerOut2, s_toleranceReallyLow)); } -/////////////////////////////////////////////////////////////////////////////// -//Quaternion order test -//determines that ordering is same between systems. -/////////////////////////////////////////////////////////////////////////////// -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_OrderTest_Success) -{ - AZ::Vector3 axis = AZ::Vector3(1.0f, 0.7f, 0.3f); - axis.Normalize(); - AZ::Quaternion azQuaternion1 = AZ::Quaternion::CreateFromAxisAngle(axis, AZ::Constants::HalfPi); - - AZ::Vector3 axis2 = AZ::Vector3(0.2f, 0.5f, 0.9f); - axis2.Normalize(); - AZ::Quaternion azQuaternion2 = AZ::Quaternion::CreateFromAxisAngle(axis2, AZ::Constants::HalfPi); - - MCore::Quaternion emQuaternion1(azQuaternion1.GetX(), azQuaternion1.GetY(), azQuaternion1.GetZ(), azQuaternion1.GetW()); - MCore::Quaternion emQuaternion2(azQuaternion2.GetX(), azQuaternion2.GetY(), azQuaternion2.GetZ(), azQuaternion2.GetW()); - - AZ::Quaternion azQuaterionOut = azQuaternion1 * azQuaternion2; - AZ::Quaternion azQuaterionOut2 = azQuaternion2 * azQuaternion1; - MCore::Quaternion emQuaterionOut = emQuaternion1 * emQuaternion2; - - AZ::Vector3 azVertexIn(0.1f, 0.2f, 0.3f); - - AZ::Vector3 azVertexOut, azVertexOut2; - AZ::Vector3 emVertexOut; - - azVertexOut = azQuaterionOut.TransformVector(azVertexIn); - azVertexOut2 = azQuaterionOut2.TransformVector(azVertexIn); - emVertexOut = emQuaterionOut * azVertexIn; - - bool same = AZVector3CompareClose(emVertexOut, azVertexOut.GetX(), azVertexOut.GetY(), azVertexOut.GetZ(), s_toleranceMedium); - ASSERT_TRUE(same); -} - - /////////////////////////////////////////////////////////////////////////////// // Quaternion Matrix /////////////////////////////////////////////////////////////////////////////// @@ -616,225 +468,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternionConversion_ToMatrix_Success) ASSERT_TRUE(AZ::IsClose(azMatrix.GetElement(3, 3), 1.0f, s_toleranceReallyLow)); } -/////////////////////////////////////////////////////////////////////////////// -// AZEMQuaternion Compare Output tests -// Determines the AZ and MCore quaternion outputs are same/close after same math operations. -/////////////////////////////////////////////////////////////////////////////// -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_CompareOperatorAddEquivalent_Success) -{ - // Quaternion test: operator '+' and operator '+=' - AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f); - azQuaternion.Normalize(); - azQuaternion2.Normalize(); - azQuaternion = azQuaternion + azQuaternion2; - azQuaternion2 += azQuaternion; - - MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f); - emQuaternion.Normalize(); - emQuaternion2.Normalize(); - emQuaternion = emQuaternion + emQuaternion2; - emQuaternion2 += emQuaternion; - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '+'"; - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '+='"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_CompareOperatorSubtractEquivalent_Success) -{ - // Quaternion test: operator '-' and operator '-=' - AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f); - azQuaternion.Normalize(); - azQuaternion2.Normalize(); - azQuaternion = azQuaternion - azQuaternion2; - azQuaternion2 -= azQuaternion; - - MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f); - emQuaternion.Normalize(); - emQuaternion2.Normalize(); - emQuaternion = emQuaternion - emQuaternion2; - emQuaternion2 -= emQuaternion; - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '-'"; - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '-='"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_CompareOperatorMultiplyHasSimilarOutput_Success) -{ - // Quaternion test: operator '*' and operator '*=' with another quaternion, vector3 and float - AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f); - AZ::Quaternion azQuaternion3 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - azQuaternion.Normalize(); - azQuaternion2.Normalize(); - azQuaternion3.Normalize(); - azQuaternion = azQuaternion * azQuaternion2; - azQuaternion2 *= azQuaternion; - azQuaternion3 *= 0.5f; - AZ::Vector3 aztestVec3 = azQuaternion2.TransformVector(m_azNormalizedVector3_a); - - MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f); - MCore::Quaternion emQuaternion3 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f); - emQuaternion.Normalize(); - emQuaternion2.Normalize(); - emQuaternion3.Normalize(); - emQuaternion = emQuaternion * emQuaternion2; - emQuaternion2 *= emQuaternion; - emQuaternion3 *= 0.5f; - AZ::Vector3 emtestVec3 = emQuaternion2 * m_azNormalizedVector3_a; - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*' with another quaternion"; - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*=' with another quaternion"; - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion3, emQuaternion3, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*=' with a float value"; - EXPECT_TRUE(AZVector3CompareClose(aztestVec3, emtestVec3, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*' with a vector3"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_EquivalentOperatorsHasSameOutput_Success) -{ - // Testing Quaternion == Quaternion and operator!= - bool azCheck = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() == AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized(); - bool azCheck2 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() == AZ::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).GetNormalized(); - bool azCheck3 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() != AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized(); - bool azCheck4 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() != AZ::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).GetNormalized(); - - bool emCheck = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() == MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized(); - bool emCheck2 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() == MCore::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).Normalized(); - bool emCheck3 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() != MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized(); - bool emCheck4 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() != MCore::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).Normalized(); - - EXPECT_TRUE(azCheck == emCheck) << "AZ/MCore Quaternions should have same output of 'true' with operator '=='"; - EXPECT_TRUE(azCheck2 == emCheck2) << "AZ/MCore Quaternions should have same output of 'false' with operator '=='"; - EXPECT_TRUE(azCheck3 == emCheck3) << "AZ/MCore Quaternions should have same output of 'false' with operator '!='"; - EXPECT_TRUE(azCheck4 == emCheck4) << "AZ/MCore Quaternions should have same output of 'true' with operator '!='"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_InverseHasSimilarOutput_Success) -{ - // Test quaternions inverse method - AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetInverseFull(); - AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetInverseFull(); - - MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Inverse(); - MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Inverse(); - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Inverse output"; - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar Inverse output"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_ConjugateHasSimilarOutput_Success) -{ - // Test quaternion conjugate method - AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetConjugate(); - AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetConjugate(); - - MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Conjugate(); - MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Conjugate(); - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Conjugate output"; - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar Conjugate output"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSameSquareLengthOutput_Success) -{ - // Test AZ and MCore quaternions to have similar square length - float azTest = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetLengthSq(); - float azTest2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetLengthSq(); - - float emTest = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().SquareLength(); - float emTest2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().SquareLength(); - - EXPECT_TRUE(AZ::GetAbs(azTest - emTest) < s_toleranceLow) << "AZ/MCore Quaternions should have similar square length output"; - EXPECT_TRUE(AZ::GetAbs(azTest2 - emTest2) < s_toleranceLow) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar square length output"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSameLengthOutput_Success) -{ - // Test AZ and MCore quaternions to have similar length - // AZ GetLength, GetLengthApprox, GetLength all returns sqrtf(Dot(*this)) - float azTest = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetLength(); - float azTest2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetLength(); - - float emTest = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Length(); - float emTest2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Length(); - - EXPECT_TRUE(AZ::GetAbs(azTest - emTest) < s_toleranceLow) << "AZ/MCore Quaternions should have similar length output"; - EXPECT_TRUE(AZ::GetAbs(azTest2 - emTest2) < s_toleranceLow) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar length output"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSameDotProductOutput_Success) -{ - // Test AZ and MCore quaternions to have similar dot product - float azDotTest = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().Dot(AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f)); - float azDotTest2 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().Dot(AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f)); - float azDotTest3 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().Dot(AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f)); - - float emDotTest = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Dot(MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f)); - float emDotTest2 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Dot(MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f)); - float emDotTest3 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Dot(MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f)); - - EXPECT_TRUE(AZ::GetAbs(azDotTest - emDotTest) < s_toleranceLow) << "AZ/MCore Quaternions should have similar dot product output"; - EXPECT_TRUE(AZ::GetAbs(azDotTest2 - emDotTest2) < s_toleranceLow) << "AZ/MCore Quaternions should have similar dot product output"; - EXPECT_TRUE(AZ::GetAbs(azDotTest3 - emDotTest3) < s_toleranceLow) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar dot product output"; -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSimilarLerpOutput_Success) -{ - // Test AZ and MCore quaternions to have similar Linear Interpolated quaternions - float testCases[6] = { 0.0f, 0.1f, 0.25f, 0.5f, 0.8f, 1.0f }; - for (float testVal : testCases) - { - AZ::Quaternion azQuaternionA = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized(); - AZ::Quaternion azQuaternionB = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).GetNormalized(); - AZ::Quaternion azQuaternionC = azQuaternionA.Lerp(azQuaternionB, testVal); - - MCore::Quaternion emQuaternionA = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized(); - MCore::Quaternion emQuaternionB = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).Normalized(); - MCore::Quaternion emQuaternionC = emQuaternionA.Lerp(emQuaternionB, testVal); - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternionA, emQuaternionA, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Lerp output with given float: " << testVal; - } -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSimilarNLerpOutput_Success) -{ - // Test AZ and MCore quaternions to have similar Linear Interpolated and then normalized quaternions - float testCases[6] = {0.0f, 0.1f, 0.25f, 0.5f, 0.8f, 1.0f}; - for (float testVal : testCases) - { - AZ::Quaternion azQuaternionA = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized(); - AZ::Quaternion azQuaternionB = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).GetNormalized(); - AZ::Quaternion azQuaternionC = azQuaternionA.NLerp(azQuaternionB, testVal); - - MCore::Quaternion emQuaternionA = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized(); - MCore::Quaternion emQuaternionB = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).Normalized(); - MCore::Quaternion emQuaternionC = emQuaternionA.NLerp(emQuaternionB, testVal); - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternionA, emQuaternionA, s_toleranceLow)) << "AZ/MCore Quaternions should have similar NLerp output with given float: " << testVal; - } -} - -TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSimilarSLerpOutput_Success) -{ - // Test AZ and MCore quaternions to have similar spherical Linear Interpolated quaternions - float testCases[6] = { 0.0f, 0.1f, 0.25f, 0.5f, 0.8f, 1.0f }; - for (float testVal : testCases) - { - AZ::Quaternion azQuaternionA = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized(); - AZ::Quaternion azQuaternionB = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).GetNormalized(); - AZ::Quaternion azQuaternionC = azQuaternionA.Slerp(azQuaternionB, testVal); - - MCore::Quaternion emQuaternionA = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized(); - MCore::Quaternion emQuaternionB = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).Normalized(); - MCore::Quaternion emQuaternionC = emQuaternionA.Slerp(emQuaternionB, testVal); - - EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternionA, emQuaternionA, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Slerp output with given float: " << testVal; - } -} - ////////////////////////////////////////////////////////////////// // Skinning ////////////////////////////////////////////////////////////////// diff --git a/Gems/EMotionFX/Code/Tests/Matchers.h b/Gems/EMotionFX/Code/Tests/Matchers.h index 64200e84f2..ad3c204f72 100644 --- a/Gems/EMotionFX/Code/Tests/Matchers.h +++ b/Gems/EMotionFX/Code/Tests/Matchers.h @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include #include #include @@ -76,37 +76,6 @@ inline bool IsCloseMatcherP::gmock_Impl:: return false; } -template<> -template<> -inline bool IsCloseMatcherP::gmock_Impl::MatchAndExplain(const MCore::Quaternion& arg, ::testing::MatchResultListener* result_listener) const -{ - const MCore::Quaternion compareQuat = (expected.Dot(arg) < 0.0f) ? -arg : arg; - const AZ::Vector4 compareVec4(compareQuat.x, compareQuat.y, compareQuat.z, compareQuat.w); - - if (::testing::ExplainMatchResult(IsClose(AZ::Vector4(expected.x, expected.y, expected.z, expected.w)), compareVec4, result_listener)) - { - return true; - } - - AZ::Vector3 gotAxis; - AZ::Vector3 expectedAxis; - float gotAngle; - float expectedAngle; - - // convert to an axis and angle representation - expected.ToAxisAngle(&expectedAxis, &expectedAngle); - compareQuat.ToAxisAngle(&gotAxis, &gotAngle); - - *result_listener << "\n Got Axis: "; - PrintTo(gotAxis, result_listener->stream()); - *result_listener << ", Got Angle: " << gotAngle << "\n"; - *result_listener << "Expected Axis: "; - PrintTo(expectedAxis, result_listener->stream()); - *result_listener << ", Expected Angle: " << expectedAngle; - - return false; -} - template<> template<> inline bool IsCloseMatcherP::gmock_Impl::MatchAndExplain(const EMotionFX::Transform& arg, ::testing::MatchResultListener* result_listener) const diff --git a/Gems/EMotionFX/Code/Tests/Printers.cpp b/Gems/EMotionFX/Code/Tests/Printers.cpp index 8fd196fda0..ebf5167508 100644 --- a/Gems/EMotionFX/Code/Tests/Printers.cpp +++ b/Gems/EMotionFX/Code/Tests/Printers.cpp @@ -34,18 +34,6 @@ namespace AZStd } } // namespace AZStd -namespace MCore -{ - void PrintTo(const Quaternion& quaternion, ::std::ostream* os) - { - *os << "(x: " << quaternion.x - << ", y: " << quaternion.y - << ", z: " << quaternion.z - << ", w: " << quaternion.w - << ")"; - } -} // namespace MCore - namespace EMotionFX { void PrintTo(const Transform& transform, ::std::ostream* os) diff --git a/Gems/EMotionFX/Code/Tests/Printers.h b/Gems/EMotionFX/Code/Tests/Printers.h index c262cb2bed..afa8ea4b7b 100644 --- a/Gems/EMotionFX/Code/Tests/Printers.h +++ b/Gems/EMotionFX/Code/Tests/Printers.h @@ -11,7 +11,6 @@ #include #include #include -#include #include namespace AZ @@ -25,11 +24,6 @@ namespace AZStd void PrintTo(const string& string, ::std::ostream* os); } // namespace AZStd -namespace MCore -{ - void PrintTo(const Quaternion& quaternion, ::std::ostream* os); -} // namespace MCore - namespace EMotionFX { void PrintTo(const Transform& transform, ::std::ostream* os); From ce99e3f2ecc4970595f8ec7bdb97c338964743c8 Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 29 Jul 2021 18:00:53 +0100 Subject: [PATCH 056/157] Fixed autogen namespace always going upper case Signed-off-by: pereslav --- .../Code/Source/AutoGen/AutoComponent_Source.jinja | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index c0d4fe0dac..d2be2f682a 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -970,7 +970,7 @@ enum class NetworkProperties {% macro DefineComponentServiceProxyGrabs(Component, ClassType, ComponentType) %} {% for Service in Component.iter('ComponentRelation') %} {% if Service.attrib['Constraint'] != 'Incompatible' %} -m_{{ LowerFirst(Service.attrib['Name']) }} = FindComponent<{{ UpperFirst(Service.attrib['Namespace']) }}::{{ UpperFirst(Service.attrib['Name']) }}>(); +m_{{ LowerFirst(Service.attrib['Name']) }} = FindComponent<{{ Service.attrib['Namespace'] }}::{{ UpperFirst(Service.attrib['Name']) }}>(); {% endif %} {% endfor %} {% endmacro %} @@ -1709,12 +1709,12 @@ namespace {{ Component.attrib['Namespace'] }} {% for Service in Component.iter('ComponentRelation') %} {% if Service.attrib['Constraint'] != 'Incompatible' %} - const {{ UpperFirst(Service.attrib['Namespace']) }}::{{ UpperFirst(Service.attrib['Name']) }}* {{ ComponentBaseName }}::Get{{ UpperFirst(Service.attrib['Name']) }}() const + const {{ Service.attrib['Namespace'] }}::{{ UpperFirst(Service.attrib['Name']) }}* {{ ComponentBaseName }}::Get{{ UpperFirst(Service.attrib['Name']) }}() const { return m_{{ LowerFirst(Service.attrib['Name']) }}; } - {{ UpperFirst(Service.attrib['Namespace']) }}::{{ UpperFirst(Service.attrib['Name']) }}* {{ ComponentBaseName }}::Get{{ UpperFirst(Service.attrib['Name']) }}() + {{ Service.attrib['Namespace'] }}::{{ UpperFirst(Service.attrib['Name']) }}* {{ ComponentBaseName }}::Get{{ UpperFirst(Service.attrib['Name']) }}() { return m_{{ LowerFirst(Service.attrib['Name']) }}; } From 5a18b246518d26c1b89cebfb3607e5787564a8d2 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Thu, 29 Jul 2021 10:08:19 -0700 Subject: [PATCH 057/157] Visualizer: use template functor over hardcoded lambdas Signed-off-by: Jacob Hilliard --- .../Include/Atom/Utils/ImGuiCpuProfiler.h | 14 +++++++++ .../Include/Atom/Utils/ImGuiCpuProfiler.inl | 29 ++++--------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index 62b71bdbb8..75b7ec9fdd 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -27,6 +27,20 @@ namespace AZ //! Stores all the data associated with a row in the table. struct TableRow { + template + struct TableRowCompareFunctor + { + TableRowCompareFunctor(T memberPointer, bool isAscending) : m_memberPointer(memberPointer), m_ascending(isAscending){}; + + bool operator()(const TableRow* lhs, const TableRow* rhs) + { + return m_ascending ? lhs->*m_memberPointer < rhs->*m_memberPointer : lhs->*m_memberPointer > rhs->*m_memberPointer; + } + + T m_memberPointer; + bool m_ascending; + }; + // Update running statistics with new region data void RecordRegion(const AZ::RHI::CachedTimeRegion& region, AZStd::thread_id threadId); diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index 90b6c67905..ffd7af2f20 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -208,39 +208,22 @@ namespace AZ switch (columnToSort) { case (0): // Sort by group name - AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_groupName < rhs->m_groupName : lhs->m_groupName > rhs->m_groupName; - }); + AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_groupName, ascending)); break; case (1): // Sort by region name - AZStd::sort(m_tableData.begin(), m_tableData.end(),[ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_regionName < rhs->m_regionName - : lhs->m_regionName > rhs->m_regionName; - }); + AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_regionName, ascending)); break; case (2): // Sort by average time - AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_runningAverageTicks < rhs->m_runningAverageTicks - : lhs->m_runningAverageTicks > rhs->m_runningAverageTicks; - }); + AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_runningAverageTicks, ascending)); break; case (3): // Sort by max time - AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_maxTicks < rhs->m_maxTicks - : lhs->m_maxTicks > rhs->m_maxTicks; - }); + AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_maxTicks, ascending)); break; case (4): // Sort by invocations - AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_invocationsLastFrame < rhs->m_invocationsLastFrame - : lhs->m_invocationsLastFrame > rhs->m_invocationsLastFrame; - }); + AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_invocationsLastFrame, ascending)); break; case (5): // Sort by total time - AZStd::sort(m_tableData.begin(), m_tableData.end(), [ascending](const TableRow* lhs, const TableRow* rhs){ - return ascending ? lhs->m_lastFrameTotalTicks < rhs->m_lastFrameTotalTicks - : lhs->m_lastFrameTotalTicks > rhs->m_lastFrameTotalTicks; - }); + AZStd::sort(m_tableData.begin(), m_tableData.end(), TableRow::TableRowCompareFunctor(&TableRow::m_lastFrameTotalTicks, ascending)); break; } sortSpecs->SpecsDirty = false; From c9301a8c947f3f21ca1789eed84ea28fb5976e4d Mon Sep 17 00:00:00 2001 From: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com> Date: Thu, 29 Jul 2021 12:04:04 -0700 Subject: [PATCH 058/157] Fix a bug in patching templates and improve error messaging (#2394) * Fix a bug in patching templates and improve error messaging * Fixed incorrect order of function arguments * Fix build errors regarding c style strings and casting entity ids Signed-off-by: srikappa-amzn --- .../Instance/InstanceToTemplatePropagator.cpp | 2 +- .../Prefab/PrefabPublicHandler.cpp | 59 +++++++++++++------ .../Prefab/PrefabPublicHandler.h | 7 ++- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp index c7bf72ff7b..8f93ebb6df 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp @@ -177,7 +177,7 @@ namespace AzToolsFramework PrefabDomUtils::ApplyPatches(templateDomReference, templateDomReference.GetAllocator(), providedPatch); //trigger propagation - if (result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Success) + if (result.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed) { AZ_Error("Prefab", false, "Patch was not successfully applied."); return false; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 16db933192..a03e48062c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -90,10 +90,11 @@ namespace AzToolsFramework AZStd::unordered_map nestedInstanceLinkPatchesMap; // Retrieve all entities affected and identify Instances - if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances)) + PrefabOperationResult retrieveEntitiesAndInstancesOutcome = RetrieveAndSortPrefabEntitiesAndInstances( + inputEntityList, commonRootEntityOwningInstance->get(), entities, instances); + if (!retrieveEntitiesAndInstancesOutcome.IsSuccess()) { - return AZ::Failure( - AZStd::string("Could not create a new prefab out of the entities provided - invalid selection.")); + return retrieveEntitiesAndInstancesOutcome; } AZStd::unordered_map oldEntityAliases; @@ -646,7 +647,12 @@ namespace AzToolsFramework { // Retrieve all nested instances that are part of the subtree under the current entity. EntityList entities; - RetrieveAndSortPrefabEntitiesAndInstances({ entity }, beforeOwningInstance->get(), entities, instancesInvolved); + PrefabOperationResult retrieveEntitiesAndInstancesOutcome = RetrieveAndSortPrefabEntitiesAndInstances( + { entity }, beforeOwningInstance->get(), entities, instancesInvolved); + if (!retrieveEntitiesAndInstancesOutcome.IsSuccess()) + { + return retrieveEntitiesAndInstancesOutcome; + } } for (Instance* instance : instancesInvolved) @@ -748,7 +754,9 @@ namespace AzToolsFramework AZStd::vector instances; // Retrieve all descendant entities and instances of this entity that belonged to the same owning instance. - RetrieveAndSortPrefabEntitiesAndInstances({ entity }, beforeOwningInstance->get(), entities, instances); + PrefabOperationResult retrieveEntitiesAndInstancesOutcome = RetrieveAndSortPrefabEntitiesAndInstances( + { entity }, beforeOwningInstance->get(), entities, instances); + AZ_Error("Prefab", retrieveEntitiesAndInstancesOutcome.IsSuccess(), retrieveEntitiesAndInstancesOutcome.GetError().data()); AZStd::vector> instanceUniquePtrs; AZStd::vector> instancePatches; @@ -981,11 +989,12 @@ namespace AzToolsFramework AZStd::vector instances; EntityList inputEntityList = EntityIdSetToEntityList(duplicationSet); - bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances); + PrefabOperationResult retrieveEntitiesAndInstancesOutcome = + RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances); - if (!success) + if (!retrieveEntitiesAndInstancesOutcome.IsSuccess()) { - return AZ::Failure(AZStd::string("Failed to retrieve entities and instances from the given list of entity ids for duplication")); + return AZStd::move(retrieveEntitiesAndInstancesOutcome); } // Take a snapshot of the instance DOM before we manipulate it @@ -1128,11 +1137,12 @@ namespace AzToolsFramework AZStd::vector entities; AZStd::vector instances; - bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances); + PrefabOperationResult retrieveEntitiesAndInstancesOutcome = + RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances); - if (!success) + if (!retrieveEntitiesAndInstancesOutcome.IsSuccess()) { - return AZ::Failure(AZStd::string("DeleteEntitiesAndAllDescendantsInInstance")); + return AZStd::move(retrieveEntitiesAndInstancesOutcome); } for (AZ::Entity* entity : entities) @@ -1405,13 +1415,16 @@ namespace AzToolsFramework return nullptr; } - bool PrefabPublicHandler::RetrieveAndSortPrefabEntitiesAndInstances( - const EntityList& inputEntities, Instance& commonRootEntityOwningInstance, - EntityList& outEntities, AZStd::vector& outInstances) const + PrefabOperationResult PrefabPublicHandler::RetrieveAndSortPrefabEntitiesAndInstances( + const EntityList& inputEntities, + Instance& commonRootEntityOwningInstance, + EntityList& outEntities, + AZStd::vector& outInstances) const { if (inputEntities.size() == 0) { - return false; + return AZ::Failure( + AZStd::string("An empty list of input entities is provided to retrieve the prefab entities and instances.")); } AZStd::queue entityQueue; @@ -1438,8 +1451,8 @@ namespace AzToolsFramework AZ_Assert( owningInstance.has_value(), "An error occurred while retrieving entities and prefab instances : " - "Owning instance of entity with id '%llu' couldn't be found", - entity->GetId()); + "Owning instance of entity with name '%s' and id '%llu' couldn't be found", + entity->GetName().c_str(), static_cast(entity->GetId())); // Check if this entity is owned by the same instance owning the root. if (&owningInstance->get() == &commonRootEntityOwningInstance) @@ -1480,7 +1493,10 @@ namespace AzToolsFramework else { // This can only happen if one entity does not share the common root! - return false; + return AZ::Failure(AZStd::string::format( + "Entity with name '%s' and id '%llu' has an owning instance that doesn't belong to the instance " + "hierarchy of the selected entities.", + entity->GetName().c_str(), static_cast(entity->GetId()))); } } } @@ -1501,7 +1517,12 @@ namespace AzToolsFramework outInstances.push_back(instancePtr); } - return (outEntities.size() + outInstances.size()) > 0; + if ((outEntities.size() + outInstances.size()) == 0) + { + return AZ::Failure( + AZStd::string("An empty list of entities and prefab instances were retrieved from the selected entities")); + } + return AZ::Success(); } EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutLevelInstance( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index f0c88a7a79..0e24b0841d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -64,8 +64,11 @@ namespace AzToolsFramework private: PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants); - bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, Instance& commonRootEntityOwningInstance, - EntityList& outEntities, AZStd::vector& outInstances) const; + PrefabOperationResult RetrieveAndSortPrefabEntitiesAndInstances( + const EntityList& inputEntities, + Instance& commonRootEntityOwningInstance, + EntityList& outEntities, + AZStd::vector& outInstances) const; EntityIdList GenerateEntityIdListWithoutLevelInstance(const EntityIdList& entityIds) const; InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const; From 99f7085c05450983e187bc31c16084f6d3c7ec59 Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Thu, 29 Jul 2021 14:56:13 -0500 Subject: [PATCH 059/157] Fixes resource selectors not showing (#2621) These statics were getting dead-stripped by the compiler, so removed some of the macro magic and just do direct registration instead. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> --- .../Editor/AudioControlsEditorPlugin.cpp | 4 +- .../Source/Editor/AudioResourceSelectors.cpp | 37 +++++++++++++++---- .../Source/Editor/AudioResourceSelectors.h | 14 +++++++ .../Code/audiosystem_editor_files.cmake | 1 + 4 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp index 973cb836a0..b318cea128 100644 --- a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -39,7 +39,7 @@ CAudioControlsEditorPlugin::CAudioControlsEditorPlugin(IEditor* editor) QtViewOptions options; options.canHaveMultipleInstances = true; RegisterQtViewPane(editor, LyViewPane::AudioControlsEditor, LyViewPane::CategoryOther, options); - RegisterModuleResourceSelectors(GetIEditor()->GetResourceSelectorHost()); + RegisterAudioControlsResourceSelectors(); Audio::AudioSystemRequestBus::BroadcastResult(ms_pIAudioProxy, &Audio::AudioSystemRequestBus::Events::GetFreeAudioProxy); diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp index f0c9ebe3d1..74233be2e9 100644 --- a/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp @@ -7,14 +7,13 @@ */ +#include #include #include #include #include #include -using namespace AudioControls; - namespace AudioControls { //-------------------------------------------------------------------------------------------// @@ -67,10 +66,32 @@ namespace AudioControls } //-------------------------------------------------------------------------------------------// - REGISTER_RESOURCE_SELECTOR("AudioTrigger", AudioTriggerSelector, ":/AudioControlsEditor/Icons/Trigger_Icon.png"); - REGISTER_RESOURCE_SELECTOR("AudioSwitch", AudioSwitchSelector, ":/AudioControlsEditor/Icons/Switch_Icon.png"); - REGISTER_RESOURCE_SELECTOR("AudioSwitchState", AudioSwitchStateSelector, ":/AudioControlsEditor/Icons/State_Icon.png"); - REGISTER_RESOURCE_SELECTOR("AudioRTPC", AudioRTPCSelector, ":/AudioControlsEditor/Icons/RTPC_Icon.png"); - REGISTER_RESOURCE_SELECTOR("AudioEnvironment", AudioEnvironmentSelector, ":/AudioControlsEditor/Icons/Environment_Icon.png"); - REGISTER_RESOURCE_SELECTOR("AudioPreloadRequest", AudioPreloadRequestSelector, ":/AudioControlsEditor/Icons/Bank_Icon.png"); + static SStaticResourceSelectorEntry audioTriggerSelector( + "AudioTrigger", AudioTriggerSelector, ":/Icons/Trigger_Icon.svg"); + static SStaticResourceSelectorEntry audioSwitchSelector( + "AudioSwitch", AudioSwitchSelector, ":/Icons/Switch_Icon.svg"); + static SStaticResourceSelectorEntry audioStateSelector( + "AudioSwitchState", AudioSwitchStateSelector, ":/Icons/Property_Icon.png"); + static SStaticResourceSelectorEntry audioRtpcSelector( + "AudioRTPC", AudioRTPCSelector, ":/Icons/RTPC_Icon.svg"); + static SStaticResourceSelectorEntry audioEnvironmentSelector( + "AudioEnvironment", AudioEnvironmentSelector, ":/Icons/Environment_Icon.svg"); + static SStaticResourceSelectorEntry audioPreloadSelector( + "AudioPreloadRequest", AudioPreloadRequestSelector, ":/Icons/Bank_Icon.png"); + + //-------------------------------------------------------------------------------------------// + void RegisterAudioControlsResourceSelectors() + { + if (IResourceSelectorHost* host = GetIEditor()->GetResourceSelectorHost(); + host != nullptr) + { + host->RegisterResourceSelector(&audioTriggerSelector); + host->RegisterResourceSelector(&audioSwitchSelector); + host->RegisterResourceSelector(&audioStateSelector); + host->RegisterResourceSelector(&audioRtpcSelector); + host->RegisterResourceSelector(&audioEnvironmentSelector); + host->RegisterResourceSelector(&audioPreloadSelector); + } + } + } // namespace AudioControls diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h new file mode 100644 index 0000000000..d2bff7c799 --- /dev/null +++ b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +namespace AudioControls +{ + void RegisterAudioControlsResourceSelectors(); +} diff --git a/Gems/AudioSystem/Code/audiosystem_editor_files.cmake b/Gems/AudioSystem/Code/audiosystem_editor_files.cmake index 9333cea7e3..25f78121d6 100644 --- a/Gems/AudioSystem/Code/audiosystem_editor_files.cmake +++ b/Gems/AudioSystem/Code/audiosystem_editor_files.cmake @@ -54,6 +54,7 @@ set(FILES Source/Editor/AudioControlsEditorWindow.h Source/Editor/AudioControlsLoader.h Source/Editor/AudioControlsWriter.h + Source/Editor/AudioResourceSelectors.h Source/Editor/AudioSystemPanel.h Source/Editor/ImplementationManager.h Source/Editor/InspectorPanel.h From ca2889a0efda03202a41dacc6f11ad10d6ad686d Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 29 Jul 2021 15:17:58 -0500 Subject: [PATCH 060/157] fixing material property override lua test script O3DE vector usage in lua has changed since script was written Signed-off-by: Guthrie Adams --- .../material_property_overrides_demo.lua | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua b/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua index c470748801..685fd8310b 100644 --- a/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua +++ b/Gems/Atom/Feature/Common/Assets/Scripts/material_property_overrides_demo.lua @@ -53,10 +53,9 @@ function PropertyOverrideTest:OnActivate() self.originalAssignments = MaterialComponentRequestBus.Event.GetOriginalMaterialAssignments(self.entityId); self.assignmentIds = self.originalAssignments:GetKeys() - for index = 0, self.assignmentIds:Size() do - local idOutcome = self.assignmentIds:At(index) - if (idOutcome:IsSuccess()) then - local id = idOutcome:GetValue() + for index = 1, self.assignmentIds:GetSize() do + local id = self.assignmentIds[index] + if (id ~= nil) then self.colors[index] = randomColor() self.lerpDirs[index] = randomDir() end @@ -88,10 +87,9 @@ end function PropertyOverrideTest:UpdateProperties() Debug.Log("Overriding properties...") - for index = 0, self.assignmentIds:Size() do - local idOutcome = self.assignmentIds:At(index) - if (idOutcome:IsSuccess()) then - local id = idOutcome:GetValue() + for index = 1, self.assignmentIds:GetSize() do + local id = self.assignmentIds[index] + if (id ~= nil) then self:UpdateFactor(id) self:UpdateTexture(id) end @@ -134,10 +132,9 @@ function lerpColor(color, lerpDir, deltaTime) end function PropertyOverrideTest:lerpColors(deltaTime) - for index = 0, self.assignmentIds:Size() do - local idOutcome = self.assignmentIds:At(index) - if (idOutcome:IsSuccess()) then - local id = idOutcome:GetValue() + for index = 1, self.assignmentIds:GetSize() do + local id = self.assignmentIds[index] + if (id ~= nil) then lerpColor(self.colors[index], self.lerpDirs[index], deltaTime) self:UpdateColor(id, self.colors[index]) end From 8612d7bce293c4f79ca115262cbf42d051e352a9 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 29 Jul 2021 13:35:32 -0700 Subject: [PATCH 061/157] Fix incorrect blending math Signed-off-by: puvvadar --- .../Components/LocalPredictionPlayerInputComponent.cpp | 2 +- .../Code/Source/MultiplayerSystemComponent.cpp | 8 ++++---- Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index a3a5a31eb2..23578e5c18 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -157,7 +157,7 @@ namespace Multiplayer { // Client blends from previous frame to target so here we subtract blend factor to get to that state const float blendFactor = AZStd::min(AZStd::max(0.f, input.GetHostBlendFactor()), 1.f); - const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * blendFactor); + const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * (1.f - blendFactor)); m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary { ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index c16d35e725..893e53fbf6 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -861,12 +861,12 @@ namespace Multiplayer { m_tickFactor += deltaTime / serverRateSeconds; // Linear close to the origin, but asymptote at y = 1 - const float renderBlendFactor = AZStd::clamp(1.0f - (std::pow(cl_renderTickBlendBase, m_tickFactor)), 0.0f, 1.0f); + m_renderBlendFactor = AZStd::clamp(1.0f - (std::pow(cl_renderTickBlendBase, m_tickFactor)), 0.0f, 1.0f); AZLOG ( NET_Blending, "Computed blend factor of %0.3f using a tick factor of %0.3f, a frametime of %0.3f and a serverTickRate of %0.3f", - renderBlendFactor, + m_renderBlendFactor, m_tickFactor, deltaTime, serverRateSeconds @@ -913,7 +913,7 @@ namespace Multiplayer for (NetBindComponent* netBindComponent : gatheredEntities) { - netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); } } else @@ -925,7 +925,7 @@ namespace Multiplayer NetBindComponent* netBindComponent = entity->FindComponent(); if (netBindComponent != nullptr) { - netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); } } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 36ef45d647..5f0e23b2dc 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -156,6 +156,7 @@ namespace Multiplayer HostFrameId m_lastReplicatedHostFrameId = HostFrameId(0); double m_serverSendAccumulator = 0.0; + float m_renderBlendFactor = 0.0f; float m_tickFactor = 0.0f; #if !defined(AZ_RELEASE_BUILD) From 70b3840288679dbca7cabebc5d48d8756f8dee39 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 29 Jul 2021 14:30:45 -0700 Subject: [PATCH 062/157] Fix the home key popping up ImGui when it shouldn't. (#2620) This disables WM_INPUT forwarding to the input system while in game mode and makes ImGui listen to the synthetic keyboard events from the viewport instead - these synthetic events go through Qt's event system, so will only show up when the viewport "sees" a home key press. Signed-off-by: nvsickle --- Code/Editor/Core/QtEditorApplication.cpp | 52 +++++++++++++----------- Gems/ImGui/Code/Source/ImGuiManager.cpp | 20 ++++----- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Code/Editor/Core/QtEditorApplication.cpp b/Code/Editor/Core/QtEditorApplication.cpp index 46e789cd7c..5a4763d8e8 100644 --- a/Code/Editor/Core/QtEditorApplication.cpp +++ b/Code/Editor/Core/QtEditorApplication.cpp @@ -415,33 +415,37 @@ namespace Editor } // Ensure that the Windows WM_INPUT messages get passed through to the AzFramework input system. - // These events are now consumed both in and out of game mode. - if (msg->message == WM_INPUT) + // These events are only broadcast in game mode. In Editor mode, RenderViewportWidget creates synthetic + // keyboard and mouse events via Qt. + if (GetIEditor()->IsInGameMode()) { - UINT rawInputSize; - const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER); - GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, NULL, &rawInputSize, rawInputHeaderSize); - - AZStd::array rawInputBytesArray; - LPBYTE rawInputBytes = rawInputBytesArray.data(); - - const UINT bytesCopied = GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize); - CRY_ASSERT(bytesCopied == rawInputSize); - - RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes; - CRY_ASSERT(rawInput); - - AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput); - - return false; - } - else if (msg->message == WM_DEVICECHANGE) - { - if (msg->wParam == 0x0007) // DBT_DEVNODES_CHANGED + if (msg->message == WM_INPUT) { - AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputDeviceChangeEvent); + UINT rawInputSize; + const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER); + GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, NULL, &rawInputSize, rawInputHeaderSize); + + AZStd::array rawInputBytesArray; + LPBYTE rawInputBytes = rawInputBytesArray.data(); + + const UINT bytesCopied = GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize); + CRY_ASSERT(bytesCopied == rawInputSize); + + RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes; + CRY_ASSERT(rawInput); + + AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput); + + return false; + } + else if (msg->message == WM_DEVICECHANGE) + { + if (msg->wParam == 0x0007) // DBT_DEVNODES_CHANGED + { + AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputDeviceChangeEvent); + } + return true; } - return true; } return false; diff --git a/Gems/ImGui/Code/Source/ImGuiManager.cpp b/Gems/ImGui/Code/Source/ImGuiManager.cpp index cd8486b711..ac3247b6a4 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.cpp +++ b/Gems/ImGui/Code/Source/ImGuiManager.cpp @@ -452,7 +452,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel) const InputDeviceId& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId(); // Handle Keyboard Hotkeys - if (inputDeviceId == InputDeviceKeyboard::Id && inputChannel.IsStateBegan()) + if (InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId) && inputChannel.IsStateBegan()) { // Cycle through ImGui Menu Bar States on Home button press if (inputChannelId == InputDeviceKeyboard::Key::NavigationHome) @@ -477,7 +477,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel) } // Handle Keyboard Modifier Keys - if (inputDeviceId == InputDeviceKeyboard::Id) + if (InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId)) { if (inputChannelId == InputDeviceKeyboard::Key::ModifierShiftL || inputChannelId == InputDeviceKeyboard::Key::ModifierShiftR) @@ -506,14 +506,10 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel) // Handle Controller Inputs int inputControllerIndex = -1; bool controllerInput = false; - for (int i = 0; i < MaxControllerNumber; ++i) + if (InputDeviceGamepad::IsGamepadDevice(inputDeviceId)) { - //Allow only one controller navigating ImGui at the same time. After menu bar dismissed, other controllers could take over - if (inputDeviceId == InputDeviceGamepad::IdForIndexN(i)) - { - inputControllerIndex = i; - controllerInput = true; - } + inputControllerIndex = inputDeviceId.GetIndex(); + controllerInput = true; } @@ -570,7 +566,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel) } // Handle Mouse Inputs - if (inputDeviceId == InputDeviceMouse::Id) + if (InputDeviceMouse::IsMouseDevice(inputDeviceId)) { const int mouseButtonIndex = GetAzMouseButtonIndex(inputChannelId); if (0 <= mouseButtonIndex && mouseButtonIndex < AZ_ARRAY_SIZE(io.MouseDown)) @@ -584,7 +580,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel) } // Handle Touch Inputs - if (inputDeviceId == InputDeviceTouch::Id) + if (InputDeviceTouch::IsTouchDevice(inputDeviceId)) { const int touchIndex = GetAzTouchIndex(inputChannelId); if (0 <= touchIndex && touchIndex < AZ_ARRAY_SIZE(io.MouseDown)) @@ -605,7 +601,7 @@ bool ImGuiManager::OnInputChannelEventFiltered(const InputChannel& inputChannel) } // Handle Virtual Keyboard Inputs - if (inputDeviceId == InputDeviceVirtualKeyboard::Id) + if (InputDeviceVirtualKeyboard::IsVirtualKeyboardDevice(inputDeviceId)) { if (inputChannelId == AzFramework::InputDeviceVirtualKeyboard::Command::EditEnter) { From 4d618ea619e8bb2b6e4c930f77bd97411ae4d50a Mon Sep 17 00:00:00 2001 From: Jacob Hilliard Date: Tue, 20 Jul 2021 16:03:22 -0700 Subject: [PATCH 063/157] Profiling: Add more instrumentation Adds new instrumentation macros throughout the codebase, using the visualizer to find where current instrumentation is lacking using the shadowed sponza sample + editor. Some notes from exploring: - We spend ~5ms in CullingScene: BeginCulling - PipelineStateCache: Compact usually 1ms - CompileImageBarriers takes most of the time in CompileResourceBarriers Signed-off-by: Jacob Hilliard --- Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp | 1 + Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp | 1 + Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp | 2 ++ Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp | 2 +- Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp | 2 ++ Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp | 1 + Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp | 7 ++++++- Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 4 +++- 8 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp index b670dc1234..d2298cda3f 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp @@ -126,6 +126,7 @@ namespace AZ ResultCode FrameGraph::End() { + AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraph: End"); ResultCode resultCode = ValidateEnd(); if (resultCode != ResultCode::Success) { diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp index 3189acab49..342e537993 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphExecuter.cpp @@ -72,6 +72,7 @@ namespace AZ void FrameGraphExecuter::Begin(const FrameGraph& frameGraph) { AZ_TRACE_METHOD(); + AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphExecuter: Begin"); BeginInternal(frameGraph); } diff --git a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp index 1170b82d78..0210d941dc 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -205,6 +206,7 @@ namespace AZ void PipelineStateCache::Compact() { + AZ_ATOM_PROFILE_FUNCTION("RHI", "PipelineStateCache: Compact"); AZStd::unique_lock lock(m_mutex); // Merge the pending cache into the read-only cache. diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp index 083fb87b93..49244f776f 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHISystem.cpp @@ -223,7 +223,7 @@ namespace AZ * own RHI scopes to the frame scheduler. This happens prior to the RPI pass graph registration. */ { - AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "RHISystem :FrameUpdate: OnFramePrepare"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RHI", "RHISystem: FrameUpdate: OnFramePrepare"); RHISystemNotificationBus::Broadcast(&RHISystemNotificationBus::Events::OnFramePrepare, m_frameScheduler); } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp index c98fd51fbb..ba4aa76a60 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp @@ -469,6 +469,8 @@ namespace AZ ResourceTransitionLoggerNull logger(imageFrameAttachment.GetId()); #endif + AZ_ATOM_PROFILE_FUNCTION("RHI", "FrameGraphCompiler: CompileImageBarriers (DX12)"); + Image& image = static_cast(*imageFrameAttachment.GetImage()); RHI::ImageScopeAttachment* scopeAttachment = imageFrameAttachment.GetFirstScopeAttachment(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index e192e71fc4..c630fe0e5d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -720,6 +720,7 @@ namespace AZ void CullingScene::BeginCulling(const AZStd::vector& views) { + AZ_ATOM_PROFILE_FUNCTION("RPI", "CullingScene: BeginCulling"); m_cullDataConcurrencyCheck.soft_lock(); m_debugCtx.ResetCullStats(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index f62dfa1d70..27e3612a4c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -298,6 +298,7 @@ namespace AZ void PassSystem::ProcessQueuedChanges() { + AZ_ATOM_PROFILE_FUNCTION("RPI", "PassSystem: ProcessQueuedChanges"); RemovePasses(); BuildPasses(); InitializePasses(); @@ -313,7 +314,11 @@ namespace AZ m_state = PassSystemState::Rendering; Pass::FramePrepareParams params{ &frameGraphBuilder }; - m_rootPass->FrameBegin(params); + + { + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Pass: FrameBegin"); + m_rootPass->FrameBegin(params); + } } void PassSystem::FrameEnd() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index bc700dd24f..071a07ecda 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -408,6 +408,7 @@ namespace AZ { AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "m_srgCallback"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "ShaderResourceGroupCallback: SrgCallback"); // Set values for scene srg if (m_srg && m_srgCallback) { @@ -418,7 +419,7 @@ namespace AZ // Get active pipelines which need to be rendered and notify them frame started AZStd::vector activePipelines; { - AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "OnStartFrame"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnStartFrame"); for (auto& pipeline : m_pipelines) { if (pipeline->NeedsRender()) @@ -483,6 +484,7 @@ namespace AZ { AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "CollectDrawPackets"); + AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "CollectDrawPackets"); AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion(); // Launch FeatureProcessor::Render() jobs From ffbeb903c1ee70ef978c37c420b8402bb4516bb3 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 29 Jul 2021 18:09:40 -0500 Subject: [PATCH 064/157] Material Component: Add functions to lookup material ids by name Signed-off-by: Guthrie Adams --- .../Scripts/material_find_overrides_demo.lua | 160 ++++++++++++++++++ .../Feature/Material/MaterialAssignment.h | 7 +- .../Source/Material/MaterialAssignment.cpp | 43 +++++ .../Material/MaterialComponentBus.h | 5 + .../Material/MaterialComponentController.cpp | 13 +- .../Material/MaterialComponentController.h | 1 + .../Source/Mesh/MeshComponentController.cpp | 6 + .../Source/Mesh/MeshComponentController.h | 2 + .../Code/Source/AtomActorInstance.cpp | 11 ++ .../Code/Source/AtomActorInstance.h | 2 + 10 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua diff --git a/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua b/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua new file mode 100644 index 0000000000..dda3974043 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Scripts/material_find_overrides_demo.lua @@ -0,0 +1,160 @@ +---------------------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + +local FindMaterialAssignmentTest = +{ + Properties = + { + Textures = + { + "materials/presets/macbeth/05_blue_flower_srgb.tif.streamingimage", + "materials/presets/macbeth/06_bluish_green_srgb.tif.streamingimage", + "materials/presets/macbeth/09_moderate_red_srgb.tif.streamingimage", + "materials/presets/macbeth/11_yellow_green_srgb.tif.streamingimage", + "materials/presets/macbeth/12_orange_yellow_srgb.tif.streamingimage", + "materials/presets/macbeth/17_magenta_srgb.tif.streamingimage" + }, + }, +} + +function randomColor() + return Color(math.random(), math.random(), math.random(), 1.0) +end + +function randomDir() + dir = {} + for i = 1, 3 do + lerpDir = math.random() + if lerpDir < 0.5 then + table.insert(dir, -1.0) + else + table.insert(dir, 1.0) + end + end + return dir +end + +function FindMaterialAssignmentTest:OnActivate() + self.timer = 0.0 + self.totalTime = 0.0 + self.totalTimeMax = 200.0 + self.timeUpdate = 2.0 + self.colors = {} + self.lerpDirs = {} + + self.assignmentIds = + { + MaterialComponentRequestBus.Event.FindMaterialAssignmentId(self.entityId, -1, "lambert"), + } + + for index = 1, #self.assignmentIds do + local id = self.assignmentIds[index] + if (id ~= nil) then + self.colors[index] = randomColor() + self.lerpDirs[index] = randomDir() + end + end + self.tickBusHandler = TickBus.Connect(self); +end + +function FindMaterialAssignmentTest:UpdateFactor(assignmentId) + local propertyName = Name("baseColor.factor") + local propertyValue = math.random() + MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue); +end + +function FindMaterialAssignmentTest:UpdateColor(assignmentId, color) + local propertyName = Name("baseColor.color") + local propertyValue = color + MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, propertyValue); +end + +function FindMaterialAssignmentTest:UpdateTexture(assignmentId) + if (#self.Properties.Textures > 0) then + local propertyName = Name("baseColor.textureMap") + local textureName = self.Properties.Textures[ math.random( #self.Properties.Textures ) ] + Debug.Log(textureName) + local textureAssetId = AssetCatalogRequestBus.Broadcast.GetAssetIdByPath(textureName, Uuid(), false) + MaterialComponentRequestBus.Event.SetPropertyOverride(self.entityId, assignmentId, propertyName, textureAssetId); + end +end + +function FindMaterialAssignmentTest:UpdateProperties() + Debug.Log("Overriding properties...") + for index = 1, #self.assignmentIds do + local id = self.assignmentIds[index] + if (id ~= nil) then + self:UpdateFactor(id) + self:UpdateTexture(id) + end + end +end + +function FindMaterialAssignmentTest:ClearProperties() + Debug.Log("Clearing properties...") + MaterialComponentRequestBus.Event.ClearAllPropertyOverrides(self.entityId); +end + +function lerpColor(color, lerpDir, deltaTime) + local lerpSpeed = 0.5 + color.r = color.r + deltaTime * lerpDir[1] * lerpSpeed + if color.r > 1.0 then + color.r = 1.0 + lerpDir[1] = -1.0 + elseif color.r < 0 then + color.r = 0 + lerpDir[1] = 1.0 + end + + color.g = color.g + deltaTime * lerpDir[2] * lerpSpeed + if color.g > 1.0 then + color.g = 1.0 + lerpDir[2] = -1.0 + elseif color.g < 0 then + color.g = 0 + lerpDir[2] = 1.0 + end + + color.b = color.b + deltaTime * lerpDir[3] * lerpSpeed + if color.b > 1.0 then + color.b = 1.0 + lerpDir[3] = -1.0 + elseif color.b < 0 then + color.b = 0 + lerpDir[3] = 1.0 + end +end + +function FindMaterialAssignmentTest:lerpColors(deltaTime) + for index = 1, #self.assignmentIds do + local id = self.assignmentIds[index] + if (id ~= nil) then + lerpColor(self.colors[index], self.lerpDirs[index], deltaTime) + self:UpdateColor(id, self.colors[index]) + end + end +end + +function FindMaterialAssignmentTest:OnTick(deltaTime, timePoint) + self.timer = self.timer + deltaTime + self.totalTime = self.totalTime + deltaTime + self:lerpColors(deltaTime) + + if (self.timer > self.timeUpdate and self.totalTime < self.totalTimeMax) then + self.timer = self.timer - self.timeUpdate + self:UpdateProperties() + elseif self.totalTime > self.totalTimeMax then + self:ClearProperties() + self.tickBusHandler:Disconnect(self); + end +end + +return FindMaterialAssignmentTest \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 12a9c0fccc..f0f66cbd4c 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -63,5 +63,8 @@ namespace AZ //! Utility function for generating a set of available material assignments in a model MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model); - } // namespace Render -} // namespace AZ + //! Find an assignment id corresponding to the lod and label substring filters + MaterialAssignmentId FindMaterialAssignmentIdInModel( + const Data::Instance model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter); + } // namespace R ender + } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index ec48d57d1a..074d5c39e8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -166,5 +166,48 @@ namespace AZ return materials; } + + MaterialAssignmentId FindMaterialAssignmentIdInLod( + const Data::Instance& lod, const MaterialAssignmentLodIndex lodIndex, const AZStd::string& labelFilter) + { + for (const AZ::RPI::ModelLod::Mesh& mesh : lod->GetMeshes()) + { + if (mesh.m_material && mesh.m_material->GetAssetId().IsValid()) + { + AZ::Data::AssetInfo assetInfo; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, mesh.m_material->GetAssetId()); + if (assetInfo.m_assetId.IsValid() && AZ::StringFunc::Contains(assetInfo.m_relativePath, labelFilter, true)) + { + return MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId()); + } + } + } + return MaterialAssignmentId(); + } + + MaterialAssignmentId FindMaterialAssignmentIdInModel( + const Data::Instance model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter) + { + if (model && !labelFilter.empty()) + { + if (lodFilter < model->GetLodCount()) + { + return FindMaterialAssignmentIdInLod(model->GetLods()[lodFilter], lodFilter, labelFilter); + } + + for (size_t lodIndex = 0; lodIndex < model->GetLodCount(); ++lodIndex) + { + const MaterialAssignmentId result = + FindMaterialAssignmentIdInLod(model->GetLods()[lodIndex], MaterialAssignmentId::NonLodIndex, labelFilter); + if (!result.IsDefault()) + { + return result; + } + } + } + + return MaterialAssignmentId(); + } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h index 134bf6db47..6b637a67c5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h @@ -21,6 +21,8 @@ namespace AZ public: //! Get all material assignments that can be overridden virtual MaterialAssignmentMap GetOriginalMaterialAssignments() const = 0; + //! Get material assignment id matching lod and label substring + virtual MaterialAssignmentId FindMaterialAssignmentId(const MaterialAssignmentLodIndex lod, const AZStd::string& label) const = 0; //! Set material overrides virtual void SetMaterialOverrides(const MaterialAssignmentMap& materials) = 0; //! Get material overrides @@ -69,6 +71,9 @@ namespace AZ : public ComponentBus { public: + //! Get material assignment id matching lod and label substring + virtual MaterialAssignmentId FindMaterialAssignmentId( + const MaterialAssignmentLodIndex lod, const AZStd::string& label) const = 0; virtual MaterialAssignmentMap GetMaterialAssignments() const = 0; virtual AZStd::unordered_set GetModelUvNames() const = 0; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 5d9df24854..e39f5cfad5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -33,6 +33,7 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Category, "render") ->Attribute(AZ::Script::Attributes::Module, "render") ->Event("GetOriginalMaterialAssignments", &MaterialComponentRequestBus::Events::GetOriginalMaterialAssignments) + ->Event("FindMaterialAssignmentId", &MaterialComponentRequestBus::Events::FindMaterialAssignmentId) ->Event("SetMaterialOverrides", &MaterialComponentRequestBus::Events::SetMaterialOverrides) ->Event("GetMaterialOverrides", &MaterialComponentRequestBus::Events::GetMaterialOverrides) ->Event("ClearAllMaterialOverrides", &MaterialComponentRequestBus::Events::ClearAllMaterialOverrides) @@ -249,10 +250,20 @@ namespace AZ MaterialAssignmentMap MaterialComponentController::GetOriginalMaterialAssignments() const { MaterialAssignmentMap materialAssignmentMap; - MaterialReceiverRequestBus::EventResult(materialAssignmentMap, m_entityId, &MaterialReceiverRequestBus::Events::GetMaterialAssignments); + MaterialReceiverRequestBus::EventResult( + materialAssignmentMap, m_entityId, &MaterialReceiverRequestBus::Events::GetMaterialAssignments); return materialAssignmentMap; } + MaterialAssignmentId MaterialComponentController::FindMaterialAssignmentId( + const MaterialAssignmentLodIndex lod, const AZStd::string& label) const + { + MaterialAssignmentId materialAssignmentId; + MaterialReceiverRequestBus::EventResult( + materialAssignmentId, m_entityId, &MaterialReceiverRequestBus::Events::FindMaterialAssignmentId, lod, label); + return materialAssignmentId; + } + void MaterialComponentController::SetMaterialOverrides(const MaterialAssignmentMap& materials) { // this function is called twice once material asset is changed, a temp variable is diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index eb1d7465c0..de7f991d60 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -46,6 +46,7 @@ namespace AZ //! MaterialComponentRequestBus overrides... MaterialAssignmentMap GetOriginalMaterialAssignments() const override; + MaterialAssignmentId FindMaterialAssignmentId(const MaterialAssignmentLodIndex lod, const AZStd::string& label) const override; void SetMaterialOverrides(const MaterialAssignmentMap& materials) override; const MaterialAssignmentMap& GetMaterialOverrides() const override; void ClearAllMaterialOverrides() override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 29bd9a839b..fa4586daba 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -252,6 +252,12 @@ namespace AZ } } + MaterialAssignmentId MeshComponentController::FindMaterialAssignmentId( + const MaterialAssignmentLodIndex lod, const AZStd::string& label) const + { + return FindMaterialAssignmentIdInModel(GetModel(), lod, label); + } + MaterialAssignmentMap MeshComponentController::GetMaterialAssignments() const { return GetMaterialAssignmentsFromModel(GetModel()); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 80b483452f..d99d5000eb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -111,6 +111,8 @@ namespace AZ void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; // MaterialReceiverRequestBus::Handler overrides ... + virtual MaterialAssignmentId FindMaterialAssignmentId( + const MaterialAssignmentLodIndex lod, const AZStd::string& label) const override; MaterialAssignmentMap GetMaterialAssignments() const override; AZStd::unordered_set GetModelUvNames() const override; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 4c6045d7ce..706ed27a4d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -308,6 +308,17 @@ namespace AZ m_skinnedMeshFeatureProcessor = nullptr; } + MaterialAssignmentId AtomActorInstance::FindMaterialAssignmentId( + const MaterialAssignmentLodIndex lod, const AZStd::string& label) const + { + if (m_skinnedMeshInstance && m_skinnedMeshInstance->m_model) + { + return FindMaterialAssignmentIdInModel(m_skinnedMeshInstance->m_model, lod, label); + } + + return MaterialAssignmentId(); + } + MaterialAssignmentMap AtomActorInstance::GetMaterialAssignments() const { if (m_skinnedMeshInstance && m_skinnedMeshInstance->m_model) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h index c854fed3c1..1686b52d1a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h @@ -120,6 +120,8 @@ namespace AZ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MaterialReceiverRequestBus::Handler overrides... + virtual MaterialAssignmentId FindMaterialAssignmentId( + const MaterialAssignmentLodIndex lod, const AZStd::string& label) const override; MaterialAssignmentMap GetMaterialAssignments() const override; AZStd::unordered_set GetModelUvNames() const override; From e087cd87fb5d3d42a5970a2c0606b61d82fa9d34 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 30 Jul 2021 10:49:41 -0500 Subject: [PATCH 065/157] removed extra space from namespace comment Signed-off-by: Guthrie Adams --- .../Code/Include/Atom/Feature/Material/MaterialAssignment.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index f0f66cbd4c..907b1a1740 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -66,5 +67,5 @@ namespace AZ //! Find an assignment id corresponding to the lod and label substring filters MaterialAssignmentId FindMaterialAssignmentIdInModel( const Data::Instance model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter); - } // namespace R ender - } // namespace AZ + } // namespace Render +} // namespace AZ From 0313b16a85115d71a54c1def1bd6e20d31038eb9 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 30 Jul 2021 09:50:54 -0700 Subject: [PATCH 066/157] display unused variables in the editor; bump builder version for recent change to EntityId nodes Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Builder/ScriptCanvasBuilder.cpp | 70 +++++++++++++++---- .../Code/Builder/ScriptCanvasBuilder.h | 14 ++-- .../Code/Builder/ScriptCanvasBuilderWorker.h | 1 + .../EditorScriptCanvasComponent.cpp | 4 +- .../Grammar/AbstractCodeModel.cpp | 23 ++++-- .../ScriptCanvas/Grammar/AbstractCodeModel.h | 5 +- 6 files changed, 82 insertions(+), 35 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp index 73e18a356c..9c3cdca3e8 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.cpp @@ -31,29 +31,42 @@ namespace ScriptCanvasBuilder m_source.Reset(); m_variables.clear(); m_overrides.clear(); + m_overridesUnused.clear(); m_entityIds.clear(); m_dependencies.clear(); } void BuildVariableOverrides::CopyPreviousOverriddenValues(const BuildVariableOverrides& source) { - for (auto& overriddenValue : m_overrides) + auto copyPreviousIfFound = [](ScriptCanvas::GraphVariable& overriddenValue, const AZStd::vector& source) { - auto iter = AZStd::find_if(source.m_overrides.begin(), source.m_overrides.end(), [&overriddenValue](const auto& candidate) { return candidate.GetVariableId() == overriddenValue.GetVariableId(); }); - - if (iter != source.m_overrides.end()) + if (auto iter = AZStd::find_if(source.begin(), source.end(), [&overriddenValue](const auto& candidate) { return candidate.GetVariableId() == overriddenValue.GetVariableId(); }); + iter != source.end()) { overriddenValue.DeepCopy(*iter); overriddenValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); overriddenValue.SetAllowSignalOnChange(false); - // check that a name update is not necessary anymore + return true; + } + else + { + return false; + } + }; + + for (auto& overriddenValue : m_overrides) + { + if (!copyPreviousIfFound(overriddenValue, source.m_overrides)) + { + // the variable in question may have been previously unused, and is now used, so copy the previous value over + copyPreviousIfFound(overriddenValue, source.m_overridesUnused); } } ////////////////////////////////////////////////////////////////////////// // #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one. // the above will provide the data to handle the cases where only certain dependency nodes were removed - // until then we do a sanity check, if any part of the depenecies were altered, assume no overrides are valid. + // until then we do a sanity check, if any part of the dependencies were altered, assume no overrides are valid. if (m_dependencies.size() != source.m_dependencies.size()) { return; @@ -86,31 +99,41 @@ namespace ScriptCanvasBuilder if (auto serializeContext = azrtti_cast(reflectContext)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("source", &BuildVariableOverrides::m_source) ->Field("variables", &BuildVariableOverrides::m_variables) ->Field("entityId", &BuildVariableOverrides::m_entityIds) ->Field("overrides", &BuildVariableOverrides::m_overrides) + ->Field("overridesUnused", &BuildVariableOverrides::m_overridesUnused) ->Field("dependencies", &BuildVariableOverrides::m_dependencies) ; if (auto editContext = serializeContext->GetEditContext()) { - editContext->Class< BuildVariableOverrides>("Variables", "Variables exposed by the attached Script Canvas Graph") - ->ClassElement(AZ::Edit::ClassElements::Group, "Variable Fields") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + editContext->Class("Variables", "Variables exposed by the attached Script Canvas Graph") ->DataElement(AZ::Edit::UIHandlers::Default, &BuildVariableOverrides::m_overrides, "Variables", "Array of Variables within Script Canvas Graph") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) + ->DataElement(AZ::Edit::UIHandlers::Default, &BuildVariableOverrides::m_overridesUnused, "Unused Variables", "Unused variables within Script Canvas Graph, when used they keep the values set here") + ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) ->DataElement(AZ::Edit::UIHandlers::Default, &BuildVariableOverrides::m_dependencies, "Dependencies", "Variables in Dependencies of the Script Canvas Graph") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) ; } } } // use this to initialize the new data, and make sure they have a editor graph variable for proper editor display - void BuildVariableOverrides::PopulateFromParsedResults(const ScriptCanvas::Grammar::ParsedRuntimeInputs& inputs, const ScriptCanvas::VariableData& variables) + void BuildVariableOverrides::PopulateFromParsedResults(ScriptCanvas::Grammar::AbstractCodeModelConstPtr abstractCodeModel, const ScriptCanvas::VariableData& variables) { + if (!abstractCodeModel) + { + AZ_Error("ScriptCanvasBuider", false, "null abstract code model"); + return; + } + + const ScriptCanvas::Grammar::ParsedRuntimeInputs& inputs = abstractCodeModel->GetRuntimeInputs(); + for (auto& variable : inputs.m_variables) { auto graphVariable = variables.FindVariable(variable.first); @@ -148,6 +171,23 @@ namespace ScriptCanvasBuilder } } } + + for (auto& variable : abstractCodeModel->GetVariablesUnused()) + { + auto graphVariable = variables.FindVariable(variable->m_sourceVariableId); + if (!graphVariable) + { + AZ_Error("ScriptCanvasBuilder", false, "Missing Variable from graph data that was just parsed"); + continue; + } + + // copy to override unused list for editor display + m_overridesUnused.push_back(*graphVariable); + auto& overrideValue = m_overridesUnused.back(); + overrideValue.DeepCopy(*graphVariable); + overrideValue.SetScriptInputControlVisibility(AZ::Edit::PropertyVisibility::Hide); + overrideValue.SetAllowSignalOnChange(false); + } } EditorAssetTree* EditorAssetTree::ModRoot() @@ -346,7 +386,7 @@ namespace ScriptCanvasBuilder BuildVariableOverrides result; result.m_source = editorAssetTree.m_asset; - result.PopulateFromParsedResults(parseOutcome.GetValue()->GetRuntimeInputs(), *variableData); + result.PopulateFromParsedResults(parseOutcome.GetValue(), *variableData); // recurse... for (auto& dependentAsset : editorAssetTree.m_dependencies) @@ -356,7 +396,7 @@ namespace ScriptCanvasBuilder if (!parseDependentOutcome.IsSuccess()) { return AZ::Failure(AZStd::string::format - ("ParseEditorAssetTree failed to parse dependent graph from %s-%s: %s" + ( "ParseEditorAssetTree failed to parse dependent graph from %s-%s: %s" , dependentAsset.m_asset.GetId().ToString().c_str() , dependentAsset.m_asset.GetHint().c_str() , parseDependentOutcome.GetError().c_str())); diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h index c5478b51f4..f03e78bc3e 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilder.h @@ -10,16 +10,9 @@ #include #include +#include #include -namespace ScriptCanvas -{ - namespace Grammar - { - struct ParsedRuntimeInputs; - } -} - namespace ScriptCanvasEditor { class ScriptCanvasAsset; @@ -43,7 +36,7 @@ namespace ScriptCanvasBuilder bool IsEmpty() const; // use this to initialize the new data, and make sure they have a editor graph variable for proper editor display - void PopulateFromParsedResults(const ScriptCanvas::Grammar::ParsedRuntimeInputs& inputs, const ScriptCanvas::VariableData& variables); + void PopulateFromParsedResults(ScriptCanvas::Grammar::AbstractCodeModelConstPtr abstractCodeModel, const ScriptCanvas::VariableData& variables); // #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one. AZ::Data::Asset m_source; @@ -52,8 +45,9 @@ namespace ScriptCanvasBuilder AZStd::vector m_variables; // the values here may or may not be overrides AZStd::vector> m_entityIds; - // this is all that gets exposed to the edit context + // these two variable lists are all that gets exposed to the edit context AZStd::vector m_overrides; + AZStd::vector m_overridesUnused; // AZStd::vector m_entityIdRuntimeInputIndices; since all of the entity ids need to go in, they may not need indices AZStd::vector m_dependencies; }; diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h index 6bd5caf1a6..668e1a0bcd 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderWorker.h @@ -58,6 +58,7 @@ namespace ScriptCanvasBuilder AddAssetDependencySearch, PrefabIntegration, CorrectGraphVariableVersion, + ReflectEntityIdNodes, // add new entries above Current, }; diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index dbc525e8e1..4a7a11778c 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -424,14 +424,14 @@ namespace ScriptCanvasEditor void EditorScriptCanvasComponent::OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) { - OnScriptCanvasAssetReady(asset); + // OnScriptCanvasAssetReady(asset); } void EditorScriptCanvasComponent::OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) { if (isSuccessful) { - OnScriptCanvasAssetReady(asset); + // OnScriptCanvasAssetReady(asset); } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 3e4a425a6e..4509e7e907 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -1358,17 +1358,23 @@ namespace ScriptCanvas { if (variable->m_isMember) { - return !this->m_variableUse.memberVariables.contains(variable); + if (!this->m_variableUse.memberVariables.contains(variable)) + { + m_variablesUnused.push_back(variable); + return true; + } } else { - return !this->m_variableUse.localVariables.contains(variable); + if (!this->m_variableUse.localVariables.contains(variable)) + { + m_variablesUnused.push_back(variable); + return true; + } } } - else - { - return false; - } + + return false; }); } @@ -2068,6 +2074,11 @@ namespace ScriptCanvas return m_variables; } + const AZStd::vector& AbstractCodeModel::GetVariablesUnused() const + { + return m_variablesUnused; + } + bool AbstractCodeModel::IsActiveGraph() const { if (!m_nodeablesByNode.empty()) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h index cdbdf611e5..7c5340bd18 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h @@ -138,6 +138,8 @@ namespace ScriptCanvas const AZStd::vector& GetVariables() const; + const AZStd::vector& GetVariablesUnused() const; + bool IsErrorFree() const; // has modified data or handlers @@ -166,8 +168,6 @@ namespace ScriptCanvas void AddAllVariablesPreParse(); - void AddAllVariablesPreParse_LegacyFunctions(); - void AddDebugInformation(); void AddDebugInformation(ExecutionChild& execution); @@ -519,6 +519,7 @@ namespace ScriptCanvas AZStd::unordered_map m_dependencyByVariable; AZStd::vector m_variables; + AZStd::vector m_variablesUnused; AZStd::vector m_possibleExecutionRoots; // true iff there are no internal errors and no error validation events From 3633bf2ed0ea199ff6d0309aeaef2698efd26375 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 30 Jul 2021 10:07:23 -0700 Subject: [PATCH 067/157] remove accidental submission of commented out event handling Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/Components/EditorScriptCanvasComponent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp index 4a7a11778c..dbc525e8e1 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorScriptCanvasComponent.cpp @@ -424,14 +424,14 @@ namespace ScriptCanvasEditor void EditorScriptCanvasComponent::OnAssetReady(const ScriptCanvasMemoryAsset::pointer asset) { - // OnScriptCanvasAssetReady(asset); + OnScriptCanvasAssetReady(asset); } void EditorScriptCanvasComponent::OnAssetSaved(const ScriptCanvasMemoryAsset::pointer asset, bool isSuccessful) { if (isSuccessful) { - // OnScriptCanvasAssetReady(asset); + OnScriptCanvasAssetReady(asset); } } From e52606da697eacb390b9ff510450483871c8de45 Mon Sep 17 00:00:00 2001 From: nemerle <96597+nemerle@users.noreply.github.com> Date: Fri, 30 Jul 2021 19:26:34 +0200 Subject: [PATCH 068/157] AZStd::ref prevented compiler from using RVO Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- .../Code/Include/ScriptEvents/Internal/VersionedProperty.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/VersionedProperty.h b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/VersionedProperty.h index 07d85adf05..b308a074e0 100644 --- a/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/VersionedProperty.h +++ b/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/VersionedProperty.h @@ -109,7 +109,7 @@ namespace ScriptEventData { VersionedProperty property = VersionedProperty("Void"); property.Set(VoidType {}); - return AZStd::ref(property); + return property; } template From 318fee8e22a87a73483a1fc5d2d4c46b6220382c Mon Sep 17 00:00:00 2001 From: puvvadar Date: Fri, 30 Jul 2021 10:38:15 -0700 Subject: [PATCH 069/157] Fix tabs Signed-off-by: puvvadar --- Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 5f0e23b2dc..e2fb7deacc 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -156,7 +156,7 @@ namespace Multiplayer HostFrameId m_lastReplicatedHostFrameId = HostFrameId(0); double m_serverSendAccumulator = 0.0; - float m_renderBlendFactor = 0.0f; + float m_renderBlendFactor = 0.0f; float m_tickFactor = 0.0f; #if !defined(AZ_RELEASE_BUILD) From 893a80a54e5a119dfc9b92e234c049f28fcc66d2 Mon Sep 17 00:00:00 2001 From: chcurran <82187351+carlitosan@users.noreply.github.com> Date: Fri, 30 Jul 2021 11:37:40 -0700 Subject: [PATCH 070/157] Fix variables names in the property window Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com> --- .../View/Widgets/VariablePanel/VariableDockWidget.cpp | 1 - .../Code/Include/ScriptCanvas/Core/Datum.cpp | 1 - .../Include/ScriptCanvas/Variable/GraphVariable.cpp | 11 ----------- .../Include/ScriptCanvas/Variable/GraphVariable.h | 3 --- 4 files changed, 16 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/VariableDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/VariableDockWidget.cpp index 65333059cc..60bc7ba0d2 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/VariableDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/VariablePanel/VariableDockWidget.cpp @@ -120,7 +120,6 @@ namespace ScriptCanvasEditor m_variableName = m_variable->GetVariableName(); const AZStd::string variableTypeName = TranslationHelper::GetSafeTypeName(m_variable->GetDatum()->GetType()); - m_variable->SetDisplayName(variableTypeName); m_componentTitle = AZStd::string::format("%s Variable", variableTypeName.data()); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp index 47f74329e0..e4569af820 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp @@ -2083,7 +2083,6 @@ namespace ScriptCanvas editContext->Class("Datum", "Datum") ->ClassElement(AZ::Edit::ClassElements::EditorData, "Datum") ->Attribute(AZ::Edit::Attributes::Visibility, &Datum::GetVisibility) - ->Attribute(AZ::Edit::Attributes::ChildNameLabelOverride, &Datum::GetLabel) ->DataElement(AZ::Edit::UIHandlers::Default, &Datum::m_storage, "Datum", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Datum::GetDatumVisibility) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp index cc9e60e765..3d76883adc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.cpp @@ -348,7 +348,6 @@ namespace ScriptCanvas void GraphVariable::SetVariableName(AZStd::string_view variableName) { m_variableName = variableName; - SetDisplayName(variableName); } AZStd::string_view GraphVariable::GetVariableName() const @@ -356,16 +355,6 @@ namespace ScriptCanvas return m_variableName; } - void GraphVariable::SetDisplayName(const AZStd::string& displayName) - { - m_datum.SetLabel(displayName); - } - - AZStd::string_view GraphVariable::GetDisplayName() const - { - return m_datum.GetLabel(); - } - void GraphVariable::SetScriptInputControlVisibility(const AZ::Crc32& inputControlVisibility) { m_inputControlVisibility = inputControlVisibility; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h index fd15ac95ee..dbc0a814c6 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Variable/GraphVariable.h @@ -134,9 +134,6 @@ namespace ScriptCanvas void SetVariableName(AZStd::string_view displayName); AZStd::string_view GetVariableName() const; - void SetDisplayName(const AZStd::string& displayName); - AZStd::string_view GetDisplayName() const; - void SetScriptInputControlVisibility(const AZ::Crc32& inputControlVisibility); AZ::Crc32 GetInputControlVisibility() const; From 02486a6fbeeaf9898232e5a4dccf4644a8f64c92 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Fri, 30 Jul 2021 11:38:53 -0700 Subject: [PATCH 071/157] Add usage intention to GetPrevious descriptor Signed-off-by: puvvadar --- .../Code/Include/Multiplayer/NetworkTime/RewindableObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h index 072c1843f2..a8af564c15 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h @@ -60,7 +60,7 @@ namespace Multiplayer //! @return value in const base type form const BASE_TYPE& Get() const; - //! Const base type retriever for one host frame behind Get(). + //! Const base type retriever for one host frame behind Get(). Only intended for use in SyncRewind contexts. //! @return value in const base type form const BASE_TYPE& GetPrevious() const; From 0cf6ecf3f7ff64cd987917a1ab64d9f73fe3d89a Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Tue, 13 Jul 2021 16:25:10 -0700 Subject: [PATCH 072/157] Deleted unused "default" materials from RPI. Long ago these were used as defaults for FBX material conversion process, but that's no longer the case. And I'm about to add a new approach for default material conversion in SceneAPI. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI/Assets/Materials/Default.materialtype | 90 ------------- .../RPI/Assets/Materials/DefaultMaterial.azsl | 127 ------------------ .../Assets/Materials/DefaultMaterial.shader | 26 ---- .../Materials/DefaultMaterial_DepthPass.azsl | 33 ----- .../DefaultMaterial_DepthPass.shader | 20 --- .../RPI/Assets/atom_rpi_asset_files.cmake | 5 - 6 files changed, 301 deletions(-) delete mode 100644 Gems/Atom/RPI/Assets/Materials/Default.materialtype delete mode 100644 Gems/Atom/RPI/Assets/Materials/DefaultMaterial.azsl delete mode 100644 Gems/Atom/RPI/Assets/Materials/DefaultMaterial.shader delete mode 100644 Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.azsl delete mode 100644 Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.shader diff --git a/Gems/Atom/RPI/Assets/Materials/Default.materialtype b/Gems/Atom/RPI/Assets/Materials/Default.materialtype deleted file mode 100644 index e8e6ff24eb..0000000000 --- a/Gems/Atom/RPI/Assets/Materials/Default.materialtype +++ /dev/null @@ -1,90 +0,0 @@ -{ - "description": "A simple default base material used primarily for imported model files like FBX.", - "propertyLayout": { - "version": 1, - "properties": { - "general": [ - { - "id": "DiffuseColor", - "type": "color", - "defaultValue": [ 1.0, 1.0, 1.0 ], - "connection": { - "type": "shaderInput", - "id": "m_diffuseColor" - } - }, - { - "id": "DiffuseMap", - "type": "image", - "defaultValue": "", - "connection": { - "type": "shaderInput", - "id": "m_diffuseMap" - } - }, - { - "id": "UseDiffuseMap", - "type": "bool", - "defaultValue": false, - "connection": { - "type": "shaderOption", - "id": "o_useDiffuseMap" - } - }, - { - "id": "SpecularColor", - "type": "color", - "defaultValue": [ 0.0, 0.0, 0.0 ], - "connection": { - "type": "shaderInput", - "id": "m_specularColor" - } - }, - { - "id": "SpecularMap", - "type": "image", - "defaultValue": "", - "connection": { - "type": "shaderInput", - "id": "m_specularMap" - } - }, - { - "id": "UseSpecularMap", - "type": "bool", - "defaultValue": false, - "connection": { - "type": "shaderOption", - "id": "o_useSpecularMap" - } - }, - { - "id": "NormalMap", - "type": "image", - "defaultValue": "", - "connection": { - "type": "shaderInput", - "id": "m_normalMap" - } - }, - { - "id": "UseNormalMap", - "type": "bool", - "defaultValue": false, - "connection": { - "type": "shaderOption", - "id": "o_useNormalMap" - } - } - ] - } - }, - "shaders": [ - { - "file": "DefaultMaterial.shader" - }, - { - "file": "DefaultMaterial_DepthPass.shader" - } - ] -} diff --git a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial.azsl b/Gems/Atom/RPI/Assets/Materials/DefaultMaterial.azsl deleted file mode 100644 index 6640ed3fca..0000000000 --- a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial.azsl +++ /dev/null @@ -1,127 +0,0 @@ - -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -#include -#include -#include - -ShaderResourceGroup MaterialSrg : SRG_PerMaterial -{ - float4 m_diffuseColor; - float3 m_specularColor; - - Texture2D m_diffuseMap; - Texture2D m_normalMap; - Texture2D m_specularMap; - - Sampler m_sampler - { - MaxAnisotropy = 16; - AddressU = Wrap; - AddressV = Wrap; - AddressW = Wrap; - }; -} - -option bool o_useDiffuseMap = false; -option bool o_useSpecularMap = false; -option bool o_useNormalMap = false; - -struct VertexInput -{ - float3 m_position : POSITION; - float3 m_normal : NORMAL; - float4 m_tangent : TANGENT; - float3 m_bitangent : BITANGENT; - float2 m_uv : UV0; -}; - -struct VertexOutput -{ - float4 m_position : SV_Position; - float3 m_normal : NORMAL; - float3 m_tangent : TANGENT; - float3 m_bitangent : BITANGENT; - float2 m_uv : UV0; - float3 m_positionToCamera : VIEW; -}; - -VertexOutput MainVS(VertexInput input) -{ - const float4x4 objectToWorldMatrix = ObjectSrg::GetWorldMatrix(); - - VertexOutput output; - float3 worldPosition = mul(objectToWorldMatrix, float4(input.m_position,1)).xyz; - output.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0)); - - output.m_uv = input.m_uv; - - output.m_positionToCamera = ViewSrg::m_worldPosition - worldPosition; - - float3x3 objectToWorldMatrixIT = ObjectSrg::GetWorldMatrixInverseTranspose(); - - ConstructTBN(input.m_normal, input.m_tangent, input.m_bitangent, objectToWorldMatrix, objectToWorldMatrixIT, output.m_normal, output.m_tangent, output.m_bitangent); - - return output; -} - -struct PixelOutput -{ - float4 m_color : SV_Target0; -}; - -PixelOutput MainPS(VertexOutput input) -{ - PixelOutput output; - - // Very rough placeholder lighting - static const float3 lightDir = normalize(float3(1,1,1)); - - float4 baseColor = MaterialSrg::m_diffuseColor; - if (o_useDiffuseMap) - { - baseColor *= MaterialSrg::m_diffuseMap.Sample(MaterialSrg::m_sampler, input.m_uv); - } - - float3 specular = MaterialSrg::m_specularColor; - if (o_useSpecularMap) - { - specular *= MaterialSrg::m_specularMap.Sample(MaterialSrg::m_sampler, input.m_uv).rgb; - } - - float3 normal; - if (o_useNormalMap) - { - float4 sampledValue = MaterialSrg::m_normalMap.Sample(MaterialSrg::m_sampler, input.m_uv); - normal = GetWorldSpaceNormal(sampledValue.xy, input.m_normal, input.m_tangent, input.m_bitangent); - } - else - { - normal = normalize(input.m_normal); - } - - float3 viewDir = normalize(input.m_positionToCamera); - float3 H = normalize(lightDir + viewDir); - float NdotH = max(0.001, dot(normal, H)); - float NdotL = saturate(dot(normal, lightDir)); - - float3 diffuse = NdotL * baseColor.xyz; - - specular = pow(NdotH, 5.0) * specular; - - // Combined - float3 result = diffuse + specular + float3(0.1, 0.1, 0.1) * baseColor.xyz; - - output.m_color = float4(result.xyz, baseColor.a); - - return output; -} diff --git a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial.shader b/Gems/Atom/RPI/Assets/Materials/DefaultMaterial.shader deleted file mode 100644 index ceea480f43..0000000000 --- a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial.shader +++ /dev/null @@ -1,26 +0,0 @@ -{ - "Source" : "DefaultMaterial.azsl", - - "DepthStencilState" : { - "Depth" : { "Enable" : true, "CompareFunc" : "Equal" } - }, - - "DrawList" : "forward", - - "ProgramSettings": - { - "EntryPoints": - [ - { - "name": "MainVS", - "type": "Vertex" - }, - { - "name": "MainPS", - "type": "Fragment" - } - ] - } -} - - diff --git a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.azsl b/Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.azsl deleted file mode 100644 index 961fde7568..0000000000 --- a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.azsl +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -#include - -struct VertexInput -{ - float3 m_position : POSITION; -}; - -struct VertexOutput -{ - float4 m_position : SV_Position; -}; - -VertexOutput MainVS(VertexInput input) -{ - const float4x4 objectToWorldMatrix = ObjectSrg::GetWorldMatrix(); - - VertexOutput output; - float3 worldPosition = mul(objectToWorldMatrix, float4(input.m_position,1)).xyz; - output.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0)); - return output; -} diff --git a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.shader b/Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.shader deleted file mode 100644 index 19ba1d5d9d..0000000000 --- a/Gems/Atom/RPI/Assets/Materials/DefaultMaterial_DepthPass.shader +++ /dev/null @@ -1,20 +0,0 @@ -{ - "Source" : "DefaultMaterial_DepthPass.azsl", - - "DepthStencilState" : { - "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } - }, - - "DrawList" : "depth", - - "ProgramSettings": - { - "EntryPoints": - [ - { - "name": "MainVS", - "type": "Vertex" - } - ] - } -} diff --git a/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake b/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake index 8f85259f7d..9e89427a70 100644 --- a/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake +++ b/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake @@ -7,11 +7,6 @@ # set(FILES - Materials/Default.materialtype - Materials/DefaultMaterial.azsl - Materials/DefaultMaterial.shader - Materials/DefaultMaterial_DepthPass.azsl - Materials/DefaultMaterial_DepthPass.shader Shader/DecomposeMsImage.azsl Shader/DecomposeMsImage.shader Shader/ImagePreview.azsl From 14d2e38b90c07bf2bd4fc0afc7d2e3409d88e84f Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Sat, 17 Jul 2021 00:07:23 -0700 Subject: [PATCH 073/157] Refactored how model material slots work in preparation to support more flexible material conversion options for the scene asset pipeline. The material slot IDs are based on the MaterialUid that come from SceneAPI. Since these IDs are also used as the AssetId sub-ID for the converted material assets, the system was just checking the material asset sub-ID to determine the material slot ID. But in order to support certain FBX material conversion options, we needed to break this tie, so the slot ID is separate from the AssetId of the material in that slot. This will allow some other material to be used in the slot, instead of being forced to use one that was generated from the FBX. Here we inttroduce a new struct ModelMaterialSlot which formalizes the concept of material slot, with an ID, display name, and default material assignment. The ID still comes from the MaterialUid like before. The display name is built-in, rather than being parsed out from the asset file name. And the default material assignment can be any material asset, it doesn't have to come from the FBX (or other scene file). This commit is just the preliminary set of changes. Cursory testing shows that it works pretty well but more testing is needed (and likely some fixes) before merging. Here is what's left to do... Add serialization version converters to preserve prior prefab data. See if we can get rid of GetLabelByAssetId function only rely on the display name inside ModelMaterialSlot. I'm not sure if the condition for enabling the "Edit Material Instance..." context menu item is correct. Test actors Lots more testing in general Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Feature/Material/MaterialAssignmentId.h | 35 +++-- .../Source/Material/MaterialAssignment.cpp | 6 +- .../Source/Material/MaterialAssignmentId.cpp | 51 ++++--- .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 20 +-- .../SkinnedMesh/SkinnedMeshInputBuffers.cpp | 7 +- .../Include/Atom/RPI.Public/Model/ModelLod.h | 2 + .../Atom/RPI.Reflect/Model/ModelAsset.h | 3 + .../Atom/RPI.Reflect/Model/ModelLodAsset.h | 29 +++- .../RPI.Reflect/Model/ModelLodAssetCreator.h | 6 +- .../RPI.Reflect/Model/ModelMaterialSlot.h | 43 ++++++ .../Model/ModelAssetBuilderComponent.cpp | 10 +- .../Code/Source/RPI.Public/Model/ModelLod.cpp | 9 +- .../Source/RPI.Public/Model/ModelSystem.cpp | 1 + .../Source/RPI.Reflect/Model/ModelAsset.cpp | 24 ++++ .../RPI.Reflect/Model/ModelLodAsset.cpp | 48 ++++++- .../Model/ModelLodAssetCreator.cpp | 32 ++++- .../RPI.Reflect/Model/ModelMaterialSlot.cpp | 30 ++++ .../RPI/Code/atom_rpi_reflect_files.cmake | 2 + .../Material/MaterialComponentBus.h | 3 + .../Material/EditorMaterialComponent.cpp | 136 +++++++++--------- .../EditorMaterialComponentExporter.cpp | 6 +- .../EditorMaterialComponentExporter.h | 11 +- .../Material/EditorMaterialComponentSlot.cpp | 33 ++--- .../Material/EditorMaterialComponentSlot.h | 4 +- .../Material/MaterialComponentConfig.cpp | 2 +- .../Source/Mesh/MeshComponentController.cpp | 13 ++ .../Source/Mesh/MeshComponentController.h | 1 + .../EMotionFXAtom/Code/Source/ActorAsset.cpp | 8 +- .../Code/Source/AtomActorInstance.cpp | 13 ++ .../Code/Source/AtomActorInstance.h | 1 + .../Rendering/Atom/WhiteBoxAtomRenderMesh.cpp | 5 +- 31 files changed, 399 insertions(+), 195 deletions(-) create mode 100644 Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h create mode 100644 Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h index dd198a7179..d9ae8099da 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace AZ { @@ -23,7 +24,7 @@ namespace AZ using MaterialAssignmentLodIndex = AZ::u64; //! MaterialAssignmentId is used to address available and overridable material slots on a model. - //! The LOD and one of the model's original material asset IDs are used as coordinates that identify + //! The LOD and one of the model's original material slot IDs are used as coordinates that identify //! a specific material slot or a set of slots matching either. struct MaterialAssignmentId final { @@ -33,41 +34,39 @@ namespace AZ MaterialAssignmentId() = default; - MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId); + MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, RPI::ModelMaterialSlot::StableId materialSlotStableId); - //! Create an ID that maps to all material slots, regardless of asset ID or LOD, effectively applying to an entire model. + //! Create an ID that maps to all material slots, regardless of slot ID or LOD, effectively applying to an entire model. static MaterialAssignmentId CreateDefault(); - //! Create an ID that maps to all material slots with a corresponding asset ID, regardless of LOD. - static MaterialAssignmentId CreateFromAssetOnly(AZ::Data::AssetId materialAssetId); + //! Create an ID that maps to all material slots with a corresponding slot ID, regardless of LOD. + static MaterialAssignmentId CreateFromStableIdOnly(RPI::ModelMaterialSlot::StableId materialSlotStableId); - //! Create an ID that maps to a specific material slot with a corresponding asset ID and LOD. - static MaterialAssignmentId CreateFromLodAndAsset(MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId); + //! Create an ID that maps to a specific material slot with a corresponding stable ID and LOD. + static MaterialAssignmentId CreateFromLodAndStableId(MaterialAssignmentLodIndex lodIndex, RPI::ModelMaterialSlot::StableId materialSlotStableId); - //! Returns true if the asset ID and LOD are invalid + //! Returns true if the slot stable ID and LOD are invalid, meaning this assignment applies to the entire model. bool IsDefault() const; - //! Returns true if the asset ID is valid and LOD is invalid - bool IsAssetOnly() const; + //! Returns true if the slot stable ID is valid and LOD is invalid, meaning this assignment applies to every LOD. + bool IsSlotIdOnly() const; - //! Returns true if the asset ID and LOD are both valid - bool IsLodAndAsset() const; + //! Returns true if the slot stable ID and LOD are both valid, meaning this assignment applies to a single material slot on a specific LOD. + bool IsLodAndSlotId() const; - //! Creates a string composed of the asset path and LOD + //! Creates a string describing all the details of the assignment ID AZStd::string ToString() const; - //! Creates a hash composed of the asset ID sub ID and LOD + //! Creates a hash composed of all elements of the assignment ID size_t GetHash() const; - //! Returns true if both asset ID sub IDs and LODs match bool operator==(const MaterialAssignmentId& rhs) const; - - //! Returns true if both asset ID sub IDs and LODs do not match bool operator!=(const MaterialAssignmentId& rhs) const; static constexpr MaterialAssignmentLodIndex NonLodIndex = -1; + MaterialAssignmentLodIndex m_lodIndex = NonLodIndex; - AZ::Data::AssetId m_materialAssetId = AZ::Data::AssetId(); + RPI::ModelMaterialSlot::StableId m_materialSlotStableId = RPI::ModelMaterialSlot::InvalidStableId; }; } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index ec48d57d1a..9ae4f65304 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -123,7 +123,7 @@ namespace AZ } const MaterialAssignment& assetAssignment = - GetMaterialAssignmentFromMap(materials, MaterialAssignmentId::CreateFromAssetOnly(id.m_materialAssetId)); + GetMaterialAssignmentFromMap(materials, MaterialAssignmentId::CreateFromStableIdOnly(id.m_materialSlotStableId)); if (assetAssignment.m_materialInstance.get()) { return assetAssignment; @@ -152,11 +152,11 @@ namespace AZ { if (mesh.m_material) { - const MaterialAssignmentId generalId = MaterialAssignmentId::CreateFromAssetOnly(mesh.m_material->GetAssetId()); + const MaterialAssignmentId generalId = MaterialAssignmentId::CreateFromStableIdOnly(mesh.m_materialSlotStableId); materials[generalId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); const MaterialAssignmentId specificId = - MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId()); + MaterialAssignmentId::CreateFromLodAndStableId(lodIndex, mesh.m_materialSlotStableId); materials[specificId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp index 71dea0596f..8b6b0be237 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp @@ -19,9 +19,9 @@ namespace AZ if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("lodIndex", &MaterialAssignmentId::m_lodIndex) - ->Field("materialAssetId", &MaterialAssignmentId::m_materialAssetId) + ->Field("materialSlotStableId", &MaterialAssignmentId::m_materialSlotStableId) ; } @@ -33,75 +33,72 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Module, "render") ->Constructor() ->Constructor() - ->Constructor() + ->Constructor() ->Method("IsDefault", &MaterialAssignmentId::IsDefault) - ->Method("IsAssetOnly", &MaterialAssignmentId::IsAssetOnly) - ->Method("IsLodAndAsset", &MaterialAssignmentId::IsLodAndAsset) + ->Method("IsAssetOnly", &MaterialAssignmentId::IsSlotIdOnly) // Included for compatibility. Use "IsSlotIdOnly" instead. + ->Method("IsLodAndAsset", &MaterialAssignmentId::IsLodAndSlotId) // Included for compatibility. Use "IsLodAndSlotId" instead. + ->Method("IsSlotIdOnly", &MaterialAssignmentId::IsSlotIdOnly) + ->Method("IsLodAndSlotId", &MaterialAssignmentId::IsLodAndSlotId) ->Method("ToString", &MaterialAssignmentId::ToString) ->Property("lodIndex", BehaviorValueProperty(&MaterialAssignmentId::m_lodIndex)) - ->Property("materialAssetId", BehaviorValueProperty(&MaterialAssignmentId::m_materialAssetId)) + ->Property("materialSlotStableId", BehaviorValueProperty(&MaterialAssignmentId::m_materialSlotStableId)) ; } } - MaterialAssignmentId::MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId) + MaterialAssignmentId::MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, RPI::ModelMaterialSlot::StableId materialSlotStableId) : m_lodIndex(lodIndex) - , m_materialAssetId(materialAssetId) + , m_materialSlotStableId(materialSlotStableId) { } MaterialAssignmentId MaterialAssignmentId::CreateDefault() { - return MaterialAssignmentId(NonLodIndex, AZ::Data::AssetId()); + return MaterialAssignmentId(NonLodIndex, RPI::ModelMaterialSlot::InvalidStableId); } - MaterialAssignmentId MaterialAssignmentId::CreateFromAssetOnly(AZ::Data::AssetId materialAssetId) + MaterialAssignmentId MaterialAssignmentId::CreateFromStableIdOnly(RPI::ModelMaterialSlot::StableId materialSlotStableId) { - return MaterialAssignmentId(NonLodIndex, materialAssetId); + return MaterialAssignmentId(NonLodIndex, materialSlotStableId); } - MaterialAssignmentId MaterialAssignmentId::CreateFromLodAndAsset( - MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId) + MaterialAssignmentId MaterialAssignmentId::CreateFromLodAndStableId( + MaterialAssignmentLodIndex lodIndex, RPI::ModelMaterialSlot::StableId materialSlotStableId) { - return MaterialAssignmentId(lodIndex, materialAssetId); + return MaterialAssignmentId(lodIndex, materialSlotStableId); } bool MaterialAssignmentId::IsDefault() const { - return m_lodIndex == NonLodIndex && !m_materialAssetId.IsValid(); + return m_lodIndex == NonLodIndex && m_materialSlotStableId == RPI::ModelMaterialSlot::InvalidStableId; } - bool MaterialAssignmentId::IsAssetOnly() const + bool MaterialAssignmentId::IsSlotIdOnly() const { - return m_lodIndex == NonLodIndex && m_materialAssetId.IsValid(); + return m_lodIndex == NonLodIndex && m_materialSlotStableId != RPI::ModelMaterialSlot::InvalidStableId; } - bool MaterialAssignmentId::IsLodAndAsset() const + bool MaterialAssignmentId::IsLodAndSlotId() const { - return m_lodIndex != NonLodIndex && m_materialAssetId.IsValid(); + return m_lodIndex != NonLodIndex && m_materialSlotStableId != RPI::ModelMaterialSlot::InvalidStableId; } AZStd::string MaterialAssignmentId::ToString() const { - AZStd::string assetPathString; - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAssetId); - AZ::StringFunc::Path::StripPath(assetPathString); - AZ::StringFunc::Path::StripExtension(assetPathString); - return AZStd::string::format("%s:%llu", assetPathString.c_str(), m_lodIndex); + return AZStd::string::format("%u:%llu", m_materialSlotStableId, m_lodIndex); } size_t MaterialAssignmentId::GetHash() const { size_t seed = 0; AZStd::hash_combine(seed, m_lodIndex); - AZStd::hash_combine(seed, m_materialAssetId.m_subId); + AZStd::hash_combine(seed, m_materialSlotStableId); return seed; } bool MaterialAssignmentId::operator==(const MaterialAssignmentId& rhs) const { - return m_lodIndex == rhs.m_lodIndex && m_materialAssetId.m_subId == rhs.m_materialAssetId.m_subId; + return m_lodIndex == rhs.m_lodIndex && m_materialSlotStableId == rhs.m_materialSlotStableId; } bool MaterialAssignmentId::operator!=(const MaterialAssignmentId& rhs) const diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index c6362f3a5d..6e031aa853 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -589,18 +589,6 @@ namespace AZ { AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender); - auto modelAsset = model->GetModelAsset(); - for (const auto& modelLodAsset : modelAsset->GetLodAssets()) - { - for (const auto& mesh : modelLodAsset->GetMeshes()) - { - if (mesh.GetMaterialAsset().GetStatus() != Data::AssetData::AssetStatus::Ready) - { - - } - } - } - m_model = model; const size_t modelLodCount = m_model->GetLodCount(); m_drawPacketListsByLod.resize(modelLodCount); @@ -644,10 +632,12 @@ namespace AZ for (size_t meshIndex = 0; meshIndex < meshCount; ++meshIndex) { - Data::Instance material = modelLod.GetMeshes()[meshIndex].m_material; + const RPI::ModelLod::Mesh& mesh = modelLod.GetMeshes()[meshIndex]; + + Data::Instance material = mesh.m_material; // Determine if there is a material override specified for this sub mesh - const MaterialAssignmentId materialAssignmentId(modelLodIndex, material ? material->GetAssetId() : AZ::Data::AssetId()); + const MaterialAssignmentId materialAssignmentId(modelLodIndex, mesh.m_materialSlotStableId); const MaterialAssignment& materialAssignment = GetMaterialAssignmentFromMapWithFallback(m_materialAssignments, materialAssignmentId); if (materialAssignment.m_materialInstance.get()) { @@ -790,7 +780,7 @@ namespace AZ // retrieve the material Data::Instance material = mesh.m_material; - const MaterialAssignmentId materialAssignmentId(rayTracingLod, material ? material->GetAssetId() : AZ::Data::AssetId()); + const MaterialAssignmentId materialAssignmentId(rayTracingLod, mesh.m_materialSlotStableId); const MaterialAssignment& materialAssignment = GetMaterialAssignmentFromMapWithFallback(m_materialAssignments, materialAssignmentId); if (materialAssignment.m_materialInstance.get()) { diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp index 155b751272..640e30d0f6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp @@ -639,8 +639,13 @@ namespace AZ Aabb localAabb = lod.m_subMeshProperties[i].m_aabb; modelLodCreator.SetMeshAabb(AZStd::move(localAabb)); + + // Create a separate material slot for each sub-mesh + AZ::RPI::ModelMaterialSlot materialSlot; + materialSlot.m_stableId = i; + materialSlot.m_defaultMaterialAsset = lod.m_subMeshProperties[i].m_material; - modelLodCreator.SetMeshMaterialAsset(lod.m_subMeshProperties[i].m_material); + modelLodCreator.SetMeshMaterialSlot(materialSlot); modelLodCreator.EndMesh(); } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h index dcc4813b3d..36892d0027 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h @@ -72,6 +72,8 @@ namespace AZ RHI::IndexBufferView m_indexBufferView; StreamInfoList m_streamInfo; + + ModelMaterialSlot::StableId m_materialSlotStableId = ModelMaterialSlot::InvalidStableId; //! The default material assigned to the mesh by the asset. Data::Instance m_material; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h index b7414f73a2..891aec04b3 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h @@ -49,6 +49,9 @@ namespace AZ //! Returns the model-space axis aligned bounding box const AZ::Aabb& GetAabb() const; + + //! Returns the list of all ModelMaterialSlot's for the model, across all LODs. + RPI::ModelMaterialSlotMap GetModelMaterialSlots() const; //! Returns the number of Lods in the model size_t GetLodCount() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h index 4e86b0e367..61e2ebeb05 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -84,8 +85,9 @@ namespace AZ //! Returns the number of indices in this mesh uint32_t GetIndexCount() const; - //! Returns the reference to material asset used by this mesh - const Data::Asset & GetMaterialAsset() const; + //! Returns the index of the material slot used by this mesh. + //! This indexes into the ModelLodAsset's material slot list. + size_t GetMaterialSlotIndex() const; //! Returns the name of this mesh const AZ::Name& GetName() const; @@ -124,7 +126,9 @@ namespace AZ AZ::Name m_name; AZ::Aabb m_aabb = AZ::Aabb::CreateNull(); - Data::Asset m_materialAsset{ Data::AssetLoadBehavior::PreLoad }; + // Identifies the material that is used by this mesh. + // References material slot in the ModelLodAsset that owns this mesh; see ModelLodAsset::GetMaterialSlot(). + size_t m_materialSlotIndex = 0; // Both the buffer in m_indexBufferAssetView and the buffers in m_streamBufferInfo // may point to either unique buffers for the mesh or to consolidated @@ -143,11 +147,21 @@ namespace AZ //! Returns the model-space axis-aligned bounding box of all meshes in the lod const AZ::Aabb& GetAabb() const; + + //! Returns an array view into the collection of material slots available to this lod + AZStd::array_view GetMaterialSlots() const; + + //! Returns a specific material slot by index, with error checking. + //! The index can be retrieved from Mesh::GetMaterialSlotIndex(). + const ModelMaterialSlot& GetMaterialSlot(size_t slotIndex) const; + + //! Find a material slot with the given stableId, or returns null if it isn't found. + const ModelMaterialSlot* FindMaterialSlot(uint32_t stableId) const; private: AZStd::vector m_meshes; AZ::Aabb m_aabb = AZ::Aabb::CreateNull(); - + // These buffers owned by the lod are the consolidated super buffers. // Meshes may either have views into these buffers or they may own // their own buffers. @@ -155,6 +169,13 @@ namespace AZ Data::Asset m_indexBuffer; AZStd::vector> m_streamBuffers; + // Lists all of the material slots that are used by this LOD. + // Note the same slot can appear in multiple LODs in the model, so that LODs don't have to refer back to the model asset. + AZStd::vector m_materialSlots; + + // A default ModelMaterialSlot to be returned upon error conditions. + ModelMaterialSlot m_fallbackSlot; + void AddMesh(const Mesh& mesh); void SetReady(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h index c3291e5c73..5672b49f68 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include @@ -45,9 +46,10 @@ namespace AZ //! Begin and BeginMesh must be called first. void SetMeshAabb(AZ::Aabb&& aabb); - //! Sets the material asset for the current SubMesh. + //! Sets the material slot data for the current SubMesh. + //! Adds a new material slot to the ModelLodAsset if it doesn't already exist. //! Begin and BeginMesh must be called first - void SetMeshMaterialAsset(const Data::Asset& materialAsset); + void SetMeshMaterialSlot(const ModelMaterialSlot& materialSlot); //! Sets the given BufferAssetView to the current SubMesh as the index buffer. //! Begin and BeginMesh must be called first diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h new file mode 100644 index 0000000000..27137459b7 --- /dev/null +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AZ +{ + class ReflectContext; + + namespace RPI + { + //! Use by model assets to identify a logical material slot. + //! Each slot has a unique ID, a name, and a default material. Each mesh in model will reference a single ModelMaterialSlot. + //! Other classes like MeshFeatureProcessor and MaterialComponent can override the material associated with individual slots + //! to alter the default appearance of the mesh. + struct ModelMaterialSlot + { + AZ_TYPE_INFO(ModelMaterialSlot, "{0E88A62A-D83D-4C1B-8DE7-CE972B8124B5}"); + + static void Reflect(AZ::ReflectContext* context); + + using StableId = uint32_t; + static const StableId InvalidStableId = -1; + + //! This ID must have a consistent value when the asset is reprocessed by the asset pipeline, and must be unique within the ModelLodAsset. + //! In practice, this set using the MaterialUid from SceneAPI. See ModelAssetBuilderComponent::CreateMesh. + StableId m_stableId = InvalidStableId; + + Name m_displayName; //!< The name of the slot as displayed to the user in UI. (Using Name instead of string for fast copies) + + Data::Asset m_defaultMaterialAsset{ Data::AssetLoadBehavior::PreLoad }; //!< The material that will be applied to this slot by default. + }; + + using ModelMaterialSlotMap = AZStd::unordered_map; + + } //namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index aa2ad37647..608ee17d95 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -109,7 +109,7 @@ namespace AZ if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(27); // [ATOM-15658] + ->Version(29); // (updated to separate material slot ID from default material asset) } } @@ -1806,8 +1806,12 @@ namespace AZ auto iter = materialAssetsByUid.find(meshView.m_materialUid); if (iter != materialAssetsByUid.end()) { - const Data::Asset& materialAsset = iter->second.m_asset; - lodAssetCreator.SetMeshMaterialAsset(materialAsset); + ModelMaterialSlot materialSlot; + materialSlot.m_stableId = meshView.m_materialUid; + materialSlot.m_displayName = iter->second.m_name; + materialSlot.m_defaultMaterialAsset = iter->second.m_asset; + + lodAssetCreator.SetMeshMaterialSlot(materialSlot); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp index b68930e4a3..2dfee9e2f1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp @@ -100,10 +100,13 @@ namespace AZ } } - auto& materialAsset = mesh.GetMaterialAsset(); - if (materialAsset.IsReady()) + const ModelMaterialSlot& materialSlot = lodAsset.GetMaterialSlot(mesh.GetMaterialSlotIndex()); + + meshInstance.m_materialSlotStableId = materialSlot.m_stableId; + + if (materialSlot.m_defaultMaterialAsset.IsReady()) { - meshInstance.m_material = Material::FindOrCreate(materialAsset); + meshInstance.m_material = Material::FindOrCreate(materialSlot.m_defaultMaterialAsset); } m_meshes.emplace_back(AZStd::move(meshInstance)); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp index 610f183eb1..b9781843cf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp @@ -24,6 +24,7 @@ namespace AZ { ModelLodAsset::Reflect(context); ModelAsset::Reflect(context); + ModelMaterialSlot::Reflect(context); MorphTargetMetaAsset::Reflect(context); SkinMetaAsset::Reflect(context); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp index 083de10d47..486faafbdb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp @@ -56,6 +56,30 @@ namespace AZ { return m_aabb; } + + RPI::ModelMaterialSlotMap ModelAsset::GetModelMaterialSlots() const + { + RPI::ModelMaterialSlotMap slotMap; + + for (const Data::Asset& lod : GetLodAssets()) + { + for (const AZ::RPI::ModelMaterialSlot& materialSlot : lod->GetMaterialSlots()) + { + auto iter = slotMap.find(materialSlot.m_stableId); + if (iter == slotMap.end()) + { + slotMap.emplace(materialSlot.m_stableId, materialSlot); + } + else + { + AZ_Assert(materialSlot.m_displayName == iter->second.m_displayName && materialSlot.m_defaultMaterialAsset.GetId() == iter->second.m_defaultMaterialAsset.GetId(), + "Multiple LODs have mismatched data for the same material slot."); + } + } + } + + return slotMap; + } size_t ModelAsset::GetLodCount() const { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp index 190e4c5315..4811f6a1db 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp @@ -23,24 +23,25 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("Meshes", &ModelLodAsset::m_meshes) ->Field("Aabb", &ModelLodAsset::m_aabb) + ->Field("MaterialSlots", &ModelLodAsset::m_materialSlots) ; } Mesh::Reflect(context); } - + void ModelLodAsset::Mesh::Reflect(AZ::ReflectContext* context) { if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) - ->Field("Material", &ModelLodAsset::Mesh::m_materialAsset) + ->Version(1) ->Field("Name", &ModelLodAsset::Mesh::m_name) ->Field("AABB", &ModelLodAsset::Mesh::m_aabb) + ->Field("MaterialSlotIndex", &ModelLodAsset::Mesh::m_materialSlotIndex) ->Field("IndexBufferAssetView", &ModelLodAsset::Mesh::m_indexBufferAssetView) ->Field("StreamBufferInfo", &ModelLodAsset::Mesh::m_streamBufferInfo) ; @@ -75,9 +76,9 @@ namespace AZ return m_indexBufferAssetView.GetBufferViewDescriptor().m_elementCount; } - const Data::Asset & ModelLodAsset::Mesh::GetMaterialAsset() const + size_t ModelLodAsset::Mesh::GetMaterialSlotIndex() const { - return m_materialAsset; + return m_materialSlotIndex; } const AZ::Name& ModelLodAsset::Mesh::GetName() const @@ -118,6 +119,41 @@ namespace AZ { return m_aabb; } + + AZStd::array_view ModelLodAsset::GetMaterialSlots() const + { + return m_materialSlots; + } + + const ModelMaterialSlot& ModelLodAsset::GetMaterialSlot(size_t slotIndex) const + { + if (slotIndex < m_materialSlots.size()) + { + return m_materialSlots[slotIndex]; + } + else + { + AZ_Error("ModelAsset", false, "Material slot index %zu out of range. ModelAsset has %zu slots.", slotIndex, m_materialSlots.size()); + return m_fallbackSlot; + } + } + + const ModelMaterialSlot* ModelLodAsset::FindMaterialSlot(uint32_t stableId) const + { + auto iter = AZStd::find_if(m_materialSlots.begin(), m_materialSlots.end(), [&stableId](const ModelMaterialSlot& existingMaterialSlot) + { + return existingMaterialSlot.m_stableId == stableId; + }); + + if (iter == m_materialSlots.end()) + { + return nullptr; + } + else + { + return iter; + } + } const BufferAssetView* ModelLodAsset::Mesh::GetSemanticBufferAssetView(const AZ::Name& semantic) const { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp index 6f17a5c590..5a066d2517 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp @@ -60,12 +60,32 @@ namespace AZ m_currentMesh.m_aabb = AZStd::move(aabb); } } - - void ModelLodAssetCreator::SetMeshMaterialAsset(const Data::Asset& materialAsset) + + void ModelLodAssetCreator::SetMeshMaterialSlot(const ModelMaterialSlot& materialSlot) { - if (ValidateIsMeshReady()) + auto iter = AZStd::find_if(m_asset->m_materialSlots.begin(), m_asset->m_materialSlots.end(), [&materialSlot](const ModelMaterialSlot& existingMaterialSlot) + { + return existingMaterialSlot.m_stableId == materialSlot.m_stableId; + }); + + if (iter == m_asset->m_materialSlots.end()) { - m_currentMesh.m_materialAsset = materialAsset; + m_currentMesh.m_materialSlotIndex = m_asset->m_materialSlots.size(); + m_asset->m_materialSlots.push_back(materialSlot); + } + else + { + if (materialSlot.m_displayName != iter->m_displayName) + { + ReportWarning("Material slot %u was already added with a different name.", materialSlot.m_stableId); + } + + if (materialSlot.m_defaultMaterialAsset != iter->m_defaultMaterialAsset) + { + ReportWarning("Material slot %u was already added with a different MaterialAsset.", materialSlot.m_stableId); + } + + *iter = materialSlot; } } @@ -288,7 +308,9 @@ namespace AZ creator.SetMeshName(sourceMesh.GetName()); AZ::Aabb aabb = sourceMesh.GetAabb(); creator.SetMeshAabb(AZStd::move(aabb)); - creator.SetMeshMaterialAsset(sourceMesh.GetMaterialAsset()); + + const ModelMaterialSlot& materialSlot = sourceAsset->GetMaterialSlot(sourceMesh.GetMaterialSlotIndex()); + creator.SetMeshMaterialSlot(materialSlot); // Mesh index buffer view const BufferAssetView& sourceIndexBufferView = sourceMesh.GetIndexBufferAssetView(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp new file mode 100644 index 0000000000..61f3ebbe3a --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +namespace AZ +{ + namespace RPI + { + void ModelMaterialSlot::Reflect(AZ::ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("StableId", &ModelMaterialSlot::m_stableId) + ->Field("DisplayName", &ModelMaterialSlot::m_displayName) + ->Field("DefaultMaterialAsset", &ModelMaterialSlot::m_defaultMaterialAsset) + ; + } + } + + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake index c049837045..49c7231fed 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_reflect_files.cmake @@ -22,6 +22,7 @@ set(FILES Include/Atom/RPI.Reflect/Model/ModelKdTree.h Include/Atom/RPI.Reflect/Model/ModelLodAsset.h Include/Atom/RPI.Reflect/Model/ModelLodIndex.h + Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h Include/Atom/RPI.Reflect/Model/ModelAssetCreator.h Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h Include/Atom/RPI.Reflect/Model/MorphTargetDelta.h @@ -106,6 +107,7 @@ set(FILES Source/RPI.Reflect/Model/ModelLodAsset.cpp Source/RPI.Reflect/Model/ModelAssetCreator.cpp Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp + Source/RPI.Reflect/Model/ModelMaterialSlot.cpp Source/RPI.Reflect/Model/MorphTargetDelta.cpp Source/RPI.Reflect/Model/MorphTargetMetaAsset.cpp Source/RPI.Reflect/Model/MorphTargetMetaAssetCreator.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h index 134bf6db47..4072684987 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h @@ -69,6 +69,9 @@ namespace AZ : public ComponentBus { public: + //! Returns the list of all ModelMaterialSlot's for the model, across all LODs. + virtual RPI::ModelMaterialSlotMap GetModelMaterialSlots() const = 0; + virtual MaterialAssignmentMap GetMaterialAssignments() const = 0; virtual AZStd::unordered_set GetModelUvNames() const = 0; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index d7dc4335b3..f1767a8b1d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -44,57 +44,8 @@ namespace AZ if (classElement.GetVersion() < 3) { - // The default material was changed from an asset to an EditorMaterialComponentSlot and old data must be converted - constexpr AZ::u32 defaultMaterialAssetDataCrc = AZ_CRC("defaultMaterialAsset", 0x736fc071); - - Data::Asset oldDefaultMaterialData; - if (!classElement.GetChildData(defaultMaterialAssetDataCrc, oldDefaultMaterialData)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to get defaultMaterialAsset element"); - return false; - } - - if (!classElement.RemoveElementByName(defaultMaterialAssetDataCrc)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to remove defaultMaterialAsset element"); - return false; - } - - EditorMaterialComponentSlot newDefaultMaterialData; - newDefaultMaterialData.m_id = DefaultMaterialAssignmentId; - newDefaultMaterialData.m_materialAsset = oldDefaultMaterialData; - classElement.AddElementWithData(context, "defaultMaterialSlot", newDefaultMaterialData); - - // Slots now support and display the default material asset when empty - // The old placeholder assignments are irrelevant and must be cleared - constexpr AZ::u32 materialSlotsByLodDataCrc = AZ_CRC("materialSlotsByLod", 0xb1498db6); - - EditorMaterialComponentSlotsByLodContainer lodSlotData; - if (!classElement.GetChildData(materialSlotsByLodDataCrc, lodSlotData)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to get materialSlotsByLod element"); - return false; - } - - if (!classElement.RemoveElementByName(materialSlotsByLodDataCrc)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to remove materialSlotsByLod element"); - return false; - } - - // Find and clear all slots that are assigned to the slot's default value - for (auto& lodSlots : lodSlotData) - { - for (auto& slot : lodSlots) - { - if (slot.m_materialAsset.GetId() == slot.m_id.m_materialAssetId) - { - slot.m_materialAsset = {}; - } - } - } - - classElement.AddElementWithData(context, "materialSlotsByLod", lodSlotData); + AZ_Error("EditorMaterialComponent", false, "Material Component version < 3 is no longer supported"); + return false; } if (classElement.GetVersion() < 4) @@ -238,7 +189,7 @@ namespace AZ for (auto& materialSlotPair : GetMaterialSlots()) { EditorMaterialComponentSlot* materialSlot = materialSlotPair.second; - if (materialSlot->m_id.IsAssetOnly()) + if (materialSlot->m_id.IsSlotIdOnly()) { materialSlot->Clear(); } @@ -251,7 +202,7 @@ namespace AZ for (auto& materialSlotPair : GetMaterialSlots()) { EditorMaterialComponentSlot* materialSlot = materialSlotPair.second; - if (materialSlot->m_id.IsLodAndAsset()) + if (materialSlot->m_id.IsLodAndSlotId()) { materialSlot->Clear(); } @@ -318,6 +269,9 @@ namespace AZ // Build the controller configuration from the editor configuration MaterialComponentConfig config = m_controller.GetConfiguration(); config.m_materials.clear(); + + RPI::ModelMaterialSlotMap modelMaterialSlots; + MaterialReceiverRequestBus::EventResult(modelMaterialSlots, GetEntityId(), &MaterialReceiverRequestBus::Events::GetModelMaterialSlots); for (const auto& materialSlotPair : GetMaterialSlots()) { @@ -340,10 +294,15 @@ namespace AZ } else if (!materialSlot->m_propertyOverrides.empty() || !materialSlot->m_matModUvOverrides.empty()) { - MaterialAssignment& materialAssignment = config.m_materials[materialSlot->m_id]; - materialAssignment.m_materialAsset.Create(materialSlot->m_id.m_materialAssetId); - materialAssignment.m_propertyOverrides = materialSlot->m_propertyOverrides; - materialAssignment.m_matModUvOverrides = materialSlot->m_matModUvOverrides; + auto materialSlotIter = modelMaterialSlots.find(materialSlot->m_id.m_materialSlotStableId); + + if (materialSlotIter != modelMaterialSlots.end()) + { + MaterialAssignment& materialAssignment = config.m_materials[materialSlot->m_id]; + materialAssignment.m_materialAsset = materialSlotIter->second.m_defaultMaterialAsset; + materialAssignment.m_propertyOverrides = materialSlot->m_propertyOverrides; + materialAssignment.m_matModUvOverrides = materialSlot->m_matModUvOverrides; + } } } @@ -362,6 +321,9 @@ namespace AZ // Get the known material assignment slots from the associated model or other source MaterialAssignmentMap materialsFromSource; MaterialReceiverRequestBus::EventResult(materialsFromSource, GetEntityId(), &MaterialReceiverRequestBus::Events::GetMaterialAssignments); + + RPI::ModelMaterialSlotMap modelMaterialSlots; + MaterialReceiverRequestBus::EventResult(modelMaterialSlots, GetEntityId(), &MaterialReceiverRequestBus::Events::GetModelMaterialSlots); // Generate the table of editable materials using the source data to define number of groups, elements, and initial values for (const auto& materialPair : materialsFromSource) @@ -385,6 +347,29 @@ namespace AZ OnConfigurationChanged(); }; + const char* UnknownSlotName = ""; + + // If this is the default material assignment ID then it represents the default slot which is not contained in any other group + if (slot.m_id == DefaultMaterialAssignmentId) + { + slot.m_label = "Default Material"; + } + else + { + auto slotIter = modelMaterialSlots.find(slot.m_id.m_materialSlotStableId); + if (slotIter != modelMaterialSlots.end()) + { + const Name& displayName = slotIter->second.m_displayName; + slot.m_label = !displayName.IsEmpty() ? displayName.GetStringView() : UnknownSlotName; + + slot.m_defaultMaterialAsset = slotIter->second.m_defaultMaterialAsset; + } + else + { + slot.m_label = UnknownSlotName; + } + } + // if material is present in controller configuration, assign its data const MaterialAssignment& materialFromController = GetMaterialAssignmentFromMap(config.m_materials, slot.m_id); slot.m_materialAsset = materialFromController.m_materialAsset; @@ -400,13 +385,13 @@ namespace AZ continue; } - if (slot.m_id.IsAssetOnly()) + if (slot.m_id.IsSlotIdOnly()) { m_materialSlots.push_back(slot); continue; } - if (slot.m_id.IsLodAndAsset()) + if (slot.m_id.IsLodAndSlotId()) { // Resize the containers to fit all elements m_materialSlotsByLod.resize(AZ::GetMax(m_materialSlotsByLod.size(), aznumeric_cast(slot.m_id.m_lodIndex + 1))); @@ -452,17 +437,19 @@ namespace AZ { AzToolsFramework::ScopedUndoBatch undoBatch("Generating materials."); SetDirty(); + + RPI::ModelMaterialSlotMap modelMaterialSlots; + MaterialReceiverRequestBus::EventResult(modelMaterialSlots, GetEntityId(), &MaterialReceiverRequestBus::Events::GetModelMaterialSlots); // First generating a unique set of all material asset IDs that will be used for source data generation AZStd::unordered_set assetIds; - auto materialSlots = GetMaterialSlots(); - for (auto& materialSlotPair : materialSlots) + for (auto& materialSlot : modelMaterialSlots) { - EditorMaterialComponentSlot* materialSlot = materialSlotPair.second; - if (materialSlot->m_id.m_materialAssetId.IsValid()) + Data::AssetId defaultMaterialAssetId = materialSlot.second.m_defaultMaterialAsset.GetId(); + if (defaultMaterialAssetId.IsValid()) { - assetIds.insert(materialSlot->m_id.m_materialAssetId); + assetIds.insert(defaultMaterialAssetId); } } @@ -472,7 +459,7 @@ namespace AZ for (const AZ::Data::AssetId& assetId : assetIds) { EditorMaterialComponentExporter::ExportItem exportItem; - exportItem.m_assetId = assetId; + exportItem.m_originalAssetId = assetId; exportItems.push_back(exportItem); } @@ -489,12 +476,23 @@ namespace AZ const auto& assetIdOutcome = AZ::RPI::AssetUtils::MakeAssetId(exportItem.m_exportPath, 0); if (assetIdOutcome) { - for (auto& materialSlotPair : materialSlots) + for (auto& materialSlotPair : GetMaterialSlots()) { - EditorMaterialComponentSlot* materialSlot = materialSlotPair.second; - if (materialSlot && materialSlot->m_id.m_materialAssetId == exportItem.m_assetId) + EditorMaterialComponentSlot* editorMaterialSlot = materialSlotPair.second; + + if (editorMaterialSlot) { - materialSlot->m_materialAsset.Create(assetIdOutcome.GetValue()); + // Only update the slot of it was originally empty, having no override material. + // We need to check whether replaced material corresponds to this slot's default material. + if (!editorMaterialSlot->m_materialAsset.GetId().IsValid()) + { + auto materialSlot = modelMaterialSlots.find(editorMaterialSlot->m_id.m_materialSlotStableId); + if (materialSlot != modelMaterialSlots.end() && + materialSlot->second.m_defaultMaterialAsset.GetId() == exportItem.m_originalAssetId) + { + editorMaterialSlot->m_materialAsset.Create(assetIdOutcome.GetValue()); + } + } } } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp index bde500bdc5..1e6b19f616 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp @@ -132,7 +132,7 @@ namespace AZ int row = 0; for (ExportItem& exportItem : exportItems) { - QFileInfo fileInfo(GetExportPathByAssetId(exportItem.m_assetId).c_str()); + QFileInfo fileInfo(GetExportPathByAssetId(exportItem.m_originalAssetId).c_str()); // Configuring initial settings based on whether or not the target file already exists exportItem.m_exportPath = fileInfo.absoluteFilePath().toUtf8().constData(); @@ -147,7 +147,7 @@ namespace AZ // Create a check box for toggling the enabled state of this item QCheckBox* materialSlotCheckBox = new QCheckBox(tableWidget); materialSlotCheckBox->setChecked(exportItem.m_enabled); - materialSlotCheckBox->setText(GetLabelByAssetId(exportItem.m_assetId).c_str()); + materialSlotCheckBox->setText(GetLabelByAssetId(exportItem.m_originalAssetId).c_str()); tableWidget->setCellWidget(row, MaterialSlotColumn, materialSlotCheckBox); // Create a file picker widget for selecting the save path for the exported material @@ -256,7 +256,7 @@ namespace AZ } EditorMaterialComponentUtil::MaterialEditData editData; - if (!EditorMaterialComponentUtil::LoadMaterialEditDataFromAssetId(exportItem.m_assetId, editData)) + if (!EditorMaterialComponentUtil::LoadMaterialEditDataFromAssetId(exportItem.m_originalAssetId, editData)) { AZ_Warning("AZ::Render::EditorMaterialComponentExporter", false, "Failed to load material data."); return false; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h index 00bef9ee66..289bde0c75 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h @@ -19,10 +19,10 @@ namespace AZ { namespace EditorMaterialComponentExporter { - // Attemts to generate a display label for a material slot by parsing its file name + //! Attemts to generate a display label for a material slot by parsing its file name AZStd::string GetLabelByAssetId(const AZ::Data::AssetId& assetId); - // Generates a destination file path for exporting material source data + //! Generates a destination file path for exporting material source data AZStd::string GetExportPathByAssetId(const AZ::Data::AssetId& assetId); struct ExportItem @@ -30,16 +30,17 @@ namespace AZ bool m_enabled = true; bool m_exists = false; bool m_overwrite = false; - AZ::Data::AssetId m_assetId; + AZ::Data::AssetId m_originalAssetId; //!< AssetId of the original built-in material, which will be exported. AZStd::string m_exportPath; }; using ExportItemsContainer = AZStd::vector; - // Generates and opens a dialog for configuring material data export paths and actions + //! Generates and opens a dialog for configuring material data export paths and actions. + //! Note this will not modify the m_originalAssetId field in each ExportItem. bool OpenExportDialog(ExportItemsContainer& exportItems); - // Attemts to construct and save material source data from a product asset + //! Attemts to construct and save material source data from a product asset bool ExportMaterialSourceData(const ExportItem& exportItem); } // namespace EditorMaterialComponentExporter } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index d341bbb290..c8a2024b39 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include -#include +#include #include AZ_POP_DISABLE_WARNING @@ -48,7 +48,7 @@ namespace AZ return false; } - const MaterialAssignmentId newId(oldId.first, oldId.second); + const MaterialAssignmentId newId(oldId.first, oldId.second.m_subId); classElement.AddElementWithData(context, "id", newId); } @@ -83,6 +83,7 @@ namespace AZ ->Version(5, &EditorMaterialComponentSlot::ConvertVersion) ->Field("id", &EditorMaterialComponentSlot::m_id) ->Field("materialAsset", &EditorMaterialComponentSlot::m_materialAsset) + ->Field("defaultMaterialAsset", &EditorMaterialComponentSlot::m_defaultMaterialAsset) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -121,21 +122,12 @@ namespace AZ AZ::Data::AssetId EditorMaterialComponentSlot::GetDefaultAssetId() const { - return m_id.m_materialAssetId; + return m_defaultMaterialAsset.GetId(); } AZStd::string EditorMaterialComponentSlot::GetLabel() const { - // Generate the label for the material slot based on the assignment ID - // If this is the default material assignment ID then it represents the default slot which is not contained in any other group - if (m_id == DefaultMaterialAssignmentId) - { - return "Default Material"; - } - - // Otherwise the label can be generated by parsing the source file name associated with the asset ID - const AZStd::string& label = EditorMaterialComponentExporter::GetLabelByAssetId(m_id.m_materialAssetId); - return !label.empty() ? label : ""; + return m_label; } bool EditorMaterialComponentSlot::HasSourceData() const @@ -183,27 +175,22 @@ namespace AZ OnMaterialChanged(); } - void EditorMaterialComponentSlot::SetDefaultAsset() + void EditorMaterialComponentSlot::ResetToDefaultAsset() { - m_materialAsset = {}; + m_materialAsset = m_defaultMaterialAsset; m_propertyOverrides = {}; m_matModUvOverrides = {}; - if (m_id.m_materialAssetId.IsValid()) - { - // If no material is assigned to this slot, assign the default material from the slot id to edit its properties - m_materialAsset.Create(m_id.m_materialAssetId); - } OnMaterialChanged(); } void EditorMaterialComponentSlot::OpenMaterialExporter() { // Because we are generating a source material from this specific slot there is only one entry - // But we still need to allow the user to reconfigure it using the dialogue + // But we still need to allow the user to reconfigure it using the dialog EditorMaterialComponentExporter::ExportItemsContainer exportItems; { EditorMaterialComponentExporter::ExportItem exportItem; - exportItem.m_assetId = m_id.m_materialAssetId; + exportItem.m_originalAssetId = m_defaultMaterialAsset.GetId(); exportItems.push_back(exportItem); } @@ -275,7 +262,7 @@ namespace AZ QAction* action = nullptr; action = menu.addAction("Generate/Manage Source Material...", [this]() { OpenMaterialExporter(); }); - action->setEnabled(m_id.m_materialAssetId.IsValid()); + action->setEnabled(m_defaultMaterialAsset.GetId().IsValid()); menu.addSeparator(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h index e8b4f46854..79fddf2611 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h @@ -34,7 +34,7 @@ namespace AZ AZStd::string GetLabel() const; bool HasSourceData() const; void OpenMaterialEditor() const; - void SetDefaultAsset(); + void ResetToDefaultAsset(); void Clear(); void ClearOverrides(); void OpenMaterialExporter(); @@ -42,7 +42,9 @@ namespace AZ void OpenUvNameMapInspector(); MaterialAssignmentId m_id; + AZStd::string m_label; Data::Asset m_materialAsset; + Data::Asset m_defaultMaterialAsset; MaterialPropertyOverrideMap m_propertyOverrides; AZStd::function m_materialChangedCallback; AZStd::function m_propertyChangedCallback; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentConfig.cpp index a0adcd3187..f7b7177e29 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentConfig.cpp @@ -44,7 +44,7 @@ namespace AZ for (const auto& oldPair : oldMaterials) { const DeprecatedMaterialAssignmentId& oldId = oldPair.first; - const MaterialAssignmentId newId(oldId.first, oldId.second); + const MaterialAssignmentId newId(oldId.first, oldId.second.m_subId); newMaterials[newId] = oldPair.second; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 29bd9a839b..a2a3022e91 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -251,6 +251,19 @@ namespace AZ m_meshFeatureProcessor->SetTransform(m_meshHandle, m_transformInterface->GetWorldTM(), m_cachedNonUniformScale); } } + + RPI::ModelMaterialSlotMap MeshComponentController::GetModelMaterialSlots() const + { + Data::Asset modelAsset = GetModelAsset(); + if (modelAsset.IsReady()) + { + return modelAsset->GetModelMaterialSlots(); + } + else + { + return {}; + } + } MaterialAssignmentMap MeshComponentController::GetMaterialAssignments() const { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 80b483452f..78c2e0797f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -111,6 +111,7 @@ namespace AZ void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; // MaterialReceiverRequestBus::Handler overrides ... + RPI::ModelMaterialSlotMap GetModelMaterialSlots() const override; MaterialAssignmentMap GetMaterialAssignments() const override; AZStd::unordered_set GetModelUvNames() const override; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp index 3143191135..ae617f910f 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp @@ -96,12 +96,10 @@ namespace AZ skinnedSubMesh.m_vertexCount = aznumeric_cast(subMeshVertexCount); lodVertexCount += aznumeric_cast(subMeshVertexCount); - // The default material id used by a sub-mesh is the guid of the source scene file plus the subId which is a unique material ID from the scene API - AZ::u32 subId = modelMesh.GetMaterialAsset().GetId().m_subId; - AZ::Data::AssetId materialId{ actorAssetId.m_guid, subId }; - + skinnedSubMesh.m_material = lodAsset->GetMaterialSlot(modelMesh.GetMaterialSlotIndex()).m_defaultMaterialAsset; // Queue the material asset - the ModelLod seems to handle delayed material loads - skinnedSubMesh.m_material = Data::AssetManager::Instance().GetAsset(materialId, azrtti_typeid(), skinnedSubMesh.m_material.GetAutoLoadBehavior()); + skinnedSubMesh.m_material.QueueLoad(); + subMeshes.push_back(skinnedSubMesh); } else diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 4c6045d7ce..6697162c18 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -307,6 +307,19 @@ namespace AZ m_meshFeatureProcessor = nullptr; m_skinnedMeshFeatureProcessor = nullptr; } + + RPI::ModelMaterialSlotMap AtomActorInstance::GetModelMaterialSlots() const + { + Data::Asset modelAsset = GetModelAsset(); + if (modelAsset.IsReady()) + { + return modelAsset->GetModelMaterialSlots(); + } + else + { + return {}; + } + } MaterialAssignmentMap AtomActorInstance::GetMaterialAssignments() const { diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h index c854fed3c1..e7a4047012 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h @@ -120,6 +120,7 @@ namespace AZ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MaterialReceiverRequestBus::Handler overrides... + RPI::ModelMaterialSlotMap GetModelMaterialSlots() const override; MaterialAssignmentMap GetMaterialAssignments() const override; AZStd::unordered_set GetModelUvNames() const override; diff --git a/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp b/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp index 3f089a8639..5a9b8191ed 100644 --- a/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp +++ b/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp @@ -116,7 +116,10 @@ namespace WhiteBox // set the default material if (auto materialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(TexturedMaterialPath.data())) { - modelLodCreator.SetMeshMaterialAsset(materialAsset); + AZ::RPI::ModelMaterialSlot materialSlot; + materialSlot.m_stableId = 0; + materialSlot.m_defaultMaterialAsset = materialAsset; + modelLodCreator.SetMeshMaterialSlot(materialSlot); } else { From e3ceaa477e338d553920f8363fed99384dac0335 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Sat, 17 Jul 2021 12:54:40 -0700 Subject: [PATCH 074/157] Added a version converter for MaterialAssignmentId. This allowed me to successfully load the Sponza level in AtomTest. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Feature/Material/MaterialAssignmentId.h | 1 + .../Source/Material/MaterialAssignmentId.cpp | 27 ++++++++++++++++++- .../Material/EditorMaterialComponentSlot.cpp | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h index d9ae8099da..e58a8397db 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h @@ -31,6 +31,7 @@ namespace AZ AZ_RTTI(AZ::Render::MaterialAssignmentId, "{EB603581-4654-4C17-B6DE-AE61E79EDA97}"); AZ_CLASS_ALLOCATOR(AZ::Render::MaterialAssignmentId, SystemAllocator, 0); static void Reflect(ReflectContext* context); + static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); MaterialAssignmentId() = default; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp index 8b6b0be237..5db6c4c15c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp @@ -14,12 +14,37 @@ namespace AZ { namespace Render { + bool MaterialAssignmentId::ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) + { + if (classElement.GetVersion() < 2) + { + constexpr AZ::u32 materialAssetIdCrc = AZ_CRC("materialAssetId"); + + AZ::Data::AssetId materialAssetId; + if (!classElement.GetChildData(materialAssetIdCrc, materialAssetId)) + { + AZ_Error("AZ::Render::MaterialAssignmentId::ConvertVersion", false, "Failed to get AssetId element"); + return false; + } + + if (!classElement.RemoveElementByName(materialAssetIdCrc)) + { + AZ_Error("AZ::Render::MaterialAssignmentId::ConvertVersion", false, "Failed to remove deprecated element materialAssetId"); + // No need to early-return, the object will still load successfully, it will just report more errors about the unrecognized element. + } + + classElement.AddElementWithData(context, "materialSlotStableId", materialAssetId.m_subId); + } + + return true; + } + void MaterialAssignmentId::Reflect(ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(2) + ->Version(2, &MaterialAssignmentId::ConvertVersion) ->Field("lodIndex", &MaterialAssignmentId::m_lodIndex) ->Field("materialSlotStableId", &MaterialAssignmentId::m_materialSlotStableId) ; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index c8a2024b39..0a32f9b125 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -80,7 +80,7 @@ namespace AZ if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(5, &EditorMaterialComponentSlot::ConvertVersion) + ->Version(6, &EditorMaterialComponentSlot::ConvertVersion) ->Field("id", &EditorMaterialComponentSlot::m_id) ->Field("materialAsset", &EditorMaterialComponentSlot::m_materialAsset) ->Field("defaultMaterialAsset", &EditorMaterialComponentSlot::m_defaultMaterialAsset) From 670dd6c5bc2031881f25737488075d6616cf3544 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Sat, 17 Jul 2021 18:18:28 -0700 Subject: [PATCH 075/157] Removed the GetLabelByAssetId function since now we can use the display name that comes with the ModelMaterialSlot. Updated OpenMaterialExporter() to account for the fact that multiple material slots can have the same default material asset. Updated the material inspector to sort material slots by name to match the order in the Material Component. Updated ExportItem to protect its data members, which makes it more clear that assetId and materialSlotName are readonly inputs. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/EditorMaterialComponent.cpp | 53 +++++++---- .../EditorMaterialComponentExporter.cpp | 90 ++++++------------- .../EditorMaterialComponentExporter.h | 32 +++++-- .../Material/EditorMaterialComponentSlot.cpp | 5 +- 4 files changed, 88 insertions(+), 92 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index f1767a8b1d..16a657a64f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -17,6 +17,7 @@ #include #include #include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include @@ -438,30 +439,46 @@ namespace AZ AzToolsFramework::ScopedUndoBatch undoBatch("Generating materials."); SetDirty(); + Data::AssetId modelAssetId; + MeshComponentRequestBus::EventResult(modelAssetId, GetEntityId(), &MeshComponentRequestBus::Events::GetModelAssetId); + RPI::ModelMaterialSlotMap modelMaterialSlots; MaterialReceiverRequestBus::EventResult(modelMaterialSlots, GetEntityId(), &MaterialReceiverRequestBus::Events::GetModelMaterialSlots); + + EditorMaterialComponentExporter::ExportItemsContainer exportItems; - // First generating a unique set of all material asset IDs that will be used for source data generation - AZStd::unordered_set assetIds; - - for (auto& materialSlot : modelMaterialSlots) + // Generate a list of export items for the set of unique default material assets from the model. + for (auto& materialSlotPair : modelMaterialSlots) { - Data::AssetId defaultMaterialAssetId = materialSlot.second.m_defaultMaterialAsset.GetId(); - if (defaultMaterialAssetId.IsValid()) + // We only care about material assets that were generated from the model source file, since those are the + // ones that would need conversion (other materials already have their own source file). This can be detected + // by matching GUID component of the AssetId. + Data::AssetId defaultMaterialAssetId = materialSlotPair.second.m_defaultMaterialAsset.GetId(); + bool materialWasGeneratedFromModel = defaultMaterialAssetId.IsValid() && defaultMaterialAssetId.m_guid == modelAssetId.m_guid; + if (materialWasGeneratedFromModel) { - assetIds.insert(defaultMaterialAssetId); + auto duplicateAssetIter = AZStd::find_if(exportItems.begin(), exportItems.end(), + [defaultMaterialAssetId](const EditorMaterialComponentExporter::ExportItem& existingExportItem) + { + return existingExportItem.GetOriginalAssetId() == defaultMaterialAssetId; + }); + + // It's possible for multiple material slots to have the same default material asset. So we just use the first one, which just means the + // exported material file name will be based on the first relevant material slot's name. + if (duplicateAssetIter == exportItems.end()) + { + EditorMaterialComponentExporter::ExportItem exportItem{defaultMaterialAssetId, materialSlotPair.second.m_displayName.GetStringView()}; + exportItems.push_back(exportItem); + } } } - // Convert the unique set of asset IDs into export items that can be configured in the dialog - // The order should not matter because the table in the dialog can sort itself for a specific row - EditorMaterialComponentExporter::ExportItemsContainer exportItems; - for (const AZ::Data::AssetId& assetId : assetIds) - { - EditorMaterialComponentExporter::ExportItem exportItem; - exportItem.m_originalAssetId = assetId; - exportItems.push_back(exportItem); - } + // Sort by display name so the list order will match what's displayed in the Material Component. + AZStd::sort(exportItems.begin(), exportItems.end(), + [](const EditorMaterialComponentExporter::ExportItem& a, const EditorMaterialComponentExporter::ExportItem& b) + { + return a.GetMaterialSlotName() < b.GetMaterialSlotName(); + }); // Display the export dialog so that the user can configure how they want different materials to be exported if (EditorMaterialComponentExporter::OpenExportDialog(exportItems)) @@ -473,7 +490,7 @@ namespace AZ continue; } - const auto& assetIdOutcome = AZ::RPI::AssetUtils::MakeAssetId(exportItem.m_exportPath, 0); + const auto& assetIdOutcome = AZ::RPI::AssetUtils::MakeAssetId(exportItem.GetExportPath(), 0); if (assetIdOutcome) { for (auto& materialSlotPair : GetMaterialSlots()) @@ -488,7 +505,7 @@ namespace AZ { auto materialSlot = modelMaterialSlots.find(editorMaterialSlot->m_id.m_materialSlotStableId); if (materialSlot != modelMaterialSlots.end() && - materialSlot->second.m_defaultMaterialAsset.GetId() == exportItem.m_originalAssetId) + materialSlot->second.m_defaultMaterialAsset.GetId() == exportItem.GetOriginalAssetId()) { editorMaterialSlot->m_materialAsset.Create(assetIdOutcome.GetValue()); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp index 1e6b19f616..32a36392a4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.cpp @@ -37,47 +37,7 @@ namespace AZ { namespace EditorMaterialComponentExporter { - AZStd::string GetLabelByAssetId(const AZ::Data::AssetId& assetId) - { - AZStd::string label; - if (assetId.IsValid()) - { - // Material assets that are exported through the scene pipeline have their filenames generated by adding - // the DCC material name as a prefix and a unique number to the end of the source file name. - // Rather than storing the DCC material name inside of the material asset we can reproduce it by removing - // the prefix and suffix from the product file name. - - // We need the material product path as the initial string that will be stripped down - const AZStd::string& productPath = AZ::RPI::AssetUtils::GetProductPathByAssetId(assetId); - if (!productPath.empty() && AzFramework::StringFunc::Path::GetFileName(productPath.c_str(), label)) - { - // If there is a source file, typically an FBX or other model file, we must get its filename to remove the prefix from the label - AZStd::string prefix; - const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(assetId); - if (!sourcePath.empty() && AZ::StringFunc::Path::GetFileName(sourcePath.c_str(), prefix)) - { - if (!prefix.empty() && prefix.size() < label.size()) - { - if (AZ::StringFunc::StartsWith(label, prefix, false)) - { - // All of the product filename's tokens are separated by underscores so we must also remove the first underscore after the prefix - label = label.substr(prefix.size() + 1); - } - } - } - - // We can remove the numeric suffix by stripping the label of everything after the last underscore - const auto iter = label.find_last_of("_"); - if (iter != AZStd::string::npos) - { - label = label.substr(0, iter); - } - } - } - return label; - } - - AZStd::string GetExportPathByAssetId(const AZ::Data::AssetId& assetId) + AZStd::string GetExportPathByAssetId(const AZ::Data::AssetId& assetId, const AZStd::string& materialSlotName) { AZStd::string exportPath; if (assetId.IsValid()) @@ -85,7 +45,7 @@ namespace AZ exportPath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(assetId); AZ::StringFunc::Path::StripExtension(exportPath); exportPath += "_"; - exportPath += GetLabelByAssetId(assetId); + exportPath += materialSlotName; exportPath += "."; exportPath += AZ::RPI::MaterialSourceData::Extension; AZ::StringFunc::Path::Normalize(exportPath); @@ -132,12 +92,12 @@ namespace AZ int row = 0; for (ExportItem& exportItem : exportItems) { - QFileInfo fileInfo(GetExportPathByAssetId(exportItem.m_originalAssetId).c_str()); + QFileInfo fileInfo(GetExportPathByAssetId(exportItem.GetOriginalAssetId(), exportItem.GetMaterialSlotName()).c_str()); // Configuring initial settings based on whether or not the target file already exists - exportItem.m_exportPath = fileInfo.absoluteFilePath().toUtf8().constData(); - exportItem.m_exists = fileInfo.exists(); - exportItem.m_overwrite = false; + exportItem.SetExportPath(fileInfo.absoluteFilePath().toUtf8().constData()); + exportItem.SetExists(fileInfo.exists()); + exportItem.SetOverwrite(false); // Populate the table with data for every column tableWidget->setItem(row, MaterialSlotColumn, new QTableWidgetItem()); @@ -146,23 +106,23 @@ namespace AZ // Create a check box for toggling the enabled state of this item QCheckBox* materialSlotCheckBox = new QCheckBox(tableWidget); - materialSlotCheckBox->setChecked(exportItem.m_enabled); - materialSlotCheckBox->setText(GetLabelByAssetId(exportItem.m_originalAssetId).c_str()); + materialSlotCheckBox->setChecked(exportItem.GetEnabled()); + materialSlotCheckBox->setText(exportItem.GetMaterialSlotName().c_str()); tableWidget->setCellWidget(row, MaterialSlotColumn, materialSlotCheckBox); // Create a file picker widget for selecting the save path for the exported material AzQtComponents::BrowseEdit* materialFileWidget = new AzQtComponents::BrowseEdit(tableWidget); materialFileWidget->setLineEditReadOnly(true); materialFileWidget->setClearButtonEnabled(false); - materialFileWidget->setEnabled(exportItem.m_enabled); + materialFileWidget->setEnabled(exportItem.GetEnabled()); materialFileWidget->setText(fileInfo.fileName()); tableWidget->setCellWidget(row, MaterialFileColumn, materialFileWidget); // Create a check box for toggling the overwrite state of this item QWidget* overwriteCheckBoxContainer = new QWidget(tableWidget); QCheckBox* overwriteCheckBox = new QCheckBox(overwriteCheckBoxContainer); - overwriteCheckBox->setChecked(exportItem.m_overwrite); - overwriteCheckBox->setEnabled(exportItem.m_enabled && exportItem.m_exists); + overwriteCheckBox->setChecked(exportItem.GetOverwrite()); + overwriteCheckBox->setEnabled(exportItem.GetEnabled() && exportItem.GetExists()); overwriteCheckBoxContainer->setLayout(new QHBoxLayout(overwriteCheckBoxContainer)); overwriteCheckBoxContainer->layout()->addWidget(overwriteCheckBox); @@ -173,21 +133,21 @@ namespace AZ // Whenever the selection is updated, automatically apply the change to the export item QObject::connect(materialSlotCheckBox, &QCheckBox::stateChanged, materialSlotCheckBox, [&exportItem, materialFileWidget, materialSlotCheckBox, overwriteCheckBox]([[maybe_unused]] int state) { - exportItem.m_enabled = materialSlotCheckBox->isChecked(); - materialFileWidget->setEnabled(exportItem.m_enabled); - overwriteCheckBox->setEnabled(exportItem.m_enabled && exportItem.m_exists); + exportItem.SetEnabled(materialSlotCheckBox->isChecked()); + materialFileWidget->setEnabled(exportItem.GetEnabled()); + overwriteCheckBox->setEnabled(exportItem.GetEnabled() && exportItem.GetExists()); }); // Whenever the overwrite check box is updated, automatically apply the change to the export item QObject::connect(overwriteCheckBox, &QCheckBox::stateChanged, overwriteCheckBox, [&exportItem, overwriteCheckBox]([[maybe_unused]] int state) { - exportItem.m_overwrite = overwriteCheckBox->isChecked(); + exportItem.SetOverwrite(overwriteCheckBox->isChecked()); }); // Whenever the browse button is clicked, open a save file dialog in the same location as the current export file setting QObject::connect(materialFileWidget, &AzQtComponents::BrowseEdit::attachedButtonTriggered, materialFileWidget, [&dialog, &exportItem, materialFileWidget, overwriteCheckBox]() { QFileInfo fileInfo = QFileDialog::getSaveFileName(&dialog, QString("Select Material Filename"), - exportItem.m_exportPath.c_str(), + exportItem.GetExportPath().c_str(), QString("Material (*.material)"), nullptr, QFileDialog::DontConfirmOverwrite); @@ -195,14 +155,14 @@ namespace AZ // Only update the export data if a valid path and filename was selected if (!fileInfo.absoluteFilePath().isEmpty()) { - exportItem.m_exportPath = fileInfo.absoluteFilePath().toUtf8().constData(); - exportItem.m_exists = fileInfo.exists(); - exportItem.m_overwrite = fileInfo.exists(); + exportItem.SetExportPath(fileInfo.absoluteFilePath().toUtf8().constData()); + exportItem.SetExists(fileInfo.exists()); + exportItem.SetOverwrite(fileInfo.exists()); // Update the controls to display the new state materialFileWidget->setText(fileInfo.fileName()); - overwriteCheckBox->setChecked(exportItem.m_overwrite); - overwriteCheckBox->setEnabled(exportItem.m_enabled && exportItem.m_exists); + overwriteCheckBox->setChecked(exportItem.GetOverwrite()); + overwriteCheckBox->setEnabled(exportItem.GetEnabled() && exportItem.GetExists()); } }); @@ -245,24 +205,24 @@ namespace AZ bool ExportMaterialSourceData(const ExportItem& exportItem) { - if (!exportItem.m_enabled || exportItem.m_exportPath.empty()) + if (!exportItem.GetEnabled() || exportItem.GetExportPath().empty()) { return false; } - if (exportItem.m_exists && !exportItem.m_overwrite) + if (exportItem.GetExists() && !exportItem.GetOverwrite()) { return true; } EditorMaterialComponentUtil::MaterialEditData editData; - if (!EditorMaterialComponentUtil::LoadMaterialEditDataFromAssetId(exportItem.m_originalAssetId, editData)) + if (!EditorMaterialComponentUtil::LoadMaterialEditDataFromAssetId(exportItem.GetOriginalAssetId(), editData)) { AZ_Warning("AZ::Render::EditorMaterialComponentExporter", false, "Failed to load material data."); return false; } - if (!EditorMaterialComponentUtil::SaveSourceMaterialFromEditData(exportItem.m_exportPath, editData)) + if (!EditorMaterialComponentUtil::SaveSourceMaterialFromEditData(exportItem.GetExportPath(), editData)) { AZ_Warning("AZ::Render::EditorMaterialComponentExporter", false, "Failed to save material data."); return false; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h index 289bde0c75..4830db33c4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentExporter.h @@ -19,19 +19,39 @@ namespace AZ { namespace EditorMaterialComponentExporter { - //! Attemts to generate a display label for a material slot by parsing its file name - AZStd::string GetLabelByAssetId(const AZ::Data::AssetId& assetId); - //! Generates a destination file path for exporting material source data - AZStd::string GetExportPathByAssetId(const AZ::Data::AssetId& assetId); + AZStd::string GetExportPathByAssetId(const AZ::Data::AssetId& assetId, const AZStd::string& materialSlotName); - struct ExportItem + class ExportItem { + public: + //! @param originalAssetId AssetId of the original built-in material, which will be exported. + //! @param materialSlotName The name of the material slot will be used as part of the exported file name. + ExportItem(AZ::Data::AssetId originalAssetId, const AZStd::string& materialSlotName) + : m_originalAssetId(originalAssetId) + , m_materialSlotName(materialSlotName) + {} + + void SetEnabled(bool enabled) { m_enabled = enabled; } + void SetExists(bool exists) { m_exists = exists; } + void SetOverwrite(bool overwrite) { m_overwrite = overwrite; } + void SetExportPath(const AZStd::string& exportPath) { m_exportPath = exportPath; } + + bool GetEnabled() const { return m_enabled; } + bool GetExists() const { return m_exists; } + bool GetOverwrite() const { return m_overwrite; } + const AZStd::string& GetExportPath() const { return m_exportPath; } + + AZ::Data::AssetId GetOriginalAssetId() const { return m_originalAssetId; } + const AZStd::string& GetMaterialSlotName() const { return m_materialSlotName; } + + private: bool m_enabled = true; bool m_exists = false; bool m_overwrite = false; - AZ::Data::AssetId m_originalAssetId; //!< AssetId of the original built-in material, which will be exported. AZStd::string m_exportPath; + AZ::Data::AssetId m_originalAssetId; //!< AssetId of the original built-in material, which will be exported. + AZStd::string m_materialSlotName; }; using ExportItemsContainer = AZStd::vector; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 0a32f9b125..717b87feec 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -189,8 +189,7 @@ namespace AZ // But we still need to allow the user to reconfigure it using the dialog EditorMaterialComponentExporter::ExportItemsContainer exportItems; { - EditorMaterialComponentExporter::ExportItem exportItem; - exportItem.m_originalAssetId = m_defaultMaterialAsset.GetId(); + EditorMaterialComponentExporter::ExportItem exportItem{m_defaultMaterialAsset.GetId(), m_label}; exportItems.push_back(exportItem); } @@ -205,7 +204,7 @@ namespace AZ } // Generate a new asset ID utilizing the export file path so that we can update this material slot to reference the new asset - const auto& assetIdOutcome = AZ::RPI::AssetUtils::MakeAssetId(exportItem.m_exportPath, 0); + const auto& assetIdOutcome = AZ::RPI::AssetUtils::MakeAssetId(exportItem.GetExportPath(), 0); if (assetIdOutcome) { m_materialAsset.Create(assetIdOutcome.GetValue()); From e145ce1d01334ddea612077150138f893ea41dd7 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Sat, 17 Jul 2021 18:46:04 -0700 Subject: [PATCH 076/157] Updated EditorMaterialComponentSlot to support editing property overrides and UV overrides for the material, regardless of whether there is a material override or not. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/EditorMaterialComponentSlot.cpp | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 717b87feec..f9243510cf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -227,9 +227,11 @@ namespace AZ OnPropertyChanged(); }; - if (m_materialAsset.GetId().IsValid()) + Data::Asset assetToEdit = m_materialAsset.GetId().IsValid() ? m_materialAsset : m_defaultMaterialAsset; + + if (assetToEdit.GetId().IsValid()) { - if (EditorMaterialComponentInspector::OpenInspectorDialog(GetLabel(), m_materialAsset.GetId(), m_propertyOverrides, applyPropertyChangedCallback)) + if (EditorMaterialComponentInspector::OpenInspectorDialog(GetLabel(), assetToEdit.GetId(), m_propertyOverrides, applyPropertyChangedCallback)) { OnMaterialChanged(); } @@ -244,10 +246,12 @@ namespace AZ // Treated as a special property. It will be updated together with properties. OnPropertyChanged(); }; - - if (m_materialAsset.GetId().IsValid()) + + Data::Asset assetToEdit = m_materialAsset.GetId().IsValid() ? m_materialAsset : m_defaultMaterialAsset; + + if (assetToEdit.GetId().IsValid()) { - if (EditorMaterialComponentInspector::OpenInspectorDialog(m_materialAsset.GetId(), m_matModUvOverrides, m_modelUvNames, applyMatModUvOverrideChangedCallback)) + if (EditorMaterialComponentInspector::OpenInspectorDialog(assetToEdit.GetId(), m_matModUvOverrides, m_modelUvNames, applyMatModUvOverrideChangedCallback)) { OnMaterialChanged(); } @@ -268,11 +272,13 @@ namespace AZ action = menu.addAction("Edit Source Material...", [this]() { OpenMaterialEditor(); }); action->setEnabled(HasSourceData()); + bool hasAnyMaterial = m_defaultMaterialAsset.GetId().IsValid() || m_materialAsset.GetId().IsValid(); + action = menu.addAction("Edit Material Instance...", [this]() { OpenMaterialInspector(); }); - action->setEnabled(m_materialAsset.GetId().IsValid()); + action->setEnabled(hasAnyMaterial); action = menu.addAction("Edit Material Instance UV Map...", [this]() { OpenUvNameMapInspector(); }); - action->setEnabled(m_materialAsset.GetId().IsValid()); + action->setEnabled(hasAnyMaterial); menu.addSeparator(); From 28671c8546179ffe0686f658fc6ef8095a5e4a76 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Mon, 19 Jul 2021 23:40:18 -0700 Subject: [PATCH 077/157] Addressed suggestions from gadams3 to make EditorMaterialComponent get the default material assets from its own data rather than fetching them from the asset. Presumably this should give more reliable behavior. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/EditorMaterialComponent.cpp | 37 +++++-------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 16a657a64f..866b2dec56 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -271,9 +271,6 @@ namespace AZ MaterialComponentConfig config = m_controller.GetConfiguration(); config.m_materials.clear(); - RPI::ModelMaterialSlotMap modelMaterialSlots; - MaterialReceiverRequestBus::EventResult(modelMaterialSlots, GetEntityId(), &MaterialReceiverRequestBus::Events::GetModelMaterialSlots); - for (const auto& materialSlotPair : GetMaterialSlots()) { const EditorMaterialComponentSlot* materialSlot = materialSlotPair.second; @@ -295,15 +292,10 @@ namespace AZ } else if (!materialSlot->m_propertyOverrides.empty() || !materialSlot->m_matModUvOverrides.empty()) { - auto materialSlotIter = modelMaterialSlots.find(materialSlot->m_id.m_materialSlotStableId); - - if (materialSlotIter != modelMaterialSlots.end()) - { - MaterialAssignment& materialAssignment = config.m_materials[materialSlot->m_id]; - materialAssignment.m_materialAsset = materialSlotIter->second.m_defaultMaterialAsset; - materialAssignment.m_propertyOverrides = materialSlot->m_propertyOverrides; - materialAssignment.m_matModUvOverrides = materialSlot->m_matModUvOverrides; - } + MaterialAssignment& materialAssignment = config.m_materials[materialSlot->m_id]; + materialAssignment.m_materialAsset = materialSlot->m_defaultMaterialAsset; + materialAssignment.m_propertyOverrides = materialSlot->m_propertyOverrides; + materialAssignment.m_matModUvOverrides = materialSlot->m_matModUvOverrides; } } @@ -442,18 +434,15 @@ namespace AZ Data::AssetId modelAssetId; MeshComponentRequestBus::EventResult(modelAssetId, GetEntityId(), &MeshComponentRequestBus::Events::GetModelAssetId); - RPI::ModelMaterialSlotMap modelMaterialSlots; - MaterialReceiverRequestBus::EventResult(modelMaterialSlots, GetEntityId(), &MaterialReceiverRequestBus::Events::GetModelMaterialSlots); - EditorMaterialComponentExporter::ExportItemsContainer exportItems; // Generate a list of export items for the set of unique default material assets from the model. - for (auto& materialSlotPair : modelMaterialSlots) + for (auto& materialSlotPair : GetMaterialSlots()) { // We only care about material assets that were generated from the model source file, since those are the // ones that would need conversion (other materials already have their own source file). This can be detected // by matching GUID component of the AssetId. - Data::AssetId defaultMaterialAssetId = materialSlotPair.second.m_defaultMaterialAsset.GetId(); + Data::AssetId defaultMaterialAssetId = materialSlotPair.second->m_defaultMaterialAsset.GetId(); bool materialWasGeneratedFromModel = defaultMaterialAssetId.IsValid() && defaultMaterialAssetId.m_guid == modelAssetId.m_guid; if (materialWasGeneratedFromModel) { @@ -467,7 +456,7 @@ namespace AZ // exported material file name will be based on the first relevant material slot's name. if (duplicateAssetIter == exportItems.end()) { - EditorMaterialComponentExporter::ExportItem exportItem{defaultMaterialAssetId, materialSlotPair.second.m_displayName.GetStringView()}; + EditorMaterialComponentExporter::ExportItem exportItem{defaultMaterialAssetId, materialSlotPair.second->GetLabel()}; exportItems.push_back(exportItem); } } @@ -499,16 +488,10 @@ namespace AZ if (editorMaterialSlot) { - // Only update the slot of it was originally empty, having no override material. - // We need to check whether replaced material corresponds to this slot's default material. - if (!editorMaterialSlot->m_materialAsset.GetId().IsValid()) + if (!editorMaterialSlot->m_materialAsset.GetId().IsValid() && //< Only update the slot of it was originally empty, having no override material. + editorMaterialSlot->m_defaultMaterialAsset.GetId() == exportItem.GetOriginalAssetId()) //< We need to check whether replaced material corresponds to this slot's default material. { - auto materialSlot = modelMaterialSlots.find(editorMaterialSlot->m_id.m_materialSlotStableId); - if (materialSlot != modelMaterialSlots.end() && - materialSlot->second.m_defaultMaterialAsset.GetId() == exportItem.GetOriginalAssetId()) - { - editorMaterialSlot->m_materialAsset.Create(assetIdOutcome.GetValue()); - } + editorMaterialSlot->m_materialAsset.Create(assetIdOutcome.GetValue()); } } } From 3daf3f7d7ae71d5d98ba6ce0fe7cc4be28e542e8 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Tue, 20 Jul 2021 12:16:12 -0700 Subject: [PATCH 078/157] Fixed an issue with Actors where the material slot IDs were incorrect, and caused the displayed slot labels to be all "" (and likely other issues). Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Feature/SkinnedMesh/SkinnedMeshInputBuffers.h | 2 +- .../Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp | 7 +------ .../EMotionFXAtom/Code/Source/ActorAsset.cpp | 5 +++-- .../EMotionFXAtom/Code/Source/AtomActorInstance.cpp | 12 +++++++----- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshInputBuffers.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshInputBuffers.h index 5d333e070e..c52bed8cf2 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshInputBuffers.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/SkinnedMesh/SkinnedMeshInputBuffers.h @@ -45,7 +45,7 @@ namespace AZ uint32_t m_vertexOffset = 0; uint32_t m_vertexCount = 0; Aabb m_aabb = Aabb::CreateNull(); - Data::Asset m_material; + AZ::RPI::ModelMaterialSlot m_materialSlot; }; //! Buffer views for a specific sub-mesh that are not modified during skinning and thus are shared by all instances of the same skinned mesh diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp index 640e30d0f6..afd215b4bc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp @@ -640,12 +640,7 @@ namespace AZ Aabb localAabb = lod.m_subMeshProperties[i].m_aabb; modelLodCreator.SetMeshAabb(AZStd::move(localAabb)); - // Create a separate material slot for each sub-mesh - AZ::RPI::ModelMaterialSlot materialSlot; - materialSlot.m_stableId = i; - materialSlot.m_defaultMaterialAsset = lod.m_subMeshProperties[i].m_material; - - modelLodCreator.SetMeshMaterialSlot(materialSlot); + modelLodCreator.SetMeshMaterialSlot(lod.m_subMeshProperties[i].m_materialSlot); modelLodCreator.EndMesh(); } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp index ae617f910f..415f0d1ce3 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp @@ -96,9 +96,10 @@ namespace AZ skinnedSubMesh.m_vertexCount = aznumeric_cast(subMeshVertexCount); lodVertexCount += aznumeric_cast(subMeshVertexCount); - skinnedSubMesh.m_material = lodAsset->GetMaterialSlot(modelMesh.GetMaterialSlotIndex()).m_defaultMaterialAsset; + skinnedSubMesh.m_materialSlot = lodAsset->GetMaterialSlot(modelMesh.GetMaterialSlotIndex()); + // Queue the material asset - the ModelLod seems to handle delayed material loads - skinnedSubMesh.m_material.QueueLoad(); + skinnedSubMesh.m_materialSlot.m_defaultMaterialAsset.QueueLoad(); subMeshes.push_back(skinnedSubMesh); } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 6697162c18..f77e8d6bbd 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -503,16 +503,18 @@ namespace AZ const AZStd::vector< SkinnedSubMeshProperties>& subMeshProperties = inputLod.GetSubMeshProperties(); for (const SkinnedSubMeshProperties& submesh : subMeshProperties) { - AZ_Error("AtomActorInstance", submesh.m_material, "Actor does not have a valid default material in lod %d", lodIndex); - if (submesh.m_material) + Data::Asset materialAsset = submesh.m_materialSlot.m_defaultMaterialAsset; + AZ_Error("AtomActorInstance", materialAsset, "Actor does not have a valid default material in lod %d", lodIndex); + + if (materialAsset) { - if (!submesh.m_material->IsReady()) + if (!materialAsset->IsReady()) { // Start listening for the material's OnAssetReady event. // AtomActorInstance::Create is called on the main thread, so there should be no need to synchronize with the OnAssetReady event handler // since those events will also come from the main thread - m_waitForMaterialLoadIds.insert(submesh.m_material->GetId()); - Data::AssetBus::MultiHandler::BusConnect(submesh.m_material->GetId()); + m_waitForMaterialLoadIds.insert(materialAsset->GetId()); + Data::AssetBus::MultiHandler::BusConnect(materialAsset->GetId()); } } } From a71ee7eb3a3c2e3b2f4d9defa80505eb6196ed4c Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Tue, 20 Jul 2021 13:43:24 -0700 Subject: [PATCH 079/157] Fixed the MaterialAssignmentId version converter to properly handle the default material assignment slot. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Common/Code/Source/Material/MaterialAssignmentId.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp index 5db6c4c15c..b8a03af6d1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp @@ -33,7 +33,14 @@ namespace AZ // No need to early-return, the object will still load successfully, it will just report more errors about the unrecognized element. } - classElement.AddElementWithData(context, "materialSlotStableId", materialAssetId.m_subId); + if (materialAssetId.IsValid()) + { + classElement.AddElementWithData(context, "materialSlotStableId", materialAssetId.m_subId); + } + else + { + classElement.AddElementWithData(context, "materialSlotStableId", RPI::ModelMaterialSlot::InvalidStableId); + } } return true; From fec79a7d53a0753dbd3d68a403ee9ea98a4ab172 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Tue, 20 Jul 2021 16:23:56 -0700 Subject: [PATCH 080/157] Moved the material slot list from ModelLodAsset to ModelAsset, so all the slots live in one main list. This removes data duplication between LODs and cleans up the code a bit. I had to update the ModelLod class to take in both the ModelLodAsset and ModelAsset for initialization so it can fetch the slots for each mesh. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../SkinnedMesh/SkinnedMeshInputBuffers.cpp | 5 ++- .../Include/Atom/RPI.Public/Model/Model.h | 4 +- .../Include/Atom/RPI.Public/Model/ModelLod.h | 7 +-- .../Atom/RPI.Reflect/Model/ModelAsset.h | 12 ++++- .../RPI.Reflect/Model/ModelAssetCreator.h | 4 ++ .../Atom/RPI.Reflect/Model/ModelLodAsset.h | 29 +++--------- .../RPI.Reflect/Model/ModelLodAssetCreator.h | 5 +-- .../Model/MaterialAssetBuilderComponent.cpp | 2 +- .../Model/ModelAssetBuilderComponent.cpp | 13 +++--- .../Model/ModelAssetBuilderComponent.h | 1 + .../Code/Source/RPI.Public/Model/Model.cpp | 12 ++--- .../Code/Source/RPI.Public/Model/ModelLod.cpp | 20 ++++++--- .../Source/RPI.Public/Model/ModelSystem.cpp | 6 +-- .../Source/RPI.Reflect/Model/ModelAsset.cpp | 36 +++++++-------- .../RPI.Reflect/Model/ModelAssetCreator.cpp | 27 ++++++++++++ .../RPI.Reflect/Model/ModelLodAsset.cpp | 44 ++----------------- .../Model/ModelLodAssetCreator.cpp | 29 +++--------- .../Source/Mesh/MeshComponentController.cpp | 2 +- .../EMotionFXAtom/Code/Source/ActorAsset.cpp | 2 +- .../Code/Source/AtomActorInstance.cpp | 2 +- .../Rendering/Atom/WhiteBoxAtomRenderMesh.cpp | 30 +++++++------ .../Rendering/Atom/WhiteBoxAtomRenderMesh.h | 1 + 22 files changed, 135 insertions(+), 158 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp index afd215b4bc..de2c52d1c8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp @@ -639,8 +639,9 @@ namespace AZ Aabb localAabb = lod.m_subMeshProperties[i].m_aabb; modelLodCreator.SetMeshAabb(AZStd::move(localAabb)); - - modelLodCreator.SetMeshMaterialSlot(lod.m_subMeshProperties[i].m_materialSlot); + + modelCreator.AddMaterialSlot(lod.m_subMeshProperties[i].m_materialSlot); + modelLodCreator.SetMeshMaterialSlot(lod.m_subMeshProperties[i].m_materialSlot.m_stableId); modelLodCreator.EndMesh(); } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h index 32880a221c..a19c985f2d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h @@ -90,8 +90,8 @@ namespace AZ private: Model() = default; - static Data::Instance CreateInternal(ModelAsset& modelAsset); - RHI::ResultCode Init(ModelAsset& modelAsset); + static Data::Instance CreateInternal(const Data::Asset& modelAsset); + RHI::ResultCode Init(const Data::Asset& modelAsset); AZStd::fixed_vector, ModelLodAsset::LodCountMax> m_lods; Data::Asset m_modelAsset; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h index 36892d0027..0d0304a04e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/ModelLod.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -84,7 +85,7 @@ namespace AZ AZ_INSTANCE_DATA(ModelLod, "{3C796FC9-2067-4E0F-A660-269F8254D1D5}"); AZ_CLASS_ALLOCATOR(ModelLod, AZ::SystemAllocator, 0); - static Data::Instance FindOrCreate(const Data::Asset& lodAsset); + static Data::Instance FindOrCreate(const Data::Asset& lodAsset, const Data::Asset& modelAsset); ~ModelLod() = default; @@ -124,8 +125,8 @@ namespace AZ private: ModelLod() = default; - static Data::Instance CreateInternal(ModelLodAsset& lodAsset); - RHI::ResultCode Init(ModelLodAsset& lodAsset); + static Data::Instance CreateInternal(const Data::Asset& lodAsset, const AZStd::any* modelAssetAny); + RHI::ResultCode Init(const Data::Asset& lodAsset, const Data::Asset& modelAsset); bool SetMeshInstanceData( const ModelLodAsset::Mesh::StreamBufferInfo& streamBufferInfo, diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h index 891aec04b3..dbcfc69d56 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h @@ -51,7 +51,10 @@ namespace AZ const AZ::Aabb& GetAabb() const; //! Returns the list of all ModelMaterialSlot's for the model, across all LODs. - RPI::ModelMaterialSlotMap GetModelMaterialSlots() const; + const ModelMaterialSlotMap& GetMaterialSlots() const; + + //! Find a material slot with the given stableId, or returns an invalid slot if it isn't found. + const ModelMaterialSlot& FindMaterialSlot(uint32_t stableId) const; //! Returns the number of Lods in the model size_t GetLodCount() const; @@ -100,6 +103,13 @@ namespace AZ volatile mutable bool m_isKdTreeCalculationRunning = false; mutable AZStd::mutex m_kdTreeLock; mutable AZStd::optional m_modelTriangleCount; + + // Lists all of the material slots that are used by this LOD. + // Note the same slot can appear in multiple LODs in the model, so that LODs don't have to refer back to the model asset. + ModelMaterialSlotMap m_materialSlots; + + // A default ModelMaterialSlot to be returned upon error conditions. + ModelMaterialSlot m_fallbackSlot; AZStd::size_t CalculateTriangleCount() const; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAssetCreator.h index 0b8cb678dc..d87ae1c57e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAssetCreator.h @@ -29,6 +29,10 @@ namespace AZ //! Assigns a name to the model void SetName(AZStd::string_view name); + + //! Adds a new material slot to the asset. + //! If a slot with the same stable ID already exists, it will be replaced. + void AddMaterialSlot(const ModelMaterialSlot& materialSlot); //! Adds a Lod to the model. void AddLodAsset(Data::Asset&& lodAsset); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h index 61e2ebeb05..8c8edddfe1 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h @@ -85,9 +85,9 @@ namespace AZ //! Returns the number of indices in this mesh uint32_t GetIndexCount() const; - //! Returns the index of the material slot used by this mesh. - //! This indexes into the ModelLodAsset's material slot list. - size_t GetMaterialSlotIndex() const; + //! Returns the ID of the material slot used by this mesh. + //! This maps into the ModelAsset's material slot list. + ModelMaterialSlot::StableId GetMaterialSlotId() const; //! Returns the name of this mesh const AZ::Name& GetName() const; @@ -126,9 +126,9 @@ namespace AZ AZ::Name m_name; AZ::Aabb m_aabb = AZ::Aabb::CreateNull(); - // Identifies the material that is used by this mesh. - // References material slot in the ModelLodAsset that owns this mesh; see ModelLodAsset::GetMaterialSlot(). - size_t m_materialSlotIndex = 0; + // Identifies the material slot that is used by this mesh. + // References material slot in the ModelAsset that owns this mesh; see ModelAsset::FindMaterialSlot(). + ModelMaterialSlot::StableId m_materialSlotId = ModelMaterialSlot::InvalidStableId; // Both the buffer in m_indexBufferAssetView and the buffers in m_streamBufferInfo // may point to either unique buffers for the mesh or to consolidated @@ -147,16 +147,6 @@ namespace AZ //! Returns the model-space axis-aligned bounding box of all meshes in the lod const AZ::Aabb& GetAabb() const; - - //! Returns an array view into the collection of material slots available to this lod - AZStd::array_view GetMaterialSlots() const; - - //! Returns a specific material slot by index, with error checking. - //! The index can be retrieved from Mesh::GetMaterialSlotIndex(). - const ModelMaterialSlot& GetMaterialSlot(size_t slotIndex) const; - - //! Find a material slot with the given stableId, or returns null if it isn't found. - const ModelMaterialSlot* FindMaterialSlot(uint32_t stableId) const; private: AZStd::vector m_meshes; @@ -169,13 +159,6 @@ namespace AZ Data::Asset m_indexBuffer; AZStd::vector> m_streamBuffers; - // Lists all of the material slots that are used by this LOD. - // Note the same slot can appear in multiple LODs in the model, so that LODs don't have to refer back to the model asset. - AZStd::vector m_materialSlots; - - // A default ModelMaterialSlot to be returned upon error conditions. - ModelMaterialSlot m_fallbackSlot; - void AddMesh(const Mesh& mesh); void SetReady(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h index 5672b49f68..776347cb2b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAssetCreator.h @@ -46,10 +46,9 @@ namespace AZ //! Begin and BeginMesh must be called first. void SetMeshAabb(AZ::Aabb&& aabb); - //! Sets the material slot data for the current SubMesh. - //! Adds a new material slot to the ModelLodAsset if it doesn't already exist. + //! Sets the ID of the model's material slot that this mesh uses. //! Begin and BeginMesh must be called first - void SetMeshMaterialSlot(const ModelMaterialSlot& materialSlot); + void SetMeshMaterialSlot(ModelMaterialSlot::StableId id); //! Sets the given BufferAssetView to the current SubMesh as the index buffer. //! Begin and BeginMesh must be called first diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp index c55eb947a1..7187cb391a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp @@ -91,7 +91,7 @@ namespace AZ if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(14); // [ATOM-13410] + ->Version(16); // Optional material conversion } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index 608ee17d95..7100b2cd48 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -367,6 +367,9 @@ namespace AZ MorphTargetMetaAssetCreator morphTargetMetaCreator; morphTargetMetaCreator.Begin(MorphTargetMetaAsset::ConstructAssetId(modelAssetId, modelAssetName)); + + ModelAssetCreator modelAssetCreator; + modelAssetCreator.Begin(modelAssetId); uint32_t lodIndex = 0; for (const SourceMeshContentList& sourceMeshContentList : sourceMeshContentListsByLod) @@ -429,7 +432,7 @@ namespace AZ for (const ProductMeshView& meshView : lodMeshViews) { - if (!CreateMesh(meshView, indexBuffer, streamBuffers, lodAssetCreator, context.m_materialsByUid)) + if (!CreateMesh(meshView, indexBuffer, streamBuffers, modelAssetCreator, lodAssetCreator, context.m_materialsByUid)) { return AZ::SceneAPI::Events::ProcessingResult::Failure; } @@ -469,10 +472,6 @@ namespace AZ } sourceMeshContentListsByLod.clear(); - // Build the final asset structure - ModelAssetCreator modelAssetCreator; - modelAssetCreator.Begin(modelAssetId); - // Finalize all LOD assets for (auto& lodAsset : lodAssets) { @@ -1796,6 +1795,7 @@ namespace AZ const ProductMeshView& meshView, const BufferAssetView& lodIndexBuffer, const AZStd::vector& lodStreamBuffers, + ModelAssetCreator& modelAssetCreator, ModelLodAssetCreator& lodAssetCreator, const MaterialAssetsByUid& materialAssetsByUid) { @@ -1811,7 +1811,8 @@ namespace AZ materialSlot.m_displayName = iter->second.m_name; materialSlot.m_defaultMaterialAsset = iter->second.m_asset; - lodAssetCreator.SetMeshMaterialSlot(materialSlot); + modelAssetCreator.AddMaterialSlot(materialSlot); + lodAssetCreator.SetMeshMaterialSlot(materialSlot.m_stableId); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h index 79dec962df..832a8700ba 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h @@ -294,6 +294,7 @@ namespace AZ const ProductMeshView& meshView, const BufferAssetView& lodIndexBuffer, const AZStd::vector& lodStreamBuffers, + ModelAssetCreator& modelAssetCreator, ModelLodAssetCreator& lodAssetCreator, const MaterialAssetsByUid& materialAssetsByUid); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp index e684c4832a..32fe297c57 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp @@ -40,7 +40,7 @@ namespace AZ return m_lods; } - Data::Instance Model::CreateInternal(ModelAsset& modelAsset) + Data::Instance Model::CreateInternal(const Data::Asset& modelAsset) { AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender); Data::Instance model = aznew Model(); @@ -54,15 +54,15 @@ namespace AZ return nullptr; } - RHI::ResultCode Model::Init(ModelAsset& modelAsset) + RHI::ResultCode Model::Init(const Data::Asset& modelAsset) { AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender); - m_lods.resize(modelAsset.GetLodAssets().size()); + m_lods.resize(modelAsset->GetLodAssets().size()); for (size_t lodIndex = 0; lodIndex < m_lods.size(); ++lodIndex) { - const Data::Asset& lodAsset = modelAsset.GetLodAssets()[lodIndex]; + const Data::Asset& lodAsset = modelAsset->GetLodAssets()[lodIndex]; if (!lodAsset) { @@ -70,7 +70,7 @@ namespace AZ return RHI::ResultCode::Fail; } - Data::Instance lodInstance = ModelLod::FindOrCreate(lodAsset); + Data::Instance lodInstance = ModelLod::FindOrCreate(lodAsset, modelAsset); if (lodInstance == nullptr) { return RHI::ResultCode::Fail; @@ -98,7 +98,7 @@ namespace AZ m_lods[lodIndex] = AZStd::move(lodInstance); } - m_modelAsset = { &modelAsset, AZ::Data::AssetLoadBehavior::PreLoad }; + m_modelAsset = modelAsset; m_isUploadPending = true; return RHI::ResultCode::Success; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp index 2dfee9e2f1..dc39200a65 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelLod.cpp @@ -19,11 +19,14 @@ namespace AZ { namespace RPI { - Data::Instance ModelLod::FindOrCreate(const Data::Asset& lodAsset) + Data::Instance ModelLod::FindOrCreate(const Data::Asset& lodAsset, const Data::Asset& modelAsset) { + AZStd::any modelAssetAny{&modelAsset}; + return Data::InstanceDatabase::Instance().FindOrCreate( Data::InstanceId::CreateFromAssetId(lodAsset.GetId()), - lodAsset); + lodAsset, + &modelAssetAny); } AZStd::array_view ModelLod::GetMeshes() const @@ -31,10 +34,13 @@ namespace AZ return m_meshes; } - Data::Instance ModelLod::CreateInternal(ModelLodAsset& lodAsset) + Data::Instance ModelLod::CreateInternal(const Data::Asset& lodAsset, const AZStd::any* modelAssetAny) { + AZ_Assert(modelAssetAny != nullptr, "Invalid model asset param"); + auto modelAsset = AZStd::any_cast*>(*modelAssetAny); + Data::Instance lod = aznew ModelLod(); - const RHI::ResultCode resultCode = lod->Init(lodAsset); + const RHI::ResultCode resultCode = lod->Init(lodAsset, *modelAsset); if (resultCode == RHI::ResultCode::Success) { @@ -44,11 +50,11 @@ namespace AZ return nullptr; } - RHI::ResultCode ModelLod::Init(ModelLodAsset& lodAsset) + RHI::ResultCode ModelLod::Init(const Data::Asset& lodAsset, const Data::Asset& modelAsset) { AZ_TRACE_METHOD(); - for (const ModelLodAsset::Mesh& mesh : lodAsset.GetMeshes()) + for (const ModelLodAsset::Mesh& mesh : lodAsset->GetMeshes()) { Mesh meshInstance; @@ -100,7 +106,7 @@ namespace AZ } } - const ModelMaterialSlot& materialSlot = lodAsset.GetMaterialSlot(mesh.GetMaterialSlotIndex()); + const ModelMaterialSlot& materialSlot = modelAsset->FindMaterialSlot(mesh.GetMaterialSlotId()); meshInstance.m_materialSlotStableId = materialSlot.m_stableId; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp index b9781843cf..1ed81f8e16 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/ModelSystem.cpp @@ -41,9 +41,9 @@ namespace AZ { //Create Lod Database AZ::Data::InstanceHandler lodInstanceHandler; - lodInstanceHandler.m_createFunction = [](Data::AssetData* modelLodAsset) + lodInstanceHandler.m_createFunctionWithParam = [](Data::AssetData* modelLodAsset, const AZStd::any* modelAsset) { - return ModelLod::CreateInternal(*(azrtti_cast(modelLodAsset))); + return ModelLod::CreateInternal(Data::Asset{modelLodAsset, AZ::Data::AssetLoadBehavior::PreLoad}, modelAsset); }; Data::InstanceDatabase::Create(azrtti_typeid(), lodInstanceHandler); @@ -51,7 +51,7 @@ namespace AZ AZ::Data::InstanceHandler modelInstanceHandler; modelInstanceHandler.m_createFunction = [](Data::AssetData* modelAsset) { - return Model::CreateInternal(*(azrtti_cast(modelAsset))); + return Model::CreateInternal(Data::Asset{modelAsset, AZ::Data::AssetLoadBehavior::PreLoad}); }; Data::InstanceDatabase::Create(azrtti_typeid(), modelInstanceHandler); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp index 486faafbdb..275b056514 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp @@ -29,9 +29,10 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("Name", &ModelAsset::m_name) ->Field("Aabb", &ModelAsset::m_aabb) + ->Field("MaterialSlots", &ModelAsset::m_materialSlots) ->Field("LodAssets", &ModelAsset::m_lodAssets) ; } @@ -57,28 +58,23 @@ namespace AZ return m_aabb; } - RPI::ModelMaterialSlotMap ModelAsset::GetModelMaterialSlots() const + const ModelMaterialSlotMap& ModelAsset::GetMaterialSlots() const { - RPI::ModelMaterialSlotMap slotMap; + return m_materialSlots; + } - for (const Data::Asset& lod : GetLodAssets()) - { - for (const AZ::RPI::ModelMaterialSlot& materialSlot : lod->GetMaterialSlots()) - { - auto iter = slotMap.find(materialSlot.m_stableId); - if (iter == slotMap.end()) - { - slotMap.emplace(materialSlot.m_stableId, materialSlot); - } - else - { - AZ_Assert(materialSlot.m_displayName == iter->second.m_displayName && materialSlot.m_defaultMaterialAsset.GetId() == iter->second.m_defaultMaterialAsset.GetId(), - "Multiple LODs have mismatched data for the same material slot."); - } - } - } + const ModelMaterialSlot& ModelAsset::FindMaterialSlot(uint32_t stableId) const + { + auto iter = m_materialSlots.find(stableId); - return slotMap; + if (iter == m_materialSlots.end()) + { + return m_fallbackSlot; + } + else + { + return iter->second; + } } size_t ModelAsset::GetLodCount() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAssetCreator.cpp index 0c7a12fa8b..b35c9e44fe 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAssetCreator.cpp @@ -29,6 +29,33 @@ namespace AZ m_asset->m_name = name; } } + + void ModelAssetCreator::AddMaterialSlot(const ModelMaterialSlot& materialSlot) + { + if (ValidateIsReady()) + { + auto iter = m_asset->m_materialSlots.find(materialSlot.m_stableId); + + if (iter == m_asset->m_materialSlots.end()) + { + m_asset->m_materialSlots[materialSlot.m_stableId] = materialSlot; + } + else + { + if (materialSlot.m_displayName != iter->second.m_displayName) + { + ReportWarning("Material slot %u was already added with a different name.", materialSlot.m_stableId); + } + + if (materialSlot.m_defaultMaterialAsset != iter->second.m_defaultMaterialAsset) + { + ReportWarning("Material slot %u was already added with a different default MaterialAsset.", materialSlot.m_stableId); + } + + iter->second = materialSlot; + } + } + } void ModelAssetCreator::AddLodAsset(Data::Asset&& lodAsset) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp index 4811f6a1db..ccf0d49b46 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAsset.cpp @@ -23,10 +23,9 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(0) ->Field("Meshes", &ModelLodAsset::m_meshes) ->Field("Aabb", &ModelLodAsset::m_aabb) - ->Field("MaterialSlots", &ModelLodAsset::m_materialSlots) ; } @@ -41,7 +40,7 @@ namespace AZ ->Version(1) ->Field("Name", &ModelLodAsset::Mesh::m_name) ->Field("AABB", &ModelLodAsset::Mesh::m_aabb) - ->Field("MaterialSlotIndex", &ModelLodAsset::Mesh::m_materialSlotIndex) + ->Field("MaterialSlotId", &ModelLodAsset::Mesh::m_materialSlotId) ->Field("IndexBufferAssetView", &ModelLodAsset::Mesh::m_indexBufferAssetView) ->Field("StreamBufferInfo", &ModelLodAsset::Mesh::m_streamBufferInfo) ; @@ -76,9 +75,9 @@ namespace AZ return m_indexBufferAssetView.GetBufferViewDescriptor().m_elementCount; } - size_t ModelLodAsset::Mesh::GetMaterialSlotIndex() const + ModelMaterialSlot::StableId ModelLodAsset::Mesh::GetMaterialSlotId() const { - return m_materialSlotIndex; + return m_materialSlotId; } const AZ::Name& ModelLodAsset::Mesh::GetName() const @@ -120,41 +119,6 @@ namespace AZ return m_aabb; } - AZStd::array_view ModelLodAsset::GetMaterialSlots() const - { - return m_materialSlots; - } - - const ModelMaterialSlot& ModelLodAsset::GetMaterialSlot(size_t slotIndex) const - { - if (slotIndex < m_materialSlots.size()) - { - return m_materialSlots[slotIndex]; - } - else - { - AZ_Error("ModelAsset", false, "Material slot index %zu out of range. ModelAsset has %zu slots.", slotIndex, m_materialSlots.size()); - return m_fallbackSlot; - } - } - - const ModelMaterialSlot* ModelLodAsset::FindMaterialSlot(uint32_t stableId) const - { - auto iter = AZStd::find_if(m_materialSlots.begin(), m_materialSlots.end(), [&stableId](const ModelMaterialSlot& existingMaterialSlot) - { - return existingMaterialSlot.m_stableId == stableId; - }); - - if (iter == m_materialSlots.end()) - { - return nullptr; - } - else - { - return iter; - } - } - const BufferAssetView* ModelLodAsset::Mesh::GetSemanticBufferAssetView(const AZ::Name& semantic) const { const AZStd::array_view& streamBufferList = GetStreamBufferInfoList(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp index 5a066d2517..f94116db70 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelLodAssetCreator.cpp @@ -61,32 +61,14 @@ namespace AZ } } - void ModelLodAssetCreator::SetMeshMaterialSlot(const ModelMaterialSlot& materialSlot) + void ModelLodAssetCreator::SetMeshMaterialSlot(ModelMaterialSlot::StableId id) { - auto iter = AZStd::find_if(m_asset->m_materialSlots.begin(), m_asset->m_materialSlots.end(), [&materialSlot](const ModelMaterialSlot& existingMaterialSlot) - { - return existingMaterialSlot.m_stableId == materialSlot.m_stableId; - }); - - if (iter == m_asset->m_materialSlots.end()) + if (!ValidateIsMeshReady()) { - m_currentMesh.m_materialSlotIndex = m_asset->m_materialSlots.size(); - m_asset->m_materialSlots.push_back(materialSlot); + return; } - else - { - if (materialSlot.m_displayName != iter->m_displayName) - { - ReportWarning("Material slot %u was already added with a different name.", materialSlot.m_stableId); - } - if (materialSlot.m_defaultMaterialAsset != iter->m_defaultMaterialAsset) - { - ReportWarning("Material slot %u was already added with a different MaterialAsset.", materialSlot.m_stableId); - } - - *iter = materialSlot; - } + m_currentMesh.m_materialSlotId = id; } void ModelLodAssetCreator::SetMeshIndexBuffer(const BufferAssetView& bufferAssetView) @@ -309,8 +291,7 @@ namespace AZ AZ::Aabb aabb = sourceMesh.GetAabb(); creator.SetMeshAabb(AZStd::move(aabb)); - const ModelMaterialSlot& materialSlot = sourceAsset->GetMaterialSlot(sourceMesh.GetMaterialSlotIndex()); - creator.SetMeshMaterialSlot(materialSlot); + creator.SetMeshMaterialSlot(sourceMesh.GetMaterialSlotId()); // Mesh index buffer view const BufferAssetView& sourceIndexBufferView = sourceMesh.GetIndexBufferAssetView(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index a2a3022e91..2f4a649c30 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -257,7 +257,7 @@ namespace AZ Data::Asset modelAsset = GetModelAsset(); if (modelAsset.IsReady()) { - return modelAsset->GetModelMaterialSlots(); + return modelAsset->GetMaterialSlots(); } else { diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp index 415f0d1ce3..feabdb9510 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp @@ -96,7 +96,7 @@ namespace AZ skinnedSubMesh.m_vertexCount = aznumeric_cast(subMeshVertexCount); lodVertexCount += aznumeric_cast(subMeshVertexCount); - skinnedSubMesh.m_materialSlot = lodAsset->GetMaterialSlot(modelMesh.GetMaterialSlotIndex()); + skinnedSubMesh.m_materialSlot = actor->GetMeshAsset()->FindMaterialSlot(modelMesh.GetMaterialSlotId()); // Queue the material asset - the ModelLod seems to handle delayed material loads skinnedSubMesh.m_materialSlot.m_defaultMaterialAsset.QueueLoad(); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index f77e8d6bbd..062e39b844 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -313,7 +313,7 @@ namespace AZ Data::Asset modelAsset = GetModelAsset(); if (modelAsset.IsReady()) { - return modelAsset->GetModelMaterialSlots(); + return modelAsset->GetMaterialSlots(); } else { diff --git a/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp b/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp index 5a9b8191ed..daa0ad59f8 100644 --- a/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp +++ b/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.cpp @@ -112,20 +112,8 @@ namespace WhiteBox AddLodBuffers(modelLodCreator); modelLodCreator.BeginMesh(); modelLodCreator.SetMeshAabb(meshData.GetAabb()); - - // set the default material - if (auto materialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(TexturedMaterialPath.data())) - { - AZ::RPI::ModelMaterialSlot materialSlot; - materialSlot.m_stableId = 0; - materialSlot.m_defaultMaterialAsset = materialAsset; - modelLodCreator.SetMeshMaterialSlot(materialSlot); - } - else - { - AZ_Error("CreateLodAsset", false, "Could not load material."); - return false; - } + + modelLodCreator.SetMeshMaterialSlot(OneMaterialSlotId); AddMeshBuffers(modelLodCreator); modelLodCreator.EndMesh(); @@ -157,6 +145,20 @@ namespace WhiteBox modelCreator.Begin(AZ::Data::AssetId(AZ::Uuid::CreateRandom())); modelCreator.SetName(ModelName); modelCreator.AddLodAsset(AZStd::move(m_lodAsset)); + + if (auto materialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(TexturedMaterialPath.data())) + { + AZ::RPI::ModelMaterialSlot materialSlot; + materialSlot.m_stableId = OneMaterialSlotId; + materialSlot.m_defaultMaterialAsset = materialAsset; + modelCreator.AddMaterialSlot(materialSlot); + } + else + { + AZ_Error("CreateLodAsset", false, "Could not load material."); + return; + } + modelCreator.End(m_modelAsset); } diff --git a/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.h b/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.h index 00179f196d..63aca62051 100644 --- a/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.h +++ b/Gems/WhiteBox/Code/Source/Rendering/Atom/WhiteBoxAtomRenderMesh.h @@ -91,6 +91,7 @@ namespace WhiteBox // TODO: LYN-784 static constexpr AZStd::string_view TexturedMaterialPath = "materials/defaultpbr.azmaterial"; static constexpr AZStd::string_view SolidMaterialPath = "materials/defaultpbr.azmaterial"; + static constexpr AZ::RPI::ModelMaterialSlot::StableId OneMaterialSlotId = 0; //! White box model name. static constexpr AZStd::string_view ModelName = "WhiteBoxMesh"; From 75b4d62dcb2ae68d5900e5d5d9c07d5269e5a246 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Tue, 20 Jul 2021 16:59:25 -0700 Subject: [PATCH 081/157] Restored the version converter EditorMaterialComponent::ConvertVersion for version 3, which wasn't possible with an earlier version of my changes. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/EditorMaterialComponent.cpp | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 866b2dec56..d2f8c1daa0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -45,8 +45,57 @@ namespace AZ if (classElement.GetVersion() < 3) { - AZ_Error("EditorMaterialComponent", false, "Material Component version < 3 is no longer supported"); - return false; + // The default material was changed from an asset to an EditorMaterialComponentSlot and old data must be converted + constexpr AZ::u32 defaultMaterialAssetDataCrc = AZ_CRC("defaultMaterialAsset", 0x736fc071); + + Data::Asset oldDefaultMaterialData; + if (!classElement.GetChildData(defaultMaterialAssetDataCrc, oldDefaultMaterialData)) + { + AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to get defaultMaterialAsset element"); + return false; + } + + if (!classElement.RemoveElementByName(defaultMaterialAssetDataCrc)) + { + AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to remove defaultMaterialAsset element"); + return false; + } + + EditorMaterialComponentSlot newDefaultMaterialData; + newDefaultMaterialData.m_id = DefaultMaterialAssignmentId; + newDefaultMaterialData.m_materialAsset = oldDefaultMaterialData; + classElement.AddElementWithData(context, "defaultMaterialSlot", newDefaultMaterialData); + + // Slots now support and display the default material asset when empty + // The old placeholder assignments are irrelevant and must be cleared + constexpr AZ::u32 materialSlotsByLodDataCrc = AZ_CRC("materialSlotsByLod", 0xb1498db6); + + EditorMaterialComponentSlotsByLodContainer lodSlotData; + if (!classElement.GetChildData(materialSlotsByLodDataCrc, lodSlotData)) + { + AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to get materialSlotsByLod element"); + return false; + } + + if (!classElement.RemoveElementByName(materialSlotsByLodDataCrc)) + { + AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to remove materialSlotsByLod element"); + return false; + } + + // Find and clear all slots that are assigned to the slot's default value + for (auto& lodSlots : lodSlotData) + { + for (auto& slot : lodSlots) + { + if (slot.m_materialAsset.GetId() == slot.m_defaultMaterialAsset.GetId()) + { + slot.m_materialAsset = {}; + } + } + } + + classElement.AddElementWithData(context, "materialSlotsByLod", lodSlotData); } if (classElement.GetVersion() < 4) From abec7a4f5bcb69ba4450ae538c5f0c11291f1b4e Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Wed, 21 Jul 2021 09:16:01 -0700 Subject: [PATCH 082/157] Fixed an issue where a default material should show up as a filled-in value in the UI even though it should appear as empty, indicating the default is being used. Also, I'm going back on what I said in my last commit, and removing the converter for version 3 in EditorMaterialComponent::ConvertVersion. The code that I had put in before wouldn't work because it was relying on the new m_defaultMaterialAsset which will be empty for old data. The only way we could support version conversion is if we preserve legacy versions of multiple types like EditorMaterialComponentSlot and MaterialAssignmentId. Since this serialization version is old and pre-dates the public release of O3DE, it's unlikely that we need to continue supporting this version so isn't worth maintaining. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/EditorMaterialComponent.cpp | 62 +++---------------- 1 file changed, 9 insertions(+), 53 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index d2f8c1daa0..c7bd88219a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -45,64 +45,15 @@ namespace AZ if (classElement.GetVersion() < 3) { - // The default material was changed from an asset to an EditorMaterialComponentSlot and old data must be converted - constexpr AZ::u32 defaultMaterialAssetDataCrc = AZ_CRC("defaultMaterialAsset", 0x736fc071); - - Data::Asset oldDefaultMaterialData; - if (!classElement.GetChildData(defaultMaterialAssetDataCrc, oldDefaultMaterialData)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to get defaultMaterialAsset element"); - return false; - } - - if (!classElement.RemoveElementByName(defaultMaterialAssetDataCrc)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to remove defaultMaterialAsset element"); - return false; - } - - EditorMaterialComponentSlot newDefaultMaterialData; - newDefaultMaterialData.m_id = DefaultMaterialAssignmentId; - newDefaultMaterialData.m_materialAsset = oldDefaultMaterialData; - classElement.AddElementWithData(context, "defaultMaterialSlot", newDefaultMaterialData); - - // Slots now support and display the default material asset when empty - // The old placeholder assignments are irrelevant and must be cleared - constexpr AZ::u32 materialSlotsByLodDataCrc = AZ_CRC("materialSlotsByLod", 0xb1498db6); - - EditorMaterialComponentSlotsByLodContainer lodSlotData; - if (!classElement.GetChildData(materialSlotsByLodDataCrc, lodSlotData)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to get materialSlotsByLod element"); - return false; - } - - if (!classElement.RemoveElementByName(materialSlotsByLodDataCrc)) - { - AZ_Error("AZ::Render::EditorMaterialComponent::ConvertVersion", false, "Failed to remove materialSlotsByLod element"); - return false; - } - - // Find and clear all slots that are assigned to the slot's default value - for (auto& lodSlots : lodSlotData) - { - for (auto& slot : lodSlots) - { - if (slot.m_materialAsset.GetId() == slot.m_defaultMaterialAsset.GetId()) - { - slot.m_materialAsset = {}; - } - } - } - - classElement.AddElementWithData(context, "materialSlotsByLod", lodSlotData); + AZ_Error("EditorMaterialComponent", false, "Material Component version < 3 is no longer supported"); + return false; } if (classElement.GetVersion() < 4) { classElement.AddElementWithData(context, "materialSlotsByLodEnabled", true); } - + return true; } @@ -414,7 +365,11 @@ namespace AZ // if material is present in controller configuration, assign its data const MaterialAssignment& materialFromController = GetMaterialAssignmentFromMap(config.m_materials, slot.m_id); - slot.m_materialAsset = materialFromController.m_materialAsset; + if (materialFromController.m_materialAsset != slot.m_defaultMaterialAsset) // Prevents the default material from showing up as a filled-in value in the property field + { + slot.m_materialAsset = materialFromController.m_materialAsset; + } + slot.m_propertyOverrides = materialFromController.m_propertyOverrides; slot.m_matModUvOverrides = materialFromController.m_matModUvOverrides; @@ -629,3 +584,4 @@ namespace AZ } } // namespace Render } // namespace AZ + From 21d5baa1843099e573e7f7085f788e02880ab20c Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Wed, 21 Jul 2021 11:28:24 -0700 Subject: [PATCH 083/157] Fixed an issue where I had changed prior functionality by mistake, preventing exported materials from replacing material assignments. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Source/Material/EditorMaterialComponent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index c7bd88219a..7d0573c027 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -492,8 +492,8 @@ namespace AZ if (editorMaterialSlot) { - if (!editorMaterialSlot->m_materialAsset.GetId().IsValid() && //< Only update the slot of it was originally empty, having no override material. - editorMaterialSlot->m_defaultMaterialAsset.GetId() == exportItem.GetOriginalAssetId()) //< We need to check whether replaced material corresponds to this slot's default material. + // We need to check whether replaced material corresponds to this slot's default material. + if (editorMaterialSlot->m_defaultMaterialAsset.GetId() == exportItem.GetOriginalAssetId()) { editorMaterialSlot->m_materialAsset.Create(assetIdOutcome.GetValue()); } From 6fa891848df9a82d5cc46d01d83b8c17771b3557 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Wed, 21 Jul 2021 23:52:40 -0700 Subject: [PATCH 084/157] Factored out redundant call to GetMaterialSlots(). Removed code that was intended to handle duplicate default material assignments, but duplicacate default material assignments aren't possible yet. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Material/EditorMaterialComponent.cpp | 45 +++++++------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 7d0573c027..bc91e8adad 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -365,7 +365,7 @@ namespace AZ // if material is present in controller configuration, assign its data const MaterialAssignment& materialFromController = GetMaterialAssignmentFromMap(config.m_materials, slot.m_id); - if (materialFromController.m_materialAsset != slot.m_defaultMaterialAsset) // Prevents the default material from showing up as a filled-in value in the property field + //if (materialFromController.m_materialAsset != slot.m_defaultMaterialAsset) // Prevents the default material from showing up as a filled-in value in the property field { slot.m_materialAsset = materialFromController.m_materialAsset; } @@ -438,40 +438,27 @@ namespace AZ Data::AssetId modelAssetId; MeshComponentRequestBus::EventResult(modelAssetId, GetEntityId(), &MeshComponentRequestBus::Events::GetModelAssetId); - EditorMaterialComponentExporter::ExportItemsContainer exportItems; + // First generating a unique set of all material asset IDs that will be used for source data generation + AZStd::unordered_map assetIdMap; - // Generate a list of export items for the set of unique default material assets from the model. - for (auto& materialSlotPair : GetMaterialSlots()) + auto materialSlots = GetMaterialSlots(); + for (auto& materialSlotPair : materialSlots) { - // We only care about material assets that were generated from the model source file, since those are the - // ones that would need conversion (other materials already have their own source file). This can be detected - // by matching GUID component of the AssetId. Data::AssetId defaultMaterialAssetId = materialSlotPair.second->m_defaultMaterialAsset.GetId(); - bool materialWasGeneratedFromModel = defaultMaterialAssetId.IsValid() && defaultMaterialAssetId.m_guid == modelAssetId.m_guid; - if (materialWasGeneratedFromModel) + if (defaultMaterialAssetId.IsValid()) { - auto duplicateAssetIter = AZStd::find_if(exportItems.begin(), exportItems.end(), - [defaultMaterialAssetId](const EditorMaterialComponentExporter::ExportItem& existingExportItem) - { - return existingExportItem.GetOriginalAssetId() == defaultMaterialAssetId; - }); - - // It's possible for multiple material slots to have the same default material asset. So we just use the first one, which just means the - // exported material file name will be based on the first relevant material slot's name. - if (duplicateAssetIter == exportItems.end()) - { - EditorMaterialComponentExporter::ExportItem exportItem{defaultMaterialAssetId, materialSlotPair.second->GetLabel()}; - exportItems.push_back(exportItem); - } + assetIdMap[defaultMaterialAssetId] = materialSlotPair.second->GetLabel(); } } - // Sort by display name so the list order will match what's displayed in the Material Component. - AZStd::sort(exportItems.begin(), exportItems.end(), - [](const EditorMaterialComponentExporter::ExportItem& a, const EditorMaterialComponentExporter::ExportItem& b) - { - return a.GetMaterialSlotName() < b.GetMaterialSlotName(); - }); + // Convert the unique set of asset IDs into export items that can be configured in the dialog + // The order should not matter because the table in the dialog can sort itself for a specific row + EditorMaterialComponentExporter::ExportItemsContainer exportItems; + for (auto assetIdInfo : assetIdMap) + { + EditorMaterialComponentExporter::ExportItem exportItem{assetIdInfo.first, assetIdInfo.second}; + exportItems.push_back(exportItem); + } // Display the export dialog so that the user can configure how they want different materials to be exported if (EditorMaterialComponentExporter::OpenExportDialog(exportItems)) @@ -486,7 +473,7 @@ namespace AZ const auto& assetIdOutcome = AZ::RPI::AssetUtils::MakeAssetId(exportItem.GetExportPath(), 0); if (assetIdOutcome) { - for (auto& materialSlotPair : GetMaterialSlots()) + for (auto& materialSlotPair : materialSlots) { EditorMaterialComponentSlot* editorMaterialSlot = materialSlotPair.second; From b19a89588948d0ccffe9385e53e8bfcec65da154 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Wed, 21 Jul 2021 23:54:37 -0700 Subject: [PATCH 085/157] Reverted accidentally commented out code. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Source/Material/EditorMaterialComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index bc91e8adad..9f1d0d14d2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -365,7 +365,7 @@ namespace AZ // if material is present in controller configuration, assign its data const MaterialAssignment& materialFromController = GetMaterialAssignmentFromMap(config.m_materials, slot.m_id); - //if (materialFromController.m_materialAsset != slot.m_defaultMaterialAsset) // Prevents the default material from showing up as a filled-in value in the property field + if (materialFromController.m_materialAsset != slot.m_defaultMaterialAsset) // Prevents the default material from showing up as a filled-in value in the property field { slot.m_materialAsset = materialFromController.m_materialAsset; } From 1a478608a7fd74e98ac94070faf5ea288897da28 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Thu, 22 Jul 2021 16:11:35 -0700 Subject: [PATCH 086/157] Restored the previous behavior of preventing material property overrides when there is no explicit material override assignment. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Source/Material/EditorMaterialComponent.cpp | 8 +------- .../Code/Source/Material/EditorMaterialComponentSlot.cpp | 6 ++---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 9f1d0d14d2..a4e058561e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -365,10 +365,7 @@ namespace AZ // if material is present in controller configuration, assign its data const MaterialAssignment& materialFromController = GetMaterialAssignmentFromMap(config.m_materials, slot.m_id); - if (materialFromController.m_materialAsset != slot.m_defaultMaterialAsset) // Prevents the default material from showing up as a filled-in value in the property field - { - slot.m_materialAsset = materialFromController.m_materialAsset; - } + slot.m_materialAsset = materialFromController.m_materialAsset; slot.m_propertyOverrides = materialFromController.m_propertyOverrides; slot.m_matModUvOverrides = materialFromController.m_matModUvOverrides; @@ -435,9 +432,6 @@ namespace AZ AzToolsFramework::ScopedUndoBatch undoBatch("Generating materials."); SetDirty(); - Data::AssetId modelAssetId; - MeshComponentRequestBus::EventResult(modelAssetId, GetEntityId(), &MeshComponentRequestBus::Events::GetModelAssetId); - // First generating a unique set of all material asset IDs that will be used for source data generation AZStd::unordered_map assetIdMap; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index f9243510cf..7d89fb0571 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -272,13 +272,11 @@ namespace AZ action = menu.addAction("Edit Source Material...", [this]() { OpenMaterialEditor(); }); action->setEnabled(HasSourceData()); - bool hasAnyMaterial = m_defaultMaterialAsset.GetId().IsValid() || m_materialAsset.GetId().IsValid(); - action = menu.addAction("Edit Material Instance...", [this]() { OpenMaterialInspector(); }); - action->setEnabled(hasAnyMaterial); + action->setEnabled(m_materialAsset.GetId().IsValid()); action = menu.addAction("Edit Material Instance UV Map...", [this]() { OpenUvNameMapInspector(); }); - action->setEnabled(hasAnyMaterial); + action->setEnabled(m_materialAsset.GetId().IsValid()); menu.addSeparator(); From 66f7fa2f4273ac5adc46cef0a6e0f161472a54fb Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Fri, 23 Jul 2021 10:53:55 -0700 Subject: [PATCH 087/157] Fixed a bug where a new entity using a mesh that was already loaded would not be able to correctly initialize a material component. Repro steps: - Create two entities. - Entity 1 - Add a mesh component and assign a model with multiple sub-meshes - Add a material component. The material component looks correct. - Entity 2 - Add a mesh component and assign the same model as the other entity - Add a material component. The material component shows "" for all material slot names The problem was that ReflectedPropertyEditor creates a new Asset<> reference with the correct ID but does not load it. This asset is passed to EditorMaterialComponent, MaterialComponentController, and MeshFeatureProcessor and none of these tell the Asset to load. The MeshFeatureProcessor was not loading the Asset or connecting to the AssetBus because the instance already existed in the InstanceDatabse so from the FP's perspecive there was no need. But for the FP's GetModelAsset() API to function correctly it needs to have the asset initialized to the available AssetData pointer. So we updated the MeshFeatureProcessor to always connect to the AssetBus so it will find the available AssetData via the OnAssetReady callback. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 6e031aa853..8e2c6f2e9b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -485,20 +485,12 @@ namespace AZ AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id."); return; } - - // Check if the model is in the instance database and skip the loading process in this case. - // The model asset id is used as instance id to indicate that it is a static and shared. - Data::Instance model = Data::InstanceDatabase::Instance().Find(Data::InstanceId::CreateFromAssetId(m_modelAsset.GetId())); - if (model) + + if (!m_modelAsset.IsReady()) { - // In case the mesh asset requires instancing (e.g. when containing a cloth buffer), the model will always be cloned and there will not be a - // model instance with the asset id as instance id as searched above. - m_parent->Init(model); - m_modelChangedEvent.Signal(AZStd::move(model)); - return; + m_modelAsset.QueueLoad(); } - m_modelAsset.QueueLoad(); Data::AssetBus::Handler::BusConnect(modelAsset.GetId()); } From 13679a7cc3437bd45430e57e7cf076ca87cbbbe8 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Fri, 23 Jul 2021 11:02:06 -0700 Subject: [PATCH 088/157] Reverted partial support for property overrides on default material assignments. This needs more UI design discussion first. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Source/Material/EditorMaterialComponentSlot.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 7d89fb0571..39dde65a99 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -227,11 +227,9 @@ namespace AZ OnPropertyChanged(); }; - Data::Asset assetToEdit = m_materialAsset.GetId().IsValid() ? m_materialAsset : m_defaultMaterialAsset; - - if (assetToEdit.GetId().IsValid()) + if (m_materialAsset.GetId().IsValid()) { - if (EditorMaterialComponentInspector::OpenInspectorDialog(GetLabel(), assetToEdit.GetId(), m_propertyOverrides, applyPropertyChangedCallback)) + if (EditorMaterialComponentInspector::OpenInspectorDialog(GetLabel(), m_materialAsset.GetId(), m_propertyOverrides, applyPropertyChangedCallback)) { OnMaterialChanged(); } @@ -247,11 +245,9 @@ namespace AZ OnPropertyChanged(); }; - Data::Asset assetToEdit = m_materialAsset.GetId().IsValid() ? m_materialAsset : m_defaultMaterialAsset; - - if (assetToEdit.GetId().IsValid()) + if (m_materialAsset.GetId().IsValid()) { - if (EditorMaterialComponentInspector::OpenInspectorDialog(assetToEdit.GetId(), m_matModUvOverrides, m_modelUvNames, applyMatModUvOverrideChangedCallback)) + if (EditorMaterialComponentInspector::OpenInspectorDialog(m_materialAsset.GetId(), m_matModUvOverrides, m_modelUvNames, applyMatModUvOverrideChangedCallback)) { OnMaterialChanged(); } From da243235081f99ba9fd06e336dab5d1e7ad0839a Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Fri, 30 Jul 2021 15:24:32 -0500 Subject: [PATCH 089/157] [SPEC-7794] Removing references to alembic in cmake & asset processor. Signed-off-by: Ken Pruiksma --- Registry/AssetProcessorPlatformConfig.setreg | 3 --- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 1 - cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 1 - cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 1 - 4 files changed, 6 deletions(-) diff --git a/Registry/AssetProcessorPlatformConfig.setreg b/Registry/AssetProcessorPlatformConfig.setreg index 26aa5b2663..f1cb49c9cf 100644 --- a/Registry/AssetProcessorPlatformConfig.setreg +++ b/Registry/AssetProcessorPlatformConfig.setreg @@ -142,9 +142,6 @@ "Exclude TempFiles": { "pattern": ".*\\\\/\\\\$tmp[0-9]*_.*" }, - "Exclude AlembicCompressionTemplates": { - "pattern": ".*\\\\/Presets\\\\/GeomCache\\\\/.*" - }, "Exclude TmpAnimationCompression": { "pattern": ".*\\\\/Editor\\\\/Tmp\\\\/AnimationCompression\\\\/.*" }, diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 209ae9b062..7bb2c61774 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -10,7 +10,6 @@ ly_associate_package(PACKAGE_NAME zlib-1.2.8-rev2-multiplatform TARGETS zlib PACKAGE_HASH e6f34b8ac16acf881e3d666ef9fd0c1aee94c3f69283fb6524d35d6f858eebbb) ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) -ly_associate_package(PACKAGE_NAME alembic-1.7.11-rev3-multiplatform TARGETS alembic PACKAGE_HASH ba7a7d4943dd752f5a662374f6c48b93493df1d8e2c5f6a8d101f3b50700dd25) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index f7884fae46..bdffbd5dc7 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -10,7 +10,6 @@ ly_associate_package(PACKAGE_NAME zlib-1.2.8-rev2-multiplatform TARGETS zlib PACKAGE_HASH e6f34b8ac16acf881e3d666ef9fd0c1aee94c3f69283fb6524d35d6f858eebbb) ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) -ly_associate_package(PACKAGE_NAME alembic-1.7.11-rev3-multiplatform TARGETS alembic PACKAGE_HASH ba7a7d4943dd752f5a662374f6c48b93493df1d8e2c5f6a8d101f3b50700dd25) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 2b6e1da9ab..0134a45565 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -10,7 +10,6 @@ ly_associate_package(PACKAGE_NAME zlib-1.2.8-rev2-multiplatform TARGETS zlib PACKAGE_HASH e6f34b8ac16acf881e3d666ef9fd0c1aee94c3f69283fb6524d35d6f858eebbb) ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) -ly_associate_package(PACKAGE_NAME alembic-1.7.11-rev3-multiplatform TARGETS alembic PACKAGE_HASH ba7a7d4943dd752f5a662374f6c48b93493df1d8e2c5f6a8d101f3b50700dd25) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) From 461743ef2dc5a9d82e51bdfcca692fb1ac915ad8 Mon Sep 17 00:00:00 2001 From: SergeyAMZN <60428010+SergeyAMZN@users.noreply.github.com> Date: Fri, 30 Jul 2021 22:14:49 +0100 Subject: [PATCH 090/157] =?UTF-8?q?Enabled=20PhysX=20system=20component=20?= =?UTF-8?q?in=20asset=20builders=20since=20it's=20required=20=E2=80=A6=20(?= =?UTF-8?q?#2652)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enabled PhysX system component in asset builders since it's required for cooking collision meshes Signed-off-by: pereslav * Added AssetCatalogService to the list of dependent Signed-off-by: pereslav --- Gems/PhysX/Code/Source/SystemComponent.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Gems/PhysX/Code/Source/SystemComponent.cpp b/Gems/PhysX/Code/Source/SystemComponent.cpp index af38927f10..d8c4b47a2a 100644 --- a/Gems/PhysX/Code/Source/SystemComponent.cpp +++ b/Gems/PhysX/Code/Source/SystemComponent.cpp @@ -95,6 +95,7 @@ namespace PhysX { serialize->Class() ->Version(1) + ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AZ_CRC_CE("AssetBuilder") })) ->Field("Enabled", &SystemComponent::m_enabled) ; @@ -122,13 +123,14 @@ namespace PhysX incompatible.push_back(AZ_CRC("PhysXService", 0x75beae2d)); } - void SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + void SystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) { - required.push_back(AZ_CRC("AssetDatabaseService", 0x3abf5601)); } - void SystemComponent::GetDependentServices([[maybe_unused]]AZ::ComponentDescriptor::DependencyArrayType& dependent) + void SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { + dependent.push_back(AZ_CRC_CE("AssetDatabaseService")); + dependent.push_back(AZ_CRC_CE("AssetCatalogService")); } SystemComponent::SystemComponent() From e2eba69d338f90493ca7ea624957f1b7bf520a03 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 30 Jul 2021 18:19:35 -0500 Subject: [PATCH 091/157] updating FindMaterialAssignmentIdInLod to use ModelMaterialSlot } Signed-off-by: Guthrie Adams --- .../Source/Material/MaterialAssignment.cpp | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index 2c68309e27..e43dde5d78 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -33,8 +33,7 @@ namespace AZ serializeContext->Class() ->Version(1) ->Field("MaterialAsset", &MaterialAssignment::m_materialAsset) - ->Field("PropertyOverrides", &MaterialAssignment::m_propertyOverrides) - ; + ->Field("PropertyOverrides", &MaterialAssignment::m_propertyOverrides); } if (auto behaviorContext = azrtti_cast(context)) @@ -50,8 +49,7 @@ namespace AZ ->Constructor&, const Data::Instance&>() ->Method("ToString", &MaterialAssignment::ToString) ->Property("materialAsset", BehaviorValueProperty(&MaterialAssignment::m_materialAsset)) - ->Property("propertyOverrides", BehaviorValueProperty(&MaterialAssignment::m_propertyOverrides)) - ; + ->Property("propertyOverrides", BehaviorValueProperty(&MaterialAssignment::m_propertyOverrides)); behaviorContext->ConstantProperty("DefaultMaterialAssignment", BehaviorConstant(DefaultMaterialAssignment)) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) @@ -67,7 +65,6 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Category, "render") ->Attribute(AZ::Script::Attributes::Module, "render"); - } } @@ -152,7 +149,8 @@ namespace AZ { if (mesh.m_material) { - const MaterialAssignmentId generalId = MaterialAssignmentId::CreateFromStableIdOnly(mesh.m_materialSlotStableId); + const MaterialAssignmentId generalId = + MaterialAssignmentId::CreateFromStableIdOnly(mesh.m_materialSlotStableId); materials[generalId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); const MaterialAssignmentId specificId = @@ -168,19 +166,17 @@ namespace AZ } MaterialAssignmentId FindMaterialAssignmentIdInLod( - const Data::Instance& lod, const MaterialAssignmentLodIndex lodIndex, const AZStd::string& labelFilter) + const Data::Instance model, + const Data::Instance& lod, + const MaterialAssignmentLodIndex lodIndex, + const AZStd::string& labelFilter) { for (const AZ::RPI::ModelLod::Mesh& mesh : lod->GetMeshes()) { - if (mesh.m_material && mesh.m_material->GetAssetId().IsValid()) + const AZ::RPI::ModelMaterialSlot& slot = model->GetModelAsset()->FindMaterialSlot(mesh.m_materialSlotStableId); + if (AZ::StringFunc::Contains(slot.m_displayName.GetCStr(), labelFilter, true)) { - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, mesh.m_material->GetAssetId()); - if (assetInfo.m_assetId.IsValid() && AZ::StringFunc::Contains(assetInfo.m_relativePath, labelFilter, true)) - { - return MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId()); - } + return MaterialAssignmentId::CreateFromLodAndStableId(lodIndex, mesh.m_materialSlotStableId); } } return MaterialAssignmentId(); @@ -193,13 +189,13 @@ namespace AZ { if (lodFilter < model->GetLodCount()) { - return FindMaterialAssignmentIdInLod(model->GetLods()[lodFilter], lodFilter, labelFilter); + return FindMaterialAssignmentIdInLod(model, model->GetLods()[lodFilter], lodFilter, labelFilter); } for (size_t lodIndex = 0; lodIndex < model->GetLodCount(); ++lodIndex) { const MaterialAssignmentId result = - FindMaterialAssignmentIdInLod(model->GetLods()[lodIndex], MaterialAssignmentId::NonLodIndex, labelFilter); + FindMaterialAssignmentIdInLod(model, model->GetLods()[lodIndex], MaterialAssignmentId::NonLodIndex, labelFilter); if (!result.IsDefault()) { return result; From bb372f05cda5ab1baee5af5d28b18c591a47442a Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 30 Jul 2021 18:20:21 -0500 Subject: [PATCH 092/157] Fixed the emplace function implementations for stack and queue (#2657) * Fixed the emplace function implementations for stack and queue Cleaned up several functions in the stack, queue and priority_queue classes that were non-standard or weren't needed. Updated the "style" of the code to use more modern concepts: "typedef" -> "using", empty constructor body -> default keyword. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced the custom implementations of AZStd stack, (proirity)queue Theses classes now have a template alias to the standard library version of the classes Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/EBus/Policies.h | 6 +- .../AzCore/Serialization/AZStdContainers.inl | 2 - .../AzCore/AzCore/std/containers/queue.h | 201 +----------------- .../AzCore/AzCore/std/containers/stack.h | 98 +-------- .../AzCore/Tests/AZStd/DequeAndSimilar.cpp | 21 +- .../UnitTest/TestDebugDisplayRequests.cpp | 8 +- .../Visibility/OctreeSystemComponent.cpp | 2 +- .../GridMate/GridMate/Replica/ReplicaMgr.cpp | 10 +- .../GridMate/GridMate/Replica/ReplicaMgr.h | 16 +- .../Source/BlendTreeParameterNode.cpp | 2 +- .../ServerToClientReplicationWindow.cpp | 6 +- 11 files changed, 55 insertions(+), 317 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/EBus/Policies.h b/Code/Framework/AzCore/AzCore/EBus/Policies.h index 0217874416..db11043ef8 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Policies.h +++ b/Code/Framework/AzCore/AzCore/EBus/Policies.h @@ -268,7 +268,7 @@ namespace AZ m_messages.pop(); if (numMessages == 1) { - m_messages.get_container().clear(); // If it was the last message, free all memory. + m_messages = {}; } } ////////////////////////////////////////////////////////////////////////// @@ -280,7 +280,7 @@ namespace AZ void Clear() { AZStd::lock_guard lock(m_messagesMutex); - m_messages.get_container().clear(); + m_messages = {}; } void SetActive(bool isActive) @@ -289,7 +289,7 @@ namespace AZ m_isActive = isActive; if (!m_isActive) { - m_messages.get_container().clear(); + m_messages = {}; } }; diff --git a/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl b/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl index 35a2d64c0d..9eb65dec76 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl +++ b/Code/Framework/AzCore/AzCore/Serialization/AZStdContainers.inl @@ -42,8 +42,6 @@ namespace AZStd class unordered_multiset; template class bitset; - template*/ > - class stack; template class intrusive_ptr; diff --git a/Code/Framework/AzCore/AzCore/std/containers/queue.h b/Code/Framework/AzCore/AzCore/std/containers/queue.h index f1df1dd787..8026ebe943 100644 --- a/Code/Framework/AzCore/AzCore/std/containers/queue.h +++ b/Code/Framework/AzCore/AzCore/std/containers/queue.h @@ -5,206 +5,17 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#ifndef AZSTD_QUEUE_H -#define AZSTD_QUEUE_H 1 +#pragma once #include #include #include +#include namespace AZStd { - /** - * FIFO queue complaint with \ref CStd (23.2.3.1) - * The only extension we have is that we allow access - * to the underlying container via: get_container function. - * Check the queue \ref AZStdExamples. - */ - template > - class queue - { - enum - { - CONTAINER_VERSION = 1 - }; - public: - typedef queue this_type; - typedef Container container_type; - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - - AZ_FORCE_INLINE queue() {} - - AZ_FORCE_INLINE explicit queue(const container_type& container) - : m_container(container) {} - AZ_FORCE_INLINE bool empty() const { return m_container.empty(); } - AZ_FORCE_INLINE size_type size() const { return m_container.size(); } - AZ_FORCE_INLINE reference front() { return m_container.front(); } - AZ_FORCE_INLINE const_reference front() const { return m_container.front(); } - AZ_FORCE_INLINE reference back() { return m_container.back(); } - AZ_FORCE_INLINE const_reference back() const { return m_container.back(); } - AZ_FORCE_INLINE void push(const value_type& value) { m_container.push_back(value); } - AZ_FORCE_INLINE void pop() { m_container.pop_front(); } - - AZ_FORCE_INLINE void push() { m_container.push_back(); } - - AZ_FORCE_INLINE queue(this_type&& rhs) - : m_container(AZStd::move(rhs.m_container)) {} - AZ_FORCE_INLINE explicit queue(Container&& container) - : m_container(AZStd::move(container)) {} - this_type& operator=(this_type&& rhs) - { - m_container = AZStd::move(rhs.m_container); - return (*this); - } - void push(value_type&& value) { m_container.push_back(AZStd::move(value)); } - template - void emplace(Args&&... args) { m_container.emplace_back(AZStd::forward(args)...); } - void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); } - - AZ_FORCE_INLINE Container& get_container() { return m_container; } - AZ_FORCE_INLINE const Container& get_container() const { return m_container; } - - protected: - Container m_container; - }; - - // queue TEMPLATE FUNCTIONS - template - AZ_FORCE_INLINE bool operator==(const AZStd::queue& left, const AZStd::queue& right) - { - return left.get_container() == right.get_container(); - } - - template - AZ_FORCE_INLINE bool operator!=(const AZStd::queue& left, const AZStd::queue& right) - { - return left.get_container() != right.get_container(); - } - - /* template - AZ_FORCE_INLINE bool operator<(const queue& left, const queue& right) - { - return left.get_container() < right.get_container(); - } - - template - AZ_FORCE_INLINE bool operator>(const queue& left, const queue& right) - { - return left.get_container() > right.get_container(); - } - - template - AZ_FORCE_INLINE operator<=(const queue& left, const queue& right) - { - return left.get_container() <= right.get_container(); - } - - template - AZ_FORCE_INLINE bool operator>=(const queue& left, const queue& right) - { - return left.get_container() >= right.get_container(); - }*/ - - /** - * Priority queue is complaint with \ref CStd (23.2.3.2) - * The only extension we have is that we allow access - * to the underlying container via: get_container function. - * Check the priority_queue \ref AZStdExamples. - */ - template, class Predicate = AZStd::less > - class priority_queue - { - enum - { - CONTAINER_VERSION = 1 - }; - public: - typedef priority_queue this_type; - typedef Container container_type; - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - - AZ_FORCE_INLINE priority_queue() {} - AZ_FORCE_INLINE explicit priority_queue(const Predicate& comp) - : m_comp(comp) {} - AZ_FORCE_INLINE priority_queue(const Predicate& comp, const container_type& container) - : m_container(container) - , m_comp(comp) - { - // construct by copying specified container, comparator - AZStd::make_heap(m_container.begin(), m_container.end(), comp); - } - template - AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last) - : m_container(first, last) - , m_comp() - { - AZStd::make_heap(m_container.begin(), m_container.end(), m_comp); - } - - template - AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last, const Predicate& comp) - : m_container(first, last) - , m_comp(comp) - { // construct by copying [_First, _Last), specified comparator - AZStd::make_heap(m_container.begin(), m_container.end(), m_comp); - } - - template - AZ_FORCE_INLINE priority_queue(InputIterator first, InputIterator last, const Predicate& comp, const container_type& container) - : m_container(container) - , m_comp(comp) - { // construct by copying [_First, _Last), container, and comparator - m_container.insert(m_container.end(), first, last); - AZStd::make_heap(m_container.begin(), m_container.end(), m_comp); - } - - AZ_FORCE_INLINE bool empty() const { return m_container.empty(); } - AZ_FORCE_INLINE size_type size() const { return m_container.size(); } - AZ_FORCE_INLINE const_reference top() const { return m_container.front(); } - AZ_FORCE_INLINE reference top() { return m_container.front(); } - AZ_FORCE_INLINE void push(const value_type& value) - { - m_container.push_back(value); - AZStd::push_heap(m_container.begin(), m_container.end(), m_comp); - } - - AZ_FORCE_INLINE void pop() - { - AZStd::pop_heap(m_container.begin(), m_container.end(), m_comp); - m_container.pop_back(); - } - - AZ_FORCE_INLINE priority_queue(this_type&& rhs) - : m_container(AZStd::move(rhs.m_container)) - , m_comp(AZStd::move(rhs.m_comp)) {} - AZ_FORCE_INLINE explicit priority_queue(const Predicate& pred, Container&& container) - : m_container(AZStd::move(container)) - , m_comp(pred) {} - this_type& operator=(this_type&& rhs) - { - m_container = AZStd::move(rhs.m_container); - m_comp = AZStd::move(rhs.m_comp); - return (*this); - } - void push(value_type&& value) { m_container.push_back(AZStd::move(value)); AZStd::push_heap(m_container.begin(), m_container.end(), m_comp); } - template - void emplace(Args&& args) { m_container.emplace_back(AZStd::forward(args)); AZStd::push_heap(m_container.begin(), m_container.end(), m_comp); } - void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); AZStd::swap(m_comp, rhs.m_comp); } - - AZ_FORCE_INLINE Container& get_container() { return m_container; } - AZ_FORCE_INLINE const Container& get_container() const { return m_container; } - - protected: - Container m_container; - Predicate m_comp; - }; + template> + using queue = std::queue; + template, class Compare = AZStd::less> + using priority_queue = std::priority_queue; } - -#endif // AZSTD_QUEUE_H -#pragma once diff --git a/Code/Framework/AzCore/AzCore/std/containers/stack.h b/Code/Framework/AzCore/AzCore/std/containers/stack.h index 715d46c933..aa0d62d105 100644 --- a/Code/Framework/AzCore/AzCore/std/containers/stack.h +++ b/Code/Framework/AzCore/AzCore/std/containers/stack.h @@ -5,103 +5,13 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#ifndef AZSTD_STACK_H -#define AZSTD_STACK_H 1 +#pragma once #include +#include namespace AZStd { - /** - * Stack container is complaint with \ref CStd (23.2.3.3) - * The only extension we have is that we allow access - * to the underlying container via: get_container function. - * Check the stack \ref AZStdExamples. - */ - template > - class stack - { - enum - { - CONTAINER_VERSION = 1 - }; - public: - typedef stack this_type; - typedef Container container_type; - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - - AZ_FORCE_INLINE stack() {} - AZ_FORCE_INLINE explicit stack(const container_type& container) - : m_container(container) {} - AZ_FORCE_INLINE bool empty() const { return m_container.empty(); } - AZ_FORCE_INLINE size_type size() const { return m_container.size(); } - AZ_FORCE_INLINE reference top() { return m_container.back(); } - AZ_FORCE_INLINE const_reference top() const { return m_container.back(); } - AZ_FORCE_INLINE reference back() { return m_container.back(); } - AZ_FORCE_INLINE const_reference back() const { return m_container.back(); } - AZ_FORCE_INLINE void push(const value_type& value) { m_container.push_back(value); } - AZ_FORCE_INLINE void pop() { m_container.pop_back(); } - AZ_FORCE_INLINE void push() { m_container.push_back(); } - - AZ_FORCE_INLINE stack(this_type&& rhs) - : m_container(AZStd::move(rhs.m_container)) {} - AZ_FORCE_INLINE explicit stack(Container&& container) - : m_container(AZStd::move(container)) {} - this_type& operator=(this_type&& rhs) { m_container = AZStd::move(rhs.m_container); return *this; } - void push(value_type&& value) { m_container.push_back(AZStd::move(value)); } - template - void emplace(Args&& args) { m_container.emplace_back(AZStd::forward(args)); } - void swap(this_type&& rhs) { m_container.swap(AZStd::move(rhs.m_container)); } - - void swap(this_type& rhs) { AZStd::swap(m_container, rhs.m_container); } - - AZ_FORCE_INLINE Container& get_container() { return m_container; } - AZ_FORCE_INLINE const Container& get_container() const { return m_container; } - - protected: - Container m_container; - }; - - // queue TEMPLATE FUNCTIONS - template - AZ_FORCE_INLINE bool operator==(const AZStd::stack& left, const AZStd::stack& right) - { - return left.get_container() == right.get_container(); - } - - template - AZ_FORCE_INLINE bool operator!=(const AZStd::stack& left, const AZStd::stack& right) - { - return left.get_container() != right.get_container(); - } - - /* template - AZ_FORCE_INLINE bool operator<(const queue& left, const queue& right) - { - return left.get_container() < right.get_container(); - } - - template - AZ_FORCE_INLINE bool operator>(const queue& left, const queue& right) - { - return left.get_container() > right.get_container(); - } - - template - AZ_FORCE_INLINE operator<=(const queue& left, const queue& right) - { - return left.get_container() <= right.get_container(); - } - - template - AZ_FORCE_INLINE bool operator>=(const queue& left, const queue& right) - { - return left.get_container() >= right.get_container(); - }*/ + template> + using stack = std::stack; } - -#endif // AZSTD_STACK_H -#pragma once diff --git a/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp b/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp index 587d900b90..33a5d29b4f 100644 --- a/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/DequeAndSimilar.cpp @@ -298,7 +298,7 @@ namespace UnitTest AZ_TEST_ASSERT(int_queue.empty()); AZ_TEST_ASSERT(int_queue.size() == 0); - // Queue uses deque as default container, so try to contruct to queue from a deque. + // Queue uses deque as default container, so try to construct to queue from a deque. deque container(40, 10); int_queue_type int_queue2(container); AZ_TEST_ASSERT(!int_queue2.empty()); @@ -324,7 +324,7 @@ namespace UnitTest AZ_TEST_ASSERT(int_queue2.size() == 40); AZ_TEST_ASSERT(int_queue2.back() == 20); - int_queue.push(); + int_queue.emplace(); AZ_TEST_ASSERT(!int_queue.empty()); AZ_TEST_ASSERT(int_queue.size() == 1); @@ -423,7 +423,7 @@ namespace UnitTest AZ_TEST_ASSERT(int_stack2.size() == 40); AZ_TEST_ASSERT(int_stack2.top() == 10); - int_stack.push(); + int_stack.emplace(); AZ_TEST_ASSERT(!int_stack.empty()); AZ_TEST_ASSERT(int_stack.size() == 1); // StackContainerTest-End @@ -669,4 +669,19 @@ namespace UnitTest ++iteration; } } + + using StackContainerTestFixture = ScopedAllocatorSetupFixture; + + TEST_F(StackContainerTestFixture, StackEmplaceOperator_SupportsZeroOrMoreArguments) + { + using TestPairType = AZStd::pair; + AZStd::stack testStack; + testStack.emplace(); + testStack.emplace(1); + testStack.emplace(2, 3); + + using ContainerType = typename AZStd::stack::container_type; + AZStd::stack expectedStack(ContainerType{ TestPairType{ 0, 0 }, TestPairType{ 1, 0 }, TestPairType{ 2, 3 } }); + EXPECT_EQ(expectedStack, testStack); + } } diff --git a/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp b/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp index cc663f36b8..ecbacd125b 100644 --- a/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp +++ b/Code/Framework/AzFramework/AzFramework/UnitTest/TestDebugDisplayRequests.cpp @@ -32,7 +32,7 @@ namespace UnitTest void TestDebugDisplayRequests::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max) { - const AZ::Transform& tm = m_transforms.back(); + const AZ::Transform& tm = m_transforms.top(); m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), min.GetY(), min.GetZ()))); m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), min.GetY(), max.GetZ()))); m_points.push_back(tm.TransformPoint(AZ::Vector3(min.GetX(), max.GetY(), min.GetZ()))); @@ -50,7 +50,7 @@ namespace UnitTest void TestDebugDisplayRequests::DrawWireQuad(float width, float height) { - const AZ::Transform& tm = m_transforms.back(); + const AZ::Transform& tm = m_transforms.top(); m_points.push_back(tm.TransformPoint(AZ::Vector3(-0.5f * width, 0.0f, -0.5f * height))); m_points.push_back(tm.TransformPoint(AZ::Vector3(-0.5f * width, 0.0f, 0.5f * height))); m_points.push_back(tm.TransformPoint(AZ::Vector3(0.5f * width, 0.0f, -0.5f * height))); @@ -64,7 +64,7 @@ namespace UnitTest void TestDebugDisplayRequests::DrawPoints(const AZStd::vector& points) { - const AZ::Transform& tm = m_transforms.back(); + const AZ::Transform& tm = m_transforms.top(); for (const auto& point : points) { m_points.push_back(tm.TransformPoint(point)); @@ -100,7 +100,7 @@ namespace UnitTest void TestDebugDisplayRequests::PushMatrix(const AZ::Transform& tm) { - m_transforms.push(m_transforms.back() * tm); + m_transforms.push(m_transforms.top() * tm); } void TestDebugDisplayRequests::PopMatrix() diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp index 5ef1cda30e..b4cad8511f 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Visibility/OctreeSystemComponent.cpp @@ -481,7 +481,7 @@ namespace AzFramework if (!m_freeOctreeNodes.empty()) { // Take a free block of child nodes from our free list - ExtractPageAndOffsetFromIndex(m_freeOctreeNodes.back(), nextChildPage, nextChildOffset); + ExtractPageAndOffsetFromIndex(m_freeOctreeNodes.top(), nextChildPage, nextChildOffset); m_freeOctreeNodes.pop(); } else diff --git a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp index 2bc8d3e9f0..b8eea00871 100644 --- a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp +++ b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.cpp @@ -1688,12 +1688,12 @@ namespace GridMate return; //No connections to update } bool updateRate = false; - AZ::u32 minRateBytesPerSecond = m_connByCongestionState.top().m_rate; + AZ::u32 minRateBytesPerSecond = m_connByCongestionState.front().m_rate; //const AZ::u32 old = minRateBytesPerSecond; //For debugging - auto connIt = AZStd::find(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end(), id); + auto connIt = AZStd::find(m_connByCongestionState.begin(), m_connByCongestionState.end(), id); - if ( connIt == m_connByCongestionState.get_container().end()) + if ( connIt == m_connByCongestionState.end()) { return; //Already disconnected } @@ -1708,11 +1708,11 @@ namespace GridMate //If new min or old min increased, rebuild the heap and send an update if (bytesPerSecond < minRateBytesPerSecond - || (id == m_connByCongestionState.top().m_connection && bytesPerSecond > minRateBytesPerSecond)) + || (id == m_connByCongestionState.front().m_connection && bytesPerSecond > minRateBytesPerSecond)) { updateRate = true; minRateBytesPerSecond = bytesPerSecond; - AZStd::make_heap(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end()); + AZStd::make_heap(m_connByCongestionState.begin(), m_connByCongestionState.end()); } } diff --git a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h index 93a46d8ad7..bd9f1a1ee9 100644 --- a/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h +++ b/Code/Framework/GridMate/GridMate/Replica/ReplicaMgr.h @@ -459,7 +459,7 @@ namespace GridMate } }; static bool k_enableBackPressure; - AZStd::priority_queue m_connByCongestionState; ///< Connections priority queue sorted by congestion window + AZStd::vector m_connByCongestionState; ///< Connections priority queue sorted by congestion window /*** * Updates connection's rate in priority and updates send limit * @@ -479,7 +479,9 @@ namespace GridMate } AZ_Assert(carrier, "NULL carrier!"); - m_connByCongestionState.emplace(RateConnectionPair(AZ::u32(1500), id)); //default to 1500Bps (ex 1 Ethernet frame/second minimum) + m_connByCongestionState.emplace_back(AZ::u32(1500), id); //default to 1500Bps (ex 1 Ethernet frame/second minimum) + // Restore the heap property after pushing back another element + AZStd::push_heap(m_connByCongestionState.begin(), m_connByCongestionState.end()); } void OnDisconnect(Carrier* carrier, ConnectionID id, CarrierDisconnectReason reason) override { @@ -490,17 +492,17 @@ namespace GridMate } AZ_Assert(carrier, "NULL carrier!"); - auto connIt = AZStd::find(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end(), id); - if (connIt != m_connByCongestionState.get_container().end()) + auto connIt = AZStd::find(m_connByCongestionState.begin(), m_connByCongestionState.end(), id); + if (connIt != m_connByCongestionState.end()) { //Since we are using a weakly sorted heap, we need to re-generate when the top is removed - bool remake = (connIt == m_connByCongestionState.get_container().begin()); + bool remake = (connIt == m_connByCongestionState.begin()); - m_connByCongestionState.get_container().erase(connIt); + m_connByCongestionState.erase(connIt); if (remake) { - AZStd::make_heap(m_connByCongestionState.get_container().begin(), m_connByCongestionState.get_container().end()); + AZStd::make_heap(m_connByCongestionState.begin(), m_connByCongestionState.end()); } } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeParameterNode.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeParameterNode.cpp index 682657e5bb..8197cae9d0 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeParameterNode.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/BlendTreeParameterNode.cpp @@ -395,7 +395,7 @@ namespace EMotionFX } // If new parameter matches the last deleted parameter, we add it back to the parameter mask. - if (!m_deletedParameterNames.empty() && newParameterName == m_deletedParameterNames.back()) + if (!m_deletedParameterNames.empty() && newParameterName == m_deletedParameterNames.top()) { m_parameterNames.push_back(newParameterName); SortAndRemoveDuplicates(GetAnimGraph(), m_parameterNames); // make sure the mask is sorted correctly. diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index 740f9abea2..ba9740f8db 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -107,8 +107,10 @@ namespace Multiplayer void ServerToClientReplicationWindow::UpdateWindow() { // clear the candidate queue, we're going to rebuild it - ReplicationCandidateQueue clearQueue; - clearQueue.get_container().reserve(sv_MaxEntitiesToTrackReplication); + ReplicationCandidateQueue::container_type clearQueueContainer; + clearQueueContainer.reserve(sv_MaxEntitiesToTrackReplication); + // Move the clearQueueContainer into the ReplicationCandidateQueue to maintain the reserved memory + ReplicationCandidateQueue clearQueue(ReplicationCandidateQueue::value_compare{}, AZStd::move(clearQueueContainer)); m_candidateQueue.swap(clearQueue); m_replicationSet.clear(); From 5d3d3b907ed528ff417091a8633ea95c39326dbb Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 30 Jul 2021 16:52:43 -0700 Subject: [PATCH 093/157] Changed a couple function parameters to const& Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Include/Atom/Feature/Material/MaterialAssignment.h | 2 +- .../Common/Code/Source/Material/MaterialAssignment.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 907b1a1740..987e78ae0f 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -66,6 +66,6 @@ namespace AZ //! Find an assignment id corresponding to the lod and label substring filters MaterialAssignmentId FindMaterialAssignmentIdInModel( - const Data::Instance model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter); + const Data::Instance& model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter); } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index e43dde5d78..4d437be244 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -166,7 +166,7 @@ namespace AZ } MaterialAssignmentId FindMaterialAssignmentIdInLod( - const Data::Instance model, + const Data::Instance& model, const Data::Instance& lod, const MaterialAssignmentLodIndex lodIndex, const AZStd::string& labelFilter) @@ -183,7 +183,7 @@ namespace AZ } MaterialAssignmentId FindMaterialAssignmentIdInModel( - const Data::Instance model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter) + const Data::Instance& model, const MaterialAssignmentLodIndex lodFilter, const AZStd::string& labelFilter) { if (model && !labelFilter.empty()) { From bb782e83b46d41fd8a64b7ce4a62aa598913d7c9 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Wed, 28 Jul 2021 09:33:28 -0600 Subject: [PATCH 094/157] Promote IndexedDataVector to public Feature/Utils header Signed-off-by: Jeremy Ong --- .../Atom/Feature/Utils}/IndexedDataVector.h | 0 .../Atom/Feature/Utils}/IndexedDataVector.inl | 0 .../Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp | 2 +- .../Code/Source/CoreLights/CapsuleLightFeatureProcessor.h | 2 +- .../Code/Source/CoreLights/DirectionalLightFeatureProcessor.h | 2 +- .../Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h | 2 +- .../Code/Source/CoreLights/PointLightFeatureProcessor.h | 2 +- .../Common/Code/Source/CoreLights/QuadLightFeatureProcessor.h | 2 +- .../Code/Source/CoreLights/SimplePointLightFeatureProcessor.h | 2 +- .../Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.h | 2 +- .../Code/Source/Decals/DecalTextureArrayFeatureProcessor.h | 2 +- .../Code/Source/Shadows/ProjectedShadowFeatureProcessor.h | 2 +- Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake | 4 ++-- 13 files changed, 12 insertions(+), 12 deletions(-) rename Gems/Atom/Feature/Common/Code/{Source/CoreLights => Include/Atom/Feature/Utils}/IndexedDataVector.h (100%) rename Gems/Atom/Feature/Common/Code/{Source/CoreLights => Include/Atom/Feature/Utils}/IndexedDataVector.inl (100%) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/IndexedDataVector.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h similarity index 100% rename from Gems/Atom/Feature/Common/Code/Source/CoreLights/IndexedDataVector.h rename to Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/IndexedDataVector.inl b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl similarity index 100% rename from Gems/Atom/Feature/Common/Code/Source/CoreLights/IndexedDataVector.inl rename to Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index 6ad0099686..1500079b00 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -284,7 +284,7 @@ namespace AZ passSystem->AddPassCreator(Name("ReflectionScreenSpaceCompositePass"), &Render::ReflectionScreenSpaceCompositePass::Create); passSystem->AddPassCreator(Name("ReflectionCopyFrameBufferPass"), &Render::ReflectionCopyFrameBufferPass::Create); - // Add RayTracing pas + // Add RayTracing pass passSystem->AddPassCreator(Name("RayTracingPass"), &Render::RayTracingPass::Create); // setup handler for load pass template mappings diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.h index a85831e290..6749acfcf5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/CapsuleLightFeatureProcessor.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h index a312b31dda..4c486c4540 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h @@ -9,9 +9,9 @@ #pragma once #include -#include #include +#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 2e97ae1ded..36837a67fb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index b7b644da9e..3c231c1fb0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.h index 567d309dff..17d6aab304 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/QuadLightFeatureProcessor.h @@ -10,7 +10,7 @@ #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.h index 3d36bb1978..bd9160b171 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimplePointLightFeatureProcessor.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.h index 1d72c3e6cc..bc132be77c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/SimpleSpotLightFeatureProcessor.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h index 649928d26d..57c5c69e0d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -16,7 +17,6 @@ #include #include #include -#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index 3dbf88addb..8beed800b6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -10,10 +10,10 @@ #include #include +#include #include #include #include -#include namespace AZ::Render { diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 401fac8c0c..40188109ca 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -37,6 +37,8 @@ set(FILES Include/Atom/Feature/TransformService/TransformServiceFeatureProcessor.h Include/Atom/Feature/Utils/FrameCaptureBus.h Include/Atom/Feature/Utils/GpuBufferHandler.h + Include/Atom/Feature/Utils/IndexedDataVector.h + Include/Atom/Feature/Utils/IndexedDataVector.inl Include/Atom/Feature/Utils/MultiIndexedDataVector.h Include/Atom/Feature/Utils/MultiSparseVector.h Include/Atom/Feature/Utils/ProfilingCaptureBus.h @@ -77,8 +79,6 @@ set(FILES Source/CoreLights/DiskLightFeatureProcessor.cpp Source/CoreLights/EsmShadowmapsPass.h Source/CoreLights/EsmShadowmapsPass.cpp - Source/CoreLights/IndexedDataVector.h - Source/CoreLights/IndexedDataVector.inl Source/CoreLights/LtcCommon.h Source/CoreLights/LtcCommon.cpp Source/CoreLights/PointLightFeatureProcessor.h From e1ce742f14f096e9a2e9d0a7af68cca9068f8628 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Wed, 28 Jul 2021 12:30:06 -0600 Subject: [PATCH 095/157] Generalize comments pertaining to light data and consolidate inline header Signed-off-by: Jeremy Ong --- .../Atom/Feature/Utils/IndexedDataVector.h | 128 ++++++++++++++++-- .../Atom/Feature/Utils/IndexedDataVector.inl | 113 ---------------- .../Code/atom_feature_common_files.cmake | 1 - 3 files changed, 120 insertions(+), 122 deletions(-) delete mode 100644 Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h index f2a372aca9..a73ba2f16b 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h @@ -15,11 +15,15 @@ namespace AZ { namespace Render { + // Growable vector that leverages indirection to support erasure of elements while maintaining + // resident data in a densely packed region of memory. Useful as a backing store for growable + // buffers intended to be uploaded to the GPU for example. template class IndexedDataVector { public: IndexedDataVector(); + explicit IndexedDataVector(size_t initialReservedSize); ~IndexedDataVector() = default; static constexpr IndexType NoFreeSlot = std::numeric_limits::max(); @@ -39,17 +43,125 @@ namespace AZ IndexType GetRawIndex(IndexType index) const; private: + constexpr static size_t InitialReservedSize = 128; - static constexpr size_t InitialReservedCount = 128; - - // stores the index of data vector for respective light, it also include a linked list to flag the free slots + // Stores data indices and an embedded free list AZStd::vector m_indices; - // stores the index of index vector for respective light + // Stores the indirection index AZStd::vector m_dataToIndices; - // stores light data AZStd::vector m_data; }; -#include "IndexedDataVector.inl" - } -} + template + inline IndexedDataVector::IndexedDataVector() + : IndexedDataVector(InitialReservedSize) + { + } + + template + inline IndexedDataVector::IndexedDataVector(size_t initialReservedSize) + { + m_dataToIndices.reserve(initialReservedSize); + m_indices.reserve(initialReservedSize); + m_data.reserve(initialReservedSize); + } + + template + inline void IndexedDataVector::Clear() + { + m_dataToIndices.clear(); + m_indices.clear(); + m_data.clear(); + + m_firstFreeSlot = NoFreeSlot; + } + + template + inline IndexType IndexedDataVector::GetFreeSlotIndex() + { + IndexType freeSlotIndex = static_cast(m_indices.size()); + + if (freeSlotIndex == NoFreeSlot) + { + // the vector is full + return NoFreeSlot; + } + + if (m_firstFreeSlot == NoFreeSlot) + { + // If there's no free slot, add on to the end. + m_indices.push_back(freeSlotIndex); + } + else + { + // Fill the free slot. m_indices uses it's empty slots to store a linked list (via indices) to other empty slots. + freeSlotIndex = m_firstFreeSlot; + m_firstFreeSlot = m_indices.at(m_firstFreeSlot); + m_indices.at(freeSlotIndex) = static_cast(m_data.size()); + } + + // The data itself is always packed and m_indices points at it, so push a new entry to the back. + m_data.push_back(DataType()); + m_dataToIndices.push_back(freeSlotIndex); + + return freeSlotIndex; + } + + template + inline void IndexedDataVector::RemoveIndex(IndexType index) + { + IndexType dataIndex = m_indices.at(index); + + // Copy the back light on top of this one. + m_data.at(dataIndex) = m_data.back(); + m_dataToIndices.at(dataIndex) = m_dataToIndices.back(); + + // Update the index of the moved light + m_indices.at(m_dataToIndices.at(dataIndex)) = dataIndex; + + // Pop the back + m_data.pop_back(); + m_dataToIndices.pop_back(); + + // Use free slot to link to next free slot + m_indices.at(index) = m_firstFreeSlot; + m_firstFreeSlot = index; + } + + template + inline DataType& IndexedDataVector::GetData(IndexType index) + { + return m_data.at(m_indices.at(index)); + } + + template + inline const DataType& IndexedDataVector::GetData(IndexType index) const + { + return m_data.at(m_indices.at(index)); + } + + template + inline size_t IndexedDataVector::GetDataCount() const + { + return m_data.size(); + } + + template + inline AZStd::vector& IndexedDataVector::GetDataVector() + { + return m_data; + } + + template + inline const AZStd::vector& IndexedDataVector::GetDataVector() const + { + return m_data; + } + + template + IndexType IndexedDataVector::GetRawIndex(IndexType index) const + { + return m_indices.at(index); + } + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl deleted file mode 100644 index da10e5a503..0000000000 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -template -inline IndexedDataVector::IndexedDataVector() -{ - m_dataToIndices.reserve(InitialReservedCount); - m_indices.reserve(InitialReservedCount); - m_data.reserve(InitialReservedCount); -} - -template -inline void IndexedDataVector::Clear() -{ - m_dataToIndices.clear(); - m_indices.clear(); - m_data.clear(); - - m_firstFreeSlot = NoFreeSlot; -} - -template -inline IndexType IndexedDataVector::GetFreeSlotIndex() -{ - IndexType freeSlotIndex = static_cast(m_indices.size()); - - if (freeSlotIndex == NoFreeSlot) - { - // the vector is full - return NoFreeSlot; - } - - if (m_firstFreeSlot == NoFreeSlot) - { - // If there's no free slot, add on to the end. - m_indices.push_back(freeSlotIndex); - } - else - { - // Fill the free slot. m_indices uses it's empty slots to store a linked list (via indices) to other empty slots. - freeSlotIndex = m_firstFreeSlot; - m_firstFreeSlot = m_indices.at(m_firstFreeSlot); - m_indices.at(freeSlotIndex) = static_cast(m_data.size()); - } - - // The data itself is always packed and m_indices points at it, so push a new entry to the back. - m_data.push_back(DataType()); - m_dataToIndices.push_back(freeSlotIndex); - - return freeSlotIndex; -} - -template -inline void IndexedDataVector::RemoveIndex(IndexType index) -{ - IndexType dataIndex = m_indices.at(index); - - // Copy the back light on top of this one. - m_data.at(dataIndex) = m_data.back(); - m_dataToIndices.at(dataIndex) = m_dataToIndices.back(); - - // Update the index of the moved light - m_indices.at(m_dataToIndices.at(dataIndex)) = dataIndex; - - // Pop the back - m_data.pop_back(); - m_dataToIndices.pop_back(); - - // Use free slot to link to next free slot - m_indices.at(index) = m_firstFreeSlot; - m_firstFreeSlot = index; -} - -template -inline DataType& IndexedDataVector::GetData(IndexType index) -{ - return m_data.at(m_indices.at(index)); -} - -template -inline const DataType& IndexedDataVector::GetData(IndexType index) const -{ - return m_data.at(m_indices.at(index)); -} - -template -inline size_t IndexedDataVector::GetDataCount() const -{ - return m_data.size(); -} - -template -inline AZStd::vector& IndexedDataVector::GetDataVector() -{ - return m_data; -} - -template -inline const AZStd::vector& IndexedDataVector::GetDataVector() const -{ - return m_data; -} - -template -IndexType IndexedDataVector::GetRawIndex(IndexType index) const -{ - return m_indices.at(index); -} diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 40188109ca..e4a914ac34 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -38,7 +38,6 @@ set(FILES Include/Atom/Feature/Utils/FrameCaptureBus.h Include/Atom/Feature/Utils/GpuBufferHandler.h Include/Atom/Feature/Utils/IndexedDataVector.h - Include/Atom/Feature/Utils/IndexedDataVector.inl Include/Atom/Feature/Utils/MultiIndexedDataVector.h Include/Atom/Feature/Utils/MultiSparseVector.h Include/Atom/Feature/Utils/ProfilingCaptureBus.h From 78760245c5a96d81881ccc2b800c2a58390a3a5c Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Wed, 28 Jul 2021 15:26:41 -0600 Subject: [PATCH 096/157] Remove one level of indentation Signed-off-by: Jeremy Ong --- .../Atom/Feature/Utils/IndexedDataVector.h | 267 +++++++++--------- 1 file changed, 132 insertions(+), 135 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h index a73ba2f16b..9231813d36 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h @@ -8,160 +8,157 @@ #pragma once -#include #include +#include -namespace AZ +namespace AZ::Render { - namespace Render + // Growable vector that leverages indirection to support erasure of elements while maintaining + // resident data in a densely packed region of memory. Useful as a backing store for growable + // buffers intended to be uploaded to the GPU for example. + template + class IndexedDataVector { - // Growable vector that leverages indirection to support erasure of elements while maintaining - // resident data in a densely packed region of memory. Useful as a backing store for growable - // buffers intended to be uploaded to the GPU for example. - template - class IndexedDataVector - { - public: - IndexedDataVector(); - explicit IndexedDataVector(size_t initialReservedSize); - ~IndexedDataVector() = default; - - static constexpr IndexType NoFreeSlot = std::numeric_limits::max(); - IndexType m_firstFreeSlot = NoFreeSlot; - - void Clear(); - IndexType GetFreeSlotIndex(); - void RemoveIndex(IndexType index); - - DataType& GetData(IndexType index); - const DataType& GetData(IndexType index) const; - size_t GetDataCount() const; - - AZStd::vector& GetDataVector(); - const AZStd::vector& GetDataVector() const; - - IndexType GetRawIndex(IndexType index) const; - - private: - constexpr static size_t InitialReservedSize = 128; - - // Stores data indices and an embedded free list - AZStd::vector m_indices; - // Stores the indirection index - AZStd::vector m_dataToIndices; - AZStd::vector m_data; - }; - - template - inline IndexedDataVector::IndexedDataVector() - : IndexedDataVector(InitialReservedSize) + public: + IndexedDataVector(); + explicit IndexedDataVector(size_t initialReservedSize); + ~IndexedDataVector() = default; + + static constexpr IndexType NoFreeSlot = std::numeric_limits::max(); + IndexType m_firstFreeSlot = NoFreeSlot; + + void Clear(); + IndexType GetFreeSlotIndex(); + void RemoveIndex(IndexType index); + + DataType& GetData(IndexType index); + const DataType& GetData(IndexType index) const; + size_t GetDataCount() const; + + AZStd::vector& GetDataVector(); + const AZStd::vector& GetDataVector() const; + + IndexType GetRawIndex(IndexType index) const; + + private: + constexpr static size_t InitialReservedSize = 128; + + // Stores data indices and an embedded free list + AZStd::vector m_indices; + // Stores the indirection index + AZStd::vector m_dataToIndices; + AZStd::vector m_data; + }; + + template + inline IndexedDataVector::IndexedDataVector() + : IndexedDataVector(InitialReservedSize) + { + } + + template + inline IndexedDataVector::IndexedDataVector(size_t initialReservedSize) + { + m_dataToIndices.reserve(initialReservedSize); + m_indices.reserve(initialReservedSize); + m_data.reserve(initialReservedSize); + } + + template + inline void IndexedDataVector::Clear() + { + m_dataToIndices.clear(); + m_indices.clear(); + m_data.clear(); + + m_firstFreeSlot = NoFreeSlot; + } + + template + inline IndexType IndexedDataVector::GetFreeSlotIndex() + { + IndexType freeSlotIndex = static_cast(m_indices.size()); + + if (freeSlotIndex == NoFreeSlot) { + // the vector is full + return NoFreeSlot; } - template - inline IndexedDataVector::IndexedDataVector(size_t initialReservedSize) + if (m_firstFreeSlot == NoFreeSlot) { - m_dataToIndices.reserve(initialReservedSize); - m_indices.reserve(initialReservedSize); - m_data.reserve(initialReservedSize); + // If there's no free slot, add on to the end. + m_indices.push_back(freeSlotIndex); + } + else + { + // Fill the free slot. m_indices uses it's empty slots to store a linked list (via indices) to other empty slots. + freeSlotIndex = m_firstFreeSlot; + m_firstFreeSlot = m_indices.at(m_firstFreeSlot); + m_indices.at(freeSlotIndex) = static_cast(m_data.size()); } - template - inline void IndexedDataVector::Clear() - { - m_dataToIndices.clear(); - m_indices.clear(); - m_data.clear(); + // The data itself is always packed and m_indices points at it, so push a new entry to the back. + m_data.push_back(DataType()); + m_dataToIndices.push_back(freeSlotIndex); - m_firstFreeSlot = NoFreeSlot; - } + return freeSlotIndex; + } - template - inline IndexType IndexedDataVector::GetFreeSlotIndex() - { - IndexType freeSlotIndex = static_cast(m_indices.size()); + template + inline void IndexedDataVector::RemoveIndex(IndexType index) + { + IndexType dataIndex = m_indices.at(index); - if (freeSlotIndex == NoFreeSlot) - { - // the vector is full - return NoFreeSlot; - } + // Copy the back light on top of this one. + m_data.at(dataIndex) = m_data.back(); + m_dataToIndices.at(dataIndex) = m_dataToIndices.back(); - if (m_firstFreeSlot == NoFreeSlot) - { - // If there's no free slot, add on to the end. - m_indices.push_back(freeSlotIndex); - } - else - { - // Fill the free slot. m_indices uses it's empty slots to store a linked list (via indices) to other empty slots. - freeSlotIndex = m_firstFreeSlot; - m_firstFreeSlot = m_indices.at(m_firstFreeSlot); - m_indices.at(freeSlotIndex) = static_cast(m_data.size()); - } + // Update the index of the moved light + m_indices.at(m_dataToIndices.at(dataIndex)) = dataIndex; - // The data itself is always packed and m_indices points at it, so push a new entry to the back. - m_data.push_back(DataType()); - m_dataToIndices.push_back(freeSlotIndex); + // Pop the back + m_data.pop_back(); + m_dataToIndices.pop_back(); - return freeSlotIndex; - } + // Use free slot to link to next free slot + m_indices.at(index) = m_firstFreeSlot; + m_firstFreeSlot = index; + } - template - inline void IndexedDataVector::RemoveIndex(IndexType index) - { - IndexType dataIndex = m_indices.at(index); + template + inline DataType& IndexedDataVector::GetData(IndexType index) + { + return m_data.at(m_indices.at(index)); + } - // Copy the back light on top of this one. - m_data.at(dataIndex) = m_data.back(); - m_dataToIndices.at(dataIndex) = m_dataToIndices.back(); + template + inline const DataType& IndexedDataVector::GetData(IndexType index) const + { + return m_data.at(m_indices.at(index)); + } - // Update the index of the moved light - m_indices.at(m_dataToIndices.at(dataIndex)) = dataIndex; + template + inline size_t IndexedDataVector::GetDataCount() const + { + return m_data.size(); + } - // Pop the back - m_data.pop_back(); - m_dataToIndices.pop_back(); + template + inline AZStd::vector& IndexedDataVector::GetDataVector() + { + return m_data; + } - // Use free slot to link to next free slot - m_indices.at(index) = m_firstFreeSlot; - m_firstFreeSlot = index; - } + template + inline const AZStd::vector& IndexedDataVector::GetDataVector() const + { + return m_data; + } - template - inline DataType& IndexedDataVector::GetData(IndexType index) - { - return m_data.at(m_indices.at(index)); - } - - template - inline const DataType& IndexedDataVector::GetData(IndexType index) const - { - return m_data.at(m_indices.at(index)); - } - - template - inline size_t IndexedDataVector::GetDataCount() const - { - return m_data.size(); - } - - template - inline AZStd::vector& IndexedDataVector::GetDataVector() - { - return m_data; - } - - template - inline const AZStd::vector& IndexedDataVector::GetDataVector() const - { - return m_data; - } - - template - IndexType IndexedDataVector::GetRawIndex(IndexType index) const - { - return m_indices.at(index); - } - } // namespace Render -} // namespace AZ + template + IndexType IndexedDataVector::GetRawIndex(IndexType index) const + { + return m_indices.at(index); + } +} // namespace AZ::Render From 68a7a21e62f31633b3ab0f7b0c7f0476188549f4 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Sat, 31 Jul 2021 00:25:53 -0600 Subject: [PATCH 097/157] Reintroduce .h and .inl split Signed-off-by: Jeremy Ong --- .../Atom/Feature/Utils/IndexedDataVector.h | 117 +-------------- .../Atom/Feature/Utils/IndexedDataVector.inl | 134 ++++++++++++++++++ .../Code/atom_feature_common_files.cmake | 1 + 3 files changed, 140 insertions(+), 112 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h index 9231813d36..37835bd6a8 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.h @@ -38,6 +38,9 @@ namespace AZ::Render AZStd::vector& GetDataVector(); const AZStd::vector& GetDataVector() const; + AZStd::vector& GetIndexVector(); + const AZStd::vector& GetIndexVector() const; + IndexType GetRawIndex(IndexType index) const; private: @@ -49,116 +52,6 @@ namespace AZ::Render AZStd::vector m_dataToIndices; AZStd::vector m_data; }; - - template - inline IndexedDataVector::IndexedDataVector() - : IndexedDataVector(InitialReservedSize) - { - } - - template - inline IndexedDataVector::IndexedDataVector(size_t initialReservedSize) - { - m_dataToIndices.reserve(initialReservedSize); - m_indices.reserve(initialReservedSize); - m_data.reserve(initialReservedSize); - } - - template - inline void IndexedDataVector::Clear() - { - m_dataToIndices.clear(); - m_indices.clear(); - m_data.clear(); - - m_firstFreeSlot = NoFreeSlot; - } - - template - inline IndexType IndexedDataVector::GetFreeSlotIndex() - { - IndexType freeSlotIndex = static_cast(m_indices.size()); - - if (freeSlotIndex == NoFreeSlot) - { - // the vector is full - return NoFreeSlot; - } - - if (m_firstFreeSlot == NoFreeSlot) - { - // If there's no free slot, add on to the end. - m_indices.push_back(freeSlotIndex); - } - else - { - // Fill the free slot. m_indices uses it's empty slots to store a linked list (via indices) to other empty slots. - freeSlotIndex = m_firstFreeSlot; - m_firstFreeSlot = m_indices.at(m_firstFreeSlot); - m_indices.at(freeSlotIndex) = static_cast(m_data.size()); - } - - // The data itself is always packed and m_indices points at it, so push a new entry to the back. - m_data.push_back(DataType()); - m_dataToIndices.push_back(freeSlotIndex); - - return freeSlotIndex; - } - - template - inline void IndexedDataVector::RemoveIndex(IndexType index) - { - IndexType dataIndex = m_indices.at(index); - - // Copy the back light on top of this one. - m_data.at(dataIndex) = m_data.back(); - m_dataToIndices.at(dataIndex) = m_dataToIndices.back(); - - // Update the index of the moved light - m_indices.at(m_dataToIndices.at(dataIndex)) = dataIndex; - - // Pop the back - m_data.pop_back(); - m_dataToIndices.pop_back(); - - // Use free slot to link to next free slot - m_indices.at(index) = m_firstFreeSlot; - m_firstFreeSlot = index; - } - - template - inline DataType& IndexedDataVector::GetData(IndexType index) - { - return m_data.at(m_indices.at(index)); - } - - template - inline const DataType& IndexedDataVector::GetData(IndexType index) const - { - return m_data.at(m_indices.at(index)); - } - - template - inline size_t IndexedDataVector::GetDataCount() const - { - return m_data.size(); - } - - template - inline AZStd::vector& IndexedDataVector::GetDataVector() - { - return m_data; - } - - template - inline const AZStd::vector& IndexedDataVector::GetDataVector() const - { - return m_data; - } - - template - IndexType IndexedDataVector::GetRawIndex(IndexType index) const - { - return m_indices.at(index); - } } // namespace AZ::Render + +#include diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl new file mode 100644 index 0000000000..076caad7f4 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/IndexedDataVector.inl @@ -0,0 +1,134 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +namespace AZ::Render +{ + template + inline IndexedDataVector::IndexedDataVector() + : IndexedDataVector(InitialReservedSize) + { + } + + template + inline IndexedDataVector::IndexedDataVector(size_t initialReservedSize) + { + m_dataToIndices.reserve(initialReservedSize); + m_indices.reserve(initialReservedSize); + m_data.reserve(initialReservedSize); + } + + template + inline void IndexedDataVector::Clear() + { + m_dataToIndices.clear(); + m_indices.clear(); + m_data.clear(); + + m_firstFreeSlot = NoFreeSlot; + } + + template + inline IndexType IndexedDataVector::GetFreeSlotIndex() + { + IndexType freeSlotIndex = static_cast(m_indices.size()); + + if (freeSlotIndex == NoFreeSlot) + { + // the vector is full + return NoFreeSlot; + } + + if (m_firstFreeSlot == NoFreeSlot) + { + // If there's no free slot, add on to the end. + m_indices.push_back(freeSlotIndex); + } + else + { + // Fill the free slot. m_indices uses it's empty slots to store a linked list (via indices) to other empty slots. + freeSlotIndex = m_firstFreeSlot; + m_firstFreeSlot = m_indices.at(m_firstFreeSlot); + m_indices.at(freeSlotIndex) = static_cast(m_data.size()); + } + + // The data itself is always packed and m_indices points at it, so push a new entry to the back. + m_data.push_back(DataType()); + m_dataToIndices.push_back(freeSlotIndex); + + return freeSlotIndex; + } + + template + inline void IndexedDataVector::RemoveIndex(IndexType index) + { + IndexType dataIndex = m_indices.at(index); + + // Copy the back light on top of this one. + m_data.at(dataIndex) = m_data.back(); + m_dataToIndices.at(dataIndex) = m_dataToIndices.back(); + + // Update the index of the moved light + m_indices.at(m_dataToIndices.at(dataIndex)) = dataIndex; + + // Pop the back + m_data.pop_back(); + m_dataToIndices.pop_back(); + + // Use free slot to link to next free slot + m_indices.at(index) = m_firstFreeSlot; + m_firstFreeSlot = index; + } + + template + inline DataType& IndexedDataVector::GetData(IndexType index) + { + return m_data.at(m_indices.at(index)); + } + + template + inline const DataType& IndexedDataVector::GetData(IndexType index) const + { + return m_data.at(m_indices.at(index)); + } + + template + inline size_t IndexedDataVector::GetDataCount() const + { + return m_data.size(); + } + + template + inline AZStd::vector& IndexedDataVector::GetDataVector() + { + return m_data; + } + + template + inline const AZStd::vector& IndexedDataVector::GetDataVector() const + { + return m_data; + } + + template + inline AZStd::vector& IndexedDataVector::GetIndexVector() + { + return m_dataToIndices; + } + + template + inline const AZStd::vector& IndexedDataVector::GetIndexVector() const + { + return m_dataToIndices; + } + + template + IndexType IndexedDataVector::GetRawIndex(IndexType index) const + { + return m_indices.at(index); + } +} // namespace AZ::Render diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index e4a914ac34..40188109ca 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -38,6 +38,7 @@ set(FILES Include/Atom/Feature/Utils/FrameCaptureBus.h Include/Atom/Feature/Utils/GpuBufferHandler.h Include/Atom/Feature/Utils/IndexedDataVector.h + Include/Atom/Feature/Utils/IndexedDataVector.inl Include/Atom/Feature/Utils/MultiIndexedDataVector.h Include/Atom/Feature/Utils/MultiSparseVector.h Include/Atom/Feature/Utils/ProfilingCaptureBus.h From b46a80be2cd3313dae12c387918ec955406be533 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Sat, 31 Jul 2021 08:42:02 -0700 Subject: [PATCH 098/157] Fix for Linux/Vulkan/Editor crash on startup * Temporary fix for Linux/Vulkan/XCB where the swap chain is not ready to present until the resize is complete * Fix invalid GUID from LinuxXcbConnectionManager Signed-off-by: spham-amzn --- .../Linux/AzFramework/API/ApplicationAPI_Linux.h | 2 +- Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h | 9 +++++++++ Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp | 4 ++++ Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp | 9 +++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h b/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h index 03c65ce0c3..9b57d1d49e 100644 --- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h @@ -35,7 +35,7 @@ namespace AzFramework class LinuxXcbConnectionManager { public: - AZ_RTTI(LinuxXcbConnectionManager, "{649951316-3626-4C9D-9DCA-2E7ABF84C0A9}"); + AZ_RTTI(LinuxXcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}"); virtual ~LinuxXcbConnectionManager() = default; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h index 14e9968e42..c1fd4453d4 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h @@ -81,6 +81,15 @@ namespace AZ AZ_RTTI(SwapChain, "{888B64A5-D956-406F-9C33-CF6A54FC41B0}", Object); +#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB) + // On Linux platforms that uses XCB, a resize may occur in the swap chain but the command queue may still + // reference the original surface. This flag is a temporary fix to make sure that all the swap chains + // have finished their resize events before presenting the command queue. + + // [GFX TODO][GHI - 2678] + AZStd::atomic_bool m_resized{ false }; +#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB + protected: SwapChain(); diff --git a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp index b0501d937d..5fbb83fccf 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp @@ -164,6 +164,10 @@ namespace AZ m_currentImageIndex = 0; } +#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB) + m_resized.store(true); +#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB + return resultCode; } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp index ca6c829cca..84b4964235 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandQueue.cpp @@ -42,6 +42,15 @@ namespace AZ void CommandQueue::ExecuteWork(const RHI::ExecuteWorkRequest& rhiRequest) { +#if defined(PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB) + for (RHI::SwapChain* swapChain : rhiRequest.m_swapChainsToPresent) + { + if (!swapChain->m_resized) + { + return; + } + } +#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB const ExecuteWorkRequest& request = static_cast(rhiRequest); QueueCommand([=](void* queue) { From f9303a2eaa1b1efb9cf25be57e7e3b3cdc42465a Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Sat, 31 Jul 2021 17:22:51 -0600 Subject: [PATCH 099/157] Add runtime RenderDoc support for Windows dx12/vulkan via --enableRenderDoc option - RenderDoc is disabled when building the monolithic build - The installation path is inferred on Windows, but may be overridden on Windows/Linux via the ATOM_RENDERDOC_PATH environment variable - Linux support may work, but I have no means to test it - Android support shouldn't be difficult to add, but requires a renderdoc_android.cmake file that understands how the RenderDoc package is distributed as part of the Android toolchain Signed-off-by: Jeremy Ong --- Gems/Atom/RHI/Code/CMakeLists.txt | 23 +++++++ Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h | 26 +++++++- .../Atom/RHI/Code/Include/Atom/RHI/RHIUtils.h | 3 + .../Code/Platform/Linux/renderdoc_linux.cmake | 36 ++++++++++ .../Platform/Windows/renderdoc_windows.cmake | 38 +++++++++++ Gems/Atom/RHI/Code/Source/RHI/Factory.cpp | 65 +++++++++++++++++++ Gems/Atom/RHI/Code/Source/RHI/RHIUtils.cpp | 12 ++++ 7 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 Gems/Atom/RHI/Code/Platform/Linux/renderdoc_linux.cmake create mode 100644 Gems/Atom/RHI/Code/Platform/Windows/renderdoc_windows.cmake diff --git a/Gems/Atom/RHI/Code/CMakeLists.txt b/Gems/Atom/RHI/Code/CMakeLists.txt index 8e1ae3bdf0..82b80e5151 100644 --- a/Gems/Atom/RHI/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Code/CMakeLists.txt @@ -10,6 +10,23 @@ ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${P include(${pal_dir}/AtomRHITests_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +set(RENDERDOC_CMAKE ${CMAKE_CURRENT_SOURCE_DIR}/${pal_dir}/renderdoc_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +if(EXISTS ${RENDERDOC_CMAKE}) + include(${RENDERDOC_CMAKE}) +endif() + +if(TARGET "3rdParty::renderdoc") + message(STATUS "Renderdoc found") + set(USE_RENDERDOC_DEFINE "USE_RENDERDOC") + set(RENDERDOC_BUILD_DEPENDENCY "3rdParty::renderdoc") + set(RENDERDOC_API_DEPENDENCY "3rdParty::renderdoc_api") +else() + message(STATUS "Renderdoc missing") + set(USE_RENDERDOC_DEFINE "") + set(RENDERDOC_BUILD_DEPENDENCY "") + set(RENDERDOC_API_DEPENDENCY "") +endif() + ly_add_target( NAME Atom_RHI.Reflect STATIC NAMESPACE Gem @@ -43,6 +60,12 @@ ly_add_target( AZ::AzCore AZ::AzFramework Gem::Atom_RHI.Reflect + ${RENDERDOC_BUILD_DEPENDENCY} + PUBLIC + ${RENDERDOC_API_DEPENDENCY} + COMPILE_DEFINITIONS + PUBLIC + ${USE_RENDERDOC_DEFINE} ) ly_add_target( diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h index a9f9120e8d..24f09c6580 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h @@ -11,6 +11,11 @@ #include #include +#if defined(USE_RENDERDOC) +#include +#include +#endif + namespace AZ { namespace RHI @@ -66,7 +71,7 @@ namespace AZ public: AZ_TYPE_INFO(Factory, "{2C0231FD-DD11-4154-A4F5-177181E26D8E}"); - Factory() = default; + Factory(); virtual ~Factory() = default; // Note that you have to delete these for safety reasons, you will trip a static_assert if you do not @@ -93,6 +98,25 @@ namespace AZ /// Access the global factory instance. static Factory& Get(); +#if defined(USE_RENDERDOC) +#if defined(AZ_PLATFORM_WINDOWS) + static const char* RENDERDOC_MODULE = "renderdoc.dll"; +#elif defined(AZ_PLATFORM_LINUX) + static const char* RENDERDOC_MODULE = "librenderdoc.so"; +#elif defined(AZ_PLATFORM_ANDROID) + static const char* RENDERDOC_MODULE = "libVkLayer_GLES_RenderDoc.so" +#else + static const char* RENDERDOC_MODULE = nullptr; +#endif + + /// Access the RenderDoc API pointer if available. + /// The availability of the render doc API at runtime depends on the following: + /// - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake) + /// - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable + /// - The module loaded successfully at runtime, and the API function pointer was retrieved successfully + static RENDERDOC_API_1_1_2* GetRenderDocAPI(); +#endif + /// Returns the name of the Factory. virtual Name GetName() = 0; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHIUtils.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHIUtils.h index 68d92a77bb..73e8e1ad56 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/RHIUtils.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/RHIUtils.h @@ -37,6 +37,9 @@ namespace AZ //! If multiple values exist it will return the last one AZStd::string GetCommandLineValue(const AZStd::string& commandLineOption); + //! Returns true if the command line option is set + bool QueryCommandLineOption(const AZStd::string& commandLineOption); + //! Returns if the current bakcend is a null renderer bool IsNullRenderer(); } diff --git a/Gems/Atom/RHI/Code/Platform/Linux/renderdoc_linux.cmake b/Gems/Atom/RHI/Code/Platform/Linux/renderdoc_linux.cmake new file mode 100644 index 0000000000..0faccf80ec --- /dev/null +++ b/Gems/Atom/RHI/Code/Platform/Linux/renderdoc_linux.cmake @@ -0,0 +1,36 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +# Prevent bundling the renderdoc dll with a packaged title +if(NOT LY_MONOLITHIC_GAME) + if(DEFINED ENV{"ATOM_RENDERDOC_PATH"}) + set(RENDERDOC_PATH ENV{"ATOM_RENDERDOC_PATH"}) + endif() + + if(RENDERDOC_PATH) + # Normalize file path + file(TO_CMAKE_PATH "${RENDERDOC_PATH}" RENDERDOC_PATH) + + if(EXISTS "${RENDERDOC_PATH}/librenderdoc.so") + ly_add_external_target( + NAME renderdoc + VERSION + 3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH} + INCLUDE_DIRECTORIES "." + RUNTIME_DEPENDENCIES "${RENDERDOC_PATH}/librenderdoc.so" + ) + + ly_add_external_target( + NAME renderdoc_api + VERSION + 3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH} + INCLUDE_DIRECTORIES "." + ) + endif() + endif() +endif() \ No newline at end of file diff --git a/Gems/Atom/RHI/Code/Platform/Windows/renderdoc_windows.cmake b/Gems/Atom/RHI/Code/Platform/Windows/renderdoc_windows.cmake new file mode 100644 index 0000000000..499321b2ab --- /dev/null +++ b/Gems/Atom/RHI/Code/Platform/Windows/renderdoc_windows.cmake @@ -0,0 +1,38 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +# Prevent bundling the renderdoc dll with a packaged title +if(NOT LY_MONOLITHIC_GAME) + # Common installation path for renderdoc path + set(RENDERDOC_PATH "C:/Program Files/RenderDoc") + if(DEFINED ENV{"ATOM_RENDERDOC_PATH"}) + set(RENDERDOC_PATH ENV{"ATOM_RENDERDOC_PATH"}) + endif() + + if(RENDERDOC_PATH) + # Normalize file path + file(TO_CMAKE_PATH "${RENDERDOC_PATH}" RENDERDOC_PATH) + + if(EXISTS "${RENDERDOC_PATH}/renderdoc.dll") + ly_add_external_target( + NAME renderdoc + VERSION + 3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH} + INCLUDE_DIRECTORIES "." + RUNTIME_DEPENDENCIES "${RENDERDOC_PATH}/renderdoc.dll" + ) + + ly_add_external_target( + NAME renderdoc_api + VERSION + 3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH} + INCLUDE_DIRECTORIES "." + ) + endif() + endif() +endif() \ No newline at end of file diff --git a/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp b/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp index 974d63f88b..8e4a96158f 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp @@ -11,6 +11,15 @@ #include #include +#if defined(USE_RENDERDOC) +#include +#include + +static AZStd::unique_ptr s_renderDocModule; +static RENDERDOC_API_1_1_2* s_renderDocApi = nullptr; +#endif + + namespace AZ { namespace RHI @@ -30,6 +39,48 @@ namespace AZ return AZ_CRC("RHIPlatformService", 0xfff2cea4); } + Factory::Factory() + { +#if defined(USE_RENDERDOC) + // If RenderDoc is requested, we need to load the library as early as possible (before device queries/factories are made) + bool enableRenderDoc = RHI::QueryCommandLineOption("enableRenderDoc"); + + if (enableRenderDoc && RENDERDOC_MODULE && !s_renderDocModule) + { + s_renderDocModule = DynamicModuleHandle::Create(RENDERDOC_MODULE); + if (s_renderDocModule) + { + if (s_renderDocModule->Load(false)) + { + pRENDERDOC_GetAPI renderDocGetAPI = s_renderDocModule->GetFunction("RENDERDOC_GetAPI"); + if (renderDocGetAPI) + { + if (!renderDocGetAPI(eRENDERDOC_API_Version_1_1_2, reinterpret_cast(&s_renderDocApi))) + { + s_renderDocApi = nullptr; + } + } + + if (s_renderDocApi) + { + // Prevent RenderDoc from handling any exceptions that may interfere with the O3DE exception handler + s_renderDocApi->UnloadCrashHandler(); + } + else + { + AZ_Printf("RHISystem", "RenderDoc module loaded but failed to retrieve API function pointer.\n"); + } + } + else + { + AZ_Printf("RHISystem", "RenderDoc module requested but module failed to load.\n"); + } + } + } +#endif // defined(USE_RENDERDOC) + + } + void Factory::Register(Factory* instance) { Interface::Register(instance); @@ -58,6 +109,13 @@ namespace AZ ResourceInvalidateBus::ClearQueuedEvents(); Interface::Unregister(instance); + +#if defined(USE_RENDERDOC) + if (s_renderDocModule) + { + s_renderDocModule->Unload(); + } +#endif } bool Factory::IsReady() @@ -71,5 +129,12 @@ namespace AZ AZ_Assert(factory, "RHI::Factory is not connected to a platform. Call IsReady() to get the status of the platform. A null de-reference is imminent."); return *factory; } + +#if defined(USE_RENDERDOC) + RENDERDOC_API_1_1_2* Factory::GetRenderDocAPI() + { + return s_renderDocApi; + } +#endif } } diff --git a/Gems/Atom/RHI/Code/Source/RHI/RHIUtils.cpp b/Gems/Atom/RHI/Code/Source/RHI/RHIUtils.cpp index 8df5e5b5be..bc4cde9406 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/RHIUtils.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/RHIUtils.cpp @@ -122,5 +122,17 @@ namespace AZ } return commandLineValue; } + + bool QueryCommandLineOption(const AZStd::string& commandLineOption) + { + const AzFramework::CommandLine* commandLine = nullptr; + AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetApplicationCommandLine); + + if (commandLine) + { + return commandLine->HasSwitch(commandLineOption); + } + return false; + } } } From b5895bc09bd8e7b6db1f6be45012127adfba8746 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Fri, 30 Jul 2021 18:46:56 -0500 Subject: [PATCH 100/157] Move most AZ::Job function bodies out of the header Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Jobs/Job.cpp | 309 +++++++++++++++++ Code/Framework/AzCore/AzCore/Jobs/Job.h | 324 +----------------- .../AzCore/AzCore/azcore_files.cmake | 1 + 3 files changed, 323 insertions(+), 311 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Jobs/Job.cpp diff --git a/Code/Framework/AzCore/AzCore/Jobs/Job.cpp b/Code/Framework/AzCore/AzCore/Jobs/Job.cpp new file mode 100644 index 0000000000..66493e193b --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Jobs/Job.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#include +#include +#include +#include +#include +#include + +AZ::Job::Job(bool isAutoDelete, AZ::JobContext* context, bool isCompletion, AZ::s8 priority) +{ + if (context) + { + m_context = context; + } + else + { + m_context = JobContext::GetParentContext(); + } + + unsigned int countAndFlags = 1; + if (isAutoDelete) + { + countAndFlags |= (unsigned int)FLAG_AUTO_DELETE; + } + if (isCompletion) + { + countAndFlags |= (unsigned int)FLAG_COMPLETION; + } + countAndFlags |= (unsigned int)((priority << FLAG_PRIORITY_START_BIT) & FLAG_PRIORITY_MASK); + SetDependentCountAndFlags(countAndFlags); + StoreDependent(NULL); + +#ifdef AZ_DEBUG_JOB_STATE + SetState(STATE_SETUP); +#endif // AZ_DEBUG_JOB_STATE +} + +void AZ::Job::Start() +{ + //jobs are created with a count set to 1, we remove that count to allow the job to start +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Jobs must be in the setup state before they can be started")); + SetState(STATE_STARTED); +#endif + DecrementDependentCount(); +} + +void AZ::Job::Reset(bool isClearDependent) +{ +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_PROCESSING), "Jobs must not be running when they are reset"); + SetState(STATE_SETUP); +#endif + unsigned int countAndFlags = GetDependentCountAndFlags(); + AZ_Assert((countAndFlags & (unsigned int)FLAG_AUTO_DELETE) == 0, "You can't call reset on AutoDelete jobs!"); + // Remove the FLAG_DEPENDENTCOUNT_MASK and FLAG_CHILD_JOBS flags + countAndFlags = (countAndFlags & (~(FLAG_DEPENDENTCOUNT_MASK) & ~(FLAG_CHILD_JOBS))) | 1; + SetDependentCountAndFlags(countAndFlags); + if (isClearDependent) + { + StoreDependent(NULL); + } + else + { + Job* dependent = GetDependent(); + if (dependent) + { +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in setup state before it can be re-initialized")); +#endif + dependent->IncrementDependentCount(); + } + } +} + +void AZ::Job::SetDependent(Job* dependent) +{ + AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); + AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in the setup state")); +#endif + dependent->IncrementDependentCount(); + StoreDependent(dependent); +} + +void AZ::Job::SetDependentStarted(Job* dependent) +{ + AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); + //We don't require the dependent to be in STATE_SETUP, the user can call this from a context where they + //know the dependent has not started yet, although it is in STATE_STARTED already, e.g. if SetDependent + //is called from a job which the dependent is already dependent on. + //Note that if the user gets this wrong, the dependent may start before this job is finished, and the asserts + //may not even trigger due to race conditions. Hence why this function is 'experts only'. + AZ_Assert((dependent->m_state == STATE_SETUP) || (dependent->m_state == STATE_STARTED) + || (dependent->m_state == STATE_SUSPENDED), "Dependent must be in the setup, started, or suspended state"); +#endif + dependent->IncrementDependentCount(); + StoreDependent(dependent); +} + +void AZ::Job::SetDependentChild(Job* dependent) +{ + AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); + AZ_Assert(dependent->m_state == STATE_PROCESSING, "Dependent must be processing to add a child"); +#endif + dependent->IncrementDependentCountAndSetChildFlag(); + StoreDependent(dependent); +} + +void AZ::Job::SetContinuation(Job* continuationJob) +{ +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_PROCESSING, "Continuation jobs can only be set while we are processing, otherwise a regular dependent should be used"); +#endif + Job* dependent = GetDependent(); + if (dependent) //nothing to do if there is no dependent... doesn't usually happen, except with synchronous processing and assists + { + continuationJob->SetDependentStarted(dependent); + } +} + +void AZ::Job::StartAsChild(Job* childJob) +{ +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_PROCESSING, "Child jobs can only be added while we are processing"); +#endif + childJob->SetDependentChild(this); + childJob->Start(); +} + +void AZ::Job::WaitForChildren() +{ +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_PROCESSING, "We must be currently processing in order to suspend"); +#endif + if (GetDependentCount() != 0) + { +#ifdef AZ_DEBUG_JOB_STATE + SetState(STATE_SUSPENDED); +#endif // AZ_DEBUG_JOB_STATE + m_context->GetJobManager().SuspendJobUntilReady(this); +#ifdef AZ_DEBUG_JOB_STATE + SetState(STATE_PROCESSING); +#endif // AZ_DEBUG_JOB_STATE + } + AZ_Assert(GetDependentCount() == 0, "Suspended job has resumed, but still has non-zero dependent count, bug in JobManager?"); +} + +bool AZ::Job::IsCancelled() const +{ + JobCancelGroup* cancelGroup = m_context->GetCancelGroup(); + if (cancelGroup && cancelGroup->IsCancelled()) + { + if (!IsCompletion()) // always run completion jobs, as they can be holding a synchronization primitive + { + return true; + } + } + return false; +} + +bool AZ::Job::IsAutoDelete() const +{ + return (GetDependentCountAndFlags() & (unsigned int)FLAG_AUTO_DELETE) ? true : false; +} + +bool AZ::Job::IsCompletion() const +{ + return (GetDependentCountAndFlags() & (unsigned int)FLAG_COMPLETION) ? true : false; +} + +void AZ::Job::StartAndAssistUntilComplete() +{ + m_context->GetJobManager().StartJobAndAssistUntilComplete(this); +} + +void AZ::Job::StartAndWaitForCompletion() +{ + //check if we are in a worker thread or a general user thread + Job* currentJob = m_context->GetJobManager().GetCurrentJob(); + if (currentJob) + { + //worker thread, so just suspend this current job until the empty job completes + currentJob->StartAsChild(this); + currentJob->WaitForChildren(); + } + else + { + StartAndAssistUntilComplete(); + } +} + +unsigned int AZ::Job::GetDependentCount() const +{ + return (GetDependentCountAndFlags() & FLAG_DEPENDENTCOUNT_MASK); +} + +void AZ::Job::IncrementDependentCount() +{ + AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); +#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS + ++m_dependentCountAndFlags; +#else + m_dependentCountAndFlags.fetch_add(1, AZStd::memory_order_acq_rel); +#endif +} + +void AZ::Job::IncrementDependentCountAndSetChildFlag() +{ + AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); +#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS + int oldCount = m_dependentCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; + m_dependentCountAndFlags = (m_dependentCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; +#else + //use a single atomic operation to increment the count and set the child flag if possible + unsigned int oldCountAndFlags, newCountAndFlags; + do + { + oldCountAndFlags = m_dependentCountAndFlags.load(AZStd::memory_order_acquire); + int oldCount = oldCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; + newCountAndFlags = (oldCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; + } while (!m_dependentCountAndFlags.compare_exchange_weak(oldCountAndFlags, newCountAndFlags, AZStd::memory_order_acq_rel, AZStd::memory_order_acquire)); +#endif +} + +void AZ::Job::DecrementDependentCount() +{ +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_STARTED) + || (m_state == STATE_PROCESSING) || (m_state == STATE_SUSPENDED), //child jobs + "Job dependent count should not be decremented after job is already pending"); +#endif + AZ_Assert(GetDependentCount() > 0, ("Job dependent count is already zero")); +#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS + unsigned int countAndFlags = m_dependentCountAndFlags--; +#else + unsigned int countAndFlags = m_dependentCountAndFlags.fetch_sub(1, AZStd::memory_order_acq_rel); +#endif + unsigned int count = countAndFlags & FLAG_DEPENDENTCOUNT_MASK; + if (count == 1) + { + if (!(countAndFlags & FLAG_CHILD_JOBS)) + { +#ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_STARTED, "Job has not been started but the dependent count is zero, must be a dependency error"); + SetState(STATE_PENDING); +#endif + m_context->GetJobManager().AddPendingJob(this); + } + } +} + +AZ::s8 AZ::Job::GetPriority() const +{ + return (GetDependentCountAndFlags() >> FLAG_PRIORITY_START_BIT) & 0xff; +} + +#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS +void AZ::Job::StoreDependent(Job* job) +{ + m_dependent = job; +} + +AZ::Job* AZ::Job::GetDependent() const +{ + return m_dependent; +} + +void AZ::Job::SetDependentCountAndFlags(unsigned int countAndFlags) +{ + m_dependentCountAndFlags = countAndFlags; +} + +unsigned int AZ::Job::GetDependentCountAndFlags() const +{ + return m_dependentCountAndFlags; +} +#else +void AZ::Job::StoreDependent(Job* job) +{ + m_dependent.store(job, AZStd::memory_order_release); +} + +AZ::Job* AZ::Job::GetDependent() const +{ + return m_dependent.load(AZStd::memory_order_acquire); +} + +void AZ::Job::SetDependentCountAndFlags(unsigned int countAndFlags) +{ + m_dependentCountAndFlags.store(countAndFlags, AZStd::memory_order_release); +} + +unsigned int AZ::Job::GetDependentCountAndFlags() const +{ + return m_dependentCountAndFlags.load(AZStd::memory_order_acquire); +} +#endif diff --git a/Code/Framework/AzCore/AzCore/Jobs/Job.h b/Code/Framework/AzCore/AzCore/Jobs/Job.h index 18c639e2c2..b6632dd063 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/Job.h +++ b/Code/Framework/AzCore/AzCore/Jobs/Job.h @@ -5,15 +5,14 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#ifndef AZCORE_JOBS_JOB_H -#define AZCORE_JOBS_JOB_H 1 - -#include -#include -#include -#include -#include +#pragma once +#include +#include +#include +#include +#include + #include #if defined(_DEBUG) @@ -234,319 +233,22 @@ namespace AZ //would require atomic ops to set/read it, so not really worth it. int m_state; }; - - //============================================================================================================ - //============================================================================================================ - //============================================================================================================ - - inline Job::Job(bool isAutoDelete, JobContext* context, bool isCompletion, AZ::s8 priority) - { - if (context) - { - m_context = context; - } - else - { - m_context = JobContext::GetParentContext(); - } - - unsigned int countAndFlags = 1; - if (isAutoDelete) - { - countAndFlags |= (unsigned int)FLAG_AUTO_DELETE; - } - if (isCompletion) - { - countAndFlags |= (unsigned int)FLAG_COMPLETION; - } - countAndFlags |= (unsigned int)((priority << FLAG_PRIORITY_START_BIT) & FLAG_PRIORITY_MASK); - SetDependentCountAndFlags(countAndFlags); - StoreDependent(NULL); - -#ifdef AZ_DEBUG_JOB_STATE - SetState(STATE_SETUP); -#endif // AZ_DEBUG_JOB_STATE - } - - AZ_FORCE_INLINE void Job::Start() - { - //jobs are created with a count set to 1, we remove that count to allow the job to start -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Jobs must be in the setup state before they can be started")); - SetState(STATE_STARTED); -#endif - DecrementDependentCount(); - } - - inline void Job::Reset(bool isClearDependent) - { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_PROCESSING), "Jobs must not be running when they are reset"); - SetState(STATE_SETUP); -#endif - unsigned int countAndFlags = GetDependentCountAndFlags(); - AZ_Assert((countAndFlags & (unsigned int)FLAG_AUTO_DELETE) == 0, "You can't call reset on AutoDelete jobs!"); - // Remove the FLAG_DEPENDENTCOUNT_MASK and FLAG_CHILD_JOBS flags - countAndFlags = (countAndFlags & (~(FLAG_DEPENDENTCOUNT_MASK) & ~(FLAG_CHILD_JOBS))) | 1; - SetDependentCountAndFlags(countAndFlags); - if (isClearDependent) - { - StoreDependent(NULL); - } - else - { - Job* dependent = GetDependent(); - if (dependent) - { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in setup state before it can be re-initialized")); -#endif - dependent->IncrementDependentCount(); - } - } - } - - AZ_FORCE_INLINE void Job::SetDependent(Job* dependent) - { - AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); - AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in the setup state")); -#endif - dependent->IncrementDependentCount(); - StoreDependent(dependent); - } - - AZ_FORCE_INLINE void Job::SetDependentStarted(Job* dependent) - { - AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); - //We don't require the dependent to be in STATE_SETUP, the user can call this from a context where they - //know the dependent has not started yet, although it is in STATE_STARTED already, e.g. if SetDependent - //is called from a job which the dependent is already dependent on. - //Note that if the user gets this wrong, the dependent may start before this job is finished, and the asserts - //may not even trigger due to race conditions. Hence why this function is 'experts only'. - AZ_Assert((dependent->m_state == STATE_SETUP) || (dependent->m_state == STATE_STARTED) - || (dependent->m_state == STATE_SUSPENDED), "Dependent must be in the setup, started, or suspended state"); -#endif - dependent->IncrementDependentCount(); - StoreDependent(dependent); - } - - AZ_FORCE_INLINE void Job::SetDependentChild(Job* dependent) - { - AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); - AZ_Assert(dependent->m_state == STATE_PROCESSING, "Dependent must be processing to add a child"); -#endif - dependent->IncrementDependentCountAndSetChildFlag(); - StoreDependent(dependent); - } - - AZ_FORCE_INLINE void Job::SetContinuation(Job* continuationJob) - { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_PROCESSING, "Continuation jobs can only be set while we are processing, otherwise a regular dependent should be used"); -#endif - Job* dependent = GetDependent(); - if (dependent) //nothing to do if there is no dependent... doesn't usually happen, except with synchronous processing and assists - { - continuationJob->SetDependentStarted(dependent); - } - } - - AZ_FORCE_INLINE void Job::StartAsChild(Job* childJob) - { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_PROCESSING, "Child jobs can only be added while we are processing"); -#endif - childJob->SetDependentChild(this); - childJob->Start(); - } - - AZ_FORCE_INLINE void Job::WaitForChildren() - { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_PROCESSING, "We must be currently processing in order to suspend"); -#endif - if (GetDependentCount() != 0) - { -#ifdef AZ_DEBUG_JOB_STATE - SetState(STATE_SUSPENDED); -#endif // AZ_DEBUG_JOB_STATE - m_context->GetJobManager().SuspendJobUntilReady(this); -#ifdef AZ_DEBUG_JOB_STATE - SetState(STATE_PROCESSING); -#endif // AZ_DEBUG_JOB_STATE - } - AZ_Assert(GetDependentCount() == 0, "Suspended job has resumed, but still has non-zero dependent count, bug in JobManager?"); - } - - AZ_FORCE_INLINE bool Job::IsCancelled() const - { - JobCancelGroup* cancelGroup = m_context->GetCancelGroup(); - if (cancelGroup && cancelGroup->IsCancelled()) - { - if (!IsCompletion()) // always run completion jobs, as they can be holding a synchronization primitive - { - return true; - } - } - return false; - } - - AZ_FORCE_INLINE bool Job::IsAutoDelete() const - { - return (GetDependentCountAndFlags() & (unsigned int)FLAG_AUTO_DELETE) ? true : false; - } - - AZ_FORCE_INLINE bool Job::IsCompletion() const - { - return (GetDependentCountAndFlags() & (unsigned int)FLAG_COMPLETION) ? true : false; - } - - AZ_FORCE_INLINE void Job::StartAndAssistUntilComplete() - { - m_context->GetJobManager().StartJobAndAssistUntilComplete(this); - } - - inline void Job::StartAndWaitForCompletion() - { - //check if we are in a worker thread or a general user thread - Job* currentJob = m_context->GetJobManager().GetCurrentJob(); - if (currentJob) - { - //worker thread, so just suspend this current job until the empty job completes - currentJob->StartAsChild(this); - currentJob->WaitForChildren(); - } - else - { - StartAndAssistUntilComplete(); - } - } - - AZ_FORCE_INLINE JobContext* Job::GetContext() const + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // Inline implementations + inline JobContext* Job::GetContext() const { return m_context; } - AZ_FORCE_INLINE unsigned int Job::GetDependentCount() const - { - return (GetDependentCountAndFlags() & FLAG_DEPENDENTCOUNT_MASK); - } - - AZ_FORCE_INLINE void Job::IncrementDependentCount() - { - AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); -#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS - ++m_dependentCountAndFlags; -#else - m_dependentCountAndFlags.fetch_add(1, AZStd::memory_order_acq_rel); -#endif - } - - inline void Job::IncrementDependentCountAndSetChildFlag() - { - AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); -#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS - int oldCount = m_dependentCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; - m_dependentCountAndFlags = (m_dependentCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; -#else - //use a single atomic operation to increment the count and set the child flag if possible - unsigned int oldCountAndFlags, newCountAndFlags; - do - { - oldCountAndFlags = m_dependentCountAndFlags.load(AZStd::memory_order_acquire); - int oldCount = oldCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; - newCountAndFlags = (oldCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; - } while (!m_dependentCountAndFlags.compare_exchange_weak(oldCountAndFlags, newCountAndFlags, AZStd::memory_order_acq_rel, AZStd::memory_order_acquire)); -#endif - } - - inline void Job::DecrementDependentCount() - { #ifdef AZ_DEBUG_JOB_STATE - AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_STARTED) - || (m_state == STATE_PROCESSING) || (m_state == STATE_SUSPENDED), //child jobs - "Job dependent count should not be decremented after job is already pending"); -#endif - AZ_Assert(GetDependentCount() > 0, ("Job dependent count is already zero")); -#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS - unsigned int countAndFlags = m_dependentCountAndFlags--; -#else - unsigned int countAndFlags = m_dependentCountAndFlags.fetch_sub(1, AZStd::memory_order_acq_rel); -#endif - unsigned int count = countAndFlags & FLAG_DEPENDENTCOUNT_MASK; - if (count == 1) - { - if (!(countAndFlags & FLAG_CHILD_JOBS)) - { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_STARTED, "Job has not been started but the dependent count is zero, must be a dependency error"); - SetState(STATE_PENDING); -#endif - m_context->GetJobManager().AddPendingJob(this); - } - } - } - - inline AZ::s8 Job::GetPriority() const - { - return (GetDependentCountAndFlags() >> FLAG_PRIORITY_START_BIT) & 0xff; - } - -#ifdef AZ_DEBUG_JOB_STATE - AZ_FORCE_INLINE void Job::SetState(int state) + inline void Job::SetState(int state) { m_state = state; } #endif -#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS - AZ_FORCE_INLINE void Job::StoreDependent(Job* job) - { - m_dependent = job; - } - AZ_FORCE_INLINE Job* Job::GetDependent() const - { - return m_dependent; - } - - AZ_FORCE_INLINE void Job::SetDependentCountAndFlags(unsigned int countAndFlags) - { - m_dependentCountAndFlags = countAndFlags; - } - - AZ_FORCE_INLINE unsigned int Job::GetDependentCountAndFlags() const - { - return m_dependentCountAndFlags; - } -#else - AZ_FORCE_INLINE void Job::StoreDependent(Job* job) - { - m_dependent.store(job, AZStd::memory_order_release); - } - - AZ_FORCE_INLINE Job* Job::GetDependent() const - { - return m_dependent.load(AZStd::memory_order_acquire); - } - - AZ_FORCE_INLINE void Job::SetDependentCountAndFlags(unsigned int countAndFlags) - { - m_dependentCountAndFlags.store(countAndFlags, AZStd::memory_order_release); - } - - AZ_FORCE_INLINE unsigned int Job::GetDependentCountAndFlags() const - { - return m_dependentCountAndFlags.load(AZStd::memory_order_acquire); - } -#endif } -#endif -#pragma once + diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 667ae49387..e3d2987a3c 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -221,6 +221,7 @@ set(FILES Jobs/Internal/JobManagerWorkStealing.cpp Jobs/Internal/JobManagerWorkStealing.h Jobs/Internal/JobNotify.h + Jobs/Job.cpp Jobs/Job.h Jobs/JobCancelGroup.h Jobs/JobCompletion.h From 06cef942a957d2805170b2c377561e4875365137 Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Sat, 31 Jul 2021 18:30:49 -0600 Subject: [PATCH 101/157] PALify RenderDoc module name Signed-off-by: Jeremy Ong --- Gems/Atom/RHI/Code/CMakeLists.txt | 3 +++ Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h | 11 ----------- .../Platform/Android/Atom_RHI_Traits_Android.h | 10 ++++++++++ .../Platform/Android/Atom_RHI_Traits_Platform.h | 10 ++++++++++ .../Platform/Android/platform_android_files.cmake | 12 ++++++++++++ .../Source/Platform/Linux/Atom_RHI_Traits_Linux.h | 10 ++++++++++ .../Source/Platform/Linux/Atom_RHI_Traits_Platform.h | 10 ++++++++++ .../Source/Platform/Linux/platform_linux_files.cmake | 12 ++++++++++++ .../Code/Source/Platform/Mac/Atom_RHI_Traits_Mac.h | 8 ++++++++ .../Source/Platform/Mac/Atom_RHI_Traits_Platform.h | 10 ++++++++++ .../Source/Platform/Mac/platform_mac_files.cmake | 12 ++++++++++++ .../Platform/Windows/Atom_RHI_Traits_Platform.h | 10 ++++++++++ .../Platform/Windows/Atom_RHI_Traits_Windows.h | 10 ++++++++++ .../Platform/Windows/platform_windows_files.cmake | 12 ++++++++++++ .../Source/Platform/iOS/Atom_RHI_Traits_Platform.h | 10 ++++++++++ .../Code/Source/Platform/iOS/Atom_RHI_Traits_iOS.h | 8 ++++++++ .../Source/Platform/iOS/platform_ios_files.cmake | 12 ++++++++++++ Gems/Atom/RHI/Code/Source/RHI/Factory.cpp | 5 +++-- 18 files changed, 162 insertions(+), 13 deletions(-) create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Android.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Platform.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Android/platform_android_files.cmake create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Linux.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Platform.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Linux/platform_linux_files.cmake create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Mac.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Platform.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Mac/platform_mac_files.cmake create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Platform.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Windows.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/Windows/platform_windows_files.cmake create mode 100644 Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_Platform.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_iOS.h create mode 100644 Gems/Atom/RHI/Code/Source/Platform/iOS/platform_ios_files.cmake diff --git a/Gems/Atom/RHI/Code/CMakeLists.txt b/Gems/Atom/RHI/Code/CMakeLists.txt index 82b80e5151..892216c53f 100644 --- a/Gems/Atom/RHI/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Code/CMakeLists.txt @@ -7,6 +7,7 @@ # ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) +ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) include(${pal_dir}/AtomRHITests_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) @@ -50,9 +51,11 @@ ly_add_target( NAMESPACE Gem FILES_CMAKE atom_rhi_public_files.cmake + ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake INCLUDE_DIRECTORIES PRIVATE Source + ${pal_source_dir} PUBLIC Include BUILD_DEPENDENCIES diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h index 24f09c6580..11f28e7a94 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h @@ -13,7 +13,6 @@ #if defined(USE_RENDERDOC) #include -#include #endif namespace AZ @@ -99,16 +98,6 @@ namespace AZ static Factory& Get(); #if defined(USE_RENDERDOC) -#if defined(AZ_PLATFORM_WINDOWS) - static const char* RENDERDOC_MODULE = "renderdoc.dll"; -#elif defined(AZ_PLATFORM_LINUX) - static const char* RENDERDOC_MODULE = "librenderdoc.so"; -#elif defined(AZ_PLATFORM_ANDROID) - static const char* RENDERDOC_MODULE = "libVkLayer_GLES_RenderDoc.so" -#else - static const char* RENDERDOC_MODULE = nullptr; -#endif - /// Access the RenderDoc API pointer if available. /// The availability of the render doc API at runtime depends on the following: /// - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake) diff --git a/Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Android.h b/Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Android.h new file mode 100644 index 0000000000..2f9b2b7c00 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Android.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AZ_TRAIT_RENDERDOC_MODULE "libVkLayer_GLES_RenderDoc.so" diff --git a/Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Platform.h b/Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Platform.h new file mode 100644 index 0000000000..6af80df81e --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Android/Atom_RHI_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include "Atom_RHI_Traits_Android.h" diff --git a/Gems/Atom/RHI/Code/Source/Platform/Android/platform_android_files.cmake b/Gems/Atom/RHI/Code/Source/Platform/Android/platform_android_files.cmake new file mode 100644 index 0000000000..167afec34d --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Android/platform_android_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Atom_RHI_Traits_Platform.h + Atom_RHI_Traits_Android.h +) diff --git a/Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Linux.h b/Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Linux.h new file mode 100644 index 0000000000..35219a5d57 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Linux.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AZ_TRAIT_RENDERDOC_MODULE "librenderdoc.so" diff --git a/Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Platform.h b/Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Platform.h new file mode 100644 index 0000000000..2c2c28a96f --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Linux/Atom_RHI_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include "Atom_RHI_Traits_Linux.h" diff --git a/Gems/Atom/RHI/Code/Source/Platform/Linux/platform_linux_files.cmake b/Gems/Atom/RHI/Code/Source/Platform/Linux/platform_linux_files.cmake new file mode 100644 index 0000000000..c31e71cd20 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Linux/platform_linux_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Atom_RHI_Traits_Platform.h + Atom_RHI_Traits_Linux.h +) diff --git a/Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Mac.h b/Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Mac.h new file mode 100644 index 0000000000..03320d1dd8 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Mac.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once diff --git a/Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Platform.h b/Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Platform.h new file mode 100644 index 0000000000..ae990ab471 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Mac/Atom_RHI_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include "Atom_RHI_Traits_Mac.h" diff --git a/Gems/Atom/RHI/Code/Source/Platform/Mac/platform_mac_files.cmake b/Gems/Atom/RHI/Code/Source/Platform/Mac/platform_mac_files.cmake new file mode 100644 index 0000000000..2d4ecd8b4f --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Mac/platform_mac_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Atom_RHI_Traits_Platform.h + Atom_RHI_Traits_Mac.h +) diff --git a/Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Platform.h b/Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Platform.h new file mode 100644 index 0000000000..6e19903677 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include "Atom_RHI_Traits_Windows.h" diff --git a/Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Windows.h b/Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Windows.h new file mode 100644 index 0000000000..82358784a3 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Windows/Atom_RHI_Traits_Windows.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#define AZ_TRAIT_RENDERDOC_MODULE "renderdoc.dll" diff --git a/Gems/Atom/RHI/Code/Source/Platform/Windows/platform_windows_files.cmake b/Gems/Atom/RHI/Code/Source/Platform/Windows/platform_windows_files.cmake new file mode 100644 index 0000000000..fc282d0163 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/Windows/platform_windows_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Atom_RHI_Traits_Platform.h + Atom_RHI_Traits_Windows.h +) diff --git a/Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_Platform.h b/Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_Platform.h new file mode 100644 index 0000000000..c39f94db8b --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_Platform.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include "Atom_RHI_Traits_iOS.h" diff --git a/Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_iOS.h b/Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_iOS.h new file mode 100644 index 0000000000..03320d1dd8 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/iOS/Atom_RHI_Traits_iOS.h @@ -0,0 +1,8 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once diff --git a/Gems/Atom/RHI/Code/Source/Platform/iOS/platform_ios_files.cmake b/Gems/Atom/RHI/Code/Source/Platform/iOS/platform_ios_files.cmake new file mode 100644 index 0000000000..d487385fa6 --- /dev/null +++ b/Gems/Atom/RHI/Code/Source/Platform/iOS/platform_ios_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Atom_RHI_Traits_Platform.h + Atom_RHI_Traits_iOS.h +) diff --git a/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp b/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp index 8e4a96158f..3162a71e34 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp @@ -14,6 +14,7 @@ #if defined(USE_RENDERDOC) #include #include +#include static AZStd::unique_ptr s_renderDocModule; static RENDERDOC_API_1_1_2* s_renderDocApi = nullptr; @@ -45,9 +46,9 @@ namespace AZ // If RenderDoc is requested, we need to load the library as early as possible (before device queries/factories are made) bool enableRenderDoc = RHI::QueryCommandLineOption("enableRenderDoc"); - if (enableRenderDoc && RENDERDOC_MODULE && !s_renderDocModule) + if (enableRenderDoc && AZ_TRAIT_RENDERDOC_MODULE && !s_renderDocModule) { - s_renderDocModule = DynamicModuleHandle::Create(RENDERDOC_MODULE); + s_renderDocModule = DynamicModuleHandle::Create(AZ_TRAIT_RENDERDOC_MODULE); if (s_renderDocModule) { if (s_renderDocModule->Load(false)) From af0d7575560afe90991f27bc797bf8f5d014d29f Mon Sep 17 00:00:00 2001 From: Jeremy Ong Date: Mon, 2 Aug 2021 09:50:24 -0600 Subject: [PATCH 102/157] Remove CMake status message when not compiling with RenderDoc Signed-off-by: Jeremy Ong --- Gems/Atom/RHI/Code/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Atom/RHI/Code/CMakeLists.txt b/Gems/Atom/RHI/Code/CMakeLists.txt index 892216c53f..eeb8f73bac 100644 --- a/Gems/Atom/RHI/Code/CMakeLists.txt +++ b/Gems/Atom/RHI/Code/CMakeLists.txt @@ -17,12 +17,11 @@ if(EXISTS ${RENDERDOC_CMAKE}) endif() if(TARGET "3rdParty::renderdoc") - message(STATUS "Renderdoc found") + message(STATUS "Renderdoc found, adding as runtime dependency") set(USE_RENDERDOC_DEFINE "USE_RENDERDOC") set(RENDERDOC_BUILD_DEPENDENCY "3rdParty::renderdoc") set(RENDERDOC_API_DEPENDENCY "3rdParty::renderdoc_api") else() - message(STATUS "Renderdoc missing") set(USE_RENDERDOC_DEFINE "") set(RENDERDOC_BUILD_DEPENDENCY "") set(RENDERDOC_API_DEPENDENCY "") From 8088e6662a2ff7036358b7d0dcf54271f6af7cbe Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Mon, 2 Aug 2021 11:15:31 -0500 Subject: [PATCH 103/157] modify new jobs.cpp file to match AzCore standard of opening namespace AZ rather than prepend AZ:: to every function Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Jobs/Job.cpp | 515 +++++++++++----------- 1 file changed, 259 insertions(+), 256 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/Job.cpp b/Code/Framework/AzCore/AzCore/Jobs/Job.cpp index 66493e193b..43e26767ae 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/Job.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/Job.cpp @@ -12,298 +12,301 @@ #include #include -AZ::Job::Job(bool isAutoDelete, AZ::JobContext* context, bool isCompletion, AZ::s8 priority) +namespace AZ { - if (context) + Job::Job(bool isAutoDelete, AZ::JobContext* context, bool isCompletion, AZ::s8 priority) { - m_context = context; - } - else - { - m_context = JobContext::GetParentContext(); - } + if (context) + { + m_context = context; + } + else + { + m_context = JobContext::GetParentContext(); + } - unsigned int countAndFlags = 1; - if (isAutoDelete) - { - countAndFlags |= (unsigned int)FLAG_AUTO_DELETE; - } - if (isCompletion) - { - countAndFlags |= (unsigned int)FLAG_COMPLETION; - } - countAndFlags |= (unsigned int)((priority << FLAG_PRIORITY_START_BIT) & FLAG_PRIORITY_MASK); - SetDependentCountAndFlags(countAndFlags); - StoreDependent(NULL); - -#ifdef AZ_DEBUG_JOB_STATE - SetState(STATE_SETUP); -#endif // AZ_DEBUG_JOB_STATE -} - -void AZ::Job::Start() -{ - //jobs are created with a count set to 1, we remove that count to allow the job to start -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Jobs must be in the setup state before they can be started")); - SetState(STATE_STARTED); -#endif - DecrementDependentCount(); -} - -void AZ::Job::Reset(bool isClearDependent) -{ -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_PROCESSING), "Jobs must not be running when they are reset"); - SetState(STATE_SETUP); -#endif - unsigned int countAndFlags = GetDependentCountAndFlags(); - AZ_Assert((countAndFlags & (unsigned int)FLAG_AUTO_DELETE) == 0, "You can't call reset on AutoDelete jobs!"); - // Remove the FLAG_DEPENDENTCOUNT_MASK and FLAG_CHILD_JOBS flags - countAndFlags = (countAndFlags & (~(FLAG_DEPENDENTCOUNT_MASK) & ~(FLAG_CHILD_JOBS))) | 1; - SetDependentCountAndFlags(countAndFlags); - if (isClearDependent) - { + unsigned int countAndFlags = 1; + if (isAutoDelete) + { + countAndFlags |= (unsigned int)FLAG_AUTO_DELETE; + } + if (isCompletion) + { + countAndFlags |= (unsigned int)FLAG_COMPLETION; + } + countAndFlags |= (unsigned int)((priority << FLAG_PRIORITY_START_BIT) & FLAG_PRIORITY_MASK); + SetDependentCountAndFlags(countAndFlags); StoreDependent(NULL); + + #ifdef AZ_DEBUG_JOB_STATE + SetState(STATE_SETUP); + #endif // AZ_DEBUG_JOB_STATE } - else + + void Job::Start() { + //jobs are created with a count set to 1, we remove that count to allow the job to start + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Jobs must be in the setup state before they can be started")); + SetState(STATE_STARTED); + #endif + DecrementDependentCount(); + } + + void Job::Reset(bool isClearDependent) + { + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_PROCESSING), "Jobs must not be running when they are reset"); + SetState(STATE_SETUP); + #endif + unsigned int countAndFlags = GetDependentCountAndFlags(); + AZ_Assert((countAndFlags & (unsigned int)FLAG_AUTO_DELETE) == 0, "You can't call reset on AutoDelete jobs!"); + // Remove the FLAG_DEPENDENTCOUNT_MASK and FLAG_CHILD_JOBS flags + countAndFlags = (countAndFlags & (~(FLAG_DEPENDENTCOUNT_MASK) & ~(FLAG_CHILD_JOBS))) | 1; + SetDependentCountAndFlags(countAndFlags); + if (isClearDependent) + { + StoreDependent(NULL); + } + else + { + Job* dependent = GetDependent(); + if (dependent) + { + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in setup state before it can be re-initialized")); + #endif + dependent->IncrementDependentCount(); + } + } + } + + void Job::SetDependent(Job* dependent) + { + AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); + AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in the setup state")); + #endif + dependent->IncrementDependentCount(); + StoreDependent(dependent); + } + + void Job::SetDependentStarted(Job* dependent) + { + AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); + //We don't require the dependent to be in STATE_SETUP, the user can call this from a context where they + //know the dependent has not started yet, although it is in STATE_STARTED already, e.g. if SetDependent + //is called from a job which the dependent is already dependent on. + //Note that if the user gets this wrong, the dependent may start before this job is finished, and the asserts + //may not even trigger due to race conditions. Hence why this function is 'experts only'. + AZ_Assert((dependent->m_state == STATE_SETUP) || (dependent->m_state == STATE_STARTED) + || (dependent->m_state == STATE_SUSPENDED), "Dependent must be in the setup, started, or suspended state"); + #endif + dependent->IncrementDependentCount(); + StoreDependent(dependent); + } + + void Job::SetDependentChild(Job* dependent) + { + AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); + AZ_Assert(dependent->m_state == STATE_PROCESSING, "Dependent must be processing to add a child"); + #endif + dependent->IncrementDependentCountAndSetChildFlag(); + StoreDependent(dependent); + } + + void Job::SetContinuation(Job* continuationJob) + { + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_PROCESSING, "Continuation jobs can only be set while we are processing, otherwise a regular dependent should be used"); + #endif Job* dependent = GetDependent(); - if (dependent) + if (dependent) //nothing to do if there is no dependent... doesn't usually happen, except with synchronous processing and assists { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in setup state before it can be re-initialized")); -#endif - dependent->IncrementDependentCount(); + continuationJob->SetDependentStarted(dependent); } } -} -void AZ::Job::SetDependent(Job* dependent) -{ - AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); - AZ_Assert(dependent->m_state == STATE_SETUP, ("Dependent must be in the setup state")); -#endif - dependent->IncrementDependentCount(); - StoreDependent(dependent); -} - -void AZ::Job::SetDependentStarted(Job* dependent) -{ - AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); - //We don't require the dependent to be in STATE_SETUP, the user can call this from a context where they - //know the dependent has not started yet, although it is in STATE_STARTED already, e.g. if SetDependent - //is called from a job which the dependent is already dependent on. - //Note that if the user gets this wrong, the dependent may start before this job is finished, and the asserts - //may not even trigger due to race conditions. Hence why this function is 'experts only'. - AZ_Assert((dependent->m_state == STATE_SETUP) || (dependent->m_state == STATE_STARTED) - || (dependent->m_state == STATE_SUSPENDED), "Dependent must be in the setup, started, or suspended state"); -#endif - dependent->IncrementDependentCount(); - StoreDependent(dependent); -} - -void AZ::Job::SetDependentChild(Job* dependent) -{ - AZ_Assert(!GetDependent(), ("Job already has a dependent, should be cleared after the job is done")); -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_SETUP, ("Dependent can only be set before the jobs are started")); - AZ_Assert(dependent->m_state == STATE_PROCESSING, "Dependent must be processing to add a child"); -#endif - dependent->IncrementDependentCountAndSetChildFlag(); - StoreDependent(dependent); -} - -void AZ::Job::SetContinuation(Job* continuationJob) -{ -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_PROCESSING, "Continuation jobs can only be set while we are processing, otherwise a regular dependent should be used"); -#endif - Job* dependent = GetDependent(); - if (dependent) //nothing to do if there is no dependent... doesn't usually happen, except with synchronous processing and assists + void Job::StartAsChild(Job* childJob) { - continuationJob->SetDependentStarted(dependent); + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_PROCESSING, "Child jobs can only be added while we are processing"); + #endif + childJob->SetDependentChild(this); + childJob->Start(); } -} -void AZ::Job::StartAsChild(Job* childJob) -{ -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_PROCESSING, "Child jobs can only be added while we are processing"); -#endif - childJob->SetDependentChild(this); - childJob->Start(); -} - -void AZ::Job::WaitForChildren() -{ -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_PROCESSING, "We must be currently processing in order to suspend"); -#endif - if (GetDependentCount() != 0) + void Job::WaitForChildren() { -#ifdef AZ_DEBUG_JOB_STATE - SetState(STATE_SUSPENDED); -#endif // AZ_DEBUG_JOB_STATE - m_context->GetJobManager().SuspendJobUntilReady(this); -#ifdef AZ_DEBUG_JOB_STATE - SetState(STATE_PROCESSING); -#endif // AZ_DEBUG_JOB_STATE - } - AZ_Assert(GetDependentCount() == 0, "Suspended job has resumed, but still has non-zero dependent count, bug in JobManager?"); -} - -bool AZ::Job::IsCancelled() const -{ - JobCancelGroup* cancelGroup = m_context->GetCancelGroup(); - if (cancelGroup && cancelGroup->IsCancelled()) - { - if (!IsCompletion()) // always run completion jobs, as they can be holding a synchronization primitive + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_PROCESSING, "We must be currently processing in order to suspend"); + #endif + if (GetDependentCount() != 0) { - return true; + #ifdef AZ_DEBUG_JOB_STATE + SetState(STATE_SUSPENDED); + #endif // AZ_DEBUG_JOB_STATE + m_context->GetJobManager().SuspendJobUntilReady(this); + #ifdef AZ_DEBUG_JOB_STATE + SetState(STATE_PROCESSING); + #endif // AZ_DEBUG_JOB_STATE + } + AZ_Assert(GetDependentCount() == 0, "Suspended job has resumed, but still has non-zero dependent count, bug in JobManager?"); + } + + bool Job::IsCancelled() const + { + JobCancelGroup* cancelGroup = m_context->GetCancelGroup(); + if (cancelGroup && cancelGroup->IsCancelled()) + { + if (!IsCompletion()) // always run completion jobs, as they can be holding a synchronization primitive + { + return true; + } + } + return false; + } + + bool Job::IsAutoDelete() const + { + return (GetDependentCountAndFlags() & (unsigned int)FLAG_AUTO_DELETE) ? true : false; + } + + bool Job::IsCompletion() const + { + return (GetDependentCountAndFlags() & (unsigned int)FLAG_COMPLETION) ? true : false; + } + + void Job::StartAndAssistUntilComplete() + { + m_context->GetJobManager().StartJobAndAssistUntilComplete(this); + } + + void Job::StartAndWaitForCompletion() + { + //check if we are in a worker thread or a general user thread + Job* currentJob = m_context->GetJobManager().GetCurrentJob(); + if (currentJob) + { + //worker thread, so just suspend this current job until the empty job completes + currentJob->StartAsChild(this); + currentJob->WaitForChildren(); + } + else + { + StartAndAssistUntilComplete(); } } - return false; -} -bool AZ::Job::IsAutoDelete() const -{ - return (GetDependentCountAndFlags() & (unsigned int)FLAG_AUTO_DELETE) ? true : false; -} - -bool AZ::Job::IsCompletion() const -{ - return (GetDependentCountAndFlags() & (unsigned int)FLAG_COMPLETION) ? true : false; -} - -void AZ::Job::StartAndAssistUntilComplete() -{ - m_context->GetJobManager().StartJobAndAssistUntilComplete(this); -} - -void AZ::Job::StartAndWaitForCompletion() -{ - //check if we are in a worker thread or a general user thread - Job* currentJob = m_context->GetJobManager().GetCurrentJob(); - if (currentJob) + unsigned int Job::GetDependentCount() const { - //worker thread, so just suspend this current job until the empty job completes - currentJob->StartAsChild(this); - currentJob->WaitForChildren(); + return (GetDependentCountAndFlags() & FLAG_DEPENDENTCOUNT_MASK); } - else + + void Job::IncrementDependentCount() { - StartAndAssistUntilComplete(); + AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); + #ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS + ++m_dependentCountAndFlags; + #else + m_dependentCountAndFlags.fetch_add(1, AZStd::memory_order_acq_rel); + #endif } -} -unsigned int AZ::Job::GetDependentCount() const -{ - return (GetDependentCountAndFlags() & FLAG_DEPENDENTCOUNT_MASK); -} - -void AZ::Job::IncrementDependentCount() -{ - AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); -#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS - ++m_dependentCountAndFlags; -#else - m_dependentCountAndFlags.fetch_add(1, AZStd::memory_order_acq_rel); -#endif -} - -void AZ::Job::IncrementDependentCountAndSetChildFlag() -{ - AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); -#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS - int oldCount = m_dependentCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; - m_dependentCountAndFlags = (m_dependentCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; -#else - //use a single atomic operation to increment the count and set the child flag if possible - unsigned int oldCountAndFlags, newCountAndFlags; - do + void Job::IncrementDependentCountAndSetChildFlag() { - oldCountAndFlags = m_dependentCountAndFlags.load(AZStd::memory_order_acquire); - int oldCount = oldCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; - newCountAndFlags = (oldCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; - } while (!m_dependentCountAndFlags.compare_exchange_weak(oldCountAndFlags, newCountAndFlags, AZStd::memory_order_acq_rel, AZStd::memory_order_acquire)); -#endif -} - -void AZ::Job::DecrementDependentCount() -{ -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_STARTED) - || (m_state == STATE_PROCESSING) || (m_state == STATE_SUSPENDED), //child jobs - "Job dependent count should not be decremented after job is already pending"); -#endif - AZ_Assert(GetDependentCount() > 0, ("Job dependent count is already zero")); -#ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS - unsigned int countAndFlags = m_dependentCountAndFlags--; -#else - unsigned int countAndFlags = m_dependentCountAndFlags.fetch_sub(1, AZStd::memory_order_acq_rel); -#endif - unsigned int count = countAndFlags & FLAG_DEPENDENTCOUNT_MASK; - if (count == 1) - { - if (!(countAndFlags & FLAG_CHILD_JOBS)) + AZ_Assert(GetDependentCount() < FLAG_DEPENDENTCOUNT_MASK, "Dependent count overflow"); + #ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS + int oldCount = m_dependentCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; + m_dependentCountAndFlags = (m_dependentCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; + #else + //use a single atomic operation to increment the count and set the child flag if possible + unsigned int oldCountAndFlags, newCountAndFlags; + do { -#ifdef AZ_DEBUG_JOB_STATE - AZ_Assert(m_state == STATE_STARTED, "Job has not been started but the dependent count is zero, must be a dependency error"); - SetState(STATE_PENDING); -#endif - m_context->GetJobManager().AddPendingJob(this); + oldCountAndFlags = m_dependentCountAndFlags.load(AZStd::memory_order_acquire); + int oldCount = oldCountAndFlags & FLAG_DEPENDENTCOUNT_MASK; + newCountAndFlags = (oldCountAndFlags & ~FLAG_DEPENDENTCOUNT_MASK) | (oldCount + 1) | FLAG_CHILD_JOBS; + } while (!m_dependentCountAndFlags.compare_exchange_weak(oldCountAndFlags, newCountAndFlags, AZStd::memory_order_acq_rel, AZStd::memory_order_acquire)); + #endif + } + + void Job::DecrementDependentCount() + { + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert((m_state == STATE_SETUP) || (m_state == STATE_STARTED) + || (m_state == STATE_PROCESSING) || (m_state == STATE_SUSPENDED), //child jobs + "Job dependent count should not be decremented after job is already pending"); + #endif + AZ_Assert(GetDependentCount() > 0, ("Job dependent count is already zero")); + #ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS + unsigned int countAndFlags = m_dependentCountAndFlags--; + #else + unsigned int countAndFlags = m_dependentCountAndFlags.fetch_sub(1, AZStd::memory_order_acq_rel); + #endif + unsigned int count = countAndFlags & FLAG_DEPENDENTCOUNT_MASK; + if (count == 1) + { + if (!(countAndFlags & FLAG_CHILD_JOBS)) + { + #ifdef AZ_DEBUG_JOB_STATE + AZ_Assert(m_state == STATE_STARTED, "Job has not been started but the dependent count is zero, must be a dependency error"); + SetState(STATE_PENDING); + #endif + m_context->GetJobManager().AddPendingJob(this); + } } } -} -AZ::s8 AZ::Job::GetPriority() const -{ - return (GetDependentCountAndFlags() >> FLAG_PRIORITY_START_BIT) & 0xff; -} + AZ::s8 Job::GetPriority() const + { + return (GetDependentCountAndFlags() >> FLAG_PRIORITY_START_BIT) & 0xff; + } #ifdef AZCORE_JOBS_IMPL_SYNCHRONOUS -void AZ::Job::StoreDependent(Job* job) -{ - m_dependent = job; -} + void Job::StoreDependent(Job* job) + { + m_dependent = job; + } -AZ::Job* AZ::Job::GetDependent() const -{ - return m_dependent; -} + Job* Job::GetDependent() const + { + return m_dependent; + } -void AZ::Job::SetDependentCountAndFlags(unsigned int countAndFlags) -{ - m_dependentCountAndFlags = countAndFlags; -} + void Job::SetDependentCountAndFlags(unsigned int countAndFlags) + { + m_dependentCountAndFlags = countAndFlags; + } -unsigned int AZ::Job::GetDependentCountAndFlags() const -{ - return m_dependentCountAndFlags; -} + unsigned int Job::GetDependentCountAndFlags() const + { + return m_dependentCountAndFlags; + } #else -void AZ::Job::StoreDependent(Job* job) -{ - m_dependent.store(job, AZStd::memory_order_release); -} + void Job::StoreDependent(Job* job) + { + m_dependent.store(job, AZStd::memory_order_release); + } -AZ::Job* AZ::Job::GetDependent() const -{ - return m_dependent.load(AZStd::memory_order_acquire); -} + Job* Job::GetDependent() const + { + return m_dependent.load(AZStd::memory_order_acquire); + } -void AZ::Job::SetDependentCountAndFlags(unsigned int countAndFlags) -{ - m_dependentCountAndFlags.store(countAndFlags, AZStd::memory_order_release); -} + void Job::SetDependentCountAndFlags(unsigned int countAndFlags) + { + m_dependentCountAndFlags.store(countAndFlags, AZStd::memory_order_release); + } -unsigned int AZ::Job::GetDependentCountAndFlags() const -{ - return m_dependentCountAndFlags.load(AZStd::memory_order_acquire); -} + unsigned int Job::GetDependentCountAndFlags() const + { + return m_dependentCountAndFlags.load(AZStd::memory_order_acquire); + } #endif +} \ No newline at end of file From 8014475abfdbacf83a874861cc7f00b66a465258 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 2 Aug 2021 11:28:04 -0500 Subject: [PATCH 104/157] Adding newline to the end of the new Job.cpp file Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Jobs/Job.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/Job.cpp b/Code/Framework/AzCore/AzCore/Jobs/Job.cpp index 43e26767ae..d3a2a77d92 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/Job.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/Job.cpp @@ -309,4 +309,4 @@ namespace AZ return m_dependentCountAndFlags.load(AZStd::memory_order_acquire); } #endif -} \ No newline at end of file +} From 37c3f01771aa28e49d2ae37084187a52e0b09b75 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 2 Aug 2021 12:27:03 -0500 Subject: [PATCH 105/157] Removed legacy ObjectIcons and shelve icons from Editor. Signed-off-by: Chris Galvan --- Assets/Editor/ObjectIcons/AreaTrigger.bmp | 3 -- .../Editor/ObjectIcons/AudioAreaAmbience.bmp | 3 -- Assets/Editor/ObjectIcons/AudioAreaEntity.bmp | 3 -- Assets/Editor/ObjectIcons/AudioAreaRandom.bmp | 3 -- Assets/Editor/ObjectIcons/Camera.bmp | 3 -- Assets/Editor/ObjectIcons/Checkpoint.bmp | 3 -- Assets/Editor/ObjectIcons/ClipVolume.bmp | 3 -- Assets/Editor/ObjectIcons/Clock.bmp | 3 -- Assets/Editor/ObjectIcons/Clouds.bmp | 3 -- Assets/Editor/ObjectIcons/Comment.bmp | 3 -- Assets/Editor/ObjectIcons/DeadBody.bmp | 3 -- Assets/Editor/ObjectIcons/Decal.bmp | 3 -- Assets/Editor/ObjectIcons/Dialog.bmp | 3 -- Assets/Editor/ObjectIcons/Flash.bmp | 3 -- Assets/Editor/ObjectIcons/Fog.bmp | 3 -- Assets/Editor/ObjectIcons/FogVolume.bmp | 3 -- Assets/Editor/ObjectIcons/GravitySphere.bmp | 3 -- Assets/Editor/ObjectIcons/Item.bmp | 3 -- Assets/Editor/ObjectIcons/Ladder.bmp | 3 -- Assets/Editor/ObjectIcons/Light.bmp | 3 -- .../ObjectIcons/LightPropagationVolume.bmp | 3 -- Assets/Editor/ObjectIcons/Lightning.bmp | 3 -- Assets/Editor/ObjectIcons/Magnet.bmp | 3 -- Assets/Editor/ObjectIcons/MultiTrigger.bmp | 3 -- Assets/Editor/ObjectIcons/ODD.bmp | 3 -- Assets/Editor/ObjectIcons/Particles.bmp | 3 -- Assets/Editor/ObjectIcons/PrecacheCamera.bmp | 3 -- Assets/Editor/ObjectIcons/Prefab.bmp | 3 -- Assets/Editor/ObjectIcons/Prompt.bmp | 3 -- Assets/Editor/ObjectIcons/SavePoint.bmp | 3 -- Assets/Editor/ObjectIcons/Seed.bmp | 3 -- Assets/Editor/ObjectIcons/Sound.bmp | 3 -- Assets/Editor/ObjectIcons/SpawnPoint.bmp | 3 -- Assets/Editor/ObjectIcons/T.bmp | 3 -- Assets/Editor/ObjectIcons/TagPoint.bmp | 3 -- Assets/Editor/ObjectIcons/Trigger.bmp | 3 -- .../Editor/ObjectIcons/UiCanvasRefEntity.bmp | 3 -- Assets/Editor/ObjectIcons/User.bmp | 3 -- Assets/Editor/ObjectIcons/VVVArea.bmp | 3 -- Assets/Editor/ObjectIcons/W.bmp | 3 -- Assets/Editor/ObjectIcons/Water.bmp | 3 -- Assets/Editor/ObjectIcons/animobject.bmp | 3 -- Assets/Editor/ObjectIcons/bird.bmp | 3 -- Assets/Editor/ObjectIcons/bug.bmp | 3 -- Assets/Editor/ObjectIcons/character.bmp | 3 -- Assets/Editor/ObjectIcons/death.bmp | 3 -- Assets/Editor/ObjectIcons/door.bmp | 3 -- Assets/Editor/ObjectIcons/elevator.bmp | 3 -- .../Editor/ObjectIcons/environmentProbe.bmp | 3 -- Assets/Editor/ObjectIcons/explosion.bmp | 3 -- Assets/Editor/ObjectIcons/fish.bmp | 3 -- Assets/Editor/ObjectIcons/forbiddenarea.bmp | 3 -- Assets/Editor/ObjectIcons/hazard.bmp | 3 -- Assets/Editor/ObjectIcons/health.bmp | 3 -- Assets/Editor/ObjectIcons/ledge.bmp | 3 -- Assets/Editor/ObjectIcons/mine.bmp | 3 -- Assets/Editor/ObjectIcons/physicsobject.bmp | 3 -- Assets/Editor/ObjectIcons/prefabbuilding.bmp | 3 -- .../Editor/ObjectIcons/proceduralbuilding.bmp | 3 -- .../Editor/ObjectIcons/proceduralobject.bmp | 3 -- .../Editor/ObjectIcons/proximitytrigger.bmp | 3 -- Assets/Editor/ObjectIcons/river.bmp | 3 -- Assets/Editor/ObjectIcons/road.bmp | 3 -- Assets/Editor/ObjectIcons/rope.bmp | 3 -- Assets/Editor/ObjectIcons/sequence.bmp | 3 -- Assets/Editor/ObjectIcons/shake.bmp | 3 -- Assets/Editor/ObjectIcons/smartobject.bmp | 3 -- Assets/Editor/ObjectIcons/spawngroup.bmp | 3 -- Assets/Editor/ObjectIcons/spectator.bmp | 3 -- Assets/Editor/ObjectIcons/switch.bmp | 3 -- Assets/Editor/ObjectIcons/territory.bmp | 3 -- Assets/Editor/ObjectIcons/tornado.bmp | 3 -- Assets/Editor/ObjectIcons/vehicle.bmp | 3 -- Assets/Editor/ObjectIcons/voxel.bmp | 3 -- Assets/Editor/ObjectIcons/wave.bmp | 3 -- .../Editor/Scripts/Shelves/icons/Albedo.png | 3 -- .../Shelves/icons/Diffuse_Lighting.png | 3 -- .../Shelves/icons/Diffuse_Texture_Res_360.png | 3 -- .../Scripts/Shelves/icons/Empty_Wireframe.png | 3 -- Assets/Editor/Scripts/Shelves/icons/Exit.png | 3 -- .../Scripts/Shelves/icons/Fuzziness.png | 3 -- Assets/Editor/Scripts/Shelves/icons/Gloss.png | 3 -- .../Shelves/icons/Normal_Texture_Res_360.png | 3 -- .../Shelves/icons/PrefabAddLibrary.png | 3 -- .../Shelves/icons/PrefabAddSelection.png | 3 -- .../Scripts/Shelves/icons/PrefabBreak.png | 3 -- .../Scripts/Shelves/icons/PrefabConvert.png | 3 -- .../Scripts/Shelves/icons/PrefabCreate.png | 3 -- .../Scripts/Shelves/icons/PrefabIsolate.png | 3 -- .../Scripts/Shelves/icons/Scattering.png | 3 -- .../Scripts/Shelves/icons/Solid_Wireframe.png | 3 -- .../Scripts/Shelves/icons/Spec_Amount.png | 3 -- .../Scripts/Shelves/icons/Spec_Lighting.png | 3 -- .../Shelves/icons/Texel_Per_Meter_1024.png | 3 -- .../Shelves/icons/Texel_Per_Meter_256.png | 3 -- .../Shelves/icons/Texel_Per_Meter_512.png | 3 -- Assets/Editor/Scripts/Shelves/icons/all.png | 3 -- Assets/Editor/Scripts/Shelves/icons/beams.png | 3 -- .../Editor/Scripts/Shelves/icons/blanker.png | 3 -- .../Scripts/Shelves/icons/bounding_box.png | 3 -- .../Editor/Scripts/Shelves/icons/brushes.png | 3 -- Assets/Editor/Scripts/Shelves/icons/cloud.png | 3 -- .../Scripts/Shelves/icons/cloud_dark.png | 3 -- .../Scripts/Shelves/icons/cloud_dark_rain.png | 3 -- .../Scripts/Shelves/icons/collisions.png | 3 -- .../Shelves/icons/create_ao_volume_box.png | 3 -- .../icons/create_both_vis_box_envprobe.png | 3 -- .../Scripts/Shelves/icons/create_envprobe.png | 3 -- .../Shelves/icons/create_portal_box.png | 3 -- .../Scripts/Shelves/icons/create_vis_box.png | 3 -- .../icons/create_vis_box_and_portal_box.png | 3 -- .../create_vis_box_env_probe_and_portal.png | 3 -- .../Editor/Scripts/Shelves/icons/cubemap.png | 3 -- .../Editor/Scripts/Shelves/icons/decals.png | 3 -- .../Shelves/icons/default_material.png | 3 -- .../icons/default_material_with_normals.png | 3 -- .../Editor/Scripts/Shelves/icons/designer.png | 3 -- .../Editor/Scripts/Shelves/icons/diff_acc.png | 3 -- .../Scripts/Shelves/icons/display_info.png | 3 -- .../Scripts/Shelves/icons/dual_layer_mask.png | 3 -- .../Scripts/Shelves/icons/dynamiclights.png | 3 -- .../Editor/Scripts/Shelves/icons/entities.png | 3 -- .../Shelves/icons/eye_adaptation_speed.png | 3 -- Assets/Editor/Scripts/Shelves/icons/fog.png | 3 -- .../Scripts/Shelves/icons/fogvolumes.png | 3 -- .../Shelves/icons/freeze_particles.png | 3 -- .../Scripts/Shelves/icons/full_shading.png | 3 -- Assets/Editor/Scripts/Shelves/icons/gamma.png | 3 -- Assets/Editor/Scripts/Shelves/icons/gi.png | 3 -- .../Scripts/Shelves/icons/lens_flare.png | 3 -- .../Scripts/Shelves/icons/lighting_only.png | 3 -- Assets/Editor/Scripts/Shelves/icons/lods.png | 3 -- Assets/Editor/Scripts/Shelves/icons/lsao.png | 3 -- .../Scripts/Shelves/icons/lsao_toggle.png | 3 -- Assets/Editor/Scripts/Shelves/icons/lsro.png | 3 -- .../Editor/Scripts/Shelves/icons/normals.png | 3 -- .../Scripts/Shelves/icons/normals_x.png | 3 -- .../Scripts/Shelves/icons/normals_y.png | 3 -- .../Scripts/Shelves/icons/normals_z.png | 3 -- Assets/Editor/Scripts/Shelves/icons/ocean.png | 3 -- .../Scripts/Shelves/icons/particles.png | 3 -- .../Shelves/icons/particles_bounds.png | 3 -- .../Scripts/Shelves/icons/particles_off.png | 3 -- .../Shelves/icons/particles_overdraw.png | 3 -- .../icons/particles_screen_coverage.png | 3 -- .../Scripts/Shelves/icons/placeholder.png | 3 -- .../Editor/Scripts/Shelves/icons/prefab.png | 3 -- .../Scripts/Shelves/icons/reflections.png | 3 -- Assets/Editor/Scripts/Shelves/icons/reset.png | 3 -- .../Editor/Scripts/Shelves/icons/selfocc.png | 3 -- .../Shelves/icons/shaded_wireframe.png | 3 -- .../Editor/Scripts/Shelves/icons/shadows.png | 3 -- .../Scripts/Shelves/icons/showlines.png | 3 -- Assets/Editor/Scripts/Shelves/icons/sky.png | 3 -- .../Editor/Scripts/Shelves/icons/spec_acc.png | 3 -- .../Editor/Scripts/Shelves/icons/spec_lum.png | 3 -- .../Editor/Scripts/Shelves/icons/spec_occ.png | 3 -- Assets/Editor/Scripts/Shelves/icons/ssao.png | 3 -- Assets/Editor/Scripts/Shelves/icons/ssdo.png | 3 -- .../Scripts/Shelves/icons/ssdo_toggle.png | 3 -- .../Editor/Scripts/Shelves/icons/sun.big.png | 3 -- .../Editor/Scripts/Shelves/icons/tangents.png | 3 -- .../Editor/Scripts/Shelves/icons/terrain.png | 3 -- .../Shelves/icons/time_scale_double.png | 3 -- .../Shelves/icons/time_scale_frozen.png | 3 -- .../Scripts/Shelves/icons/time_scale_half.png | 3 -- .../Shelves/icons/time_scale_quarter.png | 3 -- .../Shelves/icons/time_scale_tenth.png | 3 -- Assets/Editor/Scripts/Shelves/icons/tod.png | 3 -- .../Scripts/Shelves/icons/translucency.png | 3 -- .../Scripts/Shelves/icons/transparency.png | 3 -- .../Scripts/Shelves/icons/valid_albedo.png | 3 -- .../Scripts/Shelves/icons/valid_spec_lum.png | 3 -- .../Scripts/Shelves/icons/vegetation.png | 3 -- .../Scripts/Shelves/icons/vertex_normals.png | 3 -- .../Editor/Scripts/Shelves/icons/vis_area.png | 3 -- .../Scripts/Shelves/icons/water_volume.png | 3 -- Assets/Editor/Scripts/Shelves/icons/wind.png | 3 -- .../Scripts/Shelves/icons/wireframe.png | 3 -- Code/Editor/ToolBox.cpp | 31 +------------------ Code/Editor/ToolBox.h | 1 - 181 files changed, 1 insertion(+), 568 deletions(-) delete mode 100644 Assets/Editor/ObjectIcons/AreaTrigger.bmp delete mode 100644 Assets/Editor/ObjectIcons/AudioAreaAmbience.bmp delete mode 100644 Assets/Editor/ObjectIcons/AudioAreaEntity.bmp delete mode 100644 Assets/Editor/ObjectIcons/AudioAreaRandom.bmp delete mode 100644 Assets/Editor/ObjectIcons/Camera.bmp delete mode 100644 Assets/Editor/ObjectIcons/Checkpoint.bmp delete mode 100644 Assets/Editor/ObjectIcons/ClipVolume.bmp delete mode 100644 Assets/Editor/ObjectIcons/Clock.bmp delete mode 100644 Assets/Editor/ObjectIcons/Clouds.bmp delete mode 100644 Assets/Editor/ObjectIcons/Comment.bmp delete mode 100644 Assets/Editor/ObjectIcons/DeadBody.bmp delete mode 100644 Assets/Editor/ObjectIcons/Decal.bmp delete mode 100644 Assets/Editor/ObjectIcons/Dialog.bmp delete mode 100644 Assets/Editor/ObjectIcons/Flash.bmp delete mode 100644 Assets/Editor/ObjectIcons/Fog.bmp delete mode 100644 Assets/Editor/ObjectIcons/FogVolume.bmp delete mode 100644 Assets/Editor/ObjectIcons/GravitySphere.bmp delete mode 100644 Assets/Editor/ObjectIcons/Item.bmp delete mode 100644 Assets/Editor/ObjectIcons/Ladder.bmp delete mode 100644 Assets/Editor/ObjectIcons/Light.bmp delete mode 100644 Assets/Editor/ObjectIcons/LightPropagationVolume.bmp delete mode 100644 Assets/Editor/ObjectIcons/Lightning.bmp delete mode 100644 Assets/Editor/ObjectIcons/Magnet.bmp delete mode 100644 Assets/Editor/ObjectIcons/MultiTrigger.bmp delete mode 100644 Assets/Editor/ObjectIcons/ODD.bmp delete mode 100644 Assets/Editor/ObjectIcons/Particles.bmp delete mode 100644 Assets/Editor/ObjectIcons/PrecacheCamera.bmp delete mode 100644 Assets/Editor/ObjectIcons/Prefab.bmp delete mode 100644 Assets/Editor/ObjectIcons/Prompt.bmp delete mode 100644 Assets/Editor/ObjectIcons/SavePoint.bmp delete mode 100644 Assets/Editor/ObjectIcons/Seed.bmp delete mode 100644 Assets/Editor/ObjectIcons/Sound.bmp delete mode 100644 Assets/Editor/ObjectIcons/SpawnPoint.bmp delete mode 100644 Assets/Editor/ObjectIcons/T.bmp delete mode 100644 Assets/Editor/ObjectIcons/TagPoint.bmp delete mode 100644 Assets/Editor/ObjectIcons/Trigger.bmp delete mode 100644 Assets/Editor/ObjectIcons/UiCanvasRefEntity.bmp delete mode 100644 Assets/Editor/ObjectIcons/User.bmp delete mode 100644 Assets/Editor/ObjectIcons/VVVArea.bmp delete mode 100644 Assets/Editor/ObjectIcons/W.bmp delete mode 100644 Assets/Editor/ObjectIcons/Water.bmp delete mode 100644 Assets/Editor/ObjectIcons/animobject.bmp delete mode 100644 Assets/Editor/ObjectIcons/bird.bmp delete mode 100644 Assets/Editor/ObjectIcons/bug.bmp delete mode 100644 Assets/Editor/ObjectIcons/character.bmp delete mode 100644 Assets/Editor/ObjectIcons/death.bmp delete mode 100644 Assets/Editor/ObjectIcons/door.bmp delete mode 100644 Assets/Editor/ObjectIcons/elevator.bmp delete mode 100644 Assets/Editor/ObjectIcons/environmentProbe.bmp delete mode 100644 Assets/Editor/ObjectIcons/explosion.bmp delete mode 100644 Assets/Editor/ObjectIcons/fish.bmp delete mode 100644 Assets/Editor/ObjectIcons/forbiddenarea.bmp delete mode 100644 Assets/Editor/ObjectIcons/hazard.bmp delete mode 100644 Assets/Editor/ObjectIcons/health.bmp delete mode 100644 Assets/Editor/ObjectIcons/ledge.bmp delete mode 100644 Assets/Editor/ObjectIcons/mine.bmp delete mode 100644 Assets/Editor/ObjectIcons/physicsobject.bmp delete mode 100644 Assets/Editor/ObjectIcons/prefabbuilding.bmp delete mode 100644 Assets/Editor/ObjectIcons/proceduralbuilding.bmp delete mode 100644 Assets/Editor/ObjectIcons/proceduralobject.bmp delete mode 100644 Assets/Editor/ObjectIcons/proximitytrigger.bmp delete mode 100644 Assets/Editor/ObjectIcons/river.bmp delete mode 100644 Assets/Editor/ObjectIcons/road.bmp delete mode 100644 Assets/Editor/ObjectIcons/rope.bmp delete mode 100644 Assets/Editor/ObjectIcons/sequence.bmp delete mode 100644 Assets/Editor/ObjectIcons/shake.bmp delete mode 100644 Assets/Editor/ObjectIcons/smartobject.bmp delete mode 100644 Assets/Editor/ObjectIcons/spawngroup.bmp delete mode 100644 Assets/Editor/ObjectIcons/spectator.bmp delete mode 100644 Assets/Editor/ObjectIcons/switch.bmp delete mode 100644 Assets/Editor/ObjectIcons/territory.bmp delete mode 100644 Assets/Editor/ObjectIcons/tornado.bmp delete mode 100644 Assets/Editor/ObjectIcons/vehicle.bmp delete mode 100644 Assets/Editor/ObjectIcons/voxel.bmp delete mode 100644 Assets/Editor/ObjectIcons/wave.bmp delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Albedo.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Diffuse_Lighting.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Diffuse_Texture_Res_360.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Empty_Wireframe.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Exit.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Fuzziness.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Gloss.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Normal_Texture_Res_360.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/PrefabAddLibrary.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/PrefabAddSelection.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/PrefabBreak.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/PrefabConvert.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/PrefabCreate.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/PrefabIsolate.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Scattering.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Solid_Wireframe.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Spec_Amount.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Spec_Lighting.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_1024.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_256.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_512.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/all.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/beams.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/blanker.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/bounding_box.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/brushes.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/cloud.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/cloud_dark.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/cloud_dark_rain.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/collisions.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/create_ao_volume_box.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/create_both_vis_box_envprobe.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/create_envprobe.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/create_portal_box.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/create_vis_box.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/create_vis_box_and_portal_box.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/create_vis_box_env_probe_and_portal.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/cubemap.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/decals.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/default_material.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/default_material_with_normals.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/designer.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/diff_acc.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/display_info.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/dual_layer_mask.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/dynamiclights.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/entities.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/eye_adaptation_speed.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/fog.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/fogvolumes.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/freeze_particles.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/full_shading.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/gamma.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/gi.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/lens_flare.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/lighting_only.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/lods.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/lsao.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/lsao_toggle.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/lsro.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/normals.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/normals_x.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/normals_y.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/normals_z.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/ocean.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/particles.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/particles_bounds.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/particles_off.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/particles_overdraw.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/particles_screen_coverage.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/placeholder.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/prefab.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/reflections.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/reset.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/selfocc.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/shaded_wireframe.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/shadows.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/showlines.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/sky.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/spec_acc.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/spec_lum.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/spec_occ.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/ssao.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/ssdo.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/ssdo_toggle.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/sun.big.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/tangents.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/terrain.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/time_scale_double.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/time_scale_frozen.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/time_scale_half.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/time_scale_quarter.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/time_scale_tenth.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/tod.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/translucency.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/transparency.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/valid_albedo.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/valid_spec_lum.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/vegetation.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/vertex_normals.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/vis_area.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/water_volume.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/wind.png delete mode 100644 Assets/Editor/Scripts/Shelves/icons/wireframe.png diff --git a/Assets/Editor/ObjectIcons/AreaTrigger.bmp b/Assets/Editor/ObjectIcons/AreaTrigger.bmp deleted file mode 100644 index 779e9bd30f..0000000000 --- a/Assets/Editor/ObjectIcons/AreaTrigger.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4cf08659d31a337ceb28de2765b0177abf404f3e671f5277dd7a280f2fd6c60d -size 3128 diff --git a/Assets/Editor/ObjectIcons/AudioAreaAmbience.bmp b/Assets/Editor/ObjectIcons/AudioAreaAmbience.bmp deleted file mode 100644 index 052eb463cb..0000000000 --- a/Assets/Editor/ObjectIcons/AudioAreaAmbience.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:706b12b37518596b01fc6c5cdb3aadc5fdbe76b668e9989ba2bb03ee23376dbf -size 3126 diff --git a/Assets/Editor/ObjectIcons/AudioAreaEntity.bmp b/Assets/Editor/ObjectIcons/AudioAreaEntity.bmp deleted file mode 100644 index b490f91bc4..0000000000 --- a/Assets/Editor/ObjectIcons/AudioAreaEntity.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7e67540926b2d55c70ac5867266ac9688437fc139b459f165f9d52d9b351851c -size 3128 diff --git a/Assets/Editor/ObjectIcons/AudioAreaRandom.bmp b/Assets/Editor/ObjectIcons/AudioAreaRandom.bmp deleted file mode 100644 index 73a0a21256..0000000000 --- a/Assets/Editor/ObjectIcons/AudioAreaRandom.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:96ec04e8126bcffb7fe391dc55ea1aa6a82419825c8305117f9b0ae72b40e63e -size 3126 diff --git a/Assets/Editor/ObjectIcons/Camera.bmp b/Assets/Editor/ObjectIcons/Camera.bmp deleted file mode 100644 index fd89801011..0000000000 --- a/Assets/Editor/ObjectIcons/Camera.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4168676b803b7e3b03a90fb69502204a418b6598941c75f0c36e589a31455db5 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Checkpoint.bmp b/Assets/Editor/ObjectIcons/Checkpoint.bmp deleted file mode 100644 index fd31d3c446..0000000000 --- a/Assets/Editor/ObjectIcons/Checkpoint.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b11c94da25b704a36f2b437dae98c04a5cea54f02022567306e2cf82837bf7a1 -size 3128 diff --git a/Assets/Editor/ObjectIcons/ClipVolume.bmp b/Assets/Editor/ObjectIcons/ClipVolume.bmp deleted file mode 100644 index dba0aa32ba..0000000000 --- a/Assets/Editor/ObjectIcons/ClipVolume.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8ca14c966de6d392beb4d154221b622a417163fcdf92eb049638bf8495c13774 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Clock.bmp b/Assets/Editor/ObjectIcons/Clock.bmp deleted file mode 100644 index 1557a7e8dc..0000000000 --- a/Assets/Editor/ObjectIcons/Clock.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6d11fd9413f06706bc706a97f39cc72b1ae6ff7cb6c506cf2fcda98660e2a92f -size 3128 diff --git a/Assets/Editor/ObjectIcons/Clouds.bmp b/Assets/Editor/ObjectIcons/Clouds.bmp deleted file mode 100644 index 4530661aac..0000000000 --- a/Assets/Editor/ObjectIcons/Clouds.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1f5fd7032f82fbb7364cd0a96989918defd63f26a899836c61b039541cf3b3af -size 3128 diff --git a/Assets/Editor/ObjectIcons/Comment.bmp b/Assets/Editor/ObjectIcons/Comment.bmp deleted file mode 100644 index 78a8d8f4fa..0000000000 --- a/Assets/Editor/ObjectIcons/Comment.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9201d97225c19b8fc2fc208ab913ab100a94328b64b026ab65be9c4cd9c4e28a -size 3128 diff --git a/Assets/Editor/ObjectIcons/DeadBody.bmp b/Assets/Editor/ObjectIcons/DeadBody.bmp deleted file mode 100644 index ffebc73608..0000000000 --- a/Assets/Editor/ObjectIcons/DeadBody.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a2937837233d9f313b2500232c74952cee3f4e7497ee0e1099b301ef2fa49bf8 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Decal.bmp b/Assets/Editor/ObjectIcons/Decal.bmp deleted file mode 100644 index 4b33fe7422..0000000000 --- a/Assets/Editor/ObjectIcons/Decal.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ffbe8438c19ac2a9b6614beb78f0d651184dbe5cf2998063257dc7272c9c2c10 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Dialog.bmp b/Assets/Editor/ObjectIcons/Dialog.bmp deleted file mode 100644 index 0722f5f1e4..0000000000 --- a/Assets/Editor/ObjectIcons/Dialog.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:63640478bd3258aa310dd639014cde714780ebaa168aa784093e74fc0da23a4c -size 3126 diff --git a/Assets/Editor/ObjectIcons/Flash.bmp b/Assets/Editor/ObjectIcons/Flash.bmp deleted file mode 100644 index d7f02ed44b..0000000000 --- a/Assets/Editor/ObjectIcons/Flash.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b66daefbb3f11f527d9c10ff1dd54f87635e6561cc546a762ae2e72793ae6ef6 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Fog.bmp b/Assets/Editor/ObjectIcons/Fog.bmp deleted file mode 100644 index 2af489a79a..0000000000 --- a/Assets/Editor/ObjectIcons/Fog.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:42e0c1dc60809958d74145ae14030c22e351ef3b72ed6d820fdb19632b691c89 -size 3128 diff --git a/Assets/Editor/ObjectIcons/FogVolume.bmp b/Assets/Editor/ObjectIcons/FogVolume.bmp deleted file mode 100644 index 78d20bff41..0000000000 --- a/Assets/Editor/ObjectIcons/FogVolume.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2cbb23fc09d47d16b2414d622fd16b330d9f684398dcfc44e0fb44378dfd3287 -size 3128 diff --git a/Assets/Editor/ObjectIcons/GravitySphere.bmp b/Assets/Editor/ObjectIcons/GravitySphere.bmp deleted file mode 100644 index 06168d4698..0000000000 --- a/Assets/Editor/ObjectIcons/GravitySphere.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:26b6e2f28ed72b9cdb90410351e3a22fee3c0498ac315e71d966a1ffb77742fe -size 3128 diff --git a/Assets/Editor/ObjectIcons/Item.bmp b/Assets/Editor/ObjectIcons/Item.bmp deleted file mode 100644 index 15c610cad2..0000000000 --- a/Assets/Editor/ObjectIcons/Item.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bd6f39152affb52a7b3c4361032d1d7d77e7e94841613a83d7e2cdea9eaab553 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Ladder.bmp b/Assets/Editor/ObjectIcons/Ladder.bmp deleted file mode 100644 index dbd4a288e7..0000000000 --- a/Assets/Editor/ObjectIcons/Ladder.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:077502953026981b6e8cc5e40ab58722fc514947f175021508e6af8058340f32 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Light.bmp b/Assets/Editor/ObjectIcons/Light.bmp deleted file mode 100644 index 6a3347e78c..0000000000 --- a/Assets/Editor/ObjectIcons/Light.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c9ecfc056ab66b3221be3175889d182229c0e49bf9604abd7946fe58cc7d29a9 -size 3128 diff --git a/Assets/Editor/ObjectIcons/LightPropagationVolume.bmp b/Assets/Editor/ObjectIcons/LightPropagationVolume.bmp deleted file mode 100644 index 4ad9437883..0000000000 --- a/Assets/Editor/ObjectIcons/LightPropagationVolume.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:206820d3bb5d6a4d26bf87fc0b91a36adcbd0f154149b7cb5f5ce067f5ee4d67 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Lightning.bmp b/Assets/Editor/ObjectIcons/Lightning.bmp deleted file mode 100644 index 5c02d0368c..0000000000 --- a/Assets/Editor/ObjectIcons/Lightning.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d7c81a8000339695f73277bcebaedb0cfeacdff547f51c1ff7f4761c75927ca4 -size 3126 diff --git a/Assets/Editor/ObjectIcons/Magnet.bmp b/Assets/Editor/ObjectIcons/Magnet.bmp deleted file mode 100644 index 68b6e4e7e4..0000000000 --- a/Assets/Editor/ObjectIcons/Magnet.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:560c3af6e8f2fb98ddc8638b0ea4786131e75b6fe0acece964bfdb28f8c3ec9f -size 3128 diff --git a/Assets/Editor/ObjectIcons/MultiTrigger.bmp b/Assets/Editor/ObjectIcons/MultiTrigger.bmp deleted file mode 100644 index e96dc6f1b7..0000000000 --- a/Assets/Editor/ObjectIcons/MultiTrigger.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8a3a64d33b65c4cd5d666c11abf03b4148acadfe69e4c80e79382b56d2906ae6 -size 3128 diff --git a/Assets/Editor/ObjectIcons/ODD.bmp b/Assets/Editor/ObjectIcons/ODD.bmp deleted file mode 100644 index 5c5a7bbd89..0000000000 --- a/Assets/Editor/ObjectIcons/ODD.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:113d0a416da49ce24dae2c47514318b75e0ca4d7dc257a9927e0db4bdad35d91 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Particles.bmp b/Assets/Editor/ObjectIcons/Particles.bmp deleted file mode 100644 index 8f71edb74f..0000000000 --- a/Assets/Editor/ObjectIcons/Particles.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6ca81d96a5450660f7e17f75565595368fb7c0071df9589bcbfda2ba54d5c0ae -size 3128 diff --git a/Assets/Editor/ObjectIcons/PrecacheCamera.bmp b/Assets/Editor/ObjectIcons/PrecacheCamera.bmp deleted file mode 100644 index 8f1dca751a..0000000000 --- a/Assets/Editor/ObjectIcons/PrecacheCamera.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:73629b1903365aa6acf35fd7846896c23c38401fac12bc23b23285e5ed9ae89d -size 3126 diff --git a/Assets/Editor/ObjectIcons/Prefab.bmp b/Assets/Editor/ObjectIcons/Prefab.bmp deleted file mode 100644 index 539a0f5a56..0000000000 --- a/Assets/Editor/ObjectIcons/Prefab.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6d7fbb76f67165492a51e6b8715ee3716040d44bd5419b12481e2c9cc627c291 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Prompt.bmp b/Assets/Editor/ObjectIcons/Prompt.bmp deleted file mode 100644 index 1e9b18a97c..0000000000 --- a/Assets/Editor/ObjectIcons/Prompt.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2482da67fbf513a9597b3919562a65d361a4c8264fcc8510ef45321b4192ce4d -size 3128 diff --git a/Assets/Editor/ObjectIcons/SavePoint.bmp b/Assets/Editor/ObjectIcons/SavePoint.bmp deleted file mode 100644 index ce602eeeb4..0000000000 --- a/Assets/Editor/ObjectIcons/SavePoint.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:06f866e66e0458ccf3e014a30fef2dfaab832d9b4b1179f98b7cdd716b358b48 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Seed.bmp b/Assets/Editor/ObjectIcons/Seed.bmp deleted file mode 100644 index 3a9452d982..0000000000 --- a/Assets/Editor/ObjectIcons/Seed.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fdcea1e14d3b01b1ed6ea123767343eddc646969ee447b4bf725c233fd7946f4 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Sound.bmp b/Assets/Editor/ObjectIcons/Sound.bmp deleted file mode 100644 index 06ab261be3..0000000000 --- a/Assets/Editor/ObjectIcons/Sound.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:14a4003a9faf9a2fb3a17d2f87825c8497aeaca364c592ab75970d00e77aa203 -size 3128 diff --git a/Assets/Editor/ObjectIcons/SpawnPoint.bmp b/Assets/Editor/ObjectIcons/SpawnPoint.bmp deleted file mode 100644 index b04a20e8c0..0000000000 --- a/Assets/Editor/ObjectIcons/SpawnPoint.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7e109f57e5e9bc6bcaee7176a479bb6434353bc49a8021ab96e016ce27f41a1 -size 3128 diff --git a/Assets/Editor/ObjectIcons/T.bmp b/Assets/Editor/ObjectIcons/T.bmp deleted file mode 100644 index 767782c43d..0000000000 --- a/Assets/Editor/ObjectIcons/T.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c2288c239604402f7e85d753141fbd8a82fde9f18e4f95006b039ceeec41d0c -size 3128 diff --git a/Assets/Editor/ObjectIcons/TagPoint.bmp b/Assets/Editor/ObjectIcons/TagPoint.bmp deleted file mode 100644 index 36727d9c4a..0000000000 --- a/Assets/Editor/ObjectIcons/TagPoint.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8f58cabe21df546914abc1e8f2604989d87b4a3471c1902956a4e1e1be9930b8 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Trigger.bmp b/Assets/Editor/ObjectIcons/Trigger.bmp deleted file mode 100644 index ef712e4b09..0000000000 --- a/Assets/Editor/ObjectIcons/Trigger.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e9cfb325abea577e8737b837098ff3cecd564e302b2c30925b3d35a62fa6c7c3 -size 3128 diff --git a/Assets/Editor/ObjectIcons/UiCanvasRefEntity.bmp b/Assets/Editor/ObjectIcons/UiCanvasRefEntity.bmp deleted file mode 100644 index c1ff4d3291..0000000000 --- a/Assets/Editor/ObjectIcons/UiCanvasRefEntity.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bcd9a1efaab42cdea4557265e544f2370565872115d21cc84af6e6998bb7ad01 -size 3128 diff --git a/Assets/Editor/ObjectIcons/User.bmp b/Assets/Editor/ObjectIcons/User.bmp deleted file mode 100644 index 780242c15c..0000000000 --- a/Assets/Editor/ObjectIcons/User.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:56a379a337a44617cb6ed5a20560286b8263c75871742ca04cc61cac49736a2a -size 3128 diff --git a/Assets/Editor/ObjectIcons/VVVArea.bmp b/Assets/Editor/ObjectIcons/VVVArea.bmp deleted file mode 100644 index 82712dda92..0000000000 --- a/Assets/Editor/ObjectIcons/VVVArea.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9cab80e4ce74155a3eaf771fa9b2464c1f3b36bce6de55d3f5aa180576cabec2 -size 3128 diff --git a/Assets/Editor/ObjectIcons/W.bmp b/Assets/Editor/ObjectIcons/W.bmp deleted file mode 100644 index 40448a6334..0000000000 --- a/Assets/Editor/ObjectIcons/W.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6ebc8eacd6695caafd131d5c8ca29b45fea16bc2147cdb169478e391d6f13b70 -size 3128 diff --git a/Assets/Editor/ObjectIcons/Water.bmp b/Assets/Editor/ObjectIcons/Water.bmp deleted file mode 100644 index fb7d6c7b51..0000000000 --- a/Assets/Editor/ObjectIcons/Water.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5d24ecf0878409dc3f7ed0f447734061bb9e313e4adb767580bd961b0038236 -size 3126 diff --git a/Assets/Editor/ObjectIcons/animobject.bmp b/Assets/Editor/ObjectIcons/animobject.bmp deleted file mode 100644 index d28e4c016a..0000000000 --- a/Assets/Editor/ObjectIcons/animobject.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:514fb756bd23f0376a03ba7222a5a8479408eb68efbfcecac30957142580e494 -size 3128 diff --git a/Assets/Editor/ObjectIcons/bird.bmp b/Assets/Editor/ObjectIcons/bird.bmp deleted file mode 100644 index b6431dc2cf..0000000000 --- a/Assets/Editor/ObjectIcons/bird.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e7d72d46274c9c0863e7e34caccfdf78a7c8c77262caf1b7f4305a822ac0145c -size 3128 diff --git a/Assets/Editor/ObjectIcons/bug.bmp b/Assets/Editor/ObjectIcons/bug.bmp deleted file mode 100644 index 86cb76bed0..0000000000 --- a/Assets/Editor/ObjectIcons/bug.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d238a0d17e3469c499249bd907b5aba0b924fb8539259a1b92af64e39820b619 -size 3128 diff --git a/Assets/Editor/ObjectIcons/character.bmp b/Assets/Editor/ObjectIcons/character.bmp deleted file mode 100644 index a37997e7bf..0000000000 --- a/Assets/Editor/ObjectIcons/character.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b7bd2ee00f000d13ef096bd4d430fbca5cd35f3d641d44f4698c1270423b484 -size 3128 diff --git a/Assets/Editor/ObjectIcons/death.bmp b/Assets/Editor/ObjectIcons/death.bmp deleted file mode 100644 index 98c673af1d..0000000000 --- a/Assets/Editor/ObjectIcons/death.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d93aa4486316a2ba269f860d64f741da15359fec6111da1049331a5a75dee02 -size 3128 diff --git a/Assets/Editor/ObjectIcons/door.bmp b/Assets/Editor/ObjectIcons/door.bmp deleted file mode 100644 index 3c95318ef9..0000000000 --- a/Assets/Editor/ObjectIcons/door.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4be7c244d9350a46c18161222ace0eaea1213dd1e7ed5ba02fa94ee5a98dc728 -size 3128 diff --git a/Assets/Editor/ObjectIcons/elevator.bmp b/Assets/Editor/ObjectIcons/elevator.bmp deleted file mode 100644 index b256426aef..0000000000 --- a/Assets/Editor/ObjectIcons/elevator.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6c1cf46f0825ecf1d3331bdca3d5f6a0d348aa6346af9fb1fdb3b75cfc5564dd -size 3128 diff --git a/Assets/Editor/ObjectIcons/environmentProbe.bmp b/Assets/Editor/ObjectIcons/environmentProbe.bmp deleted file mode 100644 index 0a23ebb9f4..0000000000 --- a/Assets/Editor/ObjectIcons/environmentProbe.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:27c8ae2924af50058207e7a1e1f4e35799f27abd7cb2e0778b8903ce00e99732 -size 4152 diff --git a/Assets/Editor/ObjectIcons/explosion.bmp b/Assets/Editor/ObjectIcons/explosion.bmp deleted file mode 100644 index 27213da651..0000000000 --- a/Assets/Editor/ObjectIcons/explosion.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a93e2e2164781ed0de1be34bbbd0c85d630a31efd3fe568ea7f3c026646209c8 -size 3128 diff --git a/Assets/Editor/ObjectIcons/fish.bmp b/Assets/Editor/ObjectIcons/fish.bmp deleted file mode 100644 index 9c1d0b2d21..0000000000 --- a/Assets/Editor/ObjectIcons/fish.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:590e0458bbc0d528ba71cd048b6019ebb8d1764a55cc3b9b3e2b1446182cfaa9 -size 3128 diff --git a/Assets/Editor/ObjectIcons/forbiddenarea.bmp b/Assets/Editor/ObjectIcons/forbiddenarea.bmp deleted file mode 100644 index b41c47bf72..0000000000 --- a/Assets/Editor/ObjectIcons/forbiddenarea.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6a8eac076d5094c722513bcdb6b71def9116ae063d453017d7bb0b38068c3a7e -size 3128 diff --git a/Assets/Editor/ObjectIcons/hazard.bmp b/Assets/Editor/ObjectIcons/hazard.bmp deleted file mode 100644 index 4779f3730a..0000000000 --- a/Assets/Editor/ObjectIcons/hazard.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:71c3e9e9ccf404c3c17f71f806cd6ee0e4b48f6f2e172b52aeca78cc28668ac3 -size 3128 diff --git a/Assets/Editor/ObjectIcons/health.bmp b/Assets/Editor/ObjectIcons/health.bmp deleted file mode 100644 index 01833903c3..0000000000 --- a/Assets/Editor/ObjectIcons/health.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ded11545905ac937fe6e28929e57c10abe55befa74b44260dee5b206cdf3d15 -size 3128 diff --git a/Assets/Editor/ObjectIcons/ledge.bmp b/Assets/Editor/ObjectIcons/ledge.bmp deleted file mode 100644 index 3d6784fb44..0000000000 --- a/Assets/Editor/ObjectIcons/ledge.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c43daede42eb72eca0f80454b0e70de1e03156b5f098bcc8dbc080117c34380a -size 3128 diff --git a/Assets/Editor/ObjectIcons/mine.bmp b/Assets/Editor/ObjectIcons/mine.bmp deleted file mode 100644 index 8f4394a2dd..0000000000 --- a/Assets/Editor/ObjectIcons/mine.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:da1bb03a55949c6dc80ac18e3cf87c962e30fe2eacfd4fac74cc93db58552ac5 -size 3128 diff --git a/Assets/Editor/ObjectIcons/physicsobject.bmp b/Assets/Editor/ObjectIcons/physicsobject.bmp deleted file mode 100644 index 00bb3f2380..0000000000 --- a/Assets/Editor/ObjectIcons/physicsobject.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:74cdfbf6f61029fa6f1262f78c2787afb9dddc0218911b53349962c4ed548bbf -size 3128 diff --git a/Assets/Editor/ObjectIcons/prefabbuilding.bmp b/Assets/Editor/ObjectIcons/prefabbuilding.bmp deleted file mode 100644 index e416cbafe1..0000000000 --- a/Assets/Editor/ObjectIcons/prefabbuilding.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98aaf6d6e532f5a3f31cdc08676432e30b4e52fd4f376331f4610379f288a191 -size 3128 diff --git a/Assets/Editor/ObjectIcons/proceduralbuilding.bmp b/Assets/Editor/ObjectIcons/proceduralbuilding.bmp deleted file mode 100644 index e416cbafe1..0000000000 --- a/Assets/Editor/ObjectIcons/proceduralbuilding.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98aaf6d6e532f5a3f31cdc08676432e30b4e52fd4f376331f4610379f288a191 -size 3128 diff --git a/Assets/Editor/ObjectIcons/proceduralobject.bmp b/Assets/Editor/ObjectIcons/proceduralobject.bmp deleted file mode 100644 index e416cbafe1..0000000000 --- a/Assets/Editor/ObjectIcons/proceduralobject.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98aaf6d6e532f5a3f31cdc08676432e30b4e52fd4f376331f4610379f288a191 -size 3128 diff --git a/Assets/Editor/ObjectIcons/proximitytrigger.bmp b/Assets/Editor/ObjectIcons/proximitytrigger.bmp deleted file mode 100644 index a776094539..0000000000 --- a/Assets/Editor/ObjectIcons/proximitytrigger.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac364f478ca4dfa0186069fb69d19b8005a8d1da74cff34ced76bb85cf4402e7 -size 3128 diff --git a/Assets/Editor/ObjectIcons/river.bmp b/Assets/Editor/ObjectIcons/river.bmp deleted file mode 100644 index bf831c356a..0000000000 --- a/Assets/Editor/ObjectIcons/river.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:910d8f788514dc2d66c58027cb841a16e7d5194ee1f1ff3ccfcf5badd86c768a -size 3128 diff --git a/Assets/Editor/ObjectIcons/road.bmp b/Assets/Editor/ObjectIcons/road.bmp deleted file mode 100644 index 91a8b0916f..0000000000 --- a/Assets/Editor/ObjectIcons/road.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9e92c9792886fab49007891c38addf2f62719d6563a36cd81250de13c50fbf61 -size 3128 diff --git a/Assets/Editor/ObjectIcons/rope.bmp b/Assets/Editor/ObjectIcons/rope.bmp deleted file mode 100644 index d7f7fddb67..0000000000 --- a/Assets/Editor/ObjectIcons/rope.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:738525640cf00402ebd807ce9a35d6d7ed67be39cde7def7930b136596977a2e -size 3128 diff --git a/Assets/Editor/ObjectIcons/sequence.bmp b/Assets/Editor/ObjectIcons/sequence.bmp deleted file mode 100644 index 8e76c924f1..0000000000 --- a/Assets/Editor/ObjectIcons/sequence.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e339afca6ba8ffa2463bf6b367615e66bb953fced380d739996d52c2971feab5 -size 3128 diff --git a/Assets/Editor/ObjectIcons/shake.bmp b/Assets/Editor/ObjectIcons/shake.bmp deleted file mode 100644 index 5275a0aac9..0000000000 --- a/Assets/Editor/ObjectIcons/shake.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f3130dcb95136d806aff1882d3933eb3f7ee88aaa9876423b53dbf73f02c8cd3 -size 3128 diff --git a/Assets/Editor/ObjectIcons/smartobject.bmp b/Assets/Editor/ObjectIcons/smartobject.bmp deleted file mode 100644 index 5ecf9a273e..0000000000 --- a/Assets/Editor/ObjectIcons/smartobject.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e908579e0a62d74a1402ee786876e88eadb0ef0de0542617d02291947504078b -size 3128 diff --git a/Assets/Editor/ObjectIcons/spawngroup.bmp b/Assets/Editor/ObjectIcons/spawngroup.bmp deleted file mode 100644 index 00626fc17f..0000000000 --- a/Assets/Editor/ObjectIcons/spawngroup.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:28111b13e60816f31f3916131d4632ce2d0c48c1a7712421593f79dff79c99d0 -size 3128 diff --git a/Assets/Editor/ObjectIcons/spectator.bmp b/Assets/Editor/ObjectIcons/spectator.bmp deleted file mode 100644 index 6798c841c0..0000000000 --- a/Assets/Editor/ObjectIcons/spectator.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9a2885b3eb0845b48571f1af08d9e685b52361c78c31485c64f8e1efb38e8cc4 -size 3128 diff --git a/Assets/Editor/ObjectIcons/switch.bmp b/Assets/Editor/ObjectIcons/switch.bmp deleted file mode 100644 index 50f4e790b2..0000000000 --- a/Assets/Editor/ObjectIcons/switch.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9bdce356a35d214c4d806ba568d2de72af636410eb433be5c0390eae67d8478a -size 3128 diff --git a/Assets/Editor/ObjectIcons/territory.bmp b/Assets/Editor/ObjectIcons/territory.bmp deleted file mode 100644 index edd8b5178e..0000000000 --- a/Assets/Editor/ObjectIcons/territory.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dc350e4d3226531a35ac810fa5ebe1894bfdcafac605334afffcdd3a14416f94 -size 3128 diff --git a/Assets/Editor/ObjectIcons/tornado.bmp b/Assets/Editor/ObjectIcons/tornado.bmp deleted file mode 100644 index e30b642441..0000000000 --- a/Assets/Editor/ObjectIcons/tornado.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c54df0fb1c9b8abeee30adc5e983bfd7dd524c551909b26466a9d8b6422a094a -size 3128 diff --git a/Assets/Editor/ObjectIcons/vehicle.bmp b/Assets/Editor/ObjectIcons/vehicle.bmp deleted file mode 100644 index f65e5bb7bf..0000000000 --- a/Assets/Editor/ObjectIcons/vehicle.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50e0b4d6a86953c33b0c3ace60bb53d119fa5acd193f4d9aa2c0934f3074cb19 -size 3128 diff --git a/Assets/Editor/ObjectIcons/voxel.bmp b/Assets/Editor/ObjectIcons/voxel.bmp deleted file mode 100644 index dba0aa32ba..0000000000 --- a/Assets/Editor/ObjectIcons/voxel.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8ca14c966de6d392beb4d154221b622a417163fcdf92eb049638bf8495c13774 -size 3128 diff --git a/Assets/Editor/ObjectIcons/wave.bmp b/Assets/Editor/ObjectIcons/wave.bmp deleted file mode 100644 index 0465b41c38..0000000000 --- a/Assets/Editor/ObjectIcons/wave.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:573d22719ad010351a58733b63315a9a0fc07545dde71f3931f37371dfe44ce3 -size 3128 diff --git a/Assets/Editor/Scripts/Shelves/icons/Albedo.png b/Assets/Editor/Scripts/Shelves/icons/Albedo.png deleted file mode 100644 index f3225255c7..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Albedo.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a91ea78d1ffd91490f20efcf76ad8790e450836240b8a77dda719da963235c85 -size 2987 diff --git a/Assets/Editor/Scripts/Shelves/icons/Diffuse_Lighting.png b/Assets/Editor/Scripts/Shelves/icons/Diffuse_Lighting.png deleted file mode 100644 index 4709ee81d0..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Diffuse_Lighting.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2d8eadc0bdc63391e88936b0acfd0616c2d7bce550ea82cee1f967f971ace8a6 -size 2905 diff --git a/Assets/Editor/Scripts/Shelves/icons/Diffuse_Texture_Res_360.png b/Assets/Editor/Scripts/Shelves/icons/Diffuse_Texture_Res_360.png deleted file mode 100644 index 25c686e46a..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Diffuse_Texture_Res_360.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9cdb92de995635eadfbb6dceb25f44a737dde744e09f0fcfe7016de981dce786 -size 2975 diff --git a/Assets/Editor/Scripts/Shelves/icons/Empty_Wireframe.png b/Assets/Editor/Scripts/Shelves/icons/Empty_Wireframe.png deleted file mode 100644 index b4329c1beb..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Empty_Wireframe.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:268a5b239b9988be0ae13a2f42a99ac39ac2db9988f92604154630b661b89999 -size 2865 diff --git a/Assets/Editor/Scripts/Shelves/icons/Exit.png b/Assets/Editor/Scripts/Shelves/icons/Exit.png deleted file mode 100644 index 3706ddc01c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Exit.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:030f4dc71dac36f220cd7e7c07eb24bda2df3c1e14b054e48fc6274573734bdb -size 2898 diff --git a/Assets/Editor/Scripts/Shelves/icons/Fuzziness.png b/Assets/Editor/Scripts/Shelves/icons/Fuzziness.png deleted file mode 100644 index 6ca7e20209..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Fuzziness.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0fa6d24bbb7f969a71b9e761f2dc4ec990a7e522201af9b13b2651d0565e1f0 -size 3607 diff --git a/Assets/Editor/Scripts/Shelves/icons/Gloss.png b/Assets/Editor/Scripts/Shelves/icons/Gloss.png deleted file mode 100644 index 5063b7f01e..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Gloss.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d5b949330e86f02662bb3b25db123fd77be31c910ad7e1e21223a543820ce46a -size 2959 diff --git a/Assets/Editor/Scripts/Shelves/icons/Normal_Texture_Res_360.png b/Assets/Editor/Scripts/Shelves/icons/Normal_Texture_Res_360.png deleted file mode 100644 index 3ca3270344..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Normal_Texture_Res_360.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:49086e4fa1736415d79d7d1d5ed8484b49582db8c27957148ef2a6d7f5dec189 -size 3176 diff --git a/Assets/Editor/Scripts/Shelves/icons/PrefabAddLibrary.png b/Assets/Editor/Scripts/Shelves/icons/PrefabAddLibrary.png deleted file mode 100644 index 899b8cbc57..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/PrefabAddLibrary.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0d9c3f0be3c978deaa053d458a49908e99d8d0f7e87169b5b03b7f500e37f55 -size 3248 diff --git a/Assets/Editor/Scripts/Shelves/icons/PrefabAddSelection.png b/Assets/Editor/Scripts/Shelves/icons/PrefabAddSelection.png deleted file mode 100644 index 6144e48a2b..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/PrefabAddSelection.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5d98fa218cf0c13100584611e1c4d536bdd9cf78a4a10dd1a0a49e4265b5292d -size 503 diff --git a/Assets/Editor/Scripts/Shelves/icons/PrefabBreak.png b/Assets/Editor/Scripts/Shelves/icons/PrefabBreak.png deleted file mode 100644 index 9982a71078..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/PrefabBreak.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e538188411092f7a172ef364035df77dc228bc91d43cfc35ffbbd824e716800e -size 3231 diff --git a/Assets/Editor/Scripts/Shelves/icons/PrefabConvert.png b/Assets/Editor/Scripts/Shelves/icons/PrefabConvert.png deleted file mode 100644 index cdbd6d2ac7..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/PrefabConvert.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:52b2c98b0f50fcfdd8334bcde259aef0a0533055f6caa1a1606536f5d2eca23f -size 3079 diff --git a/Assets/Editor/Scripts/Shelves/icons/PrefabCreate.png b/Assets/Editor/Scripts/Shelves/icons/PrefabCreate.png deleted file mode 100644 index 1aad8f3446..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/PrefabCreate.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:40905f7865cd5a71bfdace3943ccdd8fe532ee111419fb023befac357256eb07 -size 490 diff --git a/Assets/Editor/Scripts/Shelves/icons/PrefabIsolate.png b/Assets/Editor/Scripts/Shelves/icons/PrefabIsolate.png deleted file mode 100644 index 4c1a1766b5..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/PrefabIsolate.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:31f8f9a5ff20b33bdf86af8da579717cda40e097db6f893ec4e2fffab720f90e -size 3211 diff --git a/Assets/Editor/Scripts/Shelves/icons/Scattering.png b/Assets/Editor/Scripts/Shelves/icons/Scattering.png deleted file mode 100644 index 3c2c5cff38..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Scattering.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9ec02e421b4e832f73576d1f1bf2b6bc60879521f3a8abbb554925982574c374 -size 3146 diff --git a/Assets/Editor/Scripts/Shelves/icons/Solid_Wireframe.png b/Assets/Editor/Scripts/Shelves/icons/Solid_Wireframe.png deleted file mode 100644 index e439baed1b..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Solid_Wireframe.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bcc61dfe03d5bae6060c1fc6814b7be299705803fdb9058cabe6227f386ddeef -size 2872 diff --git a/Assets/Editor/Scripts/Shelves/icons/Spec_Amount.png b/Assets/Editor/Scripts/Shelves/icons/Spec_Amount.png deleted file mode 100644 index 7561feb7c0..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Spec_Amount.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a67c8e063331c5c6ce256892abdde113f405c60854115ba87f6798d06f57eb02 -size 2892 diff --git a/Assets/Editor/Scripts/Shelves/icons/Spec_Lighting.png b/Assets/Editor/Scripts/Shelves/icons/Spec_Lighting.png deleted file mode 100644 index f08a036519..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Spec_Lighting.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:927d3b2f83e6e962a492ea625240bb5f336e30aa2052d1f8699b76a86a5e475d -size 2897 diff --git a/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_1024.png b/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_1024.png deleted file mode 100644 index 2d4b08f5fb..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_1024.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a3861aa38f3e521127a48f08e6c24e12e61c15450bb4d10ef27a0a95c2c420c0 -size 2889 diff --git a/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_256.png b/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_256.png deleted file mode 100644 index 4b1ceef8ab..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_256.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5ecc3596974c0c9f1703d51e60de2ca00a479012d98f11316966686cc891f982 -size 2922 diff --git a/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_512.png b/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_512.png deleted file mode 100644 index 4f328adf91..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/Texel_Per_Meter_512.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce1ca5c1d89cd6d7a0cf35142be114904ec469afab2fa69a12afe6824055b67b -size 2913 diff --git a/Assets/Editor/Scripts/Shelves/icons/all.png b/Assets/Editor/Scripts/Shelves/icons/all.png deleted file mode 100644 index 1b6e3b12d6..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/all.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ffcf54b92f48aa06f38e94826a76f350b425ad9d46c0e2170455730123a69a6d -size 3693 diff --git a/Assets/Editor/Scripts/Shelves/icons/beams.png b/Assets/Editor/Scripts/Shelves/icons/beams.png deleted file mode 100644 index 9263cc070a..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/beams.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:68c4333ba27b39baed2696fa90040cc4e669dbc5e9fab43b11abd854d5482474 -size 613 diff --git a/Assets/Editor/Scripts/Shelves/icons/blanker.png b/Assets/Editor/Scripts/Shelves/icons/blanker.png deleted file mode 100644 index 277a067134..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/blanker.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:adac9f1fc606475d1d86ca8f5b2376570ebc70161e4b5240ede3cb8f176b8f41 -size 2810 diff --git a/Assets/Editor/Scripts/Shelves/icons/bounding_box.png b/Assets/Editor/Scripts/Shelves/icons/bounding_box.png deleted file mode 100644 index 854a9f957c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/bounding_box.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f00fa9904ce4687aaf21f1553d03bf1d47390d007fd38513ad959f324a4b6ebb -size 3618 diff --git a/Assets/Editor/Scripts/Shelves/icons/brushes.png b/Assets/Editor/Scripts/Shelves/icons/brushes.png deleted file mode 100644 index 283af0629c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/brushes.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ed21a97324849633d156ec03f949a3cf21b8b682a3a6ad1dcfac6eee9df7a497 -size 734 diff --git a/Assets/Editor/Scripts/Shelves/icons/cloud.png b/Assets/Editor/Scripts/Shelves/icons/cloud.png deleted file mode 100644 index 8f28b28613..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/cloud.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:11599538b6bc197e92f07db149ccdfee50ddea630f095865bac9782254a7c06f -size 387 diff --git a/Assets/Editor/Scripts/Shelves/icons/cloud_dark.png b/Assets/Editor/Scripts/Shelves/icons/cloud_dark.png deleted file mode 100644 index 28d1d0281b..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/cloud_dark.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:559ec911f9cac84de411e92d746913c3828ebf1d1f8c7bab794fb9c768c1581d -size 387 diff --git a/Assets/Editor/Scripts/Shelves/icons/cloud_dark_rain.png b/Assets/Editor/Scripts/Shelves/icons/cloud_dark_rain.png deleted file mode 100644 index 7119b0387f..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/cloud_dark_rain.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:88d11b32db70a437fd8ff8c845b4ff26182d28f5b7a2f6b3de4fce61dffff98d -size 489 diff --git a/Assets/Editor/Scripts/Shelves/icons/collisions.png b/Assets/Editor/Scripts/Shelves/icons/collisions.png deleted file mode 100644 index af947db919..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/collisions.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0510fa11c090234a2008703917834ad0455bc6e5e9a2d2375ebd0fc279b41851 -size 3491 diff --git a/Assets/Editor/Scripts/Shelves/icons/create_ao_volume_box.png b/Assets/Editor/Scripts/Shelves/icons/create_ao_volume_box.png deleted file mode 100644 index 558a3eba64..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/create_ao_volume_box.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:24fc2750f740f0b85ca720beedb564f2a01bbeed229cb89c6d8f395d5cf5d439 -size 844 diff --git a/Assets/Editor/Scripts/Shelves/icons/create_both_vis_box_envprobe.png b/Assets/Editor/Scripts/Shelves/icons/create_both_vis_box_envprobe.png deleted file mode 100644 index d4b1023cdb..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/create_both_vis_box_envprobe.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:000effa8925a61313fdf420830857172bc69c38cb8a14737a389b9c9df1b36df -size 745 diff --git a/Assets/Editor/Scripts/Shelves/icons/create_envprobe.png b/Assets/Editor/Scripts/Shelves/icons/create_envprobe.png deleted file mode 100644 index bdaf8fdf2c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/create_envprobe.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9d91f30f31576dc957f57d59e2b94d6e45c9aef28f321240c31639c148f62aea -size 803 diff --git a/Assets/Editor/Scripts/Shelves/icons/create_portal_box.png b/Assets/Editor/Scripts/Shelves/icons/create_portal_box.png deleted file mode 100644 index 416952b279..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/create_portal_box.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6452c7e2baef1d8d285a96e72d053a8af80430e52a149ce14795c946d55896fb -size 807 diff --git a/Assets/Editor/Scripts/Shelves/icons/create_vis_box.png b/Assets/Editor/Scripts/Shelves/icons/create_vis_box.png deleted file mode 100644 index 74ac6eac4d..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/create_vis_box.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0d5e21ccaec784d3118a2609e5f26caca4a26901a92db0821e2e0f18e555534 -size 833 diff --git a/Assets/Editor/Scripts/Shelves/icons/create_vis_box_and_portal_box.png b/Assets/Editor/Scripts/Shelves/icons/create_vis_box_and_portal_box.png deleted file mode 100644 index 5da50020d9..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/create_vis_box_and_portal_box.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e5717c6fde94577b831b8d83104733f86ed82f030664624d62cb4a6d26dd5646 -size 822 diff --git a/Assets/Editor/Scripts/Shelves/icons/create_vis_box_env_probe_and_portal.png b/Assets/Editor/Scripts/Shelves/icons/create_vis_box_env_probe_and_portal.png deleted file mode 100644 index cd39aade30..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/create_vis_box_env_probe_and_portal.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:07e831e8cab5e1e222b4a4d6a64932bbb8a9a5fcb7cae020432905a7c1e53402 -size 782 diff --git a/Assets/Editor/Scripts/Shelves/icons/cubemap.png b/Assets/Editor/Scripts/Shelves/icons/cubemap.png deleted file mode 100644 index d55d04b978..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/cubemap.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9775b4823563dbff4c3410c1751f022e2985f91202e6d691f86172ef1f820f4b -size 3353 diff --git a/Assets/Editor/Scripts/Shelves/icons/decals.png b/Assets/Editor/Scripts/Shelves/icons/decals.png deleted file mode 100644 index b9e4c92bd7..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/decals.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c12d69b2d85c339bbff06011fff7c2468a2b2e6c67726ad7fb0ab82384eb39df -size 918 diff --git a/Assets/Editor/Scripts/Shelves/icons/default_material.png b/Assets/Editor/Scripts/Shelves/icons/default_material.png deleted file mode 100644 index 9fda69eaab..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/default_material.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:98146b9b75602ddc8a46529fe0427303491dfe4584cadb914d3774377593c7ef -size 3809 diff --git a/Assets/Editor/Scripts/Shelves/icons/default_material_with_normals.png b/Assets/Editor/Scripts/Shelves/icons/default_material_with_normals.png deleted file mode 100644 index cbb0f9bbf2..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/default_material_with_normals.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a1c7e790dad53937ed0845cb89c5651c7932a696d7d34d85df6fc8c4b09c7245 -size 3106 diff --git a/Assets/Editor/Scripts/Shelves/icons/designer.png b/Assets/Editor/Scripts/Shelves/icons/designer.png deleted file mode 100644 index 9018385ebb..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/designer.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e790bb52b7f7d52e79b2c5b84ee4a4587a721c7e3c70d2d7e0eb683b478b51f7 -size 1015 diff --git a/Assets/Editor/Scripts/Shelves/icons/diff_acc.png b/Assets/Editor/Scripts/Shelves/icons/diff_acc.png deleted file mode 100644 index df3eac041c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/diff_acc.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b341792fb1c13db8144f74c3895942251c07e67e87ac374c09df21e3459b3610 -size 3930 diff --git a/Assets/Editor/Scripts/Shelves/icons/display_info.png b/Assets/Editor/Scripts/Shelves/icons/display_info.png deleted file mode 100644 index 22572bc6e5..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/display_info.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0fc2408c2f1801de3f625dcbdf960104195c1d47d7e240f4ec9391a7b645399c -size 3623 diff --git a/Assets/Editor/Scripts/Shelves/icons/dual_layer_mask.png b/Assets/Editor/Scripts/Shelves/icons/dual_layer_mask.png deleted file mode 100644 index c47a0f7350..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/dual_layer_mask.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:80bca215bbcec9d9e1e33abfbf0b17d6032327a175d6f9d4d76bfefd5c7f2480 -size 3517 diff --git a/Assets/Editor/Scripts/Shelves/icons/dynamiclights.png b/Assets/Editor/Scripts/Shelves/icons/dynamiclights.png deleted file mode 100644 index 541d8f9304..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/dynamiclights.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ef3cae03d5f38bdf9e82ff29b1a77133a44e5e859cfdb063c449ee5609902367 -size 780 diff --git a/Assets/Editor/Scripts/Shelves/icons/entities.png b/Assets/Editor/Scripts/Shelves/icons/entities.png deleted file mode 100644 index 0bf2eda8cc..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/entities.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:42de1878f5cef5c3f80dd56e042584eeb8759cacd58a0b22115644ed38800836 -size 870 diff --git a/Assets/Editor/Scripts/Shelves/icons/eye_adaptation_speed.png b/Assets/Editor/Scripts/Shelves/icons/eye_adaptation_speed.png deleted file mode 100644 index a485e39655..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/eye_adaptation_speed.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f1b4a6d4cca72740f14e97239bf8490d23ccb3d9283d4ff558f0302d9fa773ad -size 1017 diff --git a/Assets/Editor/Scripts/Shelves/icons/fog.png b/Assets/Editor/Scripts/Shelves/icons/fog.png deleted file mode 100644 index 68137429de..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/fog.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4dea1c985077475184c32562609e27b7919cd1c08776174a83f38f095a11f3d4 -size 394 diff --git a/Assets/Editor/Scripts/Shelves/icons/fogvolumes.png b/Assets/Editor/Scripts/Shelves/icons/fogvolumes.png deleted file mode 100644 index 8c305abb4a..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/fogvolumes.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bbf140c23e75f1c1035defd58ec8522230abdb5fc7538953ed88eb3bc06c9ca3 -size 349 diff --git a/Assets/Editor/Scripts/Shelves/icons/freeze_particles.png b/Assets/Editor/Scripts/Shelves/icons/freeze_particles.png deleted file mode 100644 index 963374b096..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/freeze_particles.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:52986df9e8a866606cbfbe8a9702f15483a6f3bfa0b15563e64a5c6d208dab55 -size 4076 diff --git a/Assets/Editor/Scripts/Shelves/icons/full_shading.png b/Assets/Editor/Scripts/Shelves/icons/full_shading.png deleted file mode 100644 index 4decb4c800..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/full_shading.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:339d6542b6a259feeb7dc8ebc536ca6fed44a91faaf021b1453a735b39d98450 -size 3021 diff --git a/Assets/Editor/Scripts/Shelves/icons/gamma.png b/Assets/Editor/Scripts/Shelves/icons/gamma.png deleted file mode 100644 index 43b16f55a6..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/gamma.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b93bb51dd54685b9dd1a37b535c7cb456110b45c62ae64eaaceb61a58b99f254 -size 1418 diff --git a/Assets/Editor/Scripts/Shelves/icons/gi.png b/Assets/Editor/Scripts/Shelves/icons/gi.png deleted file mode 100644 index 51fb05190c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/gi.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cbc47ed9888c792af55b4e0ab5d5c7a7b8a582fdb202fa035e21b974c7df1022 -size 885 diff --git a/Assets/Editor/Scripts/Shelves/icons/lens_flare.png b/Assets/Editor/Scripts/Shelves/icons/lens_flare.png deleted file mode 100644 index 2da269b7c7..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/lens_flare.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e2cbf9570c227884d49ac2a702377821891d06eaa91b6bf92861088508927796 -size 670 diff --git a/Assets/Editor/Scripts/Shelves/icons/lighting_only.png b/Assets/Editor/Scripts/Shelves/icons/lighting_only.png deleted file mode 100644 index bd4590053c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/lighting_only.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:695dcdc3004705d1489b5b2a0a750bf6d30940d343a62bc8ff06bc103d3ae6f7 -size 2870 diff --git a/Assets/Editor/Scripts/Shelves/icons/lods.png b/Assets/Editor/Scripts/Shelves/icons/lods.png deleted file mode 100644 index a6ad158679..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/lods.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:266450829046d2be9557c86f8061f1b50d8f55795436b608689d6c117c5b970d -size 1156 diff --git a/Assets/Editor/Scripts/Shelves/icons/lsao.png b/Assets/Editor/Scripts/Shelves/icons/lsao.png deleted file mode 100644 index 127b421a30..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/lsao.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7a253c696ce28fb7699b6879c35e874d906033b59e89224d307bf029dd9257e6 -size 3926 diff --git a/Assets/Editor/Scripts/Shelves/icons/lsao_toggle.png b/Assets/Editor/Scripts/Shelves/icons/lsao_toggle.png deleted file mode 100644 index c264be14bd..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/lsao_toggle.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:734ca55bc936d229c56abb4f141a746fe64affc570570d182308f6f0d8f21638 -size 3952 diff --git a/Assets/Editor/Scripts/Shelves/icons/lsro.png b/Assets/Editor/Scripts/Shelves/icons/lsro.png deleted file mode 100644 index ff4099a887..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/lsro.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a100211ce724c005cd2fadecb4ca3c36feacad4f7cb4bbccd8761ae622d59aa3 -size 1153 diff --git a/Assets/Editor/Scripts/Shelves/icons/normals.png b/Assets/Editor/Scripts/Shelves/icons/normals.png deleted file mode 100644 index 1f723ef0d1..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/normals.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:58e65981a6b66482ac3443f644fe210d9c90d01b4a5ab381796d37bf6d5be289 -size 3215 diff --git a/Assets/Editor/Scripts/Shelves/icons/normals_x.png b/Assets/Editor/Scripts/Shelves/icons/normals_x.png deleted file mode 100644 index 98a705b559..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/normals_x.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1be96cc2682443b03bfc4696403d5c3d98eec709878acac0b690dbb635d04ea9 -size 3227 diff --git a/Assets/Editor/Scripts/Shelves/icons/normals_y.png b/Assets/Editor/Scripts/Shelves/icons/normals_y.png deleted file mode 100644 index 8c109bee9b..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/normals_y.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2eaf04f15e42ac910dc7c29fb61034dc5126a80832b6a0bc0a842b549c23eaf7 -size 3118 diff --git a/Assets/Editor/Scripts/Shelves/icons/normals_z.png b/Assets/Editor/Scripts/Shelves/icons/normals_z.png deleted file mode 100644 index 078ceded6c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/normals_z.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0c8ec3131755522c3f1a4fc45cef0b9ace4641316d890d3f6f042557f220d6ba -size 3152 diff --git a/Assets/Editor/Scripts/Shelves/icons/ocean.png b/Assets/Editor/Scripts/Shelves/icons/ocean.png deleted file mode 100644 index 04c4fff0fc..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/ocean.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1407119e10f378a6ae375f3951dbfe42505560f75a88687f4c03e0ac2e85a05e -size 700 diff --git a/Assets/Editor/Scripts/Shelves/icons/particles.png b/Assets/Editor/Scripts/Shelves/icons/particles.png deleted file mode 100644 index daecfbc256..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/particles.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d9875276bc1b8055f306d0bf95b0ba3f6c8f9a49447a68f75334e86b360f4359 -size 713 diff --git a/Assets/Editor/Scripts/Shelves/icons/particles_bounds.png b/Assets/Editor/Scripts/Shelves/icons/particles_bounds.png deleted file mode 100644 index 04321c8ed5..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/particles_bounds.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:231f6c7939361f71b9926f551bbf2eb93ca4ec8394318dcfed0fa413ccd58e66 -size 4073 diff --git a/Assets/Editor/Scripts/Shelves/icons/particles_off.png b/Assets/Editor/Scripts/Shelves/icons/particles_off.png deleted file mode 100644 index ed7fe76f44..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/particles_off.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b6e656417153394c5466a207bd6ff21072c6ef82fe6972380ceda7fa6e60c478 -size 4053 diff --git a/Assets/Editor/Scripts/Shelves/icons/particles_overdraw.png b/Assets/Editor/Scripts/Shelves/icons/particles_overdraw.png deleted file mode 100644 index 86a8a72b52..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/particles_overdraw.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8f021d07012f712d8ab70af609974e1cb0933d571bbe0f184e0e7479ee172834 -size 3004 diff --git a/Assets/Editor/Scripts/Shelves/icons/particles_screen_coverage.png b/Assets/Editor/Scripts/Shelves/icons/particles_screen_coverage.png deleted file mode 100644 index fd20e416b2..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/particles_screen_coverage.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:387a799eeb739b6183f3d47186c122ea51c8998664bd0cff76e28f8de2cf49ee -size 4024 diff --git a/Assets/Editor/Scripts/Shelves/icons/placeholder.png b/Assets/Editor/Scripts/Shelves/icons/placeholder.png deleted file mode 100644 index f3225255c7..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/placeholder.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a91ea78d1ffd91490f20efcf76ad8790e450836240b8a77dda719da963235c85 -size 2987 diff --git a/Assets/Editor/Scripts/Shelves/icons/prefab.png b/Assets/Editor/Scripts/Shelves/icons/prefab.png deleted file mode 100644 index 84d2b08397..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/prefab.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:332071c8b20030de53ec194dfe853b29f45a0de04d99dcd1b1c4b32dcf2946a5 -size 683 diff --git a/Assets/Editor/Scripts/Shelves/icons/reflections.png b/Assets/Editor/Scripts/Shelves/icons/reflections.png deleted file mode 100644 index 0fc82618b8..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/reflections.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ee9fdf1b6ab47cfc72c3794a46b6886b9993e691a7d097b3d109127ddcde46ac -size 640 diff --git a/Assets/Editor/Scripts/Shelves/icons/reset.png b/Assets/Editor/Scripts/Shelves/icons/reset.png deleted file mode 100644 index 8cc13235ae..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/reset.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:120be39c58db0bab5450db22604f94cf31eb68a480f06daf3d4f76828461385b -size 4076 diff --git a/Assets/Editor/Scripts/Shelves/icons/selfocc.png b/Assets/Editor/Scripts/Shelves/icons/selfocc.png deleted file mode 100644 index f3a1ece6a3..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/selfocc.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:83e8233f9f0594151e734583f9fd3835250f370dac8b648554f1060d79efa43b -size 2935 diff --git a/Assets/Editor/Scripts/Shelves/icons/shaded_wireframe.png b/Assets/Editor/Scripts/Shelves/icons/shaded_wireframe.png deleted file mode 100644 index 79d4148d9c..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/shaded_wireframe.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f514eebcdcd02d8195d8b51966ad84cfb8162c3811facc6da9fc0a71e10443bc -size 3041 diff --git a/Assets/Editor/Scripts/Shelves/icons/shadows.png b/Assets/Editor/Scripts/Shelves/icons/shadows.png deleted file mode 100644 index 06fd30ee05..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/shadows.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:281c6d85ab6d7e706f73865a7beb523bf64e505d8fd2b3c367f6ad56b008a77e -size 818 diff --git a/Assets/Editor/Scripts/Shelves/icons/showlines.png b/Assets/Editor/Scripts/Shelves/icons/showlines.png deleted file mode 100644 index b4329c1beb..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/showlines.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:268a5b239b9988be0ae13a2f42a99ac39ac2db9988f92604154630b661b89999 -size 2865 diff --git a/Assets/Editor/Scripts/Shelves/icons/sky.png b/Assets/Editor/Scripts/Shelves/icons/sky.png deleted file mode 100644 index 86d018f2d8..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/sky.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3598e1bdc4c47d6be99ad6ff10e91b307bb4a94286fff57a0c339d6aaed2e0a3 -size 620 diff --git a/Assets/Editor/Scripts/Shelves/icons/spec_acc.png b/Assets/Editor/Scripts/Shelves/icons/spec_acc.png deleted file mode 100644 index b66acb25ca..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/spec_acc.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ee2c46410495a75862d8f5d2e69cce11c94745680ef03b50ba7b17af9c137656 -size 3334 diff --git a/Assets/Editor/Scripts/Shelves/icons/spec_lum.png b/Assets/Editor/Scripts/Shelves/icons/spec_lum.png deleted file mode 100644 index 7561feb7c0..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/spec_lum.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a67c8e063331c5c6ce256892abdde113f405c60854115ba87f6798d06f57eb02 -size 2892 diff --git a/Assets/Editor/Scripts/Shelves/icons/spec_occ.png b/Assets/Editor/Scripts/Shelves/icons/spec_occ.png deleted file mode 100644 index 624f8481ad..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/spec_occ.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:23a7074e8ced66649cc8c2f69db33559bd600658709aaf287a9d9de9c98a05f6 -size 3182 diff --git a/Assets/Editor/Scripts/Shelves/icons/ssao.png b/Assets/Editor/Scripts/Shelves/icons/ssao.png deleted file mode 100644 index 376a0a2157..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/ssao.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:134cbfd478080236c3f5ea2ee32319e63ee21ff48f187b709ab9dc0f3688c2dd -size 3932 diff --git a/Assets/Editor/Scripts/Shelves/icons/ssdo.png b/Assets/Editor/Scripts/Shelves/icons/ssdo.png deleted file mode 100644 index 517658c1f5..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/ssdo.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c200aad6ad59b7d466edc44026ffca2272ca3b20944070210db1108f21f1cb60 -size 3972 diff --git a/Assets/Editor/Scripts/Shelves/icons/ssdo_toggle.png b/Assets/Editor/Scripts/Shelves/icons/ssdo_toggle.png deleted file mode 100644 index 881b07cb2f..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/ssdo_toggle.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c897d61016bc32c7072273a081e624880b90beb89e90f20b25e689f5198d1f63 -size 3966 diff --git a/Assets/Editor/Scripts/Shelves/icons/sun.big.png b/Assets/Editor/Scripts/Shelves/icons/sun.big.png deleted file mode 100644 index 0a5363ddca..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/sun.big.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c49214e755a68e48bba8b8be9183777c24c3443aa734e4969e74bc42d5979cb7 -size 539 diff --git a/Assets/Editor/Scripts/Shelves/icons/tangents.png b/Assets/Editor/Scripts/Shelves/icons/tangents.png deleted file mode 100644 index 7a1f5c0a3a..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/tangents.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8a5f21232c186fed9bd9a0d62bd4023dca1d496e151ad0fee5b593fc67645bf -size 1115 diff --git a/Assets/Editor/Scripts/Shelves/icons/terrain.png b/Assets/Editor/Scripts/Shelves/icons/terrain.png deleted file mode 100644 index b32c4cde98..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/terrain.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:821ef3daa0cdf246985c0bc1bd988edeceadb672dd81f4813320e8d50ca0e41c -size 461 diff --git a/Assets/Editor/Scripts/Shelves/icons/time_scale_double.png b/Assets/Editor/Scripts/Shelves/icons/time_scale_double.png deleted file mode 100644 index 03ae1a21ea..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/time_scale_double.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:86ebd1c792b9024662a179995ba65d181157a9887112f12571fbfe05a3dc8a79 -size 3145 diff --git a/Assets/Editor/Scripts/Shelves/icons/time_scale_frozen.png b/Assets/Editor/Scripts/Shelves/icons/time_scale_frozen.png deleted file mode 100644 index a1756ce9fa..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/time_scale_frozen.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4fbe9783be75404b2364726b09f9013360522d2e71f479476a715b6577def003 -size 3386 diff --git a/Assets/Editor/Scripts/Shelves/icons/time_scale_half.png b/Assets/Editor/Scripts/Shelves/icons/time_scale_half.png deleted file mode 100644 index c3f9f03d98..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/time_scale_half.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a6740a0e38ea99c83c1460a33f62c3dead3ab85f05bf446426fb39a75aa76f8 -size 3137 diff --git a/Assets/Editor/Scripts/Shelves/icons/time_scale_quarter.png b/Assets/Editor/Scripts/Shelves/icons/time_scale_quarter.png deleted file mode 100644 index a8a9b8cdd8..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/time_scale_quarter.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b0baf9f76bcc0bcd38fea907b79edde3bcb66e78b221094473a8abd0b222734 -size 3175 diff --git a/Assets/Editor/Scripts/Shelves/icons/time_scale_tenth.png b/Assets/Editor/Scripts/Shelves/icons/time_scale_tenth.png deleted file mode 100644 index 0aba084827..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/time_scale_tenth.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f71d44c06aa67ab94b190bd74516ce73c534a7d6421415437db262659b2ff32a -size 3124 diff --git a/Assets/Editor/Scripts/Shelves/icons/tod.png b/Assets/Editor/Scripts/Shelves/icons/tod.png deleted file mode 100644 index 0d5c4682c2..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/tod.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6028cef57651c79f5eb83c52eb0ab63eb42dbf4014dcb0f60c4c15ab8fe3cafd -size 977 diff --git a/Assets/Editor/Scripts/Shelves/icons/translucency.png b/Assets/Editor/Scripts/Shelves/icons/translucency.png deleted file mode 100644 index 8487c5916f..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/translucency.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:07457d1315f4cf1bd931187d849a1e842c931640edb53abb2a4f5b2d8d65716b -size 3110 diff --git a/Assets/Editor/Scripts/Shelves/icons/transparency.png b/Assets/Editor/Scripts/Shelves/icons/transparency.png deleted file mode 100644 index 4f41c6491b..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/transparency.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e59571a1490d7dd4696bc118bd4ccc8e08a663afac1ce3f2d88bb5d7d6fdb196 -size 558 diff --git a/Assets/Editor/Scripts/Shelves/icons/valid_albedo.png b/Assets/Editor/Scripts/Shelves/icons/valid_albedo.png deleted file mode 100644 index c3a76d6dfa..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/valid_albedo.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce233f32949099694d4294b95252068c4486edba163a466ebdb20a54a2338f0f -size 3120 diff --git a/Assets/Editor/Scripts/Shelves/icons/valid_spec_lum.png b/Assets/Editor/Scripts/Shelves/icons/valid_spec_lum.png deleted file mode 100644 index 13f8404057..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/valid_spec_lum.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5f365970f6f9138d6e78a2053338eb1275c562fb700670ab00e800e6a43280d -size 3199 diff --git a/Assets/Editor/Scripts/Shelves/icons/vegetation.png b/Assets/Editor/Scripts/Shelves/icons/vegetation.png deleted file mode 100644 index 4492e38ce8..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/vegetation.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:48a435a0632d7d0a8bdfee418423d8c411c4eab9b1da0fac257f32451a233d8f -size 747 diff --git a/Assets/Editor/Scripts/Shelves/icons/vertex_normals.png b/Assets/Editor/Scripts/Shelves/icons/vertex_normals.png deleted file mode 100644 index 80c51660c0..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/vertex_normals.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:101e61f7e5b40aaa48bed685f854fc01c58aec66ca8becc5386f6f0c22c020ad -size 1114 diff --git a/Assets/Editor/Scripts/Shelves/icons/vis_area.png b/Assets/Editor/Scripts/Shelves/icons/vis_area.png deleted file mode 100644 index 0d16d4a477..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/vis_area.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae9997b5b999a6b66e56d6024617f718ea06fd389a98a97465a5d76780a1da75 -size 3915 diff --git a/Assets/Editor/Scripts/Shelves/icons/water_volume.png b/Assets/Editor/Scripts/Shelves/icons/water_volume.png deleted file mode 100644 index 2be9a96264..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/water_volume.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e88a2a6e4d14bced3d3e48c25d4bfe075d8587898cd61fbd0e3ab99e4391e663 -size 602 diff --git a/Assets/Editor/Scripts/Shelves/icons/wind.png b/Assets/Editor/Scripts/Shelves/icons/wind.png deleted file mode 100644 index 54ed666138..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/wind.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:caa003d65336c2e2a8987122ace98e0300e5d8afe1864dffef0d1651b136ccc1 -size 720 diff --git a/Assets/Editor/Scripts/Shelves/icons/wireframe.png b/Assets/Editor/Scripts/Shelves/icons/wireframe.png deleted file mode 100644 index 85a71daccc..0000000000 --- a/Assets/Editor/Scripts/Shelves/icons/wireframe.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fd5356c97575c12fa7038443c0216a316c234e4e50e2e439ff8dde4504e56243 -size 2848 diff --git a/Code/Editor/ToolBox.cpp b/Code/Editor/ToolBox.cpp index 77cb479873..82817e1ff7 100644 --- a/Code/Editor/ToolBox.cpp +++ b/Code/Editor/ToolBox.cpp @@ -321,42 +321,13 @@ bool CToolBoxManager::SetMacroTitle(int index, const QString& title, bool bToolb } ////////////////////////////////////////////////////////////////////////// -void CToolBoxManager::Load(ActionManager* actionManager) +void CToolBoxManager::Load([[maybe_unused]] ActionManager* actionManager) { Clear(); QString path; GetSaveFilePath(path); Load(path, nullptr, true, nullptr); - - if (actionManager) - { - auto engineSourceAssetPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / "Assets"; - LoadShelves((engineSourceAssetPath / "Editor" / "Scripts").c_str(), - (engineSourceAssetPath / "Editor" / "Scripts" / "Shelves").c_str(), actionManager); - } -} - -void CToolBoxManager::LoadShelves(QString scriptPath, QString shelvesPath, ActionManager* actionManager) -{ - IFileUtil::FileArray files; - CFileUtil::ScanDirectory(shelvesPath, "*.xml", files); - - const int shelfCount = files.size(); - for (int idx = 0; idx < shelfCount; ++idx) - { - if (Path::GetExt(files[idx].filename) != "xml") - { - continue; - } - - QString shelfName(PathUtil::GetFileName(files[idx].filename.toUtf8().data())); - - AmazonToolbar toolbar(shelfName, shelfName); - Load(shelvesPath + QString("/") + files[idx].filename, &toolbar, false, actionManager); - - m_toolbars.push_back(toolbar); - } } void CToolBoxManager::Load(QString xmlpath, AmazonToolbar* pToolbar, bool bToolbox, ActionManager* actionManager) diff --git a/Code/Editor/ToolBox.h b/Code/Editor/ToolBox.h index 691b9cd089..0c91305c79 100644 --- a/Code/Editor/ToolBox.h +++ b/Code/Editor/ToolBox.h @@ -129,7 +129,6 @@ public: void Save() const; // Load macros configuration from registry. void Load(ActionManager* actionManager = nullptr); - void LoadShelves(QString scriptPath, QString shelvesPath, ActionManager* actionManager); //! Get the number of managed macros. int GetMacroCount(bool bToolbox) const; From 7d84a005c00c1b1c3d1b9ef0e5456d0ecf15146d Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 2 Aug 2021 10:49:13 -0700 Subject: [PATCH 106/157] Updated unit tests and fixed build failures. --- .../Model/ModelAssetBuilderComponent.h | 1 + Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp | 46 +++++++++++-------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h index 832a8700ba..843f756df6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.h @@ -42,6 +42,7 @@ namespace AZ using SkinData = AZ::SceneAPI::DataTypes::ISkinWeightData; class Stream; + class ModelAssetCreator; class ModelLodAssetCreator; class BufferAssetCreator; struct PackedCompressedMorphTargetDelta; diff --git a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp index cdf0d0166d..625240a01f 100644 --- a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -91,7 +92,7 @@ namespace UnitTest AZ::Aabb m_aabb = AZ::Aabb::CreateNull(); uint32_t m_indexCount = 0; uint32_t m_vertexCount = 0; - AZ::Data::Asset m_material; + AZ::RPI::ModelMaterialSlot::StableId m_materialSlotId = AZ::RPI::ModelMaterialSlot::InvalidStableId; }; struct ExpectedLod @@ -136,6 +137,7 @@ namespace UnitTest return true; } + //! This function assumes the model has "sharedMeshCount + separateMeshCount" unique material slots, with incremental IDs starting at 0. AZ::Data::Asset BuildTestLod(const uint32_t sharedMeshCount, const uint32_t separateMeshCount, ExpectedLod& expectedLod) { using namespace AZ; @@ -148,6 +150,8 @@ namespace UnitTest const uint32_t indexCount = 36; const uint32_t vertexCount = 36; + RPI::ModelMaterialSlot::StableId materialSlotId = 0; + if(sharedMeshCount > 0) { const uint32_t sharedIndexCount = indexCount * sharedMeshCount; @@ -164,7 +168,7 @@ namespace UnitTest ExpectedMesh expectedMesh; expectedMesh.m_indexCount = indexCount; expectedMesh.m_vertexCount = vertexCount; - expectedMesh.m_material = m_materialAsset; + expectedMesh.m_materialSlotId = i; RHI::BufferViewDescriptor indexBufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(i * indexCount, indexCount, sizeof(uint32_t)); @@ -180,7 +184,7 @@ namespace UnitTest creator.BeginMesh(); Aabb aabb = expectedMesh.m_aabb; creator.SetMeshAabb(AZStd::move(aabb)); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(materialSlotId++); creator.SetMeshIndexBuffer({ sharedIndexBuffer, indexBufferViewDescriptor }); creator.AddMeshStreamBuffer(GetPositionSemantic(), AZ::Name(), { sharedPositionBuffer, vertexBufferViewDescriptor }); creator.EndMesh(); @@ -195,7 +199,7 @@ namespace UnitTest ExpectedMesh expectedMesh; expectedMesh.m_indexCount = indexCount; expectedMesh.m_vertexCount = vertexCount; - expectedMesh.m_material = m_materialAsset; + expectedMesh.m_materialSlotId = sharedMeshCount + i; RHI::BufferViewDescriptor indexBufferViewDescriptor = RHI::BufferViewDescriptor::CreateStructured(0, indexCount, sizeof(uint32_t)); @@ -213,7 +217,7 @@ namespace UnitTest creator.BeginMesh(); Aabb aabb = expectedMesh.m_aabb; creator.SetMeshAabb(AZStd::move(aabb)); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(materialSlotId++); creator.SetMeshIndexBuffer({ BuildTestBuffer(indexCount, sizeof(uint32_t)), indexBufferViewDescriptor }); creator.AddMeshStreamBuffer(GetPositionSemantic(), AZ::Name(), { positonBuffer, positionBufferViewDescriptor }); @@ -239,6 +243,15 @@ namespace UnitTest creator.Begin(Data::AssetId(AZ::Uuid::CreateRandom())); creator.SetName("TestModel"); + + for (RPI::ModelMaterialSlot::StableId materialSlotId = 0; materialSlotId < sharedMeshCount + separateMeshCount; ++materialSlotId) + { + RPI::ModelMaterialSlot slot; + slot.m_defaultMaterialAsset = m_materialAsset; + slot.m_displayName = AZStd::string::format("Slot%d", materialSlotId); + slot.m_stableId = materialSlotId; + creator.AddMaterialSlot(slot); + } for (uint32_t i = 0; i < lodCount; ++i) { @@ -263,7 +276,7 @@ namespace UnitTest EXPECT_TRUE(mesh.GetAabb() == expectedMesh.m_aabb); EXPECT_TRUE(mesh.GetIndexCount() == expectedMesh.m_indexCount); EXPECT_TRUE(mesh.GetVertexCount() == expectedMesh.m_vertexCount); - EXPECT_TRUE(mesh.GetMaterialAsset() == expectedMesh.m_material); + EXPECT_TRUE(mesh.GetMaterialSlotId() == expectedMesh.m_materialSlotId); } void ValidateLodAsset(const AZ::RPI::ModelLodAsset* lodAsset, const ExpectedLod& expectedLod) @@ -687,11 +700,11 @@ namespace UnitTest } } - // Tests that if we try to set the material id on a mesh + // Tests that if we try to set the material slot on a mesh // without calling Begin or BeginMesh that it fails // as expected. Also tests the case that Begin *is* // called but BeginMesh is not. - TEST_F(ModelTests, SetMaterialIdNoBeginNoBeginMesh) + TEST_F(ModelTests, SetMaterialSlotNoBeginNoBeginMesh) { using namespace AZ; @@ -699,7 +712,7 @@ namespace UnitTest { ErrorMessageFinder messageFinder("Begin() was not called"); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(0); } creator.Begin(Data::AssetId(AZ::Uuid::CreateRandom())); @@ -707,7 +720,7 @@ namespace UnitTest //This should still fail even if we call Begin but not BeginMesh { ErrorMessageFinder messageFinder("BeginMesh() was not called"); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(0); } } @@ -827,7 +840,7 @@ namespace UnitTest creator.BeginMesh(); creator.SetMeshAabb(AZStd::move(aabb)); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(0); creator.SetMeshIndexBuffer({ BuildTestBuffer(indexCount, sizeof(uint32_t)), indexBufferViewDescriptor }); creator.AddMeshStreamBuffer(GetPositionSemantic(), AZ::Name(), { BuildTestBuffer(vertexCount, sizeof(float) * 3), vertexBufferViewDescriptor }); @@ -842,7 +855,7 @@ namespace UnitTest ErrorMessageFinder messageFinder("BeginMesh() was not called", 5); creator.SetMeshAabb(AZStd::move(aabb)); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(0); creator.SetMeshIndexBuffer({ BuildTestBuffer(indexCount, sizeof(uint32_t)), indexBufferViewDescriptor }); creator.AddMeshStreamBuffer(GetPositionSemantic(), AZ::Name(), { BuildTestBuffer(vertexCount, sizeof(float) * 3), vertexBufferViewDescriptor }); @@ -885,7 +898,7 @@ namespace UnitTest creator.BeginMesh(); creator.SetMeshAabb(AZStd::move(aabb)); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(0); creator.SetMeshIndexBuffer({ BuildTestBuffer(indexCount, sizeof(uint32_t)), indexBufferViewDescriptor }); creator.AddMeshStreamBuffer(GetPositionSemantic(), AZ::Name(), { BuildTestBuffer(vertexCount, sizeof(float) * 3), vertexBufferViewDescriptor }); @@ -907,7 +920,7 @@ namespace UnitTest creator.BeginMesh(); creator.SetMeshAabb(AZStd::move(aabb)); - creator.SetMeshMaterialAsset(m_materialAsset); + creator.SetMeshMaterialSlot(0); creator.SetMeshIndexBuffer({ BuildTestBuffer(indexCount, sizeof(uint32_t)), indexBufferViewDescriptor }); creator.AddMeshStreamBuffer(GetPositionSemantic(), AZ::Name(), { BuildTestBuffer(vertexCount, sizeof(float) * 3), vertexBufferViewDescriptor }); @@ -1019,10 +1032,7 @@ namespace UnitTest lodCreator.BeginMesh(); lodCreator.SetMeshAabb(AZ::Aabb::CreateFromMinMax({-1.0f, -1.0f, -0.5f}, {1.0f, 1.0f, 0.5f})); - lodCreator.SetMeshMaterialAsset( - AZ::Data::Asset(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0), - AZ::AzTypeInfo::Uuid(), "") - ); + lodCreator.SetMeshMaterialSlot(AZ::Sfmt::GetInstance().Rand32()); { AZ::Data::Asset indexBuffer = BuildTestBuffer(indicesCount, sizeof(uint32_t)); From 9ee9730294bb1f4b4a260a90c5f551cb8c42549d Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Mon, 2 Aug 2021 10:57:57 -0700 Subject: [PATCH 107/157] Automated test for scene files with and without python scripts running python incorrectly (#2373) * Cleared m_scriptFilename between scene files. This fixes a bug where a Python script file would be run on a scene file that didn't have a script file set. Added a general case version to SceneBuilderWorker.cpp, to make it easy to mark all scene files as dirty. Automated tests for this will come in a separate pull request. Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Work in progress automated tests Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Python test done Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Sorted jobs work now. This may sort too aggressively, I'll remove the additional sorting after some testing. Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Cleaned up test Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Fixed stray ' Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Removed temp code from test Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Command line help options for AP Removed job sorting that wasn't actually sorting jobs Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Changed constant variable names to match coding standards Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- .../PythonTests/assetpipeline/CMakeLists.txt | 1 + .../assetpipeline/fbx_tests/CMakeLists.txt | 21 ++++ .../a_simple_box_with_script.fbx | 3 + .../a_simple_box_with_script.fbx.assetinfo | 9 ++ .../b_simple_box_no_script.fbx | 3 + .../b_simple_box_no_script.fbx.assetinfo | 15 +++ .../python_builder.py | 45 +++++++ .../fbx_tests/pythonassetbuildertests.py | 94 ++++++++++++++ .../AssetManager/assetProcessorManager.cpp | 6 +- .../AssetManager/assetProcessorManager.h | 5 + .../AssetProcessor/native/assetprocessor.h | 5 + .../resourcecompiler/RCQueueSortModel.cpp | 10 ++ .../resourcecompiler/RCQueueSortModel.h | 9 ++ .../native/resourcecompiler/rccontroller.cpp | 5 + .../native/resourcecompiler/rccontroller.h | 5 +- .../utilities/ApplicationManagerBase.cpp | 118 ++++++++++++++---- .../native/utilities/ApplicationManagerBase.h | 5 + 17 files changed, 329 insertions(+), 30 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx.assetinfo create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx.assetinfo create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/python_builder.py create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/pythonassetbuildertests.py diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt index 1b42d0d871..29b30a12b4 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt @@ -7,6 +7,7 @@ # add_subdirectory(asset_processor_tests) +add_subdirectory(fbx_tests) if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) ## AP Python Tests ## diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt new file mode 100644 index 0000000000..4a26500ee2 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) + ly_add_pytest( + NAME SceneProcessingTests.PythonAssetBuilderTests + TEST_SUITE main + PATH ${CMAKE_CURRENT_LIST_DIR}/pythonassetbuildertests.py + PYTEST_MARKS "not SUITE_sandbox" # don't run sandbox tests in this file + EXCLUDE_TEST_RUN_TARGET_FROM_IDE + RUNTIME_DEPENDENCIES + AZ::AssetProcessorBatch + AZ::AssetProcessor + ) + +endif() diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx new file mode 100644 index 0000000000..e31b4a96f2 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f82aecb36faf5cf9f2730e5ad264db38a3a469f8f48aff9b74682d1a32b098f0 +size 11644 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx.assetinfo b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx.assetinfo new file mode 100644 index 0000000000..07018ab521 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/a_simple_box_with_script.fbx.assetinfo @@ -0,0 +1,9 @@ +{ + "values": + [ + { + "$type": "ScriptProcessorRule", + "scriptFilename": "TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/python_builder.py" + } + ] +} diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx new file mode 100644 index 0000000000..e31b4a96f2 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f82aecb36faf5cf9f2730e5ad264db38a3a469f8f48aff9b74682d1a32b098f0 +size 11644 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx.assetinfo b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx.assetinfo new file mode 100644 index 0000000000..72d756d655 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/b_simple_box_no_script.fbx.assetinfo @@ -0,0 +1,15 @@ +{ + "values": [ + { + "$type": "{07B356B7-3635-40B5-878A-FAC4EFD5AD86} MeshGroup", + "name": "b_simple_box_no_script", + "nodeSelectionList": { + "selectedNodes": [ + {}, + "RootNode", + "RootNode.Cube" + ] + } + } + ] +} \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/python_builder.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/python_builder.py new file mode 100644 index 0000000000..7ad5894a86 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene/python_builder.py @@ -0,0 +1,45 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" +import datetime, uuid, os +import azlmbr.scene as sceneApi +import azlmbr.scene.graph + +def output_test_data(scene): + source_filename = os.path.basename(scene.sourceFilename) + source_filename = source_filename.replace('.','_') + + log_output_file_name = f"{source_filename}.log" + + log_output_folder = os.path.dirname(scene.sourceFilename) + log_output_location = os.path.join(log_output_folder, log_output_file_name) + + # Saving a file to the temp folder is the easiest way to have this test communicate + # with the outer python test. + with open(log_output_location, "w") as f: + # Just write something to the file, but the filename is the main information + # used for the test. + f.write(f"scene.sourceFilename: {scene.sourceFilename}\n") + return True + +mySceneJobHandler = None + +def on_update_manifest(args): + scene = args[0] + result = output_test_data(scene) + global mySceneJobHandler + mySceneJobHandler.disconnect() + mySceneJobHandler = None + return result + +def main(): + global mySceneJobHandler + mySceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() + mySceneJobHandler.connect() + mySceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/pythonassetbuildertests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/pythonassetbuildertests.py new file mode 100644 index 0000000000..6a568349d2 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/pythonassetbuildertests.py @@ -0,0 +1,94 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +# Import builtin libraries +import pytest +import logging +import os +import stat + +# Import LyTestTools +from ly_test_tools.o3de.asset_processor import AssetProcessor +from ly_test_tools.o3de import asset_processor as asset_processor_utils +import ly_test_tools.environment.file_system as fs + +# Import fixtures +from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor +from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture + +# Import LyShared +from ly_test_tools.o3de.ap_log_parser import APLogParser, APOutputParser +import ly_test_tools.o3de.pipeline_utils as utils + +# Use the following logging pattern to hook all test logging together: +logger = logging.getLogger(__name__) +# Configuring the logging is done in ly_test_tools at the following location: +# ~/dev/Tools/LyTestTools/ly_test_tools/log/py_logging_util.py + +# Helper: variables we will use for parameter values in the test: +targetProjects = ["AutomatedTesting"] + +@pytest.fixture +def local_resources(request, workspace, ap_setup_fixture): + ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.mark.usefixtures("asset_processor") +@pytest.mark.usefixtures("ap_setup_fixture") +@pytest.mark.usefixtures("local_resources") +@pytest.mark.parametrize("project", targetProjects) +@pytest.mark.assetpipeline +@pytest.mark.SUITE_main +class TestsPythonAssetProcessing_APBatch(object): + + @pytest.mark.BAT + @pytest.mark.assetpipeline + def test_ProcessAssetWithoutScriptAfterAssetWithScript_ScriptOnlyRunsOnExpectedAsset(self, workspace, ap_setup_fixture, asset_processor): + # This is a regression test. The situation it's testing is, the Python script to run + # defined in scene manifest files was persisting in a single builder. So if + # that builder processed file a.fbx, then b.fbx, and a.fbx has a Python script to run, + # it was also running that Python script on b.fbx. + + asset_processor.prepare_test_environment(ap_setup_fixture["tests_dir"], "TwoSceneFiles_OneWithPythonOneWithout_PythonOnlyRunsOnFirstScene") + + asset_processor_extra_params = [ + # Disabling Atom assets disables most products, using the debugOutput flag ensures one product is output. + "--debugOutput", + # By default, if job priorities are equal, jobs run in an arbitrary order. This makes sure + # jobs are run by sorting on the database source name, so they run in the same order each time + # when this test is run. + "--sortJobsByDBSourceName", + # Disabling Atom products means this asset won't need a lot of source dependencies to be processed, + # keeping the scope of this test down. + "--regset=\"/O3DE/SceneAPI/AssetImporter/SkipAtomOutput=true\"", + # The bug this regression test happened when the same builder processed FBX files with and without Python. + # This flag ensures that only one builder is launched, so that situation can be replicated. + "--regset=\"/Amazon/AssetProcessor/Settings/Jobs/maxJobs=1\""] + + result, _ = asset_processor.batch_process(extra_params=asset_processor_extra_params) + assert result, "AP Batch failed" + + expected_product_list = [ + "a_simple_box_with_script.dbgsg", + "b_simple_box_no_script.dbgsg" + ] + + missing_assets, _ = utils.compare_assets_with_cache(expected_product_list, + asset_processor.project_test_cache_folder()) + assert not missing_assets, f'The following assets were expected to be in, but not found in cache: {str(missing_assets)}' + + # The Python script loaded in the scene manifest will write a log file with the source file's name + # to the temp folder. This is the easiest way to have the internal Python there communicate with this test. + expected_path = os.path.join(asset_processor.project_test_source_folder(), "a_simple_box_with_script_fbx.log") + unexpected_path = os.path.join(asset_processor.project_test_source_folder(), "b_simple_box_no_script_fbx.log") + + # Simple check to make sure the Python script in the scene manifest ran on the file it should have ran on. + assert os.path.exists(expected_path), f"Did not find expected output test asset {expected_path}" + # If this test fails here, it means the Python script from the first processed FBX file is being run + # on the second FBX file, when it should not be. + assert not os.path.exists(unexpected_path), f"Found unexpected output test asset {unexpected_path}" + diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp index 21089ef020..3a7bc6ef3e 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp @@ -3072,6 +3072,7 @@ namespace AssetProcessor QElapsedTimer elapsedTimer; elapsedTimer.start(); + for (auto jobIter = m_jobsToProcess.begin(); jobIter != m_jobsToProcess.end();) { JobDetails& job = *jobIter; @@ -3082,7 +3083,7 @@ namespace AssetProcessor jobIter = m_jobsToProcess.erase(jobIter); m_numOfJobsToAnalyze--; - // Update the remaining job status occasionally + // Update the remaining job status occasionally if (elapsedTimer.elapsed() >= MILLISECONDS_BETWEEN_PROCESS_JOBS_STATUS_UPDATE) { Q_EMIT NumRemainingJobsChanged(m_activeFiles.size() + m_filesToExamine.size() + m_numOfJobsToAnalyze); @@ -3102,7 +3103,8 @@ namespace AssetProcessor // Process the first job if no jobs were analyzed. auto jobIter = m_jobsToProcess.begin(); JobDetails& job = *jobIter; - AZ_Warning(AssetProcessor::DebugChannel, false, " Cyclic job dependency detected. Processing job (%s, %s, %s, %s) to unblock.", + AZ_Warning( + AssetProcessor::DebugChannel, false, " Cyclic job dependency detected. Processing job (%s, %s, %s, %s) to unblock.", job.m_jobEntry.m_databaseSourceName.toUtf8().data(), job.m_jobEntry.m_jobKey.toUtf8().data(), job.m_jobEntry.m_platformInfo.m_identifier.c_str(), job.m_jobEntry.m_builderGuid.ToString().c_str()); ProcessJob(job); diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h index 5fc7a73035..376af5d773 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h @@ -207,6 +207,11 @@ namespace AssetProcessor //! or a job dependency and we can only resolve these dependencies once all the create jobs are completed. struct JobToProcessEntry { + bool operator<(const JobToProcessEntry& other) + { + return m_sourceFileInfo.m_pathRelativeToScanFolder < other.m_sourceFileInfo.m_pathRelativeToScanFolder; + } + SourceFileInfo m_sourceFileInfo; AZStd::vector m_jobsToAnalyze; // a vector of pairs of diff --git a/Code/Tools/AssetProcessor/native/assetprocessor.h b/Code/Tools/AssetProcessor/native/assetprocessor.h index 2397f3b1ff..1c13eca200 100644 --- a/Code/Tools/AssetProcessor/native/assetprocessor.h +++ b/Code/Tools/AssetProcessor/native/assetprocessor.h @@ -244,6 +244,11 @@ namespace AssetProcessor m_jobEntry.m_builderGuid == rhs.m_jobEntry.m_builderGuid); } + static bool DatabaseSourceLexCompare(const JobDetails& left, const JobDetails& right) + { + return left.m_jobEntry.m_databaseSourceName <= right.m_jobEntry.m_databaseSourceName; + } + JobDetails() = default; }; diff --git a/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.cpp b/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.cpp index c39a0c66e9..774876234d 100644 --- a/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.cpp +++ b/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.cpp @@ -197,10 +197,20 @@ namespace AssetProcessor { return priorityLeft > priorityRight; } + + // Optionally stabilize queue order on the source name. + // This is used in automated tests, to allow tests to have a stable + // order that jobs with otherwise equal priority run, so tests process + // assets in the same order each time they are run. + if (m_sortQueueOnDBSourceName) + { + return leftJob->GetJobEntry().m_databaseSourceName < rightJob->GetJobEntry().m_databaseSourceName; + } // if we get all the way down here it means we're dealing with two assets which are not // in any compile groups, not a priority platform, not a priority type, priority platform, etc. // we can arrange these any way we want, but must pick at least a stable order. + return leftJob->GetJobEntry().m_jobRunKey < rightJob->GetJobEntry().m_jobRunKey; } diff --git a/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.h b/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.h index fbeacd8b8c..7fc60fdd60 100644 --- a/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.h +++ b/Code/Tools/AssetProcessor/native/resourcecompiler/RCQueueSortModel.h @@ -50,6 +50,10 @@ namespace AssetProcessor void AddJobIdEntry(AssetProcessor::RCJob* rcJob); void RemoveJobIdEntry(AssetProcessor::RCJob* rcJob); + void SetQueueSortOnDBSourceName() + { + m_sortQueueOnDBSourceName = true; + } // implement QSortFilteRProxyModel: bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; @@ -68,6 +72,11 @@ namespace AssetProcessor QSet m_currentlyConnectedPlatforms; bool m_dirtyNeedsResort = false; // instead of constantly resorting, we resort only when someone wants to pull an element from us + // By default, jobs with equal priority and escalation sort on the job run key. This flag changes + // jobs to sort on the database source name. This is used for testing, to guarantee jobs run in the same + // order for those tests each time they are run. + bool m_sortQueueOnDBSourceName = false; + // --------------------------------------------------------- // AssetProcessorPlatformBus::Handler void AssetProcessorPlatformConnected(const AZStd::string platform) override; diff --git a/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.cpp b/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.cpp index 11ef68de29..660144095b 100644 --- a/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.cpp +++ b/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.cpp @@ -163,6 +163,11 @@ namespace AssetProcessor return ((!m_RCQueueSortModel.GetNextPendingJob()) && (m_RCJobListModel.jobsInFlight() == 0)); } + void RCController::SetQueueSortOnDBSourceName() + { + m_RCQueueSortModel.SetQueueSortOnDBSourceName(); + } + void RCController::JobSubmitted(JobDetails details) { AssetProcessor::QueueElementID checkFile(details.m_jobEntry.m_databaseSourceName, details.m_jobEntry.m_platformInfo.m_identifier.c_str(), details.m_jobEntry.m_jobKey); diff --git a/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.h b/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.h index c555c7a585..51ae6b4a26 100644 --- a/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.h +++ b/Code/Tools/AssetProcessor/native/resourcecompiler/rccontroller.h @@ -54,10 +54,11 @@ namespace AssetProcessor void StartJob(AssetProcessor::RCJob* rcJob); int NumberOfPendingCriticalJobsPerPlatform(QString platform); - void SetSystemRoot(const QDir& systemRoot); int NumberOfPendingJobsPerPlatform(QString platform); bool IsIdle(); - bool IsPriorityCopyJob(AssetProcessor::RCJob* rcJob); + + void SetQueueSortOnDBSourceName(); + Q_SIGNALS: void FileCompiled(JobEntry entry, AssetBuilderSDK::ProcessJobResponse response); void FileFailed(JobEntry entry); diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp index 5e2de8e4cd..b90364e1c5 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp @@ -49,8 +49,6 @@ static const qint64 s_ReservedDiskSpaceInBytes = 256 * 1024; //! Maximum number of temp folders allowed static const int s_MaximumTempFolders = 10000; -const char AdditionalScanFolders[] = "additionalScanFolders"; - ApplicationManagerBase::ApplicationManagerBase(int* argc, char*** argv, QObject* parent) : ApplicationManager(argc, argv, parent) { @@ -155,55 +153,90 @@ void ApplicationManagerBase::InitAssetProcessorManager() const AzFramework::CommandLine* commandLine = nullptr; AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine); - if(commandLine->HasSwitch("zeroAnalysisMode")) + struct APCommandLineSwitch + { + APCommandLineSwitch(const char* switchTitle, const char* helpText) + : m_switch(switchTitle) + , m_helpText(helpText) + { + + } + const char* m_switch; + const char* m_helpText; + }; + + const APCommandLineSwitch Command_waitOnLaunch("waitOnLaunch", "Briefly pauses Asset Processor during initializiation. Useful if you want to attach a debugger."); + const APCommandLineSwitch Command_zeroAnalysisMode("zeroAnalysisMode", "Enables using file modification time when examining source assets for processing."); + const APCommandLineSwitch Command_enableQueryLogging("enableQueryLogging", "Enables logging database queries."); + const APCommandLineSwitch Command_dependencyScanPattern("dependencyScanPattern", "Scans assets that match the given pattern for missing product dependencies."); + const APCommandLineSwitch Command_dsp("dsp", Command_dependencyScanPattern.m_helpText); + const APCommandLineSwitch Command_fileDependencyScanPattern("fileDependencyScanPattern", "Used with dependencyScanPattern to farther filter the scan."); + const APCommandLineSwitch Command_fdsp("fdsp", Command_fileDependencyScanPattern.m_helpText); + const APCommandLineSwitch Command_additionalScanFolders("additionalScanFolders", "Used with dependencyScanPattern to farther filter the scan."); + const APCommandLineSwitch Command_dependencyScanMaxIteration("dependencyScanMaxIteration", "Used to limit the number of recursive searches per line when running dependencyScanPattern."); + const APCommandLineSwitch Command_warningLevel("warningLevel", "Configure the error and warning reporting level for AssetProcessor. Pass in 1 for fatal errors, 2 for fatal errors and warnings."); + const APCommandLineSwitch Command_acceptInput("acceptInput", "Enable external control messaging via the ControlRequestHandler, used with automated tests."); + const APCommandLineSwitch Command_debugOutput("debugOutput", "When enabled, builders that support it will output debug information as product assets. Used primarily with scene files."); + const APCommandLineSwitch Command_sortJobsByDBSourceName("sortJobsByDBSourceName", "When enabled, sorts pending jobs with equal priority and dependencies by database source name instead of job ID. Useful for automated tests to process assets in the same order each time."); + const APCommandLineSwitch Command_truncatefingerprint("truncatefingerprint", "Truncates the fingerprint used for processed assets. Useful if you plan to compress product assets to share on another machine because some compression formats like zip will truncate file mod timestamps."); + const APCommandLineSwitch Command_help("help", "Displays this message."); + const APCommandLineSwitch Command_h("h", Command_help.m_helpText); + + if (commandLine->HasSwitch(Command_waitOnLaunch.m_switch)) + { + // Useful for attaching the debugger, this forces a short pause. + AZStd::this_thread::sleep_for(AZStd::chrono::seconds(20)); + } + + if (commandLine->HasSwitch(Command_zeroAnalysisMode.m_switch)) { m_assetProcessorManager->SetEnableModtimeSkippingFeature(true); } - if(commandLine->HasSwitch("enableQueryLogging")) + if (commandLine->HasSwitch(Command_enableQueryLogging.m_switch)) { m_assetProcessorManager->SetQueryLogging(true); } - if (commandLine->HasSwitch("dependencyScanPattern")) + if (commandLine->HasSwitch(Command_dependencyScanPattern.m_switch)) { - m_dependencyScanPattern = commandLine->GetSwitchValue("dependencyScanPattern", 0).c_str(); + m_dependencyScanPattern = commandLine->GetSwitchValue(Command_dependencyScanPattern.m_switch, 0).c_str(); } - else if (commandLine->HasSwitch("dsp")) + else if (commandLine->HasSwitch(Command_dsp.m_switch)) { - m_dependencyScanPattern = commandLine->GetSwitchValue("dsp", 0).c_str(); + m_dependencyScanPattern = commandLine->GetSwitchValue(Command_dsp.m_switch, 0).c_str(); } m_fileDependencyScanPattern = "*"; - if (commandLine->HasSwitch("fileDependencyScanPattern")) + if (commandLine->HasSwitch(Command_fileDependencyScanPattern.m_switch)) { - m_fileDependencyScanPattern = commandLine->GetSwitchValue("fileDependencyScanPattern", 0).c_str(); + m_fileDependencyScanPattern = commandLine->GetSwitchValue(Command_fileDependencyScanPattern.m_switch, 0).c_str(); } - else if (commandLine->HasSwitch("fdsp")) + else if (commandLine->HasSwitch(Command_fdsp.m_switch)) { - m_fileDependencyScanPattern = commandLine->GetSwitchValue("fdsp", 0).c_str(); + m_fileDependencyScanPattern = commandLine->GetSwitchValue(Command_fdsp.m_switch, 0).c_str(); } - if (commandLine->HasSwitch(AdditionalScanFolders)) + if (commandLine->HasSwitch(Command_additionalScanFolders.m_switch)) { - for (size_t idx = 0; idx < commandLine->GetNumSwitchValues(AdditionalScanFolders); idx++) + for (size_t idx = 0; idx < commandLine->GetNumSwitchValues(Command_additionalScanFolders.m_switch); idx++) { - AZStd::string value = commandLine->GetSwitchValue(AdditionalScanFolders, idx); + AZStd::string value = commandLine->GetSwitchValue(Command_additionalScanFolders.m_switch, idx); m_dependencyAddtionalScanFolders.emplace_back(AZStd::move(value)); } } - if (commandLine->HasSwitch("dependencyScanMaxIteration")) + if (commandLine->HasSwitch(Command_dependencyScanMaxIteration.m_switch)) { - AZStd::string maxIterationAsString = commandLine->GetSwitchValue("dependencyScanMaxIteration", 0); + AZStd::string maxIterationAsString = commandLine->GetSwitchValue(Command_dependencyScanMaxIteration.m_switch, 0); m_dependencyScanMaxIteration = AZStd::stoi(maxIterationAsString); } - if (commandLine->HasSwitch("warningLevel")) + if (commandLine->HasSwitch(Command_warningLevel.m_switch)) { using namespace AssetProcessor; - const AZStd::string& levelString = commandLine->GetSwitchValue("warningLevel", 0); + const AZStd::string& levelString = commandLine->GetSwitchValue(Command_warningLevel.m_switch, 0); WarningLevel warningLevel = WarningLevel::Default; switch(AZStd::stoi(levelString)) @@ -217,26 +250,30 @@ void ApplicationManagerBase::InitAssetProcessorManager() } AssetProcessor::JobDiagnosticRequestBus::Broadcast(&AssetProcessor::JobDiagnosticRequestBus::Events::SetWarningLevel, warningLevel); } - if (commandLine->HasSwitch("acceptInput")) + if (commandLine->HasSwitch(Command_acceptInput.m_switch)) { InitControlRequestHandler(); } - if (commandLine->HasSwitch("debugOutput")) + if (commandLine->HasSwitch(Command_debugOutput.m_switch)) { m_assetProcessorManager->SetBuilderDebugFlag(true); } - constexpr char truncateFingerprintSwitch[] = "truncatefingerprint"; - if(commandLine->HasSwitch(truncateFingerprintSwitch)) + if (commandLine->HasSwitch(Command_sortJobsByDBSourceName.m_switch)) + { + m_sortJobsByDBSourceName = true; + } + + if (commandLine->HasSwitch(Command_truncatefingerprint.m_switch)) { // Zip archive format uses 2 second precision truncated const int ArchivePrecision = 2000; int precision = ArchivePrecision; - if(commandLine->GetNumSwitchValues(truncateFingerprintSwitch) > 0) + if (commandLine->GetNumSwitchValues(Command_truncatefingerprint.m_switch) > 0) { - precision = AZStd::stoi(commandLine->GetSwitchValue(truncateFingerprintSwitch, 0)); + precision = AZStd::stoi(commandLine->GetSwitchValue(Command_truncatefingerprint.m_switch, 0)); if(precision < 1) { @@ -246,6 +283,31 @@ void ApplicationManagerBase::InitAssetProcessorManager() AssetUtilities::SetTruncateFingerprintTimestamp(precision); } + + if (commandLine->HasSwitch(Command_help.m_switch) || commandLine->HasSwitch(Command_h.m_switch)) + { + // Other O3DE tools have a more full featured system for registering command flags + // that includes help output, but right now the AssetProcessor just checks strings + // via HasSwitch. This means this help output has to be updated manually. + AZ_TracePrintf("AssetProcessor", "Asset Processor Command Line Flags:\n"); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_waitOnLaunch.m_switch, Command_waitOnLaunch.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_zeroAnalysisMode.m_switch, Command_zeroAnalysisMode.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_enableQueryLogging.m_switch, Command_enableQueryLogging.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_dependencyScanPattern.m_switch, Command_dependencyScanPattern.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_dsp.m_switch, Command_dsp.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_fileDependencyScanPattern.m_switch, Command_fileDependencyScanPattern.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_fdsp.m_switch, Command_fdsp.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_additionalScanFolders.m_switch, Command_additionalScanFolders.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_dependencyScanMaxIteration.m_switch, Command_dependencyScanMaxIteration.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_warningLevel.m_switch, Command_warningLevel.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_acceptInput.m_switch, Command_acceptInput.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_debugOutput.m_switch, Command_debugOutput.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_sortJobsByDBSourceName.m_switch, Command_sortJobsByDBSourceName.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_truncatefingerprint.m_switch, Command_truncatefingerprint.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_help.m_switch, Command_help.m_helpText); + AZ_TracePrintf("AssetProcessor", "\t%s : %s\n", Command_h.m_switch, Command_h.m_helpText); + AZ_TracePrintf("AssetProcessor", "\tregset : set the given registry key to the given value.\n"); + } } void ApplicationManagerBase::Rescan() @@ -281,6 +343,11 @@ void ApplicationManagerBase::InitRCController() { m_rcController = new AssetProcessor::RCController(m_platformConfiguration->GetMinJobs(), m_platformConfiguration->GetMaxJobs()); + if (m_sortJobsByDBSourceName) + { + m_rcController->SetQueueSortOnDBSourceName(); + } + QObject::connect(m_assetProcessorManager, &AssetProcessor::AssetProcessorManager::AssetToProcess, m_rcController, &AssetProcessor::RCController::JobSubmitted); QObject::connect(m_rcController, &AssetProcessor::RCController::FileCompiled, m_assetProcessorManager, &AssetProcessor::AssetProcessorManager::AssetProcessed, Qt::UniqueConnection); QObject::connect(m_rcController, &AssetProcessor::RCController::FileFailed, m_assetProcessorManager, &AssetProcessor::AssetProcessorManager::AssetFailed); @@ -1807,4 +1874,3 @@ void ApplicationManagerBase::OnActiveJobsCountChanged(unsigned int count) AssetProcessor::AssetProcessorStatusEntry entry(AssetProcessor::AssetProcessorStatus::Processing_Jobs, count); Q_EMIT AssetProcessorStatusChanged(entry); } - diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h index 40106c69ec..7e6347b4d1 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.h @@ -236,6 +236,11 @@ protected: int m_remainingAPMJobs = 0; bool m_assetProcessorManagerIsReady = false; + // When job priority and escalation is equal, jobs sort in order by job key. + // This switches that behavior to instead sort by the DB source name, which + // allows automated tests to get deterministic behavior out of Asset Processor. + bool m_sortJobsByDBSourceName = false; + unsigned int m_highestConnId = 0; AzToolsFramework::Ticker* m_ticker = nullptr; // for ticking the tickbus. From afe5398f0ff6280f039a71e7f278e1c34a0d7644 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 2 Aug 2021 11:19:03 -0700 Subject: [PATCH 108/157] Fixed model unit tests --- Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp index 625240a01f..368fb2c3c6 100644 --- a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp @@ -107,6 +107,18 @@ namespace UnitTest AZStd::vector m_lods; }; + void SetUp() override + { + RPITestFixture::SetUp(); + + auto assetId = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0); + auto typeId = AZ::AzTypeInfo::Uuid(); + m_materialAsset = AZ::Data::Asset(assetId, typeId, ""); + + // Some tests attempt to serialize-in the model asset, which should not attempt to actually load this dummy asset reference. + m_materialAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehaviorNamespace::NoLoad); + } + AZ::RHI::ShaderSemantic GetPositionSemantic() const { return AZ::RHI::ShaderSemantic(AZ::Name("POSITION")); @@ -312,9 +324,7 @@ namespace UnitTest } const uint32_t m_manyMesh = 100; // Not too much to hold up the tests but enough to stress them - AZ::Data::Asset m_materialAsset = - AZ::Data::Asset(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0), - AZ::AzTypeInfo::Uuid(), ""); + AZ::Data::Asset m_materialAsset; }; From cc57ee7d20921b9592079fb8c8b63a26b071f748 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 2 Aug 2021 13:19:15 -0500 Subject: [PATCH 109/157] Fixed Vegetation Layer Spawner documentation link. Signed-off-by: Chris Galvan --- Gems/Vegetation/Code/Source/Editor/EditorSpawnerComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Vegetation/Code/Source/Editor/EditorSpawnerComponent.h b/Gems/Vegetation/Code/Source/Editor/EditorSpawnerComponent.h index 709b645ea2..6563a8f8b9 100644 --- a/Gems/Vegetation/Code/Source/Editor/EditorSpawnerComponent.h +++ b/Gems/Vegetation/Code/Source/Editor/EditorSpawnerComponent.h @@ -29,6 +29,6 @@ namespace Vegetation static constexpr const char* const s_componentDescription = "Creates dynamic vegetation in a specified area"; static constexpr const char* const s_icon = "Editor/Icons/Components/Vegetation.svg"; static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/Vegetation.svg"; - static constexpr const char* const s_helpUrl = "https://o3de.org/docs/user-guide/components/reference/vegetation-layer-spawner/"; + static constexpr const char* const s_helpUrl = "https://o3de.org/docs/user-guide/components/reference/vegetation/layer-spawner/"; }; } From 74498089c3fe08474c97f51b72565f836a6e14c7 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 2 Aug 2021 10:45:09 -0700 Subject: [PATCH 110/157] Ensure Editor FOV corrects on resize Signed-off-by: nvsickle --- Code/Editor/EditorViewportWidget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 357c27fd72..4ea36728ad 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -472,6 +472,12 @@ void EditorViewportWidget::Update() m_Camera.SetZRange(cameraState.m_nearClip, cameraState.m_farClip); } + // Ensure the FOV matches our internally stored setting if we're using the Editor camera + if (!m_viewEntityId.IsValid() && !GetIEditor()->IsInGameMode()) + { + SetFOV(GetFOV()); + } + // Reset the camera update flag now that we're finished updating our viewport context m_updateCameraPositionNextTick = false; @@ -2624,8 +2630,6 @@ void EditorViewportWidget::DestroyRenderContext() ////////////////////////////////////////////////////////////////////////// void EditorViewportWidget::SetDefaultCamera() { - // Ensure the FOV matches our internally stored setting - SetFOV(GetFOV()); if (IsDefaultCamera()) { return; From 8730d5657fa96328ba391b33eca7ae6db6d5539f Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Fri, 16 Jul 2021 08:52:55 -0700 Subject: [PATCH 111/157] Allow special characters in AnimGraph node group names Relying on the command system's string processing syntax prevents certain names from being used. This converts the AnimGraphAdjustNodeGroup command to be directly invokable, so that arguments can be passed directly, instead of going through the CommandLine string parsing. Signed-off-by: Chris Burel --- .../Source/AnimGraphNodeCommands.cpp | 28 +- .../Source/AnimGraphNodeGroupCommands.cpp | 251 +++++++++--------- .../Source/AnimGraphNodeGroupCommands.h | 71 ++++- .../CommandSystem/Source/ParameterMixins.h | 2 + .../Source/AnimGraph/BlendGraphWidget.cpp | 30 ++- .../Source/AnimGraph/NodeGroupWindow.cpp | 47 ++-- Gems/EMotionFX/Code/MCore/Source/Command.cpp | 6 +- Gems/EMotionFX/Code/MCore/Source/Command.h | 2 +- 8 files changed, 260 insertions(+), 177 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeCommands.cpp index f72833df56..fe41312701 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeCommands.cpp @@ -11,6 +11,7 @@ #include "CommandManager.h" #include +#include #include #include #include @@ -858,8 +859,16 @@ namespace CommandSystem // add it to the old node group if it was assigned to one before if (!mNodeGroupName.empty()) { - commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -nodeNames \"%s\" -nodeAction \"add\"", animGraph->GetID(), mNodeGroupName.c_str(), mName.c_str()); - if (GetCommandManager()->ExecuteCommandInsideCommand(commandString.c_str(), outResult) == false) + auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ animGraph->GetID(), + /*name = */ mNodeGroupName, + /*visible = */ AZStd::nullopt, + /*newName = */ AZStd::nullopt, + /*nodeNames = */ {{mName}}, + /*nodeAction = */ CommandSystem::CommandAnimGraphAdjustNodeGroup::NodeAction::Add + ); + if (GetCommandManager()->ExecuteCommandInsideCommand(command, outResult) == false) { if (outResult.size() > 0) { @@ -1363,11 +1372,16 @@ namespace CommandSystem EMotionFX::AnimGraphNodeGroup* nodeGroup = node->GetAnimGraph()->FindNodeGroupForNode(node); if (nodeGroup && !cutMode) { - commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %d -name \"%s\" -nodeNames \"%s\" -nodeAction \"add\"", - targetAnimGraph->GetID(), - nodeGroup->GetName(), - nodeName.c_str()); - commandGroup->AddCommandString(commandString); + auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ targetAnimGraph->GetID(), + /*name = */ nodeGroup->GetNameString(), + /*visible = */ AZStd::nullopt, + /*newName = */ AZStd::nullopt, + /*nodeNames = */ {{nodeName}}, + /*nodeAction = */ CommandSystem::CommandAnimGraphAdjustNodeGroup::NodeAction::Add + ); + commandGroup->AddCommand(command); } // Recurse through the child nodes. diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.cpp index 29ee45312b..f5f913f0ca 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include "AnimGraphNodeGroupCommands.h" #include "AnimGraphConnectionCommands.h" @@ -22,45 +23,46 @@ namespace CommandSystem { + AZ_CLASS_ALLOCATOR_IMPL(CommandAnimGraphAdjustNodeGroup, EMotionFX::CommandAllocator, 0) + //-------------------------------------------------------------------------------- // CommandAnimGraphAdjustNodeGroup //-------------------------------------------------------------------------------- - CommandAnimGraphAdjustNodeGroup::CommandAnimGraphAdjustNodeGroup(MCore::Command* orgCommand) - : MCore::Command("AnimGraphAdjustNodeGroup", orgCommand) + CommandAnimGraphAdjustNodeGroup::CommandAnimGraphAdjustNodeGroup( + MCore::Command* orgCommand, + AZ::u32 animGraphId, + AZStd::string name, + AZStd::optional visible, + AZStd::optional newName, + AZStd::optional> nodeNames, + AZStd::optional nodeAction, + AZStd::optional color, + AZStd::optional updateUI + ) + : MCore::Command(s_commandName, orgCommand) + , ParameterMixinAnimGraphId(animGraphId) + , m_name(AZStd::move(name)) + , m_isVisible(visible) + , m_newName(AZStd::move(newName)) + , m_nodeNames(AZStd::move(nodeNames)) + , m_nodeAction(nodeAction) + , m_color(color) + , m_updateUI(updateUI) { } - - CommandAnimGraphAdjustNodeGroup::~CommandAnimGraphAdjustNodeGroup() + AZStd::vector CommandAnimGraphAdjustNodeGroup::GenerateNodeNameVector(EMotionFX::AnimGraph* animGraph, const AZStd::vector& nodeIDs) { - } - - - AZStd::string CommandAnimGraphAdjustNodeGroup::GenerateNodeNameString(EMotionFX::AnimGraph* animGraph, const AZStd::vector& nodeIDs) - { - if (nodeIDs.empty()) + AZStd::vector result; + for (const auto& nodeID : nodeIDs) { - return ""; - } - - AZStd::string result; - - const size_t numNodes = nodeIDs.size(); - for (size_t i = 0; i < numNodes; ++i) - { - EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeById(nodeIDs[i]); + const EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeById(nodeID); if (!animGraphNode) { continue; } - - result += animGraphNode->GetName(); - if (i < numNodes - 1) - { - result += ';'; - } + result.emplace_back(animGraphNode->GetName()); } - return result; } @@ -80,78 +82,51 @@ namespace CommandSystem } - bool CommandAnimGraphAdjustNodeGroup::Execute(const MCore::CommandLine& parameters, AZStd::string& outResult) + bool CommandAnimGraphAdjustNodeGroup::Execute(const MCore::CommandLine&, AZStd::string& outResult) { - EMotionFX::AnimGraph* animGraph = CommandsGetAnimGraph(parameters, this, outResult); + EMotionFX::AnimGraph* animGraph = EMotionFX::GetAnimGraphManager().FindAnimGraphByID(m_animGraphId); if (!animGraph) { return false; } - // get the node group name - AZStd::string groupName; - parameters.GetValue("name", this, groupName); - // find the node group index - const uint32 groupIndex = animGraph->FindNodeGroupIndexByName(groupName.c_str()); + const uint32 groupIndex = animGraph->FindNodeGroupIndexByName(m_name.c_str()); if (groupIndex == MCORE_INVALIDINDEX32) { - outResult = AZStd::string::format("Node group \"%s\" can not be found.", groupName.c_str()); + outResult = AZStd::string::format("Node group \"%s\" can not be found.", m_name.c_str()); return false; } - // get a pointer to the node group and keep the old name EMotionFX::AnimGraphNodeGroup* nodeGroup = animGraph->GetNodeGroup(groupIndex); - mOldName = nodeGroup->GetName(); - // is visible? - if (parameters.CheckIfHasParameter("isVisible")) + if (m_isVisible.has_value()) { - const bool isVisible = parameters.GetValueAsBool("isVisible", this); - mOldIsVisible = nodeGroup->GetIsVisible(); - nodeGroup->SetIsVisible(isVisible); + m_oldIsVisible = nodeGroup->GetIsVisible(); + nodeGroup->SetIsVisible(*m_isVisible); } - // background color - if (parameters.CheckIfHasParameter("color")) + if (m_color.has_value()) { - const AZ::Vector4 colorVector4 = parameters.GetValueAsVector4("color", this); - const AZ::u32 color = AZ::Color(static_cast(colorVector4.GetX()), static_cast(colorVector4.GetY()), static_cast(colorVector4.GetZ()), static_cast(colorVector4.GetW())).ToU32(); - mOldColor = nodeGroup->GetColor(); - nodeGroup->SetColor(color); + m_oldColor = nodeGroup->GetColor(); + nodeGroup->SetColor(*m_color); } - // set the new name - // if the new name is empty, the name is not changed - AZStd::string newGroupName; - parameters.GetValue("newName", this, newGroupName); - if (!newGroupName.empty()) + if (m_newName.has_value()) { - nodeGroup->SetName(newGroupName.c_str()); + nodeGroup->SetName(m_newName->c_str()); } // check if parametes nodeNames is set - if (parameters.CheckIfHasParameter("nodeNames")) + if (m_nodeNames.has_value()) { // keep the old nodes IDs - mOldNodeIds = CollectNodeIdsFromGroup(nodeGroup); - - // get the node action - AZStd::string nodeAction; - parameters.GetValue("nodeAction", this, nodeAction); - - // get the node names and split the string - AZStd::string nodeNamesString; - parameters.GetValue("nodeNames", this, nodeNamesString); - - - AZStd::vector nodeNames; - AzFramework::StringFunc::Tokenize(nodeNamesString.c_str(), nodeNames, ";", false, true); + m_oldNodeIds = CollectNodeIdsFromGroup(nodeGroup); // remove the selected nodes from the given node group - if (AzFramework::StringFunc::Equal(nodeAction.c_str(), "remove")) + if (*m_nodeAction == NodeAction::Remove) { - for (const AZStd::string& nodeName : nodeNames) + for (const AZStd::string& nodeName : *m_nodeNames) { EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeByName(nodeName.c_str()); if (!animGraphNode) @@ -163,9 +138,9 @@ namespace CommandSystem nodeGroup->RemoveNodeById(animGraphNode->GetId()); } } - else if (AzFramework::StringFunc::Equal(nodeAction.c_str(), "add")) // add the selected nodes to the given node group + else if (*m_nodeAction == NodeAction::Add) { - for (const AZStd::string& nodeName : nodeNames) + for (const AZStd::string& nodeName : *m_nodeNames) { EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeByName(nodeName.c_str()); if (!animGraphNode) @@ -184,12 +159,12 @@ namespace CommandSystem nodeGroup->AddNode(animGraphNode->GetId()); } } - else if (AzFramework::StringFunc::Equal(nodeAction.c_str(), "replace")) // clear the node group and then add the selected nodes to the given node group + else if (*m_nodeAction == NodeAction::Replace) { // clear the node group upfront nodeGroup->RemoveAllNodes(); - for (const AZStd::string& nodeName : nodeNames) + for (const AZStd::string& nodeName : *m_nodeNames) { EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeByName(nodeName.c_str()); if (!animGraphNode) @@ -211,68 +186,40 @@ namespace CommandSystem } // save the current dirty flag and tell the anim graph that something got changed - mOldDirtyFlag = animGraph->GetDirtyFlag(); + m_oldDirtyFlag = animGraph->GetDirtyFlag(); animGraph->SetDirtyFlag(true); return true; } // undo the command - bool CommandAnimGraphAdjustNodeGroup::Undo(const MCore::CommandLine& parameters, AZStd::string& outResult) + bool CommandAnimGraphAdjustNodeGroup::Undo(const MCore::CommandLine&, AZStd::string& outResult) { - EMotionFX::AnimGraph* animGraph = CommandsGetAnimGraph(parameters, this, outResult); + EMotionFX::AnimGraph* animGraph = EMotionFX::GetAnimGraphManager().FindAnimGraphByID(m_animGraphId); if (!animGraph) { return false; } - AZStd::string commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i", animGraph->GetID()); - - // set the old name or simply set the name if the name is not changed - if (parameters.CheckIfHasParameter("newName")) - { - AZStd::string newName; - parameters.GetValue("newName", this, newName); - - commandString += AZStd::string::format(" -name \"%s\"", newName.c_str()); - commandString += AZStd::string::format(" -newName \"%s\"", mOldName.c_str()); - } - else - { - commandString += AZStd::string::format(" -name \"%s\"", mOldName.c_str()); - } - - // set the old visible flag - if (parameters.CheckIfHasParameter("isVisible")) - { - commandString += AZStd::string::format(" -isVisible %i", mOldIsVisible); - } - - // set the old color - if (parameters.CheckIfHasParameter("color")) - { - AZ::Color oldColor; - oldColor.FromU32(mOldColor); - const AZStd::string oldColorString = AZStd::string::format("%.8f,%.8f,%.8f,%.8f", static_cast(oldColor.GetR()), static_cast(oldColor.GetG()), static_cast(oldColor.GetB()), static_cast(oldColor.GetA())); - - commandString += AZStd::string::format(" -color \"%s\"", oldColorString.c_str()); - } - - // set the old nodes - if (parameters.CheckIfHasParameter("nodeNames")) - { - const AZStd::string nodeNamesString = CommandAnimGraphAdjustNodeGroup::GenerateNodeNameString(animGraph, mOldNodeIds); - commandString += AZStd::string::format(" -nodeNames \"%s\" -nodeAction \"replace\"", nodeNamesString.c_str()); - } + CommandAnimGraphAdjustNodeGroup* command = aznew CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ m_animGraphId, + /*name = */ m_newName.has_value() ? *m_newName : m_name, + /*visible = */ m_isVisible.has_value() ? AZStd::optional(m_oldIsVisible) : AZStd::nullopt, + /*newName = */ m_newName.has_value() ? AZStd::optional(m_name) : AZStd::nullopt, + /*nodeNames = */ m_nodeNames.has_value() ? AZStd::optional>(GenerateNodeNameVector(animGraph, m_oldNodeIds)) : AZStd::nullopt, + /*nodeAction = */ m_nodeNames.has_value() ? AZStd::optional(NodeAction::Replace) : AZStd::nullopt, + /*color = */ m_color.has_value() ? AZStd::optional(m_oldColor) : AZStd::nullopt + ); // execute the command - if (!GetCommandManager()->ExecuteCommandInsideCommand(commandString, outResult)) + if (!GetCommandManager()->ExecuteCommandInsideCommand(command, outResult)) { AZ_Error("EMotionFX", false, outResult.c_str()); } // set the dirty flag back to the old value - animGraph->SetDirtyFlag(mOldDirtyFlag); + animGraph->SetDirtyFlag(m_oldDirtyFlag); return true; } @@ -282,7 +229,7 @@ namespace CommandSystem { GetSyntax().ReserveParameters(8); GetSyntax().AddRequiredParameter("name", "The name of the node group to adjust.", MCore::CommandSyntax::PARAMTYPE_STRING); - GetSyntax().AddParameter("animGraphID", "The id of the blend set the node group belongs to.", MCore::CommandSyntax::PARAMTYPE_INT, "-1"); + EMotionFX::ParameterMixinAnimGraphId::InitSyntax(GetSyntax(), /*isParameterRequired=*/ false); GetSyntax().AddParameter("isVisible", "The visibility flag of the node group.", MCore::CommandSyntax::PARAMTYPE_BOOLEAN, "true"); GetSyntax().AddParameter("newName", "The new name of the node group.", MCore::CommandSyntax::PARAMTYPE_STRING, ""); GetSyntax().AddParameter("nodeNames", "A list of node names that should be added/removed to/from the node group.", MCore::CommandSyntax::PARAMTYPE_STRING, ""); @@ -291,6 +238,51 @@ namespace CommandSystem GetSyntax().AddParameter("updateUI", "Setting this to true will trigger a refresh of the node groups UI.", MCore::CommandSyntax::PARAMTYPE_BOOLEAN, "true"); } + bool CommandAnimGraphAdjustNodeGroup::SetCommandParameters(const MCore::CommandLine& parameters) + { + EMotionFX::ParameterMixinAnimGraphId::SetCommandParameters(parameters); + m_name = parameters.GetValue("name", this); + + if (parameters.CheckIfHasParameter("isVisible")) + { + m_isVisible = parameters.GetValueAsBool("isVisible", this); + } + if (parameters.CheckIfHasParameter("newName")) + { + m_newName = parameters.GetValue("newName", this); + } + if (parameters.CheckIfHasParameter("nodeNames")) + { + m_nodeNames.emplace(); + AzFramework::StringFunc::Tokenize(parameters.GetValue("nodeNames", this), m_nodeNames.value(), ";", false, true); + } + if (parameters.CheckIfHasValue("nodeAction")) + { + const AZStd::string& nodeActionStr = parameters.GetValue("nodeAction", this); + if (nodeActionStr == "add") + { + m_nodeAction = NodeAction::Add; + } + else if (nodeActionStr == "remove") + { + m_nodeAction = NodeAction::Remove; + } + else if (nodeActionStr == "replace") + { + m_nodeAction = NodeAction::Replace; + } + } + if (parameters.CheckIfHasParameter("color")) + { + m_color = AZ::Color(parameters.GetValueAsVector4("color", this)).ToU32(); + } + if (parameters.CheckIfHasParameter("updateUI")) + { + m_updateUI = parameters.GetValueAsBool("updateUI", this); + } + + return true; + } const char* CommandAnimGraphAdjustNodeGroup::GetDescription() const { @@ -447,21 +439,20 @@ namespace CommandSystem MCore::CommandGroup commandGroup; - AZStd::string commandString = AZStd::string::format("AnimGraphAddNodeGroup -animGraphID %i -name \"%s\" -updateUI %s",animGraph->GetID(), mOldName.c_str(), updateWindow.c_str()); - commandGroup.AddCommandString(commandString); + commandGroup.AddCommandString(AZStd::string::format("AnimGraphAddNodeGroup -animGraphID %i -name \"%s\" -updateUI %s",animGraph->GetID(), mOldName.c_str(), updateWindow.c_str())); - const AZStd::string nodeNamesString = CommandAnimGraphAdjustNodeGroup::GenerateNodeNameString(animGraph, mOldNodeIds); + auto* command = aznew CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ animGraph->GetID(), + /*name = */ mOldName, + /*visible = */ mOldIsVisible, + /*newName = */ AZStd::nullopt, + /*nodeNames = */ CommandAnimGraphAdjustNodeGroup::GenerateNodeNameVector(animGraph, mOldNodeIds), + /*nodeAction = */ CommandAnimGraphAdjustNodeGroup::NodeAction::Add, + /*color = */ mOldColor + ); - AZ::Color oldColor; - oldColor.FromU32(mOldColor); - const AZStd::string oldColorString = AZStd::string::format("%.8f,%.8f,%.8f,%.8f", - static_cast(oldColor.GetR()), static_cast(oldColor.GetG()), static_cast(oldColor.GetB()), static_cast(oldColor.GetA())); - - commandString = AZStd::string::format( - "AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -isVisible %s -color \"%s\" -nodeNames \"%s\" -nodeAction \"add\" -updateUI %s", - animGraph->GetID(), mOldName.c_str(), AZStd::to_string(mOldIsVisible).c_str(), oldColorString.c_str(), nodeNamesString.c_str(), updateWindow.c_str()); - - commandGroup.AddCommandString(commandString); + commandGroup.AddCommand(command); AZStd::string result; if (!GetCommandManager()->ExecuteCommandGroupInsideCommand(commandGroup, result)) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h index 85bd92f970..0fc497d2f1 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h @@ -13,22 +13,73 @@ #include #include #include +#include namespace CommandSystem { // adjust a node group - MCORE_DEFINECOMMAND_START(CommandAnimGraphAdjustNodeGroup, "Adjust anim graph node group", true) -public: - static AZStd::string GenerateNodeNameString(EMotionFX::AnimGraph* animGraph, const AZStd::vector& nodeIDs); - static AZStd::vector CollectNodeIdsFromGroup(EMotionFX::AnimGraphNodeGroup* nodeGroup); + class CommandAnimGraphAdjustNodeGroup + : public MCore::Command + , public EMotionFX::ParameterMixinAnimGraphId + { + public: + AZ_CLASS_ALLOCATOR_DECL - AZStd::string mOldName; - bool mOldIsVisible; - AZ::u32 mOldColor; - AZStd::vector mOldNodeIds; - bool mOldDirtyFlag; - MCORE_DEFINECOMMAND_END + static constexpr inline AZStd::string_view s_commandName = "AnimGraphAdjustNodeGroup"; + enum class NodeAction + { + Add, + Remove, + Replace + }; + + explicit CommandAnimGraphAdjustNodeGroup( + MCore::Command* orgCommand = nullptr, + AZ::u32 animGraphId = MCORE_INVALIDINDEX32, + AZStd::string name = AZStd::string{}, + AZStd::optional visible = AZStd::nullopt, + AZStd::optional newName = AZStd::nullopt, + AZStd::optional> nodeNames = AZStd::nullopt, + AZStd::optional nodeAction = AZStd::nullopt, + AZStd::optional color = AZStd::nullopt, + AZStd::optional updateUI = AZStd::nullopt + ); + bool Execute(const MCore::CommandLine& parameters, AZStd::string& outResult) override; + bool Undo(const MCore::CommandLine& parameters, AZStd::string& outResult) override; + void InitSyntax() override; + bool SetCommandParameters(const MCore::CommandLine& parameters) override; + bool GetIsUndoable() const override + { + return true; + } + const char* GetHistoryName() const override + { + return "Adjust anim graph node group"; + } + const char* GetDescription() const override; + MCore::Command* Create() override + { + return new CommandAnimGraphAdjustNodeGroup(this); + } + + static AZStd::vector GenerateNodeNameVector(EMotionFX::AnimGraph* animGraph, const AZStd::vector& nodeIDs); + static AZStd::vector CollectNodeIdsFromGroup(EMotionFX::AnimGraphNodeGroup* nodeGroup); + + private: + AZStd::string m_name; + AZStd::optional m_isVisible; + AZStd::optional m_newName; + AZStd::optional> m_nodeNames; + AZStd::optional m_nodeAction; + AZStd::optional m_color; + AZStd::optional m_updateUI; + + bool m_oldIsVisible; + AZ::u32 m_oldColor; + AZStd::vector m_oldNodeIds; + bool m_oldDirtyFlag; + }; // add node group MCORE_DEFINECOMMAND_START(CommandAnimGraphAddNodeGroup, "Add anim graph node group", true) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ParameterMixins.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ParameterMixins.h index eb5de65f13..6461921160 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ParameterMixins.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ParameterMixins.h @@ -80,6 +80,8 @@ namespace EMotionFX AZ_RTTI(ParameterMixinAnimGraphId, "{3F48199E-6566-471F-A7EA-ADF67CAC4DCD}") AZ_CLASS_ALLOCATOR_DECL + ParameterMixinAnimGraphId() = default; + ParameterMixinAnimGraphId(AZ::u32 id) : m_animGraphId(id) {} virtual ~ParameterMixinAnimGraphId() = default; static void Reflect(AZ::ReflectContext* context); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp index 9ec28d2e21..8a4a338b6e 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1208,7 +1209,7 @@ namespace EMStudio MCore::CommandGroup commandGroup("Adjust anim graph node group"); - AZStd::string nodeNames; + AZStd::vector nodeNames; for (const QModelIndex& selectedIndex : selectionList) { // Skip transitions and blend tree connections. @@ -1221,12 +1222,19 @@ namespace EMStudio EMotionFX::AnimGraphNodeGroup* nodeGroup = animGraph->FindNodeGroupForNode(selectedNode); if (nodeGroup) { - const AZStd::string command = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -nodeNames \"%s\" -nodeAction \"remove\"", animGraph->GetID(), nodeGroup->GetName(), selectedNode->GetName()); - commandGroup.AddCommandString(command); + auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ animGraph->GetID(), + /*name = */ nodeGroup->GetNameString(), + /*visible = */ AZStd::nullopt, + /*newName = */ AZStd::nullopt, + /*nodeNames = */ {{selectedNode->GetNameString()}}, + /*nodeAction = */ CommandSystem::CommandAnimGraphAdjustNodeGroup::NodeAction::Remove + ); + commandGroup.AddCommand(command); } - nodeNames += selectedNode->GetName(); - nodeNames += ";"; + nodeNames.emplace_back(selectedNode->GetName()); } if (!nodeNames.empty()) { @@ -1235,8 +1243,16 @@ namespace EMStudio if (newNodeGroup) { - const AZStd::string command = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -nodeNames \"%s\" -nodeAction \"add\"", animGraph->GetID(), newNodeGroup->GetName(), nodeNames.c_str()); - commandGroup.AddCommandString(command); + auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ animGraph->GetID(), + /*name = */ newNodeGroup->GetNameString(), + /*visible = */ AZStd::nullopt, + /*newName = */ AZStd::nullopt, + /*nodeNames = */ nodeNames, + /*nodeAction = */ CommandSystem::CommandAnimGraphAdjustNodeGroup::NodeAction::Add + ); + commandGroup.AddCommand(command); } AZStd::string outResult; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGroupWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGroupWindow.cpp index ecb9a227af..8ab7aa8d72 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGroupWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGroupWindow.cpp @@ -74,11 +74,6 @@ namespace EMStudio mLineEdit->setText(nodeGroup.c_str()); mLineEdit->selectAll(); - // create add the error message - /*mErrorMsg = new QLabel("Error: Duplicate name found"); - mErrorMsg->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); - mErrorMsg->setVisible(false);*/ - // create the button layout QHBoxLayout* buttonLayout = new QHBoxLayout(); mOKButton = new QPushButton("OK"); @@ -139,10 +134,16 @@ namespace EMStudio void NodeGroupRenameWindow::Accepted() { // Execute the command - AZStd::string commandString, outResult; + AZStd::string outResult; const AZStd::string convertedNewName = FromQtString(mLineEdit->text()); - commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -newName \"%s\"", mAnimGraph->GetID(), mNodeGroup.c_str(), convertedNewName.c_str()); - if (GetCommandManager()->ExecuteCommand(commandString.c_str(), outResult) == false) + auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName), + mAnimGraph->GetID(), + /*name = */ mNodeGroup, + /*visible = */ AZStd::nullopt, + /*newName = */ convertedNewName + ); + if (!GetCommandManager()->ExecuteCommand(command, outResult)) { MCore::LogError(outResult.c_str()); } @@ -167,7 +168,7 @@ namespace EMStudio mAdjustCallback = new CommandAnimGraphAdjustNodeGroupCallback(false); GetCommandManager()->RegisterCommandCallback("AnimGraphAddNodeGroup", mCreateCallback); GetCommandManager()->RegisterCommandCallback("AnimGraphRemoveNodeGroup", mRemoveCallback); - GetCommandManager()->RegisterCommandCallback("AnimGraphAdjustNodeGroup", mAdjustCallback); + GetCommandManager()->RegisterCommandCallback(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName.data(), mAdjustCallback); // add the add button mAddAction = new QAction(MysticQt::GetMysticQt()->FindIcon("Images/Icons/Plus.svg"), tr("Add new node group"), this); @@ -486,13 +487,16 @@ namespace EMStudio bool isVisible = state == Qt::Checked; - // construct the command - AZStd::string commandString; - commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -isVisible %s", animGraph->GetID(), nodeGroup->GetName(), AZStd::to_string(isVisible).c_str()); + auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ animGraph->GetID(), + /*name = */ nodeGroup->GetNameString(), + /*visible = */ isVisible + ); // execute the command AZStd::string resultString; - if (GetCommandManager()->ExecuteCommand(commandString.c_str(), resultString) == false) + if (GetCommandManager()->ExecuteCommand(command, resultString) == false) { if (resultString.size() > 0) { @@ -519,16 +523,21 @@ namespace EMStudio // get a pointer to the node group EMotionFX::AnimGraphNodeGroup* nodeGroup = animGraph->GetNodeGroup(groupIndex); - // get the color - AZ::Vector4 finalColor = color.GetAsVector4(); - // construct the command - AZStd::string commandString; - commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -color \"%s\"", animGraph->GetID(), nodeGroup->GetName(), AZStd::to_string(finalColor).c_str()); + auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName), + /*animGraphId = */ animGraph->GetID(), + /*name = */ nodeGroup->GetName(), + /*visible = */ AZStd::nullopt, + /*newName = */ AZStd::nullopt, + /*nodeNames = */ AZStd::nullopt, + /*nodeAction = */ AZStd::nullopt, + /*color = */ color.ToU32() + ); // execute the command AZStd::string resultString; - if (GetCommandManager()->ExecuteCommand(commandString.c_str(), resultString) == false) + if (GetCommandManager()->ExecuteCommand(command, resultString) == false) { if (resultString.size() > 0) { diff --git a/Gems/EMotionFX/Code/MCore/Source/Command.cpp b/Gems/EMotionFX/Code/MCore/Source/Command.cpp index b358a28546..39e9fde965 100644 --- a/Gems/EMotionFX/Code/MCore/Source/Command.cpp +++ b/Gems/EMotionFX/Code/MCore/Source/Command.cpp @@ -28,10 +28,10 @@ namespace MCore // constructor - Command::Command(const char* commandName, Command* originalCommand) + Command::Command(AZStd::string commandName, Command* originalCommand) + : mOrgCommand(originalCommand) + , mCommandName(AZStd::move(commandName)) { - mCommandName = commandName; - mOrgCommand = originalCommand; } diff --git a/Gems/EMotionFX/Code/MCore/Source/Command.h b/Gems/EMotionFX/Code/MCore/Source/Command.h index 6ad10ff559..7309c5dc91 100644 --- a/Gems/EMotionFX/Code/MCore/Source/Command.h +++ b/Gems/EMotionFX/Code/MCore/Source/Command.h @@ -185,7 +185,7 @@ namespace MCore * @param commandName The unique identifier for the command. * @param originalCommand The original command, or nullptr when this is the original command. */ - Command(const char* commandName, Command* originalCommand); + Command(AZStd::string commandName, Command* originalCommand); /** * Destructor. From 9e6832c6a982ca751db5cef2f33225b59e123a91 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 20 Jul 2021 13:03:56 -0700 Subject: [PATCH 112/157] Remove `BaseObject` as a base class from `NodeGroup` Nothing uses the use count that the `BaseObject` base class provides, so there's no reason to keep it. Signed-off-by: Chris Burel --- .../Source/NodeGroupCommands.cpp | 31 +++------- .../CommandSystem/Source/NodeGroupCommands.h | 2 +- .../EMotionFX/Code/EMotionFX/Source/Actor.cpp | 6 +- .../Source/Importer/ChunkProcessors.cpp | 2 +- .../Code/EMotionFX/Source/NodeGroup.cpp | 57 ++---------------- .../Code/EMotionFX/Source/NodeGroup.h | 58 ++----------------- 6 files changed, 21 insertions(+), 135 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp index fe4a3e1ca9..229ad34f19 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp @@ -24,7 +24,6 @@ namespace CommandSystem // constructor CommandAdjustNodeGroup::CommandAdjustNodeGroup(MCore::Command* orgCommand) : MCore::Command("AdjustNodeGroup", orgCommand) - , mOldNodeGroup(nullptr) { } @@ -32,10 +31,7 @@ namespace CommandSystem // destructor CommandAdjustNodeGroup::~CommandAdjustNodeGroup() { - if (mOldNodeGroup) - { - mOldNodeGroup->Destroy(); - } + delete mOldNodeGroup; } @@ -65,10 +61,7 @@ namespace CommandSystem } // copy the old node group for undo - if (mOldNodeGroup) - { - mOldNodeGroup->Destroy(); - } + delete mOldNodeGroup; mOldNodeGroup = aznew EMotionFX::NodeGroup(*nodeGroup); @@ -235,11 +228,8 @@ namespace CommandSystem } } - // delete the old node group - if (mOldNodeGroup) - { - mOldNodeGroup->Destroy(); - } + delete mOldNodeGroup; + mOldNodeGroup = nullptr; // set the dirty flag back to the old value @@ -304,7 +294,7 @@ namespace CommandSystem } // add new node group to the actor - EMotionFX::NodeGroup* nodeGroup = EMotionFX::NodeGroup::Create(name.c_str()); + EMotionFX::NodeGroup* nodeGroup = aznew EMotionFX::NodeGroup(name); actor->AddNodeGroup(nodeGroup); // save the current dirty flag and tell the actor that something got changed @@ -374,10 +364,7 @@ namespace CommandSystem // destructor CommandRemoveNodeGroup::~CommandRemoveNodeGroup() { - if (mOldNodeGroup) - { - mOldNodeGroup->Destroy(); - } + delete mOldNodeGroup; } @@ -407,11 +394,7 @@ namespace CommandSystem } // copy the old node group for undo - if (mOldNodeGroup) - { - mOldNodeGroup->Destroy(); - } - + delete mOldNodeGroup; mOldNodeGroup = aznew EMotionFX::NodeGroup(*nodeGroup); // remove the node group diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h index e87ce2d62d..1931b6842e 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h @@ -22,7 +22,7 @@ namespace CommandSystem // adjust a node group MCORE_DEFINECOMMAND_START(CommandAdjustNodeGroup, "Adjust node group", true) bool mOldDirtyFlag; - EMotionFX::NodeGroup* mOldNodeGroup; + EMotionFX::NodeGroup* mOldNodeGroup = nullptr; MCORE_DEFINECOMMAND_END diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 973d8eb460..c6b210da58 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -1015,7 +1015,7 @@ namespace EMotionFX const uint32 numGroups = mNodeGroups.GetLength(); for (uint32 i = 0; i < numGroups; ++i) { - mNodeGroups[i]->Destroy(); + delete mNodeGroups[i]; } mNodeGroups.Clear(); } @@ -2085,7 +2085,7 @@ namespace EMotionFX { if (delFromMem) { - mNodeGroups[index]->Destroy(); + delete mNodeGroups[index]; } mNodeGroups.Remove(index); @@ -2097,7 +2097,7 @@ namespace EMotionFX mNodeGroups.RemoveByValue(group); if (delFromMem) { - group->Destroy(); + delete group; } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp index 7e7a9ae1c2..3cec3b599c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp @@ -1469,7 +1469,7 @@ namespace EMotionFX } // create the new group inside the actor - NodeGroup* newGroup = NodeGroup::Create(groupName, fileGroup.mNumNodes, fileGroup.mDisabledOnDefault ? false : true); + NodeGroup* newGroup = aznew NodeGroup(groupName, fileGroup.mNumNodes, fileGroup.mDisabledOnDefault ? false : true); // read the node numbers uint16 nodeIndex; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp index d73926a166..e22ad5f064 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.cpp @@ -17,63 +17,16 @@ namespace EMotionFX AZ_CLASS_ALLOCATOR_IMPL(NodeGroup, NodeAllocator, 0) - // default constructor - NodeGroup::NodeGroup() - : BaseObject() + NodeGroup::NodeGroup(const AZStd::string& groupName, uint16 numNodes, bool enabledOnDefault) + : mName(groupName) + , mNodes(numNodes) + , mEnabledOnDefault(enabledOnDefault) { - SetIsEnabledOnDefault(true); - } - - - // extended constructor - NodeGroup::NodeGroup(const char* groupName, bool enabledOnDefault) - : BaseObject() - { - SetName(groupName); - SetIsEnabledOnDefault(enabledOnDefault); - } - - - // another extended constructor - NodeGroup::NodeGroup(const char* groupName, uint16 numNodes, bool enabledOnDefault) - : BaseObject() - { - SetName(groupName); - SetNumNodes(numNodes); - SetIsEnabledOnDefault(enabledOnDefault); - } - - - // destructor - NodeGroup::~NodeGroup() - { - mNodes.Clear(); - } - - - // create - NodeGroup* NodeGroup::Create() - { - return aznew NodeGroup(); - } - - - // create - NodeGroup* NodeGroup::Create(const char* groupName, bool enabledOnDefault) - { - return aznew NodeGroup(groupName, enabledOnDefault); - } - - - // create - NodeGroup* NodeGroup::Create(const char* groupName, uint16 numNodes, bool enabledOnDefault) - { - return aznew NodeGroup(groupName, numNodes, enabledOnDefault); } // set the name of the group - void NodeGroup::SetName(const char* groupName) + void NodeGroup::SetName(const AZStd::string& groupName) { mName = groupName; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.h b/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.h index c6dc86273b..dfe876c86a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/NodeGroup.h @@ -30,38 +30,19 @@ namespace EMotionFX * might contain incorrect or even uninitialized data. */ class EMFX_API NodeGroup - : public BaseObject { public: AZ_CLASS_ALLOCATOR_DECL - /** - * The default creation method. - * This does not assign a name and there will be nodes inside this group on default. - * Also the default enabled state is set to true. - */ - static NodeGroup* Create(); - /** - * Extended creation. - * @param groupName The name of the group. Please keep in mind that it is not allowed to have two groups with the same name inside an Actor. - * @param enabledOnDefault Set to true (default) when the nodes inside this group should be enabled on default. - */ - static NodeGroup* Create(const char* groupName, bool enabledOnDefault = true); - - /** - * Another extended constructor. - * @param groupName The name of the group. Please keep in mind that it is not allowed to have two groups with the same name inside an Actor. - * @param numNodes The number of nodes to create inside the group. This will have all uninitialized values for the node indices in the group, so be sure that you - * set them all to some valid node index using the NodeGroup::SetNode(...) method. This method automatically calls the SetNumNodes(...) method. - * @param enabledOnDefault Set to true (default) when the nodes inside this group should be enabled on default. - */ - static NodeGroup* Create(const char* groupName, uint16 numNodes, bool enabledOnDefault = true); + NodeGroup(const AZStd::string& groupName = {}, uint16 numNodes = 0, bool enabledOnDefault = true); + NodeGroup(const NodeGroup& aOther); + NodeGroup& operator=(const NodeGroup& aOther); /** * Set the name of the group. Please keep in mind that group names must be unique inside the Actor objects. So you should not have two or more groups with the same name. * @param groupName The name of the group. */ - void SetName(const char* groupName); + void SetName(const AZStd::string& groupName); /** * Get the name of the group as null terminated character buffer. @@ -172,37 +153,6 @@ namespace EMotionFX */ void SetIsEnabledOnDefault(bool enabledOnDefault); - /** - * The default constructor. - * This does not assign a name and there will be nodes inside this group on default. - * Also the default enabled state is set to true. - */ - NodeGroup(); - - /** - * Extended constructor. - * @param groupName The name of the group. Please keep in mind that it is not allowed to have two groups with the same name inside an Actor. - * @param enabledOnDefault Set to true (default) when the nodes inside this group should be enabled on default. - */ - NodeGroup(const char* groupName, bool enabledOnDefault = true); - - /** - * Another extended constructor. - * @param groupName The name of the group. Please keep in mind that it is not allowed to have two groups with the same name inside an Actor. - * @param numNodes The number of nodes to create inside the group. This will have all uninitialized values for the node indices in the group, so be sure that you - * set them all to some valid node index using the NodeGroup::SetNode(...) method. This method automatically calls the SetNumNodes(...) method. - * @param enabledOnDefault Set to true (default) when the nodes inside this group should be enabled on default. - */ - NodeGroup(const char* groupName, uint16 numNodes, bool enabledOnDefault = true); - - /** - * The destructor. - */ - ~NodeGroup(); - - NodeGroup(const NodeGroup& aOther); - NodeGroup& operator=(const NodeGroup& aOther); - private: AZStd::string mName; /**< The name of the group. */ MCore::SmallArray mNodes; /**< The node index numbers that are inside this group. */ From 02c16a318e1bbfeb0b4afbf6dca52abaf16aae3c Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 20 Jul 2021 13:28:32 -0700 Subject: [PATCH 113/157] Prefer `unique_ptr` to a raw pointer for `CommandAdjustNodeGroup`'s members Signed-off-by: Chris Burel --- .../Source/NodeGroupCommands.cpp | 16 ++------- .../CommandSystem/Source/NodeGroupCommands.h | 36 +++++++++++++++---- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp index 229ad34f19..acb1388e38 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp @@ -9,7 +9,7 @@ // include the required headers #include "NodeGroupCommands.h" #include "CommandManager.h" -#include +#include #include #include #include @@ -28,13 +28,6 @@ namespace CommandSystem } - // destructor - CommandAdjustNodeGroup::~CommandAdjustNodeGroup() - { - delete mOldNodeGroup; - } - - // execute bool CommandAdjustNodeGroup::Execute(const MCore::CommandLine& parameters, AZStd::string& outResult) { @@ -60,10 +53,7 @@ namespace CommandSystem return false; } - // copy the old node group for undo - delete mOldNodeGroup; - - mOldNodeGroup = aznew EMotionFX::NodeGroup(*nodeGroup); + mOldNodeGroup = AZStd::make_unique(*nodeGroup); // check if newName is set and apply new name if (parameters.CheckIfHasParameter("newName")) @@ -228,8 +218,6 @@ namespace CommandSystem } } - delete mOldNodeGroup; - mOldNodeGroup = nullptr; // set the dirty flag back to the old value diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h index 1931b6842e..d691df7c82 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h @@ -9,10 +9,13 @@ #pragma once // include the required headers +#include #include "CommandSystemConfig.h" #include #include #include +#include +#include EMFX_FORWARD_DECLARE(Actor); EMFX_FORWARD_DECLARE(NodeGroup); @@ -20,20 +23,41 @@ EMFX_FORWARD_DECLARE(NodeGroup); namespace CommandSystem { // adjust a node group - MCORE_DEFINECOMMAND_START(CommandAdjustNodeGroup, "Adjust node group", true) - bool mOldDirtyFlag; - EMotionFX::NodeGroup* mOldNodeGroup = nullptr; - MCORE_DEFINECOMMAND_END + class CommandAdjustNodeGroup + : public MCore::Command + { + public: + CommandAdjustNodeGroup(MCore::Command* orgCommand = nullptr); + bool Execute(const MCore::CommandLine& parameters, AZStd::string& outResult) override; + bool Undo(const MCore::CommandLine& parameters, AZStd::string& outResult) override; + void InitSyntax() override; + bool GetIsUndoable() const override + { + return true; + } + const char* GetHistoryName() const override + { + return "Adjust node group"; + } + const char* GetDescription() const override; + MCore::Command* Create() override + { + return new CommandAdjustNodeGroup(this); + } + protected: + bool mOldDirtyFlag = false; + AZStd::unique_ptr mOldNodeGroup = nullptr; + }; // add node group - MCORE_DEFINECOMMAND_START(CommandAddNodeGroup, "Add node group", true) + MCORE_DEFINECOMMAND_START(CommandAddNodeGroup, "Add node group", true) bool mOldDirtyFlag; MCORE_DEFINECOMMAND_END // remove a node group - MCORE_DEFINECOMMAND_START(CommandRemoveNodeGroup, "Remove node group", true) + MCORE_DEFINECOMMAND_START(CommandRemoveNodeGroup, "Remove node group", true) EMotionFX::NodeGroup * mOldNodeGroup; bool mOldDirtyFlag; MCORE_DEFINECOMMAND_END From 3a95243df513c35ddb8814c10aff1cffe62dff5b Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 20 Jul 2021 13:37:58 -0700 Subject: [PATCH 114/157] Allow special characters in Actor node group names Relying on the command system's string processing syntax prevents certain names from being used. This converts the AdjustNodeGroup command to be directly invokable, so that arguments can be passed directly, instead of going through the CommandLine string parsing. Signed-off-by: Chris Burel --- .../Source/NodeGroupCommands.cpp | 222 ++++++++---------- .../CommandSystem/Source/NodeGroupCommands.h | 35 ++- .../NodeGroups/NodeGroupManagementWidget.cpp | 115 ++------- .../Source/NodeGroups/NodeGroupWidget.cpp | 76 +++--- .../Source/NodeGroups/NodeGroupWidget.h | 3 +- .../Source/NodeGroups/NodeGroupsPlugin.cpp | 3 +- 6 files changed, 186 insertions(+), 268 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp index acb1388e38..ea83d90d4b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.cpp @@ -20,208 +20,147 @@ namespace CommandSystem //-------------------------------------------------------------------------------- // CommandAdjustNodeGroup //-------------------------------------------------------------------------------- + AZ_CLASS_ALLOCATOR_IMPL(CommandAdjustNodeGroup, EMotionFX::CommandAllocator, 0) - // constructor - CommandAdjustNodeGroup::CommandAdjustNodeGroup(MCore::Command* orgCommand) - : MCore::Command("AdjustNodeGroup", orgCommand) + CommandAdjustNodeGroup::CommandAdjustNodeGroup( + MCore::Command* orgCommand, + uint32 actorId, + const AZStd::string& name, + AZStd::optional newName, + AZStd::optional enabledOnDefault, + AZStd::optional> nodeNames, + AZStd::optional nodeAction + ) + : MCore::Command(s_commandName.data(), orgCommand) + , EMotionFX::ParameterMixinActorId(actorId) + , m_name(name) + , m_newName(AZStd::move(newName)) + , m_enabledOnDefault(enabledOnDefault) + , m_nodeNames(AZStd::move(nodeNames)) + , m_nodeAction(nodeAction) { } // execute - bool CommandAdjustNodeGroup::Execute(const MCore::CommandLine& parameters, AZStd::string& outResult) + bool CommandAdjustNodeGroup::Execute(const MCore::CommandLine&, AZStd::string& outResult) { - AZStd::string valueString; - - // get the motion id and the corresponding motion pointer - const int32 actorID = parameters.GetValueAsInt("actorID", this); - parameters.GetValue("name", this, &valueString); - // get the actor - EMotionFX::Actor* actor = EMotionFX::GetActorManager().FindActorByID(actorID); + EMotionFX::Actor* actor = EMotionFX::GetActorManager().FindActorByID(m_actorId); if (actor == nullptr) { - outResult = AZStd::string::format("Cannot adjust node group. Actor with id='%i' does not exist.", actorID); + outResult = AZStd::string::format("Cannot adjust node group. Actor with id='%i' does not exist.", m_actorId); return false; } // get the node group - EMotionFX::NodeGroup* nodeGroup = actor->FindNodeGroupByNameNoCase(valueString.c_str()); + EMotionFX::NodeGroup* nodeGroup = actor->FindNodeGroupByNameNoCase(m_name.c_str()); if (nodeGroup == nullptr) { - outResult = AZStd::string::format("Cannot adjust node group. Node group with name='%s' does not exist.", valueString.c_str()); + outResult = AZStd::string::format("Cannot adjust node group. Node group with name='%s' does not exist.", m_name.c_str()); return false; } - mOldNodeGroup = AZStd::make_unique(*nodeGroup); + m_oldNodeGroup = AZStd::make_unique(*nodeGroup); // check if newName is set and apply new name - if (parameters.CheckIfHasParameter("newName")) + if (m_newName.has_value()) { - parameters.GetValue("newName", this, &valueString); - nodeGroup->SetName(valueString.c_str()); + nodeGroup->SetName(*m_newName); } // check if parameter disabledOnDefault is set and adjust it - if (parameters.CheckIfHasParameter("enabledOnDefault")) + if (m_enabledOnDefault.has_value()) { - const bool enabledOnDefault = parameters.GetValueAsBool("enabledOnDefault", this); - nodeGroup->SetIsEnabledOnDefault(enabledOnDefault); + nodeGroup->SetIsEnabledOnDefault(*m_enabledOnDefault); } // check if parametes nodeNames is set - if (parameters.CheckIfHasParameter("nodeNames")) + if (m_nodeNames.has_value()) { - // get the node action - AZStd::string nodeAction; - parameters.GetValue("nodeAction", this, &valueString); - - // get the node names and split the string - AZStd::string nodeNameString; - parameters.GetValue("nodeNames", this, &nodeNameString); - - // get the individual node names - AZStd::vector nodeNames; - AzFramework::StringFunc::Tokenize(nodeNameString.c_str(), nodeNames, MCore::CharacterConstants::semiColon, true /* keep empty strings */, true /* keep space strings */); - - // get the number of nodes - const size_t numNodes = nodeNames.size(); - - // remove the selected nodes from the node group - if (AzFramework::StringFunc::Equal(valueString.c_str(), "remove", false /* no case */)) + if (*m_nodeAction == NodeAction::Replace) { - for (size_t i = 0; i < numNodes; ++i) - { - // get the node - EMotionFX::Node* node = actor->GetSkeleton()->FindNodeByName(nodeNames[i].c_str()); - if (node == nullptr) - { - continue; - } - - // remove the node - nodeGroup->RemoveNodeByNodeIndex((uint16)node->GetNodeIndex()); - } - } - else if (AzFramework::StringFunc::Equal(valueString.c_str(), "add", false /* no case */)) // add the selected nodes to the node group - { - for (size_t i = 0; i < numNodes; ++i) - { - // get the node - EMotionFX::Node* node = actor->GetSkeleton()->FindNodeByName(nodeNames[i].c_str()); - if (node == nullptr) - { - continue; - } - - // add the node - uint16 nodeIndex = (uint16)node->GetNodeIndex(); - nodeGroup->RemoveNodeByNodeIndex(nodeIndex); - nodeGroup->AddNode(nodeIndex); - } - } - else // selected nodes form the new node group - { - // clear previous nodes nodeGroup->GetNodeArray().Clear(); - - // add all nodes to the group - for (size_t i = 0; i < numNodes; ++i) + } + for (const AZStd::string& nodeName : *m_nodeNames) + { + EMotionFX::Node* node = actor->GetSkeleton()->FindNodeByName(nodeName); + if (!node) { - // get the node - EMotionFX::Node* node = actor->GetSkeleton()->FindNodeByName(nodeNames[i].c_str()); + continue; + } - // check if node exists - if (node == nullptr) - { - continue; - } - - // add the node - nodeGroup->AddNode((uint16)node->GetNodeIndex()); + uint16 nodeIndex = (uint16)node->GetNodeIndex(); + nodeGroup->RemoveNodeByNodeIndex(nodeIndex); + if (*m_nodeAction == NodeAction::Add || *m_nodeAction == NodeAction::Replace) + { + nodeGroup->AddNode(nodeIndex); } } } // save the current dirty flag and tell the actor that something got changed - mOldDirtyFlag = actor->GetDirtyFlag(); + m_oldDirtyFlag = actor->GetDirtyFlag(); actor->SetDirtyFlag(true); return true; } // undo the command - bool CommandAdjustNodeGroup::Undo(const MCore::CommandLine& parameters, AZStd::string& outResult) + bool CommandAdjustNodeGroup::Undo(const MCore::CommandLine&, AZStd::string& outResult) { // return if no information about the previous node group was stored - if (!mOldNodeGroup) + if (!m_oldNodeGroup) { return false; } - // get the motion id and the corresponding motion pointer - int32 actorID = parameters.GetValueAsInt("actorID", this); - - // get the name - AZStd::string name; - if (parameters.CheckIfHasParameter("newName")) - { - parameters.GetValue("newName", this, &name); - } - else - { - parameters.GetValue("name", this, &name); - } - - // get the actor - EMotionFX::Actor* actor = EMotionFX::GetActorManager().FindActorByID(actorID); + EMotionFX::Actor* actor = EMotionFX::GetActorManager().FindActorByID(m_actorId); // return error if actor was not found if (actor == nullptr) { - outResult = AZStd::string::format("Cannot adjust node group. Actor with id='%i' does not exist.", actorID); + outResult = AZStd::string::format("Cannot adjust node group. Actor with id='%i' does not exist.", m_actorId); return false; } - // get the node group - EMotionFX::NodeGroup* nodeGroup = actor->FindNodeGroupByNameNoCase(name.c_str()); + EMotionFX::NodeGroup* nodeGroup = actor->FindNodeGroupByNameNoCase(m_newName.has_value() ? m_newName->c_str() : m_name.c_str()); - // return error if node group name is not set - if (nodeGroup == nullptr) + if (!nodeGroup) { - outResult = AZStd::string::format("Cannot adjust node group. Node group with name='%s' does not exist.", name.c_str()); + outResult = AZStd::string::format("Cannot adjust node group. Node group with name='%s' does not exist.", m_newName.has_value() ? m_newName->c_str() : m_name.c_str()); return false; } // reset the old values - if (parameters.CheckIfHasParameter("enabledOnDefault")) + if (m_enabledOnDefault.has_value()) { - nodeGroup->SetIsEnabledOnDefault(mOldNodeGroup->GetIsEnabledOnDefault()); + nodeGroup->SetIsEnabledOnDefault(m_oldNodeGroup->GetIsEnabledOnDefault()); } - if (parameters.CheckIfHasParameter("newName")) + if (m_newName.has_value()) { - nodeGroup->SetName(mOldNodeGroup->GetName()); + nodeGroup->SetName(m_oldNodeGroup->GetName()); } - if (parameters.CheckIfHasParameter("nodeNames")) + if (m_nodeNames.has_value()) { // clear previous nodes nodeGroup->GetNodeArray().Clear(); - const uint32 numNodes = mOldNodeGroup->GetNumNodes(); - nodeGroup->SetNumNodes(static_cast(numNodes)); + const uint16 numNodes = m_oldNodeGroup->GetNumNodes(); + nodeGroup->SetNumNodes(numNodes); // add all nodes to the group - for (uint32 i = 0; i < numNodes; ++i) + for (uint16 i = 0; i < numNodes; ++i) { - nodeGroup->SetNode(static_cast(i), mOldNodeGroup->GetNode(static_cast(i))); + nodeGroup->SetNode(i, m_oldNodeGroup->GetNode(i)); } } - mOldNodeGroup = nullptr; + m_oldNodeGroup = nullptr; // set the dirty flag back to the old value - actor->SetDirtyFlag(mOldDirtyFlag); + actor->SetDirtyFlag(m_oldDirtyFlag); return true; } @@ -230,7 +169,7 @@ namespace CommandSystem void CommandAdjustNodeGroup::InitSyntax() { GetSyntax().ReserveParameters(6); - GetSyntax().AddRequiredParameter("actorID", "The id of the actor the node group belongs to.", MCore::CommandSyntax::PARAMTYPE_INT); + EMotionFX::ParameterMixinActorId::InitSyntax(GetSyntax(), /*isParameterRequired=*/ true); GetSyntax().AddRequiredParameter("name", "The name of the node group to adjust.", MCore::CommandSyntax::PARAMTYPE_STRING); GetSyntax().AddParameter("newName", "The new name of the node group.", MCore::CommandSyntax::PARAMTYPE_STRING, ""); GetSyntax().AddParameter("enabledOnDefault", "The enabled on default flag.", MCore::CommandSyntax::PARAMTYPE_BOOLEAN, "false"); @@ -239,6 +178,45 @@ namespace CommandSystem } + bool CommandAdjustNodeGroup::SetCommandParameters(const MCore::CommandLine& parameters) + { + EMotionFX::ParameterMixinActorId::SetCommandParameters(parameters); + + m_name = parameters.GetValue("name", this); + if (parameters.CheckIfHasParameter("newName")) + { + m_newName = parameters.GetValue("newName", this); + } + if (parameters.CheckIfHasParameter("enabledOnDefault")) + { + m_enabledOnDefault = parameters.GetValueAsBool("enabledOnDefault", this); + } + if (parameters.CheckIfHasParameter("nodeNames")) + { + m_nodeNames.emplace(); + AzFramework::StringFunc::Tokenize(parameters.GetValue("nodeNames", this), m_nodeNames.value(), ";", false, true); + } + if (parameters.CheckIfHasParameter("nodeAction")) + { + const AZStd::string& nodeActionStr = parameters.GetValue("nodeAction", this); + if (nodeActionStr == "add") + { + m_nodeAction = NodeAction::Add; + } + else if (nodeActionStr == "remove") + { + m_nodeAction = NodeAction::Remove; + } + else if (nodeActionStr == "replace") + { + m_nodeAction = NodeAction::Replace; + } + } + + return true; + } + + // get the description const char* CommandAdjustNodeGroup::GetDescription() const { diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h index d691df7c82..d29918822d 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h @@ -25,12 +25,33 @@ namespace CommandSystem // adjust a node group class CommandAdjustNodeGroup : public MCore::Command + , public EMotionFX::ParameterMixinActorId { public: - CommandAdjustNodeGroup(MCore::Command* orgCommand = nullptr); + AZ_CLASS_ALLOCATOR_DECL + + enum class NodeAction + { + Add, + Remove, + Replace + }; + + static constexpr inline AZStd::string_view s_commandName = "AdjustNodeGroup"; + + CommandAdjustNodeGroup( + MCore::Command* orgCommand = nullptr, + uint32 actorId = MCORE_INVALIDINDEX32, + const AZStd::string& name = {}, + AZStd::optional newName = AZStd::nullopt, + AZStd::optional enabledOnDefault = AZStd::nullopt, + AZStd::optional> nodeNames = AZStd::nullopt, + AZStd::optional nodeAction = AZStd::nullopt + ); bool Execute(const MCore::CommandLine& parameters, AZStd::string& outResult) override; bool Undo(const MCore::CommandLine& parameters, AZStd::string& outResult) override; void InitSyntax() override; + bool SetCommandParameters(const MCore::CommandLine& parameters) override; bool GetIsUndoable() const override { return true; @@ -45,9 +66,15 @@ namespace CommandSystem return new CommandAdjustNodeGroup(this); } - protected: - bool mOldDirtyFlag = false; - AZStd::unique_ptr mOldNodeGroup = nullptr; + private: + AZStd::string m_name; + AZStd::optional m_newName; + AZStd::optional m_enabledOnDefault; + AZStd::optional> m_nodeNames; + AZStd::optional m_nodeAction; + + bool m_oldDirtyFlag = false; + AZStd::unique_ptr m_oldNodeGroup = nullptr; }; // add node group diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupManagementWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupManagementWidget.cpp index 1624b9d9ea..84c281a18f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupManagementWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupManagementWidget.cpp @@ -112,8 +112,13 @@ namespace EMStudio // execute the command AZStd::string outResult; - AZStd::string command = AZStd::string::format("AdjustNodeGroup -actorID %i -name \"%s\" -newName \"%s\"", mActor->GetID(), mNodeGroupName.c_str(), convertedNewName.c_str()); - if (GetCommandManager()->ExecuteCommand(command.c_str(), outResult) == false) + auto* command = aznew CommandSystem::CommandAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAdjustNodeGroup::s_commandName), + /*actorId=*/ mActor->GetID(), + /*name=*/ mNodeGroupName, + /*newName=*/ convertedNewName + ); + if (GetCommandManager()->ExecuteCommand(command, outResult) == false) { AZ_Error("EMotionFX", false, outResult.c_str()); } @@ -362,98 +367,6 @@ namespace EMStudio mSelectedRow = MCORE_INVALIDINDEX32; } } - /*void NodeGroupManagementWidget::UpdateNodeGroupWidget(QTableWidgetItem* current, QTableWidgetItem* previous) - { - MCORE_UNUSED(previous); - - // return if no node group widget is set - if (mNodeGroupWidget == nullptr) - return; - - // set the node group widget to the actual selection - mNodeGroupWidget->SetActor( mActor ); - - if (current) - { - // set the current row - mSelectedRow = current->row(); - - // set the node group - NodeGroup* nodeGroup = mActor->FindNodeGroupByName( FromQtString(mNodeGroupsTable->item(current->row(), 1)->text()).c_str() ); - mNodeGroupWidget->SetNodeGroup( nodeGroup ); - } - else - { - mNodeGroupWidget->SetNodeGroup( nullptr ); - mSelectedRow = MCORE_INVALIDINDEX32; - } - }*/ - - - // called whenever a cell is changed - /*void NodeGroupManagementWidget::NodeGroupNamesChanged(const QString& text) - { - // get the sender widget - QWidget* senderWidget = (QWidget*)sender(); - - // check for duplicates - const int duplicateFound = SearchTableForString( mNodeGroupsTable, text ); - - // mark edit field in red, if entry already exists - if (duplicateFound >= 0) - GetManager()->SetWidgetAsInvalidInput( senderWidget ); - else - senderWidget->setStyleSheet(""); - }*/ - - - // starts editing - /*void NodeGroupManagementWidget::NodeGroupeNameDoubleClicked(QTableWidgetItem* item) - { - // add new line edit for the selected widget - QLineEdit* lineEdit = new QLineEdit( mNodeGroupsTable->item(item->row(), 0)->text() ); - mNodeGroupsTable->setCellWidget( item->row(), 0, lineEdit ); - - // jump into the edit field - lineEdit->selectAll(); - lineEdit->setFocus(); - mNodeGroupsTable->setCurrentCell( item->row(), 0 ); - - // connect slots for edit finishing and text change - connect( lineEdit, SIGNAL(editingFinished()), this, SLOT(NodeGroupNameEditingFinished()) ); - connect( lineEdit, SIGNAL(textChanged(QString)), this, SLOT(NodeGroupNamesChanged(QString)) ); - }*/ - - - // called when editing is finished - /*void NodeGroupManagementWidget::NodeGroupNameEditingFinished() - { - // get the current item - QTableWidgetItem* item = mNodeGroupsTable->currentItem(); - - // get the sender widget - QLineEdit* senderWidget = (QLineEdit*)sender(); - - // return if one of the widgets does not exist - if (item == nullptr || senderWidget == nullptr) - return; - - // call commands for name change if name does not exist yet - if (senderWidget->styleSheet() == "") - { - // call command for adding a new node group - String outResult; - String command; - command.Format( "AdjustNodeGroup -actorID %i -name \"%s\" -newName \"%s\"", mActor->GetID(), FromQtString(item->text()).c_str(), FromQtString(senderWidget->text()).c_str() ); - if (EMStudio::GetCommandManager()->ExecuteCommand( command.c_str(), outResult ) == false) - LogError( outResult.c_str() ); - } - else - { - // delete the line edit - mNodeGroupsTable->setCellWidget(item->row(), item->column(), nullptr); - } - }*/ // function to add a new node group with the specified name @@ -562,16 +475,20 @@ namespace EMStudio if (rowChechbox == senderCheckbox) { nodeGroupName = mNodeGroupsTable->item(i, 1)->text().toUtf8().data(); + break; } } // execute the command AZStd::string outResult; - const AZStd::string command = AZStd::string::format("AdjustNodeGroup -actorID %i -name \"%s\" -enabledOnDefault \"%s\"", - mActor->GetID(), - nodeGroupName.c_str(), - AZStd::to_string(checked).c_str()); - if (EMStudio::GetCommandManager()->ExecuteCommand(command.c_str(), outResult) == false) + auto* command = aznew CommandSystem::CommandAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAdjustNodeGroup::s_commandName), + /*actorId=*/ mActor->GetID(), + /*name=*/ nodeGroupName, + /*newName=*/ AZStd::nullopt, + /*enabledOnDefault=*/ checked + ); + if (EMStudio::GetCommandManager()->ExecuteCommand(command, outResult) == false) { AZ_Error("EMotionFX", false, outResult.c_str()); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.cpp index 31d704a1d5..39ee1c4f5b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.cpp @@ -35,7 +35,6 @@ namespace EMStudio mNodeTable = nullptr; mSelectNodesButton = nullptr; mNodeGroup = nullptr; - mNodeAction = ""; // init the widget Init(); @@ -254,11 +253,11 @@ namespace EMStudio QWidget* senderWidget = (QWidget*)sender(); if (senderWidget == mAddNodesButton) { - mNodeAction = "add"; + mNodeAction = CommandSystem::CommandAdjustNodeGroup::NodeAction::Add; } else { - mNodeAction = "select"; + mNodeAction = CommandSystem::CommandAdjustNodeGroup::NodeAction::Replace; } // get the selected actorinstance @@ -293,46 +292,37 @@ namespace EMStudio // remove nodes void NodeGroupWidget::RemoveNodesButtonPressed() { - // generate node list string - AZStd::string nodeList; - uint32 lowestSelectedRow = MCORE_INVALIDINDEX32; - const uint32 numTableRows = mNodeTable->rowCount(); - for (uint32 i = 0; i < numTableRows; ++i) - { - // get the current table item - QTableWidgetItem* item = mNodeTable->item(i, 0); - if (item == nullptr) - { - continue; - } - - // add the item to remove list, if it's selected - if (item->isSelected()) - { - nodeList += AZStd::string::format("%s;", item->text().toUtf8().data()); - if ((uint32)item->row() < lowestSelectedRow) - { - lowestSelectedRow = (uint32)item->row(); - } - } - } - - // stop here if nothing selected - if (nodeList.empty()) + if (mNodeTable->selectedItems().empty()) { return; } - // call command for adjusting disable on default flag + // generate node list string + AZStd::vector nodeList; + int lowestSelectedRow = AZStd::numeric_limits::max(); + for (const QTableWidgetItem* item : mNodeTable->selectedItems()) + { + nodeList.emplace_back(FromQtString(item->text())); + lowestSelectedRow = AZStd::min(lowestSelectedRow, item->row()); + } + AZStd::string outResult; - AZStd::string command = AZStd::string::format("AdjustNodeGroup -actorID %i -name \"%s\" -nodeAction \"remove\" -nodeNames \"%s\"", mActor->GetID(), mNodeGroup->GetName(), nodeList.c_str()); + auto* command = aznew CommandSystem::CommandAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAdjustNodeGroup::s_commandName), + /*actorId=*/ mActor->GetID(), + /*name=*/ mNodeGroup->GetName(), + /*newName=*/ AZStd::nullopt, + /*enabledOnDefault=*/ AZStd::nullopt, + /*nodeNames=*/ AZStd::move(nodeList), + /*nodeAction=*/ CommandSystem::CommandAdjustNodeGroup::NodeAction::Remove + ); if (EMStudio::GetCommandManager()->ExecuteCommand(command, outResult) == false) { AZ_Error("EMotionFX", false, outResult.c_str()); } // selected the next row - if (lowestSelectedRow > ((uint32)mNodeTable->rowCount() - 1)) + if (lowestSelectedRow > (mNodeTable->rowCount() - 1)) { mNodeTable->selectRow(lowestSelectedRow - 1); } @@ -353,19 +343,23 @@ namespace EMStudio } // generate node list string - AZStd::string nodeList; - nodeList.reserve(16448); - const uint32 numSelectedNodes = selectionList.GetLength(); - for (uint32 i = 0; i < numSelectedNodes; ++i) + AZStd::vector nodeList; + const uint32 selectionListSize = selectionList.GetLength(); + for (uint32 i = 0; i < selectionListSize; ++i) { - nodeList += selectionList[i].GetNodeName(); - nodeList += ";"; + nodeList.emplace_back(selectionList[i].GetNodeName()); } - AzFramework::StringFunc::Strip(nodeList, MCore::CharacterConstants::semiColon, true /* case sensitive */, false /* beginning */, true /* ending */); - // call command for adjusting disable on default flag AZStd::string outResult; - AZStd::string command = AZStd::string::format("AdjustNodeGroup -actorID %i -name \"%s\" -nodeAction \"%s\" -nodeNames \"%s\"", mActor->GetID(), mNodeGroup->GetName(), mNodeAction.c_str(), nodeList.c_str()); + auto* command = aznew CommandSystem::CommandAdjustNodeGroup( + GetCommandManager()->FindCommand(CommandSystem::CommandAdjustNodeGroup::s_commandName), + /*actorId=*/ mActor->GetID(), + /*name=*/ mNodeGroup->GetName(), + /*newName=*/ AZStd::nullopt, + /*enabledOnDefault=*/ AZStd::nullopt, + /*nodeNames=*/ AZStd::move(nodeList), + /*nodeAction=*/ mNodeAction + ); if (EMStudio::GetCommandManager()->ExecuteCommand(command, outResult) == false) { AZ_Error("EMotionFX", false, outResult.c_str()); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.h index ebef94b05c..2b4cad06de 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupWidget.h @@ -13,6 +13,7 @@ #include #include "../../../../EMStudioSDK/Source/DockWidgetPlugin.h" #include "../../../../EMStudioSDK/Source/NodeSelectionWindow.h" +#include #endif QT_FORWARD_DECLARE_CLASS(QLineEdit) @@ -58,7 +59,7 @@ namespace EMStudio CommandSystem::SelectionList mNodeSelectionList; EMotionFX::NodeGroup* mNodeGroup; uint16 mNodeGroupIndex; - AZStd::string mNodeAction; + CommandSystem::CommandAdjustNodeGroup::NodeAction mNodeAction; // widgets QTableWidget* mNodeTable; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupsPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupsPlugin.cpp index 91a96ef39d..218035dc30 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupsPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/NodeGroups/NodeGroupsPlugin.cpp @@ -11,6 +11,7 @@ #include "../../../../EMStudioSDK/Source/EMStudioCore.h" #include #include +#include #include "../../../../EMStudioSDK/Source/EMStudioManager.h" // include qt headers @@ -99,7 +100,7 @@ namespace EMStudio GetCommandManager()->RegisterCommandCallback("Select", mSelectCallback); GetCommandManager()->RegisterCommandCallback("Unselect", mUnselectCallback); GetCommandManager()->RegisterCommandCallback("ClearSelection", mClearSelectionCallback); - GetCommandManager()->RegisterCommandCallback("AdjustNodeGroup", mAdjustNodeGroupCallback); + GetCommandManager()->RegisterCommandCallback(CommandSystem::CommandAdjustNodeGroup::s_commandName.data(), mAdjustNodeGroupCallback); GetCommandManager()->RegisterCommandCallback("AddNodeGroup", mAddNodeGroupCallback); GetCommandManager()->RegisterCommandCallback("RemoveNodeGroup", mRemoveNodeGroupCallback); From 24607df8f303a2bf9fc75365b16ed00438fcaff4 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 2 Aug 2021 14:02:39 -0500 Subject: [PATCH 115/157] Added .gitignore so that Script Canvas debug logs don't get picked up as untracked files. Signed-off-by: Chris Galvan --- Gems/ScriptCanvas/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 Gems/ScriptCanvas/.gitignore diff --git a/Gems/ScriptCanvas/.gitignore b/Gems/ScriptCanvas/.gitignore new file mode 100644 index 0000000000..7ae9da2d7f --- /dev/null +++ b/Gems/ScriptCanvas/.gitignore @@ -0,0 +1 @@ +Assets/Logs/ \ No newline at end of file From 8542de8c3291458b11bebc158e273d067d442504 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 2 Aug 2021 12:02:58 -0700 Subject: [PATCH 116/157] Fixed a link error on android (clang) --- .../Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h | 2 +- .../RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h index 27137459b7..dd46aca6cd 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h @@ -26,7 +26,7 @@ namespace AZ static void Reflect(AZ::ReflectContext* context); using StableId = uint32_t; - static const StableId InvalidStableId = -1; + static const StableId InvalidStableId; //! This ID must have a consistent value when the asset is reprocessed by the asset pipeline, and must be unique within the ModelLodAsset. //! In practice, this set using the MaterialUid from SceneAPI. See ModelAssetBuilderComponent::CreateMesh. diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp index 61f3ebbe3a..0900949625 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelMaterialSlot.cpp @@ -13,6 +13,10 @@ namespace AZ { namespace RPI { + // Normally this would be defined in the header file and substituted by the compiler, but for + // some reason clang doesn't accept it. + const ModelMaterialSlot::StableId ModelMaterialSlot::InvalidStableId = -1; + void ModelMaterialSlot::Reflect(AZ::ReflectContext* context) { if (auto* serializeContext = azrtti_cast(context)) From ed8227f47a8def7c7cec1ba3579ac026965574ff Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 2 Aug 2021 14:32:11 -0500 Subject: [PATCH 117/157] Updated new project template .gitignore files so that temporary level saves in _savebackup files will be ignored as untracked files. Signed-off-by: Chris Galvan --- Templates/DefaultProject/Template/.gitignore | 3 ++- Templates/MinimalProject/Template/.gitignore | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Templates/DefaultProject/Template/.gitignore b/Templates/DefaultProject/Template/.gitignore index f21f551ce4..28b4b330f5 100644 --- a/Templates/DefaultProject/Template/.gitignore +++ b/Templates/DefaultProject/Template/.gitignore @@ -1,4 +1,5 @@ [Bb]uild/ [Cc]ache/ [Uu]ser/ -[Uu]ser_test*/ \ No newline at end of file +[Uu]ser_test*/ +_savebackup/ \ No newline at end of file diff --git a/Templates/MinimalProject/Template/.gitignore b/Templates/MinimalProject/Template/.gitignore index 9a6d119b1b..a3c776304c 100644 --- a/Templates/MinimalProject/Template/.gitignore +++ b/Templates/MinimalProject/Template/.gitignore @@ -1,3 +1,4 @@ [Bb]uild/ [Cc]ache/ -[Uu]ser/ \ No newline at end of file +[Uu]ser/ +_savebackup/ \ No newline at end of file From d03c2c9977338fdfb0313d093c2678ff0d9841d7 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 2 Aug 2021 13:53:13 -0700 Subject: [PATCH 118/157] Copy jinja/py files to the install folder (#2643) * Copy jinja/py files to the install folder Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * code review comment Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * moving AzAutoGen to cmake folder and removing the header-only project Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Framework/AzAutoGen/CMakeLists.txt | 14 -------------- Code/Framework/AzAutoGen/azautogen_files.cmake | 11 ----------- Code/Framework/CMakeLists.txt | 1 - {Code/Framework/AzAutoGen => cmake}/AzAutoGen.py | 0 cmake/LyAutoGen.cmake | 6 +++--- cmake/Platform/Common/Install_common.cmake | 16 ++++++++-------- cmake/cmake_files.cmake | 1 + 7 files changed, 12 insertions(+), 37 deletions(-) delete mode 100644 Code/Framework/AzAutoGen/CMakeLists.txt delete mode 100644 Code/Framework/AzAutoGen/azautogen_files.cmake rename {Code/Framework/AzAutoGen => cmake}/AzAutoGen.py (100%) diff --git a/Code/Framework/AzAutoGen/CMakeLists.txt b/Code/Framework/AzAutoGen/CMakeLists.txt deleted file mode 100644 index 9338520570..0000000000 --- a/Code/Framework/AzAutoGen/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -ly_add_target( - NAME AzAutoGen HEADERONLY - NAMESPACE AZ - FILES_CMAKE - azautogen_files.cmake -) diff --git a/Code/Framework/AzAutoGen/azautogen_files.cmake b/Code/Framework/AzAutoGen/azautogen_files.cmake deleted file mode 100644 index 9eb4460b5c..0000000000 --- a/Code/Framework/AzAutoGen/azautogen_files.cmake +++ /dev/null @@ -1,11 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(FILES - AzAutoGen.py -) diff --git a/Code/Framework/CMakeLists.txt b/Code/Framework/CMakeLists.txt index 45ccb22b14..61f65de5a4 100644 --- a/Code/Framework/CMakeLists.txt +++ b/Code/Framework/CMakeLists.txt @@ -6,7 +6,6 @@ # # -add_subdirectory(AzAutoGen) add_subdirectory(AtomCore) add_subdirectory(AzCore) add_subdirectory(AzQtComponents) diff --git a/Code/Framework/AzAutoGen/AzAutoGen.py b/cmake/AzAutoGen.py similarity index 100% rename from Code/Framework/AzAutoGen/AzAutoGen.py rename to cmake/AzAutoGen.py diff --git a/cmake/LyAutoGen.cmake b/cmake/LyAutoGen.cmake index 64cb73a453..4aec0f9726 100644 --- a/cmake/LyAutoGen.cmake +++ b/cmake/LyAutoGen.cmake @@ -25,17 +25,17 @@ function(ly_add_autogen) list(FILTER AZCG_INPUTFILES INCLUDE REGEX ".*\.(xml|json|jinja)$") target_include_directories(${ly_add_autogen_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated") execute_process( - COMMAND ${LY_PYTHON_CMD} "${LY_ROOT_FOLDER}/Code/Framework/AzAutoGen/AzAutoGen.py" "${CMAKE_BINARY_DIR}/Azcg/TemplateCache/" "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated/" "${CMAKE_CURRENT_SOURCE_DIR}" "${AZCG_INPUTFILES}" "${ly_add_autogen_AUTOGEN_RULES}" "-n" + COMMAND ${LY_PYTHON_CMD} "${LY_ROOT_FOLDER}/cmake/AzAutoGen.py" "${CMAKE_BINARY_DIR}/Azcg/TemplateCache/" "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated/" "${CMAKE_CURRENT_SOURCE_DIR}" "${AZCG_INPUTFILES}" "${ly_add_autogen_AUTOGEN_RULES}" "-n" OUTPUT_VARIABLE AUTOGEN_OUTPUTS ) string(STRIP "${AUTOGEN_OUTPUTS}" AUTOGEN_OUTPUTS) set(AZCG_DEPENDENCIES ${AZCG_INPUTFILES}) - list(APPEND AZCG_DEPENDENCIES "${LY_ROOT_FOLDER}/Code/Framework/AzAutoGen/AzAutoGen.py") + list(APPEND AZCG_DEPENDENCIES "${LY_ROOT_FOLDER}/cmake/AzAutoGen.py") add_custom_command( OUTPUT ${AUTOGEN_OUTPUTS} DEPENDS ${AZCG_DEPENDENCIES} COMMAND ${CMAKE_COMMAND} -E echo "Running AutoGen for ${ly_add_autogen_NAME}" - COMMAND ${LY_PYTHON_CMD} "${LY_ROOT_FOLDER}/Code/Framework/AzAutoGen/AzAutoGen.py" "${CMAKE_BINARY_DIR}/Azcg/TemplateCache/" "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated/" "${CMAKE_CURRENT_SOURCE_DIR}" "${AZCG_INPUTFILES}" "${ly_add_autogen_AUTOGEN_RULES}" + COMMAND ${LY_PYTHON_CMD} "${LY_ROOT_FOLDER}/cmake/AzAutoGen.py" "${CMAKE_BINARY_DIR}/Azcg/TemplateCache/" "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated/" "${CMAKE_CURRENT_SOURCE_DIR}" "${AZCG_INPUTFILES}" "${ly_add_autogen_AUTOGEN_RULES}" VERBATIM ) set_target_properties(${ly_add_autogen_NAME} PROPERTIES AUTOGEN_INPUT_FILES "${AZCG_INPUTFILES}") diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 612358f938..353c015fd3 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -45,7 +45,6 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. # Instead, we install them with install(DIRECTORY) - set(include_location "include") get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) if (include_directories) unset(public_headers) @@ -63,9 +62,10 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar continue() endif() + unset(rel_include_dir) cmake_path(RELATIVE_PATH include_directory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE rel_include_dir) - cmake_path(APPEND include_location "${rel_include_dir}" ".." OUTPUT_VARIABLE destination_dir) - cmake_path(NORMAL_PATH destination_dir) + cmake_path(APPEND rel_include_dir "..") + cmake_path(NORMAL_PATH rel_include_dir OUTPUT_VARIABLE destination_dir) install(DIRECTORY ${include_directory} DESTINATION ${destination_dir} @@ -75,6 +75,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar PATTERN *.hpp PATTERN *.inl PATTERN *.hxx + PATTERN *.jinja # LyAutoGen files ) endif() endforeach() @@ -156,10 +157,9 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar foreach(include ${include_directories}) string(GENEX_STRIP ${include} include_genex_expr) if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions - cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE target_include) - cmake_path(NORMAL_PATH target_include) - # Escape the LY_ROOT_FOLDER variable so that it isn't resolved during the install step - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/${include_location}/${target_include}\n") + # Make the include path relative to the source dir where the target will be declared + cmake_path(RELATIVE_PATH include BASE_DIRECTORY ${absolute_target_source_dir} OUTPUT_VARIABLE target_include) + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "${target_include}\n") endif() endforeach() endif() @@ -204,7 +204,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar set(TARGET_RUN_HELPER "add_custom_target(${RUN_TARGET_NAME}) set_target_properties(${RUN_TARGET_NAME} PROPERTIES - FOLDER \"CMakePredefinedTargets/SDK\" + FOLDER \"O3DE_SDK\" VS_DEBUGGER_COMMAND \$> VS_DEBUGGER_COMMAND_ARGUMENTS \"--project-path=\${LY_DEFAULT_PROJECT_PATH}\" )" diff --git a/cmake/cmake_files.cmake b/cmake/cmake_files.cmake index 490817d625..aa275b634a 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -9,6 +9,7 @@ set(FILES 3rdParty.cmake 3rdPartyPackages.cmake + AzAutoGen.py CMakeFiles.cmake CommandExecution.cmake Configurations.cmake From c3103a3fe7d2a0cc6bd4c1b157bdf5dfcfcff1ed Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 2 Aug 2021 14:25:53 -0700 Subject: [PATCH 119/157] Fix release build error. Atom's DebugCamera SetOrthographic was only using a parameter during an assert, leading to a release compile error, this fixes that Signed-off-by: nvsickle --- Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp b/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp index 9a6f7c83ab..330b6571f3 100644 --- a/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp +++ b/Gems/Atom/Component/DebugCamera/Code/Source/CameraComponent.cpp @@ -235,7 +235,7 @@ namespace AZ UpdateViewToClipMatrix(); } - void CameraComponent::SetOrthographic(bool orthographic) + void CameraComponent::SetOrthographic([[maybe_unused]] bool orthographic) { AZ_Assert(!orthographic, "DebugCamera does not support orthographic projection"); } From 07e2bea1fe5f2250b778b871fe1c78568a0fbc2c Mon Sep 17 00:00:00 2001 From: puvvadar Date: Mon, 2 Aug 2021 17:41:09 -0700 Subject: [PATCH 120/157] Add connection interface timeout config and remove Ctrl+G timer Signed-off-by: puvvadar --- .../AzNetworking/Framework/INetworkInterface.h | 8 ++++++++ .../TcpTransport/TcpNetworkInterface.cpp | 12 +++++++++++- .../AzNetworking/TcpTransport/TcpNetworkInterface.h | 3 +++ .../UdpTransport/UdpNetworkInterface.cpp | 12 +++++++++++- .../AzNetworking/UdpTransport/UdpNetworkInterface.h | 3 +++ .../Source/Editor/MultiplayerEditorConnection.cpp | 1 + .../Editor/MultiplayerEditorSystemComponent.cpp | 6 +----- 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h index d47f76ceb8..c5f79699dd 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h @@ -103,6 +103,14 @@ namespace AzNetworking //! @return boolean true on success virtual bool Disconnect(ConnectionId connectionId, DisconnectReason reason) = 0; + //! Sets whether this connection interface can disconnect by virtue of a timeout + //! @param doesTimeout If this connection interface will automatically disconnect due to a timeout + virtual void SetDoesTimeout(bool doesTimeout) = 0; + + //! Whether this connection interface will disconnect by virtue of a time out (does not account for cvars affecting all connections) + //! @return boolean true if this connection will not disconnect on timeout (does not account for cvars affecting all connections) + virtual bool DoesTimeout() = 0; + //! Const access to the metrics tracked by this network interface. //! @return const reference to the metrics tracked by this network interface const NetworkInterfaceMetrics& GetMetrics() const; diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp index f9569b5c7e..b3aeef3345 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp @@ -174,6 +174,16 @@ namespace AzNetworking return connection->Disconnect(reason, TerminationEndpoint::Local); } + void TcpNetworkInterface::SetDoesTimeout(bool doesTimeout) + { + m_doesTimeout = doesTimeout; + } + + bool TcpNetworkInterface::DoesTimeout() + { + return m_doesTimeout; + } + void TcpNetworkInterface::QueueNewConnection(const PendingConnection& pendingConnection) { m_pendingConnections.PushBackItem(pendingConnection); @@ -306,7 +316,7 @@ namespace AzNetworking { tcpConnection->SendReliablePacket(CorePackets::HeartbeatPacket()); } - else if (net_TcpTimeoutConnections) + else if (net_TcpTimeoutConnections && m_networkInterface.DoesTimeout()) { tcpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local); return TimeoutResult::Delete; diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h index 1d590da2aa..d1e9fb67cc 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h @@ -99,6 +99,8 @@ namespace AzNetworking bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override; bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; + void SetDoesTimeout(bool doesTimeout) override; + bool DoesTimeout() override; //! @} //! Queues a new incoming connection for this network interface. @@ -154,6 +156,7 @@ namespace AzNetworking AZ::Name m_name; TrustZone m_trustZone; uint16_t m_port = 0; + bool m_doesTimeout = true; IConnectionListener& m_connectionListener; TcpConnectionSet m_connectionSet; TcpSocketManager m_tcpSocketManager; diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp index a3ddb856d2..5be8594a2f 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp @@ -397,6 +397,16 @@ namespace AzNetworking return connection->Disconnect(reason, TerminationEndpoint::Local); } + void UdpNetworkInterface::SetDoesTimeout(bool doesTimeout) + { + m_doesTimeout = doesTimeout; + } + + bool UdpNetworkInterface::DoesTimeout() + { + return m_doesTimeout; + } + bool UdpNetworkInterface::IsEncrypted() const { return m_socket->IsEncrypted(); @@ -729,7 +739,7 @@ namespace AzNetworking { udpConnection->SendUnreliablePacket(CorePackets::HeartbeatPacket()); } - else if (net_UdpTimeoutConnections) + else if (net_UdpTimeoutConnections && m_networkInterface.DoesTimeout()) { udpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local); return TimeoutResult::Delete; diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h index 7a391c152e..b2e80dc3e9 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h @@ -104,6 +104,8 @@ namespace AzNetworking bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override; bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; + void SetDoesTimeout(bool doesTimeout) override; + bool DoesTimeout() override; //! @} //! Returns true if this is an encrypted socket, false if not. @@ -179,6 +181,7 @@ namespace AzNetworking TrustZone m_trustZone; uint16_t m_port = 0; bool m_allowIncomingConnections = false; + bool m_doesTimeout = true; IConnectionListener& m_connectionListener; UdpConnectionSet m_connectionSet; TimeoutQueue m_connectionTimeoutQueue; diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index deb53bacab..db2a36ae20 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -32,6 +32,7 @@ namespace Multiplayer { m_networkEditorInterface = AZ::Interface::Get()->CreateNetworkInterface( AZ::Name(MPEditorInterfaceName), ProtocolType::Tcp, TrustZone::ExternalClientToServer, *this); + m_networkEditorInterface->SetDoesTimeout(false); if (editorsv_isDedicated) { uint16_t editorServerPort = DefaultServerEditorPort; diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 9030b150e6..d557c65215 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -147,13 +147,9 @@ namespace Multiplayer processLaunchInfo.m_showWindow = true; processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; - // Launch the Server and give it a few seconds to boot up + // Launch the Server AzFramework::ProcessWatcher* outProcess = AzFramework::ProcessWatcher::LaunchProcess( processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE); - if (outProcess) - { - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(15000)); - } return outProcess; } From 115f669679521f6ad0d49317945dd82347a9233e Mon Sep 17 00:00:00 2001 From: puvvadar Date: Mon, 2 Aug 2021 20:31:02 -0700 Subject: [PATCH 121/157] Rename timeout functions for readability Signed-off-by: puvvadar --- .../AzNetworking/AzNetworking/Framework/INetworkInterface.h | 4 ++-- .../AzNetworking/TcpTransport/TcpNetworkInterface.cpp | 6 +++--- .../AzNetworking/TcpTransport/TcpNetworkInterface.h | 4 ++-- .../AzNetworking/UdpTransport/UdpNetworkInterface.cpp | 6 +++--- .../AzNetworking/UdpTransport/UdpNetworkInterface.h | 4 ++-- .../Code/Source/Editor/MultiplayerEditorConnection.cpp | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h index c5f79699dd..303fd3de0f 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h @@ -105,11 +105,11 @@ namespace AzNetworking //! Sets whether this connection interface can disconnect by virtue of a timeout //! @param doesTimeout If this connection interface will automatically disconnect due to a timeout - virtual void SetDoesTimeout(bool doesTimeout) = 0; + virtual void SetTimeoutEnabled(bool doesTimeout) = 0; //! Whether this connection interface will disconnect by virtue of a time out (does not account for cvars affecting all connections) //! @return boolean true if this connection will not disconnect on timeout (does not account for cvars affecting all connections) - virtual bool DoesTimeout() = 0; + virtual bool IsTimeoutEnabled() = 0; //! Const access to the metrics tracked by this network interface. //! @return const reference to the metrics tracked by this network interface diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp index b3aeef3345..26972cfa0b 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp @@ -174,12 +174,12 @@ namespace AzNetworking return connection->Disconnect(reason, TerminationEndpoint::Local); } - void TcpNetworkInterface::SetDoesTimeout(bool doesTimeout) + void TcpNetworkInterface::SetTimeoutEnabled(bool doesTimeout) { m_doesTimeout = doesTimeout; } - bool TcpNetworkInterface::DoesTimeout() + bool TcpNetworkInterface::IsTimeoutEnabled() { return m_doesTimeout; } @@ -316,7 +316,7 @@ namespace AzNetworking { tcpConnection->SendReliablePacket(CorePackets::HeartbeatPacket()); } - else if (net_TcpTimeoutConnections && m_networkInterface.DoesTimeout()) + else if (net_TcpTimeoutConnections && m_networkInterface.IsTimeoutEnabled()) { tcpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local); return TimeoutResult::Delete; diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h index d1e9fb67cc..f041f707be 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h @@ -99,8 +99,8 @@ namespace AzNetworking bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override; bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; - void SetDoesTimeout(bool doesTimeout) override; - bool DoesTimeout() override; + void SetTimeoutEnabled(bool doesTimeout) override; + bool IsTimeoutEnabled() override; //! @} //! Queues a new incoming connection for this network interface. diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp index 5be8594a2f..6be01d84ed 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp @@ -397,12 +397,12 @@ namespace AzNetworking return connection->Disconnect(reason, TerminationEndpoint::Local); } - void UdpNetworkInterface::SetDoesTimeout(bool doesTimeout) + void UdpNetworkInterface::SetTimeoutEnabled(bool doesTimeout) { m_doesTimeout = doesTimeout; } - bool UdpNetworkInterface::DoesTimeout() + bool UdpNetworkInterface::IsTimeoutEnabled() { return m_doesTimeout; } @@ -739,7 +739,7 @@ namespace AzNetworking { udpConnection->SendUnreliablePacket(CorePackets::HeartbeatPacket()); } - else if (net_UdpTimeoutConnections && m_networkInterface.DoesTimeout()) + else if (net_UdpTimeoutConnections && m_networkInterface.IsTimeoutEnabled()) { udpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local); return TimeoutResult::Delete; diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h index b2e80dc3e9..087ed9d52f 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h @@ -104,8 +104,8 @@ namespace AzNetworking bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override; bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; - void SetDoesTimeout(bool doesTimeout) override; - bool DoesTimeout() override; + void SetTimeoutEnabled(bool doesTimeout) override; + bool IsTimeoutEnabled() override; //! @} //! Returns true if this is an encrypted socket, false if not. diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index db2a36ae20..fc398182ef 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -32,7 +32,7 @@ namespace Multiplayer { m_networkEditorInterface = AZ::Interface::Get()->CreateNetworkInterface( AZ::Name(MPEditorInterfaceName), ProtocolType::Tcp, TrustZone::ExternalClientToServer, *this); - m_networkEditorInterface->SetDoesTimeout(false); + m_networkEditorInterface->SetTimeoutEnabled(false); if (editorsv_isDedicated) { uint16_t editorServerPort = DefaultServerEditorPort; From 573fe425d7030d7aadc9149c8ff45c177798cd5c Mon Sep 17 00:00:00 2001 From: puvvadar Date: Mon, 2 Aug 2021 20:34:39 -0700 Subject: [PATCH 122/157] Also rename some variables to match renamed timeout funcs Signed-off-by: puvvadar --- .../AzNetworking/TcpTransport/TcpNetworkInterface.cpp | 6 +++--- .../AzNetworking/TcpTransport/TcpNetworkInterface.h | 4 ++-- .../AzNetworking/UdpTransport/UdpNetworkInterface.cpp | 6 +++--- .../AzNetworking/UdpTransport/UdpNetworkInterface.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp index 26972cfa0b..52c696b663 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp @@ -174,14 +174,14 @@ namespace AzNetworking return connection->Disconnect(reason, TerminationEndpoint::Local); } - void TcpNetworkInterface::SetTimeoutEnabled(bool doesTimeout) + void TcpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled) { - m_doesTimeout = doesTimeout; + m_timeoutEnabled = timeoutEnabled; } bool TcpNetworkInterface::IsTimeoutEnabled() { - return m_doesTimeout; + return m_timeoutEnabled; } void TcpNetworkInterface::QueueNewConnection(const PendingConnection& pendingConnection) diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h index f041f707be..3eb792bc7f 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h @@ -99,7 +99,7 @@ namespace AzNetworking bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override; bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; - void SetTimeoutEnabled(bool doesTimeout) override; + void SetTimeoutEnabled(bool timeoutEnabled) override; bool IsTimeoutEnabled() override; //! @} @@ -156,7 +156,7 @@ namespace AzNetworking AZ::Name m_name; TrustZone m_trustZone; uint16_t m_port = 0; - bool m_doesTimeout = true; + bool m_timeoutEnabled = true; IConnectionListener& m_connectionListener; TcpConnectionSet m_connectionSet; TcpSocketManager m_tcpSocketManager; diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp index 6be01d84ed..a80cb82d03 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp @@ -397,14 +397,14 @@ namespace AzNetworking return connection->Disconnect(reason, TerminationEndpoint::Local); } - void UdpNetworkInterface::SetTimeoutEnabled(bool doesTimeout) + void UdpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled) { - m_doesTimeout = doesTimeout; + m_timeoutEnabled = timeoutEnabled; } bool UdpNetworkInterface::IsTimeoutEnabled() { - return m_doesTimeout; + return m_timeoutEnabled; } bool UdpNetworkInterface::IsEncrypted() const diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h index 087ed9d52f..0260491295 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h @@ -104,7 +104,7 @@ namespace AzNetworking bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override; bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; - void SetTimeoutEnabled(bool doesTimeout) override; + void SetTimeoutEnabled(bool timeoutEnabled) override; bool IsTimeoutEnabled() override; //! @} @@ -181,7 +181,7 @@ namespace AzNetworking TrustZone m_trustZone; uint16_t m_port = 0; bool m_allowIncomingConnections = false; - bool m_doesTimeout = true; + bool m_timeoutEnabled = true; IConnectionListener& m_connectionListener; UdpConnectionSet m_connectionSet; TimeoutQueue m_connectionTimeoutQueue; From 6964e4f7e9182871b4e6c05607d5308237564ae1 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Mon, 2 Aug 2021 20:35:44 -0700 Subject: [PATCH 123/157] Missed one variable rename Signed-off-by: puvvadar --- .../AzNetworking/AzNetworking/Framework/INetworkInterface.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h index 303fd3de0f..f2ad1c03c3 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h @@ -104,8 +104,8 @@ namespace AzNetworking virtual bool Disconnect(ConnectionId connectionId, DisconnectReason reason) = 0; //! Sets whether this connection interface can disconnect by virtue of a timeout - //! @param doesTimeout If this connection interface will automatically disconnect due to a timeout - virtual void SetTimeoutEnabled(bool doesTimeout) = 0; + //! @param timeoutEnabled If this connection interface will automatically disconnect due to a timeout + virtual void SetTimeoutEnabled(bool timeoutEnabled) = 0; //! Whether this connection interface will disconnect by virtue of a time out (does not account for cvars affecting all connections) //! @return boolean true if this connection will not disconnect on timeout (does not account for cvars affecting all connections) From 86758fda35484b939f3cbffb7deb25b9d940cf6e Mon Sep 17 00:00:00 2001 From: hultonha Date: Thu, 22 Jul 2021 13:15:33 +0100 Subject: [PATCH 124/157] documentation pass for modular viewport camera controller Signed-off-by: hultonha --- .../ModularViewportCameraController.h | 66 ++++++++++++------- .../ModularViewportCameraController.cpp | 39 +++++------ 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index 1d2ccc07e1..ca6044c9de 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -16,18 +16,21 @@ namespace AtomToolsFramework { - class ModernViewportCameraControllerInstance; + class ModularViewportCameraControllerInstance; + + //! Builder class to create and configure a ModularViewportCameraControllerInstance. class ModularViewportCameraController : public AzFramework::MultiViewportController< - ModernViewportCameraControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities> + ModularViewportCameraControllerInstance, + AzFramework::ViewportControllerPriority::DispatchToAllPriorities> { public: using CameraListBuilder = AZStd::function; using CameraPropsBuilder = AZStd::function; - //! Sets the camera list builder callback used to populate new ModernViewportCameraControllerInstances + //! Sets the camera list builder callback used to populate new ModularViewportCameraControllerInstances void SetCameraListBuilderCallback(const CameraListBuilder& builder); - //! Sets the camera props builder callback used to populate new ModernViewportCameraControllerInstances + //! Sets the camera props builder callback used to populate new ModularViewportCameraControllerInstances void SetCameraPropsBuilderCallback(const CameraPropsBuilder& builder); //! Sets up a camera list based on this controller's CameraListBuilderCallback void SetupCameras(AzFramework::Cameras& cameras); @@ -35,18 +38,22 @@ namespace AtomToolsFramework void SetupCameraProperies(AzFramework::CameraProps& cameraProps); private: - CameraListBuilder m_cameraListBuilder; - CameraPropsBuilder m_cameraPropsBuilder; + CameraListBuilder + m_cameraListBuilder; //!< Builder to generate a list of CameraInputs to run in the ModularViewportCameraControllerInstance. + CameraPropsBuilder m_cameraPropsBuilder; //!< Builder to define custom camera properties to use for things such as rotate and + //!< translate interpolation. }; - class ModernViewportCameraControllerInstance final - : public AzFramework::MultiViewportControllerInstanceInterface, - public ModularViewportCameraControllerRequestBus::Handler, - private AzFramework::ViewportDebugDisplayEventBus::Handler + //! A customizable camera controller than can be configured to a run varying set of CameraInput instances. + //! The controller can also be animated from its current transform to a new translation and orientation. + class ModularViewportCameraControllerInstance final + : public AzFramework::MultiViewportControllerInstanceInterface + , public ModularViewportCameraControllerRequestBus::Handler + , private AzFramework::ViewportDebugDisplayEventBus::Handler { public: - explicit ModernViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModularViewportCameraController* controller); - ~ModernViewportCameraControllerInstance() override; + explicit ModularViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModularViewportCameraController* controller); + ~ModularViewportCameraControllerInstance() override; // MultiViewportControllerInstanceInterface overrides ... bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; @@ -60,25 +67,34 @@ namespace AtomToolsFramework // AzFramework::ViewportDebugDisplayEventBus overrides ... void DisplayViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + //! The current mode the camera controller is in. enum class CameraMode { - Control, - Animation + Control, //!< The camera is being driven by user input. + Animation //!< The camera is being animated (interpolated) from one transform to another. }; - AzFramework::Camera m_camera; - AzFramework::Camera m_targetCamera; - AzFramework::CameraSystem m_cameraSystem; - AzFramework::CameraProps m_cameraProps; + //! Encapsulates an animation (interpolation) between two transforms. + struct CameraAnimation + { + AZ::Transform m_transformStart = + AZ::Transform::CreateIdentity(); //!< The transform of the camera at the start of the animation. + AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity(); //!< The transform of the camera at the end of the animation. + float m_animationT = 0.0f; //!< The interpolation amount between the start and end transforms (in the range 0.0-1.0). + }; - AZ::Transform m_transformStart = AZ::Transform::CreateIdentity(); - AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity(); - float m_animationT = 0.0f; - CameraMode m_cameraMode = CameraMode::Control; + AzFramework::Camera m_camera; //!< The current camera state (pitch/yaw/position/look-distance). + AzFramework::Camera m_targetCamera; //!< The target (next) camera state that m_camera is catching up to. + AzFramework::CameraSystem m_cameraSystem; //!< The camera system responsible for managing all CameraInputs. + AzFramework::CameraProps m_cameraProps; //!< Camera properties to control rotate and translate smoothness. + + CameraAnimation m_cameraAnimation; //!< Camera animation state (used during CameraMode::Animation). + CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in. AZStd::optional m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished. //!< Will be cleared when the view changes (camera looks away). - bool m_updatingTransform = false; - - AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler; + bool m_updatingTransformInternally = + false; //!< Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally). + AZ::RPI::ViewportContext::MatrixChangedEvent::Handler + m_cameraViewMatrixChangeHandler; //!< Listen for camera view changes outside of the camera controller. }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index 10cfa059aa..ce4c6021af 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -84,7 +84,7 @@ namespace AtomToolsFramework } } - ModernViewportCameraControllerInstance::ModernViewportCameraControllerInstance( + ModularViewportCameraControllerInstance::ModularViewportCameraControllerInstance( const AzFramework::ViewportId viewportId, ModularViewportCameraController* controller) : MultiViewportControllerInstanceInterface(viewportId, controller) { @@ -95,7 +95,8 @@ namespace AtomToolsFramework { auto handleCameraChange = [this, viewportContext](const AZ::Matrix4x4&) { - if (!m_updatingTransform) + // ignore these updates if the camera is being updated internally + if (!m_updatingTransformInternally) { UpdateCameraFromTransform(m_targetCamera, viewportContext->GetCameraTransform()); m_camera = m_targetCamera; @@ -111,7 +112,7 @@ namespace AtomToolsFramework ModularViewportCameraControllerRequestBus::Handler::BusConnect(viewportId); } - ModernViewportCameraControllerInstance::~ModernViewportCameraControllerInstance() + ModularViewportCameraControllerInstance::~ModularViewportCameraControllerInstance() { ModularViewportCameraControllerRequestBus::Handler::BusDisconnect(); AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect(); @@ -132,7 +133,7 @@ namespace AtomToolsFramework return AzFramework::ViewportControllerPriority::Normal; } - bool ModernViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) + bool ModularViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) { if (event.m_priority == GetPriority(m_cameraSystem)) { @@ -142,7 +143,7 @@ namespace AtomToolsFramework return false; } - void ModernViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) + void ModularViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) { // only update for a single priority (normal is the default) if (event.m_priority != AzFramework::ViewportControllerPriority::Normal) @@ -152,7 +153,7 @@ namespace AtomToolsFramework if (auto viewportContext = RetrieveViewportContext(GetViewportId())) { - m_updatingTransform = true; + m_updatingTransformInternally = true; if (m_cameraMode == CameraMode::Control) { @@ -180,10 +181,12 @@ namespace AtomToolsFramework return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); }; - const float transitionT = smootherStepFn(m_animationT); + const auto& [transformStart, transformEnd, animationT] = m_cameraAnimation; + + const float transitionT = smootherStepFn(animationT); const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation( - m_transformStart.GetRotation().Slerp(m_transformEnd.GetRotation(), transitionT), - m_transformStart.GetTranslation().Lerp(m_transformEnd.GetTranslation(), transitionT)); + transformStart.GetRotation().Slerp(transformEnd.GetRotation(), transitionT), + transformStart.GetTranslation().Lerp(transformEnd.GetTranslation(), transitionT)); const AZ::Vector3 eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(current)); m_camera.m_pitch = eulerAngles.GetX(); @@ -191,21 +194,21 @@ namespace AtomToolsFramework m_camera.m_lookAt = current.GetTranslation(); m_targetCamera = m_camera; - if (m_animationT >= 1.0f) + if (animationT >= 1.0f) { m_cameraMode = CameraMode::Control; } - m_animationT = AZ::GetClamp(m_animationT + event.m_deltaTime.count(), 0.0f, 1.0f); + m_cameraAnimation.m_animationT = AZ::GetClamp(animationT + event.m_deltaTime.count(), 0.0f, 1.0f); viewportContext->SetCameraTransform(current); } - m_updatingTransform = false; + m_updatingTransformInternally = false; } } - void ModernViewportCameraControllerInstance::DisplayViewport( + void ModularViewportCameraControllerInstance::DisplayViewport( [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { if (const float alpha = AZStd::min(-m_camera.m_lookDist / 5.0f, 1.0f); alpha > AZ::Constants::FloatEpsilon) @@ -216,16 +219,14 @@ namespace AtomToolsFramework } } - void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance) + void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance) { - m_animationT = 0.0f; m_cameraMode = CameraMode::Animation; - m_transformStart = m_camera.Transform(); - m_transformEnd = worldFromLocal; - m_lookAtAfterInterpolation = m_transformEnd.GetTranslation() + m_transformEnd.GetBasisY() * lookAtDistance; + m_cameraAnimation = CameraAnimation{ m_camera.Transform(), worldFromLocal, 0.0f }; + m_lookAtAfterInterpolation = worldFromLocal.GetTranslation() + worldFromLocal.GetBasisY() * lookAtDistance; } - AZStd::optional ModernViewportCameraControllerInstance::LookAtAfterInterpolation() const + AZStd::optional ModularViewportCameraControllerInstance::LookAtAfterInterpolation() const { return m_lookAtAfterInterpolation; } From 71a299d739b2750e1a6864e3f8ab73d742c6b0a2 Mon Sep 17 00:00:00 2001 From: hultonha Date: Tue, 3 Aug 2021 13:53:34 +0100 Subject: [PATCH 125/157] minor comment grammar fix Signed-off-by: hultonha --- .../Viewport/ModularViewportCameraController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index ca6044c9de..79219f50b0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -44,7 +44,7 @@ namespace AtomToolsFramework //!< translate interpolation. }; - //! A customizable camera controller than can be configured to a run varying set of CameraInput instances. + //! A customizable camera controller that can be configured to run a varying set of CameraInput instances. //! The controller can also be animated from its current transform to a new translation and orientation. class ModularViewportCameraControllerInstance final : public AzFramework::MultiViewportControllerInstanceInterface From be5a7f821c1f7727a1525808f74f30b77bf17875 Mon Sep 17 00:00:00 2001 From: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Tue, 3 Aug 2021 09:21:36 -0500 Subject: [PATCH 126/157] {LYN-4514} Re-factored Blast gem's python asset builder (#2143) * {LYN-4514} Re-factored Blast gem's python asset builder * Re-factored Blast gem's python asset builder so that the .blast file creates an asset info scene manifest * Added a python script to act as a SceneAPI script + Python Asset Builder (blast_asset_builder.py) * renaming types from "Slice" to "Chunk" Tests: Re-enabled Gems/Blast/Code/Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> * renaming from Slice to Chunks Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> * updated the Copyright Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> * Removing StdAfx.h includes Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> * null check added m_blastChunksAsset.Get() removing 'slice' like EditorBlastSliceAssetHandlerTestFixture delete old asset builder blast file Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> * adding source deps for FBX -> BLAST file Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> * removing slice name Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> * Adding error message and updates from PR Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> --- .../Code/Source/Asset/BlastChunksAsset.cpp | 33 ++ .../Code/Source/Asset/BlastChunksAsset.h | 32 ++ .../Code/Source/Asset/BlastSliceAsset.cpp | 62 --- .../Blast/Code/Source/Asset/BlastSliceAsset.h | 36 -- Gems/Blast/Code/Source/BlastModule.cpp | 4 +- .../Editor/EditorBlastChunksAssetHandler.cpp | 144 +++++++ .../Editor/EditorBlastChunksAssetHandler.h | 46 +++ .../Editor/EditorBlastMeshDataComponent.cpp | 36 +- .../Editor/EditorBlastMeshDataComponent.h | 8 +- .../Editor/EditorBlastSliceAssetHandler.cpp | 345 ---------------- .../Editor/EditorBlastSliceAssetHandler.h | 101 ----- .../Source/Editor/EditorSystemComponent.cpp | 14 +- .../Source/Editor/EditorSystemComponent.h | 4 +- .../EditorBlastChunksAssetHandlerTest.cpp | 207 ++++++++++ .../EditorBlastSliceAssetHandlerTest.cpp | 377 ------------------ Gems/Blast/Code/blast_editor_files.cmake | 4 +- .../Blast/Code/blast_editor_tests_files.cmake | 2 +- Gems/Blast/Code/blast_files.cmake | 4 +- .../Editor/Scripts/asset_builder_blast.py | 323 --------------- .../Editor/Scripts/blast_asset_builder.py | 290 ++++++++++++++ Gems/Blast/Editor/Scripts/bootstrap.py | 13 +- 21 files changed, 801 insertions(+), 1284 deletions(-) create mode 100644 Gems/Blast/Code/Source/Asset/BlastChunksAsset.cpp create mode 100644 Gems/Blast/Code/Source/Asset/BlastChunksAsset.h delete mode 100644 Gems/Blast/Code/Source/Asset/BlastSliceAsset.cpp delete mode 100644 Gems/Blast/Code/Source/Asset/BlastSliceAsset.h create mode 100644 Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.cpp create mode 100644 Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.h delete mode 100644 Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.cpp delete mode 100644 Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.h create mode 100644 Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp delete mode 100644 Gems/Blast/Code/Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp delete mode 100755 Gems/Blast/Editor/Scripts/asset_builder_blast.py create mode 100644 Gems/Blast/Editor/Scripts/blast_asset_builder.py diff --git a/Gems/Blast/Code/Source/Asset/BlastChunksAsset.cpp b/Gems/Blast/Code/Source/Asset/BlastChunksAsset.cpp new file mode 100644 index 0000000000..1d0ce15241 --- /dev/null +++ b/Gems/Blast/Code/Source/Asset/BlastChunksAsset.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace Blast +{ + void BlastChunksAsset::SetModelAssetIds(const AZStd::vector& modelAssetIds) + { + m_modelAssetIds = modelAssetIds; + } + + const AZStd::vector& BlastChunksAsset::GetModelAssetIds() const + { + return m_modelAssetIds; + } + + void BlastChunksAsset::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("modelAssetIds", &BlastChunksAsset::m_modelAssetIds); + } + } + +} // namespace Blast diff --git a/Gems/Blast/Code/Source/Asset/BlastChunksAsset.h b/Gems/Blast/Code/Source/Asset/BlastChunksAsset.h new file mode 100644 index 0000000000..1f6442d8fd --- /dev/null +++ b/Gems/Blast/Code/Source/Asset/BlastChunksAsset.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +namespace Blast +{ + //! The product asset file from a .blast_chunks file product asset file + class BlastChunksAsset final + : public AZ::Data::AssetData + { + public: + AZ_RTTI(BlastChunksAsset, "{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}", AZ::Data::AssetData); + AZ_CLASS_ALLOCATOR(BlastChunksAsset, AZ::SystemAllocator, 0); + + BlastChunksAsset() = default; + ~BlastChunksAsset() override = default; + + void SetModelAssetIds(const AZStd::vector& modelAssetIds); + const AZStd::vector& GetModelAssetIds() const; + + static void Reflect(AZ::ReflectContext* context); + + private: + AZStd::vector m_modelAssetIds; + }; +} // namespace Blast diff --git a/Gems/Blast/Code/Source/Asset/BlastSliceAsset.cpp b/Gems/Blast/Code/Source/Asset/BlastSliceAsset.cpp deleted file mode 100644 index acb3043c19..0000000000 --- a/Gems/Blast/Code/Source/Asset/BlastSliceAsset.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -namespace Blast -{ - void BlastSliceAsset::SetMeshIdList(const AZStd::vector& meshAssetIdList) - { - m_meshAssetIdList = meshAssetIdList; - } - - const AZStd::vector& BlastSliceAsset::GetMeshIdList() const - { - return m_meshAssetIdList; - } - - void BlastSliceAsset::SetMaterialId(const AZ::Data::AssetId& materialAssetId) - { - m_materialAssetId = materialAssetId; - } - - const AZ::Data::AssetId& BlastSliceAsset::GetMaterialId() const - { - return m_materialAssetId; - } - - void BlastSliceAsset::Reflect(AZ::ReflectContext* context) - { - if (auto serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(1) - ->Field("meshAssetIdList", &BlastSliceAsset::m_meshAssetIdList) - ->Field("materialAssetId", &BlastSliceAsset::m_materialAssetId); - } - - if (AZ::BehaviorContext* behavior = azrtti_cast(context)) - { - behavior->Class("BlastSliceAsset") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Module, "blast") - ->Method("SetMeshIdList", &BlastSliceAsset::SetMeshIdList) - ->Method("GetMeshIdList", &BlastSliceAsset::GetMeshIdList) - ->Method("SetMaterialId", &BlastSliceAsset::SetMaterialId) - ->Method("GetMaterialId", &BlastSliceAsset::GetMaterialId) - ->Method( - "GetAssetTypeId", - [](BlastSliceAsset*) - { - return azrtti_typeid(); - }); - } - } - -} // namespace Blast diff --git a/Gems/Blast/Code/Source/Asset/BlastSliceAsset.h b/Gems/Blast/Code/Source/Asset/BlastSliceAsset.h deleted file mode 100644 index cab51791cd..0000000000 --- a/Gems/Blast/Code/Source/Asset/BlastSliceAsset.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#include - -namespace Blast -{ - //! The product asset file from a .blast_slice file product asset file - class BlastSliceAsset final : public AZ::Data::AssetData - { - public: - AZ_RTTI(BlastSliceAsset, "{D04AAF07-EB12-4E50-8964-114A9B9C1FD1}", AZ::Data::AssetData); - AZ_CLASS_ALLOCATOR(BlastSliceAsset, AZ::SystemAllocator, 0); - - BlastSliceAsset() = default; - ~BlastSliceAsset() override = default; - - void SetMeshIdList(const AZStd::vector& meshAssetIdList); - const AZStd::vector& GetMeshIdList() const; - - void SetMaterialId(const AZ::Data::AssetId& materialAssetId); - const AZ::Data::AssetId& GetMaterialId() const; - - static void Reflect(AZ::ReflectContext* context); - - private: - AZStd::vector m_meshAssetIdList; - AZ::Data::AssetId m_materialAssetId; - }; -} // namespace Blast diff --git a/Gems/Blast/Code/Source/BlastModule.cpp b/Gems/Blast/Code/Source/BlastModule.cpp index cbb93a86f7..70b3285d1d 100644 --- a/Gems/Blast/Code/Source/BlastModule.cpp +++ b/Gems/Blast/Code/Source/BlastModule.cpp @@ -16,7 +16,6 @@ #ifdef BLAST_EDITOR #include #include -#include #include #endif @@ -40,8 +39,7 @@ namespace Blast #ifdef BLAST_EDITOR EditorSystemComponent::CreateDescriptor(), EditorBlastFamilyComponent::CreateDescriptor(), - EditorBlastMeshDataComponent::CreateDescriptor(), - BlastSliceAssetStorageComponent::CreateDescriptor(), + EditorBlastMeshDataComponent::CreateDescriptor() #endif }); } diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.cpp new file mode 100644 index 0000000000..d3ae8222b1 --- /dev/null +++ b/Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Blast +{ + // + // EditorBlastChunksAssetHandler + // + + EditorBlastChunksAssetHandler::~EditorBlastChunksAssetHandler() + { + Unregister(); + } + + AZ::Data::AssetPtr EditorBlastChunksAssetHandler::CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) + { + if (type != GetAssetType()) + { + AZ_Error("Blast", type == GetAssetType(), "Invalid asset type! We only handle 'BlastChunksAsset'"); + return {}; + } + + if (!CanHandleAsset(id)) + { + return nullptr; + } + + return aznew BlastChunksAsset; + } + + AZ::Data::AssetHandler::LoadResult EditorBlastChunksAssetHandler::LoadAssetData( + const AZ::Data::Asset& asset, + AZStd::shared_ptr stream, + [[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) + { + BlastChunksAsset* blastChunksAsset = asset.GetAs(); + AZ_Error("blast", blastChunksAsset, + "This should be a BlastChunksAsset type, as this is the only type we process!"); + if (!blastChunksAsset) + { + return LoadResult::Error; + } + + // get all products from the source scene asset + bool found = false; + AZStd::vector productsAssetInfo; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + found, + &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, + asset.Get()->GetId().m_guid, + productsAssetInfo); + + if (!found) + { + AZ_Error("blast", + found, + "Could not find asset models produced by source asset ID %s, verify the output product model assets.", + asset.Get()->GetId().m_guid.ToString().c_str()); + return LoadResult::Error; + } + + // find all model assets + AZStd::vector modelAssetIdList; + for (const AZ::Data::AssetInfo& assetInfo : productsAssetInfo) + { + if (azrtti_typeid() == assetInfo.m_assetType) + { + modelAssetIdList.push_back(assetInfo.m_assetId); + } + } + blastChunksAsset->SetModelAssetIds(modelAssetIdList); + + return LoadResult::LoadComplete; + } + + void EditorBlastChunksAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr) + { + delete ptr; + } + + void EditorBlastChunksAssetHandler::GetHandledAssetTypes(AZStd::vector& assetTypes) + { + assetTypes.push_back(azrtti_typeid()); + } + + void EditorBlastChunksAssetHandler::Register() + { + AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!"); + AZ::Data::AssetManager::Instance().RegisterHandler(this, azrtti_typeid()); + AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid()); + } + + void EditorBlastChunksAssetHandler::Unregister() + { + AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid()); + if (AZ::Data::AssetManager::IsReady()) + { + AZ::Data::AssetManager::Instance().UnregisterHandler(this); + } + } + + AZ::Data::AssetType EditorBlastChunksAssetHandler::GetAssetType() const + { + return azrtti_typeid(); + } + + const char* EditorBlastChunksAssetHandler::GetAssetTypeDisplayName() const + { + return "Blast Chunks Asset"; + } + + const char* EditorBlastChunksAssetHandler::GetGroup() const + { + return "Blast"; + } + + const char* EditorBlastChunksAssetHandler::GetBrowserIcon() const + { + return "Icons/Components/Box.png"; + } + + void EditorBlastChunksAssetHandler::GetAssetTypeExtensions(AZStd::vector& extensions) + { + extensions.push_back("blast_chunks"); + } + +} // namespace Blast diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.h b/Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.h new file mode 100644 index 0000000000..baeb26a1ff --- /dev/null +++ b/Gems/Blast/Code/Source/Editor/EditorBlastChunksAssetHandler.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Blast +{ + class EditorBlastChunksAssetHandler final + : public AZ::Data::AssetHandler + , public AZ::AssetTypeInfoBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(EditorBlastChunksAssetHandler, AZ::SystemAllocator, 0); + + ~EditorBlastChunksAssetHandler() override; + + // AZ::Data::AssetHandler + AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override; + LoadResult LoadAssetData( + const AZ::Data::Asset& asset, + AZStd::shared_ptr stream, + const AZ::Data::AssetFilterCB& assetLoadFilterCB) override; + void DestroyAsset(AZ::Data::AssetPtr ptr) override; + void GetHandledAssetTypes(AZStd::vector& assetTypes) override; + + // AZ::AssetTypeInfoBus::Handler + AZ::Data::AssetType GetAssetType() const override; + const char* GetAssetTypeDisplayName() const override; + const char* GetGroup() const override; + const char* GetBrowserIcon() const override; + void GetAssetTypeExtensions(AZStd::vector& extensions) override; + + void Register(); + void Unregister(); + }; +} // namespace Blast diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp index 3c29d1498e..27e57a569e 100644 --- a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp +++ b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.cpp @@ -45,10 +45,10 @@ namespace Blast if (AZ::SerializeContext* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(4) + ->Version(5) ->Field("Show Mesh Assets", &EditorBlastMeshDataComponent::m_showMeshAssets) ->Field("Mesh Assets", &EditorBlastMeshDataComponent::m_meshAssets) - ->Field("Blast Slice", &EditorBlastMeshDataComponent::m_blastSliceAsset); + ->Field("Blast Chunks", &EditorBlastMeshDataComponent::m_blastChunksAsset); if (AZ::EditContext* ec = serialize->GetEditContext()) { @@ -77,9 +77,9 @@ namespace Blast ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnMeshAssetsChanged) ->DataElement( - AZ::Edit::UIHandlers::Default, &EditorBlastMeshDataComponent::m_blastSliceAsset, "Blast Slice", - "Slice override to fill out meshes and material") - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnSliceAssetChanged); + AZ::Edit::UIHandlers::Default, &EditorBlastMeshDataComponent::m_blastChunksAsset, "Blast Chunks", + "Manifest override to fill out meshes and material") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnBlastChunksAssetChanged); } } } @@ -107,23 +107,27 @@ namespace Blast UnregisterModel(); } - void EditorBlastMeshDataComponent::OnSliceAssetChanged() + void EditorBlastMeshDataComponent::OnBlastChunksAssetChanged() { - if (!m_blastSliceAsset.GetId().IsValid()) + if (!m_blastChunksAsset.GetId().IsValid()) { return; } using namespace AZ::Data; + const AssetId blastAssetId = m_blastChunksAsset.GetId(); + m_blastChunksAsset = AssetManager::Instance().GetAsset(blastAssetId, AssetLoadBehavior::QueueLoad); + m_blastChunksAsset.BlockUntilLoadComplete(); - const AssetId blastAssetId = m_blastSliceAsset.GetId(); - m_blastSliceAsset = - AssetManager::Instance().GetAsset(blastAssetId, AssetLoadBehavior::QueueLoad); - m_blastSliceAsset.BlockUntilLoadComplete(); + if (!m_blastChunksAsset.Get() || m_blastChunksAsset.Get()->GetModelAssetIds().empty()) + { + AZ_Warning("blast", false, "Blast Chunk Asset does not contain any models.") + return; + } // load up the new mesh list m_meshAssets.clear(); - for (const auto& meshId : m_blastSliceAsset.Get()->GetMeshIdList()) + for (const auto& meshId : m_blastChunksAsset.Get()->GetModelAssetIds()) { auto meshAsset = AssetManager::Instance().GetAsset(meshId, AssetLoadBehavior::QueueLoad); if (meshAsset) @@ -135,8 +139,8 @@ namespace Blast UnregisterModel(); RegisterModel(); - AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( - &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree); + using namespace AzToolsFramework; + ToolsApplicationEvents::Bus::Broadcast(&ToolsApplicationEvents::InvalidatePropertyDisplay, Refresh_EntireTree); } void EditorBlastMeshDataComponent::OnMeshAssetsChanged() @@ -205,9 +209,9 @@ namespace Blast gameEntity->CreateComponent(m_meshAssets); } - const AZ::Data::Asset& EditorBlastMeshDataComponent::GetBlastSliceAsset() const + const AZ::Data::Asset& EditorBlastMeshDataComponent::GetBlastChunksAsset() const { - return m_blastSliceAsset; + return m_blastChunksAsset; } const AZStd::vector>& EditorBlastMeshDataComponent::GetMeshAssets() const diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.h b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.h index 81818d3bf7..aed5155be7 100644 --- a/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.h +++ b/Gems/Blast/Code/Source/Editor/EditorBlastMeshDataComponent.h @@ -7,7 +7,7 @@ */ #pragma once -#include +#include #include #include #include @@ -43,14 +43,14 @@ namespace Blast // EditorComponentBase void BuildGameEntity(AZ::Entity* gameEntity) override; - const AZ::Data::Asset& GetBlastSliceAsset() const; + const AZ::Data::Asset& GetBlastChunksAsset() const; const AZStd::vector>& GetMeshAssets() const; void OnMaterialsUpdated(const AZ::Render::MaterialAssignmentMap& materials) override; void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; private: - void OnSliceAssetChanged(); + void OnBlastChunksAssetChanged(); void OnMeshAssetsChanged(); AZ::Crc32 GetMeshAssetsVisibility() const; void OnMeshAssetsVisibilityChanged(); @@ -62,7 +62,7 @@ namespace Blast ////////////////////////////////////////////////////////////////////////// // Reflected data bool m_showMeshAssets = false; - AZ::Data::Asset m_blastSliceAsset; + AZ::Data::Asset m_blastChunksAsset; AZStd::vector> m_meshAssets; ////////////////////////////////////////////////////////////////////////// diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.cpp b/Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.cpp deleted file mode 100644 index 52df273254..0000000000 --- a/Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -namespace Blast -{ - // BlastSliceAssetStorageComponent - - void BlastSliceAssetStorageComponent::Reflect(AZ::ReflectContext* context) - { - using namespace AZ::Edit; - - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(2) - ->Field("Mesh Data", &BlastSliceAssetStorageComponent::m_meshAssetIdList) - ->Field("Mesh Path List", &BlastSliceAssetStorageComponent::m_meshAssetPathList); - - if (AZ::EditContext* ec = serialize->GetEditContext()) - { - ec->Class( - "Blast Slice Storage Component", "Used process blast slice data") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Category, "Physics") - ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Box.png") - ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Box.png") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->Attribute(AZ::Edit::Attributes::AddableByUser, false) - ->DataElement( - AZ::Edit::UIHandlers::Default, &BlastSliceAssetStorageComponent::m_meshAssetIdList, "Mesh Data", - "Slice data to fill out the mesh list") - ->DataElement( - AZ::Edit::UIHandlers::Default, &BlastSliceAssetStorageComponent::m_meshAssetPathList, - "Mesh Paths", "The mesh path list"); - } - } - - if (AZ::BehaviorContext* behavior = azrtti_cast(context)) - { - behavior->Class("BlastSliceAssetStorageComponent") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Module, "blast") - ->Method("GenerateAssetInfo", &BlastSliceAssetStorageComponent::GenerateAssetInfo) - ->Method("WriteMaterialFile", &BlastSliceAssetStorageComponent::WriteMaterialFile); - } - } - - bool BlastSliceAssetStorageComponent::GenerateAssetInfo( - const AZStd::vector& chunkNames, AZStd::string_view blastFilename, - AZStd::string_view assetinfoFilename) - { - AZ::SerializeContext* serializeContext = nullptr; - AZ::ComponentApplicationBus::BroadcastResult( - serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); - if (serializeContext == nullptr) - { - return false; - } - using namespace AZ::SceneAPI::Containers; - using namespace AZ::SceneAPI::SceneData; - - AZStd::string filename; - AZ::StringFunc::Path::Split(blastFilename.data(), nullptr, nullptr, &filename, nullptr); - - AZStd::any sceneManifestPointer(serializeContext->CreateAny(azrtti_typeid())); - SceneManifest* sceneManifest = AZStd::any_cast(&sceneManifestPointer); - - AZStd::vector meshGroupData; - meshGroupData.reserve(chunkNames.size()); - - AZStd::vector materialRuleData; - materialRuleData.reserve(chunkNames.size()); - - for (const AZStd::string& chunkName : chunkNames) - { - meshGroupData.emplace_back(serializeContext->CreateAny(azrtti_typeid())); - AZStd::any& meshGroupPointer = meshGroupData.back(); - MeshGroup* meshGroup = AZStd::any_cast(&meshGroupPointer); - - // make selection list - meshGroup->GetSceneNodeSelectionList().RemoveSelectedNode("RootNode"); - for (const AZStd::string& node : chunkNames) - { - meshGroup->GetSceneNodeSelectionList().RemoveSelectedNode( - AZStd::string::format("RootNode.%s", node.c_str())); - } - meshGroup->GetSceneNodeSelectionList().AddSelectedNode( - AZStd::string::format("RootNode.%s", chunkName.c_str())); - - // create a default material for the mesh group - materialRuleData.emplace_back(serializeContext->CreateAny(azrtti_typeid())); - AZStd::any& materialRulePointer = materialRuleData.back(); - MaterialRule* materialRule = AZStd::any_cast(&materialRulePointer); - - // override the deleter since the AZStd::any will clean up later on - AZStd::shared_ptr materialRuleEntry = AZStd::shared_ptr( - materialRule, - [](auto) - { - }); - meshGroup->GetRuleContainer().AddRule(materialRuleEntry); - - // construct the asset name for the chunk's mesh group - AZStd::string meshGroupName(filename); - meshGroupName.append("-"); - meshGroupName.append(chunkName); - // TODO: Uncomment lines below as part of SPEC-3542 - // meshGroup->OverrideId(AZ::Uuid::CreateName(meshGroupName.c_str())); - // meshGroup->SetName(AZStd::move(meshGroupName)); - - // override the deleter since the AZStd::any will clean up later on - AZStd::shared_ptr meshGroupEntry = AZStd::shared_ptr( - meshGroup, - [](auto) - { - }); - sceneManifest->AddEntry(AZStd::move(meshGroupEntry)); - } - - return sceneManifest->SaveToFile(assetinfoFilename.data()); - } - - bool BlastSliceAssetStorageComponent::WriteMaterialFile( - AZStd::string_view materialGroupName, const AZStd::vector& materialNames, - AZStd::string_view materialFilename) - { - AZ::GFxFramework::MaterialGroup group; - for (const auto& texture : materialNames) - { - auto mat = AZStd::make_shared(); - mat->SetName(texture); - mat->SetTexture(AZ::GFxFramework::TextureMapType::Diffuse, "EngineAssets/Textures/white.dds"); - group.AddMaterial(mat); - } - group.SetMtlName(materialGroupName); - return group.WriteMtlFile(materialFilename.data()); - } - - // - // EditorBlastSliceAssetHandler - // - - EditorBlastSliceAssetHandler::~EditorBlastSliceAssetHandler() - { - Unregister(); - } - - AZ::Data::AssetPtr EditorBlastSliceAssetHandler::CreateAsset( - const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) - { - if (type != GetAssetType()) - { - AZ_Error("Blast", type == GetAssetType(), "Invalid asset type! We only handle 'BlastAsset'"); - return {}; - } - - if (!CanHandleAsset(id)) - { - return nullptr; - } - - return aznew BlastSliceAsset; - } - - AZ::Data::AssetHandler::LoadResult EditorBlastSliceAssetHandler::LoadAssetData( - const AZ::Data::Asset& asset, AZStd::shared_ptr stream, - const AZ::Data::AssetFilterCB& assetLoadFilterCB) - { - BlastSliceAsset* blastSliceAssetData = asset.GetAs(); - AZ_Error( - "blast", blastSliceAssetData, - "This should be a BlastSliceAsset type, as this is the only type we process!"); - AZ::SerializeContext* serializeContext = nullptr; - AZ::ComponentApplicationBus::BroadcastResult( - serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); - if (blastSliceAssetData && serializeContext) - { - AZ::ObjectStream::FilterDescriptor filter(assetLoadFilterCB); - AZStd::unique_ptr baseEntity( - AZ::Utils::LoadObjectFromStream(*stream, serializeContext, filter)); - AZ_Error("Blast", baseEntity, "Could not load slice root entity {asset id}"); - if (!baseEntity) - { - return LoadResult::Error; - } - - auto&& sliceComponent = baseEntity->FindComponent(); - AZ_Error("Blast", sliceComponent, "blast_slice entity missing SliceComponent!"); - if (sliceComponent == nullptr) - { - return LoadResult::Error; - } - - AZStd::vector enityList; - sliceComponent->GetEntities(enityList); - for (auto&& entity : enityList) - { - // the base element type to store Blast mesh data is the BlastSliceAssetStorageComponent - auto&& blastSliceAssetStorage = entity->FindComponent(); - if (blastSliceAssetStorage) - { - if (blastSliceAssetStorage->GetMeshData().empty() == false) - { - blastSliceAssetData->SetMeshIdList(blastSliceAssetStorage->GetMeshData()); - return LoadResult::LoadComplete; - } - else if (blastSliceAssetStorage->GetMeshPathList().empty() == false) - { - AZStd::vector meshAssetIdList; - meshAssetIdList.reserve(blastSliceAssetStorage->GetMeshPathList().size()); - - for (auto&& assetPath : blastSliceAssetStorage->GetMeshPathList()) - { - AZ::Data::AssetId meshAssetId; - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - meshAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - assetPath.c_str(), AZ::Data::s_invalidAssetType, false); - - if (meshAssetId.IsValid()) - { - meshAssetIdList.emplace_back(meshAssetId); - } - } - blastSliceAssetData->SetMeshIdList(meshAssetIdList); - return LoadResult::LoadComplete; - } - } - - // back up logic to load blast data for the EditorBlastMeshDataComponent - auto&& meshDataComponent = entity->FindComponent(); - if (meshDataComponent) - { - auto&& innerBlastSliceAsset = meshDataComponent->GetBlastSliceAsset(); - if (innerBlastSliceAsset.IsReady()) - { - blastSliceAssetData->SetMeshIdList(innerBlastSliceAsset.Get()->GetMeshIdList()); - blastSliceAssetData->SetMaterialId(innerBlastSliceAsset.Get()->GetMaterialId()); - return LoadResult::LoadComplete; - } - else - { - auto&& meshDataList = meshDataComponent->GetMeshAssets(); - AZStd::vector meshAssetIdList; - meshAssetIdList.reserve(meshDataList.size()); - for (auto&& meshData : meshDataList) - { - AZ::RPI::ModelAsset* meshAsset = meshData.Get(); - if (meshAsset) - { - meshAssetIdList.push_back(meshAsset->GetId()); - } - } - blastSliceAssetData->SetMeshIdList(meshAssetIdList); - return LoadResult::LoadComplete; - } - } - } - AZ_Error( - "Blast", false, "blast_slice assetId:%s missing EditorBlastMeshDataComponent!", - asset->GetId().ToString().c_str()); - } - return LoadResult::Error; - } - - void EditorBlastSliceAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr) - { - delete ptr; - } - - void EditorBlastSliceAssetHandler::GetHandledAssetTypes(AZStd::vector& assetTypes) - { - assetTypes.push_back(azrtti_typeid()); - } - - void EditorBlastSliceAssetHandler::Register() - { - AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!"); - AZ::Data::AssetManager::Instance().RegisterHandler(this, azrtti_typeid()); - AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid()); - } - - void EditorBlastSliceAssetHandler::Unregister() - { - AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid()); - if (AZ::Data::AssetManager::IsReady()) - { - AZ::Data::AssetManager::Instance().UnregisterHandler(this); - } - } - - AZ::Data::AssetType EditorBlastSliceAssetHandler::GetAssetType() const - { - return azrtti_typeid(); - } - - const char* EditorBlastSliceAssetHandler::GetAssetTypeDisplayName() const - { - return "Blast Slice Asset"; - } - - const char* EditorBlastSliceAssetHandler::GetGroup() const - { - return "Blast"; - } - - const char* EditorBlastSliceAssetHandler::GetBrowserIcon() const - { - return "Icons/Components/Box.png"; - } - - void EditorBlastSliceAssetHandler::GetAssetTypeExtensions(AZStd::vector& extensions) - { - extensions.push_back("blast_slice"); - } - -} // namespace Blast diff --git a/Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.h b/Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.h deleted file mode 100644 index f33290f7f8..0000000000 --- a/Gems/Blast/Code/Source/Editor/EditorBlastSliceAssetHandler.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Blast -{ - //! Used to create store asset references (i.e. ids) to fill out the EditorBlastMeshDataComponent - class BlastSliceAssetStorageComponent final : public AzToolsFramework::Components::EditorComponentBase - { - public: - AZ_COMPONENT( - BlastSliceAssetStorageComponent, "{696C7E62-1EA4-41E2-B4F6-7BD0D30888DC}", - AzToolsFramework::Components::EditorComponentBase); - - ~BlastSliceAssetStorageComponent() override = default; - - static void Reflect(AZ::ReflectContext* context); - - const AZStd::vector& GetMeshData() const - { - return m_meshAssetIdList; - } - - void SetMeshData(const AZStd::vector& meshAssetIdList) - { - m_meshAssetIdList = meshAssetIdList; - } - - const AZStd::vector& GetMeshPathList() const - { - return m_meshAssetPathList; - } - - void SetMeshPathList(const AZStd::vector& meshAssetPathList) - { - m_meshAssetPathList = meshAssetPathList; - } - - private: - // AZ::Component interface implementation - void Activate() override {} - void Deactivate() override {} - - // EditorComponentBase - void BuildGameEntity([[maybe_unused]] AZ::Entity* gameEntity) override {} - - // Script API - bool GenerateAssetInfo( - const AZStd::vector& chunkNames, - AZStd::string_view blastFilename, - AZStd::string_view assetinfoFilename); - - bool WriteMaterialFile( - AZStd::string_view materialGroupName, - const AZStd::vector& materialNames, - AZStd::string_view materialFilename); - - AZStd::vector m_meshAssetIdList; - AZStd::vector m_meshAssetPathList; - }; - - class EditorBlastSliceAssetHandler final - : public AZ::Data::AssetHandler - , public AZ::AssetTypeInfoBus::Handler - { - public: - AZ_CLASS_ALLOCATOR(EditorBlastSliceAssetHandler, AZ::SystemAllocator, 0); - - ~EditorBlastSliceAssetHandler() override; - - // AZ::Data::AssetHandler - AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override; - LoadResult LoadAssetData( - const AZ::Data::Asset& asset, AZStd::shared_ptr stream, - const AZ::Data::AssetFilterCB& assetLoadFilterCB) override; - void DestroyAsset(AZ::Data::AssetPtr ptr) override; - void GetHandledAssetTypes(AZStd::vector& assetTypes) override; - - // AZ::AssetTypeInfoBus::Handler - AZ::Data::AssetType GetAssetType() const override; - const char* GetAssetTypeDisplayName() const override; - const char* GetGroup() const override; - const char* GetBrowserIcon() const override; - void GetAssetTypeExtensions(AZStd::vector& extensions) override; - - void Register(); - void Unregister(); - }; -} // namespace Blast diff --git a/Gems/Blast/Code/Source/Editor/EditorSystemComponent.cpp b/Gems/Blast/Code/Source/Editor/EditorSystemComponent.cpp index d8d703e51f..dc1cb0fc98 100644 --- a/Gems/Blast/Code/Source/Editor/EditorSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Editor/EditorSystemComponent.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include #include @@ -16,7 +16,7 @@ namespace Blast { void EditorSystemComponent::Reflect(AZ::ReflectContext* context) { - BlastSliceAsset::Reflect(context); + BlastChunksAsset::Reflect(context); if (auto serializeContext = azrtti_cast(context)) { @@ -26,14 +26,14 @@ namespace Blast void EditorSystemComponent::Activate() { - m_editorBlastSliceAssetHandler = AZStd::make_unique(); - m_editorBlastSliceAssetHandler->Register(); + m_editorBlastChunksAssetHandler = AZStd::make_unique(); + m_editorBlastChunksAssetHandler->Register(); auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); if (assetCatalog) { - assetCatalog->EnableCatalogForAsset(azrtti_typeid()); - assetCatalog->AddExtension("blast_slice"); + assetCatalog->EnableCatalogForAsset(azrtti_typeid()); + assetCatalog->AddExtension("blast_chunks"); } AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); @@ -46,7 +46,7 @@ namespace Blast void EditorSystemComponent::Deactivate() { AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); - m_editorBlastSliceAssetHandler.reset(); + m_editorBlastChunksAssetHandler.reset(); } // This will be called when the IEditor instance is ready diff --git a/Gems/Blast/Code/Source/Editor/EditorSystemComponent.h b/Gems/Blast/Code/Source/Editor/EditorSystemComponent.h index 737a7d968d..31daae1a18 100644 --- a/Gems/Blast/Code/Source/Editor/EditorSystemComponent.h +++ b/Gems/Blast/Code/Source/Editor/EditorSystemComponent.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include namespace Blast { @@ -39,7 +39,7 @@ namespace Blast required.push_back(AZ_CRC("BlastService", 0x75beae2d)); } - AZStd::unique_ptr m_editorBlastSliceAssetHandler; + AZStd::unique_ptr m_editorBlastChunksAssetHandler; // AZ::Component void Activate() override; diff --git a/Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp b/Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp new file mode 100644 index 0000000000..9f48cae4da --- /dev/null +++ b/Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#include +#include +#include + +#include +#include +#include + +#include + +namespace UnitTest +{ + MockComponentApplication::MockComponentApplication() + { + AZ::ComponentApplicationBus::Handler::BusConnect(); + AZ::Interface::Register(this); + } + + MockComponentApplication::~MockComponentApplication() + { + AZ::Interface::Unregister(this); + AZ::ComponentApplicationBus::Handler::BusDisconnect(); + } + + class MockAssetCatalogRequestBusHandler final + : public AZ::Data::AssetCatalogRequestBus::Handler + { + public: + MockAssetCatalogRequestBusHandler() + { + AZ::Data::AssetCatalogRequestBus::Handler::BusConnect(); + } + + virtual ~MockAssetCatalogRequestBusHandler() + { + AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect(); + } + + MOCK_METHOD3(GetAssetIdByPath, AZ::Data::AssetId(const char*, const AZ::Data::AssetType&, bool)); + MOCK_METHOD1(GetAssetInfoById, AZ::Data::AssetInfo(const AZ::Data::AssetId&)); + MOCK_METHOD1(AddAssetType, void(const AZ::Data::AssetType&)); + MOCK_METHOD1(AddDeltaCatalog, bool(AZStd::shared_ptr)); + MOCK_METHOD1(AddExtension, void(const char*)); + MOCK_METHOD0(ClearCatalog, void()); + MOCK_METHOD5(CreateBundleManifest, bool(const AZStd::string&, const AZStd::vector&, const AZStd::string&, int, const AZStd::vector&)); + MOCK_METHOD2(CreateDeltaCatalog, bool(const AZStd::vector&, const AZStd::string&)); + MOCK_METHOD0(DisableCatalog, void()); + MOCK_METHOD1(EnableCatalogForAsset, void(const AZ::Data::AssetType&)); + MOCK_METHOD3(EnumerateAssets, void(BeginAssetEnumerationCB, AssetEnumerationCB, EndAssetEnumerationCB)); + MOCK_METHOD1(GenerateAssetIdTEMP, AZ::Data::AssetId(const char*)); + MOCK_METHOD1(GetAllProductDependencies, AZ::Outcome, AZStd::string>(const AZ::Data::AssetId&)); + MOCK_METHOD3(GetAllProductDependenciesFilter, AZ::Outcome, AZStd::string>(const AZ::Data::AssetId&, const AZStd::unordered_set&, const AZStd::vector&)); + MOCK_METHOD1(GetAssetPathById, AZStd::string(const AZ::Data::AssetId&)); + MOCK_METHOD1(GetDirectProductDependencies, AZ::Outcome, AZStd::string>(const AZ::Data::AssetId&)); + MOCK_METHOD1(GetHandledAssetTypes, void(AZStd::vector&)); + MOCK_METHOD0(GetRegisteredAssetPaths, AZStd::vector()); + MOCK_METHOD2(InsertDeltaCatalog, bool(AZStd::shared_ptr, size_t)); + MOCK_METHOD2(InsertDeltaCatalogBefore, bool(AZStd::shared_ptr, AZStd::shared_ptr)); + MOCK_METHOD1(LoadCatalog, bool(const char*)); + MOCK_METHOD2(RegisterAsset, void(const AZ::Data::AssetId&, AZ::Data::AssetInfo&)); + MOCK_METHOD1(RemoveDeltaCatalog, bool(AZStd::shared_ptr)); + MOCK_METHOD1(SaveCatalog, bool(const char*)); + MOCK_METHOD0(StartMonitoringAssets, void()); + MOCK_METHOD0(StopMonitoringAssets, void()); + MOCK_METHOD1(UnregisterAsset, void(const AZ::Data::AssetId&)); + }; + + class MockAssetManager + : public AZ::Data::AssetManager + { + public: + MockAssetManager(const AZ::Data::AssetManager::Descriptor& desc) : + AssetManager(desc) + { + } + }; + + class EditorBlastChunkAssetHandlerTestFixture + : public AllocatorsTestFixture + { + public: + AZStd::unique_ptr m_mockComponentApplicationBusHandler; + AZStd::unique_ptr m_mockAssetCatalogRequestBusHandler; + AZStd::unique_ptr m_mockAssetManager; + AZStd::unique_ptr m_serializeContext; + + void SetUpChunkComponents() + { + m_serializeContext = AZStd::make_unique(); + + AZ::Entity::Reflect(m_serializeContext.get()); + AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get()); + } + + void TearDownChunkComponents() + { + m_serializeContext.reset(); + } + + void SetUp() override final + { + AllocatorsTestFixture::SetUp(); + AZ::AllocatorInstance::Create(); + AZ::AllocatorInstance::Create(); + + m_mockComponentApplicationBusHandler = AZStd::make_unique(); + m_mockAssetCatalogRequestBusHandler = AZStd::make_unique(); + m_mockAssetManager = AZStd::make_unique(AZ::Data::AssetManager::Descriptor{}); + + AZ::Data::AssetManager::SetInstance(m_mockAssetManager.get()); + } + + void TearDown() override final + { + m_mockAssetManager.release(); + AZ::Data::AssetManager::Destroy(); + + m_mockAssetCatalogRequestBusHandler.reset(); + m_mockComponentApplicationBusHandler.reset(); + + AZ::AllocatorInstance::Destroy(); + AZ::AllocatorInstance::Destroy(); + AllocatorsTestFixture::TearDown(); + } + + void SaveChunkAssetToStream(AZ::Entity* chunkAssetEntity, AZStd::vector& buffer) + { + buffer.clear(); + AZ::IO::ByteContainerStream> stream(&buffer); + AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&stream, *m_serializeContext.get(), AZ::ObjectStream::ST_XML); + objStream->WriteClass(chunkAssetEntity); + EXPECT_TRUE(objStream->Finalize()); + } + }; + + TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetManager_Registered) + { + Blast::EditorBlastChunksAssetHandler handler; + handler.Register(); + EXPECT_NE(nullptr, AZ::Data::AssetManager::Instance().GetHandler(azrtti_typeid())); + handler.Unregister(); + } + + TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetTypeInfoBus_Responds) + { + auto assetId = azrtti_typeid(); + + Blast::EditorBlastChunksAssetHandler handler; + handler.Register(); + + AZ::Data::AssetType assetType = AZ::Uuid::CreateNull(); + AZ::AssetTypeInfoBus::EventResult(assetType, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetType); + EXPECT_NE(AZ::Uuid::CreateNull(), assetType); + + const char* displayName = nullptr; + AZ::AssetTypeInfoBus::EventResult(displayName, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeDisplayName); + EXPECT_STREQ("Blast Chunks Asset", displayName); + + const char* group = nullptr; + AZ::AssetTypeInfoBus::EventResult(group, assetId, &AZ::AssetTypeInfoBus::Events::GetGroup); + EXPECT_STREQ("Blast", group); + + const char* icon = nullptr; + AZ::AssetTypeInfoBus::EventResult(icon, assetId, &AZ::AssetTypeInfoBus::Events::GetBrowserIcon); + EXPECT_STREQ("Icons/Components/Box.png", icon); + + AZStd::vector extensions; + AZ::AssetTypeInfoBus::Event(assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeExtensions, extensions); + ASSERT_EQ(1, extensions.size()); + ASSERT_EQ("blast_chunks", extensions[0]); + + handler.Unregister(); + } + + TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetHandler_Ready) + { + auto assetType = azrtti_typeid(); + auto&& assetManager = AZ::Data::AssetManager::Instance(); + + Blast::EditorBlastChunksAssetHandler handler; + handler.Register(); + EXPECT_EQ(&handler, assetManager.GetHandler(assetType)); + + // create and release an instance of the BlastChunkAsset asset type + { + using ::testing::Return; + using ::testing::_; + + EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_)) + .Times(2) + .WillRepeatedly(Return(AZ::Data::AssetInfo{})); + + auto assetPtr = assetManager.CreateAsset(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0)); + EXPECT_NE(nullptr, assetPtr.Get()); + EXPECT_EQ(azrtti_typeid(), assetPtr.GetType()); + } + + handler.Unregister(); + } + +} diff --git a/Gems/Blast/Code/Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp b/Gems/Blast/Code/Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp deleted file mode 100644 index 3df22d081f..0000000000 --- a/Gems/Blast/Code/Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include - -#include - -#include -#include -#include - -namespace UnitTest -{ - class MockComponentApplicationBusHandler final - //: public MockComponentApplication - : public AZ::ComponentApplicationBus::Handler - { - public: - MockComponentApplicationBusHandler() - { - AZ::ComponentApplicationBus::Handler::BusConnect(); - } - - virtual ~MockComponentApplicationBusHandler() - { - AZ::ComponentApplicationBus::Handler::BusDisconnect(); - } - - MOCK_METHOD0(Destroy, void()); - MOCK_METHOD1(RegisterComponentDescriptor, void(const AZ::ComponentDescriptor*)); - MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*)); - MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*)); - MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&)); - MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&)); - MOCK_METHOD1(AddEntity, bool(AZ::Entity*)); - MOCK_METHOD1(FindEntity, AZ::Entity*(const AZ::EntityId&)); - MOCK_METHOD1(EnumerateEntities, void(const ComponentApplicationRequests::EntityCallback&)); - MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ()); - MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); - MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); - MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); - MOCK_METHOD0(GetAppRoot, const char* ()); - MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); - MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ()); - MOCK_METHOD0(GetTickDeltaTime, float()); - MOCK_METHOD1(Tick, void(float)); - MOCK_METHOD0(TickSystem, void()); - MOCK_CONST_METHOD0(GetRequiredSystemComponents, AZ::ComponentTypeList()); - MOCK_METHOD1(ResolveModulePath, void(AZ::OSString&)); - MOCK_METHOD0(CreateSerializeContext, void()); - MOCK_METHOD0(DestroySerializeContext, void()); - MOCK_METHOD0(CreateBehaviorContext, void()); - MOCK_METHOD0(DestroyBehaviorContext, void()); - MOCK_METHOD0(RegisterCoreComponents, void()); - MOCK_METHOD1(AddSystemComponents, void(AZ::Entity*)); - MOCK_METHOD0(ReflectSerialize, void()); - MOCK_METHOD1(Reflect, void(AZ::ReflectContext*)); - MOCK_CONST_METHOD0(GetBinFolder, const char* ()); - }; - - class MockAssetCatalogRequestBusHandler final - : public AZ::Data::AssetCatalogRequestBus::Handler - { - public: - MockAssetCatalogRequestBusHandler() - { - AZ::Data::AssetCatalogRequestBus::Handler::BusConnect(); - } - - virtual ~MockAssetCatalogRequestBusHandler() - { - AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect(); - } - - MOCK_METHOD3(GetAssetIdByPath, AZ::Data::AssetId(const char*, const AZ::Data::AssetType&, bool)); - MOCK_METHOD1(GetAssetInfoById, AZ::Data::AssetInfo(const AZ::Data::AssetId&)); - MOCK_METHOD1(AddAssetType, void(const AZ::Data::AssetType&)); - MOCK_METHOD1(AddDeltaCatalog, bool(AZStd::shared_ptr)); - MOCK_METHOD1(AddExtension, void(const char*)); - MOCK_METHOD0(ClearCatalog, void()); - MOCK_METHOD5(CreateBundleManifest, bool(const AZStd::string&, const AZStd::vector&, const AZStd::string&, int, const AZStd::vector&)); - MOCK_METHOD2(CreateDeltaCatalog, bool(const AZStd::vector&, const AZStd::string&)); - MOCK_METHOD0(DisableCatalog, void()); - MOCK_METHOD1(EnableCatalogForAsset, void(const AZ::Data::AssetType&)); - MOCK_METHOD3(EnumerateAssets, void(BeginAssetEnumerationCB, AssetEnumerationCB, EndAssetEnumerationCB)); - MOCK_METHOD1(GenerateAssetIdTEMP, AZ::Data::AssetId(const char*)); - MOCK_METHOD1(GetAllProductDependencies, AZ::Outcome, AZStd::string>(const AZ::Data::AssetId&)); - MOCK_METHOD3(GetAllProductDependenciesFilter, AZ::Outcome, AZStd::string>(const AZ::Data::AssetId&, const AZStd::unordered_set&, const AZStd::vector&)); - MOCK_METHOD1(GetAssetPathById, AZStd::string(const AZ::Data::AssetId&)); - MOCK_METHOD1(GetDirectProductDependencies, AZ::Outcome, AZStd::string>(const AZ::Data::AssetId&)); - MOCK_METHOD1(GetHandledAssetTypes, void(AZStd::vector&)); - MOCK_METHOD0(GetRegisteredAssetPaths, AZStd::vector()); - MOCK_METHOD2(InsertDeltaCatalog, bool(AZStd::shared_ptr, size_t)); - MOCK_METHOD2(InsertDeltaCatalogBefore, bool(AZStd::shared_ptr, AZStd::shared_ptr)); - MOCK_METHOD1(LoadCatalog, bool(const char*)); - MOCK_METHOD2(RegisterAsset, void(const AZ::Data::AssetId&, AZ::Data::AssetInfo&)); - MOCK_METHOD1(RemoveDeltaCatalog, bool(AZStd::shared_ptr)); - MOCK_METHOD1(SaveCatalog, bool(const char*)); - MOCK_METHOD0(StartMonitoringAssets, void()); - MOCK_METHOD0(StopMonitoringAssets, void()); - MOCK_METHOD1(UnregisterAsset, void(const AZ::Data::AssetId&)); - }; - - class MockAssetManager - : public AZ::Data::AssetManager - { - public: - MockAssetManager(const AZ::Data::AssetManager::Descriptor& desc) : - AssetManager(desc) - { - } - }; - - class EditorBlastSliceAssetHandlerTestFixture - : public AllocatorsTestFixture - { - public: - AZStd::unique_ptr m_mockComponentApplicationBusHandler; - //AZStd::unique_ptr m_mockComponentApplicationBusHandler; - AZStd::unique_ptr m_mockAssetCatalogRequestBusHandler; - AZStd::unique_ptr m_mockAssetManager; - AZStd::unique_ptr m_serializeContext; - const AZ::ComponentDescriptor* m_sliceComponentDescriptor = nullptr; - - void SetUpSliceComponents() - { - m_serializeContext = AZStd::make_unique(); - - AZ::Entity::Reflect(m_serializeContext.get()); - Blast::BlastSliceAssetStorageComponent::Reflect(m_serializeContext.get()); - AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get()); - - m_sliceComponentDescriptor = AZ::SliceComponent::CreateDescriptor(); - m_sliceComponentDescriptor->Reflect(m_serializeContext.get()); - } - - void TearDownSliceComponents() - { - delete m_sliceComponentDescriptor; - m_serializeContext.reset(); - } - - void SetUp() override final - { - AllocatorsTestFixture::SetUp(); - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - - m_mockComponentApplicationBusHandler = AZStd::make_unique(); - m_mockAssetCatalogRequestBusHandler = AZStd::make_unique(); - m_mockAssetManager = AZStd::make_unique(AZ::Data::AssetManager::Descriptor{}); - - AZ::Data::AssetManager::SetInstance(m_mockAssetManager.get()); - } - - void TearDown() override final - { - AZ::Data::AssetManager::SetInstance(nullptr); - - m_mockAssetManager.reset(); - m_mockAssetCatalogRequestBusHandler.reset(); - m_mockComponentApplicationBusHandler.reset(); - - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - AllocatorsTestFixture::TearDown(); - } - - void SaveSliceAssetToStream(AZ::Entity* sliceAssetEntity, AZStd::vector& buffer) - { - buffer.clear(); - AZ::IO::ByteContainerStream> stream(&buffer); - AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&stream, *m_serializeContext.get(), AZ::ObjectStream::ST_XML); - objStream->WriteClass(sliceAssetEntity); - EXPECT_TRUE(objStream->Finalize()); - } - }; - - TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetManager_Registered) - { - Blast::EditorBlastSliceAssetHandler handler; - handler.Register(); - EXPECT_NE(nullptr, AZ::Data::AssetManager::Instance().GetHandler(azrtti_typeid())); - handler.Unregister(); - } - - TEST_F(EditorBlastSliceAssetHandlerTestFixture, BlastSliceAssetStorageComponent_Behavior_Registered) - { - AZ::BehaviorContext behaviorContext; - Blast::BlastSliceAssetStorageComponent::Reflect(&behaviorContext); - - auto classEntry = behaviorContext.m_classes.find("BlastSliceAssetStorageComponent"); - EXPECT_NE(behaviorContext.m_classes.end(), classEntry); - AZ::BehaviorClass* behaviorClass = classEntry->second; - auto methodEntry = behaviorClass->m_methods.find("GenerateAssetInfo"); - EXPECT_NE(behaviorClass->m_methods.end(), methodEntry); - AZ::BehaviorMethod* behaviorMethod = methodEntry->second; - EXPECT_EQ(4, behaviorMethod->GetNumArguments()); - EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid()); - EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid>()); - EXPECT_EQ(behaviorMethod->GetArgument(2)->m_typeId, azrtti_typeid()); - EXPECT_EQ(behaviorMethod->GetArgument(3)->m_typeId, azrtti_typeid()); - } - - TEST_F(EditorBlastSliceAssetHandlerTestFixture, BlastSliceAsset_Behavior_Registered) - { - AZ::BehaviorContext behaviorContext; - Blast::BlastSliceAsset::Reflect(&behaviorContext); - - auto classEntry = behaviorContext.m_classes.find("BlastSliceAsset"); - EXPECT_NE(behaviorContext.m_classes.end(), classEntry); - AZ::BehaviorClass* behaviorClass = classEntry->second; - - auto setMeshIdListEntry = behaviorClass->m_methods.find("SetMeshIdList"); - EXPECT_NE(behaviorClass->m_methods.end(), setMeshIdListEntry); - { - AZ::BehaviorMethod* behaviorMethod = setMeshIdListEntry->second; - EXPECT_EQ(2, behaviorMethod->GetNumArguments()); - EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid()); - EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid>()); - } - - auto getMeshIdListEntry = behaviorClass->m_methods.find("GetMeshIdList"); - EXPECT_NE(behaviorClass->m_methods.end(), getMeshIdListEntry); - { - AZ::BehaviorMethod* behaviorMethod = getMeshIdListEntry->second; - EXPECT_EQ(1, behaviorMethod->GetNumArguments()); - EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid()); - EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid>()); - } - - auto setMaterialIdEntry = behaviorClass->m_methods.find("SetMaterialId"); - EXPECT_NE(behaviorClass->m_methods.end(), setMaterialIdEntry); - { - AZ::BehaviorMethod* behaviorMethod = setMaterialIdEntry->second; - EXPECT_EQ(2, behaviorMethod->GetNumArguments()); - EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid()); - EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid()); - } - - auto getMaterialIdEntry = behaviorClass->m_methods.find("GetMaterialId"); - EXPECT_NE(behaviorClass->m_methods.end(), getMaterialIdEntry); - { - AZ::BehaviorMethod* behaviorMethod = getMaterialIdEntry->second; - EXPECT_EQ(1, behaviorMethod->GetNumArguments()); - EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid()); - EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid()); - } - - auto getAssetTypeIdEntry = behaviorClass->m_methods.find("GetAssetTypeId"); - EXPECT_NE(behaviorClass->m_methods.end(), getAssetTypeIdEntry); - { - AZ::BehaviorMethod* behaviorMethod = getAssetTypeIdEntry->second; - EXPECT_EQ(1, behaviorMethod->GetNumArguments()); - EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid()); - EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid()); - } - } - - TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetTypeInfoBus_Responds) - { - auto assetId = azrtti_typeid(); - - Blast::EditorBlastSliceAssetHandler handler; - handler.Register(); - - AZ::Data::AssetType assetType = AZ::Uuid::CreateNull(); - AZ::AssetTypeInfoBus::EventResult(assetType, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetType); - EXPECT_NE(AZ::Uuid::CreateNull(), assetType); - - const char* displayName = nullptr; - AZ::AssetTypeInfoBus::EventResult(displayName, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeDisplayName); - EXPECT_STREQ("Blast Slice Asset", displayName); - - const char* group = nullptr; - AZ::AssetTypeInfoBus::EventResult(group, assetId, &AZ::AssetTypeInfoBus::Events::GetGroup); - EXPECT_STREQ("Blast", group); - - const char* icon = nullptr; - AZ::AssetTypeInfoBus::EventResult(icon, assetId, &AZ::AssetTypeInfoBus::Events::GetBrowserIcon); - EXPECT_STREQ("Editor/Icons/Components/Box.png", icon); - - AZStd::vector extensions; - AZ::AssetTypeInfoBus::Event(assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeExtensions, extensions); - ASSERT_EQ(1, extensions.size()); - ASSERT_EQ("blast_slice", extensions[0]); - - handler.Unregister(); - } - - TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetHandler_Ready) - { - auto assetType = azrtti_typeid(); - auto&& assetManager = AZ::Data::AssetManager::Instance(); - - Blast::EditorBlastSliceAssetHandler handler; - handler.Register(); - EXPECT_EQ(&handler, assetManager.GetHandler(assetType)); - - // create and release an instance of the BlastSliceAsset asset type - { - using ::testing::Return; - using ::testing::_; - - EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_)) - .Times(1) - .WillRepeatedly(Return(AZ::Data::AssetInfo{})); - - auto assetPtr = assetManager.CreateAsset(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0)); - EXPECT_NE(nullptr, assetPtr.Get()); - EXPECT_EQ(azrtti_typeid(), assetPtr.GetType()); - } - - handler.Unregister(); - } - - TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetHandler_LoadsAssetData) - { - SetUpSliceComponents(); - - AZStd::vector meshAssetPathList = { "/foo/path/thing.cgf", "/foo/path/that.cgf" }; - AZ::Entity* storageEntity = aznew AZ::Entity(); - auto* blastStorage = storageEntity->CreateComponent(); - blastStorage->SetMeshPathList(meshAssetPathList); - - AZ::Entity sliceEntity; - AZ::SliceComponent* slice = sliceEntity.CreateComponent(); - slice->AddEntity(storageEntity); - - AZStd::vector buffer; - SaveSliceAssetToStream(&sliceEntity, buffer); - - // Load a slice with the BlastSliceAssetStorageComponent - Blast::EditorBlastSliceAssetHandler handler; - handler.Register(); - { - using ::testing::Return; - using ::testing::_; - - EXPECT_CALL(*m_mockComponentApplicationBusHandler, GetSerializeContext) - .Times(1) - .WillOnce(Return(m_serializeContext.get())); - - EXPECT_CALL(*m_mockComponentApplicationBusHandler, FindEntity(_)) - .Times(1) - .WillOnce(Return(&sliceEntity)); - - EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetIdByPath(_,_,_)) - .Times(2) - .WillRepeatedly(Return(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0))); - - EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_)) - .Times(2) - .WillRepeatedly(Return(AZ::Data::AssetInfo{})); - - auto&& assetManager = AZ::Data::AssetManager::Instance(); - auto assetPtr = assetManager.CreateAsset(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0)); - - AZ::IO::ByteContainerStream> stream(&buffer); - stream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN); - - const AZ::Data::AssetFilterCB assetLoadFilterCB{}; - bool loaded = handler.LoadAssetData(assetPtr, &stream, assetLoadFilterCB); - EXPECT_TRUE(loaded); - } - handler.Unregister(); - - TearDownSliceComponents(); - } -} diff --git a/Gems/Blast/Code/blast_editor_files.cmake b/Gems/Blast/Code/blast_editor_files.cmake index 7d417176a2..dc991fb8a9 100644 --- a/Gems/Blast/Code/blast_editor_files.cmake +++ b/Gems/Blast/Code/blast_editor_files.cmake @@ -11,8 +11,8 @@ set(FILES Source/Editor/EditorBlastFamilyComponent.cpp Source/Editor/EditorBlastMeshDataComponent.cpp Source/Editor/EditorBlastMeshDataComponent.h - Source/Editor/EditorBlastSliceAssetHandler.h - Source/Editor/EditorBlastSliceAssetHandler.cpp + Source/Editor/EditorBlastChunksAssetHandler.h + Source/Editor/EditorBlastChunksAssetHandler.cpp Source/Editor/EditorSystemComponent.h Source/Editor/EditorSystemComponent.cpp Editor/ConfigurationWidget.h diff --git a/Gems/Blast/Code/blast_editor_tests_files.cmake b/Gems/Blast/Code/blast_editor_tests_files.cmake index 4e2a63d75c..7076530312 100644 --- a/Gems/Blast/Code/blast_editor_tests_files.cmake +++ b/Gems/Blast/Code/blast_editor_tests_files.cmake @@ -7,6 +7,6 @@ # set(FILES - # Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp + Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp Tests/Editor/EditorTestMain.cpp ) diff --git a/Gems/Blast/Code/blast_files.cmake b/Gems/Blast/Code/blast_files.cmake index 1707ec46a0..530d9cf7ca 100644 --- a/Gems/Blast/Code/blast_files.cmake +++ b/Gems/Blast/Code/blast_files.cmake @@ -26,8 +26,8 @@ set(FILES Source/Asset/BlastAsset.cpp Source/Asset/BlastAssetHandler.h Source/Asset/BlastAssetHandler.cpp - Source/Asset/BlastSliceAsset.h - Source/Asset/BlastSliceAsset.cpp + Source/Asset/BlastChunksAsset.h + Source/Asset/BlastChunksAsset.cpp Source/Components/BlastFamilyComponent.h Source/Components/BlastFamilyComponent.cpp Source/Components/BlastFamilyComponentNotificationBusHandler.h diff --git a/Gems/Blast/Editor/Scripts/asset_builder_blast.py b/Gems/Blast/Editor/Scripts/asset_builder_blast.py deleted file mode 100755 index beb455e335..0000000000 --- a/Gems/Blast/Editor/Scripts/asset_builder_blast.py +++ /dev/null @@ -1,323 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" -def install_user_site(): - import os - import sys - import azlmbr.paths - executableBinFolder = azlmbr.paths.executableFolder - - # the PyAssImp module checks the Windows PATH for the assimp DLL file - if os.name == "nt": - os.environ['PATH'] = os.environ['PATH'] + os.pathsep + executableBinFolder - - # PyAssImp module needs to find the shared library for assimp to load; "posix" handles Mac and Linux - if os.name == "posix": - if 'LD_LIBRARY_PATH' in os.environ: - os.environ['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] + os.pathsep + executableBinFolder - else: - os.environ['LD_LIBRARY_PATH'] = executableBinFolder - - # add the user site packages folder to find the pyassimp egg link - import site - for item in sys.path: - if (item.find('site-packages') != -1): - site.addsitedir(item) - -install_user_site() -import pyassimp - -import azlmbr.asset -import azlmbr.asset.builder -import azlmbr.asset.entity -import azlmbr.blast -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity -import azlmbr.math -import os -import traceback -import binascii -import sys - -# the UUID must be unique amongst all the asset builders in Python or otherwise -# a collision of builders will happen preventing one from running -busIdString = '{CF5C74D1-9ED4-4851-85B1-9B15090DBEC7}' -busId = azlmbr.math.Uuid_CreateString(busIdString, 0) -handler = None -jobKeyName = 'Blast Chunk Assets' -sceneManifestType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0) -dccMaterialType = azlmbr.math.Uuid_CreateString('{C88469CF-21E7-41EB-96FD-BF14FBB05EDC}', 0) - - -def log_exception_traceback(): - exc_type, exc_value, exc_tb = sys.exc_info() - data = traceback.format_exception(exc_type, exc_value, exc_tb) - print(str(data)) - - -def get_source_fbx_filename(request): - fullPath = os.path.join(request.watchFolder, request.sourceFile) - basePath, filePart = os.path.split(fullPath) - filename = os.path.splitext(filePart)[0] + '.fbx' - filename = os.path.join(basePath, filename) - return filename - - -def raise_error(message): - raise RuntimeError(f'[ERROR]: {message}') - - -def generate_asset_info(chunkNames, request): - import azlmbr.blast - - # write out an object stream with the extension of .fbx.assetinfo.generated - basePath, sceneFile = os.path.split(request.sourceFile) - assetinfoFilename = os.path.splitext(sceneFile)[0] + '.fbx.assetinfo.generated' - assetinfoFilename = os.path.join(basePath, assetinfoFilename) - assetinfoFilename = assetinfoFilename.replace('\\', '/').lower() - outputFilename = os.path.join(request.tempDirPath, assetinfoFilename) - - storage = azlmbr.blast.BlastSliceAssetStorageComponent() - if (storage.GenerateAssetInfo(chunkNames, request.sourceFile, outputFilename)): - product = azlmbr.asset.builder.JobProduct(assetinfoFilename, sceneManifestType, 1) - product.dependenciesHandled = True - return product - raise_error('Failed to generate assetinfo.generated') - - -def export_fbx_manifest(request): - output = [] - fbxFilename = get_source_fbx_filename(request) - sceneAsset = pyassimp.load(fbxFilename) - with sceneAsset as scene: - rootNode = scene.mRootNode.contents - for index in range(0, rootNode.mNumChildren): - child = rootNode.mChildren[index] - childNode = child.contents - childNodeName = bytes.decode(childNode.mName.data) - output.append(str(childNodeName)) - return output - - -def convert_to_asset_paths(fbxFilename, gameRoot, chunkNameList): - realtivePath = fbxFilename[len(gameRoot) + 1:] - realtivePath = os.path.splitext(realtivePath)[0] - output = [] - for chunk in chunkNameList: - assetPath = realtivePath + '-' + chunk + '.cgf' - assetPath = assetPath.replace('\\', '/') - assetPath = assetPath.lower() - output.append(assetPath) - return output - - -# creates a single job to compile for each platform -def create_jobs(request): - fbxSidecarFilename = get_source_fbx_filename(request) - if (os.path.exists(fbxSidecarFilename) is False): - print('[WARN] Sidecar FBX file {} is missing for blast file {}'.format(fbxSidecarFilename, request.sourceFile)) - return azlmbr.asset.builder.CreateJobsResponse() - - # see if the FBX file already has a .assetinfo source asset, if so then do not create a job - if (os.path.exists(f'{fbxSidecarFilename}.assetinfo')): - response = azlmbr.asset.builder.CreateJobsResponse() - response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess - return response - - # create job descriptor for each platform - jobDescriptorList = [] - for platformInfo in request.enabledPlatforms: - jobDesc = azlmbr.asset.builder.JobDescriptor() - jobDesc.jobKey = jobKeyName - jobDesc.priority = 12 # higher than the 'Scene compilation' or 'fbx' - jobDesc.set_platform_identifier(platformInfo.identifier) - jobDescriptorList.append(jobDesc) - - response = azlmbr.asset.builder.CreateJobsResponse() - response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess - response.createJobOutputs = jobDescriptorList - return response - -# handler to create jobs for a source asset - - -def on_create_jobs(args): - try: - request = args[0] - return create_jobs(request) - except: - log_exception_traceback() - return azlmbr.asset.builder.CreateJobsResponse() - - -def generate_blast_slice_asset(chunkNameList, request): - # get list of relative chunk paths - fbxFilename = get_source_fbx_filename(request) - assetPaths = convert_to_asset_paths(fbxFilename, request.watchFolder, chunkNameList) - - outcome = azlmbr.asset.entity.PythonBuilderRequestBus(bus.Broadcast, 'CreateEditorEntity', 'BlastData') - if (outcome.IsSuccess() is False): - raise_error('could not create an editor entity') - blastDataEntityId = outcome.GetValue() - - # create a component for the editor entity - gameType = azlmbr.entity.EntityType().Game - blastMeshDataTypeIdList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Blast Slice Storage Component"], gameType) - componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', blastDataEntityId, blastMeshDataTypeIdList[0]) - if (componentOutcome.IsSuccess() is False): - raise_error('failed to add component (Blast Slice Storage Component) to the blast_slice') - - # build the blast slice using the chunk asset paths - blastMeshComponentId = componentOutcome.GetValue()[0] - outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', blastMeshComponentId) - if(outcome.IsSuccess() is False): - raise_error(f'failed to create Property Tree Editor for component ({blastMeshComponentId})') - pte = outcome.GetValue() - pte.set_visible_enforcement(True) - pte.set_value('Mesh Paths', assetPaths) - - # write out an object stream with the extension of .blast_slice - basePath, sceneFile = os.path.split(request.sourceFile) - blastFilename = os.path.splitext(sceneFile)[0] + '.blast_slice' - blastFilename = os.path.join(basePath, blastFilename) - blastFilename = blastFilename.replace('\\', '/').lower() - tempFilename = os.path.join(request.tempDirPath, blastFilename) - entityList = [blastDataEntityId] - makeDynamic = False - outcome = azlmbr.asset.entity.PythonBuilderRequestBus(bus.Broadcast, 'WriteSliceFile', tempFilename, entityList, makeDynamic) - if (outcome.IsSuccess() is False): - raise_error(f'WriteSliceFile failed for blast_slice file ({blastFilename})') - - # return a job product - blastSliceAsset = azlmbr.blast.BlastSliceAsset() - subId = binascii.crc32(blastFilename.encode('utf8')) - product = azlmbr.asset.builder.JobProduct(blastFilename, blastSliceAsset.GetAssetTypeId(), subId) - product.dependenciesHandled = True - return product - - -def read_in_string(data, dataLength): - stringData = '' - for idx in range(4, dataLength - 1): - char = bytes.decode(data[idx]) - if (str.isascii(char)): - stringData += char - return stringData - - -def import_material_info(fbxFilename): - _, group_name = os.path.split(fbxFilename) - group_name = os.path.splitext(group_name)[0] - output = {} - output['group_name'] = group_name - output['material_name_list'] = [] - sceneAsset = pyassimp.load(fbxFilename) - with sceneAsset as scene: - for materialIndex in range(0, scene.mNumMaterials): - material = scene.mMaterials[materialIndex].contents - for materialPropertyIdx in range(0, material.mNumProperties): - materialProperty = material.mProperties[materialPropertyIdx].contents - materialPropertyName = bytes.decode(materialProperty.mKey.data) - if (materialPropertyName.endswith('mat.name') and materialProperty.mType is 3): - stringData = read_in_string(materialProperty.mData, materialProperty.mDataLength) - output['material_name_list'].append(stringData) - return output - - -def write_material_file(sourceFile, destFolder): - # preserve source MTL files - rootPath, materialSourceFile = os.path.split(sourceFile) - materialSourceFile = os.path.splitext(materialSourceFile)[0] + '.mtl' - materialSourceFile = os.path.join(rootPath, materialSourceFile) - if (os.path.exists(materialSourceFile)): - print(f'{materialSourceFile} source already exists') - return None - - # auto-generate a DCC material file - info = import_material_info(sourceFile) - materialGroupName = info['group_name'] - materialNames = info['material_name_list'] - materialFilename = materialGroupName + '.dccmtl.generated' - subId = binascii.crc32(materialFilename.encode('utf8')) - materialFilename = os.path.join(destFolder, materialFilename) - storage = azlmbr.blast.BlastSliceAssetStorageComponent() - storage.WriteMaterialFile(materialGroupName, materialNames, materialFilename) - product = azlmbr.asset.builder.JobProduct(materialFilename, dccMaterialType, subId) - product.dependenciesHandled = True - return product - - -def process_fbx_file(request): - # fill out response object - response = azlmbr.asset.builder.ProcessJobResponse() - productOutputs = [] - - # write out DCCMTL file as a product (if needed) - materialProduct = write_material_file(get_source_fbx_filename(request), request.tempDirPath) - if (materialProduct is not None): - productOutputs.append(materialProduct) - - # prepare output folder - basePath, _ = os.path.split(request.sourceFile) - outputPath = os.path.join(request.tempDirPath, basePath) - os.makedirs(outputPath) - - # parse FBX for chunk names - chunkNameList = export_fbx_manifest(request) - - # create assetinfo generated (is product) - productOutputs.append(generate_asset_info(chunkNameList, request)) - - # write out the blast_slice object stream - productOutputs.append(generate_blast_slice_asset(chunkNameList, request)) - - response.outputProducts = productOutputs - response.resultCode = azlmbr.asset.builder.ProcessJobResponse_Success - response.dependenciesHandled = True - return response - - -# using the incoming 'request' find the type of job via 'jobKey' to determine what to do -def on_process_job(args): - try: - request = args[0] - if (request.jobDescription.jobKey.startswith(jobKeyName)): - return process_fbx_file(request) - - return azlmbr.asset.builder.ProcessJobResponse() - except: - log_exception_traceback() - return azlmbr.asset.builder.ProcessJobResponse() - -# register asset builder -def register_asset_builder(): - assetPattern = azlmbr.asset.builder.AssetBuilderPattern() - assetPattern.pattern = '*.blast' - assetPattern.type = azlmbr.asset.builder.AssetBuilderPattern_Wildcard - - builderDescriptor = azlmbr.asset.builder.AssetBuilderDesc() - builderDescriptor.name = "Blast Gem" - builderDescriptor.patterns = [assetPattern] - builderDescriptor.busId = busId - builderDescriptor.version = 5 - - outcome = azlmbr.asset.builder.PythonAssetBuilderRequestBus(azlmbr.bus.Broadcast, 'RegisterAssetBuilder', builderDescriptor) - if outcome.IsSuccess(): - # created the asset builder to hook into the notification bus - handler = azlmbr.asset.builder.PythonBuilderNotificationBusHandler() - handler.connect(busId) - handler.add_callback('OnCreateJobsRequest', on_create_jobs) - handler.add_callback('OnProcessJobRequest', on_process_job) - return handler - - -# create the asset builder handler -try: - handler = register_asset_builder() -except: - handler = None - log_exception_traceback() diff --git a/Gems/Blast/Editor/Scripts/blast_asset_builder.py b/Gems/Blast/Editor/Scripts/blast_asset_builder.py new file mode 100644 index 0000000000..06dc15f5c1 --- /dev/null +++ b/Gems/Blast/Editor/Scripts/blast_asset_builder.py @@ -0,0 +1,290 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +""" +This a Python Asset Builder script examines each .blast file to see if an +associated .fbx file needs to be processed by exporting all of its chunks +into a scene manifest + +This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene +manifest that writes out asset chunk data for .blast files +""" +import os, traceback, binascii, sys, json, pathlib +import azlmbr.math +import azlmbr.asset +import azlmbr.asset.entity +import azlmbr.asset.builder +import azlmbr.bus + +# +# Python Asset Builder +# +busId = azlmbr.math.Uuid_CreateString('{D4FA20E3-8EF4-44A3-A045-AAE6C1CCAAAB}', 0) +jobKeyName = 'Blast Chunk Assets' + +def log_exception_traceback(): + exc_type, exc_value, exc_tb = sys.exc_info() + data = traceback.format_exception(exc_type, exc_value, exc_tb) + print(str(data)) + +def raise_error(message): + print (f'ERROR - {message}'); + raise RuntimeError(f'[ERROR]: {message}'); + +# creates a single job to compile for each platform +def get_source_fbx_filename(request): + fullPath = os.path.join(request.watchFolder, request.sourceFile) + basePath, filePart = os.path.split(fullPath) + filename = os.path.splitext(filePart)[0] + '.fbx' + filename = os.path.join(basePath, filename) + return filename + +def create_jobs(request): + fbxSidecarFilename = get_source_fbx_filename(request) + if (os.path.exists(fbxSidecarFilename) is False): + print('[WARN] Sidecar FBX file {} is missing for blast file {}'.format(fbxSidecarFilename, request.sourceFile)) + return azlmbr.asset.builder.CreateJobsResponse() + + # see if the FBX file already has a .assetinfo source asset, if so then do not create a job + establishedAssetInfo = f'{fbxSidecarFilename}.assetinfo'; + if (os.path.exists(establishedAssetInfo)): + response = azlmbr.asset.builder.CreateJobsResponse() + response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess + return response + + # create job descriptor for each platform + jobDescriptorList = [] + for platformInfo in request.enabledPlatforms: + sourceFileDependency = azlmbr.asset.builder.SourceFileDependency() + sourceFileDependency.sourceFileDependencyPath = fbxSidecarFilename + + jobDependency = azlmbr.asset.builder.JobDependency() + jobDependency.sourceFile = sourceFileDependency + jobDependency.jobKey = jobKeyName + jobDependency.platformIdentifier = platformInfo.identifier + + jobDesc = azlmbr.asset.builder.JobDescriptor() + jobDesc.jobKey = jobKeyName + jobDesc.set_platform_identifier(platformInfo.identifier) + jobDesc.jobDependencyList = [jobDependency] + jobDescriptorList.append(jobDesc) + + response = azlmbr.asset.builder.CreateJobsResponse() + response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess + response.createJobOutputs = jobDescriptorList + return response + +# to create jobs for a source asset +def on_create_jobs(args): + try: + request = args[0] + return create_jobs(request) + except: + log_exception_traceback() + return azlmbr.asset.builder.CreateJobsResponse() + +def generate_assetinfo_product(request): + # write out a product asset file with the extension of .fbx.assetinfo.generated + basePath, sceneFile = os.path.split(request.sourceFile) + assetinfoFilename = os.path.splitext(sceneFile)[0] + '.fbx.assetinfo.generated' + assetinfoFilename = os.path.join(basePath, assetinfoFilename) + assetinfoFilename = assetinfoFilename.replace('\\', '/').lower() + outputFilename = os.path.join(request.tempDirPath, assetinfoFilename) + + # the only rule in it is to run this file again as a scene processor + currentScript = pathlib.Path(__file__).resolve() + aDict = {"values": [{"$type": "ScriptProcessorRule", "scriptFilename": f"{currentScript}"}]} + jsonString = json.dumps(aDict) + jsonFile = open(outputFilename, "w") + jsonFile.write(jsonString) + jsonFile.close() + + # return a job product for the generated assetinfo file + sceneManifestType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0) + subId = 1 + product = azlmbr.asset.builder.JobProduct(outputFilename, sceneManifestType, subId) + product.dependenciesHandled = True + return product + +def process_fbx_file(request): + # fill out response object + response = azlmbr.asset.builder.ProcessJobResponse() + productOutputs = [] + + # prepare output folder + basePath, _ = os.path.split(request.sourceFile) + outputPath = os.path.join(request.tempDirPath, basePath) + os.makedirs(outputPath) + + # create assetinfo generated file + productOutputs.append(generate_assetinfo_product(request)) + + response.outputProducts = productOutputs + response.resultCode = azlmbr.asset.builder.ProcessJobResponse_Success + response.dependenciesHandled = True + return response + +# using the incoming 'request' find the type of job via 'jobKey' to determine what to do +def on_process_job(args): + try: + request = args[0] + if (request.jobDescription.jobKey.startswith(jobKeyName)): + return process_fbx_file(request) + + return azlmbr.asset.builder.ProcessJobResponse() + except: + log_exception_traceback() + return azlmbr.asset.builder.ProcessJobResponse() + +# register asset builder +def register_asset_builder(): + assetPattern = azlmbr.asset.builder.AssetBuilderPattern() + assetPattern.pattern = '*.blast' + assetPattern.type = azlmbr.asset.builder.AssetBuilderPattern_Wildcard + + builderDescriptor = azlmbr.asset.builder.AssetBuilderDesc() + builderDescriptor.name = "Blast Scene Builder" + builderDescriptor.patterns = [assetPattern] + builderDescriptor.busId = busId + builderDescriptor.version = 1 + + outcome = azlmbr.asset.builder.PythonAssetBuilderRequestBus(azlmbr.bus.Broadcast, 'RegisterAssetBuilder', builderDescriptor) + if outcome.IsSuccess(): + # created the asset builder to hook into the notification bus + handler = azlmbr.asset.builder.PythonBuilderNotificationBusHandler() + handler.connect(busId) + handler.add_callback('OnCreateJobsRequest', on_create_jobs) + handler.add_callback('OnProcessJobRequest', on_process_job) + return handler + +# create the asset builder handler +pythonAssetBuilderHandler = None +try: + if (pythonAssetBuilderHandler == None): + pythonAssetBuilderHandler = register_asset_builder() +except: + pythonAssetBuilderHandler = None + +# +# SceneAPI Processor +# +blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) + +def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): + import azlmbr.scene + import azlmbr.object + import azlmbr.paths + import json, os + + jsonFilename = os.path.basename(scene.sourceFilename) + jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks') + + # prepare output folder + basePath, _ = os.path.split(jsonFilename) + outputPath = os.path.join(outputDirectory, basePath) + if not os.path.exists(outputPath): + os.makedirs(outputPath, False) + + # write out a JSON file with the chunk file info + with open(jsonFilename, "w") as jsonFile: + jsonFile.write(scene.manifest.ExportToJson()) + + exportProduct = azlmbr.scene.ExportProduct() + exportProduct.filename = jsonFilename + exportProduct.sourceId = scene.sourceGuid + exportProduct.assetType = blastChunksAssetType + exportProduct.subId = 101 + + exportProductList = azlmbr.scene.ExportProductList() + exportProductList.AddProduct(exportProduct) + return exportProductList + +def on_prepare_for_export(args): + try: + scene = args[0] # azlmbr.scene.Scene + outputDirectory = args[1] # string + platformIdentifier = args[2] # string + productList = args[3] # azlmbr.scene.ExportProductList + return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList) + except: + log_exception_traceback() + +def get_mesh_node_names(sceneGraph): + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + meshDataList = [] + node = sceneGraph.get_root() + children = [] + + while node.IsValid(): + # store children to process after siblings + if sceneGraph.has_node_child(node): + children.append(sceneGraph.get_node_child(node)) + + # store any node that has mesh data content + nodeContent = sceneGraph.get_node_content(node) + if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): + if sceneGraph.is_node_end_point(node) is False: + nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) + nodePath = nodeName.get_path() + if (len(nodeName.get_path())): + meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) + + # advance to next node + if sceneGraph.has_node_sibling(node): + node = sceneGraph.get_node_sibling(node) + elif children: + node = children.pop() + else: + node = azlmbr.scene.graph.NodeIndex() + + return meshDataList + +def update_manifest(scene): + import uuid, os + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + graph = sceneData.SceneGraph(scene.graph) + meshNameList = get_mesh_node_names(graph) + sceneManifest = sceneData.SceneManifest() + sourceFilenameOnly = os.path.basename(scene.sourceFilename) + sourceFilenameOnly = sourceFilenameOnly.replace('.','_') + + for activeMeshIndex in range(len(meshNameList)): + chunkName = meshNameList[activeMeshIndex] + chunkPath = chunkName.get_path() + meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) + meshGroup = sceneManifest.add_mesh_group(meshGroupName) + meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' + sceneManifest.mesh_group_select_node(meshGroup, chunkPath) + + return sceneManifest.export() + +sceneJobHandler = None + +def on_update_manifest(args): + try: + scene = args[0] + return update_manifest(scene) + except: + global sceneJobHandler + sceneJobHandler = None + log_exception_traceback() + +# try to create SceneAPI handler for processing +try: + import azlmbr.scene as sceneApi + if (sceneJobHandler == None): + sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() + sceneJobHandler.connect() + sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) + sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export) +except: + sceneJobHandler = None diff --git a/Gems/Blast/Editor/Scripts/bootstrap.py b/Gems/Blast/Editor/Scripts/bootstrap.py index d9687bb85b..93004d474f 100755 --- a/Gems/Blast/Editor/Scripts/bootstrap.py +++ b/Gems/Blast/Editor/Scripts/bootstrap.py @@ -4,6 +4,13 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ - -# LYN-652 to re-enable once the Blast gem tests are stable -# import asset_builder_blast +try: + import azlmbr.asset + import azlmbr.asset.entity + import azlmbr.asset.builder + import blast_asset_builder +except: + # this script only runs in an asset processing environment + # like the AssetProcessor or an AssetBuilder + # plus the Blast gem needs to be enabled for the project + pass From 7393c86416e8c84bff35bdd074d1b7ead99fc9ba Mon Sep 17 00:00:00 2001 From: hultonha Date: Tue, 3 Aug 2021 15:24:54 +0100 Subject: [PATCH 127/157] some formatting and naming changes after PR feedback Signed-off-by: hultonha --- .../Viewport/ModularViewportCameraController.h | 18 +++++++++--------- .../ModularViewportCameraController.cpp | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index 79219f50b0..d8778a9b9d 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -38,8 +38,8 @@ namespace AtomToolsFramework void SetupCameraProperies(AzFramework::CameraProps& cameraProps); private: - CameraListBuilder - m_cameraListBuilder; //!< Builder to generate a list of CameraInputs to run in the ModularViewportCameraControllerInstance. + //! Builder to generate a list of CameraInputs to run in the ModularViewportCameraControllerInstance. + CameraListBuilder m_cameraListBuilder; CameraPropsBuilder m_cameraPropsBuilder; //!< Builder to define custom camera properties to use for things such as rotate and //!< translate interpolation. }; @@ -77,10 +77,10 @@ namespace AtomToolsFramework //! Encapsulates an animation (interpolation) between two transforms. struct CameraAnimation { - AZ::Transform m_transformStart = - AZ::Transform::CreateIdentity(); //!< The transform of the camera at the start of the animation. + //! The transform of the camera at the start of the animation. + AZ::Transform m_transformStart = AZ::Transform::CreateIdentity(); AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity(); //!< The transform of the camera at the end of the animation. - float m_animationT = 0.0f; //!< The interpolation amount between the start and end transforms (in the range 0.0-1.0). + float m_time = 0.0f; //!< The interpolation amount between the start and end transforms (in the range 0.0 - 1.0). }; AzFramework::Camera m_camera; //!< The current camera state (pitch/yaw/position/look-distance). @@ -92,9 +92,9 @@ namespace AtomToolsFramework CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in. AZStd::optional m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished. //!< Will be cleared when the view changes (camera looks away). - bool m_updatingTransformInternally = - false; //!< Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally). - AZ::RPI::ViewportContext::MatrixChangedEvent::Handler - m_cameraViewMatrixChangeHandler; //!< Listen for camera view changes outside of the camera controller. + //! Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally). + bool m_updatingTransformInternally = false; + //! Listen for camera view changes outside of the camera controller. + AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index ce4c6021af..cc87ba1e46 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -181,12 +181,12 @@ namespace AtomToolsFramework return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); }; - const auto& [transformStart, transformEnd, animationT] = m_cameraAnimation; + const auto& [transformStart, transformEnd, animationTime] = m_cameraAnimation; - const float transitionT = smootherStepFn(animationT); + const float transitionTime = smootherStepFn(animationTime); const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation( - transformStart.GetRotation().Slerp(transformEnd.GetRotation(), transitionT), - transformStart.GetTranslation().Lerp(transformEnd.GetTranslation(), transitionT)); + transformStart.GetRotation().Slerp(transformEnd.GetRotation(), transitionTime), + transformStart.GetTranslation().Lerp(transformEnd.GetTranslation(), transitionTime)); const AZ::Vector3 eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(current)); m_camera.m_pitch = eulerAngles.GetX(); @@ -194,12 +194,12 @@ namespace AtomToolsFramework m_camera.m_lookAt = current.GetTranslation(); m_targetCamera = m_camera; - if (animationT >= 1.0f) + if (animationTime >= 1.0f) { m_cameraMode = CameraMode::Control; } - m_cameraAnimation.m_animationT = AZ::GetClamp(animationT + event.m_deltaTime.count(), 0.0f, 1.0f); + m_cameraAnimation.m_time = AZ::GetClamp(animationTime + event.m_deltaTime.count(), 0.0f, 1.0f); viewportContext->SetCameraTransform(current); } From 6520c347e4c49a18a410d39414662d64964af59d Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Tue, 3 Aug 2021 08:00:39 -0700 Subject: [PATCH 128/157] Disabling a flaky test (#2749) ContainerFilterTest_ContainersWithAndWithoutFiltering_Success Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index 156719b8a7..e25c3dbcf7 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -1150,7 +1150,7 @@ namespace UnitTest #if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) #else - TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) + TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) #endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); From 00470acc1cf25636a8569d9af00b91eddd63922a Mon Sep 17 00:00:00 2001 From: puvvadar Date: Tue, 3 Aug 2021 09:36:39 -0700 Subject: [PATCH 129/157] Add const to timeout enabled getter Signed-off-by: puvvadar --- .../AzNetworking/AzNetworking/Framework/INetworkInterface.h | 2 +- .../AzNetworking/TcpTransport/TcpNetworkInterface.cpp | 2 +- .../AzNetworking/TcpTransport/TcpNetworkInterface.h | 2 +- .../AzNetworking/UdpTransport/UdpNetworkInterface.cpp | 2 +- .../AzNetworking/UdpTransport/UdpNetworkInterface.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h index f2ad1c03c3..09aa62f7d7 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h @@ -109,7 +109,7 @@ namespace AzNetworking //! Whether this connection interface will disconnect by virtue of a time out (does not account for cvars affecting all connections) //! @return boolean true if this connection will not disconnect on timeout (does not account for cvars affecting all connections) - virtual bool IsTimeoutEnabled() = 0; + virtual bool IsTimeoutEnabled() const = 0; //! Const access to the metrics tracked by this network interface. //! @return const reference to the metrics tracked by this network interface diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp index 52c696b663..62335a9b39 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp @@ -179,7 +179,7 @@ namespace AzNetworking m_timeoutEnabled = timeoutEnabled; } - bool TcpNetworkInterface::IsTimeoutEnabled() + bool TcpNetworkInterface::IsTimeoutEnabled() const { return m_timeoutEnabled; } diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h index 3eb792bc7f..b9ea88974d 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h @@ -100,7 +100,7 @@ namespace AzNetworking bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; void SetTimeoutEnabled(bool timeoutEnabled) override; - bool IsTimeoutEnabled() override; + bool IsTimeoutEnabled() const override; //! @} //! Queues a new incoming connection for this network interface. diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp index a80cb82d03..48b3ad57e1 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp @@ -402,7 +402,7 @@ namespace AzNetworking m_timeoutEnabled = timeoutEnabled; } - bool UdpNetworkInterface::IsTimeoutEnabled() + bool UdpNetworkInterface::IsTimeoutEnabled() const { return m_timeoutEnabled; } diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h index 0260491295..949914da91 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h @@ -105,7 +105,7 @@ namespace AzNetworking bool StopListening() override; bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override; void SetTimeoutEnabled(bool timeoutEnabled) override; - bool IsTimeoutEnabled() override; + bool IsTimeoutEnabled() const override; //! @} //! Returns true if this is an encrypted socket, false if not. From 3a689aa31929001e6d6df360519ff3fc7e34ce2b Mon Sep 17 00:00:00 2001 From: michabr <82236305+michabr@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:14:09 -0700 Subject: [PATCH 130/157] Reenable support for UI Elements that use Render Targets (#2352) * Re-add support for UI Elements that use Render Targets * Move LyShine pass request from Atom's MainPipeline.pass to project's * Make all dynamic draw contexts in LyShine draw to pass directly without the need of draw list tags * Remove local RPI changes that are no longer needed * Prevent crash if LyShine gem is enabled but its custom pass hasn't been added to the main render pipeline * Revert to default UI pass if the LyShine pass has not been added to project's main render pipeline Signed-off-by: abrmich --- AutomatedTesting/Passes/MainPipeline.pass | 483 ++++++++++++++++++ .../Atom/Feature/Common/Assets/Passes/UI.pass | 8 +- .../Code/Source/RPI.Public/PipelineState.cpp | 2 +- .../AtomBridge/Assets/Shaders/LyShineUI.azsl | 15 +- .../Shaders/LyShineUI.shadervariantlist | 22 +- Gems/LyShine/Assets/Passes/LyShineParent.pass | 22 + .../Passes/LyShinePassTemplates.azasset | 13 + Gems/LyShine/Code/CMakeLists.txt | 3 + Gems/LyShine/Code/Editor/EditorWindow.cpp | 14 + Gems/LyShine/Code/Editor/EditorWindow.h | 3 + Gems/LyShine/Code/Editor/ViewportWidget.cpp | 147 ++++-- Gems/LyShine/Code/Editor/ViewportWidget.h | 22 +- Gems/LyShine/Code/Source/Draw2d.cpp | 18 +- Gems/LyShine/Code/Source/LyShine.cpp | 26 +- Gems/LyShine/Code/Source/LyShine.h | 12 + Gems/LyShine/Code/Source/LyShinePass.cpp | 274 ++++++++++ Gems/LyShine/Code/Source/LyShinePass.h | 110 ++++ Gems/LyShine/Code/Source/LyShinePassDataBus.h | 61 +++ .../Code/Source/LyShineSystemComponent.cpp | 27 +- .../Code/Source/LyShineSystemComponent.h | 13 + Gems/LyShine/Code/Source/RenderGraph.cpp | 330 ++++++------ Gems/LyShine/Code/Source/RenderGraph.h | 64 ++- Gems/LyShine/Code/Source/RenderToTextureBus.h | 22 + .../LyShine/Code/Source/UiCanvasComponent.cpp | 87 +++- Gems/LyShine/Code/Source/UiCanvasComponent.h | 20 + Gems/LyShine/Code/Source/UiCanvasManager.cpp | 18 +- Gems/LyShine/Code/Source/UiCanvasManager.h | 4 + Gems/LyShine/Code/Source/UiFaderComponent.cpp | 123 ++--- Gems/LyShine/Code/Source/UiFaderComponent.h | 8 +- Gems/LyShine/Code/Source/UiMaskComponent.cpp | 174 +++---- Gems/LyShine/Code/Source/UiMaskComponent.h | 8 +- Gems/LyShine/Code/Source/UiRenderer.cpp | 139 +++-- Gems/LyShine/Code/Source/UiRenderer.h | 26 +- .../Code/Tests/UiTooltipComponentTest.cpp | 30 +- Gems/LyShine/Code/lyshine_static_files.cmake | 4 + Gems/LyShine/LyShineScript/LyShinePass.data | 20 + .../LyShineScript/PatchRenderPipeline.py | 71 +++ 37 files changed, 1951 insertions(+), 492 deletions(-) create mode 100644 AutomatedTesting/Passes/MainPipeline.pass create mode 100644 Gems/LyShine/Assets/Passes/LyShineParent.pass create mode 100644 Gems/LyShine/Assets/Passes/LyShinePassTemplates.azasset create mode 100644 Gems/LyShine/Code/Source/LyShinePass.cpp create mode 100644 Gems/LyShine/Code/Source/LyShinePass.h create mode 100644 Gems/LyShine/Code/Source/LyShinePassDataBus.h create mode 100644 Gems/LyShine/Code/Source/RenderToTextureBus.h create mode 100644 Gems/LyShine/LyShineScript/LyShinePass.data create mode 100644 Gems/LyShine/LyShineScript/PatchRenderPipeline.py diff --git a/AutomatedTesting/Passes/MainPipeline.pass b/AutomatedTesting/Passes/MainPipeline.pass new file mode 100644 index 0000000000..aa9f3757c4 --- /dev/null +++ b/AutomatedTesting/Passes/MainPipeline.pass @@ -0,0 +1,483 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "MainPipeline", + "PassClass": "ParentPass", + "Slots": [ + { + "Name": "SwapChainOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "RenderTarget" + } + ], + "PassRequests": [ + { + "Name": "MorphTargetPass", + "TemplateName": "MorphTargetPassTemplate" + }, + { + "Name": "SkinningPass", + "TemplateName": "SkinningPassTemplate", + "Connections": [ + { + "LocalSlot": "SkinnedMeshOutputStream", + "AttachmentRef": { + "Pass": "MorphTargetPass", + "Attachment": "MorphTargetDeltaOutput" + } + } + ] + }, + { + "Name": "RayTracingAccelerationStructurePass", + "TemplateName": "RayTracingAccelerationStructurePassTemplate" + }, + { + "Name": "DiffuseProbeGridUpdatePass", + "TemplateName": "DiffuseProbeGridUpdatePassTemplate", + "ExecuteAfter": [ + "RayTracingAccelerationStructurePass" + ] + }, + { + "Name": "DepthPrePass", + "TemplateName": "DepthMSAAParentTemplate", + "Connections": [ + { + "LocalSlot": "SkinnedMeshes", + "AttachmentRef": { + "Pass": "SkinningPass", + "Attachment": "SkinnedMeshOutputStream" + } + }, + { + "LocalSlot": "SwapChainOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "SwapChainOutput" + } + } + ] + }, + { + "Name": "MotionVectorPass", + "TemplateName": "MotionVectorParentTemplate", + "Connections": [ + { + "LocalSlot": "SkinnedMeshes", + "AttachmentRef": { + "Pass": "SkinningPass", + "Attachment": "SkinnedMeshOutputStream" + } + }, + { + "LocalSlot": "Depth", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + }, + { + "LocalSlot": "SwapChainOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "SwapChainOutput" + } + } + ] + }, + { + "Name": "LightCullingPass", + "TemplateName": "LightCullingParentTemplate", + "Connections": [ + { + "LocalSlot": "SkinnedMeshes", + "AttachmentRef": { + "Pass": "SkinningPass", + "Attachment": "SkinnedMeshOutputStream" + } + }, + { + "LocalSlot": "DepthMSAA", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "DepthMSAA" + } + }, + { + "LocalSlot": "SwapChainOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "SwapChainOutput" + } + } + ] + }, + { + "Name": "ShadowPass", + "TemplateName": "ShadowParentTemplate", + "Connections": [ + { + "LocalSlot": "SkinnedMeshes", + "AttachmentRef": { + "Pass": "SkinningPass", + "Attachment": "SkinnedMeshOutputStream" + } + }, + { + "LocalSlot": "SwapChainOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "SwapChainOutput" + } + } + ] + }, + { + "Name": "OpaquePass", + "TemplateName": "OpaqueParentTemplate", + "Connections": [ + { + "LocalSlot": "DirectionalShadowmap", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "DirectionalShadowmap" + } + }, + { + "LocalSlot": "DirectionalESM", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "DirectionalESM" + } + }, + { + "LocalSlot": "ProjectedShadowmap", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "ProjectedShadowmap" + } + }, + { + "LocalSlot": "ProjectedESM", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "ProjectedESM" + } + }, + { + "LocalSlot": "TileLightData", + "AttachmentRef": { + "Pass": "LightCullingPass", + "Attachment": "TileLightData" + } + }, + { + "LocalSlot": "LightListRemapped", + "AttachmentRef": { + "Pass": "LightCullingPass", + "Attachment": "LightListRemapped" + } + }, + { + "LocalSlot": "DepthLinear", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "DepthLinear" + } + }, + { + "LocalSlot": "DepthStencil", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "DepthMSAA" + } + }, + { + "LocalSlot": "SwapChainOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "SwapChainOutput" + } + } + ] + }, + { + "Name": "TransparentPass", + "TemplateName": "TransparentParentTemplate", + "Connections": [ + { + "LocalSlot": "DirectionalShadowmap", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "DirectionalShadowmap" + } + }, + { + "LocalSlot": "DirectionalESM", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "DirectionalESM" + } + }, + { + "LocalSlot": "ProjectedShadowmap", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "ProjectedShadowmap" + } + }, + { + "LocalSlot": "ProjectedESM", + "AttachmentRef": { + "Pass": "ShadowPass", + "Attachment": "ProjectedESM" + } + }, + { + "LocalSlot": "TileLightData", + "AttachmentRef": { + "Pass": "LightCullingPass", + "Attachment": "TileLightData" + } + }, + { + "LocalSlot": "LightListRemapped", + "AttachmentRef": { + "Pass": "LightCullingPass", + "Attachment": "LightListRemapped" + } + }, + { + "LocalSlot": "InputLinearDepth", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "DepthLinear" + } + }, + { + "LocalSlot": "DepthStencil", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + }, + { + "LocalSlot": "InputOutput", + "AttachmentRef": { + "Pass": "OpaquePass", + "Attachment": "Output" + } + } + ] + }, + { + "Name": "DeferredFogPass", + "TemplateName": "DeferredFogPassTemplate", + "Enabled": false, + "Connections": [ + { + "LocalSlot": "InputLinearDepth", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "DepthLinear" + } + }, + { + "LocalSlot": "InputDepthStencil", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + }, + { + "LocalSlot": "RenderTargetInputOutput", + "AttachmentRef": { + "Pass": "TransparentPass", + "Attachment": "InputOutput" + } + } + ], + "PassData": { + "$type": "FullscreenTrianglePassData", + "ShaderAsset": { + "FilePath": "Shaders/ScreenSpace/DeferredFog.shader" + }, + "PipelineViewTag": "MainCamera" + } + }, + { + "Name": "ReflectionCopyFrameBufferPass", + "TemplateName": "ReflectionCopyFrameBufferPassTemplate", + "Enabled": false, + "Connections": [ + { + "LocalSlot": "Input", + "AttachmentRef": { + "Pass": "DeferredFogPass", + "Attachment": "RenderTargetInputOutput" + } + } + ] + }, + { + "Name": "PostProcessPass", + "TemplateName": "PostProcessParentTemplate", + "Connections": [ + { + "LocalSlot": "LightingInput", + "AttachmentRef": { + "Pass": "DeferredFogPass", + "Attachment": "RenderTargetInputOutput" + } + }, + { + "LocalSlot": "Depth", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + }, + { + "LocalSlot": "MotionVectors", + "AttachmentRef": { + "Pass": "MotionVectorPass", + "Attachment": "MotionVectorOutput" + } + }, + { + "LocalSlot": "SwapChainOutput", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "SwapChainOutput" + } + } + ] + }, + { + "Name": "AuxGeomPass", + "TemplateName": "AuxGeomPassTemplate", + "Enabled": true, + "Connections": [ + { + "LocalSlot": "ColorInputOutput", + "AttachmentRef": { + "Pass": "PostProcessPass", + "Attachment": "Output" + } + }, + { + "LocalSlot": "DepthInputOutput", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + } + ], + "PassData": { + "$type": "RasterPassData", + "DrawListTag": "auxgeom", + "PipelineViewTag": "MainCamera" + } + }, + { + "Name": "DebugOverlayPass", + "TemplateName": "DebugOverlayParentTemplate", + "Connections": [ + { + "LocalSlot": "TileLightData", + "AttachmentRef": { + "Pass": "LightCullingPass", + "Attachment": "TileLightData" + } + }, + { + "LocalSlot": "RawLightingInput", + "AttachmentRef": { + "Pass": "PostProcessPass", + "Attachment": "RawLightingOutput" + } + }, + { + "LocalSlot": "LuminanceMipChainInput", + "AttachmentRef": { + "Pass": "PostProcessPass", + "Attachment": "LuminanceMipChainOutput" + } + }, + { + "LocalSlot": "InputOutput", + "AttachmentRef": { + "Pass": "AuxGeomPass", + "Attachment": "ColorInputOutput" + } + } + ] + }, + { + "Name": "LyShinePass", + "TemplateName": "LyShineParentTemplate", + "Connections": [ + { + "LocalSlot": "ColorInputOutput", + "AttachmentRef": { + "Pass": "DebugOverlayPass", + "Attachment": "InputOutput" + } + }, + { + "LocalSlot": "DepthInputOutput", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + } + ] + }, + { + "Name": "UIPass", + "TemplateName": "UIParentTemplate", + "Connections": [ + { + "LocalSlot": "InputOutput", + "AttachmentRef": { + "Pass": "LyShinePass", + "Attachment": "ColorInputOutput" + } + }, + { + "LocalSlot": "DepthInputOutput", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + } + ] + }, + { + "Name": "CopyToSwapChain", + "TemplateName": "FullscreenCopyTemplate", + "Connections": [ + { + "LocalSlot": "Input", + "AttachmentRef": { + "Pass": "UIPass", + "Attachment": "InputOutput" + } + }, + { + "LocalSlot": "Output", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "SwapChainOutput" + } + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Passes/UI.pass b/Gems/Atom/Feature/Common/Assets/Passes/UI.pass index ac43f17c11..fd59df5336 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/UI.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/UI.pass @@ -13,13 +13,7 @@ "ScopeAttachmentUsage": "DepthStencil", "LoadStoreAction": { "ClearValue": { - "Type": "DepthStencil", - "Value": [ - 0.0, - 0.0, - 0.0, - 0.0 - ] + "Type": "DepthStencil" }, "LoadActionStencil": "Clear" } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp index ba9e6b20ed..8e0aa62554 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp @@ -172,7 +172,7 @@ namespace AZ } m_pipelineState = m_shader->AcquirePipelineState(descriptor); - } + } m_dirty = false; } return m_pipelineState; diff --git a/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.azsl b/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.azsl index 85b2dcc509..b5c0ffa068 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.azsl +++ b/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.azsl @@ -10,9 +10,6 @@ #include -// Indicates whether to use pre-multiplied alpha -option bool o_preMultiplyAlpha; - // If true pixels with an alpha value of less than 0.5 are clipped option bool o_alphaTest; @@ -86,9 +83,9 @@ struct PSOutput float4 m_color : SV_Target0; }; -float4 SampleTriangleTexture(int texIndex, float2 uv) +float4 SampleTriangleTexture(uint texIndex, float2 uv) { - if ((InstanceSrg::m_isClamp & (1 << texIndex)) != 0) + if ((InstanceSrg::m_isClamp & (1U << texIndex)) != 0) { return InstanceSrg::m_texture[texIndex].Sample(InstanceSrg::m_clampSampler, uv); } @@ -120,14 +117,6 @@ PSOutput MainPS(VSOutput IN) resColor.xyz = LinearToSRGB(resColor.xyz); } - // Check for flag to premultiply alpha - if (o_preMultiplyAlpha) - { - // premultiply the color by the alpha. This would not be required if we had full access to the separate alpha blend mode - float preMult = resColor.w; - resColor.xyz *= preMult; - } - // If the o_modulate option is not None it means that the verts have two texture indicies. The second texture is used to // mask the first. This is used for gradient masks. if (o_modulate == Modulate::Alpha) diff --git a/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist b/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist index c7eddb10f2..56f71e72f5 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist +++ b/Gems/AtomLyIntegration/AtomBridge/Assets/Shaders/LyShineUI.shadervariantlist @@ -4,7 +4,6 @@ { "StableId": 1, "Options": { - "o_preMultiplyAlpha": "false", "o_alphaTest": "false", "o_srgbWrite": "true", "o_modulate": "Modulate::None" @@ -13,11 +12,26 @@ { "StableId": 2, "Options": { - "o_preMultiplyAlpha": "false", - "o_alphaTest": "true", - "o_srgbWrite": "true", + "o_alphaTest": "false", + "o_srgbWrite": "false", "o_modulate": "Modulate::None" } + }, + { + "StableId": 3, + "Options": { + "o_alphaTest": "true", + "o_srgbWrite": "false", + "o_modulate": "Modulate::None" + } + }, + { + "StableId": 4, + "Options": { + "o_alphaTest": "false", + "o_srgbWrite": "false", + "o_modulate": "Modulate::Alpha" + } } ] } diff --git a/Gems/LyShine/Assets/Passes/LyShineParent.pass b/Gems/LyShine/Assets/Passes/LyShineParent.pass new file mode 100644 index 0000000000..7bbd4748a7 --- /dev/null +++ b/Gems/LyShine/Assets/Passes/LyShineParent.pass @@ -0,0 +1,22 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "LyShineParentTemplate", + "PassClass": "LyShinePass", + "Slots": [ + { + "Name": "ColorInputOutput", + "SlotType": "InputOutput" + }, + { + "Name": "DepthInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "DepthStencil" + } + ] + } + } +} diff --git a/Gems/LyShine/Assets/Passes/LyShinePassTemplates.azasset b/Gems/LyShine/Assets/Passes/LyShinePassTemplates.azasset new file mode 100644 index 0000000000..c9ee5186e0 --- /dev/null +++ b/Gems/LyShine/Assets/Passes/LyShinePassTemplates.azasset @@ -0,0 +1,13 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "AssetAliasesSourceData", + "ClassData": { + "AssetPaths": [ + { + "Name": "LyShineParentTemplate", + "Path": "Passes/LyShineParent.pass" + } + ] + } +} diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 171927c4a3..93bf84c66e 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -193,6 +193,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) FILES_CMAKE lyshine_common_module_files.cmake lyshine_tests_files.cmake + COMPILE_DEFINITIONS + PRIVATE + LYSHINE_TESTS INCLUDE_DIRECTORIES PRIVATE Tests diff --git a/Gems/LyShine/Code/Editor/EditorWindow.cpp b/Gems/LyShine/Code/Editor/EditorWindow.cpp index 81360ed793..8d7e20492d 100644 --- a/Gems/LyShine/Code/Editor/EditorWindow.cpp +++ b/Gems/LyShine/Code/Editor/EditorWindow.cpp @@ -1547,6 +1547,20 @@ AssetTreeEntry* EditorWindow::GetSliceLibraryTree() return m_sliceLibraryTree; } +AZ::EntityId EditorWindow::GetCanvasForCurrentEditorMode() +{ + AZ::EntityId canvasEntityId; + if (GetEditorMode() == UiEditorMode::Edit) + { + canvasEntityId = GetCanvas(); + } + else + { + canvasEntityId = GetPreviewModeCanvas(); + } + return canvasEntityId; +} + void EditorWindow::ToggleEditorMode() { m_editorMode = (m_editorMode == UiEditorMode::Edit) ? UiEditorMode::Preview : UiEditorMode::Edit; diff --git a/Gems/LyShine/Code/Editor/EditorWindow.h b/Gems/LyShine/Code/Editor/EditorWindow.h index c2fa6808f1..d9b3e60c32 100644 --- a/Gems/LyShine/Code/Editor/EditorWindow.h +++ b/Gems/LyShine/Code/Editor/EditorWindow.h @@ -143,6 +143,9 @@ public: // member functions //! Returns the current mode of the editor (Edit or Preview) UiEditorMode GetEditorMode() { return m_editorMode; } + //! Returns the UI canvas for the current mode (Edit or Preview) + AZ::EntityId GetCanvasForCurrentEditorMode(); + //! Toggle the editor mode between Edit and Preview void ToggleEditorMode(); diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.cpp b/Gems/LyShine/Code/Editor/ViewportWidget.cpp index 46f4f4f8fa..1ce8f5b64d 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.cpp +++ b/Gems/LyShine/Code/Editor/ViewportWidget.cpp @@ -7,6 +7,8 @@ */ #include "EditorCommon.h" +#include "UiCanvasComponent.h" + #include "EditorDefs.h" #include "Settings.h" #include @@ -245,6 +247,7 @@ ViewportWidget::ViewportWidget(EditorWindow* parent) FontNotificationBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); + AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(GetCurrentContextName()); } ViewportWidget::~ViewportWidget() @@ -252,6 +255,8 @@ ViewportWidget::~ViewportWidget() AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect(); FontNotificationBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); + LyShinePassDataRequestBus::Handler::BusDisconnect(); + AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect(); m_uiRenderer.reset(); @@ -272,6 +277,8 @@ void ViewportWidget::InitUiRenderer() lyShine->SetUiRendererForEditor(m_uiRenderer); m_draw2d = AZStd::make_shared(GetViewportContext()); + + LyShinePassDataRequestBus::Handler::BusConnect(GetViewportContext()->GetRenderScene()->GetId()); } ViewportInteraction* ViewportWidget::GetViewportInteraction() @@ -487,30 +494,44 @@ void ViewportWidget::EnableCanvasRender() } void ViewportWidget::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) +{ + // Update + UiEditorMode editorMode = m_editorWindow->GetEditorMode(); + if (editorMode == UiEditorMode::Edit) + { + UpdateEditMode(deltaTime); + } + else // if (editorMode == UiEditorMode::Preview) + { + UpdatePreviewMode(deltaTime); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +int ViewportWidget::GetTickOrder() +{ + return AZ::TICK_PRE_RENDER; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void ViewportWidget::OnRenderTick() { if (!m_uiRenderer->IsReady() || !m_canvasRenderIsEnabled) { return; } -#ifdef LYSHINE_ATOM_TODO - gEnv->pRenderer->SetSrgbWrite(true); -#endif - const float dpiScale = QtHelpers::GetHighDpiScaleFactor(*this); ViewportIcon::SetDpiScaleFactor(dpiScale); - // Set up to render a frame to this viewport's window - GetViewportContext()->RenderTick(); - UiEditorMode editorMode = m_editorWindow->GetEditorMode(); if (editorMode == UiEditorMode::Edit) { - RenderEditMode(deltaTime); + RenderEditMode(); } else // if (editorMode == UiEditorMode::Preview) { - RenderPreviewMode(deltaTime); + RenderPreviewMode(); } } @@ -884,17 +905,37 @@ void ViewportWidget::OnFontTextureUpdated([[maybe_unused]] IFFont* font) m_fontTextureHasChanged = true; } +LyShine::AttachmentImagesAndDependencies ViewportWidget::GetRenderTargets() +{ + LyShine::AttachmentImagesAndDependencies canvasTargets; + + AZ::EntityId canvasEntityId = m_editorWindow->GetCanvasForCurrentEditorMode(); + if (canvasEntityId.IsValid()) + { + AZ::Entity* canvasEntity = nullptr; + EBUS_EVENT_RESULT(canvasEntity, AZ::ComponentApplicationBus, FindEntity, canvasEntityId); + AZ_Assert(canvasEntity, "Canvas entity not found by ID"); + if (canvasEntity) + { + UiCanvasComponent* canvasComponent = canvasEntity->FindComponent(); + AZ_Assert(canvasComponent, "Canvas entity has no canvas component"); + if (canvasComponent) + { + canvasComponent->GetRenderTargets(canvasTargets); + } + } + } + + return canvasTargets; +} + QPointF ViewportWidget::WidgetToViewport(const QPointF & point) const { return point * WidgetToViewportFactor(); } -void ViewportWidget::RenderEditMode(float deltaTime) +void ViewportWidget::UpdateEditMode(float deltaTime) { - // sort keys for different layers - static const int64_t backgroundKey = -0x1000; - static const int64_t topLayerKey = 0x1000000; - if (m_fontTextureHasChanged) { // A font texture has changed since we last rendered. Force a render graph update for each loaded canvas @@ -908,6 +949,28 @@ void ViewportWidget::RenderEditMode(float deltaTime) return; // this can happen if a render happens during a restart } + AZ::Vector2 canvasSize; + EBUS_EVENT_ID_RESULT(canvasSize, canvasEntityId, UiCanvasBus, GetCanvasSize); + + // Set the target size of the canvas + EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, false, canvasSize); + + // Update this canvas (must be done after SetTargetCanvasSize) + EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, false); +} + +void ViewportWidget::RenderEditMode() +{ + // sort keys for different layers + static const int64_t backgroundKey = -0x1000; + static const int64_t topLayerKey = 0x1000000; + + AZ::EntityId canvasEntityId = m_editorWindow->GetCanvas(); + if (!canvasEntityId.IsValid()) + { + return; // this can happen if a render happens during a restart + } + Draw2dHelper draw2d(m_draw2d.get()); // sets and resets 2D draw mode in constructor/destructor QTreeWidgetItemRawPtrQList selection = m_editorWindow->GetHierarchy()->selectedItems(); @@ -936,9 +999,6 @@ void ViewportWidget::RenderEditMode(float deltaTime) // Set the target size of the canvas EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, false, canvasSize); - // Update this canvas (must be done after SetTargetCanvasSize) - EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, false); - // Render this canvas QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this); AZ::Vector2 viewportSize(scaledViewportSize.width(), scaledViewportSize.height()); @@ -1037,11 +1097,8 @@ void ViewportWidget::RenderEditMode(float deltaTime) } } -void ViewportWidget::RenderPreviewMode(float deltaTime) +void ViewportWidget::UpdatePreviewMode(float deltaTime) { - // sort keys for different layers - static const int64_t backgroundKey = -0x1000; - AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas(); if (m_fontTextureHasChanged) @@ -1051,6 +1108,37 @@ void ViewportWidget::RenderPreviewMode(float deltaTime) m_fontTextureHasChanged = false; } + if (canvasEntityId.IsValid()) + { + QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this); + AZ::Vector2 viewportSize(scaledViewportSize.width(), scaledViewportSize.height()); + + // Get the canvas size + AZ::Vector2 canvasSize = m_editorWindow->GetPreviewCanvasSize(); + if (canvasSize.GetX() == 0.0f && canvasSize.GetY() == 0.0f) + { + // special value of (0,0) means use the viewport size + canvasSize = viewportSize; + } + + // Set the target size of the canvas + EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, true, canvasSize); + + // Update this canvas (must be done after SetTargetCanvasSize) + EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, true); + + // Execute events that have been queued during the canvas update + gEnv->pLyShine->ExecuteQueuedEvents(); + } +} + +void ViewportWidget::RenderPreviewMode() +{ + // sort keys for different layers + static const int64_t backgroundKey = -0x1000; + + AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas(); + // Rather than scaling to exactly fit we try to draw at one of these preset scale factors // to make it it bit more obvious that the canvas size is changing float zoomScales[] = { @@ -1096,15 +1184,6 @@ void ViewportWidget::RenderPreviewMode(float deltaTime) } } - // Set the target size of the canvas - EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, true, canvasSize); - - // Update this canvas (must be done after SetTargetCanvasSize) - EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, true); - - // Execute events that have been queued during the canvas update - gEnv->pLyShine->ExecuteQueuedEvents(); - // match scale to one of the predefined scales. If the scale is so small // that it is less than the smallest scale then leave it as it is for (int i = 0; i < AZ_ARRAY_SIZE(zoomScales); ++i) @@ -1131,14 +1210,6 @@ void ViewportWidget::RenderPreviewMode(float deltaTime) canvasToViewportMatrix.SetTranslation(translation); EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetCanvasToViewportMatrix, canvasToViewportMatrix); -#ifdef LYSHINE_ATOM_TODO // mask support with Atom - // clear the stencil buffer before rendering each canvas - required for masking - // NOTE: the FRT_CLEAR_IMMEDIATE is required since we will not be setting the render target - // We also clear the color to a mid grey so that we can see the bounds of the canvas - ColorF viewportBackgroundColor(0.5f, 0.5f, 0.5f, 0); // if clearing color we want to set alpha to zero also - gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR, viewportBackgroundColor); -#endif - m_draw2d->SetSortKey(backgroundKey); RenderViewportBackground(); diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.h b/Gems/LyShine/Code/Editor/ViewportWidget.h index 0473b219dc..620cb8fb35 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.h +++ b/Gems/LyShine/Code/Editor/ViewportWidget.h @@ -9,9 +9,11 @@ #if !defined(Q_MOC_RUN) #include "EditorCommon.h" +#include "LyShinePassDataBus.h" #include #include +#include #include @@ -27,6 +29,8 @@ class ViewportWidget : public AtomToolsFramework::RenderViewportWidget , private AzToolsFramework::EditorPickModeNotificationBus::Handler , private FontNotificationBus::Handler + , private LyShinePassDataRequestBus::Handler + , public AZ::RPI::ViewportContextNotificationBus::Handler { Q_OBJECT @@ -138,15 +142,29 @@ private: // member functions void OnFontTextureUpdated(IFFont* font) override; // ~FontNotifications + // LyShinePassDataRequestBus + LyShine::AttachmentImagesAndDependencies GetRenderTargets() override; + // ~LyShinePassDataRequestBus + // AZ::TickBus::Handler void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + int GetTickOrder() override; // ~AZ::TickBus::Handler + // AZ::RPI::ViewportContextNotificationBus::Handler overrides... + void OnRenderTick() override; + + //! Update UI canvases when in edit mode + void UpdateEditMode(float deltaTime); + //! Render the viewport when in edit mode - void RenderEditMode(float deltaTime); + void RenderEditMode(); + + //! Update UI canvases when in preview mode + void UpdatePreviewMode(float deltaTime); //! Render the viewport when in preview mode - void RenderPreviewMode(float deltaTime); + void RenderPreviewMode(); //! Fill the entire viewport area with a background color void RenderViewportBackground(); diff --git a/Gems/LyShine/Code/Source/Draw2d.cpp b/Gems/LyShine/Code/Source/Draw2d.cpp index 34ffb38fa3..2d3612fc07 100644 --- a/Gems/LyShine/Code/Source/Draw2d.cpp +++ b/Gems/LyShine/Code/Source/Draw2d.cpp @@ -9,6 +9,7 @@ #include // for SVF_P3F_C4B_T2F which will be removed in a coming PR #include +#include "LyShinePassDataBus.h" #include #include @@ -95,6 +96,12 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc AZ_Assert(scene != nullptr, "Attempting to create a DynamicDrawContext for a viewport context that has not been associated with a scene yet."); // Create and initialize a DynamicDrawContext for 2d drawing + + // Get the pass for the dynamic draw context to render to + AZ::RPI::RasterPass* uiCanvasPass = nullptr; + AZ::RPI::SceneId sceneId = scene->GetId(); + LyShinePassRequestBus::EventResult(uiCanvasPass, sceneId, &LyShinePassRequestBus::Events::GetUiCanvasPass); + m_dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(); AZ::RPI::ShaderOptionList shaderOptions; shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("true"))); @@ -106,7 +113,15 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc {"TEXCOORD0", AZ::RHI::Format::R32G32_FLOAT} }); m_dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::PrimitiveType | AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode); - m_dynamicDraw->SetOutputScope(scene.get()); + if (uiCanvasPass) + { + m_dynamicDraw->SetOutputScope(uiCanvasPass); + } + else + { + // Render target support is disabled + m_dynamicDraw->SetOutputScope(scene.get()); + } m_dynamicDraw->EndInit(); AZ::RHI::TargetBlendState targetBlendState; @@ -491,6 +506,7 @@ bool CDraw2d::GetDeferPrimitives() return m_deferCalls; } +//////////////////////////////////////////////////////////////////////////////////////////////////// void CDraw2d::SetSortKey(int64_t key) { m_dynamicDraw->SetSortKey(key); diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index f5edc4d7f1..c776dc11e9 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -163,6 +163,8 @@ CLyShine::CLyShine(ISystem* system) AzFramework::InputTextEventListener::Connect(); UiCursorBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); + AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect( + AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContextName()); AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect(); // These are internal Amazon components, so register them so that we can send back their names to our metrics collection @@ -240,9 +242,11 @@ CLyShine::~CLyShine() { UiCursorBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); + AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect(); AzFramework::InputTextEventListener::Disconnect(); AzFramework::InputChannelEventListener::Disconnect(); AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect(); + LyShinePassDataRequestBus::Handler::BusDisconnect(); UiCanvasComponent::Shutdown(); @@ -642,15 +646,19 @@ void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time { // Update the loaded UI canvases Update(deltaTime); - - // Recreate dirty render graphs and send primitive data to the dynamic draw context - Render(); } //////////////////////////////////////////////////////////////////////////////////////////////////// int CLyShine::GetTickOrder() { - return AZ::TICK_UI; + return AZ::TICK_PRE_RENDER; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CLyShine::OnRenderTick() +{ + // Recreate dirty render graphs and send primitive data to the dynamic draw context + Render(); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -658,6 +666,16 @@ void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapS { // Load cursor if its path was set before RPI was initialized LoadUiCursor(); + + LyShinePassDataRequestBus::Handler::BusConnect(AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->GetId()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +LyShine::AttachmentImagesAndDependencies CLyShine::GetRenderTargets() +{ + LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies; + m_uiCanvasManager->GetRenderTargets(attachmentImagesAndDependencies); + return attachmentImagesAndDependencies; } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/LyShine/Code/Source/LyShine.h b/Gems/LyShine/Code/Source/LyShine.h index a7a8cab700..488131389a 100644 --- a/Gems/LyShine/Code/Source/LyShine.h +++ b/Gems/LyShine/Code/Source/LyShine.h @@ -16,8 +16,11 @@ #include #include +#include #include +#include "LyShinePassDataBus.h" + #if !defined(_RELEASE) #define LYSHINE_INTERNAL_UNIT_TEST #endif @@ -40,7 +43,9 @@ class CLyShine , public AzFramework::InputChannelEventListener , public AzFramework::InputTextEventListener , public AZ::TickBus::Handler + , public AZ::RPI::ViewportContextNotificationBus::Handler , protected AZ::Render::Bootstrap::NotificationBus::Handler + , protected LyShinePassDataRequestBus::Handler { public: @@ -111,10 +116,17 @@ public: int GetTickOrder() override; // ~TickEvents + // AZ::RPI::ViewportContextNotificationBus::Handler overrides... + void OnRenderTick() override; + // AZ::Render::Bootstrap::NotificationBus void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override; // ~AZ::Render::Bootstrap::NotificationBus + // LyShinePassDataRequestBus + LyShine::AttachmentImagesAndDependencies GetRenderTargets() override; + // ~LyShinePassDataRequestBus + // Get the UIRenderer for the game (which is owned by CLyShine). This is not exposed outside the gem. UiRenderer* GetUiRenderer(); diff --git a/Gems/LyShine/Code/Source/LyShinePass.cpp b/Gems/LyShine/Code/Source/LyShinePass.cpp new file mode 100644 index 0000000000..fbf7f34e14 --- /dev/null +++ b/Gems/LyShine/Code/Source/LyShinePass.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LyShinePass.h" + +namespace LyShine +{ + AZ::RPI::Ptr LyShinePass::Create(const AZ::RPI::PassDescriptor& descriptor) + { + return aznew LyShinePass(descriptor); + } + + LyShinePass::LyShinePass(const AZ::RPI::PassDescriptor& descriptor) + : Base(descriptor) + { + } + + LyShinePass::~LyShinePass() + { + LyShinePassRequestBus::Handler::BusDisconnect(); + } + + void LyShinePass::ResetInternal() + { + LyShinePassRequestBus::Handler::BusDisconnect(); + + Base::ResetInternal(); + } + + void LyShinePass::BuildInternal() + { + AZ::RPI::Scene* scene = GetScene(); + if (scene) + { + // Listen for rebuild requests + LyShinePassRequestBus::Handler::BusConnect(scene->GetId()); + + RemoveChildren(); + + // Get the current list of render targets being used across all loaded UI Canvases + LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies; + LyShinePassDataRequestBus::EventResult( + attachmentImagesAndDependencies, + scene->GetId(), + &LyShinePassDataRequestBus::Events::GetRenderTargets + ); + + AddRttChildPasses(attachmentImagesAndDependencies); + AddUiCanvasChildPass(attachmentImagesAndDependencies); + } + + Base::BuildInternal(); + } + + void LyShinePass::RebuildRttChildren() + { + QueueForBuildAndInitialization(); + } + + AZ::RPI::RasterPass* LyShinePass::GetRttPass(const AZStd::string& name) + { + for (auto child:m_children) + { + if (child->GetName() == AZ::Name(name)) + { + return azrtti_cast(child.get()); + } + } + return nullptr; + } + + AZ::RPI::RasterPass* LyShinePass::GetUiCanvasPass() + { + return m_uiCanvasChildPass.get(); + } + + void LyShinePass::AddRttChildPasses(LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies) + { + for (const auto& attachmentImageAndDependencies : attachmentImagesAndDependencies) + { + AddRttChildPass(attachmentImageAndDependencies.first, attachmentImageAndDependencies.second); + } + } + + void LyShinePass::AddRttChildPass(AZ::Data::Instance attachmentImage, AttachmentImages attachmentImageDependencies) + { + // Add a pass that renders to the specified texture + + // Create a pass template + auto passTemplate = AZStd::make_shared(); + passTemplate->m_name = "RttChildPass"; + passTemplate->m_passClass = AZ::Name("RttChildPass"); + + // Slots + passTemplate->m_slots.resize(2); + + AZ::RPI::PassSlot& depthInOutSlot = passTemplate->m_slots[0]; + depthInOutSlot.m_name = "DepthInputOutput"; + depthInOutSlot.m_slotType = AZ::RPI::PassSlotType::InputOutput; + depthInOutSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::DepthStencil; + depthInOutSlot.m_loadStoreAction.m_clearValue = AZ::RHI::ClearValue::CreateDepthStencil(0.0f, 0); + depthInOutSlot.m_loadStoreAction.m_loadActionStencil = AZ::RHI::AttachmentLoadAction::Clear; + + AZ::RPI::PassSlot& outSlot = passTemplate->m_slots[1]; + outSlot.m_name = AZ::Name("RenderTargetOutput"); + outSlot.m_slotType = AZ::RPI::PassSlotType::Output; + outSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::RenderTarget; + outSlot.m_loadStoreAction.m_clearValue = AZ::RHI::ClearValue::CreateVector4Float(0.0f, 0.0f, 0.0f, 0.0f); + outSlot.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Clear; + + // Connections + passTemplate->m_connections.resize(1); + + AZ::RPI::PassConnection& depthInOutConnection = passTemplate->m_connections[0]; + depthInOutConnection.m_localSlot = "DepthInputOutput"; + depthInOutConnection.m_attachmentRef.m_pass = "Parent"; + depthInOutConnection.m_attachmentRef.m_attachment = "DepthInputOutput"; + + // Pass data + AZStd::shared_ptr passData = AZStd::make_shared(); + passData->m_drawListTag = AZ::Name("uicanvas"); + passData->m_pipelineViewTag = AZ::Name("MainCamera"); + auto size = attachmentImage->GetRHIImage()->GetDescriptor().m_size; + passData->m_overrideScissor = AZ::RHI::Scissor(0, 0, size.m_width, size.m_height); + passData->m_overrideViewport = AZ::RHI::Viewport(0, size.m_width, 0, size.m_height); + passTemplate->m_passData = AZStd::move(passData); + // Create a pass descriptor for the new child pass + AZ::RPI::PassDescriptor childDesc; + childDesc.m_passTemplate = passTemplate; + childDesc.m_passName = attachmentImage->GetAttachmentId(); + + AZ::RPI::PassSystemInterface* passSystem = AZ::RPI::PassSystemInterface::Get(); + AZ::RPI::Ptr rttChildPass = passSystem->CreatePass(childDesc); + AZ_Assert(rttChildPass, "[LyShinePass] Unable to create %s.", passTemplate->m_name.GetCStr()); + + // Store the info needed to attach to slots and set up frame graph dependencies + rttChildPass->m_attachmentImage = attachmentImage; + rttChildPass->m_attachmentImageDependencies = attachmentImageDependencies; + + AddChild(rttChildPass); + } + + void LyShinePass::AddUiCanvasChildPass(LyShine::AttachmentImagesAndDependencies AttachmentImagesAndDependencies) + { + if (!m_uiCanvasChildPass) + { + // Create a pass template + auto passTemplate = AZStd::make_shared(); + passTemplate->m_name = AZ::Name("LyShineChildPass"); + passTemplate->m_passClass = AZ::Name("LyShineChildPass"); + + // Slots + passTemplate->m_slots.resize(2); + + AZ::RPI::PassSlot& depthInOutSlot = passTemplate->m_slots[0]; + depthInOutSlot.m_name = "DepthInputOutput"; + depthInOutSlot.m_slotType = AZ::RPI::PassSlotType::InputOutput; + depthInOutSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::DepthStencil; + depthInOutSlot.m_loadStoreAction.m_clearValue = AZ::RHI::ClearValue::CreateDepthStencil(0.0f, 0); + depthInOutSlot.m_loadStoreAction.m_loadActionStencil = AZ::RHI::AttachmentLoadAction::Clear; + + AZ::RPI::PassSlot& inOutSlot = passTemplate->m_slots[1]; + inOutSlot.m_name = "ColorInputOutput"; + inOutSlot.m_slotType = AZ::RPI::PassSlotType::InputOutput; + inOutSlot.m_scopeAttachmentUsage = AZ::RHI::ScopeAttachmentUsage::RenderTarget; + + // Connections + passTemplate->m_connections.resize(2); + + AZ::RPI::PassConnection& depthInOutConnection = passTemplate->m_connections[0]; + depthInOutConnection.m_localSlot = "DepthInputOutput"; + depthInOutConnection.m_attachmentRef.m_pass = "Parent"; + depthInOutConnection.m_attachmentRef.m_attachment = "DepthInputOutput"; + + AZ::RPI::PassConnection& inOutConnection = passTemplate->m_connections[1]; + inOutConnection.m_localSlot = "ColorInputOutput"; + inOutConnection.m_attachmentRef.m_pass = "Parent"; + inOutConnection.m_attachmentRef.m_attachment = "ColorInputOutput"; + + // Pass data + AZStd::shared_ptr passData = AZStd::make_shared(); + passData->m_drawListTag = AZ::Name("uicanvas"); + passData->m_pipelineViewTag = AZ::Name("MainCamera"); + passTemplate->m_passData = AZStd::move(passData); + + // Create a pass descriptor for the new child pass + AZ::RPI::PassDescriptor childDesc; + childDesc.m_passTemplate = passTemplate; + childDesc.m_passName = AZ::Name("LyShineChildPass"); + + AZ::RPI::PassSystemInterface* passSystem = AZ::RPI::PassSystemInterface::Get(); + m_uiCanvasChildPass = passSystem->CreatePass(childDesc); + AZ_Assert(m_uiCanvasChildPass, "[LyShinePass] Unable to create %s.", passTemplate->m_name.GetCStr()); + } + + // Store the info needed to set up frame graph dependencies + m_uiCanvasChildPass->m_attachmentImageDependencies.clear(); + for (const auto& attachmentImageAndDescendents : AttachmentImagesAndDependencies) + { + m_uiCanvasChildPass->m_attachmentImageDependencies.emplace_back(attachmentImageAndDescendents.first); + } + + AddChild(m_uiCanvasChildPass); + } + + AZ::RPI::Ptr LyShineChildPass::Create(const AZ::RPI::PassDescriptor& descriptor) + { + return aznew LyShineChildPass(descriptor); + } + + LyShineChildPass::LyShineChildPass(const AZ::RPI::PassDescriptor& descriptor) + : RasterPass(descriptor) + { + } + + LyShineChildPass::~LyShineChildPass() + { + } + + void LyShineChildPass::SetupFrameGraphDependencies(AZ::RHI::FrameGraphInterface frameGraph) + { + AZ::RPI::RasterPass::SetupFrameGraphDependencies(frameGraph); + + for (auto attachmentImage : m_attachmentImageDependencies) + { + // Ensure that the image is imported into the attachment database. + // The image may not be imported if the owning pass has been disabled. + auto attachmentImageId = attachmentImage->GetAttachmentId(); + if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(attachmentImageId)) + { + frameGraph.GetAttachmentDatabase().ImportImage(attachmentImageId, attachmentImage->GetRHIImage()); + } + + AZ::RHI::ImageScopeAttachmentDescriptor desc; + desc.m_attachmentId = attachmentImageId; + desc.m_imageViewDescriptor = attachmentImage->GetImageView()->GetDescriptor(); + desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load; + + frameGraph.UseShaderAttachment(desc, AZ::RHI::ScopeAttachmentAccess::Read); + } + } + + AZ::RPI::Ptr RttChildPass::Create(const AZ::RPI::PassDescriptor& descriptor) + { + return aznew RttChildPass(descriptor); + } + + RttChildPass::RttChildPass(const AZ::RPI::PassDescriptor& descriptor) + : LyShineChildPass(descriptor) + { + } + + RttChildPass::~RttChildPass() + { + } + + void RttChildPass::BuildInternal() + { + AttachImageToSlot(AZ::Name("RenderTargetOutput"), m_attachmentImage); + } +} // namespace LyShine diff --git a/Gems/LyShine/Code/Source/LyShinePass.h b/Gems/LyShine/Code/Source/LyShinePass.h new file mode 100644 index 0000000000..6275353641 --- /dev/null +++ b/Gems/LyShine/Code/Source/LyShinePass.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include "LyShinePassDataBus.h" + +namespace LyShine +{ + class LyShineChildPass; + + //! Manages child passes at runtime that render to render targets + class LyShinePass final + : public AZ::RPI::ParentPass + , protected LyShinePassRequestBus::Handler + { + AZ_RPI_PASS(LyShinePass); + using Base = AZ::RPI::ParentPass; + + public: + AZ_CLASS_ALLOCATOR(LyShinePass, AZ::SystemAllocator, 0); + AZ_RTTI(LyShinePass, "C3B812ED-3771-42F4-A96F-EBD94B4D54CA", Base); + + virtual ~LyShinePass(); + static AZ::RPI::Ptr Create(const AZ::RPI::PassDescriptor& descriptor); + + protected: + // Pass behavior overrides + void ResetInternal() override; + void BuildInternal() override; + + // LyShinePassRequestBus overrides + void RebuildRttChildren() override; + AZ::RPI::RasterPass* GetRttPass(const AZStd::string& name) override; + AZ::RPI::RasterPass* GetUiCanvasPass() override; + + private: + LyShinePass() = delete; + explicit LyShinePass(const AZ::RPI::PassDescriptor& descriptor); + + // Build the render to texture child passes + void AddRttChildPasses(LyShine::AttachmentImagesAndDependencies AttachmentImagesAndDependencies); + + // Add a render to texture child pass + void AddRttChildPass(AZ::Data::Instance attachmentImage, AttachmentImages dependentAttachmentImages); + + // Append the final pass to render UI Canvas elements to the screen + void AddUiCanvasChildPass(LyShine::AttachmentImagesAndDependencies AttachmentImagesAndDependencies); + + // Pass that renders the UI Canvas elements to the screen + AZ::RPI::Ptr m_uiCanvasChildPass; + }; + + // Child pass with potential attachment dependencies + class LyShineChildPass + : public AZ::RPI::RasterPass + { + AZ_RPI_PASS(LyShineChildPass); + + friend class LyShinePass; + public: + AZ_RTTI(LyShineChildPass, "{41D525F9-09EB-4004-97DC-082078FF8DD2}", RasterPass); + AZ_CLASS_ALLOCATOR(LyShineChildPass, AZ::SystemAllocator, 0); + virtual ~LyShineChildPass(); + + //! Creates a LyShineChildPass + static AZ::RPI::Ptr Create(const AZ::RPI::PassDescriptor& descriptor); + + protected: + LyShineChildPass(const AZ::RPI::PassDescriptor& descriptor); + + // Scope producer Overrides... + void SetupFrameGraphDependencies(AZ::RHI::FrameGraphInterface frameGraph) override; + + AttachmentImages m_attachmentImageDependencies; + }; + + // Child pass that renders UI elements to a render target + class RttChildPass + : public LyShineChildPass + { + AZ_RPI_PASS(RttChildPass); + + friend class LyShinePass; + + public: + AZ_RTTI(RttChildPass, "{54B0574D-2EB3-4054-9E1D-0E0D9C8CB09A}", LyShineChildPass); + AZ_CLASS_ALLOCATOR(RttChildPass, AZ::SystemAllocator, 0); + virtual ~RttChildPass(); + + //! Creates a RttChildPass + static AZ::RPI::Ptr Create(const AZ::RPI::PassDescriptor& descriptor); + + protected: + RttChildPass(const AZ::RPI::PassDescriptor& descriptor); + + // Pass behavior overrides + void BuildInternal() override; + + AZ::Data::Instance m_attachmentImage; + }; +} // namespace LyShine diff --git a/Gems/LyShine/Code/Source/LyShinePassDataBus.h b/Gems/LyShine/Code/Source/LyShinePassDataBus.h new file mode 100644 index 0000000000..a07e43bc44 --- /dev/null +++ b/Gems/LyShine/Code/Source/LyShinePassDataBus.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include + +namespace AZ +{ + namespace RPI + { + class AttachmentImage; + class RasterPass; + } +} + +namespace LyShine +{ + using AttachmentImages = AZStd::vector>; + using AttachmentImageAndDependentsPair = AZStd::pair, AttachmentImages>; + using AttachmentImagesAndDependencies = AZStd::vector; +} + +class LyShinePassRequests + : public AZ::EBusTraits +{ +public: + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = AZ::RPI::SceneId; + + //! Called when the number of render targets has changed and the LyShine pass needs to rebuild + virtual void RebuildRttChildren() = 0; + + //! Returns a render to texture pass based on render target name + virtual AZ::RPI::RasterPass* GetRttPass(const AZStd::string& name) = 0; + + //! Returns the final pass that renders the UI canvas contents + virtual AZ::RPI::RasterPass* GetUiCanvasPass() = 0; +}; +using LyShinePassRequestBus = AZ::EBus; + +class LyShinePassDataRequests + : public AZ::EBusTraits +{ +public: + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = AZ::RPI::SceneId; + + //! Get a list of render targets that require a render to texture pass, and any + //! other render targets that are drawn on them + virtual LyShine::AttachmentImagesAndDependencies GetRenderTargets() = 0; +}; +using LyShinePassDataRequestBus = AZ::EBus; diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp index 337fe27bc5..f05cbc04d4 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp @@ -49,6 +49,7 @@ #include "UiDynamicLayoutComponent.h" #include "UiDynamicScrollBoxComponent.h" #include "UiNavigationSettings.h" +#include "LyShinePass.h" namespace LyShine { @@ -113,9 +114,11 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void LyShineSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + void LyShineSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) { - (void)required; +#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS) + required.push_back(AZ_CRC("RPISystem", 0xf2add773)); +#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -186,6 +189,17 @@ namespace LyShine RegisterComponentTypeForMenuOrdering(UiDynamicScrollBoxComponent::RTTI_Type()); RegisterComponentTypeForMenuOrdering(UiParticleEmitterComponent::RTTI_Type()); RegisterComponentTypeForMenuOrdering(UiFlipbookAnimationComponent::RTTI_Type()); + +#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS) + // Add LyShine pass + auto* passSystem = AZ::RPI::PassSystemInterface::Get(); + AZ_Assert(passSystem, "Cannot get the pass system."); + passSystem->AddPassCreator(AZ::Name("LyShinePass"), &LyShine::LyShinePass::Create); + + // Setup handler for load pass template mappings + m_loadTemplatesHandler = AZ::RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler([this]() { this->LoadPassTemplateMappings(); }); + AZ::RPI::PassSystemInterface::Get()->ConnectEvent(m_loadTemplatesHandler); +#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -386,4 +400,13 @@ namespace LyShine { UiCursorBus::Broadcast(&UiCursorInterface::SetUiCursor, m_cursorImagePathname.GetAssetPath().c_str()); } + +#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS) + //////////////////////////////////////////////////////////////////////////////////////////////////// + void LyShineSystemComponent::LoadPassTemplateMappings() + { + const char* passTemplatesFile = "Passes/LyShinePassTemplates.azasset"; + AZ::RPI::PassSystemInterface::Get()->LoadPassTemplateMappings(passTemplatesFile); + } +#endif } diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.h b/Gems/LyShine/Code/Source/LyShineSystemComponent.h index 9b5f32aa57..2e0d40e8b0 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.h +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.h @@ -20,6 +20,10 @@ #include #include "LyShine.h" +#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS) +#include +#endif + namespace LyShine { // LyShine depends on the LegacyAllocator and CryStringAllocator. This will be managed @@ -90,6 +94,11 @@ namespace LyShine void BroadcastCursorImagePathname(); +#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS) + // Load pass template mappings for this gem + void LoadPassTemplateMappings(); +#endif + protected: // data CLyShine* m_pLyShine = nullptr; @@ -102,5 +111,9 @@ namespace LyShine // We only store this in order to generate metrics on LyShine specific components static const AZStd::list* m_componentDescriptors; + +#if !defined(LYSHINE_BUILDER) && !defined(LYSHINE_TESTS) + AZ::RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler m_loadTemplatesHandler; +#endif }; } diff --git a/Gems/LyShine/Code/Source/RenderGraph.cpp b/Gems/LyShine/Code/Source/RenderGraph.cpp index 9ee26cdf8e..ee26d1dd61 100644 --- a/Gems/LyShine/Code/Source/RenderGraph.cpp +++ b/Gems/LyShine/Code/Source/RenderGraph.cpp @@ -10,6 +10,9 @@ #include "UiRenderer.h" #include +#include + +#include #ifndef _RELEASE #include @@ -78,57 +81,28 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void PrimitiveListRenderNode::Render(UiRenderer* uiRenderer) + void PrimitiveListRenderNode::Render(UiRenderer* uiRenderer + , const AZ::Matrix4x4& modelViewProjMat + , AZ::RHI::Ptr dynamicDraw) { -#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (masks/render targets) - for (int i = 0; i < m_numTextures; ++i) - { - uiRenderer->SetTexture(m_textures[i].m_texture, i, m_textures[i].m_isClampTextureMode); - } - - int blendModeState = m_blendModeState; - - IRenderer* renderer = gEnv->pRenderer; - renderer->SetState(blendModeState | uiRenderer->GetBaseState()); - - if (m_isTextureSRGB) - { - renderer->SetSrgbWrite(false); - } - - // We are using SetColorOp as a way to set flags for the ui.cfx shader by reusing flags - // that the FixedPipelineEmu.cfx shader uses. So the names colorOp and alphaOp are used - // just because this are the inputs to SetColorOp. - uint8 colorOp = m_preMultiplyAlpha ? ColorOp_PreMultiplyAlpha : ColorOp_Normal; - uint8 alphaOp = AlphaOp_Normal; - switch (m_alphaMaskType) - { - case AlphaMaskType::None: - alphaOp = AlphaOp_Normal; - break; - case AlphaMaskType::ModulateAlpha: - alphaOp = AlphaOp_ModulateAlpha; - break; - case AlphaMaskType::ModulateAlphaAndColor: - alphaOp = AlphaOp_ModulateAlphaAndColor; - break; - } - - renderer->SetColorOp(colorOp, alphaOp, DEF_TEXARG0, DEF_TEXARG0); - - renderer->DrawDynUiPrimitiveList(m_primitives, m_totalNumVertices, m_totalNumIndices); - - if (m_isTextureSRGB) - { - renderer->SetSrgbWrite(true); - } -#endif if (!uiRenderer->IsReady()) { return; } - AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); + UiRenderer::BaseState curBaseState = uiRenderer->GetBaseState(); + UiRenderer::BaseState prevBaseState = curBaseState; + if (m_isTextureSRGB) + { + curBaseState.m_srgbWrite = false; + } + + if (m_alphaMaskType == AlphaMaskType::ModulateAlpha) + { + curBaseState.m_modulateAlpha = true; + } + uiRenderer->SetBaseState(curBaseState); + const UiRenderer::UiShaderData& uiShaderData = uiRenderer->GetUiShaderData(); // Set render state @@ -167,7 +141,7 @@ namespace LyShine drawSrg->SetConstant(uiShaderData.m_isClampInputIndex, isClampTextureMode); // Set projection matrix - drawSrg->SetConstant(uiShaderData.m_viewProjInputIndex, uiRenderer->GetModelViewProjectionMatrix()); + drawSrg->SetConstant(uiShaderData.m_viewProjInputIndex, modelViewProjMat); drawSrg->Compile(); @@ -180,6 +154,8 @@ namespace LyShine { dynamicDraw->DrawIndexed(primitive.m_vertices, primitive.m_numVertices, primitive.m_indices, primitive.m_numIndices, AZ::RHI::IndexFormat::Uint16, drawSrg); } + + uiRenderer->SetBaseState(prevBaseState); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -303,33 +279,35 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void MaskRenderNode::Render(UiRenderer* uiRenderer) + void MaskRenderNode::Render(UiRenderer* uiRenderer + , const AZ::Matrix4x4& modelViewProjMat + , AZ::RHI::Ptr dynamicDraw) { UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState(); if (m_isMaskingEnabled || m_drawBehind) { - SetupBeforeRenderingMask(uiRenderer, true, priorBaseState); + SetupBeforeRenderingMask(uiRenderer, dynamicDraw, true, priorBaseState); for (RenderNode* renderNode : m_maskRenderNodes) { - renderNode->Render(uiRenderer); + renderNode->Render(uiRenderer, modelViewProjMat, dynamicDraw); } - SetupAfterRenderingMask(uiRenderer, true, priorBaseState); + SetupAfterRenderingMask(uiRenderer, dynamicDraw, true, priorBaseState); } for (RenderNode* renderNode : m_contentRenderNodes) { - renderNode->Render(uiRenderer); + renderNode->Render(uiRenderer, modelViewProjMat, dynamicDraw); } if (m_isMaskingEnabled || m_drawInFront) { - SetupBeforeRenderingMask(uiRenderer, false, priorBaseState); + SetupBeforeRenderingMask(uiRenderer, dynamicDraw, false, priorBaseState); for (RenderNode* renderNode : m_maskRenderNodes) { - renderNode->Render(uiRenderer); + renderNode->Render(uiRenderer, modelViewProjMat, dynamicDraw); } - SetupAfterRenderingMask(uiRenderer, false, priorBaseState); + SetupAfterRenderingMask(uiRenderer, dynamicDraw, false, priorBaseState); } } @@ -367,7 +345,9 @@ namespace LyShine #endif //////////////////////////////////////////////////////////////////////////////////////////////////// - void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState) + void MaskRenderNode::SetupBeforeRenderingMask(UiRenderer* uiRenderer, + AZ::RHI::Ptr dynamicDraw, + bool firstPass, UiRenderer::BaseState priorBaseState) { UiRenderer::BaseState curBaseState = priorBaseState; @@ -406,7 +386,6 @@ namespace LyShine curBaseState.m_stencilState.m_backFace = stencilOpState; // set up for stencil write - AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef()); curBaseState.m_stencilState.m_enable = true; curBaseState.m_stencilState.m_writeMask = 0xFF; @@ -421,7 +400,9 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState) + void MaskRenderNode::SetupAfterRenderingMask(UiRenderer* uiRenderer, + AZ::RHI::Ptr dynamicDraw, + bool firstPass, UiRenderer::BaseState priorBaseState) { if (m_isMaskingEnabled) { @@ -439,7 +420,6 @@ namespace LyShine uiRenderer->DecrementStencilRef(); } - AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); dynamicDraw->SetStencilReference(uiRenderer->GetStencilRef()); if (firstPass) @@ -474,16 +454,14 @@ namespace LyShine //////////////////////////////////////////////////////////////////////////////////////////////////// RenderTargetRenderNode::RenderTargetRenderNode( RenderTargetRenderNode* parentRenderTarget, - int renderTargetHandle, - SDepthTexture* renderTargetDepthSurface, + AZ::Data::Instance attachmentImage, const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize, const AZ::Color& clearColor, int nestLevel) : RenderNode(RenderNodeType::RenderTarget) , m_parentRenderTarget(parentRenderTarget) - , m_renderTargetHandle(renderTargetHandle) - , m_renderTargetDepthSurface(renderTargetDepthSurface) + , m_attachmentImage(attachmentImage) , m_viewportX(viewportTopLeft.GetX()) , m_viewportY(viewportTopLeft.GetY()) , m_viewportWidth(viewportSize.GetX()) @@ -491,6 +469,13 @@ namespace LyShine , m_clearColor(clearColor) , m_nestLevel(nestLevel) { + AZ::MakeOrthographicMatrixRH(m_modelViewProjMat, + m_viewportX, + m_viewportX + m_viewportWidth, + m_viewportY + m_viewportHeight, + m_viewportY, + 0.0f, + 1.0f); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -505,9 +490,11 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void RenderTargetRenderNode::Render(UiRenderer* uiRenderer) + void RenderTargetRenderNode::Render(UiRenderer* uiRenderer + , [[maybe_unused]] const AZ::Matrix4x4& modelViewProjMat + , [[maybe_unused]] AZ::RHI::Ptr dynamicDraw) { - if (m_renderTargetHandle <= 0) + if (!m_attachmentImage) { return; } @@ -515,39 +502,52 @@ namespace LyShine ISystem* system = gEnv->pSystem; if (system && !gEnv->IsDedicated()) { - TransformationMatrices backupMatrices; - gEnv->pRenderer->Set2DModeNonZeroTopLeft(m_viewportX, m_viewportY, m_viewportWidth, m_viewportHeight, backupMatrices); - - // this will change the viewport - gEnv->pRenderer->SetRenderTarget(m_renderTargetHandle, m_renderTargetDepthSurface); - - // clear the render target before rendering to it - // NOTE: the FRT_CLEAR_IMMEDIATE is required since we will have already set the render target - // In theory we could call this before setting the render target without the immediate flag - // but that doesn't work. Perhaps because FX_Commit is not called. - ColorF viewportBackgroundColor(m_clearColor.GetR(), m_clearColor.GetG(), m_clearColor.GetB(), m_clearColor.GetA()); - gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR, viewportBackgroundColor); - - // we could use SetSrgbWrite to write to a linear texture here. But that gets complicated with - // having to affect all decsendant element renders. So we just let it write srgb to the render target and - // allow for that when we render using the render target as a source texture. - - for (RenderNode* renderNode : m_childRenderNodes) + // Use a dedicated dynamic draw context for rendering to the texture since it can only have one draw list tag + if (!m_dynamicDraw) { - renderNode->Render(uiRenderer); + m_dynamicDraw = uiRenderer->CreateDynamicDrawContextForRTT(GetRenderTargetName()); } - gEnv->pRenderer->SetRenderTarget(0); // restore render target + if (m_dynamicDraw) + { + UiRenderer::BaseState priorBaseState = uiRenderer->GetBaseState(); - gEnv->pRenderer->Unset2DMode(backupMatrices); + UiRenderer::BaseState curBaseState = priorBaseState; + curBaseState.m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One; + curBaseState.m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::AlphaSource1Inverse; + uiRenderer->SetBaseState(curBaseState); + + for (RenderNode* renderNode : m_childRenderNodes) + { + renderNode->Render(uiRenderer, m_modelViewProjMat, m_dynamicDraw); + } + + uiRenderer->SetBaseState(priorBaseState); + } + else + { + AZ_WarningOnce("UI", false, "Failed to create a Dynamic Draw Context for UI Element's render target. "\ + "Please ensure that the custom LyShinePass has been added to the project's main render pipeline."); + } } } //////////////////////////////////////////////////////////////////////////////////////////////////// const char* RenderTargetRenderNode::GetRenderTargetName() const { - ITexture* texture = gEnv->pRenderer->EF_GetTextureByID(m_renderTargetHandle); - return texture->GetName(); + return m_attachmentImage->GetRHIImage()->GetName().GetCStr(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + int RenderTargetRenderNode::GetNestLevel() const + { + return m_nestLevel; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + const AZ::Data::Instance RenderTargetRenderNode::GetRenderTarget() const + { + return m_attachmentImage; } #ifndef _RELEASE @@ -671,31 +671,29 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void RenderGraph::BeginRenderToTexture(int renderTargetHandle, SDepthTexture* renderTargetDepthSurface, + void RenderGraph::BeginRenderToTexture([[maybe_unused]] int renderTargetHandle, [[maybe_unused]] SDepthTexture* renderTargetDepthSurface, + [[maybe_unused]] const AZ::Vector2& viewportTopLeft, [[maybe_unused]] const AZ::Vector2& viewportSize, [[maybe_unused]] const AZ::Color& clearColor) + { + // LYSHINE_ATOM_TODO - this function will be removed when all IRenderer references are gone from UI components + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + void RenderGraph::BeginRenderToTexture(AZ::Data::Instance attachmentImage, const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize, const AZ::Color& clearColor) { -#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets) // this uses pool allocator RenderTargetRenderNode* renderTargetRenderNode = new RenderTargetRenderNode( - m_currentRenderTarget, renderTargetHandle, renderTargetDepthSurface, + m_currentRenderTarget, attachmentImage, viewportTopLeft, viewportSize, clearColor, m_renderTargetNestLevel); m_currentRenderTarget = renderTargetRenderNode; m_renderNodeListStack.push(&m_currentRenderTarget->GetChildRenderNodeList()); m_renderTargetNestLevel++; -#else - AZ_UNUSED(clearColor); - AZ_UNUSED(viewportSize); - AZ_UNUSED(viewportTopLeft); - AZ_UNUSED(renderTargetDepthSurface); - AZ_UNUSED(renderTargetHandle); -#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// void RenderGraph::EndRenderToTexture() { -#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets) AZ_Assert(m_currentRenderTarget, "Calling EndRenderToTexture while not defining a render target node"); if (m_currentRenderTarget) { @@ -709,7 +707,6 @@ namespace LyShine m_renderNodeListStack.pop(); m_renderTargetNestLevel--; } -#endif } void RenderGraph::AddPrimitive( @@ -803,11 +800,22 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void RenderGraph::AddAlphaMaskPrimitive(IRenderer::DynUiPrimitive* primitive, - ITexture* texture, ITexture* maskTexture, - bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode) + void RenderGraph::AddAlphaMaskPrimitive([[maybe_unused]] IRenderer::DynUiPrimitive* primitive, + [[maybe_unused]] ITexture* texture, [[maybe_unused]] ITexture* maskTexture, + [[maybe_unused]] bool isClampTextureMode, [[maybe_unused]] bool isTextureSRGB, [[maybe_unused]] bool isTexturePremultipliedAlpha, [[maybe_unused]] BlendMode blendMode) + { + // LYSHINE_ATOM_TODO - this function will be removed when all IRenderer references are gone from UI components + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + void RenderGraph::AddAlphaMaskPrimitiveAtom(IRenderer::DynUiPrimitive* primitive, + AZ::Data::Instance contentAttachmentImage, + AZ::Data::Instance maskAttachmentImage, + bool isClampTextureMode, + bool isTextureSRGB, + bool isTexturePremultipliedAlpha, + BlendMode blendMode) { -#ifdef LYSHINE_ATOM_TODO // keeping this code for future phase (masks and render targets) AZStd::vector* renderNodeList = m_renderNodeListStack.top(); int texUnit0 = -1; @@ -842,8 +850,8 @@ namespace LyShine { // render state is the same - we can add the primitive to this list if the texture is in // the list or there is space for another texture - texUnit0 = primListRenderNode->GetOrAddTexture(texture, true); - texUnit1 = primListRenderNode->GetOrAddTexture(maskTexture, true); + texUnit0 = primListRenderNode->GetOrAddTexture(contentAttachmentImage, true); + texUnit1 = primListRenderNode->GetOrAddTexture(maskAttachmentImage, true); if (texUnit0 != -1 && texUnit1 != -1) { @@ -857,7 +865,7 @@ namespace LyShine { // We can't add this primitive to the existing render node, we need to create a new render node // this uses a pool allocator for fast allocation - renderNodeToAddTo = new PrimitiveListRenderNode(texture, maskTexture, + renderNodeToAddTo = new PrimitiveListRenderNode(contentAttachmentImage, maskAttachmentImage, isClampTextureMode, isTextureSRGB, isPreMultiplyAlpha, alphaMaskType, blendModeState); renderNodeList->push_back(renderNodeToAddTo); @@ -881,15 +889,6 @@ namespace LyShine // add this primitive to the render node renderNodeToAddTo->AddPrimitive(primitive); } -#else - AZ_UNUSED(primitive); - AZ_UNUSED(texture); - AZ_UNUSED(maskTexture); - AZ_UNUSED(isClampTextureMode); - AZ_UNUSED(isTextureSRGB); - AZ_UNUSED(isTexturePremultipliedAlpha); - AZ_UNUSED(blendMode); -#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -972,11 +971,8 @@ namespace LyShine } //////////////////////////////////////////////////////////////////////////////////////////////////// - void RenderGraph::Render(UiRenderer* uiRenderer, const AZ::Vector2& viewportSize) + void RenderGraph::Render(UiRenderer* uiRenderer, [[maybe_unused]] const AZ::Vector2& viewportSize) { - // LYSHINE_ATOM_TODO - will probably need to support this when converting UI Editor to use Atom - AZ_UNUSED(viewportSize); - AZ::RHI::Ptr dynamicDraw = uiRenderer->GetDynamicDrawContext(); // Disable stencil and enable blend/color write @@ -984,57 +980,35 @@ namespace LyShine dynamicDraw->SetTarget0BlendState(uiRenderer->GetBaseState().m_blendState); // First render the render targets, they are sorted so that more deeply nested ones are rendered first. - -#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (render targets) // They only need to be rendered the first time that a render graph is rendered after it has been built. - // Though there is a special case, if this is the first time a shader variant has been used it can miss - // the first render. So to be safe we only stop rendering to render targets after we have rendered to - // them twice with no shader compiles initiated. - if (m_renderToRenderTargetCount < 2) + if (m_renderToRenderTargetCount == 0) + { + // Enable the Rtt passes to draw onto the render targets + SetRttPassesEnabled(uiRenderer, true); + } + + // LYSHINE_ATOM_TODO - It is currently necessary to render to the targets twice. Needs investigation + constexpr int timesToRenderToRenderTargets = 2; + if (m_renderToRenderTargetCount < timesToRenderToRenderTargets) { for (RenderNode* renderNode : m_renderTargetRenderNodes) { - renderNode->Render(uiRenderer); - } - - // if the render targets render OK we don't need to render them every frame. But if a new shader - // variant needed to be compiled then they will not have rendered OK. So we check is there are - // any shaders still in the process of compiling. Because they are compiled on the render - // thread, we may not know until the next frame that a shader needed to be compiled. So we need - // the counter. - SShaderCacheStatistics stats; - gEnv->pRenderer->EF_Query(EFQ_GetShaderCacheInfo, stats); - bool waitingOnShadersToCompile = stats.m_nNumShaderAsyncCompiles > 0 ? true : false; - if (!waitingOnShadersToCompile) - { - m_renderToRenderTargetCount++; - } - else - { - m_renderToRenderTargetCount = 0; + renderNode->Render(uiRenderer, uiRenderer->GetModelViewProjectionMatrix(), dynamicDraw); } + m_renderToRenderTargetCount++; } -#else - for (RenderNode* renderNode : m_renderTargetRenderNodes) + else if (m_renderToRenderTargetCount < timesToRenderToRenderTargets + 1) { - renderNode->Render(uiRenderer); + // Disable the rtt render passes since they don't need to be rendered to until the graph becomes invalidated again. + // This is also necessary to prevent the render targets' contents getting cleared on load by the pass. + SetRttPassesEnabled(uiRenderer, false); + m_renderToRenderTargetCount++; } -#endif -#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (UI Editor) - // Set2DMode defines the viewport so we set it to canvas viewport here (the render target render nodes - // above will have set the viewport as they needed). - TransformationMatrices backupMatrices; - gEnv->pRenderer->Set2DMode(static_cast(viewportSize.GetX()), static_cast(viewportSize.GetY()), backupMatrices); -#endif for (RenderNode* renderNode : m_renderNodes) { - renderNode->Render(uiRenderer); + renderNode->Render(uiRenderer, uiRenderer->GetModelViewProjectionMatrix(), dynamicDraw); } -#ifdef LYSHINE_ATOM_TODO // keeping this code for reference for future phase (UI Editor) - // end the 2D mode - gEnv->pRenderer->Unset2DMode(backupMatrices); -#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1072,6 +1046,31 @@ namespace LyShine return m_renderNodes.empty(); } + //////////////////////////////////////////////////////////////////////////////////////////////////// + void RenderGraph::GetRenderTargetsAndDependencies(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies) + { + for (RenderNode* renderNode : m_renderTargetRenderNodes) + { + const RenderTargetRenderNode* renderTargetRenderNode = static_cast(renderNode); + + if (renderTargetRenderNode->GetNestLevel() == 0) + { + LyShine::AttachmentImages attachmentImages; + const AZStd::vector& childNodeList = renderTargetRenderNode->GetChildRenderNodeList(); + for (auto& childNode : childNodeList) + { + if (childNode->GetType() == RenderNodeType::RenderTarget) + { + const RenderTargetRenderNode* childRenderTargetRenderNode = static_cast(childNode); + attachmentImages.emplace_back(childRenderTargetRenderNode->GetRenderTarget()); + } + } + + attachmentImagesAndDependencies.emplace_back(AttachmentImageAndDependentsPair(renderTargetRenderNode->GetRenderTarget(), attachmentImages)); + } + } + } + #ifndef _RELEASE //////////////////////////////////////////////////////////////////////////////////////////////////// void RenderGraph::ValidateGraph() @@ -1540,4 +1539,19 @@ namespace LyShine return flags; } + void RenderGraph::SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled) + { + // Enable or disable the rtt render passes + AZ::RPI::SceneId sceneId = uiRenderer->GetViewportContext()->GetRenderScene()->GetId(); + for (RenderTargetRenderNode* renderTargetRenderNode : m_renderTargetRenderNodes) + { + // Find the rtt pass to disable + AZ::RPI::RasterPass* rttPass = nullptr; + LyShinePassRequestBus::EventResult(rttPass, sceneId, &LyShinePassRequestBus::Events::GetRttPass, renderTargetRenderNode->GetRenderTargetName()); + if (rttPass) + { + rttPass->SetEnabled(enabled); + } + } + } } diff --git a/Gems/LyShine/Code/Source/RenderGraph.h b/Gems/LyShine/Code/Source/RenderGraph.h index 2529c0f47e..bc5bd094c8 100644 --- a/Gems/LyShine/Code/Source/RenderGraph.h +++ b/Gems/LyShine/Code/Source/RenderGraph.h @@ -15,10 +15,13 @@ #include #include +#include #include +#include #include #include "UiRenderer.h" +#include "LyShinePass.h" #ifndef _RELEASE #include "LyShineDebug.h" #endif @@ -46,7 +49,9 @@ namespace LyShine RenderNode(RenderNodeType type) : m_type(type) {} virtual ~RenderNode() {}; - virtual void Render(UiRenderer* uiRenderer) = 0; + virtual void Render(UiRenderer* uiRenderer + , const AZ::Matrix4x4& modelViewProjMat + , AZ::RHI::Ptr dynamicDraw) = 0; RenderNodeType GetType() const { return m_type; } @@ -70,7 +75,9 @@ namespace LyShine PrimitiveListRenderNode(const AZ::Data::Instance& texture, const AZ::Data::Instance& maskTexture, bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, int blendModeState); ~PrimitiveListRenderNode() override; - void Render(UiRenderer* uiRenderer) override; + void Render(UiRenderer* uiRenderer + , const AZ::Matrix4x4& modelViewProjMat + , AZ::RHI::Ptr dynamicDraw) override; void AddPrimitive(IRenderer::DynUiPrimitive* primitive); IRenderer::DynUiPrimitiveList& GetPrimitives() const; @@ -128,7 +135,9 @@ namespace LyShine MaskRenderNode(MaskRenderNode* parentMask, bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront); ~MaskRenderNode() override; - void Render(UiRenderer* uiRenderer) override; + void Render(UiRenderer* uiRenderer + , const AZ::Matrix4x4& modelViewProjMat + , AZ::RHI::Ptr dynamicDraw) override; AZStd::vector& GetMaskRenderNodeList() { return m_maskRenderNodes; } const AZStd::vector& GetMaskRenderNodeList() const { return m_maskRenderNodes; } @@ -152,8 +161,12 @@ namespace LyShine #endif private: // functions - void SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState); - void SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState); + void SetupBeforeRenderingMask(UiRenderer* uiRenderer, + AZ::RHI::Ptr dynamicDraw, + bool firstPass, UiRenderer::BaseState priorBaseState); + void SetupAfterRenderingMask(UiRenderer* uiRenderer, + AZ::RHI::Ptr dynamicDraw, + bool firstPass, UiRenderer::BaseState priorBaseState); private: // data AZStd::vector m_maskRenderNodes; //!< The render nodes used to render the mask shape @@ -175,15 +188,17 @@ namespace LyShine // We use a pool allocator to keep these allocations fast. AZ_CLASS_ALLOCATOR(RenderTargetRenderNode, AZ::PoolAllocator, 0); - RenderTargetRenderNode(RenderTargetRenderNode* parentRenderTarget, int renderTargetHandle, - SDepthTexture* renderTargetDepthSurface, + RenderTargetRenderNode(RenderTargetRenderNode* parentRenderTarget, + AZ::Data::Instance attachmentImage, const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize, const AZ::Color& clearColor, int nestLevel); ~RenderTargetRenderNode() override; - void Render(UiRenderer* uiRenderer) override; + void Render(UiRenderer* uiRenderer + , const AZ::Matrix4x4& modelViewProjMat + , AZ::RHI::Ptr dynamicDraw) override; AZStd::vector& GetChildRenderNodeList() { return m_childRenderNodes; } const AZStd::vector& GetChildRenderNodeList() const { return m_childRenderNodes; } @@ -197,6 +212,9 @@ namespace LyShine AZ::Color GetClearColor() const { return m_clearColor; } const char* GetRenderTargetName() const; + int GetNestLevel() const; + + const AZ::Data::Instance GetRenderTarget() const; #ifndef _RELEASE // A debug-only function useful for debugging @@ -213,13 +231,16 @@ namespace LyShine RenderTargetRenderNode* m_parentRenderTarget = nullptr; //! Used while building the render graph. - int m_renderTargetHandle = -1; - SDepthTexture* m_renderTargetDepthSurface = nullptr; + AZ::Data::Instance m_attachmentImage; + + // Each render target requires a unique dynamic draw context to draw to the raster pass associated with the target + AZ::RHI::Ptr m_dynamicDraw; float m_viewportX = 0; float m_viewportY = 0; float m_viewportWidth = 0; float m_viewportHeight = 0; + AZ::Matrix4x4 m_modelViewProjMat; AZ::Color m_clearColor; int m_nestLevel = 0; }; @@ -241,9 +262,10 @@ namespace LyShine void StartChildrenForMask() override; void EndMask() override; + //! Begin rendering to a texture void BeginRenderToTexture(int renderTargetHandle, SDepthTexture* renderTargetDepthSurface, - const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize, - const AZ::Color& clearColor) override; + const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize, const AZ::Color& clearColor) override; + void EndRenderToTexture() override; void AddPrimitive(IRenderer::DynUiPrimitive* primitive, ITexture* texture, @@ -268,6 +290,20 @@ namespace LyShine void AddPrimitiveAtom(IRenderer::DynUiPrimitive* primitive, const AZ::Data::Instance& texture, bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode); + //! Add an indexed triangle list primitive to the render graph which will use maskTexture as an alpha (gradient) mask + void AddAlphaMaskPrimitiveAtom(IRenderer::DynUiPrimitive* primitive, + AZ::Data::Instance contentAttachmentImage, + AZ::Data::Instance maskAttachmentImage, + bool isClampTextureMode, + bool isTextureSRGB, + bool isTexturePremultipliedAlpha, + BlendMode blendMode); + + void BeginRenderToTexture(AZ::Data::Instance attachmentImage, + const AZ::Vector2& viewportTopLeft, + const AZ::Vector2& viewportSize, + const AZ::Color& clearColor); + //! Render the display graph void Render(UiRenderer* uiRenderer, const AZ::Vector2& viewportSize); @@ -283,6 +319,8 @@ namespace LyShine //! Test whether the render graph contains any render nodes bool IsEmpty(); + void GetRenderTargetsAndDependencies(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies); + #ifndef _RELEASE // A debug-only function useful for debugging, not called but calls can be added during debugging void ValidateGraph(); @@ -311,6 +349,8 @@ namespace LyShine //! Given a blend mode and whether the shader will be outputing premultiplied alpha, return state flags int GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const; + void SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled); + protected: // data AZStd::vector m_renderNodes; diff --git a/Gems/LyShine/Code/Source/RenderToTextureBus.h b/Gems/LyShine/Code/Source/RenderToTextureBus.h new file mode 100644 index 0000000000..310f1f93cf --- /dev/null +++ b/Gems/LyShine/Code/Source/RenderToTextureBus.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +namespace LyShine +{ + //! Ebus to handle render target requests + class RenderToTextureRequests + : public AZ::ComponentBus + { + public: + virtual AZ::RHI::AttachmentId UseRenderTarget(const AZ::Name& renderTargetName, AZ::RHI::Size size) = 0; + virtual void ReleaseRenderTarget(const AZ::RHI::AttachmentId& attachmentId) = 0; + virtual AZ::Data::Instance GetRenderTarget(const AZ::RHI::AttachmentId& attachmentId) = 0; + }; + + using RenderToTextureRequestBus = AZ::EBus; +} diff --git a/Gems/LyShine/Code/Source/UiCanvasComponent.cpp b/Gems/LyShine/Code/Source/UiCanvasComponent.cpp index 72d9f92d1f..824b0d5698 100644 --- a/Gems/LyShine/Code/Source/UiCanvasComponent.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasComponent.cpp @@ -49,6 +49,8 @@ #include #include +#include +#include #include "Animation/UiAnimationSystem.h" @@ -64,6 +66,8 @@ #include #endif +#include "LyShinePassDataBus.h" + //////////////////////////////////////////////////////////////////////////////////////////////////// //! UiCanvasNotificationBus Behavior context handler class class UiCanvasNotificationBusBehaviorHandler @@ -251,14 +255,22 @@ namespace UiRenderer* GetUiRendererForGame() { - CLyShine* lyShine = static_cast(gEnv->pLyShine); - return lyShine ? lyShine->GetUiRenderer() : nullptr; + if (gEnv && gEnv->pLyShine) + { + CLyShine* lyShine = static_cast(gEnv->pLyShine); + return lyShine->GetUiRenderer(); + } + return nullptr; } UiRenderer* GetUiRendererForEditor() { - CLyShine* lyShine = static_cast(gEnv->pLyShine); - return lyShine ? lyShine->GetUiRendererForEditor() : nullptr; + if (gEnv && gEnv->pLyShine) + { + CLyShine* lyShine = static_cast(gEnv->pLyShine); + return lyShine->GetUiRendererForEditor(); + } + return nullptr; } bool IsValidInteractable(const AZ::EntityId& entityId) @@ -1829,6 +1841,46 @@ void UiCanvasComponent::MarkRenderGraphDirty() } } +//////////////////////////////////////////////////////////////////////////////////////////////////// +AZ::RHI::AttachmentId UiCanvasComponent::UseRenderTarget(const AZ::Name& renderTargetName, AZ::RHI::Size size) +{ + // Create a render target that UI elements will render to + AZ::RHI::ImageDescriptor imageDesc; + imageDesc.m_bindFlags = AZ::RHI::ImageBindFlags::Color | AZ::RHI::ImageBindFlags::ShaderReadWrite; + imageDesc.m_size = size; + imageDesc.m_format = AZ::RHI::Format::R8G8B8A8_UNORM; + + AZ::Data::Instance pool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); + auto attachmentImage = AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, renderTargetName); + if (!attachmentImage) + { + AZ_Warning("UI", false, "Failed to create render target"); + return AZ::RHI::AttachmentId(); + } + + m_attachmentImageMap[attachmentImage->GetAttachmentId()] = attachmentImage; + + // Notify LyShine render pass that it needs to rebuild + QueueRttPassRebuild(); + + return attachmentImage->GetAttachmentId(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void UiCanvasComponent::ReleaseRenderTarget(const AZ::RHI::AttachmentId& attachmentId) +{ + m_attachmentImageMap.erase(attachmentId); + + // Notify LyShine render pass that it needs to rebuild + QueueRttPassRebuild(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +AZ::Data::Instance UiCanvasComponent::GetRenderTarget(const AZ::RHI::AttachmentId& attachmentId) +{ + return m_attachmentImageMap[attachmentId]; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void UiCanvasComponent::UpdateCanvas(float deltaTime, bool isInGame) { @@ -1864,6 +1916,8 @@ void UiCanvasComponent::RenderCanvas(bool isInGame, AZ::Vector2 viewportSize, Ui return; } + m_renderInEditor = uiRenderer ? true : false; + if (!uiRenderer) { uiRenderer = GetUiRendererForGame(); @@ -1948,6 +2002,12 @@ void UiCanvasComponent::ScheduleElementDestroy(AZ::EntityId entityId) m_elementsScheduledForDestroy.push_back(entityId); } +//////////////////////////////////////////////////////////////////////////////////////////////////// +void UiCanvasComponent::GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies) +{ + m_renderGraph.GetRenderTargetsAndDependencies(attachmentImagesAndDependencies); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void UiCanvasComponent::DestroyScheduledElements() { @@ -1959,6 +2019,17 @@ void UiCanvasComponent::DestroyScheduledElements() m_elementsScheduledForDestroy.clear(); } +//////////////////////////////////////////////////////////////////////////////////////////////////// +void UiCanvasComponent::QueueRttPassRebuild() +{ + UiRenderer* uiRenderer = m_renderInEditor ? GetUiRendererForEditor() : GetUiRendererForGame(); + if (uiRenderer && uiRenderer->GetViewportContext()) // can be null in automated testing + { + AZ::RPI::SceneId sceneId = uiRenderer->GetViewportContext()->GetRenderScene()->GetId(); + EBUS_EVENT_ID(sceneId, LyShinePassRequestBus, RebuildRttChildren); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef _RELEASE void UiCanvasComponent::GetDebugInfoInteractables(AZ::EntityId& activeInteractable, AZ::EntityId& hoverInteractable) const @@ -2350,6 +2421,7 @@ void UiCanvasComponent::Activate() UiCanvasComponentImplementationBus::Handler::BusConnect(m_entity->GetId()); UiEditorCanvasBus::Handler::BusConnect(m_entity->GetId()); UiAnimationBus::Handler::BusConnect(m_entity->GetId()); + LyShine::RenderToTextureRequestBus::Handler::BusConnect(m_entity->GetId()); // Reconnect to buses that we connect to intermittently // This will only happen if we have been deactivated and reactivated at runtime @@ -2382,6 +2454,7 @@ void UiCanvasComponent::Deactivate() UiCanvasComponentImplementationBus::Handler::BusDisconnect(); UiEditorCanvasBus::Handler::BusDisconnect(); UiAnimationBus::Handler::BusDisconnect(); + LyShine::RenderToTextureRequestBus::Handler::BusDisconnect(); // disconnect from any other buses we could be connected to if (m_hoverInteractable.IsValid() && AZ::EntityBus::Handler::BusIsConnectedId(m_hoverInteractable)) @@ -2400,6 +2473,12 @@ void UiCanvasComponent::Deactivate() DestroyRenderTarget(); } + // Destroy owned render targets + m_attachmentImageMap.clear(); + + //! Notify LyShine pass that it needs to rebuild + QueueRttPassRebuild(); + delete m_layoutManager; m_layoutManager = nullptr; diff --git a/Gems/LyShine/Code/Source/UiCanvasComponent.h b/Gems/LyShine/Code/Source/UiCanvasComponent.h index 852bb482d0..0848e368fa 100644 --- a/Gems/LyShine/Code/Source/UiCanvasComponent.h +++ b/Gems/LyShine/Code/Source/UiCanvasComponent.h @@ -32,6 +32,8 @@ #include "TextureAtlas/TextureAtlasBus.h" #include "TextureAtlas/TextureAtlasNotificationBus.h" +#include "RenderToTextureBus.h" + namespace AZ { class SerializeContext; @@ -51,6 +53,7 @@ class UiCanvasComponent , public IUiAnimationListener , public UiEditorCanvasBus::Handler , public UiCanvasComponentImplementationBus::Handler + , public LyShine::RenderToTextureRequestBus::Handler { public: // constants static const AZ::Vector2 s_defaultCanvasSize; @@ -232,6 +235,12 @@ public: // member functions void MarkRenderGraphDirty() override; // ~UiCanvasComponentImplementationInterface + // RenderToTextureRequests + AZ::RHI::AttachmentId UseRenderTarget(const AZ::Name& renderTargetName, AZ::RHI::Size size) override; + void ReleaseRenderTarget(const AZ::RHI::AttachmentId& attachmentId) override; + AZ::Data::Instance GetRenderTarget(const AZ::RHI::AttachmentId& attachmentId) override; + // ~RenderToTextureRequests + void UpdateCanvas(float deltaTime, bool isInGame); void RenderCanvas(bool isInGame, AZ::Vector2 viewportSize, UiRenderer* uiRenderer = nullptr); @@ -257,6 +266,10 @@ public: // member functions //! Queue an element to be destroyed at end of frame void ScheduleElementDestroy(AZ::EntityId entityId); + bool IsRenderGraphDirty() { return m_renderGraph.GetDirtyFlag(); } + + void GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies); + #ifndef _RELEASE struct DebugInfoNumElements { @@ -427,6 +440,9 @@ private: // member functions void DestroyScheduledElements(); + //! Notify LyShine pass that it needs to rebuild its Rtt child passes + void QueueRttPassRebuild(); + private: // static member functions static AZ::u64 CreateUniqueId(); @@ -597,4 +613,8 @@ private: // static data LyShine::RenderGraph m_renderGraph; //!< the render graph for rendering the canvas, can be cached between frames bool m_isRendering = false; + bool m_renderInEditor = false; //!< indicates whether this canvas will render in the Editor viewport or the Game viewport + + //! Map of attachments used by this canvas's elements + AZStd::unordered_map> m_attachmentImageMap; }; diff --git a/Gems/LyShine/Code/Source/UiCanvasManager.cpp b/Gems/LyShine/Code/Source/UiCanvasManager.cpp index cb27f09672..0672d7b5f6 100644 --- a/Gems/LyShine/Code/Source/UiCanvasManager.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasManager.cpp @@ -301,6 +301,17 @@ void UiCanvasManager::OnFontTextureUpdated([[maybe_unused]] IFFont* font) m_fontTextureHasChanged = true; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +void UiCanvasManager::GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies) +{ + for (auto canvas : m_loadedCanvases) + { + LyShine::AttachmentImagesAndDependencies canvasTargets; + canvas->GetRenderTargets(canvasTargets); + attachmentImagesAndDependencies.insert(attachmentImagesAndDependencies.end(), canvasTargets.begin(), canvasTargets.end()); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void UiCanvasManager::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) { @@ -606,13 +617,6 @@ void UiCanvasManager::RenderLoadedCanvases() m_fontTextureHasChanged = false; } -#ifdef LYSHINE_ATOM_TODO // render target conversion to Atom - // clear the stencil buffer before rendering the loaded canvases - required for masking - // NOTE: We want to use ClearTargetsImmediately instead of ClearTargetsLater since we will not be setting the render target - ColorF viewportBackgroundColor(0, 0, 0, 0); // if clearing color we want to set alpha to zero also - gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR_STENCIL, viewportBackgroundColor); -#endif - for (auto canvas : m_loadedCanvases) { if (!canvas->GetIsRenderToTexture()) diff --git a/Gems/LyShine/Code/Source/UiCanvasManager.h b/Gems/LyShine/Code/Source/UiCanvasManager.h index 85783fab84..a2bf2dde97 100644 --- a/Gems/LyShine/Code/Source/UiCanvasManager.h +++ b/Gems/LyShine/Code/Source/UiCanvasManager.h @@ -11,6 +11,7 @@ #include #include #include +#include "LyShinePassDataBus.h" #include class UiCanvasComponent; @@ -92,6 +93,9 @@ public: // member functions bool HandleInputEventForLoadedCanvases(const AzFramework::InputChannel& inputChannel); bool HandleTextEventForLoadedCanvases(const AZStd::string& textUTF8); + // Get the render targets used by all currently loaded UI Canvases + void GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies); + #ifndef _RELEASE void DebugDisplayCanvasData(int setting) const; void DebugDisplayDrawCallData() const; diff --git a/Gems/LyShine/Code/Source/UiFaderComponent.cpp b/Gems/LyShine/Code/Source/UiFaderComponent.cpp index dbc3981056..f195689a43 100644 --- a/Gems/LyShine/Code/Source/UiFaderComponent.cpp +++ b/Gems/LyShine/Code/Source/UiFaderComponent.cpp @@ -6,6 +6,7 @@ * */ #include "UiFaderComponent.h" +#include "RenderGraph.h" #include #include @@ -14,6 +15,9 @@ #include #include +#include +#include + #include #include #include @@ -22,6 +26,7 @@ #include #include "UiSerialize.h" +#include "RenderToTextureBus.h" // BehaviorContext UiFaderNotificationBus forwarder class BehaviorUiFaderNotificationBusHandler @@ -120,7 +125,7 @@ void UiFaderComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInter AZ::Vector2 renderTargetSize = pixelAlignedBottomRight - pixelAlignedTopLeft; bool needsResize = static_cast(renderTargetSize.GetX()) != m_renderTargetWidth || static_cast(renderTargetSize.GetY()) != m_renderTargetHeight; - if (m_renderTargetHandle == -1 || needsResize) + if (m_attachmentImageId.IsEmpty() || needsResize) { // We delay first creation of the render target until render time since size is not known in Activate // We also call this if the size has changed @@ -128,7 +133,7 @@ void UiFaderComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInter } // if the render target failed to be created (zero size for example) we don't render the element at all - if (m_renderTargetHandle == -1) + if (m_attachmentImageId.IsEmpty()) { return; } @@ -139,7 +144,7 @@ void UiFaderComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInter else { // destroy previous render target, if exists - if (m_renderTargetHandle != -1) + if (!m_attachmentImageId.IsEmpty()) { DestroyRenderTarget(); } @@ -452,54 +457,22 @@ void UiFaderComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligne m_viewportTopLeft = pixelAlignedTopLeft; m_viewportSize = renderTargetSize; -#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom - // Check if the render target already exists - if (m_renderTargetHandle != -1) - { - // Render target exists, resize it to the given size - if (!gEnv->pRenderer->ResizeRenderTarget(m_renderTargetHandle, static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY()))) - { - AZ_Warning("UI", false, "Failed to resize render target for UiFaderComponent"); - DestroyRenderTarget(); - } - } - else - { - // Create a render target that this element and its children will be rendered to. - m_renderTargetHandle = gEnv->pRenderer->CreateRenderTarget(m_renderTargetName.c_str(), - static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY()), Clr_Transparent, eTF_R8G8B8A8); + // LYSHINE_ATOM_TODO: optimize by reusing/resizing targets + DestroyRenderTarget(); - if (m_renderTargetHandle == -1) - { - AZ_Warning("UI", false, "Failed to create render target for UiFaderComponent"); - } - } - - // if depth surface already exists then destroy it - if (m_renderTargetDepthSurface) + // Create a render target that this element and its children will be rendered to + AZ::EntityId canvasEntityId; + EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); + AZ::RHI::Size imageSize(renderTargetSize.GetX(), renderTargetSize.GetY(), 1); + EBUS_EVENT_ID_RESULT(m_attachmentImageId, canvasEntityId, LyShine::RenderToTextureRequestBus, UseRenderTarget, AZ::Name(m_renderTargetName.c_str()), imageSize); + if (m_attachmentImageId.IsEmpty()) { - gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface); - m_renderTargetDepthSurface = nullptr; + AZ_Warning("UI", false, "Failed to create render target for UiFaderComponent"); } - if (m_renderTargetHandle != -1) - { - // Also create a depth surface to render the canvas to, we need depth for masking - // since that uses the stencil buffer. We support any combination of nesting faders and masks - m_renderTargetDepthSurface = gEnv->pRenderer->CreateDepthSurface( - static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY())); - - if (!m_renderTargetDepthSurface) - { - AZ_Warning("UI", false, "Failed to create depth surface for UiFaderComponent"); - DestroyRenderTarget(); - } - } -#endif - // at this point either all render targets and depth surfaces are created or none are. // If all succeeded then update the render target size - if (m_renderTargetHandle != -1) + if (!m_attachmentImageId.IsEmpty()) { m_renderTargetWidth = static_cast(renderTargetSize.GetX()); m_renderTargetHeight = static_cast(renderTargetSize.GetY()); @@ -511,16 +484,12 @@ void UiFaderComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligne //////////////////////////////////////////////////////////////////////////////////////////////////// void UiFaderComponent::DestroyRenderTarget() { - if (m_renderTargetHandle != -1) + if (!m_attachmentImageId.IsEmpty()) { - gEnv->pRenderer->DestroyRenderTarget(m_renderTargetHandle); - m_renderTargetHandle = -1; - } - - if (m_renderTargetDepthSurface) - { - gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface); - m_renderTargetDepthSurface = nullptr; + AZ::EntityId canvasEntityId; + EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); + EBUS_EVENT_ID(canvasEntityId, LyShine::RenderToTextureRequestBus, ReleaseRenderTarget, m_attachmentImageId); + m_attachmentImageId = AZ::RHI::AttachmentId{}; } } @@ -594,14 +563,20 @@ void UiFaderComponent::RenderStandardFader(LyShine::IRenderGraph* renderGraph, U void UiFaderComponent::RenderRttFader(LyShine::IRenderGraph* renderGraph, UiElementInterface* elementInterface, UiRenderInterface* renderInterface, int numChildren, bool isInGame) { + // Get the render target + AZ::Data::Instance attachmentImage; + AZ::EntityId canvasEntityId; + EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); + EBUS_EVENT_ID_RESULT(attachmentImage, canvasEntityId, LyShine::RenderToTextureRequestBus, GetRenderTarget, m_attachmentImageId); + // Render the element and its children to a render target { // we always clear to transparent black - the accumulation of alpha in the render target requires it AZ::Color clearColor(0.0f, 0.0f, 0.0f, 0.0f); // Start building the render to texture node in the render graph - renderGraph->BeginRenderToTexture(m_renderTargetHandle, m_renderTargetDepthSurface, - m_viewportTopLeft, m_viewportSize, clearColor); + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); + lyRenderGraph->BeginRenderToTexture(attachmentImage, m_viewportTopLeft, m_viewportSize, clearColor); // We don't want this fader or parent faders to affect what is rendered to the render target since we will // apply those fades when we render from the render target. @@ -624,14 +599,13 @@ void UiFaderComponent::RenderRttFader(LyShine::IRenderGraph* renderGraph, UiElem float desiredAlpha = renderGraph->GetAlphaFade() * m_fade; uint8 desiredPackedAlpha = static_cast(desiredAlpha * 255.0f); - UCol desiredPackedColor; - // This is a special case. We have an input texture that already has premultiplied alpha. - // So we tell the shader not to premultiply the output colors and we premultiply the alpha - // into the vertex colors so that they are premultiplied too. - desiredPackedColor.r = desiredPackedColor.g = desiredPackedColor.b = desiredPackedColor.a = desiredPackedAlpha; - if (m_cachedPrimitive.m_vertices[0].color.dcolor != desiredPackedColor.dcolor) + // If the fade value has changed we need to update the alpha values in the vertex colors but we do + // not want to touch or recompute the RGB values + if (m_cachedPrimitive.m_vertices[0].color.a != desiredPackedAlpha) { - // go through the cached vertices and update the color values + // go through all the cached vertices and update the alpha values + UCol desiredPackedColor = m_cachedPrimitive.m_vertices[0].color; + desiredPackedColor.a = desiredPackedAlpha; for (int i = 0; i < m_cachedPrimitive.m_numVertices; ++i) { m_cachedPrimitive.m_vertices[i].color = desiredPackedColor; @@ -639,21 +613,20 @@ void UiFaderComponent::RenderRttFader(LyShine::IRenderGraph* renderGraph, UiElem } } -#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom // Add a primitive to render a quad using the render target we have created { - // Set the texture and other render state required - ITexture* texture = gEnv->pRenderer->EF_GetTextureByID(m_renderTargetHandle); - bool isClampTextureMode = true; - bool isTextureSRGB = true; - bool isTexturePremultipliedAlpha = true; - LyShine::BlendMode blendMode = LyShine::BlendMode::Normal; - - // add a render node to render from the render target texture to the current target - renderGraph->AddPrimitive(&m_cachedPrimitive, texture, - isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode); + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); + if (lyRenderGraph) + { + // Set the texture and other render state required + AZ::Data::Instance image = attachmentImage; + bool isClampTextureMode = true; + bool isTextureSRGB = true; + bool isTexturePremultipliedAlpha = true; + LyShine::BlendMode blendMode = LyShine::BlendMode::Normal; + lyRenderGraph->AddPrimitiveAtom(&m_cachedPrimitive, image, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode); + } } -#endif } } diff --git a/Gems/LyShine/Code/Source/UiFaderComponent.h b/Gems/LyShine/Code/Source/UiFaderComponent.h index a6960a5e36..560c1beaaa 100644 --- a/Gems/LyShine/Code/Source/UiFaderComponent.h +++ b/Gems/LyShine/Code/Source/UiFaderComponent.h @@ -18,6 +18,7 @@ #include #include +#include //////////////////////////////////////////////////////////////////////////////////////////////////// class UiFaderComponent @@ -156,11 +157,8 @@ private: // data //! This is generated from the entity ID and cached AZStd::string m_renderTargetName; - //! When rendering to a texture this is the texture ID of the render target - int m_renderTargetHandle = -1; - - //! When rendering to a texture this is our depth surface - SDepthTexture* m_renderTargetDepthSurface = nullptr; + //! When rendering to a texture this is the attachment image for the render target + AZ::RHI::AttachmentId m_attachmentImageId; //! The positions used for the render to texture viewport and to render the render target to the screen AZ::Vector2 m_viewportTopLeft; diff --git a/Gems/LyShine/Code/Source/UiMaskComponent.cpp b/Gems/LyShine/Code/Source/UiMaskComponent.cpp index 4ecb558b2b..2c1763e4ec 100644 --- a/Gems/LyShine/Code/Source/UiMaskComponent.cpp +++ b/Gems/LyShine/Code/Source/UiMaskComponent.cpp @@ -14,12 +14,17 @@ #include #include "IRenderer.h" +#include "RenderToTextureBus.h" +#include "RenderGraph.h" #include #include #include #include #include +#include +#include + //////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC MEMBER FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -79,7 +84,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf AZ::Vector2 renderTargetSize = pixelAlignedBottomRight - pixelAlignedTopLeft; bool needsResize = static_cast(renderTargetSize.GetX()) != m_renderTargetWidth || static_cast(renderTargetSize.GetY()) != m_renderTargetHeight; - if (m_contentRenderTargetHandle == -1 || needsResize) + if (m_contentAttachmentImageId.IsEmpty() || needsResize) { // Need to create or resize the render target CreateOrResizeRenderTarget(pixelAlignedTopLeft, pixelAlignedBottomRight); @@ -89,7 +94,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf // in theory the child mask element could still be non-zero size and could reveal things. But the way gradient masks // currently work is that the size of the render target is defined by the size of this element, therefore nothing would // be revealed by the mask if it is zero sized. - if (m_contentRenderTargetHandle == -1) + if (m_contentAttachmentImageId.IsEmpty()) { return; } @@ -101,7 +106,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf else { // using stencil mask, not going to use render targets, destroy previous render target, if exists - if (m_contentRenderTargetHandle != -1) + if (!m_contentAttachmentImageId.IsEmpty()) { DestroyRenderTarget(); } @@ -113,7 +118,7 @@ void UiMaskComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterf else { // masking disabled, not going to use render targets, destroy previous render target, if exists - if (m_contentRenderTargetHandle != -1) + if (!m_contentAttachmentImageId.IsEmpty()) { DestroyRenderTarget(); } @@ -553,77 +558,30 @@ void UiMaskComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligned m_viewportTopLeft = pixelAlignedTopLeft; m_viewportSize = renderTargetSize; -#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom - // Check if the render target already exists - if (m_contentRenderTargetHandle != -1) - { - // Render target exists, resize it to the given size - if (!gEnv->pRenderer->ResizeRenderTarget(m_contentRenderTargetHandle, static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY()))) - { - AZ_Warning("UI", false, "Failed to resize content render target for UiMaskComponent"); - DestroyRenderTarget(); - } - } - else - { - // Create a render target that this element and its children will be rendered to. - m_contentRenderTargetHandle = gEnv->pRenderer->CreateRenderTarget(m_renderTargetName.c_str(), - static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY()), Clr_Transparent, eTF_R8G8B8A8); + // LYSHINE_ATOM_TODO: optimize by reusing/resizing targets + DestroyRenderTarget(); - if (m_contentRenderTargetHandle == -1) - { - AZ_Warning("UI", false, "Failed to create content render target for UiMaskComponent"); - } + // Create a render target that this element and its children will be rendered to + AZ::EntityId canvasEntityId; + EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); + AZ::RHI::Size imageSize(renderTargetSize.GetX(), renderTargetSize.GetY(), 1); + EBUS_EVENT_ID_RESULT(m_contentAttachmentImageId, canvasEntityId, LyShine::RenderToTextureRequestBus, UseRenderTarget, AZ::Name(m_renderTargetName.c_str()), imageSize); + if (m_contentAttachmentImageId.IsEmpty()) + { + AZ_Warning("UI", false, "Failed to create content render target for UiMaskComponent"); } - // if depth surface already exists then destroy it - if (m_renderTargetDepthSurface) + // Create separate render target for the mask texture + EBUS_EVENT_ID_RESULT(m_maskAttachmentImageId, canvasEntityId, LyShine::RenderToTextureRequestBus, UseRenderTarget, AZ::Name(m_maskRenderTargetName.c_str()), imageSize); + if (m_maskAttachmentImageId.IsEmpty()) { - gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface); - m_renderTargetDepthSurface = nullptr; + AZ_Warning("UI", false, "Failed to create mask render target for UiMaskComponent"); + DestroyRenderTarget(); } - if (m_contentRenderTargetHandle != -1) - { - // Also create a depth surface to render the canvas to, we need depth for masking - // since that uses the stencil buffer. We support any combination of nesting faders and masks - m_renderTargetDepthSurface = gEnv->pRenderer->CreateDepthSurface( - static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY())); - - if (!m_renderTargetDepthSurface) - { - AZ_Warning("UI", false, "Failed to create depth surface for UiMaskComponent"); - DestroyRenderTarget(); - } - } - - // Check if the mask render target already exists - if (m_maskRenderTargetHandle != -1) - { - // Render target exists, resize it to the given size - if (!gEnv->pRenderer->ResizeRenderTarget(m_maskRenderTargetHandle, static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY()))) - { - AZ_Warning("UI", false, "Failed to resize mask render target for UiMaskComponent"); - DestroyRenderTarget(); - } - } - else - { - // create separate render target for the mask texture - m_maskRenderTargetHandle = gEnv->pRenderer->CreateRenderTarget(m_maskRenderTargetName.c_str(), - static_cast(renderTargetSize.GetX()), static_cast(renderTargetSize.GetY()), Clr_Transparent, eTF_R8G8B8A8); - - if (m_maskRenderTargetHandle == -1) - { - AZ_Warning("UI", false, "Failed to create mask render target for UiMaskComponent"); - DestroyRenderTarget(); - } - } -#endif - // at this point either all render targets and depth surfaces are created or none are. // If all succeeded then update the render target size - if (m_contentRenderTargetHandle != -1) + if (!m_contentAttachmentImageId.IsEmpty()) { m_renderTargetWidth = static_cast(renderTargetSize.GetX()); m_renderTargetHeight = static_cast(renderTargetSize.GetY()); @@ -635,22 +593,22 @@ void UiMaskComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAligned //////////////////////////////////////////////////////////////////////////////////////////////////// void UiMaskComponent::DestroyRenderTarget() { - if (m_contentRenderTargetHandle != -1) + if (!m_contentAttachmentImageId.IsEmpty()) { - gEnv->pRenderer->DestroyRenderTarget(m_contentRenderTargetHandle); - m_contentRenderTargetHandle = -1; + AZ::EntityId canvasEntityId; + EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); + EBUS_EVENT_ID(canvasEntityId, LyShine::RenderToTextureRequestBus, ReleaseRenderTarget, m_contentAttachmentImageId); + + m_contentAttachmentImageId = AZ::RHI::AttachmentId{}; } - if (m_renderTargetDepthSurface) + if (!m_maskAttachmentImageId.IsEmpty()) { - gEnv->pRenderer->DestroyDepthSurface(m_renderTargetDepthSurface); - m_renderTargetDepthSurface = nullptr; - } + AZ::EntityId canvasEntityId; + EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); + EBUS_EVENT_ID(canvasEntityId, LyShine::RenderToTextureRequestBus, ReleaseRenderTarget, m_maskAttachmentImageId); - if (m_maskRenderTargetHandle != -1) - { - gEnv->pRenderer->DestroyRenderTarget(m_maskRenderTargetHandle); - m_maskRenderTargetHandle = -1; + m_maskAttachmentImageId = AZ::RHI::AttachmentId{}; } } @@ -747,6 +705,14 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph // we always clear to transparent black - the accumulation of alpha in the render target requires it AZ::Color clearColor(0.0f, 0.0f, 0.0f, 0.0f); + // Get the render targets + AZ::Data::Instance contentAttachmentImage; + AZ::Data::Instance maskAttachmentImage; + AZ::EntityId canvasEntityId; + EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId); + EBUS_EVENT_ID_RESULT(contentAttachmentImage, canvasEntityId, LyShine::RenderToTextureRequestBus, GetRenderTarget, m_contentAttachmentImageId); + EBUS_EVENT_ID_RESULT(maskAttachmentImage, canvasEntityId, LyShine::RenderToTextureRequestBus, GetRenderTarget, m_maskAttachmentImageId); + // We don't want parent faders to affect what is rendered to the render target since we will // apply those fades when we render from the render target. // Note that this means that, if there are parent (no render to texture) faders, we get a "free" @@ -756,8 +722,8 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph // mask render target { // Start building the render to texture node in the render graph - renderGraph->BeginRenderToTexture(m_maskRenderTargetHandle, m_renderTargetDepthSurface, - m_viewportTopLeft, m_viewportSize, clearColor); + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); + lyRenderGraph->BeginRenderToTexture(maskAttachmentImage, m_viewportTopLeft, m_viewportSize, clearColor); // Render the visual component for this element (if there is one) plus the child mask element (if there is one) RenderMaskPrimitives(renderGraph, renderInterface, childMaskElementInterface, isInGame); @@ -769,8 +735,8 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph // content render target { // Start building the render to texture node for the content render target in the render graph - renderGraph->BeginRenderToTexture(m_contentRenderTargetHandle, m_renderTargetDepthSurface, - m_viewportTopLeft, m_viewportSize, clearColor); + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); + lyRenderGraph->BeginRenderToTexture(contentAttachmentImage, m_viewportTopLeft, m_viewportSize, clearColor); // Render the "content" - the child elements excluding the child mask element (if any) RenderContentPrimitives(renderGraph, elementInterface, childMaskElementInterface, numChildren, isInGame); @@ -790,14 +756,13 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph float desiredAlpha = renderGraph->GetAlphaFade(); uint32 desiredPackedAlpha = static_cast(desiredAlpha * 255.0f); - UCol desiredPackedColor; - // This is a special case. We have an input texture that already has premultiplied alpha. - // So we tell the shader not to premultiply the output colors and we premultiply the alpha - // into the vertex colors so that they are premultiplied too. - desiredPackedColor.r = desiredPackedColor.g = desiredPackedColor.b = desiredPackedColor.a = desiredPackedAlpha; - if (m_cachedPrimitive.m_vertices[0].color.dcolor != desiredPackedColor.dcolor) + // If the fade value has changed we need to update the alpha values in the vertex colors but we do + // not want to touch or recompute the RGB values + if (m_cachedPrimitive.m_vertices[0].color.a != desiredPackedAlpha) { - // go through the cached vertices and update the color values + // go through all the cached vertices and update the alpha values + UCol desiredPackedColor = m_cachedPrimitive.m_vertices[0].color; + desiredPackedColor.a = desiredPackedAlpha; for (int i = 0; i < m_cachedPrimitive.m_numVertices; ++i) { m_cachedPrimitive.m_vertices[i].color = desiredPackedColor; @@ -805,22 +770,29 @@ void UiMaskComponent::RenderUsingGradientMask(LyShine::IRenderGraph* renderGraph } } -#ifdef LYSHINE_ATOM_TODO // [LYN-3359] Support RTT using Atom // Add a primitive to do the alpha mask { - // Set the texture and other render state required - ITexture* texture = gEnv->pRenderer->EF_GetTextureByID(m_contentRenderTargetHandle); - ITexture* maskTexture = gEnv->pRenderer->EF_GetTextureByID(m_maskRenderTargetHandle); - bool isClampTextureMode = true; - bool isTextureSRGB = true; - bool isTexturePremultipliedAlpha = true; - LyShine::BlendMode blendMode = LyShine::BlendMode::Normal; + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); + if (lyRenderGraph) + { + // Set the texture and other render state required + AZ::Data::Instance contentImage = contentAttachmentImage; + AZ::Data::Instance maskImage = maskAttachmentImage; + bool isClampTextureMode = true; + bool isTextureSRGB = true; + bool isTexturePremultipliedAlpha = false; + LyShine::BlendMode blendMode = LyShine::BlendMode::Normal; - // add a render node to render using the two render targets, one as an alpha mask of the other - renderGraph->AddAlphaMaskPrimitive(&m_cachedPrimitive, texture, maskTexture, - isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode); + // add a render node to render using the two render targets, one as an alpha mask of the other + lyRenderGraph->AddAlphaMaskPrimitiveAtom(&m_cachedPrimitive, + contentAttachmentImage, + maskAttachmentImage, + isClampTextureMode, + isTextureSRGB, + isTexturePremultipliedAlpha, + blendMode); + } } -#endif } } diff --git a/Gems/LyShine/Code/Source/UiMaskComponent.h b/Gems/LyShine/Code/Source/UiMaskComponent.h index ce0068ca97..8635f048f5 100644 --- a/Gems/LyShine/Code/Source/UiMaskComponent.h +++ b/Gems/LyShine/Code/Source/UiMaskComponent.h @@ -15,6 +15,7 @@ #include #include +#include //////////////////////////////////////////////////////////////////////////////////////////////////// class UiMaskComponent @@ -184,15 +185,16 @@ private: // data //! This is generated from the entity ID and cached AZStd::string m_maskRenderTargetName; - //! When rendering to a texture this is the texture ID of the render target - int m_contentRenderTargetHandle = -1; + //! When rendering to a texture this is the attachment image for the render target + AZ::RHI::AttachmentId m_contentAttachmentImageId; //! When rendering to a texture this is our depth surface, we use the same one for rendering the mask elements //! and the content elements - it is cleared in between. SDepthTexture* m_renderTargetDepthSurface = nullptr; //! When rendering to a texture this is the texture ID of the render target - int m_maskRenderTargetHandle = -1; + //! When rendering to a texture this is the attachment image for the render target + AZ::RHI::AttachmentId m_maskAttachmentImageId; //! The positions used for the render to texture viewport and to render the render target to the screen AZ::Vector2 m_viewportTopLeft = AZ::Vector2::CreateZero(); diff --git a/Gems/LyShine/Code/Source/UiRenderer.cpp b/Gems/LyShine/Code/Source/UiRenderer.cpp index 56374d1152..357431c80a 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.cpp +++ b/Gems/LyShine/Code/Source/UiRenderer.cpp @@ -6,6 +6,7 @@ * */ #include "UiRenderer.h" +#include "LyShinePassDataBus.h" #include #include @@ -60,25 +61,32 @@ void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstra AZ::Data::Instance uiShader = AZ::RPI::LoadShader(uiShaderFilepath); // Create scene to be used by the dynamic draw context - AZ::RPI::ScenePtr scene; if (m_viewportContext) { // Create a new scene based on the user specified viewport context - scene = CreateScene(m_viewportContext); + m_scene = CreateScene(m_viewportContext); } else { // No viewport context specified, use default scene - scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + m_scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); } // Create a dynamic draw context for UI Canvas drawing for the scene - CreateDynamicDrawContext(scene, uiShader); + m_dynamicDraw = CreateDynamicDrawContext(m_scene, uiShader); - // Cache shader data such as input indices for later use - CacheShaderData(m_dynamicDraw); + if (m_dynamicDraw) + { + // Cache shader data such as input indices for later use + CacheShaderData(m_dynamicDraw); - m_isRPIReady = true; + m_isRPIReady = true; + } + else + { + AZ_Error(LogName, false, "Failed to create a dynamic draw context for LyShine. \ + This can happen if the LyShine pass hasn't been added to the main render pipeline."); + } } AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr viewportContext) @@ -107,22 +115,40 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr uiShader) +AZ::RHI::Ptr UiRenderer::CreateDynamicDrawContext( + AZ::RPI::ScenePtr scene, + AZ::Data::Instance uiShader) { - m_dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(); + // Find the pass that renders the UI canvases after the rtt passes + AZ::RPI::RasterPass* uiCanvasPass = nullptr; + AZ::RPI::SceneId sceneId = m_scene->GetId(); + LyShinePassRequestBus::EventResult(uiCanvasPass, sceneId, &LyShinePassRequestBus::Events::GetUiCanvasPass); + + AZ::RHI::Ptr dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(); // Initialize the dynamic draw context - m_dynamicDraw->InitShader(uiShader); - m_dynamicDraw->InitVertexFormat( + dynamicDraw->InitShader(uiShader); + dynamicDraw->InitVertexFormat( { { "POSITION", AZ::RHI::Format::R32G32_FLOAT }, { "COLOR", AZ::RHI::Format::B8G8R8A8_UNORM }, { "TEXCOORD", AZ::RHI::Format::R32G32_FLOAT }, { "BLENDINDICES", AZ::RHI::Format::R16G16_UINT } } ); - m_dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState + dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState | AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode); - m_dynamicDraw->SetOutputScope(scene.get()); - m_dynamicDraw->EndInit(); + + if (uiCanvasPass) + { + dynamicDraw->SetOutputScope(uiCanvasPass); + } + else + { + // Render target support is disabled + dynamicDraw->SetOutputScope(m_scene.get()); + } + dynamicDraw->EndInit(); + + return dynamicDraw; } AZStd::shared_ptr UiRenderer::GetViewportContext() @@ -158,19 +184,26 @@ void UiRenderer::CacheShaderData(const AZ::RHI::Ptr isClampIndexName); // Cache shader variants that will be used - // LYSHINE_ATOM_TODO - more variants will be used in future phase (masks/render target support) - AZ::RPI::ShaderOptionList shaderOptionsDefault; - shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_preMultiplyAlpha"), AZ::Name("false"))); - shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false"))); - shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true"))); - shaderOptionsDefault.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None"))); - m_uiShaderData.m_shaderVariantDefault = dynamicDraw->UseShaderVariant(shaderOptionsDefault); - AZ::RPI::ShaderOptionList shaderOptionsAlphaTest; - shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_preMultiplyAlpha"), AZ::Name("false"))); - shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("true"))); - shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true"))); - shaderOptionsAlphaTest.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None"))); - m_uiShaderData.m_shaderVariantAlphaTest = dynamicDraw->UseShaderVariant(shaderOptionsAlphaTest); + AZ::RPI::ShaderOptionList shaderOptionsTextureLinear; + shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false"))); + shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("true"))); + shaderOptionsTextureLinear.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None"))); + m_uiShaderData.m_shaderVariantTextureLinear = dynamicDraw->UseShaderVariant(shaderOptionsTextureLinear); + AZ::RPI::ShaderOptionList shaderOptionsTextureSrgb; + shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false"))); + shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false"))); + shaderOptionsTextureSrgb.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None"))); + m_uiShaderData.m_shaderVariantTextureSrgb = dynamicDraw->UseShaderVariant(shaderOptionsTextureSrgb); + AZ::RPI::ShaderOptionList shaderVariantAlphaTestMask; + shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("true"))); + shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false"))); + shaderVariantAlphaTestMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::None"))); + m_uiShaderData.m_shaderVariantAlphaTestMask = dynamicDraw->UseShaderVariant(shaderVariantAlphaTestMask); + AZ::RPI::ShaderOptionList shaderVariantGradientMask; + shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_alphaTest"), AZ::Name("false"))); + shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_srgbWrite"), AZ::Name("false"))); + shaderVariantGradientMask.push_back(AZ::RPI::ShaderOption(AZ::Name("o_modulate"), AZ::Name("Modulate::Alpha"))); + m_uiShaderData.m_shaderVariantGradientMask = dynamicDraw->UseShaderVariant(shaderVariantGradientMask); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -215,6 +248,38 @@ AZ::RHI::Ptr UiRenderer::GetDynamicDrawContext() return m_dynamicDraw; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +AZ::RHI::Ptr UiRenderer::CreateDynamicDrawContextForRTT(const AZStd::string& rttName) +{ + // find the rtt pass with the specified name + AZ::RPI::RasterPass* rttPass = nullptr; + AZ::RPI::SceneId sceneId = m_scene->GetId(); + LyShinePassRequestBus::EventResult(rttPass, sceneId, &LyShinePassRequestBus::Events::GetRttPass, rttName); + if (!rttPass) + { + return nullptr; + } + + AZ::RHI::Ptr dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(); + + // Initialize the dynamic draw context + dynamicDraw->InitShader(m_dynamicDraw->GetShader()); + dynamicDraw->InitVertexFormat( + { { "POSITION", AZ::RHI::Format::R32G32_FLOAT }, + { "COLOR", AZ::RHI::Format::B8G8R8A8_UNORM }, + { "TEXCOORD", AZ::RHI::Format::R32G32_FLOAT }, + { "BLENDINDICES", AZ::RHI::Format::R16G16_UINT } } + ); + dynamicDraw->AddDrawStateOptions(AZ::RPI::DynamicDrawContext::DrawStateOptions::StencilState + | AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode); + + dynamicDraw->SetOutputScope(rttPass); + + dynamicDraw->EndInit(); + + return dynamicDraw; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// const UiRenderer::UiShaderData& UiRenderer::GetUiShaderData() { @@ -270,11 +335,27 @@ void UiRenderer::SetBaseState(BaseState state) //////////////////////////////////////////////////////////////////////////////////////////////////// AZ::RPI::ShaderVariantId UiRenderer::GetCurrentShaderVariant() { - AZ::RPI::ShaderVariantId variantId = m_uiShaderData.m_shaderVariantDefault; + AZ::RPI::ShaderVariantId variantId = m_uiShaderData.m_shaderVariantTextureLinear; if (m_baseState.m_useAlphaTest) { - variantId = m_uiShaderData.m_shaderVariantAlphaTest; + variantId = m_uiShaderData.m_shaderVariantAlphaTestMask; + } + else if (m_baseState.m_modulateAlpha) + { + variantId = m_uiShaderData.m_shaderVariantGradientMask; + } + else if (!m_baseState.m_useAlphaTest && m_baseState.m_srgbWrite) + { + variantId = m_uiShaderData.m_shaderVariantTextureLinear; + } + else if (!m_baseState.m_useAlphaTest && !m_baseState.m_srgbWrite) + { + variantId = m_uiShaderData.m_shaderVariantTextureSrgb; + } + else + { + AZ_Error(LogName, 0, "Unsupported shader variant."); } return variantId; diff --git a/Gems/LyShine/Code/Source/UiRenderer.h b/Gems/LyShine/Code/Source/UiRenderer.h index d05261c2d6..14fc67fc6b 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.h +++ b/Gems/LyShine/Code/Source/UiRenderer.h @@ -36,8 +36,10 @@ public: // types AZ::RHI::ShaderInputConstantIndex m_viewProjInputIndex; AZ::RHI::ShaderInputConstantIndex m_isClampInputIndex; - AZ::RPI::ShaderVariantId m_shaderVariantDefault; - AZ::RPI::ShaderVariantId m_shaderVariantAlphaTest; + AZ::RPI::ShaderVariantId m_shaderVariantTextureLinear; + AZ::RPI::ShaderVariantId m_shaderVariantTextureSrgb; + AZ::RPI::ShaderVariantId m_shaderVariantAlphaTestMask; + AZ::RPI::ShaderVariantId m_shaderVariantGradientMask; }; // Base state @@ -56,17 +58,23 @@ public: // types m_blendState.m_blendSource = AZ::RHI::BlendFactor::AlphaSource; m_blendState.m_blendDest = AZ::RHI::BlendFactor::AlphaSourceInverse; m_blendState.m_blendOp = AZ::RHI::BlendOp::Add; + m_blendState.m_blendAlphaSource = AZ::RHI::BlendFactor::One; + m_blendState.m_blendAlphaDest = AZ::RHI::BlendFactor::Zero; + m_blendState.m_blendAlphaOp = AZ::RHI::BlendOp::Add; // Disable stencil m_stencilState = AZ::RHI::StencilState(); m_stencilState.m_enable = 0; m_useAlphaTest = false; + m_modulateAlpha = false; } AZ::RHI::TargetBlendState m_blendState; AZ::RHI::StencilState m_stencilState; bool m_useAlphaTest = false; + bool m_modulateAlpha = false; + bool m_srgbWrite = true; }; public: // member functions @@ -93,6 +101,8 @@ public: // member functions //! Return the dynamic draw context associated with this UI renderer AZ::RHI::Ptr GetDynamicDrawContext(); + AZ::RHI::Ptr CreateDynamicDrawContextForRTT(const AZStd::string& rttName); + //! Return the shader data for the ui shader const UiShaderData& GetUiShaderData(); @@ -123,6 +133,9 @@ public: // member functions //! Decrement the current stencil reference value void DecrementStencilRef(); + //! Return the viewport context set by the user, or the default if not set + AZStd::shared_ptr GetViewportContext(); + #ifndef _RELEASE //! Setup to record debug texture data before rendering void DebugSetRecordingOptionForTextureData(int recordingOption); @@ -143,10 +156,9 @@ private: // member functions AZ::RPI::ScenePtr CreateScene(AZStd::shared_ptr viewportContext); //! Create a dynamic draw context for this renderer - void CreateDynamicDrawContext(AZ::RPI::ScenePtr scene, AZ::Data::Instance); - - //! Return the viewport context set by the user, or the default if not set - AZStd::shared_ptr GetViewportContext(); + AZ::RHI::Ptr CreateDynamicDrawContext( + AZ::RPI::ScenePtr scene, + AZ::Data::Instance uiShader); //! Bind the global white texture for all the texture units we use void BindNullTexture(); @@ -168,6 +180,8 @@ protected: // attributes // Set by user when viewport context is not the main/default viewport AZStd::shared_ptr m_viewportContext; + AZ::RPI::ScenePtr m_scene; + #ifndef _RELEASE int m_debugTextureDataRecordLevel = 0; AZStd::unordered_set m_texturesUsedInFrame; // LYSHINE_ATOM_TODO - convert to RPI::Image diff --git a/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp b/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp index 17eb2c081f..65ca1ec280 100644 --- a/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp +++ b/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp @@ -163,11 +163,9 @@ namespace UnitTest SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; gEnv->pTimer = &m_timer; + gEnv->pLyShine = nullptr; - UiCanvasComponent* uiCanvasComponent; - UiTooltipDisplayComponent* uiTooltipDisplayComponent; - UiTooltipComponent* uiTooltipComponent; - std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip(); + auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnHover); AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity(); @@ -193,11 +191,9 @@ namespace UnitTest SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; gEnv->pTimer = &m_timer; + gEnv->pLyShine = nullptr; - UiCanvasComponent* uiCanvasComponent; - UiTooltipDisplayComponent* uiTooltipDisplayComponent; - UiTooltipComponent* uiTooltipComponent; - std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip(); + auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnHover); AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity(); @@ -221,11 +217,9 @@ namespace UnitTest SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; gEnv->pTimer = &m_timer; + gEnv->pLyShine = nullptr; - UiCanvasComponent* uiCanvasComponent; - UiTooltipDisplayComponent* uiTooltipDisplayComponent; - UiTooltipComponent* uiTooltipComponent; - std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip(); + auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnPress); AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity(); @@ -249,11 +243,9 @@ namespace UnitTest SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; gEnv->pTimer = &m_timer; + gEnv->pLyShine = nullptr; - UiCanvasComponent* uiCanvasComponent; - UiTooltipDisplayComponent* uiTooltipDisplayComponent; - UiTooltipComponent* uiTooltipComponent; - std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip(); + auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnPress); AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity(); @@ -277,11 +269,9 @@ namespace UnitTest SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; gEnv->pTimer = &m_timer; + gEnv->pLyShine = nullptr; - UiCanvasComponent* uiCanvasComponent; - UiTooltipDisplayComponent* uiTooltipDisplayComponent; - UiTooltipComponent* uiTooltipComponent; - std::tie(uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent) = CreateUiCanvasWithTooltip(); + auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnClick); AZ::Entity* uiTooltipEntity = uiTooltipComponent->GetEntity(); diff --git a/Gems/LyShine/Code/lyshine_static_files.cmake b/Gems/LyShine/Code/lyshine_static_files.cmake index 7fdac831b6..0c934eb057 100644 --- a/Gems/LyShine/Code/lyshine_static_files.cmake +++ b/Gems/LyShine/Code/lyshine_static_files.cmake @@ -11,8 +11,11 @@ set(FILES Include/LyShine/Draw2d.h Source/LyShine.cpp Source/LyShine.h + Source/LyShinePassDataBus.h Source/LyShineDebug.cpp Source/LyShineDebug.h + Source/LyShinePass.cpp + Source/LyShinePass.h Source/StringUtfUtils.h Source/UiImageComponent.cpp Source/UiImageComponent.h @@ -28,6 +31,7 @@ set(FILES Source/LyShineLoadScreen.h Source/RenderGraph.cpp Source/RenderGraph.h + Source/RenderToTextureBus.h Source/TextMarkup.cpp Source/TextMarkup.h Source/UiButtonComponent.cpp diff --git a/Gems/LyShine/LyShineScript/LyShinePass.data b/Gems/LyShine/LyShineScript/LyShinePass.data new file mode 100644 index 0000000000..af44db91ed --- /dev/null +++ b/Gems/LyShine/LyShineScript/LyShinePass.data @@ -0,0 +1,20 @@ + { + "Name": "LyShinePass", + "TemplateName": "LyShineParentTemplate", + "Connections": [ + { + "LocalSlot": "ColorInputOutput", + "AttachmentRef": { + "Pass": "DebugOverlayPass", + "Attachment": "InputOutput" + } + }, + { + "LocalSlot": "DepthInputOutput", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "Depth" + } + } + ] + } \ No newline at end of file diff --git a/Gems/LyShine/LyShineScript/PatchRenderPipeline.py b/Gems/LyShine/LyShineScript/PatchRenderPipeline.py new file mode 100644 index 0000000000..09a0049e81 --- /dev/null +++ b/Gems/LyShine/LyShineScript/PatchRenderPipeline.py @@ -0,0 +1,71 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT + +""" + +import os +import sys + +# Parse arguments +if len(sys.argv) != 3: + print('Incorrect number of args') + exit() + +engine_path = sys.argv[1] +if not os.path.exists(engine_path): + print(f'Given path {engine_path} does not exist') + exit() + +project_path = sys.argv[2] +if not os.path.exists(project_path): + print(f'Given path {project_path} does not exist') + exit() + +sys.path.insert(0, os.path.join(engine_path, 'Gems/Atom/RPI/Tools/')) + +from atom_rpi_tools.pass_data import PassTemplate +import atom_rpi_tools.utils as utils + +# Folder of this py file +dir_name = os.path.dirname(os.path.realpath(__file__)) + +# Patch render pipeline to insert a custom LyShine parent pass + +# Gem::Atom_Feature_Common gem's path since default render pipeline is comming from this gem +gem_assets_path = os.path.join(engine_path,'Gems/Atom/feature/Common/Assets/') + +pipeline_relatvie_path = 'Passes/MainPipeline.pass' +srcRenderPipeline = os.path.join(gem_assets_path, pipeline_relatvie_path) +destRenderPipeline = os.path.join(project_path, pipeline_relatvie_path) +# If the project doesn't have a customized main pipeline +# copy the default render pipeline from Atom_Common_Feature gem to same path in project folder +utils.find_or_copy_file(destRenderPipeline, srcRenderPipeline) + +# Load project render pipeline +renderPipeline = PassTemplate(destRenderPipeline) + +# Skip if LyShinePass already exist +newPassName = 'LyShinePass' +if renderPipeline.find_pass(newPassName)>-1: + print('Skip merging. LyShinePass already exists') + exit() + +# Insert LyShinePass between DebugOverlayPass and UIPass +refPass = 'DebugOverlayPass' +# The data file for new pass request is in the same folder of the py file +newPassRequestFilePath = os.path.join(dir_name, 'LyShinePass.data') +newPassRequestData = utils.load_json_file(newPassRequestFilePath) +insertIndex = renderPipeline.find_pass(refPass) + 1 +if insertIndex>-1: + renderPipeline.insert_pass_request(insertIndex, newPassRequestData) +else: + print('Failed to find ', refPass) + exit() + +# Update attachment references for the passes following LyShinePass +renderPipeline.replace_references_after(newPassName, 'DebugOverlayPass', 'InputOutput', 'LyShinePass', 'ColorInputOutput') + +# Save the updated render pipeline +renderPipeline.save() From 38fd92a15ad55851052c25552fce0691a583c1f1 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:48:57 -0700 Subject: [PATCH 131/157] Always display all gems in Gem Catalog (#2341) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/CreateProjectCtrl.cpp | 2 +- .../Source/GemCatalog/GemCatalogScreen.cpp | 17 ++++------------- .../Source/GemCatalog/GemCatalogScreen.h | 4 ++-- .../ProjectManager/Source/UpdateProjectCtrl.cpp | 2 +- 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 20d564d8b0..f098518fd3 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -265,6 +265,6 @@ namespace O3DE::ProjectManager void CreateProjectCtrl::ReinitGemCatalogForSelectedTemplate() { const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); - m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true); + m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template"); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 53d772c217..863f611ec8 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -62,10 +62,10 @@ namespace O3DE::ProjectManager hLayout->addWidget(m_gemInspector); } - void GemCatalogScreen::ReinitForProject(const QString& projectPath, bool isNewProject) + void GemCatalogScreen::ReinitForProject(const QString& projectPath) { m_gemModel->clear(); - FillModel(projectPath, isNewProject); + FillModel(projectPath); if (m_filterWidget) { @@ -88,18 +88,9 @@ namespace O3DE::ProjectManager }); } - void GemCatalogScreen::FillModel(const QString& projectPath, bool isNewProject) + void GemCatalogScreen::FillModel(const QString& projectPath) { - AZ::Outcome, AZStd::string> allGemInfosResult; - if (isNewProject) - { - allGemInfosResult = PythonBindingsInterface::Get()->GetEngineGemInfos(); - } - else - { - allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); - } - + AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); if (allGemInfosResult.IsSuccess()) { // Add all available gems to the model. diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 204ad0e5c5..5b48b2f90e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -28,13 +28,13 @@ namespace O3DE::ProjectManager ~GemCatalogScreen() = default; ProjectManagerScreen GetScreenEnum() override; - void ReinitForProject(const QString& projectPath, bool isNewProject); + void ReinitForProject(const QString& projectPath); bool EnableDisableGemsForProject(const QString& projectPath); GemModel* GetGemModel() const { return m_gemModel; } private: - void FillModel(const QString& projectPath, bool isNewProject); + void FillModel(const QString& projectPath); GemListView* m_gemListView = nullptr; GemInspector* m_gemInspector = nullptr; diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 981a9352f7..6aba261cd2 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -94,7 +94,7 @@ namespace O3DE::ProjectManager Update(); // Gather the available gems that will be shown in the gem catalog. - m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false); + m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path); } void UpdateProjectCtrl::HandleGemsButton() From 69bde80de3a35f2aa1b745304709ec75f8d64c0a Mon Sep 17 00:00:00 2001 From: sharmajs-amzn <82233357+sharmajs-amzn@users.noreply.github.com> Date: Tue, 3 Aug 2021 11:15:23 -0700 Subject: [PATCH 132/157] Nighly build test fixes (#2727) Signed-off-by: sharmajs-amzn <82233357+sharmajs-amzn@users.noreply.github.com> --- .../assetpipeline/asset_processor_tests/CMakeLists.txt | 2 +- .../asset_processor_tests/asset_builder_tests.py | 2 +- .../asset_processor_tests/asset_bundler_batch_tests.py | 9 +++++++-- Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt index 8b9de91906..0170d73af0 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt @@ -97,7 +97,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) PATH ${CMAKE_CURRENT_LIST_DIR}/asset_bundler_batch_tests.py EXCLUDE_TEST_RUN_TARGET_FROM_IDE TEST_SERIAL - TIMEOUT 1500 + TIMEOUT 2400 TEST_SUITE periodic RUNTIME_DEPENDENCIES AZ::AssetProcessor diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_builder_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_builder_tests.py index 13b899dfdd..2c805f0291 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_builder_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_builder_tests.py @@ -113,7 +113,7 @@ class TestsAssetBuilder_WindowsAndMac(object): if listening_port: corrupted_slice_command.append(f'-port={listening_port}') if workspace.project: - corrupted_slice_command.append(f'-gamename={workspace.project}') + corrupted_slice_command.append(f'--project-path={workspace.project}') corrupted_slice_output = utils.safe_subprocess(corrupted_slice_command) # Verify corrupted slice produced error diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py index 768dd985fd..7f85e5e317 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py @@ -902,7 +902,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): second_input_arg = asset_lists_to_string(second_asset_list) # --secondAssetList output_arg = asset_lists_to_string(output_file) # --output - def generate_compare_command(platform_arg: str) -> object: + def generate_compare_command(platform_arg: str, project_name : str) -> object: """Creates a string containing a full Compare command. This string can be executed as-is.""" cmd = [helper["bundler_batch"], "compare", f"--firstassetFile={first_input_arg}", f"--output={output_arg}"] if platform_arg is not None: @@ -918,6 +918,8 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): if comp_type == "4": # Extra arguments for pattern comparison cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"]) + if workspace.project: + cmd.append(f'--project-path={project_name}') return cmd # End generate_compare_command() @@ -936,6 +938,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # End verify_asset_list_contents() def run_compare_command_and_verify(platform_arg: str, expect_pc_output: bool, expect_mac_output: bool) -> None: + # Expected asset list to equal result of comparison expected_pc_asset_list = None expected_mac_asset_list = None @@ -957,7 +960,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): output_mac_asset_list = helper.platform_file_name(last_output_arg, platform) # Build execution command - cmd = generate_compare_command(platform_arg) + cmd = generate_compare_command(platform_arg, workspace.project) # Execute command subprocess.check_call(cmd) @@ -992,10 +995,12 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): f"--comparisonRulesFile={rule_file}", f"--comparisonType={args[1]}", r"--addComparison", + f"--project-path={workspace.project}", ] if args[1] == "4": # If pattern comparison, append a few extra arguments cmd.extend(["--filePatternType=0", "--filePattern=*.dat"]) + subprocess.check_call(cmd) assert os.path.exists(rule_file), f"Rule file {args[0]} was not created at location: {rule_file}" diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py index 50021080fe..57454930eb 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py @@ -594,7 +594,7 @@ class AssetProcessor(object): output_list = None if capture_output: if decode: - output_list = run_result.stdout.decode('utf-8').splitlines() + output_list = run_result.stdout.decode('utf-8', errors="replace").splitlines() else: output_list = run_result.stdout.splitlines() From a0f3379999280200d74d3ddae0bf121f55097223 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Tue, 3 Aug 2021 14:08:59 -0700 Subject: [PATCH 133/157] Adds Light component tests (non-GPU portion) to AutomatedTesting from AtomTest (#2758) * Fixed Vegetation Layer Spawner documentation link. Signed-off-by: Chris Galvan Signed-off-by: jromnoa * add remaining non-GPU test portions for Light component test Signed-off-by: jromnoa * make non-GPU light component test more robust Signed-off-by: jromnoa * remove redundant logging, convert LIGHT_TYPES from list to dict, remove redundant f-string Signed-off-by: jromnoa Co-authored-by: Chris Galvan --- .../PythonTests/atom_renderer/CMakeLists.txt | 2 +- ...dra_AtomEditorComponents_LightComponent.py | 217 ++++++++++++++++++ .../atom_utils/atom_component_helper.py | 19 ++ .../atom_renderer/test_Atom_MainSuite.py | 64 +++++- 4 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_LightComponent.py create mode 100644 AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_component_helper.py diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt index a342d95d98..d4f036faeb 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt @@ -17,7 +17,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT TEST_SUITE main PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_MainSuite.py TEST_SERIAL - TIMEOUT 400 + TIMEOUT 600 RUNTIME_DEPENDENCIES AssetProcessor AutomatedTesting.Assets diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_LightComponent.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_LightComponent.py new file mode 100644 index 0000000000..ec8dc199ae --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_LightComponent.py @@ -0,0 +1,217 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT + +Hydra script that creates an entity, attaches the Light component to it for test verifications. +The test verifies that each light type option is available and can be selected without errors. +""" + +import os +import sys + +import azlmbr.bus as bus +import azlmbr.editor as editor +import azlmbr.math as math +import azlmbr.paths +import azlmbr.legacy.general as general + +sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests")) + +import editor_python_test_tools.hydra_editor_utils as hydra +from atom_renderer.atom_utils.atom_component_helper import LIGHT_TYPES + +LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type' +SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES = [ + ("Controller|Configuration|Shadows|Enable shadow", True), + ("Controller|Configuration|Shadows|Shadowmap size", 0), # 256 + ("Controller|Configuration|Shadows|Shadowmap size", 1), # 512 + ("Controller|Configuration|Shadows|Shadowmap size", 2), # 1024 + ("Controller|Configuration|Shadows|Shadowmap size", 3), # 2048 + ("Controller|Configuration|Shadows|Shadow filter method", 1), # PCF + ("Controller|Configuration|Shadows|Filtering sample count", 4.0), + ("Controller|Configuration|Shadows|Filtering sample count", 64.0), + ("Controller|Configuration|Shadows|PCF method", 0), # Bicubic + ("Controller|Configuration|Shadows|PCF method", 1), # Boundary search + ("Controller|Configuration|Shadows|Shadow filter method", 2), # ECM + ("Controller|Configuration|Shadows|ESM exponent", 50), + ("Controller|Configuration|Shadows|ESM exponent", 5000), + ("Controller|Configuration|Shadows|Shadow filter method", 3), # ESM+PCF +] +QUAD_LIGHT_PROPERTIES = [ + ("Controller|Configuration|Both directions", True), + ("Controller|Configuration|Fast approximation", True), +] +SIMPLE_POINT_LIGHT_PROPERTIES = [ + ("Controller|Configuration|Attenuation radius|Mode", 0), + ("Controller|Configuration|Attenuation radius|Radius", 100.0), +] +SIMPLE_SPOT_LIGHT_PROPERTIES = [ + ("Controller|Configuration|Shutters|Inner angle", 45.0), + ("Controller|Configuration|Shutters|Outer angle", 90.0), +] + + +def verify_required_component_property_value(entity_name, component, property_path, expected_property_value): + """ + Compares the property value of component against the expected_property_value. + :param entity_name: name of the entity to use (for test verification purposes). + :param component: component to check on a given entity for its current property value. + :param property_path: the path to the property inside the component. + :param expected_property_value: The value expected from the value inside property_path. + :return: None, but prints to general.log() which the test uses to verify against. + """ + property_value = editor.EditorComponentAPIBus( + bus.Broadcast, "GetComponentProperty", component, property_path).GetValue() + general.log(f"{entity_name}_test: Property value is {property_value} " + f"which matches {expected_property_value}") + + +def run(): + """ + Test Case - Light Component + 1. Creates a "light_entity" Entity and attaches a "Light" component to it. + 2. Updates the Light component to each light type option from the LIGHT_TYPES constant. + 3. The test will check the Editor log to ensure each light type was selected. + 4. Prints the string "Light component test (non-GPU) completed" after completion. + + Tests will fail immediately if any of these log lines are found: + 1. Trace::Assert + 2. Trace::Error + 3. Traceback (most recent call last): + + :return: None + """ + # Create a "light_entity" entity with "Light" component. + light_entity_name = "light_entity" + light_component = "Light" + light_entity = hydra.Entity(light_entity_name) + light_entity.create_entity(math.Vector3(-1.0, -2.0, 3.0), [light_component]) + general.log( + f"{light_entity_name}_test: Component added to the entity: " + f"{hydra.has_components(light_entity.id, [light_component])}") + + # Populate the light_component_id_pair value so that it can be used to select all Light component options. + light_component_id_pair = None + component_type_id_list = azlmbr.editor.EditorComponentAPIBus( + azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', [light_component], 0) + if len(component_type_id_list) < 1: + general.log(f"ERROR: A component class with name {light_component} doesn't exist") + light_component_id_pair = None + elif len(component_type_id_list) > 1: + general.log(f"ERROR: Found more than one component classes with same name: {light_component}") + light_component_id_pair = None + entity_component_id_pair = azlmbr.editor.EditorComponentAPIBus( + azlmbr.bus.Broadcast, 'GetComponentOfType', light_entity.id, component_type_id_list[0]) + if entity_component_id_pair.IsSuccess(): + light_component_id_pair = entity_component_id_pair.GetValue() + + # Test each Light component option can be selected and it's properties updated. + # Point (sphere) light type checks. + light_type_property_test( + light_type=LIGHT_TYPES['sphere'], + light_properties=SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES, + light_component_id_pair=light_component_id_pair, + light_entity_name=light_entity_name, + light_entity=light_entity + ) + + # Spot (disk) light type checks. + light_type_property_test( + light_type=LIGHT_TYPES['spot_disk'], + light_properties=SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES, + light_component_id_pair=light_component_id_pair, + light_entity_name=light_entity_name, + light_entity=light_entity + ) + + # Capsule light type checks. + azlmbr.editor.EditorComponentAPIBus( + azlmbr.bus.Broadcast, + 'SetComponentProperty', + light_component_id_pair, + LIGHT_TYPE_PROPERTY, + LIGHT_TYPES['capsule'] + ) + verify_required_component_property_value( + entity_name=light_entity_name, + component=light_entity.components[0], + property_path=LIGHT_TYPE_PROPERTY, + expected_property_value=LIGHT_TYPES['capsule'] + ) + + # Quad light type checks. + light_type_property_test( + light_type=LIGHT_TYPES['quad'], + light_properties=QUAD_LIGHT_PROPERTIES, + light_component_id_pair=light_component_id_pair, + light_entity_name=light_entity_name, + light_entity=light_entity + ) + + # Polygon light type checks. + azlmbr.editor.EditorComponentAPIBus( + azlmbr.bus.Broadcast, + 'SetComponentProperty', + light_component_id_pair, + LIGHT_TYPE_PROPERTY, + LIGHT_TYPES['polygon'] + ) + verify_required_component_property_value( + entity_name=light_entity_name, + component=light_entity.components[0], + property_path=LIGHT_TYPE_PROPERTY, + expected_property_value=LIGHT_TYPES['polygon'] + ) + + # Point (simple punctual) light type checks. + light_type_property_test( + light_type=LIGHT_TYPES['simple_point'], + light_properties=SIMPLE_POINT_LIGHT_PROPERTIES, + light_component_id_pair=light_component_id_pair, + light_entity_name=light_entity_name, + light_entity=light_entity + ) + + # Spot (simple punctual) light type checks. + light_type_property_test( + light_type=LIGHT_TYPES['simple_spot'], + light_properties=SIMPLE_SPOT_LIGHT_PROPERTIES, + light_component_id_pair=light_component_id_pair, + light_entity_name=light_entity_name, + light_entity=light_entity + ) + + general.log("Light component test (non-GPU) completed.") + + +def light_type_property_test(light_type, light_properties, light_component_id_pair, light_entity_name, light_entity): + """ + Updates the current light type and modifies its properties, then verifies they are accurate to what was set. + :param light_type: The type of light to update, must match a value in LIGHT_TYPES + :param light_properties: List of tuples detailing properties to modify with update values. + :param light_component_id_pair: Entity + component ID pair for updating the light component on a given entity. + :param light_entity_name: the name of the Entity holding the light component. + :param light_entity: the Entity object containing the light component. + :return: None + """ + azlmbr.editor.EditorComponentAPIBus( + azlmbr.bus.Broadcast, + 'SetComponentProperty', + light_component_id_pair, + LIGHT_TYPE_PROPERTY, + light_type + ) + verify_required_component_property_value( + entity_name=light_entity_name, + component=light_entity.components[0], + property_path=LIGHT_TYPE_PROPERTY, + expected_property_value=light_type + ) + + for light_property in light_properties: + light_entity.get_set_test(0, light_property[0], light_property[1]) + + +if __name__ == "__main__": + run() diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_component_helper.py new file mode 100644 index 0000000000..de4e28bb36 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_component_helper.py @@ -0,0 +1,19 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT + +File to assist with common hydra component functions or constants used across various Atom tests. +""" + +# Light type options for the Light component. +LIGHT_TYPES = { + 'unknown': 0, + 'sphere': 1, + 'spot_disk': 2, + 'capsule': 3, + 'quad': 4, + 'polygon': 5, + 'simple_point': 6, + 'simple_spot': 7, +} diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py index ed5d057626..98d2ba0632 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py @@ -12,9 +12,10 @@ import os import pytest import editor_python_test_tools.hydra_test_utils as hydra +from atom_renderer.atom_utils.atom_component_helper import LIGHT_TYPES logger = logging.getLogger(__name__) -EDITOR_TIMEOUT = 300 +EDITOR_TIMEOUT = 120 TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts") @@ -180,3 +181,64 @@ class TestAtomEditorComponentsMain(object): null_renderer=True, cfg_args=cfg_args, ) + + def test_AtomEditorComponents_LightComponent( + self, request, editor, workspace, project, launcher_platform, level): + """ + Please review the hydra script run by this test for more specific test info. + Tests that the Light component has the expected property options available to it. + """ + cfg_args = [level] + + expected_lines = [ + "light_entity Entity successfully created", + "Entity has a Light component", + "light_entity_test: Component added to the entity: True", + f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}", + "Controller|Configuration|Shadows|Enable shadow set to True", + "light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS", + "Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF + "Controller|Configuration|Shadows|Filtering sample count set to 4", + "Controller|Configuration|Shadows|Filtering sample count set to 64", + "Controller|Configuration|Shadows|PCF method set to 0", + "Controller|Configuration|Shadows|PCF method set to 1", + "Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM + "Controller|Configuration|Shadows|ESM exponent set to 50.0", + "Controller|Configuration|Shadows|ESM exponent set to 5000.0", + "Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF + f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}", + f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}", + f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}", + "light_entity Controller|Configuration|Fast approximation: SUCCESS", + "light_entity Controller|Configuration|Both directions: SUCCESS", + f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}", + f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} " + f"which matches {LIGHT_TYPES['simple_point']}", + "Controller|Configuration|Attenuation radius|Mode set to 0", + "Controller|Configuration|Attenuation radius|Radius set to 100.0", + f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} " + f"which matches {LIGHT_TYPES['simple_spot']}", + "Controller|Configuration|Shutters|Outer angle set to 45.0", + "Controller|Configuration|Shutters|Outer angle set to 90.0", + "light_entity_test: Component added to the entity: True", + "Light component test (non-GPU) completed.", + ] + + unexpected_lines = [ + "Trace::Assert", + "Trace::Error", + "Traceback (most recent call last):", + ] + + hydra.launch_and_validate_results( + request, + TEST_DIRECTORY, + editor, + "hydra_AtomEditorComponents_LightComponent.py", + timeout=EDITOR_TIMEOUT, + expected_lines=expected_lines, + unexpected_lines=unexpected_lines, + halt_on_unexpected=True, + null_renderer=True, + cfg_args=cfg_args, + ) From 24740b3f8609c9af836d4bf13dd393a2f049ea26 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 3 Aug 2021 14:52:53 -0700 Subject: [PATCH 134/157] Update the cloth rule to look for optimized meshes (#2737) The cloth rule stores the name of a mesh node that is used to retrieve cloth data from. However, at asset processing time, the model builder switches things to look for the optimized version of a mesh. The cloth rule was not doing this, so it would return the cloth data for the unoptimized mesh. This resulted in the final mesh having some data from the optimized mesh and cloth data from the non-optimized mesh. This changes the cloth rule to use the optimized version of a mesh, if it exists, and fall back to the unoptimized mesh when it does not exist. This closes issue 2454. Signed-off-by: Chris Burel --- .../RPI.Builders/Model/ModelAssetBuilderComponent.cpp | 2 +- .../Code/Source/Pipeline/SceneAPIExt/ClothRule.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index 7100b2cd48..76e427a708 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -109,7 +109,7 @@ namespace AZ if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(29); // (updated to separate material slot ID from default material asset) + ->Version(30); // (updated to separate material slot ID from default material asset) } } diff --git a/Gems/NvCloth/Code/Source/Pipeline/SceneAPIExt/ClothRule.cpp b/Gems/NvCloth/Code/Source/Pipeline/SceneAPIExt/ClothRule.cpp index 383ea9e5f6..a2683be2ab 100644 --- a/Gems/NvCloth/Code/Source/Pipeline/SceneAPIExt/ClothRule.cpp +++ b/Gems/NvCloth/Code/Source/Pipeline/SceneAPIExt/ClothRule.cpp @@ -37,7 +37,15 @@ namespace NvCloth const AZ::SceneAPI::Containers::SceneGraph& graph, const size_t numVertices) const { - const auto meshNodeIndex = graph.Find(GetMeshNodeName()); + const AZ::SceneAPI::Containers::SceneGraph::NodeIndex meshNodeIndex = [this, &graph]() + { + if (const auto index = graph.Find(GetMeshNodeName() + AZStd::string(AZ::SceneAPI::Utilities::OptimizedMeshSuffix)); index.IsValid()) + { + return index; + } + return graph.Find(GetMeshNodeName()); + }(); + if (!meshNodeIndex.IsValid()) { return {}; From f269d222b7e699ae6fb4f02fdcbcd50a792e959d Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 3 Aug 2021 17:07:03 -0500 Subject: [PATCH 135/157] Fixing issues with shader management console startup Updating test scripts Synchronizing SMC and ME application classes Signed-off-by: Guthrie Adams --- .../Application/AtomToolsApplication.cpp | 6 +-- .../Code/Source/MaterialEditorApplication.cpp | 10 ++-- .../Scripts/GenerateAllMaterialScreenshots.py | 4 +- .../ShaderManagementConsoleApplication.cpp | 48 ++++++++++--------- .../ShaderManagementConsoleApplication.h | 7 +-- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index 3a542db1a4..3d9219edc5 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -87,14 +87,12 @@ namespace AtomToolsFramework if (auto behaviorContext = azrtti_cast(context)) { - auto targetName = GetBuildTargetName(); - // this will put these methods into the 'azlmbr.AtomTools.general' module - auto addGeneral = [targetName](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder) + auto addGeneral = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder) { methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) ->Attribute(AZ::Script::Attributes::Category, "Editor") - ->Attribute(AZ::Script::Attributes::Module, targetName); + ->Attribute(AZ::Script::Attributes::Module, "atomtools.general"); }; // The reflection here is based on patterns in CryEditPythonHandler::Reflect addGeneral(behaviorContext->Method( diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp index 0977694b90..c68c139961 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -28,11 +27,11 @@ #include -#include #include #include #include +#include #include #include #include @@ -73,15 +72,14 @@ namespace MaterialEditor { QApplication::setApplicationName("O3DE Material Editor"); + // The settings registry has been created at this point, so add the CMake target AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization( *AZ::SettingsRegistry::Get(), GetBuildTargetName()); } MaterialEditorApplication::~MaterialEditorApplication() { - AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect(); MaterialEditorWindowNotificationBus::Handler::BusDisconnect(); - AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect(); } void MaterialEditorApplication::CreateStaticModules(AZStd::vector& outModules) @@ -122,8 +120,8 @@ namespace MaterialEditor &MaterialEditor::MaterialEditorWindowRequestBus::Handler::ActivateWindow); } - // Process command line options for opening one or more material documents on startup - size_t openDocumentCount = commandLine.GetNumMiscValues(); + // Process command line options for opening one or more documents on startup + size_t openDocumentCount = m_commandLine.GetNumMiscValues(); for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex) { const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex); diff --git a/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py b/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py index d2c9bf209e..d7f52d7a24 100755 --- a/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py +++ b/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py @@ -114,11 +114,11 @@ def SetCameraPitch(pitch): azlmbr.render.ArcBallControllerRequestBus(azlmbr.bus.Broadcast, 'SetPitch', pitch) def IdleFrames(numFrames): - azlmbr.materialeditor.general.idle_wait_frames(numFrames) + azlmbr.atomtools.general.idle_wait_frames(numFrames) def CaptureScreenshot(screenshotOutputPath): print("Capturing screenshot to " + screenshotOutputPath + " ...") - return ScreenshotHelper(azlmbr.materialeditor.general.idle_wait_frames).capture_screenshot_blocking(screenshotOutputPath) + return ScreenshotHelper(azlmbr.atomtools.general.idle_wait_frames).capture_screenshot_blocking(screenshotOutputPath) def ResizeViewport(width, height): # This locks the size of the render target to the desired resolution diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp index 7e09f88f4f..66580e5906 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp @@ -25,26 +25,27 @@ #include #include -#include -#include #include -#include -#include +#include +#include #include #include #include #include +#include +#include + AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include #include #include AZ_POP_DISABLE_WARNING namespace ShaderManagementConsole { + //! This function returns the build system target name of "ShaderManagementConsole AZStd::string ShaderManagementConsoleApplication::GetBuildTargetName() const { #if !defined(LY_CMAKE_TARGET) @@ -74,6 +75,11 @@ namespace ShaderManagementConsole *AZ::SettingsRegistry::Get(), GetBuildTargetName()); } + ShaderManagementConsoleApplication::~ShaderManagementConsoleApplication() + { + ShaderManagementConsoleWindowNotificationBus::Handler::BusDisconnect(); + } + void ShaderManagementConsoleApplication::CreateStaticModules(AZStd::vector& outModules) { Base::CreateStaticModules(outModules); @@ -84,8 +90,6 @@ namespace ShaderManagementConsole void ShaderManagementConsoleApplication::OnShaderManagementConsoleWindowClosing() { ExitMainLoop(); - ShaderManagementConsoleWindowNotificationBus::Handler::BusDisconnect(); - AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect(); } void ShaderManagementConsoleApplication::Destroy() @@ -104,27 +108,19 @@ namespace ShaderManagementConsole return AZStd::vector({ "passes/", "config/" }); } - void ShaderManagementConsoleApplication::ProcessCommandLine() + void ShaderManagementConsoleApplication::ProcessCommandLine(const AZ::CommandLine& commandLine) { - // Process command line options for running one or more python scripts on startup - const AZStd::string runPythonScriptSwitchName = "runpython"; - size_t runPythonScriptCount = m_commandLine.GetNumSwitchValues(runPythonScriptSwitchName); - for (size_t runPythonScriptIndex = 0; runPythonScriptIndex < runPythonScriptCount; ++runPythonScriptIndex) - { - const AZStd::string runPythonScriptPath = m_commandLine.GetSwitchValue(runPythonScriptSwitchName, runPythonScriptIndex); - AZStd::vector runPythonArgs; - AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast( - &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, runPythonScriptPath, runPythonArgs); - } - // Process command line options for opening one or more documents on startup size_t openDocumentCount = m_commandLine.GetNumMiscValues(); for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex) { - const AZStd::string openDocumentPath = m_commandLine.GetMiscValue(openDocumentIndex); - ShaderManagementConsoleDocumentSystemRequestBus::Broadcast( - &ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath); + const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex); + + AZ_Printf(GetBuildTargetName().c_str(), "Opening document: %s", openDocumentPath.c_str()); + ShaderManagementConsoleDocumentSystemRequestBus::Broadcast(&ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath); } + + Base::ProcessCommandLine(commandLine); } void ShaderManagementConsoleApplication::StartInternal() @@ -136,4 +132,12 @@ namespace ShaderManagementConsole ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast( &ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::CreateShaderManagementConsoleWindow); } + + void ShaderManagementConsoleApplication::Stop() + { + ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast( + &ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::DestroyShaderManagementConsoleWindow); + + Base::Stop(); + } } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h index 5d3696fee3..d0a2b800b2 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h @@ -26,12 +26,13 @@ namespace ShaderManagementConsole using Base = AtomToolsFramework::AtomToolsApplication; ShaderManagementConsoleApplication(int* argc, char*** argv); - virtual ~ShaderManagementConsoleApplication() = default; + virtual ~ShaderManagementConsoleApplication(); ////////////////////////////////////////////////////////////////////////// // AzFramework::Application void CreateStaticModules(AZStd::vector& outModules) override; const char* GetCurrentConfigurationName() const override; + void Stop() override; private: ////////////////////////////////////////////////////////////////////////// @@ -44,9 +45,9 @@ namespace ShaderManagementConsole void Destroy() override; ////////////////////////////////////////////////////////////////////////// - void ProcessCommandLine(); + void ProcessCommandLine(const AZ::CommandLine& commandLine) override; void StartInternal() override; AZStd::string GetBuildTargetName() const override; AZStd::vector GetCriticalAssetFilters() const override; - }; + }; } // namespace ShaderManagementConsole From b594132a47b834570763eb3bbac15110f4356de1 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 3 Aug 2021 17:19:30 -0500 Subject: [PATCH 136/157] using command line parameter instead of member Signed-off-by: Guthrie Adams --- .../MaterialEditor/Code/Source/MaterialEditorApplication.cpp | 2 +- .../Code/Source/ShaderManagementConsoleApplication.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp index c68c139961..6f1bdfb083 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp @@ -121,7 +121,7 @@ namespace MaterialEditor } // Process command line options for opening one or more documents on startup - size_t openDocumentCount = m_commandLine.GetNumMiscValues(); + size_t openDocumentCount = commandLine.GetNumMiscValues(); for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex) { const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex); diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp index 66580e5906..947cf55050 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp @@ -111,7 +111,7 @@ namespace ShaderManagementConsole void ShaderManagementConsoleApplication::ProcessCommandLine(const AZ::CommandLine& commandLine) { // Process command line options for opening one or more documents on startup - size_t openDocumentCount = m_commandLine.GetNumMiscValues(); + size_t openDocumentCount = commandLine.GetNumMiscValues(); for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex) { const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex); From 6188df4b4964e303d2bc8e83d7bc2091a33f1146 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Tue, 3 Aug 2021 15:36:56 -0700 Subject: [PATCH 137/157] Added Get Direction Vector node for Vector2,3 and 4 Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../Editor/Translation/scriptcanvas_en_us.ts | 195 ++++++++++++++++++ .../Libraries/Math/Vector2Nodes.h | 17 ++ .../Libraries/Math/Vector3Nodes.h | 18 ++ .../Libraries/Math/Vector4Nodes.h | 19 +- 4 files changed, 248 insertions(+), 1 deletion(-) diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts index f057ba2f30..5604cfb631 100644 --- a/Assets/Editor/Translation/scriptcanvas_en_us.ts +++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts @@ -2771,6 +2771,71 @@ VECTOR2_CREATEONE_OUTPUT0_TOOLTIP + + VECTOR2_DIRECTIONTO_NAME + Class/Bus: Vector2 Event/Method: DirectionTo + Get Direction Vector + + + VECTOR2_DIRECTIONTO_TOOLTIP + + + + VECTOR2_DIRECTIONTO_CATEGORY + + + + VECTOR2_DIRECTIONTO_OUT_NAME + + + + VECTOR2_DIRECTIONTO_OUT_TOOLTIP + + + + VECTOR2_DIRECTIONTOL_IN_NAME + + + + VECTOR2_DIRECTIONTO_IN_TOOLTIP + + + + VECTOR2_DIRECTIONTO_OUTPUT0_NAME + C++ Type: const Vector2 + Direction + + + VECTOR2_DIRECTIONTO_OUTPUT0_TOOLTIP + + + + VECTOR2_DIRECTIONTO_PARAM0_NAME + Simple Type: Vector2 C++ Type: Vector2* + From + + + VECTOR2_DIRECTIONTO_PARAM0_TOOLTIP + + + + VECTOR2_DIRECTIONTO_PARAM1_NAME + Simple Type: Vector2 C++ Type: Vector2* + To + + + VECTOR2_DIRECTIONTO_PARAM1_TOOLTIP + + + + VECTOR2_DIRECTIONTO_PARAM2_NAME + Simple Type: Vector2 C++ Type: Vector2* + Scale + + + VECTOR2_DIRECTIONTO_PARAM2_TOOLTIP + + VECTOR2_GETPROJECTED_NAME Class/Bus: Vector2 Event/Method: GetProjected @@ -32262,6 +32327,71 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR4_GETRECIPROCAL_PARAM0_TOOLTIP + + VECTOR4_DIRECTIONTO_NAME + Class/Bus: Vector4 Event/Method: DirectionTo + Get Direction Vector + + + VECTOR4_DIRECTIONTO_TOOLTIP + + + + VECTOR4_DIRECTIONTO_CATEGORY + + + + VECTOR4_DIRECTIONTO_OUT_NAME + + + + VECTOR4_DIRECTIONTO_OUT_TOOLTIP + + + + VECTOR4_DIRECTIONTOL_IN_NAME + + + + VECTOR4_DIRECTIONTO_IN_TOOLTIP + + + + VECTOR4_DIRECTIONTO_OUTPUT0_NAME + C++ Type: const Vector4 + Direction + + + VECTOR4_DIRECTIONTO_OUTPUT0_TOOLTIP + + + + VECTOR4_DIRECTIONTO_PARAM0_NAME + Simple Type: Vector4 C++ Type: Vector4* + From + + + VECTOR4_DIRECTIONTO_PARAM0_TOOLTIP + + + + VECTOR4_DIRECTIONTO_PARAM1_NAME + Simple Type: Vector4 C++ Type: Vector4* + To + + + VECTOR4_DIRECTIONTO_PARAM1_TOOLTIP + + + + VECTOR4_DIRECTIONTO_PARAM2_NAME + Simple Type: Vector4 C++ Type: Vector4* + Scale + + + VECTOR4_DIRECTIONTO_PARAM2_TOOLTIP + + VECTOR4_AXISX_NAME Class/Bus: Vector4 Event/Method: CreateAxisX @@ -37469,6 +37599,71 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR3_GETRECIPROCAL_PARAM0_TOOLTIP + + VECTOR3_DIRECTIONTO_NAME + Class/Bus: Vector3 Event/Method: DirectionTo + Get Direction Vector + + + VECTOR3_DIRECTIONTO_TOOLTIP + + + + VECTOR3_DIRECTIONTO_CATEGORY + + + + VECTOR3_DIRECTIONTO_OUT_NAME + + + + VECTOR3_DIRECTIONTO_OUT_TOOLTIP + + + + VECTOR3_DIRECTIONTOL_IN_NAME + + + + VECTOR3_DIRECTIONTO_IN_TOOLTIP + + + + VECTOR3_DIRECTIONTO_OUTPUT0_NAME + C++ Type: const Vector3 + Direction + + + VECTOR3_DIRECTIONTO_OUTPUT0_TOOLTIP + + + + VECTOR3_DIRECTIONTO_PARAM0_NAME + Simple Type: Vector3 C++ Type: Vector3* + From + + + VECTOR3_DIRECTIONTO_PARAM0_TOOLTIP + + + + VECTOR3_DIRECTIONTO_PARAM1_NAME + Simple Type: Vector3 C++ Type: Vector3* + To + + + VECTOR3_DIRECTIONTO_PARAM1_TOOLTIP + + + + VECTOR3_DIRECTIONTO_PARAM2_NAME + Simple Type: Vector3 C++ Type: Vector3* + Scale + + + VECTOR3_DIRECTIONTO_PARAM2_TOOLTIP + + VECTOR3_PROJECT_NAME Class/Bus: Vector3 Event/Method: Project diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h index c4fee491a3..4ac14a7db6 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h @@ -243,6 +243,22 @@ namespace ScriptCanvas } SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(ToPerpendicular, k_categoryName, "{CC4DC102-8B50-4828-BA94-0586F34E0D37}", "returns the vector (-Source.y, Source.x), a 90 degree, positive rotation", "Source"); + AZ_INLINE void DirectionToDefaults(Node& node) + { + SetDefaultValuesByIndex<0>::_(node, Data::Vector2Type()); + SetDefaultValuesByIndex<1>::_(node, Data::Vector2Type()); + SetDefaultValuesByIndex<2>::_(node, Data::NumberType(1.)); + } + + AZ_INLINE Vector2Type DirectionTo(const Vector2Type from, const Vector2Type to, NumberType optionalScale = 1.f) + { + Vector2Type r = to - from; + r.Normalize(); + r.SetLength(optionalScale); + return r; + } + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{49A2D7F6-6CD3-420E-8A79-D46B00DB6CED}", "Given two points in space, return a direction vector", "From", "To", "Scale"); + using Registrar = RegistrarGeneric < AbsoluteNode , AddNode @@ -295,6 +311,7 @@ namespace ScriptCanvas , SlerpNode , SubtractNode , ToPerpendicularNode + , DirectionToNode > ; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h index 5962cee487..eb304c8362 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h @@ -329,6 +329,23 @@ namespace ScriptCanvas } SCRIPT_CANVAS_GENERIC_FUNCTION_NODE(ZAxisCross, k_categoryName, "{29206E84-392C-412E-9DD5-781B2759260D}", "returns the vector cross product of Z-Axis X Source", "Source"); + AZ_INLINE void DirectionToDefaults(Node& node) + { + SetDefaultValuesByIndex<0>::_(node, Data::Vector3Type()); + SetDefaultValuesByIndex<1>::_(node, Data::Vector3Type()); + SetDefaultValuesByIndex<2>::_(node, Data::NumberType(1.)); + } + + AZ_INLINE Vector3Type DirectionTo(const Vector3Type from, const Vector3Type to, NumberType optionalScale = 1.f) + { + Vector3Type r = to - from; + r.Normalize(); + r.SetLength(optionalScale); + return r; + } + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{28FBD529-4C9A-4E34-B8A0-A13B5DB3C331}", "Given two points in space, return a direction vector", "From", "To", "Scale"); + + using Registrar = RegistrarGeneric < AbsoluteNode , AddNode @@ -403,6 +420,7 @@ namespace ScriptCanvas , SlerpNode , SubtractNode + , DirectionToNode #if ENABLE_EXTENDED_MATH_SUPPORT , XAxisCrossNode diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h index 4522ba07dc..ac9be8f135 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h @@ -214,6 +214,22 @@ namespace ScriptCanvas } SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_DEPRECATED(Subtract, k_categoryName, "{A5FA6465-9C39-4A44-BD7C-E8ECF9503E46}", "This node is deprecated, use Subtract (-), it provides contextual type and slots", "A", "B"); + AZ_INLINE void DirectionToDefaults(Node& node) + { + SetDefaultValuesByIndex<0>::_(node, Data::Vector4Type()); + SetDefaultValuesByIndex<1>::_(node, Data::Vector4Type()); + SetDefaultValuesByIndex<2>::_(node, Data::NumberType(1.)); + } + + AZ_INLINE Vector4Type DirectionTo(const Vector4Type from, const Vector4Type to, NumberType optionalScale = 1.f) + { + Vector4Type r = to - from; + r.Normalize(); + r.SetLength(optionalScale); + return r; + } + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{463762DE-E541-4AFE-80C2-FED1C5273319}", "Given two points in space, return a direction vector", "From", "To", "Scale"); + using Registrar = RegistrarGeneric < AbsoluteNode, AddNode, @@ -260,7 +276,8 @@ namespace ScriptCanvas #endif ReciprocalNode, - SubtractNode + SubtractNode, + DirectionToNode > ; } From 45ebf57d3f9bb42767894240e4fc701d5f5d9a34 Mon Sep 17 00:00:00 2001 From: AMZN-AlexOteiza <82234181+AMZN-AlexOteiza@users.noreply.github.com> Date: Wed, 4 Aug 2021 02:38:18 +0100 Subject: [PATCH 138/157] Fixed bug in hash_table that made rehash() function run forever (#2745) * Fixed bug in hash_table that made rehash() function to run infinitely on specific conditions when inserting an already existing element Signed-off-by: Garcia Ruiz * Replaced erasing to happen in the source list instead Signed-off-by: Garcia Ruiz * minor comment improvement Signed-off-by: Garcia Ruiz * Small commment improvement Signed-off-by: Garcia Ruiz * Small comment fix Signed-off-by: Garcia Ruiz * Added assert and fixed code with incorrect hashing Signed-off-by: Garcia Ruiz * . Signed-off-by: Garcia Ruiz * Addressed PR comments, reverted to void* as it size_t hash is different Signed-off-by: Garcia Ruiz * Fixed build on linux Signed-off-by: Garcia Ruiz * Addressed PR comments Signed-off-by: Garcia Ruiz Co-authored-by: Garcia Ruiz --- Code/Framework/AzCore/AzCore/std/hash.cpp | 1 + Code/Framework/AzCore/AzCore/std/hash_table.h | 68 ++++++++++++------- Code/Framework/AzCore/Tests/AZStd/Hashed.cpp | 49 +++++++++++++ .../PhysXSceneSimulationFilterCallback.cpp | 4 +- 4 files changed, 95 insertions(+), 27 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/std/hash.cpp b/Code/Framework/AzCore/AzCore/std/hash.cpp index c2f7a104d4..b5277de2f4 100644 --- a/Code/Framework/AzCore/AzCore/std/hash.cpp +++ b/Code/Framework/AzCore/AzCore/std/hash.cpp @@ -21,6 +21,7 @@ namespace AZStd 1610612741ul, 3221225473ul, 4294967291ul }; + // Bucket size suitable to hold n elements. AZStd::size_t hash_next_bucket_size(AZStd::size_t n) { const AZStd::size_t* first = prime_list; diff --git a/Code/Framework/AzCore/AzCore/std/hash_table.h b/Code/Framework/AzCore/AzCore/std/hash_table.h index 5b76b6cb82..c364720b3b 100644 --- a/Code/Framework/AzCore/AzCore/std/hash_table.h +++ b/Code/Framework/AzCore/AzCore/std/hash_table.h @@ -134,6 +134,7 @@ namespace AZStd void rehash(HashTable* table, size_type numBucketsMin) { size_type num_buckets = 0; + numBucketsMin = (AZStd::max)(numBucketsMin, (size_type)ceilf((float)m_list.size() / m_max_load_factor)); if (numBucketsMin != 0) @@ -143,7 +144,7 @@ namespace AZStd if (num_buckets == m_numBuckets) { - return; // no point + return; // no need yet to rehash } m_numBuckets = num_buckets; @@ -165,32 +166,43 @@ namespace AZStd while (!m_list.empty()) { cur = m_list.begin(); + typename list_type::iterator insertIter, curEnd(cur); + const typename HashTable::key_type& valueKey = Traits::key_from_value(*cur); - typename list_type::iterator newIter, iter(cur); size_type numValues = 1; - for (++iter; iter != last && table->m_keyEqual(Traits::key_from_value(*cur), Traits::key_from_value(*iter)); ++iter, ++numValues) + // Get the number of same consecutive elements in the table with same key, + // this allows range insertion of elements at once + for (++curEnd; curEnd != last && table->m_keyEqual(valueKey, Traits::key_from_value(*curEnd)); ++curEnd, ++numValues) { } - ; - const typename HashTable::key_type& valueKey = Traits::key_from_value(*cur); size_type newBucketIndex = table->bucket_from_hash(table->m_hasher(valueKey)); + + // newBucket.first holds the total number of elements in the bucket + // newBucket.second contains the pointer to the first element in the bucket vector_value_type& newBucket = newBuckets[newBucketIndex]; size_type numElements = newBucket.first; - newIter = newBucket.second; + insertIter = newBucket.second; + + // If we don't have elements in the bucket yet, transfer the elements directly if (numElements == 0) { - newList.splice(newList.begin(), m_list, cur, iter); + newList.splice(newList.begin(), m_list, cur, curEnd); newBucket.second = newList.begin(); } else { - if (!table->find_insert_position(valueKey, table->m_keyEqual, newIter, numElements, integral_constant())) + // Since there are elements already in the bucket, update `insertIter` to where the elements will need to be inserted. + if (!table->find_insert_position(valueKey, table->m_keyEqual, insertIter, numElements, integral_constant())) { - continue; + // An element was found but we don't allow for duplicate elements in this table. + // This happens when there was an insertion of two elements that are equal but have different hashes, + // which is undefined behavior for a hash table: ISO C++ N4713, section 23.14.15 - 5.3 + AZ_Assert(false, "Found a duplicate element when rehashing. " + "Review the hashing function for this type and make sure two equal elements always have the same hash"); } - newList.splice(newIter, m_list, cur, iter); + newList.splice(insertIter, m_list, cur, curEnd); } newBucket.first += numValues; @@ -251,15 +263,15 @@ namespace AZStd m_vector.set_allocator(typename vector_type::allocator_type(&m_allocator)); } - allocator_type m_allocator; ///< The single instance of the allocator shared between list and vector containers. - list_type m_list; ///< List with elements. - vector_type m_vector; ///< Buckets with list iterators. + allocator_type m_allocator; //!< The single instance of the allocator shared between list and vector containers. + list_type m_list; //!< List with elements. + vector_type m_vector; //!< Buckets with list iterators. private: - vector_value_type* m_buckets; ///< Current buckets array. (can point to the m_vector or m_startBucket). - size_type m_numBuckets; ///< Current number of buckets. - float m_max_load_factor; - vector_value_type m_startBucket; ///< Start bucket used for before we start dynamically allocate memory from m_vector. + vector_value_type* m_buckets; //!< Current buckets array. (can point to the m_vector or m_startBucket). + size_type m_numBuckets; //!< Current number of buckets. + float m_max_load_factor; //!< Maximum load (elements/buckets) before rehashing. + vector_value_type m_startBucket; //!< Start bucket used for before we start dynamically allocate memory from m_vector. }; /** @@ -321,8 +333,8 @@ namespace AZStd template AZ_FORCE_INLINE void rehash(HashTable*, size_type) {} - vector_type m_vector; ///< Buckets with list iterators. - list_type m_list; ///< List with elements. + vector_type m_vector; //!< Buckets with list iterators. + list_type m_list; //!< List with elements. }; } @@ -972,28 +984,32 @@ namespace AZStd rhs.clear(); } + // find_insert_position sets insertIter to where the element should be inserted + // and returns true if the element should be inserted, otherwise false template - bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& iter, size_type numElements, const true_type& /* is multi elements */) + bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& insertIter, size_type numElements, const true_type& /* is multi elements */) { - for (size_type i = 0; i < numElements; ++i, ++iter) + for (size_type i = 0; i < numElements; ++i, ++insertIter) { - if (keyEq(keyCmp, Traits::key_from_value(*iter))) + if (keyEq(keyCmp, Traits::key_from_value(*insertIter))) { - ++iter; + ++insertIter; break; } } + // always return true since multi elements (like multiset) allow repeated elements return true; } template - bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& iter, size_type numElements, const false_type& /* !is multi elements */) + bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& insertIter, size_type numElements, const false_type& /* !is multi elements */) { - for (size_type i = 0; i < numElements; ++i, ++iter) + for (size_type i = 0; i < numElements; ++i, ++insertIter) { - if (keyEq(keyCmp, Traits::key_from_value(*iter))) + if (keyEq(keyCmp, Traits::key_from_value(*insertIter))) { + // Element already exists, it shouldn't be inserted as we don't allow more than one repeated element for this specialization return false; } } diff --git a/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp b/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp index f2558289ea..4e4dfc1f89 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp @@ -287,6 +287,55 @@ namespace UnitTest } } + TEST_F(HashedContainers, HashTable_InsertionDuplicateOnRehash) + { + struct TwoPtrs + { + void* m_ptr1; + void* m_ptr2; + + bool operator==(const TwoPtrs& other) const + { + if (m_ptr1 == other.m_ptr1) + { + return m_ptr2 == other.m_ptr2; + } + else if (m_ptr1 == other.m_ptr2) + { + return m_ptr2 == other.m_ptr1; + } + return false; + } + }; + + // This hashing function produces different hashes for two equal values, + // which violates the requirement for hashing functions. + // The test makes sure that this does not reproduce an issue that caused the insert() function to loop infinitely. + struct TwoPtrsHasher + { + size_t operator()(const TwoPtrs& p) const + { + size_t hash{ 0 }; + AZStd::hash_combine(hash, p.m_ptr1, p.m_ptr2); + return hash; + } + }; + using PairSet = AZStd::unordered_set; + PairSet set; + set.insert({ (void*)1, (void*)2 }); + set.insert({ (void*)3, (void*)4 }); + set.insert({ (void*)5, (void*)6 }); + set.insert({ (void*)7, (void*)8 }); + // Elements with different hashes, but equal + set.insert({ (void*)0x000001ceddd9ca20, (void*)0x000001ceddd9cba0 }); // hash(148335135725641) + set.insert({ (void*)0x000001ceddd9cba0, (void*)0x000001ceddd9ca20 }); // hash(148335135764189) + AZ_TEST_START_TRACE_SUPPRESSION; + // This will trigger the assertion of duplicated elements found + // A bucket size of 23 since is where the collision between different hashes happens + set.rehash(23); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 assertion + } + TEST_F(HashedContainers, HashTable_Fixed) { array elements = { diff --git a/Gems/PhysX/Code/Source/Scene/PhysXSceneSimulationFilterCallback.cpp b/Gems/PhysX/Code/Source/Scene/PhysXSceneSimulationFilterCallback.cpp index d902fb91ca..e103913cdf 100644 --- a/Gems/PhysX/Code/Source/Scene/PhysXSceneSimulationFilterCallback.cpp +++ b/Gems/PhysX/Code/Source/Scene/PhysXSceneSimulationFilterCallback.cpp @@ -55,7 +55,9 @@ namespace PhysX size_t SceneSimulationFilterCallback::CollisionPairHasher::operator()(const CollisionActorPair& collisionPair) const { size_t hash{ 0 }; - AZStd::hash_combine(hash, collisionPair.m_actorA, collisionPair.m_actorB); + // Order elements so {1,2} and {2,1} would generate the same hash + auto [smallerVal, biggerVal] = AZStd::minmax(collisionPair.m_actorA, collisionPair.m_actorB); + AZStd::hash_combine(hash, smallerVal, biggerVal); return hash; } From d06ec45aaa2f882f13008c6a5cc9578e9cbb291d Mon Sep 17 00:00:00 2001 From: aaguilea Date: Wed, 4 Aug 2021 13:05:00 +0100 Subject: [PATCH 139/157] changes to the move rotate and scale Signed-off-by: aaguilea --- Code/Editor/Core/LevelEditorMenuHandler.cpp | 8 +-- Code/Editor/CryEdit.cpp | 3 - Code/Editor/MainWindow.cpp | 69 ++++++++++++++++++--- Code/Editor/MainWindow.h | 14 +++-- Code/Editor/Resource.h | 5 -- Code/Editor/ViewportTitleDlg.cpp | 8 +-- 6 files changed, 79 insertions(+), 28 deletions(-) diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp index 3c27c25c9a..70ff51c3d6 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp @@ -544,12 +544,12 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe auto snapMenu = modifyMenu.AddMenu(tr("Snap")); - snapMenu.AddAction(ID_SNAPANGLE); + snapMenu.AddAction(AzToolsFramework::SnapAngle); auto transformModeMenu = modifyMenu.AddMenu(tr("Transform Mode")); - transformModeMenu.AddAction(ID_EDITMODE_MOVE); - transformModeMenu.AddAction(ID_EDITMODE_ROTATE); - transformModeMenu.AddAction(ID_EDITMODE_SCALE); + transformModeMenu.AddAction(AzToolsFramework::EditModeMove); + transformModeMenu.AddAction(AzToolsFramework::EditModeRotate); + transformModeMenu.AddAction(AzToolsFramework::EditModeScale); editMenu.AddSeparator(); diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 4bfc6a319d..407dfffd3e 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -375,9 +375,6 @@ void CCryEditApp::RegisterActionHandlers() }); ON_COMMAND(ID_MOVE_OBJECT, OnMoveObject) ON_COMMAND(ID_RENAME_OBJ, OnRenameObj) - ON_COMMAND(ID_EDITMODE_MOVE, OnEditmodeMove) - ON_COMMAND(ID_EDITMODE_ROTATE, OnEditmodeRotate) - ON_COMMAND(ID_EDITMODE_SCALE, OnEditmodeScale) ON_COMMAND(ID_UNDO, OnUndo) ON_COMMAND(ID_TOOLBAR_WIDGET_REDO, OnUndo) // Can't use the same ID, because for the menu we can't have a QWidgetAction, while for the toolbar we want one ON_COMMAND(ID_IMPORT_ASSET, OnOpenAssetImporter) diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index ff322b79ac..8309d99691 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -46,6 +46,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include // AzQtComponents #include @@ -731,32 +732,84 @@ void MainWindow::InitActions() .SetStatusTip(tr("Restore saved state (Fetch)")); // Modify actions - am->AddAction(ID_EDITMODE_MOVE, tr("Move")) + am->AddAction(AzToolsFramework::EditModeMove, tr("Move")) .SetIcon(Style::icon("Move")) .SetApplyHoverEffect() .SetShortcut(tr("1")) .SetToolTip(tr("Move (1)")) .SetCheckable(true) .SetStatusTip(tr("Select and move selected object(s)")) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateEditmodeMove); - am->AddAction(ID_EDITMODE_ROTATE, tr("Rotate")) + .RegisterUpdateCallback([](QAction* action) + { + Q_ASSERT(action->isCheckable()); + + AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode; + AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( + mode, AzToolsFramework::GetEntityContextId(), + &AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode); + + action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Translation); + }) + .Connect( + &QAction::triggered, + []() + { + EditorTransformComponentSelectionRequestBus::Event( + GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode, + EditorTransformComponentSelectionRequests::Mode::Translation); + }); + am->AddAction(AzToolsFramework::EditModeRotate, tr("Rotate")) .SetIcon(Style::icon("Translate")) .SetApplyHoverEffect() .SetShortcut(tr("2")) .SetToolTip(tr("Rotate (2)")) .SetCheckable(true) .SetStatusTip(tr("Select and rotate selected object(s)")) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateEditmodeRotate); - am->AddAction(ID_EDITMODE_SCALE, tr("Scale")) + .RegisterUpdateCallback([](QAction* action) + { + Q_ASSERT(action->isCheckable()); + + AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode; + AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( + mode, AzToolsFramework::GetEntityContextId(), + &AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode); + + action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Rotation); + }) + .Connect( + &QAction::triggered, + []() + { + EditorTransformComponentSelectionRequestBus::Event( + GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode, + EditorTransformComponentSelectionRequests::Mode::Rotation); + }); + am->AddAction(AzToolsFramework::EditModeScale, tr("Scale")) .SetIcon(Style::icon("Scale")) .SetApplyHoverEffect() .SetShortcut(tr("3")) .SetToolTip(tr("Scale (3)")) .SetCheckable(true) .SetStatusTip(tr("Select and scale selected object(s)")) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateEditmodeScale); + .RegisterUpdateCallback([](QAction* action) + { + Q_ASSERT(action->isCheckable()); - am->AddAction(ID_SNAP_TO_GRID, tr("Snap to grid")) + AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode; + AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( + mode, AzToolsFramework::GetEntityContextId(), + &AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode); + + action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Scale); + }) + .Connect( &QAction::triggered,[]() + { + EditorTransformComponentSelectionRequestBus::Event( + GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode, + EditorTransformComponentSelectionRequests::Mode::Scale); + }); + + am->AddAction(AzToolsFramework::SnapToGrid, tr("Snap to grid")) .SetIcon(Style::icon("Grid")) .SetApplyHoverEffect() .SetShortcut(tr("G")) @@ -769,7 +822,7 @@ void MainWindow::InitActions() }) .Connect(&QAction::triggered, []() { SandboxEditor::SetGridSnapping(!SandboxEditor::GridSnappingEnabled()); }); - am->AddAction(ID_SNAPANGLE, tr("Snap angle")) + am->AddAction(AzToolsFramework::SnapAngle, tr("Snap angle")) .SetIcon(Style::icon("Angle")) .SetApplyHoverEffect() .SetStatusTip(tr("Snap angle")) diff --git a/Code/Editor/MainWindow.h b/Code/Editor/MainWindow.h index e70355827c..1e375b08f2 100644 --- a/Code/Editor/MainWindow.h +++ b/Code/Editor/MainWindow.h @@ -59,11 +59,17 @@ namespace AzQtComponents namespace AzToolsFramework { class Ticker; -} - -namespace AzToolsFramework -{ class QtSourceControlNotificationHandler; + + //! @name Reverse URLs. + //! Used to identify common actions and override them when necessary. + //@{ + constexpr inline AZ::Crc32 EditModeMove = AZ_CRC_CE("com.o3de.action.editor.editmode.move"); + constexpr inline AZ::Crc32 EditModeRotate = AZ_CRC_CE("com.o3de.action.editor.editmode.rotate"); + constexpr inline AZ::Crc32 EditModeScale = AZ_CRC_CE("com.o3de.action.editor.editmode.scale"); + constexpr inline AZ::Crc32 SnapToGrid = AZ_CRC_CE("com.o3de.action.editor.snaptogrid"); + constexpr inline AZ::Crc32 SnapAngle = AZ_CRC_CE("com.o3de.action.editor.snapangle"); + //@} } #define MAINFRM_LAYOUT_NORMAL "NormalLayout" diff --git a/Code/Editor/Resource.h b/Code/Editor/Resource.h index a6f714afa4..b3640fac70 100644 --- a/Code/Editor/Resource.h +++ b/Code/Editor/Resource.h @@ -82,7 +82,6 @@ #define ID_TOOLS_CUSTOMIZEKEYBOARD 32914 #define ID_EXPORT_INDOORS 32915 #define ID_VIEW_CYCLE2DVIEWPORT 32916 -#define ID_SNAPANGLE 32917 #define ID_PHYSICS_GETPHYSICSSTATE 32937 #define ID_PHYSICS_RESETPHYSICSSTATE 32938 #define ID_GAME_SYNCPLAYER 32941 @@ -108,9 +107,6 @@ #define ID_MOVE_OBJECT 33481 #define ID_RENAME_OBJ 33483 #define ID_FETCH 33496 -#define ID_EDITMODE_ROTATE 33506 -#define ID_EDITMODE_SCALE 33507 -#define ID_EDITMODE_MOVE 33508 #define ID_SELECTION_DELETE 33512 #define ID_EDIT_ESCAPE 33513 #define ID_UNDO 33524 @@ -137,7 +133,6 @@ #define ID_ADDNODE 33570 #define ID_ADDSCENETRACK 33573 #define ID_FIND 33574 -#define ID_SNAP_TO_GRID 33575 #define ID_TAG_LOC1 33576 #define ID_TAG_LOC2 33577 #define ID_TAG_LOC3 33578 diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 4d27506929..c1e1afb908 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -953,13 +953,13 @@ void CViewportTitleDlg::CheckForCameraSpeedUpdate() void CViewportTitleDlg::OnGridSnappingToggled() { m_gridSizeActionWidget->setEnabled(m_enableGridSnappingAction->isChecked()); - MainWindow::instance()->GetActionManager()->GetAction(ID_SNAP_TO_GRID)->trigger(); + MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->trigger(); } void CViewportTitleDlg::OnAngleSnappingToggled() { m_angleSizeActionWidget->setEnabled(m_enableAngleSnappingAction->isChecked()); - MainWindow::instance()->GetActionManager()->GetAction(ID_SNAPANGLE)->trigger(); + MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->trigger(); } void CViewportTitleDlg::OnGridSpinBoxChanged(double value) @@ -974,14 +974,14 @@ void CViewportTitleDlg::OnAngleSpinBoxChanged(double value) void CViewportTitleDlg::UpdateOverFlowMenuState() { - bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(ID_SNAP_TO_GRID)->isChecked(); + 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(ID_SNAPANGLE)->isChecked(); + bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked(); { QSignalBlocker signalBlocker(m_enableAngleSnappingAction); m_enableAngleSnappingAction->setChecked(angleSnappingActive); From 6d2765ef4232aefcd7203919719bb375c2f41114 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Wed, 4 Aug 2021 13:10:17 +0100 Subject: [PATCH 140/157] moved default location of surfacetypemateriallibrary.physmaterial (#2786) from 'project root' to 'project root/Assets/Physics' The functionality of creating / using the default physmaterial file has only change in related to the file location, other functionality is unchanged. The following situations can occur: This will not affect have any project that uses a custom physmaterial file. This will not affect have any project that uses the default from the old location, as the configuration will still point there. New projects created will get the default physmaterial file at the new location. A Project that fails to load (or deletes) the selected physmaterial file, will get the default physmaterial file at the new location (this happens only on startup of the editor). Issue: #2765 Signed-off-by: amzn-sean 75276488+amzn-sean@users.noreply.github.com --- .../Physics/SurfaceTypeMaterialLibrary.physmaterial} | 0 .../physics/C15096740_Material_LibraryUpdatedCorrectly.py | 5 +++-- .../Gem/PythonTests/physics/Physmaterial_Editor.py | 2 +- .../C3510644_Collider_CollisionGroups.setreg_override | 5 +++-- .../Registry/C4976227_Collider_NewGroup.setreg_override | 5 +++-- ...4_Collider_SameGroupSameLayerCollision.setreg_override | 5 +++-- ...76245_PhysXCollider_CollisionLayerTest.setreg_override | 5 +++-- .../C4982593_PhysXCollider_CollisionLayer.setreg_override | 5 +++-- AutomatedTesting/Registry/physxsystemconfiguration.setreg | 5 +++-- .../Editor/Source/Components/EditorSystemComponent.cpp | 8 ++++---- 10 files changed, 26 insertions(+), 19 deletions(-) rename AutomatedTesting/{surfacetypemateriallibrary.physmaterial => Assets/Physics/SurfaceTypeMaterialLibrary.physmaterial} (100%) diff --git a/AutomatedTesting/surfacetypemateriallibrary.physmaterial b/AutomatedTesting/Assets/Physics/SurfaceTypeMaterialLibrary.physmaterial similarity index 100% rename from AutomatedTesting/surfacetypemateriallibrary.physmaterial rename to AutomatedTesting/Assets/Physics/SurfaceTypeMaterialLibrary.physmaterial diff --git a/AutomatedTesting/Gem/PythonTests/physics/C15096740_Material_LibraryUpdatedCorrectly.py b/AutomatedTesting/Gem/PythonTests/physics/C15096740_Material_LibraryUpdatedCorrectly.py index 060779082c..341597e36a 100755 --- a/AutomatedTesting/Gem/PythonTests/physics/C15096740_Material_LibraryUpdatedCorrectly.py +++ b/AutomatedTesting/Gem/PythonTests/physics/C15096740_Material_LibraryUpdatedCorrectly.py @@ -64,7 +64,8 @@ def C15096740_Material_LibraryUpdatedCorrectly(): # Constants library_property_path = "Configuration|Physics Material|Library" - default_material_path = "surfacetypemateriallibrary.physmaterial" + + default_material_path = os.path.join("assets", "physics", "surfacetypemateriallibrary.physmaterial") new_material_path = os.path.join("physicssurfaces", "default_phys_materials.physmaterial") helper.init_idle() @@ -82,7 +83,7 @@ def C15096740_Material_LibraryUpdatedCorrectly(): default_asset = Asset.find_asset_by_path(default_material_path) test_component.set_component_property_value(library_property_path, default_asset.id) default_asset.id = test_component.get_component_property_value(library_property_path) - Report.result(Tests.override_default_library, default_asset.get_path() == default_material_path) + Report.result(Tests.override_default_library, default_asset.get_path() == default_material_path.replace(os.sep, '/')) # 4) Switch it back again to the default material library. test_component.set_component_property_value(library_property_path, azasset.AssetId()) diff --git a/AutomatedTesting/Gem/PythonTests/physics/Physmaterial_Editor.py b/AutomatedTesting/Gem/PythonTests/physics/Physmaterial_Editor.py index 54ea3c7f15..cff8ae8377 100755 --- a/AutomatedTesting/Gem/PythonTests/physics/Physmaterial_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/physics/Physmaterial_Editor.py @@ -133,7 +133,7 @@ class Physmaterial_Editor: def _set_path(self): # type: (str) -> str if self.document_filename == None: - self.document_filename = os.path.join(self.project_folder, "surfacetypemateriallibrary.physmaterial") + self.document_filename = os.path.join(self.project_folder, "assets", "physics", "surfacetypemateriallibrary.physmaterial") else: for (root, directories, root_files) in os.walk(self.project_folder): for root_file in root_files: diff --git a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override index 9fa5e26768..e4ea71f652 100644 --- a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override +++ b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override @@ -121,9 +121,10 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" + "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" }, - "assetHint": "surfacetypemateriallibrary.physmaterial" + "loadBehavior": "QueueLoad", + "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" } } } diff --git a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override index afbe6a9d38..e53d3893f8 100644 --- a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override +++ b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override @@ -109,9 +109,10 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" + "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" }, - "assetHint": "surfacetypemateriallibrary.physmaterial" + "loadBehavior": "QueueLoad", + "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" } } } diff --git a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override index 9fa5e26768..e4ea71f652 100644 --- a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override +++ b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override @@ -121,9 +121,10 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" + "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" }, - "assetHint": "surfacetypemateriallibrary.physmaterial" + "loadBehavior": "QueueLoad", + "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" } } } diff --git a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override index 9fa5e26768..e4ea71f652 100644 --- a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override +++ b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override @@ -121,9 +121,10 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" + "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" }, - "assetHint": "surfacetypemateriallibrary.physmaterial" + "loadBehavior": "QueueLoad", + "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" } } } diff --git a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override index 9fa5e26768..e4ea71f652 100644 --- a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override +++ b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override @@ -121,9 +121,10 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" + "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" }, - "assetHint": "surfacetypemateriallibrary.physmaterial" + "loadBehavior": "QueueLoad", + "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" } } } diff --git a/AutomatedTesting/Registry/physxsystemconfiguration.setreg b/AutomatedTesting/Registry/physxsystemconfiguration.setreg index 02f65b685b..83aad307a6 100644 --- a/AutomatedTesting/Registry/physxsystemconfiguration.setreg +++ b/AutomatedTesting/Registry/physxsystemconfiguration.setreg @@ -103,9 +103,10 @@ }, "MaterialLibrary": { "assetId": { - "guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}" + "guid": "{62446378-67F8-5E49-AC31-761DD5942695}" }, - "assetHint": "surfacetypemateriallibrary.physmaterial" + "loadBehavior": "QueueLoad", + "assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial" } } } diff --git a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp index 6dc845199a..e4c65c8667 100644 --- a/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp +++ b/Gems/PhysX/Code/Editor/Source/Components/EditorSystemComponent.cpp @@ -24,7 +24,7 @@ namespace PhysX { - constexpr const char* DefaultAssetFilename = "SurfaceTypeMaterialLibrary"; + constexpr const char* DefaultAssetFilePath = "Physics/SurfaceTypeMaterialLibrary"; constexpr const char* TemplateAssetFilename = "PhysX/TemplateMaterialLibrary"; static AZStd::optional> GetMaterialLibraryTemplate() @@ -227,7 +227,7 @@ namespace PhysX const AZStd::string& assetExtension = assetTypeExtensions[0]; // Use the path relative to the asset root to avoid hardcoding full path in the configuration - AZStd::string relativePath = DefaultAssetFilename; + AZStd::string relativePath = DefaultAssetFilePath; AzFramework::StringFunc::Path::ReplaceExtension(relativePath, assetExtension.c_str()); // Try to find an already existing material library @@ -237,9 +237,9 @@ namespace PhysX if (!resultAssetId.IsValid()) { // No file for the default material library, create it - const char* assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + const char* assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectsourceassets@"); AZStd::string fullPath; - AzFramework::StringFunc::Path::ConstructFull(assetRoot, DefaultAssetFilename, assetExtension.c_str(), fullPath); + AzFramework::StringFunc::Path::ConstructFull(assetRoot, DefaultAssetFilePath, assetExtension.c_str(), fullPath); if (auto materialLibraryOpt = CreateMaterialLibrary(fullPath, relativePath)) { From c9e16c1c42e4fbad0bb949beaabb06850f3c2e67 Mon Sep 17 00:00:00 2001 From: aaguilea Date: Wed, 4 Aug 2021 14:44:50 +0100 Subject: [PATCH 141/157] Erased some legacy function that are no longer necessary Signed-off-by: aaguilea --- Code/Editor/CryEdit.cpp | 69 ----------------------------------------- Code/Editor/CryEdit.h | 6 ---- 2 files changed, 75 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 407dfffd3e..3b68758d17 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -2576,75 +2576,6 @@ void CCryEditApp::OnRenameObj() { } -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnEditmodeMove() -{ - using namespace AzToolsFramework; - EditorTransformComponentSelectionRequestBus::Event( - GetEntityContextId(), - &EditorTransformComponentSelectionRequests::SetTransformMode, - EditorTransformComponentSelectionRequests::Mode::Translation); -} - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnEditmodeRotate() -{ - using namespace AzToolsFramework; - EditorTransformComponentSelectionRequestBus::Event( - GetEntityContextId(), - &EditorTransformComponentSelectionRequests::SetTransformMode, - EditorTransformComponentSelectionRequests::Mode::Rotation); -} - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnEditmodeScale() -{ - using namespace AzToolsFramework; - EditorTransformComponentSelectionRequestBus::Event( - GetEntityContextId(), - &EditorTransformComponentSelectionRequests::SetTransformMode, - EditorTransformComponentSelectionRequests::Mode::Scale); -} - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnUpdateEditmodeMove(QAction* action) -{ - Q_ASSERT(action->isCheckable()); - - AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode; - AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( - mode, AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode); - - action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Translation); -} - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnUpdateEditmodeRotate(QAction* action) -{ - Q_ASSERT(action->isCheckable()); - - AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode; - AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( - mode, AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode); - - action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Rotation); -} - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnUpdateEditmodeScale(QAction* action) -{ - Q_ASSERT(action->isCheckable()); - - AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode; - AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( - mode, AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode); - - action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Scale); -} - void CCryEditApp::OnViewSwitchToGame() { if (IsInPreviewMode()) diff --git a/Code/Editor/CryEdit.h b/Code/Editor/CryEdit.h index af0fbb0971..9406b37ea2 100644 --- a/Code/Editor/CryEdit.h +++ b/Code/Editor/CryEdit.h @@ -208,12 +208,6 @@ public: void DeleteSelectedEntities(bool includeDescendants); void OnMoveObject(); void OnRenameObj(); - void OnEditmodeMove(); - void OnEditmodeRotate(); - void OnEditmodeScale(); - void OnUpdateEditmodeMove(QAction* action); - void OnUpdateEditmodeRotate(QAction* action); - void OnUpdateEditmodeScale(QAction* action); void OnUndo(); void OnOpenAssetImporter(); void OnUpdateSelected(QAction* action); From 20515c46beb88c8ffe9b2fd0c09f4ac64ebea7c1 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Wed, 4 Aug 2021 08:20:41 -0700 Subject: [PATCH 142/157] Updated DirectionTo node's tooltips to match the translation file Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h | 2 +- .../Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h | 2 +- .../Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h index 4ac14a7db6..5caff9ff25 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h @@ -257,7 +257,7 @@ namespace ScriptCanvas r.SetLength(optionalScale); return r; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{49A2D7F6-6CD3-420E-8A79-D46B00DB6CED}", "Given two points in space, return a direction vector", "From", "To", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{49A2D7F6-6CD3-420E-8A79-D46B00DB6CED}", "Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); using Registrar = RegistrarGeneric < AbsoluteNode diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h index eb304c8362..24a1710655 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h @@ -343,7 +343,7 @@ namespace ScriptCanvas r.SetLength(optionalScale); return r; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{28FBD529-4C9A-4E34-B8A0-A13B5DB3C331}", "Given two points in space, return a direction vector", "From", "To", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{28FBD529-4C9A-4E34-B8A0-A13B5DB3C331}", "Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); using Registrar = RegistrarGeneric < diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h index ac9be8f135..d420affd9a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h @@ -228,7 +228,7 @@ namespace ScriptCanvas r.SetLength(optionalScale); return r; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{463762DE-E541-4AFE-80C2-FED1C5273319}", "Given two points in space, return a direction vector", "From", "To", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{463762DE-E541-4AFE-80C2-FED1C5273319}", "Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); using Registrar = RegistrarGeneric < AbsoluteNode, From 760acdcdcc14fde196ced69002cf3251632fc812 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Wed, 4 Aug 2021 08:21:41 -0700 Subject: [PATCH 143/157] Updated DirectionTo tooltips in the translation file Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- Assets/Editor/Translation/scriptcanvas_en_us.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts index 5604cfb631..22cd00aaea 100644 --- a/Assets/Editor/Translation/scriptcanvas_en_us.ts +++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts @@ -2778,7 +2778,7 @@ VECTOR2_DIRECTIONTO_TOOLTIP - + Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0 VECTOR2_DIRECTIONTO_CATEGORY @@ -32334,7 +32334,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR4_DIRECTIONTO_TOOLTIP - + Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0 VECTOR4_DIRECTIONTO_CATEGORY @@ -37606,7 +37606,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR3_DIRECTIONTO_TOOLTIP - + Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0 VECTOR3_DIRECTIONTO_CATEGORY From 1f0fcf2aa27ed3bd3a353ce40ba583afd7ef5887 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Wed, 4 Aug 2021 08:42:26 -0700 Subject: [PATCH 144/157] Updates GetDirectionVector nodes to also return the distance between the points Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../Editor/Translation/scriptcanvas_en_us.ts | 43 +++++++++++++++---- .../Libraries/Math/Vector2Nodes.h | 8 ++-- .../Libraries/Math/Vector3Nodes.h | 8 ++-- .../Libraries/Math/Vector4Nodes.h | 8 ++-- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts index 22cd00aaea..937f6a4d96 100644 --- a/Assets/Editor/Translation/scriptcanvas_en_us.ts +++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts @@ -2778,7 +2778,7 @@ VECTOR2_DIRECTIONTO_TOOLTIP - Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0 + Returns a direction vector between two points and the distance between them, by default the direction will be normalized, it may be optionally scaled using the Scale parameter if different from 1.0 VECTOR2_DIRECTIONTO_CATEGORY @@ -2800,14 +2800,23 @@ VECTOR2_DIRECTIONTO_IN_TOOLTIP - + VECTOR2_DIRECTIONTO_OUTPUT0_NAME C++ Type: const Vector2 Direction VECTOR2_DIRECTIONTO_OUTPUT0_TOOLTIP - + The direction between To and From normalized and optionally scaled + + + VECTOR2_DIRECTIONTO_OUTPUT1_NAME + C++ Type: float + Distance + + + VECTOR2_DIRECTIONTO_OUTPUT1_TOOLTIP + The distance between To and From VECTOR2_DIRECTIONTO_PARAM0_NAME @@ -32334,7 +32343,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR4_DIRECTIONTO_TOOLTIP - Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0 + Returns a direction vector between two points and the distance between them, by default the direction will be normalized, it may be optionally scaled using the Scale parameter if different from 1.0 VECTOR4_DIRECTIONTO_CATEGORY @@ -32363,7 +32372,16 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR4_DIRECTIONTO_OUTPUT0_TOOLTIP - + The direction between To and From normalized and optionally scaled + + + VECTOR4_DIRECTIONTO_OUTPUT1_NAME + C++ Type: float + Distance + + + VECTOR4_DIRECTIONTO_OUTPUT1_TOOLTIP + The distance between To and From VECTOR4_DIRECTIONTO_PARAM0_NAME @@ -37606,7 +37624,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR3_DIRECTIONTO_TOOLTIP - Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0 + Returns a direction vector between two points and the distance between them, by default the direction will be normalized, it may be optionally scaled using the Scale parameter if different from 1.0 VECTOR3_DIRECTIONTO_CATEGORY @@ -37628,14 +37646,23 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro VECTOR3_DIRECTIONTO_IN_TOOLTIP - + VECTOR3_DIRECTIONTO_OUTPUT0_NAME C++ Type: const Vector3 Direction VECTOR3_DIRECTIONTO_OUTPUT0_TOOLTIP - + The direction between To and From normalized and optionally scaled + + + VECTOR3_DIRECTIONTO_OUTPUT1_NAME + C++ Type: float + Distance + + + VECTOR3_DIRECTIONTO_OUTPUT1_TOOLTIP + The distance between To and From VECTOR3_DIRECTIONTO_PARAM0_NAME diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h index 5caff9ff25..670c9f31a1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector2Nodes.h @@ -250,14 +250,14 @@ namespace ScriptCanvas SetDefaultValuesByIndex<2>::_(node, Data::NumberType(1.)); } - AZ_INLINE Vector2Type DirectionTo(const Vector2Type from, const Vector2Type to, NumberType optionalScale = 1.f) + AZ_INLINE std::tuple DirectionTo(const Vector2Type from, const Vector2Type to, NumberType optionalScale = 1.f) { Vector2Type r = to - from; - r.Normalize(); + float length = r.NormalizeWithLength(); r.SetLength(optionalScale); - return r; + return std::make_tuple(r, length); } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{49A2D7F6-6CD3-420E-8A79-D46B00DB6CED}", "Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{49A2D7F6-6CD3-420E-8A79-D46B00DB6CED}", "Returns a direction vector between two points and the distance between them, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); using Registrar = RegistrarGeneric < AbsoluteNode diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h index 24a1710655..492bc83e33 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector3Nodes.h @@ -336,14 +336,14 @@ namespace ScriptCanvas SetDefaultValuesByIndex<2>::_(node, Data::NumberType(1.)); } - AZ_INLINE Vector3Type DirectionTo(const Vector3Type from, const Vector3Type to, NumberType optionalScale = 1.f) + AZ_INLINE std::tuple DirectionTo(const Vector3Type from, const Vector3Type to, NumberType optionalScale = 1.f) { Vector3Type r = to - from; - r.Normalize(); + float length = r.NormalizeWithLength(); r.SetLength(optionalScale); - return r; + return std::make_tuple(r, length); } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{28FBD529-4C9A-4E34-B8A0-A13B5DB3C331}", "Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{28FBD529-4C9A-4E34-B8A0-A13B5DB3C331}", "Returns a direction vector between two points and the distance between them, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); using Registrar = RegistrarGeneric < diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h index d420affd9a..26099c59c6 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h @@ -221,14 +221,14 @@ namespace ScriptCanvas SetDefaultValuesByIndex<2>::_(node, Data::NumberType(1.)); } - AZ_INLINE Vector4Type DirectionTo(const Vector4Type from, const Vector4Type to, NumberType optionalScale = 1.f) + AZ_INLINE std::tuple DirectionTo(const Vector4Type from, const Vector4Type to, NumberType optionalScale = 1.f) { Vector4Type r = to - from; - r.Normalize(); + float length = r.NormalizeWithLength(); r.SetLength(optionalScale); - return r; + return std::make_tuple(r, length); } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{463762DE-E541-4AFE-80C2-FED1C5273319}", "Returns a direction vector between two points, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{463762DE-E541-4AFE-80C2-FED1C5273319}", false, "Returns a direction vector between two points and the distance between them, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); using Registrar = RegistrarGeneric < AbsoluteNode, From 2c9655657695b9dc21c13b07d340bb9f0e18790e Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Wed, 4 Aug 2021 08:47:37 -0700 Subject: [PATCH 145/157] Removed unnecessary argument in node generic macro Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h index 26099c59c6..14256fc969 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/Vector4Nodes.h @@ -228,7 +228,7 @@ namespace ScriptCanvas r.SetLength(optionalScale); return std::make_tuple(r, length); } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{463762DE-E541-4AFE-80C2-FED1C5273319}", false, "Returns a direction vector between two points and the distance between them, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(DirectionTo, DirectionToDefaults, k_categoryName, "{463762DE-E541-4AFE-80C2-FED1C5273319}", "Returns a direction vector between two points and the distance between them, by default the direction will be normalized, but it may be optionally scaled using the Scale parameter if different from 1.0", "From", "To", "Scale"); using Registrar = RegistrarGeneric < AbsoluteNode, From 26c6d41e6358737f51c686b58fb76f9e76f374f6 Mon Sep 17 00:00:00 2001 From: Chris Aniszczyk Date: Wed, 4 Aug 2021 11:14:25 -0500 Subject: [PATCH 146/157] Update language Signed-off-by: Chris Aniszczyk --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c129fffb6c..e3eb6aa588 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Open 3D Engine +# O3DE (Open 3D Engine) -Open 3D Engine (O3DE) is an open-source, real-time, multi-platform 3D engine that enables developers and content creators to build AAA games, cinema-quality 3D worlds, and high-fidelity simulations without any fees or commercial obligations. +O3DE (Open 3D Engine)is an open-source, real-time, multi-platform 3D engine that enables developers and content creators to build AAA games, cinema-quality 3D worlds, and high-fidelity simulations without any fees or commercial obligations. ## Contribute For information about contributing to Open 3D Engine, visit https://o3de.org/docs/contributing/ From dbb6c1ae469eea0b9f7eebd2460f1d619bb9b23d Mon Sep 17 00:00:00 2001 From: moraaar Date: Wed, 4 Aug 2021 17:57:48 +0100 Subject: [PATCH 147/157] Fixed EntitySpawnTicket move constructor (#2832) Signed-off-by: moraaar --- .../Spawnable/SpawnableEntitiesInterface.cpp | 2 ++ .../SpawnableEntitiesManagerTests.cpp | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.cpp index 87353c5807..617eb3a0b9 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.cpp @@ -227,8 +227,10 @@ namespace AzFramework EntitySpawnTicket::EntitySpawnTicket(EntitySpawnTicket&& rhs) : m_payload(rhs.m_payload) + , m_id(rhs.m_id) { rhs.m_payload = nullptr; + rhs.m_id = 0; } EntitySpawnTicket::EntitySpawnTicket(AZ::Data::Asset spawnable) diff --git a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 7eff4b5eeb..f68af08f4a 100644 --- a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -366,6 +366,24 @@ namespace UnitTest } } + TEST_F(SpawnableEntitiesManagerTest, EntitySpawnTicket_Move_Works) + { + AzFramework::EntitySpawnTicket ticket1(*m_spawnableAsset); + AzFramework::EntitySpawnTicket ticket2(*m_spawnableAsset); + + const AzFramework::EntitySpawnTicket::Id ticket1Id = ticket1.GetId(); + const AzFramework::EntitySpawnTicket::Id ticket2Id = ticket2.GetId(); + + AzFramework::EntitySpawnTicket ticketMoveConstructor(AZStd::move(ticket1)); + EXPECT_TRUE(ticketMoveConstructor.IsValid()); + EXPECT_EQ(ticketMoveConstructor.GetId(), ticket1Id); + + AzFramework::EntitySpawnTicket ticketMoveOperator; + ticketMoveOperator = AZStd::move(ticket2); + EXPECT_TRUE(ticketMoveOperator.IsValid()); + EXPECT_EQ(ticketMoveOperator.GetId(), ticket2Id); + } + TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_DeleteTicketBeforeCall_NoCrash) { { From 6d345512c136b65e471335616130d41cb683a0d7 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard <64656371+jcbhl@users.noreply.github.com> Date: Wed, 4 Aug 2021 10:26:06 -0700 Subject: [PATCH 148/157] Visualizer: switch to erase_if to improve performance (#2779) Signed-off-by: Jacob Hilliard --- .../Code/Include/Atom/Utils/ImGuiCpuProfiler.inl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index ffd7af2f20..ae707a10a7 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -520,13 +520,14 @@ namespace AZ { AZStd::size_t sizeBeforeRemove = savedRegions.size(); - auto firstRegionToKeep = AZStd::lower_bound( - savedRegions.begin(), savedRegions.end(), deleteBeforeTick, - [](const TimeRegion& region, AZStd::sys_time_t target) + // Use erase_if over plain upper_bound + erase to avoid repeated shifts. erase requires a shift of all elements to the right + // for each element that is erased, while erase_if squashes all removes into a single shift which significantly improves perf. + AZStd::erase_if( + savedRegions, + [deleteBeforeTick](const TimeRegion& region) { - return region.m_startTick < target; + return region.m_startTick < deleteBeforeTick; }); - savedRegions.erase(savedRegions.begin(), firstRegionToKeep); m_savedRegionCount -= sizeBeforeRemove - savedRegions.size(); } From b3901b32513d2c1b0b089325f8757f92cb1f2436 Mon Sep 17 00:00:00 2001 From: Chris Aniszczyk Date: Wed, 4 Aug 2021 12:27:19 -0500 Subject: [PATCH 149/157] fix space Signed-off-by: Chris Aniszczyk --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3eb6aa588..a783139eef 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # O3DE (Open 3D Engine) -O3DE (Open 3D Engine)is an open-source, real-time, multi-platform 3D engine that enables developers and content creators to build AAA games, cinema-quality 3D worlds, and high-fidelity simulations without any fees or commercial obligations. +O3DE (Open 3D Engine) is an open-source, real-time, multi-platform 3D engine that enables developers and content creators to build AAA games, cinema-quality 3D worlds, and high-fidelity simulations without any fees or commercial obligations. ## Contribute For information about contributing to Open 3D Engine, visit https://o3de.org/docs/contributing/ From 21ca3a4aea3b79b530e9abc1f0e2618aae88f05d Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 4 Aug 2021 13:13:28 -0500 Subject: [PATCH 150/157] The enable-gem command registers gem with project if not registered (#2817) * The enable_gems command now registers the gem with the project if only registered with o3de_manifest.json Updated the `enable_gems` command to register the gem with the project if the gem is not registered with either the project or the engine being used. This allows the gem to be added to the build system if it wasn't registered before. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Adding quoting around the invocation of the OpenProjectManager command The --project-path parameter now is able to pass in a path with spaces to the invocation of the Project Manager. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 9 +- scripts/o3de/o3de/enable_gem.py | 22 ++- scripts/o3de/o3de/register.py | 6 +- scripts/o3de/tests/CMakeLists.txt | 7 + scripts/o3de/tests/unit_test_enable_gem.py | 126 ++++++++++++++++++ .../tests/unit_test_project_properties.py | 36 +++-- 6 files changed, 183 insertions(+), 23 deletions(-) create mode 100644 scripts/o3de/tests/unit_test_enable_gem.py diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 4bfc6a319d..61d4fd5aea 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -2901,7 +2901,14 @@ void CCryEditApp::OpenProjectManager(const AZStd::string& screen) { // provide the current project path for in case we want to update the project AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); - const AZStd::string commandLineOptions = AZStd::string::format(" --screen %s --project-path %s", screen.c_str(), projectPath.c_str()); +#if !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS + const char* argumentQuoteString = R"(")"; +#else + const char* argumentQuoteString = R"(\")"; +#endif + const AZStd::string commandLineOptions = AZStd::string::format(R"( --screen %s --project-path %s%s%s)", + screen.c_str(), + argumentQuoteString, projectPath.c_str(), argumentQuoteString); bool launchSuccess = AzFramework::ProjectManager::LaunchProjectManager(commandLineOptions); if (!launchSuccess) { diff --git a/scripts/o3de/o3de/enable_gem.py b/scripts/o3de/o3de/enable_gem.py index 67e1624086..1614dc4eda 100644 --- a/scripts/o3de/o3de/enable_gem.py +++ b/scripts/o3de/o3de/enable_gem.py @@ -16,7 +16,7 @@ import os import pathlib import sys -from o3de import cmake, manifest, validation +from o3de import cmake, manifest, register, validation logger = logging.getLogger() logging.basicConfig() @@ -87,8 +87,7 @@ def enable_gem_in_project(gem_name: str = None, if not enabled_gem_file.is_file(): logger.error(f'Enabled gem file {enabled_gem_file} is not present.') return 1 - # add the gem - ret_val = cmake.add_gem_dependency(enabled_gem_file, gem_json_data['gem_name']) + project_enabled_gem_file = enabled_gem_file else: # Find the path to enabled gem file. @@ -96,8 +95,21 @@ def enable_gem_in_project(gem_name: str = None, project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path) if not project_enabled_gem_file.is_file(): project_enabled_gem_file.touch() - # add the gem - ret_val = cmake.add_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) + + # Before adding the gem_dependency check if the project is registered in either the project or engine + # manifest + buildable_gems = manifest.get_engine_gems() + buildable_gems.extend(manifest.get_project_gems(project_path)) + # Convert each path to pathlib.Path object and filter out duplictes using dict.fromkeys + buildable_gems = list(dict.fromkeys(map(lambda gem_path_string: pathlib.Path(gem_path_string), buildable_gems))) + + ret_val = 0 + # If the gem is not part of buildable set, it needs to be registered + if not gem_path in buildable_gems: + ret_val = register.register(gem_path=gem_path, external_subdir_project_path=project_path) + + # add the gem if it is registered in either the project.json or engine.json + ret_val = ret_val or cmake.add_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) return ret_val diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 8481c5fae0..7e182b5d2d 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -285,14 +285,14 @@ def register_o3de_object_path(json_data: dict, manifest_data = None if engine_path: - manifest_data = manifest.get_engine_json_data(json_data, engine_path) + manifest_data = manifest.get_engine_json_data(None, engine_path) if not manifest_data: logger.error(f'Cannot load engine.json data at path {engine_path}') return 1 save_path = engine_path / 'engine.json' elif project_path: - manifest_data = manifest.get_project_json_data(json_data, project_path) + manifest_data = manifest.get_project_json_data(None, project_path) if not manifest_data: logger.error(f'Cannot load project.json data at path {project_path}') return 1 @@ -329,7 +329,7 @@ def register_o3de_object_path(json_data: dict, try: o3de_object_path = o3de_object_path.relative_to(save_path.parent) except ValueError: - pass # It is OK relative path cannot be formed + pass # It is OK relative path cannot be formed manifest_data[o3de_object_key].insert(0, o3de_object_path.as_posix()) if save_path: manifest.save_o3de_manifest(manifest_data, save_path) diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 1cd6eac7ee..de8e9e4974 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -25,6 +25,13 @@ ly_add_pytest( EXCLUDE_TEST_RUN_TARGET_FROM_IDE ) +ly_add_pytest( + NAME o3de_enable_gem + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_enable_gem.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) + ly_add_pytest( NAME o3de_global_project PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_global_project.py diff --git a/scripts/o3de/tests/unit_test_enable_gem.py b/scripts/o3de/tests/unit_test_enable_gem.py new file mode 100644 index 0000000000..12896a51ba --- /dev/null +++ b/scripts/o3de/tests/unit_test_enable_gem.py @@ -0,0 +1,126 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +import io +import json +import logging + +import pytest +import pathlib +from unittest.mock import patch + +from o3de import enable_gem + + +TEST_PROJECT_JSON_PAYLOAD = ''' +{ + "project_name": "TestProject", + "origin": "The primary repo for TestProject goes here: i.e. http://www.mydomain.com", + "license": "What license TestProject uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "TestProject", + "summary": "A short description of TestProject.", + "canonical_tags": [ + "Project" + ], + "user_tags": [ + "TestProject" + ], + "icon_path": "preview.png", + "engine": "o3de-install", + "restricted_name": "projects", + "external_subdirectories": [ + ] +} +''' + +TEST_GEM_JSON_PAYLOAD = ''' +{ + "gem_name": "TestGem", + "display_name": "TestGem", + "license": "What license TestGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "origin": "The primary repo for TestGem goes here: i.e. http://www.mydomain.com", + "type": "Code", + "summary": "A short description of TestGem.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "TestGem" + ], + "icon_path": "preview.png", + "requirements": "" +} +''' + + +@pytest.fixture(scope='class') +def init_enable_gem_data(request): + class EnableGemData: + def __init__(self): + self.project_data = json.loads(TEST_PROJECT_JSON_PAYLOAD) + self.gem_data = json.loads(TEST_GEM_JSON_PAYLOAD) + request.cls.enable_gem = EnableGemData() + + +@pytest.mark.usefixtures('init_enable_gem_data') +class TestEnableGemCommand: + @pytest.mark.parametrize("gem_path, project_path, gem_registered_with_project, gem_registered_with_engine," + "expected_result", [ + pytest.param(pathlib.PurePath('E:/TestGem'), pathlib.PurePath('E:/TestProject'), False, True, 0), + pytest.param(pathlib.PurePath('E:/TestGem'), pathlib.PurePath('E:/TestProject'), False, False, 0), + pytest.param(pathlib.PurePath('E:/TestGem'), pathlib.PurePath('E:/TestProject'), True, False, 0), + ] + ) + def test_enable_gem_registers_gem_as_well(self, gem_path, project_path, gem_registered_with_project, gem_registered_with_engine, + expected_result): + + def get_registered_path(project_name: str = None, gem_name: str = None) -> pathlib.Path: + if project_name: + return project_path + elif gem_name: + return gem_path + return None + + def get_registered_gem_path(gem_name: str) -> pathlib.Path: + return gem_path + + def save_o3de_manifest(new_project_data: dict, manifest_path: pathlib.Path = None) -> bool: + if manifest_path == project_path: + self.enable_gem.project_data = new_project_data + return True + + def get_project_json_data(json_data: pathlib.Path, project_path: pathlib.Path): + return self.enable_gem.project_data + + def get_gem_json_data(gem_path: pathlib.Path, project_path: pathlib.Path): + return self.enable_gem.gem_data + + def get_project_gems(project_path: pathlib.Path): + return [gem_path] if gem_registered_with_project else [] + + def get_engine_gems(): + return [gem_path] if gem_registered_with_engine else [] + + def add_gem_dependency(enable_gem_cmake_file: pathlib.Path, gem_name: str): + return 0 + + with patch('pathlib.Path.is_dir', return_value=True) as pathlib_is_dir_patch,\ + patch('pathlib.Path.is_file', return_value=True) as pathlib_is_file_patch,\ + patch('o3de.manifest.save_o3de_manifest', side_effect=save_o3de_manifest) as save_o3de_manifest_patch,\ + patch('o3de.manifest.get_registered', side_effect=get_registered_path) as get_registered_patch,\ + patch('o3de.manifest.get_gem_json_data', side_effect=get_gem_json_data) as get_gem_json_data_patch,\ + patch('o3de.manifest.get_project_json_data', side_effect=get_project_json_data) as get_gem_json_data_patch,\ + patch('o3de.manifest.get_project_gems', side_effect=get_project_gems) as get_project_gems_patch,\ + patch('o3de.manifest.get_engine_gems', side_effect=get_engine_gems) as get_engine_gems_patch,\ + patch('o3de.cmake.add_gem_dependency', side_effect=add_gem_dependency) as add_gem_dependency_patch,\ + patch('o3de.validation.valid_o3de_gem_json', return_value=True) as valid_gem_json_patch: + result = enable_gem.enable_gem_in_project(gem_path=gem_path, project_path=project_path) + assert result == expected_result + # If the gem isn't registered with the engine or project already it should now be registered with the project + if not gem_registered_with_engine and gem_registered_with_project: + assert gem_path.as_posix() in self.enable_gem.project_data.get('external_subdirectories', []) diff --git a/scripts/o3de/tests/unit_test_project_properties.py b/scripts/o3de/tests/unit_test_project_properties.py index f72a4dfe4c..0236e6cf90 100644 --- a/scripts/o3de/tests/unit_test_project_properties.py +++ b/scripts/o3de/tests/unit_test_project_properties.py @@ -6,33 +6,41 @@ # # +import json import pytest import pathlib from unittest.mock import patch from o3de import project_properties -TEST_DEFAULT_PROJECT_DATA = { - "template_name": "DefaultProject", - "restricted_name": "o3de", - "restricted_platform_relative_path": "Templates", - "origin": "The primary repo for DefaultProject goes here: i.e. http://www.mydomain.com", - "license": "What license DefaultProject uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "Default", - "summary": "A short description of DefaultProject.", - "included_gems": ["Atom","Camera","EMotionFX","UI","Maestro","Input","ImGui"], - "canonical_tags": [], - "user_tags": [ - "DefaultProject" +TEST_PROJECT_JSON_PAYLOAD = ''' +{ + "project_name": "TestProject", + "origin": "The primary repo for TestProject goes here: i.e. http://www.mydomain.com", + "license": "What license TestProject uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "TestProject", + "summary": "A short description of TestProject.", + "canonical_tags": [ + "Project" ], - "icon_path": "preview.png" + "user_tags": [ + "TestProject" + ], + "icon_path": "preview.png", + "engine": "o3de-install", + "restricted_name": "projects", + "external_subdirectories": [ + "D:/TestGem" + ] } +''' + @pytest.fixture(scope='class') def init_project_json_data(request): class ProjectJsonData: def __init__(self): - self.data = TEST_DEFAULT_PROJECT_DATA + self.data = json.loads(TEST_PROJECT_JSON_PAYLOAD) request.cls.project_json = ProjectJsonData() @pytest.mark.usefixtures('init_project_json_data') From 627dcc49f1e151e0f881dd9ec6690e831175a022 Mon Sep 17 00:00:00 2001 From: nemerle <96597+nemerle@users.noreply.github.com> Date: Wed, 4 Aug 2021 20:56:37 +0200 Subject: [PATCH 151/157] GetActivePathName was using default - constructed enum DocumentEditingMode() Also, SaveLevel was not using destName when constructing newFilePath Other code changes: * LogLoadTime is simplified by using QFile * reduce nesting in DoSaveDocument by using early return. * marked a few eligible methods as const * Simplified OnEnvironmentPropertyChanged a bit Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- Code/Editor/CryEditDoc.cpp | 147 ++++++++++++++++--------------------- Code/Editor/CryEditDoc.h | 30 ++++---- 2 files changed, 79 insertions(+), 98 deletions(-) diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp index 43f599b191..9421198de7 100644 --- a/Code/Editor/CryEditDoc.cpp +++ b/Code/Editor/CryEditDoc.cpp @@ -108,21 +108,12 @@ namespace Internal // CCryEditDoc construction/destruction CCryEditDoc::CCryEditDoc() - : doc_validate_surface_types(0) + : doc_validate_surface_types(nullptr) , m_modifiedModuleFlags(eModifiedNothing) - // It assumes loaded levels have already been exported. Can be a big fat lie, though. - // The right way would require us to save to the level folder the export status of the - // level. - , m_boLevelExported(true) - , m_modified(false) - , m_envProbeHeight(200.0f) - , m_envProbeSliceRelativePath("EngineAssets/Slices/DefaultLevelSetup.slice") { //////////////////////////////////////////////////////////////////////// // Set member variables to initial values //////////////////////////////////////////////////////////////////////// - m_bLoadFailed = false; - m_waterColor = QColor(0, 0, 255); m_fogTemplate = GetIEditor()->FindTemplate("Fog"); m_environmentTemplate = GetIEditor()->FindTemplate("Environment"); @@ -136,7 +127,6 @@ CCryEditDoc::CCryEditDoc() m_environmentTemplate = XmlHelpers::CreateXmlNode("Environment"); } - m_bDocumentReady = false; GetIEditor()->SetDocument(this); CLogFile::WriteLine("Document created"); RegisterConsoleVariables(); @@ -195,7 +185,7 @@ CCryEditDoc::DocumentEditingMode CCryEditDoc::GetEditMode() const QString CCryEditDoc::GetActivePathName() const { - return DocumentEditingMode() == CCryEditDoc::DocumentEditingMode::SliceEdit ? GetSlicePathName() : GetLevelPathName(); + return GetEditMode() == CCryEditDoc::DocumentEditingMode::SliceEdit ? GetSlicePathName() : GetLevelPathName(); } QString CCryEditDoc::GetTitle() const @@ -260,9 +250,9 @@ void CCryEditDoc::DeleteContents() GetIEditor()->FlushUndo(); // Notify listeners. - for (std::list::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) + for (IDocListener* listener : m_listeners) { - (*it)->OnCloseDocument(); + listener->OnCloseDocument(); } GetIEditor()->ResetViews(); @@ -458,7 +448,7 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename) ////////////////////////////////////////////////////////////////////////// // Load water color. ////////////////////////////////////////////////////////////////////////// - (*arrXmlAr[DMAS_GENERAL]).root->getAttr("WaterColor", m_waterColor); + (*arrXmlAr[DMAS_GENERAL]).root->getAttr("WaterColor", m_waterColor); ////////////////////////////////////////////////////////////////////////// // Load View Settings @@ -507,9 +497,9 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename) CAutoLogTime logtime("Post Load"); // Notify listeners. - for (std::list::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) + for (IDocListener* listener : m_listeners) { - (*it)->OnLoadDocument(); + listener->OnLoadDocument(); } } @@ -708,7 +698,8 @@ bool CCryEditDoc::SaveModified() return true; } - auto button = QMessageBox::question(AzToolsFramework::GetActiveWindow(), QString(), tr("Save changes to %1?").arg(GetTitle()), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + auto button = QMessageBox::question(AzToolsFramework::GetActiveWindow(), QString(), tr("Save changes to %1?").arg(GetTitle()), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); switch (button) { case QMessageBox::Cancel: @@ -933,8 +924,7 @@ bool CCryEditDoc::OnSaveDocument(const QString& lpszPathName) } TSaveDocContext context; - if (shouldSaveLevel && - BeforeSaveDocument(lpszPathName, context)) + if (shouldSaveLevel && BeforeSaveDocument(lpszPathName, context)) { DoSaveDocument(lpszPathName, context); saveSuccess = AfterSaveDocument(lpszPathName, context); @@ -972,7 +962,7 @@ bool CCryEditDoc::BeforeSaveDocument(const QString& lpszPathName, TSaveDocContex return TRUE; } -bool CCryEditDoc::HasLayerNameConflicts() +bool CCryEditDoc::HasLayerNameConflicts() const { AZStd::vector editorEntities; AzToolsFramework::EditorEntityContextRequestBus::Broadcast( @@ -1004,43 +994,42 @@ bool CCryEditDoc::HasLayerNameConflicts() bool CCryEditDoc::DoSaveDocument(const QString& filename, TSaveDocContext& context) { bool& bSaved = context.bSaved; - if (bSaved) + if (!bSaved) { - // Paranoia - we shouldn't get this far into the save routine without a level loaded (empty levelPath) - // If nothing is loaded, we don't need to save anything - if (filename.isEmpty()) - { - bSaved = false; - } - else - { - // Save Tag Point locations to file if auto save of tag points disabled - if (!gSettings.bAutoSaveTagPoints) - { - CCryEditApp::instance()->SaveTagLocations(); - } - - QString normalizedPath = Path::ToUnixPath(filename); - if (IsSliceFile(normalizedPath)) - { - bSaved = SaveSlice(normalizedPath); - } - else - { - bSaved = SaveLevel(normalizedPath); - } - - // Changes filename for this document. - SetPathName(normalizedPath); - } + return false; + } + // Paranoia - we shouldn't get this far into the save routine without a level loaded (empty levelPath) + // If nothing is loaded, we don't need to save anything + if (filename.isEmpty()) + { + bSaved = false; + return false; } + // Save Tag Point locations to file if auto save of tag points disabled + if (!gSettings.bAutoSaveTagPoints) + { + CCryEditApp::instance()->SaveTagLocations(); + } + + QString normalizedPath = Path::ToUnixPath(filename); + if (IsSliceFile(normalizedPath)) + { + bSaved = SaveSlice(normalizedPath); + } + else + { + bSaved = SaveLevel(normalizedPath); + } + + // Changes filename for this document. + SetPathName(normalizedPath); return bSaved; } bool CCryEditDoc::AfterSaveDocument([[maybe_unused]] const QString& lpszPathName, TSaveDocContext& context, bool bShowPrompt) { - bool& bSaved = context.bSaved; + bool bSaved = context.bSaved; GetIEditor()->Notify(eNotify_OnEndSceneSave); @@ -1067,8 +1056,7 @@ bool CCryEditDoc::AfterSaveDocument([[maybe_unused]] const QString& lpszPathName static void GetUserSettingsFile(const QString& levelFolder, QString& userSettings) { const char* pUserName = GetISystem()->GetUserName(); - QString fileName; - fileName = QStringLiteral("%1_usersettings.editor_xml").arg(pUserName); + QString fileName = QStringLiteral("%1_usersettings.editor_xml").arg(pUserName); userSettings = Path::Make(levelFolder, fileName); } @@ -1182,9 +1170,9 @@ bool CCryEditDoc::SaveLevel(const QString& filename) } QString oldFilePath = QDir(oldLevelFolder).absoluteFilePath(sourceName); - QString newFilePath = QDir(newLevelFolder).absoluteFilePath(sourceName); + QString newFilePath = QDir(newLevelFolder).absoluteFilePath(destName); CFileUtil::CopyFile(oldFilePath, newFilePath); - } while (findHandle = pIPak->FindNext(findHandle)); + } while ((findHandle = pIPak->FindNext(findHandle))); pIPak->FindClose(findHandle); } @@ -1506,7 +1494,7 @@ bool CCryEditDoc::LoadEntitiesFromLevel(const QString& levelPakFile) { AZStd::vector fileBuffer; fileBuffer.resize(entitiesFile.GetLength()); - if (fileBuffer.size() > 0) + if (!fileBuffer.empty()) { if (fileBuffer.size() == entitiesFile.ReadRaw(fileBuffer.begin(), fileBuffer.size())) { @@ -1910,7 +1898,7 @@ void CCryEditDoc::UnregisterListener(IDocListener* listener) m_listeners.remove(listener); } -void CCryEditDoc::LogLoadTime(int time) +void CCryEditDoc::LogLoadTime(int time) const { QString appFilePath = QDir::toNativeSeparators(QCoreApplication::applicationFilePath()); QString exePath = Path::GetPath(appFilePath); @@ -1922,21 +1910,18 @@ void CCryEditDoc::LogLoadTime(int time) SetFileAttributes(filename.toUtf8().data(), FILE_ATTRIBUTE_ARCHIVE); #endif - FILE* file = nullptr; - azfopen(&file, filename.toUtf8().data(), "at"); - - if (file) + QFile file(filename); + if (!file.open(QFile::Append | QFile::Text)) { - char version[50]; - GetIEditor()->GetFileVersion().ToShortString(version, AZ_ARRAY_SIZE(version)); - - QString text; - - time = time / 1000; - text = QStringLiteral("\n[%1] Level %2 loaded in %3 seconds").arg(version, level).arg(time); - fwrite(text.toUtf8().data(), text.toUtf8().length(), 1, file); - fclose(file); + return; } + + char version[50]; + GetIEditor()->GetFileVersion().ToShortString(version, AZ_ARRAY_SIZE(version)); + + time = time / 1000; + QString text = QStringLiteral("\n[%1] Level %2 loaded in %3 seconds").arg(version, level).arg(time); + file.write(text.toUtf8()); } void CCryEditDoc::SetDocumentReady(bool bReady) @@ -1944,7 +1929,7 @@ void CCryEditDoc::SetDocumentReady(bool bReady) m_bDocumentReady = bReady; } -void CCryEditDoc::GetMemoryUsage(ICrySizer* pSizer) +void CCryEditDoc::GetMemoryUsage(ICrySizer* pSizer) const { { SIZER_COMPONENT_NAME(pSizer, "UndoManager(estimate)"); @@ -2068,12 +2053,9 @@ void CCryEditDoc::InitEmptyLevel(int /*resolution*/, int /*unitSize*/, bool /*bU { // Notify listeners. std::list listeners = m_listeners; - std::list::iterator it, next; - for (it = listeners.begin(); it != listeners.end(); it = next) + for (IDocListener* listener : listeners) { - next = it; - next++; - (*it)->OnNewDocument(); + listener->OnNewDocument(); } } @@ -2134,25 +2116,23 @@ void CCryEditDoc::OnEnvironmentPropertyChanged(IVariable* pVar) { return; } + QString childValue; if (pVar->GetDataType() == IVariable::DT_COLOR) { Vec3 value; pVar->Get(value); - QString buff; QColor gammaColor = ColorLinearToGamma(ColorF(value.x, value.y, value.z)); - buff = QStringLiteral("%1,%2,%3").arg(gammaColor.red()).arg(gammaColor.green()).arg(gammaColor.blue()); - childNode->setAttr("value", buff.toUtf8().data()); + childValue = QStringLiteral("%1,%2,%3").arg(gammaColor.red()).arg(gammaColor.green()).arg(gammaColor.blue()); } else { - QString value; - pVar->Get(value); - childNode->setAttr("value", value.toUtf8().data()); + pVar->Get(childValue); } + childNode->setAttr("value", childValue.toUtf8().data()); } -QString CCryEditDoc::GetCryIndexPath(const LPCTSTR levelFilePath) +QString CCryEditDoc::GetCryIndexPath(const LPCTSTR levelFilePath) const { QString levelPath = Path::GetPath(levelFilePath); QString levelName = Path::GetFileName(levelFilePath); @@ -2183,8 +2163,7 @@ BOOL CCryEditDoc::LoadXmlArchiveArray(TDocMultiArchive& arrXmlAr, const QString& } CPakFile pakFile; - bool loadFromPakSuccess; - loadFromPakSuccess = xmlAr.LoadFromPak(levelPath, pakFile); + bool loadFromPakSuccess = xmlAr.LoadFromPak(levelPath, pakFile); pIPak->ClosePack(absoluteLevelPath.toUtf8().data()); if (!loadFromPakSuccess) { diff --git a/Code/Editor/CryEditDoc.h b/Code/Editor/CryEditDoc.h index 574f8eb7da..d32e8e5bb1 100644 --- a/Code/Editor/CryEditDoc.h +++ b/Code/Editor/CryEditDoc.h @@ -91,7 +91,7 @@ public: // Create from serialization only // ClassWizard generated virtual function overrides virtual bool OnOpenDocument(const QString& lpszPathName); - const bool IsLevelLoadFailed() const { return m_bLoadFailed; } + bool IsLevelLoadFailed() const { return m_bLoadFailed; } //! Marks this document as having errors. void SetHasErrors() { m_hasErrors = true; } @@ -121,7 +121,7 @@ public: // Create from serialization only CClouds* GetClouds() { return m_pClouds; } void SetWaterColor(const QColor& col) { m_waterColor = col; } - QColor GetWaterColor() { return m_waterColor; } + QColor GetWaterColor() const { return m_waterColor; } XmlNodeRef& GetFogTemplate() { return m_fogTemplate; } XmlNodeRef& GetEnvironmentTemplate() { return m_environmentTemplate; } void OnEnvironmentPropertyChanged(IVariable* pVar); @@ -129,7 +129,7 @@ public: // Create from serialization only void RegisterListener(IDocListener* listener); void UnregisterListener(IDocListener* listener); - void GetMemoryUsage(ICrySizer* pSizer); + void GetMemoryUsage(ICrySizer* pSizer) const; static bool IsBackupOrTempLevelSubdirectory(const QString& folderName); protected: @@ -161,14 +161,14 @@ protected: void SerializeFogSettings(CXmlArchive& xmlAr); virtual void SerializeViewSettings(CXmlArchive& xmlAr); void SerializeNameSelection(CXmlArchive& xmlAr); - void LogLoadTime(int time); + void LogLoadTime(int time) const; struct TSaveDocContext { bool bSaved; }; bool BeforeSaveDocument(const QString& lpszPathName, TSaveDocContext& context); - bool HasLayerNameConflicts(); + bool HasLayerNameConflicts() const; bool DoSaveDocument(const QString& lpszPathName, TSaveDocContext& context); bool AfterSaveDocument(const QString& lpszPathName, TSaveDocContext& context, bool bShowPrompt = true); @@ -180,7 +180,7 @@ protected: void OnStartLevelResourceList(); static void OnValidateSurfaceTypesChanged(ICVar*); - QString GetCryIndexPath(const LPCTSTR levelFilePath); + QString GetCryIndexPath(const LPCTSTR levelFilePath) const; ////////////////////////////////////////////////////////////////////////// // SliceEditorEntityOwnershipServiceNotificationBus::Handler @@ -188,24 +188,26 @@ protected: void OnSliceInstantiationFailed(const AZ::Data::AssetId& sliceAssetId, const AzFramework::SliceInstantiationTicket& /*ticket*/) override; ////////////////////////////////////////////////////////////////////////// - bool m_bLoadFailed; - QColor m_waterColor; + bool m_bLoadFailed = false; + QColor m_waterColor = QColor(0, 0, 255); XmlNodeRef m_fogTemplate; XmlNodeRef m_environmentTemplate; CClouds* m_pClouds; std::list m_listeners; - bool m_bDocumentReady; - ICVar* doc_validate_surface_types; + bool m_bDocumentReady = false; + ICVar* doc_validate_surface_types = nullptr; int m_modifiedModuleFlags; - bool m_boLevelExported; - bool m_modified; + // On construction, it assumes loaded levels have already been exported. Can be a big fat lie, though. + // The right way would require us to save to the level folder the export status of the level. + bool m_boLevelExported = true; + bool m_modified = false; QString m_pathName; QString m_slicePathName; QString m_title; AZ::Data::AssetId m_envProbeSliceAssetId; float m_terrainSize; - const char* m_envProbeSliceRelativePath; - const float m_envProbeHeight; + const char* m_envProbeSliceRelativePath = "EngineAssets/Slices/DefaultLevelSetup.slice"; + const float m_envProbeHeight = 200.0f; bool m_hasErrors = false; ///< This is used to warn the user that they may lose work when they go to save. }; From b7e69a1d1dc41722f0bf7553d66dbda128026365 Mon Sep 17 00:00:00 2001 From: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Wed, 4 Aug 2021 14:11:10 -0500 Subject: [PATCH 152/157] turning off editor.blast.tests due to AR failures on suite shutdown (#2837) removed unused code Signed-off-by: Jackson <23512001+jackalbe@users.noreply.github.com> --- .../EditorBlastChunksAssetHandlerTest.cpp | 23 ------------------- .../Blast/Code/blast_editor_tests_files.cmake | 2 +- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp b/Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp index 9f48cae4da..80a0587b1b 100644 --- a/Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp +++ b/Gems/Blast/Code/Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp @@ -88,20 +88,6 @@ namespace UnitTest AZStd::unique_ptr m_mockComponentApplicationBusHandler; AZStd::unique_ptr m_mockAssetCatalogRequestBusHandler; AZStd::unique_ptr m_mockAssetManager; - AZStd::unique_ptr m_serializeContext; - - void SetUpChunkComponents() - { - m_serializeContext = AZStd::make_unique(); - - AZ::Entity::Reflect(m_serializeContext.get()); - AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get()); - } - - void TearDownChunkComponents() - { - m_serializeContext.reset(); - } void SetUp() override final { @@ -128,15 +114,6 @@ namespace UnitTest AZ::AllocatorInstance::Destroy(); AllocatorsTestFixture::TearDown(); } - - void SaveChunkAssetToStream(AZ::Entity* chunkAssetEntity, AZStd::vector& buffer) - { - buffer.clear(); - AZ::IO::ByteContainerStream> stream(&buffer); - AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&stream, *m_serializeContext.get(), AZ::ObjectStream::ST_XML); - objStream->WriteClass(chunkAssetEntity); - EXPECT_TRUE(objStream->Finalize()); - } }; TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetManager_Registered) diff --git a/Gems/Blast/Code/blast_editor_tests_files.cmake b/Gems/Blast/Code/blast_editor_tests_files.cmake index 7076530312..10d2377ccf 100644 --- a/Gems/Blast/Code/blast_editor_tests_files.cmake +++ b/Gems/Blast/Code/blast_editor_tests_files.cmake @@ -7,6 +7,6 @@ # set(FILES - Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp + # Disabled until SPEC-7904 is fixed Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp Tests/Editor/EditorTestMain.cpp ) From 1e4c147e0bf86737e4803cb60579ed4aae3660bd Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 4 Aug 2021 15:34:22 -0500 Subject: [PATCH 153/157] Fixed asset name for default groundplane. Signed-off-by: Chris Galvan --- Assets/Editor/Prefabs/Default_Level.prefab | 6 +++--- .../{groundplane_521x521m.fbx => groundplane_512x512m.fbx} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Groudplane/{groundplane_521x521m.fbx => groundplane_512x512m.fbx} (100%) diff --git a/Assets/Editor/Prefabs/Default_Level.prefab b/Assets/Editor/Prefabs/Default_Level.prefab index 64656e1e2f..d02d669f53 100644 --- a/Assets/Editor/Prefabs/Default_Level.prefab +++ b/Assets/Editor/Prefabs/Default_Level.prefab @@ -212,10 +212,10 @@ "Configuration": { "ModelAsset": { "assetId": { - "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}", - "subId": 277333723 + "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}", + "subId": 277889906 }, - "assetHint": "objects/groudplane/groundplane_521x521m.azmodel" + "assetHint": "objects/groudplane/groundplane_512x512m.azmodel" } } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Groudplane/groundplane_521x521m.fbx b/Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Groudplane/groundplane_512x512m.fbx similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Groudplane/groundplane_521x521m.fbx rename to Gems/AtomLyIntegration/CommonFeatures/Assets/Objects/Groudplane/groundplane_512x512m.fbx From 7404622b482cd5a40b5832552958ed2c33de317f Mon Sep 17 00:00:00 2001 From: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com> Date: Wed, 4 Aug 2021 16:54:40 -0700 Subject: [PATCH 154/157] Clear prefab templates on new level creations and loads (#2842) * Clear prefab templates on new level creations and loads Signed-off-by: srikappa-amzn * Fixed failing prefab unit tests after change to clear templates Signed-off-by: srikappa-amzn --- .../Entity/PrefabEditorEntityOwnershipService.cpp | 11 ++--------- .../PrefabInstanceToTemplatePropagatorTests.cpp | 4 +++- .../Tests/Prefab/PrefabUpdateInstancesTests.cpp | 1 + .../Tests/Prefab/PrefabUpdateTemplateTests.cpp | 1 + 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp index 2d97689610..b5cf5fb878 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp @@ -72,15 +72,8 @@ namespace AzToolsFramework if (m_rootInstance != nullptr) { - // Need to save off the template id to remove the template after the instance is deleted. - Prefab::TemplateId templateId = m_rootInstance->GetTemplateId(); m_rootInstance.reset(); - if (templateId != Prefab::InvalidTemplateId) - { - // Remove the template here so that if we're in a Deactivate/Activate cycle, it can recreate the template/rootInstance - // correctly - m_prefabSystemComponent->RemoveTemplate(templateId); - } + m_prefabSystemComponent->RemoveAllTemplates(); } } @@ -95,7 +88,7 @@ namespace AzToolsFramework if (templateId != Prefab::InvalidTemplateId) { m_rootInstance->SetTemplateId(Prefab::InvalidTemplateId); - m_prefabSystemComponent->RemoveTemplate(templateId); + m_prefabSystemComponent->RemoveAllTemplates(); } m_rootInstance->SetContainerEntityName("Level"); } diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp index e3b65db97e..8379992553 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabInstanceToTemplatePropagatorTests.cpp @@ -245,7 +245,9 @@ namespace UnitTest m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBeforeUpdate, *firstInstance); //remove instance from instance - firstInstance->DetachNestedInstance(addedAlias); + AZStd::unique_ptr detachedInstance = firstInstance->DetachNestedInstance(addedAlias); + ASSERT_TRUE(detachedInstance != nullptr); + m_prefabSystemComponent->RemoveLink(detachedInstance->GetLinkId()); //create document with after change snapshot PrefabDom instanceDomAfterUpdate; diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp index 0d955789ac..baded6d43e 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateInstancesTests.cpp @@ -309,6 +309,7 @@ namespace UnitTest // and use the updated enclosing Instance to update the PrefabDom of Template. AZStd::unique_ptr detachedInstance = newEnclosingInstance->DetachNestedInstance(nestedInstanceAliases.front()); ASSERT_TRUE(detachedInstance); + m_prefabSystemComponent->RemoveLink(detachedInstance->GetLinkId()); PrefabDom updatedTemplateDom; ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*newEnclosingInstance, updatedTemplateDom)); diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp index 4e7d9d95d1..6f90e245f7 100644 --- a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabUpdateTemplateTests.cpp @@ -274,6 +274,7 @@ namespace UnitTest InstanceAlias aliasOfWheelInstanceToRetain = wheelInstanceAliasesUnderAxle.front(); AZStd::unique_ptr detachedInstance = axleInstance->DetachNestedInstance(wheelInstanceAliasesUnderAxle.back()); ASSERT_TRUE(detachedInstance); + m_prefabSystemComponent->RemoveLink(detachedInstance->GetLinkId()); PrefabDom updatedAxleInstanceDom; ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*axleInstance, updatedAxleInstanceDom)); m_prefabSystemComponent->UpdatePrefabTemplate(axleTemplateId, updatedAxleInstanceDom); From 1169c82b98d4522541fb831d69902c54792ad7a3 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Thu, 5 Aug 2021 09:45:03 +0100 Subject: [PATCH 155/157] Make camera controller priority customizable (#2826) * make 'should handle' logic customizable Signed-off-by: hultonha * updates to get priority function Signed-off-by: hultonha * minor comment tweak Signed-off-by: hultonha --- Code/Editor/EditorViewportWidget.cpp | 7 +++ .../ModularViewportCameraController.h | 35 ++++++++++--- .../ModularViewportCameraController.cpp | 50 ++++++++++++------- 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 4ea36728ad..4c638e1f82 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -1240,6 +1240,13 @@ AZStd::shared_ptr CreateMod AzFramework::ViewportId viewportId) { auto controller = AZStd::make_shared(); + + controller->SetCameraPriorityBuilderCallback( + [](AtomToolsFramework::CameraControllerPriorityFn& cameraControllerPriorityFn) + { + cameraControllerPriorityFn = AtomToolsFramework::DefaultCameraControllerPriority; + }); + controller->SetCameraPropsBuilderCallback( [](AzFramework::CameraProps& cameraProps) { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index d8778a9b9d..e6a666c640 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -18,6 +18,14 @@ namespace AtomToolsFramework { class ModularViewportCameraControllerInstance; + //! A function object to represent returning a camera controller priority. + using CameraControllerPriorityFn = + AZStd::function; + + //! The default behavior for what priority the camera controller should respond to events at. + //! @note This can change based on the state of the camera controller/system. + AzFramework::ViewportControllerPriority DefaultCameraControllerPriority(const AzFramework::CameraSystem& cameraSystem); + //! Builder class to create and configure a ModularViewportCameraControllerInstance. class ModularViewportCameraController : public AzFramework::MultiViewportController< @@ -25,23 +33,33 @@ namespace AtomToolsFramework AzFramework::ViewportControllerPriority::DispatchToAllPriorities> { public: + friend ModularViewportCameraControllerInstance; + using CameraListBuilder = AZStd::function; using CameraPropsBuilder = AZStd::function; + using CameraPriorityBuilder = AZStd::function; - //! Sets the camera list builder callback used to populate new ModularViewportCameraControllerInstances + //! Sets the camera list builder callback used to populate new ModularViewportCameraControllerInstances. void SetCameraListBuilderCallback(const CameraListBuilder& builder); - //! Sets the camera props builder callback used to populate new ModularViewportCameraControllerInstances + //! Sets the camera props builder callback used to populate new ModularViewportCameraControllerInstances. void SetCameraPropsBuilderCallback(const CameraPropsBuilder& builder); - //! Sets up a camera list based on this controller's CameraListBuilderCallback - void SetupCameras(AzFramework::Cameras& cameras); - //! Sets up properties shared across all cameras - void SetupCameraProperies(AzFramework::CameraProps& cameraProps); + //! Sets the camera controller priority builder callback used to populate new ModularViewportCameraControllerInstances. + void SetCameraPriorityBuilderCallback(const CameraPriorityBuilder& builder); private: + //! Sets up a camera list based on this controller's CameraListBuilderCallback. + void SetupCameras(AzFramework::Cameras& cameras); + //! Sets up properties shared across all cameras. + void SetupCameraProperties(AzFramework::CameraProps& cameraProps); + //! Sets up how the camera controller should decide at what priority level to respond to. + void SetupCameraControllerPriority(CameraControllerPriorityFn& cameraPriorityFn); + //! Builder to generate a list of CameraInputs to run in the ModularViewportCameraControllerInstance. CameraListBuilder m_cameraListBuilder; - CameraPropsBuilder m_cameraPropsBuilder; //!< Builder to define custom camera properties to use for things such as rotate and - //!< translate interpolation. + //! Builder to define custom camera properties to use for things such as rotate and translate interpolation. + CameraPropsBuilder m_cameraPropsBuilder; + //! Builder to define what priority level the camera controller should respond to events at. + CameraPriorityBuilder m_cameraControllerPriorityBuilder; }; //! A customizable camera controller that can be configured to run a varying set of CameraInput instances. @@ -87,6 +105,7 @@ namespace AtomToolsFramework AzFramework::Camera m_targetCamera; //!< The target (next) camera state that m_camera is catching up to. AzFramework::CameraSystem m_cameraSystem; //!< The camera system responsible for managing all CameraInputs. AzFramework::CameraProps m_cameraProps; //!< Camera properties to control rotate and translate smoothness. + CameraControllerPriorityFn m_priorityFn; //!< Controls at what priority the camera controller should respond to events. CameraAnimation m_cameraAnimation; //!< Camera animation state (used during CameraMode::Animation). CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index cc87ba1e46..e98df83930 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -68,6 +68,11 @@ namespace AtomToolsFramework m_cameraPropsBuilder = builder; } + void ModularViewportCameraController::SetCameraPriorityBuilderCallback(const CameraPriorityBuilder& builder) + { + m_cameraControllerPriorityBuilder = builder; + } + void ModularViewportCameraController::SetupCameras(AzFramework::Cameras& cameras) { if (m_cameraListBuilder) @@ -76,7 +81,7 @@ namespace AtomToolsFramework } } - void ModularViewportCameraController::SetupCameraProperies(AzFramework::CameraProps& cameraProps) + void ModularViewportCameraController::SetupCameraProperties(AzFramework::CameraProps& cameraProps) { if (m_cameraPropsBuilder) { @@ -84,12 +89,36 @@ namespace AtomToolsFramework } } + void ModularViewportCameraController::SetupCameraControllerPriority(CameraControllerPriorityFn& cameraPriorityFn) + { + if (m_cameraControllerPriorityBuilder) + { + m_cameraControllerPriorityBuilder(cameraPriorityFn); + } + } + + // what priority should the camera system respond to + AzFramework::ViewportControllerPriority DefaultCameraControllerPriority(const AzFramework::CameraSystem& cameraSystem) + { + // ModernViewportCameraControllerInstance receives events at all priorities, when it is in 'exclusive' mode + // or it is actively handling events (essentially when the camera system is 'active' and responding to inputs) + // it should only respond to the highest priority + if (cameraSystem.m_cameras.Exclusive() || cameraSystem.HandlingEvents()) + { + return AzFramework::ViewportControllerPriority::Highest; + } + + // otherwise it should only respond to normal priority events + return AzFramework::ViewportControllerPriority::Normal; + } + ModularViewportCameraControllerInstance::ModularViewportCameraControllerInstance( const AzFramework::ViewportId viewportId, ModularViewportCameraController* controller) : MultiViewportControllerInstanceInterface(viewportId, controller) { controller->SetupCameras(m_cameraSystem.m_cameras); - controller->SetupCameraProperies(m_cameraProps); + controller->SetupCameraProperties(m_cameraProps); + controller->SetupCameraControllerPriority(m_priorityFn); if (auto viewportContext = RetrieveViewportContext(GetViewportId())) { @@ -118,24 +147,9 @@ namespace AtomToolsFramework AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect(); } - // what priority should the camera system respond to - static AzFramework::ViewportControllerPriority GetPriority(const AzFramework::CameraSystem& cameraSystem) - { - // ModernViewportCameraControllerInstance receives events at all priorities, when it is in 'exclusive' mode - // or it is actively handling events (essentially when the camera system is 'active' and responding to inputs) - // it should only respond to the highest priority - if (cameraSystem.m_cameras.Exclusive() || cameraSystem.HandlingEvents()) - { - return AzFramework::ViewportControllerPriority::Highest; - } - - // otherwise it should only respond to normal priority events - return AzFramework::ViewportControllerPriority::Normal; - } - bool ModularViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) { - if (event.m_priority == GetPriority(m_cameraSystem)) + if (event.m_priority == m_priorityFn(m_cameraSystem)) { return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel)); } From e55c31d959957ab9e26ea34b9d2befe986c010f1 Mon Sep 17 00:00:00 2001 From: AMZN-AlexOteiza <82234181+AMZN-AlexOteiza@users.noreply.github.com> Date: Thu, 5 Aug 2021 11:03:02 +0100 Subject: [PATCH 156/157] Improve ui object tree to show the actual instance class (#2844) Signed-off-by: Garcia Ruiz Co-authored-by: Garcia Ruiz --- Gems/QtForPython/Editor/Scripts/show_object_tree.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gems/QtForPython/Editor/Scripts/show_object_tree.py b/Gems/QtForPython/Editor/Scripts/show_object_tree.py index d68a288a3e..48fb5e585b 100755 --- a/Gems/QtForPython/Editor/Scripts/show_object_tree.py +++ b/Gems/QtForPython/Editor/Scripts/show_object_tree.py @@ -220,6 +220,8 @@ class ObjectTreeDialog(QDialog): return for child in obj.children(): object_type = type(child).__name__ + if child.metaObject().className() != object_type: + object_type = f"{child.metaObject().className()} ({object_type})" object_name = child.objectName() text = icon_text = title = window_title = geometry_str = classes = "(N/A)" if isinstance(child, QtGui.QWindow): From 34afed6792ef8a31532daebee86d168a2c3c135f Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Thu, 5 Aug 2021 14:27:31 +0100 Subject: [PATCH 157/157] fixed Ragdoll component can crash on deactivate (#2834) fixes #2650 The root of the crash was connecting/disconnecting to the AZ::Event SceneSimulationStart when not on the main thread, as that is not thread safe. The connection/disconnection was originally handled from Enable/EnableQueued and Disable/DisabledQueued which can be called from other threads within EmotionFX. I've moved the connection/disconnection to the Constructor / destructor, as the handler is responsible for executing the queued enable/disable actions and it makes sense to have that connection happen external to the Enable/disable path. Signed-off-by: amzn-sean 75276488+amzn-sean@users.noreply.github.com --- .../Source/PhysXCharacters/API/Ragdoll.cpp | 30 ++++--------------- .../Code/Source/PhysXCharacters/API/Ragdoll.h | 1 - 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.cpp index 5d3f6bf0e1..038a1e2ee7 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.cpp @@ -36,9 +36,6 @@ namespace PhysX } } // namespace Internal - // PhysX::Ragdoll - /*static*/ AZStd::mutex Ragdoll::m_sceneEventMutex; - void Ragdoll::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -109,14 +106,15 @@ namespace PhysX }) { m_sceneOwner = sceneHandle; + if (auto* sceneInterface = AZ::Interface::Get()) + { + sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler); + } } Ragdoll::~Ragdoll() { - { - AZStd::scoped_lock lock(m_sceneEventMutex); - m_sceneStartSimHandler.Disconnect(); - } + m_sceneStartSimHandler.Disconnect(); m_nodes.clear(); //the nodes destructor will remove the simulated body from the scene. } @@ -214,13 +212,6 @@ namespace PhysX } } - // the handler is also connected in EnableSimulationQueued(), - // which will call this function, so if called from that path dont connect here. - if (!m_sceneStartSimHandler.IsConnected()) - { - AZStd::scoped_lock lock(m_sceneEventMutex); - sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler); - } sceneInterface->EnableSimulationOfBody(m_sceneOwner, m_bodyHandle); } @@ -231,12 +222,6 @@ namespace PhysX return; } - if (auto* sceneInterface = AZ::Interface::Get()) - { - AZStd::scoped_lock lock(m_sceneEventMutex); - sceneInterface->RegisterSceneSimulationStartHandler(m_sceneOwner, m_sceneStartSimHandler); - } - m_queuedInitialState = initialState; } @@ -253,11 +238,6 @@ namespace PhysX return; } - { - AZStd::scoped_lock lock(m_sceneEventMutex); - m_sceneStartSimHandler.Disconnect(); - } - physx::PxScene* pxScene = Internal::GetPxScene(m_sceneOwner); const size_t numNodes = m_nodes.size(); diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.h b/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.h index 94a39d9732..c9d0d5d661 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.h +++ b/Gems/PhysX/Code/Source/PhysXCharacters/API/Ragdoll.h @@ -81,6 +81,5 @@ namespace PhysX bool m_queuedDisableSimulation = false; AzPhysics::SceneEvents::OnSceneSimulationStartHandler m_sceneStartSimHandler; - static AZStd::mutex m_sceneEventMutex; }; } // namespace PhysX