Changing material component property inspector to dockable view pane
• Inspector is locked to a specific entity and material assignment ID • All modifications are made via the material component request bus • Removed complicated configuration management in editor material component • Multiple material property inspectors can be opened • Multiple materials across different entities can be edited simultaneously • No longer blocks the viewport or other interactions • Added functions to material component request bus for retrieving material slot labels, default materials, getting and setting property and UV overrides • Added more asset related types to material property value conversion from any • Added support for static heading widget on top of atom tools inspector, currently used for menus and messages WIP: Still investigating intermittent crash because of corrupt asset property Signed-off-by: Guthrie Adams <guthadam@amazon.com>
This commit is contained in:
@@ -109,11 +109,20 @@ namespace AZ
|
||||
{
|
||||
result.m_value = AZStd::any_cast<Color>(value);
|
||||
}
|
||||
else if (value.is<Data::AssetId>())
|
||||
{
|
||||
result.m_value = Data::Asset<RPI::ImageAsset>(
|
||||
AZStd::any_cast<Data::AssetId>(value), azrtti_typeid<RPI::StreamingImageAsset>());
|
||||
}
|
||||
else if (value.is<Data::Asset<Data::AssetData>>())
|
||||
{
|
||||
result.m_value = Data::Asset<RPI::ImageAsset>(
|
||||
AZStd::any_cast<Data::Asset<Data::AssetData>>(value).GetId(), azrtti_typeid<RPI::StreamingImageAsset>());
|
||||
}
|
||||
else if (value.is<Data::Asset<StreamingImageAsset>>())
|
||||
{
|
||||
result.m_value = Data::Asset<RPI::ImageAsset>(
|
||||
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetId(),
|
||||
azrtti_typeid<RPI::StreamingImageAsset>());
|
||||
AZStd::any_cast<Data::Asset<StreamingImageAsset>>(value).GetId(), azrtti_typeid<RPI::StreamingImageAsset>());
|
||||
}
|
||||
else if (value.is<Data::Asset<ImageAsset>>())
|
||||
{
|
||||
@@ -129,7 +138,8 @@ namespace AZ
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning("MaterialPropertyValue", false, "Cannot convert any to variant. Type in any is: %s.",
|
||||
AZ_Warning(
|
||||
"MaterialPropertyValue", false, "Cannot convert any to variant. Type in any is: %s.",
|
||||
value.get_type_info().m_id.ToString<AZStd::string>().data());
|
||||
}
|
||||
|
||||
@@ -187,5 +197,5 @@ namespace AZ
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
+6
@@ -24,6 +24,12 @@ namespace AtomToolsFramework
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
typedef AZ::Uuid BusIdType;
|
||||
|
||||
//! Add heading widget above scroll area
|
||||
virtual void AddHeading(QWidget* headingWidget) = 0;
|
||||
|
||||
//! Clear heading widgets
|
||||
virtual void ClearHeading() = 0;
|
||||
|
||||
//! Clear all inspector groups and content
|
||||
virtual void Reset() = 0;
|
||||
|
||||
|
||||
+4
-1
@@ -41,6 +41,10 @@ namespace AtomToolsFramework
|
||||
~InspectorWidget() override;
|
||||
|
||||
// InspectorRequestBus::Handler overrides...
|
||||
void AddHeading(QWidget* headingWidget) override;
|
||||
|
||||
void ClearHeading() override;
|
||||
|
||||
void Reset() override;
|
||||
|
||||
void AddGroupsBegin() override;
|
||||
@@ -77,7 +81,6 @@ namespace AtomToolsFramework
|
||||
virtual void OnHeaderClicked(const AZStd::string& groupNameId, QMouseEvent* event);
|
||||
|
||||
private:
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
QScopedPointer<Ui::InspectorWidget> m_ui;
|
||||
|
||||
struct GroupWidgetPair
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ namespace AtomToolsFramework
|
||||
m_propertyEditor->Setup(context, instanceNotificationHandler, false);
|
||||
m_propertyEditor->AddInstance(instance, instanceClassId, nullptr, instanceToCompare);
|
||||
m_propertyEditor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
m_propertyEditor->QueueInvalidation(AzToolsFramework::PropertyModificationRefreshLevel::Refresh_EntireTree);
|
||||
m_propertyEditor->InvalidateAll();
|
||||
|
||||
m_layout->addWidget(m_propertyEditor);
|
||||
setLayout(m_layout);
|
||||
|
||||
@@ -29,30 +29,40 @@ namespace AtomToolsFramework
|
||||
{
|
||||
}
|
||||
|
||||
void InspectorWidget::AddHeading(QWidget* headingWidget)
|
||||
{
|
||||
headingWidget->setParent(m_ui->m_headingSection);
|
||||
m_ui->m_headingSectionLayout->addWidget(headingWidget);
|
||||
}
|
||||
|
||||
void InspectorWidget::ClearHeading()
|
||||
{
|
||||
qDeleteAll(m_ui->m_headingSection->findChildren<QWidget*>(QString(), Qt::FindDirectChildrenOnly));
|
||||
qDeleteAll(m_ui->m_headingSectionLayout->children());
|
||||
}
|
||||
|
||||
void InspectorWidget::Reset()
|
||||
{
|
||||
qDeleteAll(m_ui->m_propertyContent->children());
|
||||
m_layout = new QVBoxLayout(m_ui->m_propertyContent);
|
||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||
m_layout->setSpacing(0);
|
||||
qDeleteAll(m_ui->m_groupContents->findChildren<QWidget*>(QString(), Qt::FindDirectChildrenOnly));
|
||||
qDeleteAll(m_ui->m_groupContentsLayout->children());
|
||||
m_groups.clear();
|
||||
}
|
||||
|
||||
void InspectorWidget::AddGroupsBegin()
|
||||
{
|
||||
setUpdatesEnabled(false);
|
||||
setVisible(false);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void InspectorWidget::AddGroupsEnd()
|
||||
{
|
||||
m_layout->addStretch();
|
||||
m_ui->m_groupContentsLayout->addStretch();
|
||||
|
||||
// Scroll to top whenever there is new content
|
||||
m_ui->m_propertyScrollArea->verticalScrollBar()->setValue(m_ui->m_propertyScrollArea->verticalScrollBar()->minimum());
|
||||
m_ui->m_groupScrollArea->verticalScrollBar()->setValue(m_ui->m_groupScrollArea->verticalScrollBar()->minimum());
|
||||
|
||||
setUpdatesEnabled(true);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void InspectorWidget::AddGroup(
|
||||
@@ -61,14 +71,14 @@ namespace AtomToolsFramework
|
||||
const AZStd::string& groupDescription,
|
||||
QWidget* groupWidget)
|
||||
{
|
||||
InspectorGroupHeaderWidget* groupHeader = new InspectorGroupHeaderWidget(m_ui->m_propertyContent);
|
||||
InspectorGroupHeaderWidget* groupHeader = new InspectorGroupHeaderWidget(m_ui->m_groupContents);
|
||||
groupHeader->setText(groupDisplayName.c_str());
|
||||
groupHeader->setToolTip(groupDescription.c_str());
|
||||
m_layout->addWidget(groupHeader);
|
||||
m_ui->m_groupContentsLayout->addWidget(groupHeader);
|
||||
|
||||
groupWidget->setObjectName(groupNameId.c_str());
|
||||
groupWidget->setParent(m_ui->m_propertyContent);
|
||||
m_layout->addWidget(groupWidget);
|
||||
groupWidget->setParent(m_ui->m_groupContents);
|
||||
m_ui->m_groupContentsLayout->addWidget(groupWidget);
|
||||
|
||||
m_groups[groupNameId] = {groupHeader, groupWidget};
|
||||
|
||||
@@ -101,28 +111,18 @@ namespace AtomToolsFramework
|
||||
bool InspectorWidget::IsGroupVisible(const AZStd::string& groupNameId) const
|
||||
{
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
if (groupItr != m_groups.end())
|
||||
{
|
||||
return groupItr->second.m_header->isVisible();
|
||||
}
|
||||
|
||||
return false;
|
||||
return groupItr != m_groups.end() ? groupItr->second.m_header->isVisible() : false;
|
||||
}
|
||||
|
||||
bool InspectorWidget::IsGroupHidden(const AZStd::string& groupNameId) const
|
||||
{
|
||||
auto groupItr = m_groups.find(groupNameId);
|
||||
if (groupItr != m_groups.end())
|
||||
{
|
||||
return groupItr->second.m_header->isHidden();
|
||||
}
|
||||
|
||||
return false;
|
||||
return groupItr != m_groups.end() ? groupItr->second.m_header->isHidden() : false;
|
||||
}
|
||||
|
||||
void InspectorWidget::RefreshGroup(const AZStd::string& groupNameId)
|
||||
{
|
||||
for (auto groupWidget : m_ui->m_propertyContent->findChildren<InspectorGroupWidget*>(groupNameId.c_str()))
|
||||
for (auto groupWidget : m_ui->m_groupContents->findChildren<InspectorGroupWidget*>(groupNameId.c_str()))
|
||||
{
|
||||
groupWidget->Refresh();
|
||||
}
|
||||
@@ -130,7 +130,7 @@ namespace AtomToolsFramework
|
||||
|
||||
void InspectorWidget::RebuildGroup(const AZStd::string& groupNameId)
|
||||
{
|
||||
for (auto groupWidget : m_ui->m_propertyContent->findChildren<InspectorGroupWidget*>(groupNameId.c_str()))
|
||||
for (auto groupWidget : m_ui->m_groupContents->findChildren<InspectorGroupWidget*>(groupNameId.c_str()))
|
||||
{
|
||||
groupWidget->Rebuild();
|
||||
}
|
||||
@@ -138,7 +138,7 @@ namespace AtomToolsFramework
|
||||
|
||||
void InspectorWidget::RefreshAll()
|
||||
{
|
||||
for (auto groupWidget : m_ui->m_propertyContent->findChildren<InspectorGroupWidget*>())
|
||||
for (auto groupWidget : m_ui->m_groupContents->findChildren<InspectorGroupWidget*>())
|
||||
{
|
||||
groupWidget->Refresh();
|
||||
}
|
||||
@@ -146,7 +146,7 @@ namespace AtomToolsFramework
|
||||
|
||||
void InspectorWidget::RebuildAll()
|
||||
{
|
||||
for (auto groupWidget : m_ui->m_propertyContent->findChildren<InspectorGroupWidget*>())
|
||||
for (auto groupWidget : m_ui->m_groupContents->findChildren<InspectorGroupWidget*>())
|
||||
{
|
||||
groupWidget->Rebuild();
|
||||
}
|
||||
|
||||
@@ -6,20 +6,14 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>693</width>
|
||||
<height>798</height>
|
||||
<width>685</width>
|
||||
<height>775</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Inspector</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="m_inspectorLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@@ -36,50 +30,103 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="m_propertyScrollArea">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>691</width>
|
||||
<height>796</height>
|
||||
</rect>
|
||||
<widget class="QWidget" name="m_sections">
|
||||
<layout class="QVBoxLayout" name="m_sectionsLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="m_propertyContent">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="m_headingSection" native="true">
|
||||
<layout class="QVBoxLayout" name="m_headingSectionLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="m_groupSection" native="true">
|
||||
<layout class="QVBoxLayout" name="m_groupSectionLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="m_groupScrollArea">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_groupContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>683</width>
|
||||
<height>763</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="m_groupContentsLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
+8
-2
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Material/MaterialAssignmentId.h>
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
@@ -23,8 +25,12 @@ namespace AZ
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
//! Open document in material editor
|
||||
virtual void OpenInMaterialEditor(const AZStd::string& sourcePath) = 0;
|
||||
//! Open source material in material editor
|
||||
virtual void OpenMaterialEditor(const AZStd::string& sourcePath) = 0;
|
||||
|
||||
//! Open material instance editor
|
||||
virtual void OpenMaterialInspector(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0;
|
||||
};
|
||||
using EditorMaterialSystemComponentRequestBus = AZ::EBus<EditorMaterialSystemComponentRequests>;
|
||||
} // namespace Render
|
||||
|
||||
+14
-2
@@ -23,6 +23,10 @@ namespace AZ
|
||||
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;
|
||||
//! Get default material asset
|
||||
virtual AZ::Data::AssetId GetDefaultMaterialAssetId(const MaterialAssignmentId& materialAssignmentId) const = 0;
|
||||
//! Get material slot label
|
||||
virtual AZStd::string GetMaterialSlotLabel(const MaterialAssignmentId& materialAssignmentId) const = 0;
|
||||
//! Set material overrides
|
||||
virtual void SetMaterialOverrides(const MaterialAssignmentMap& materials) = 0;
|
||||
//! Get material overrides
|
||||
@@ -38,7 +42,7 @@ namespace AZ
|
||||
//! Set material override
|
||||
virtual void SetMaterialOverride(const MaterialAssignmentId& materialAssignmentId, const AZ::Data::AssetId& materialAssetId) = 0;
|
||||
//! Get material override
|
||||
virtual const AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const = 0;
|
||||
virtual AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const = 0;
|
||||
//! Clear material override
|
||||
virtual void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) = 0;
|
||||
//! Set a material property override value wrapped by an AZStd::any
|
||||
@@ -95,8 +99,16 @@ namespace AZ
|
||||
virtual void ClearPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) = 0;
|
||||
//! Clear all property overrides
|
||||
virtual void ClearAllPropertyOverrides() = 0;
|
||||
//! Set Property overrides for a specific material assignment
|
||||
virtual void SetPropertyOverrides(
|
||||
const MaterialAssignmentId& materialAssignmentId, const MaterialPropertyOverrideMap& propertyOverrides) = 0;
|
||||
//! Get Property overrides for a specific material assignment
|
||||
virtual MaterialPropertyOverrideMap GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const = 0;
|
||||
//! Set Model UV overrides for a specific material assignment
|
||||
virtual void SetModelUvOverrides(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) = 0;
|
||||
//! Get Model UV overrides for a specific material assignment
|
||||
virtual AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const = 0;
|
||||
};
|
||||
using MaterialComponentRequestBus = EBus<MaterialComponentRequests>;
|
||||
|
||||
@@ -106,7 +118,7 @@ namespace AZ
|
||||
{
|
||||
public:
|
||||
virtual void OnMaterialsUpdated([[maybe_unused]] const MaterialAssignmentMap& materials) {}
|
||||
virtual void OnMaterialsEdited([[maybe_unused]] const MaterialAssignmentMap& materials) {}
|
||||
virtual void OnMaterialsEdited() {}
|
||||
};
|
||||
using MaterialComponentNotificationBus = EBus<MaterialComponentNotifications>;
|
||||
|
||||
|
||||
+48
-146
@@ -215,91 +215,21 @@ namespace AZ
|
||||
void EditorMaterialComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
m_controller.SetDefaultMaterialOverride(assetId);
|
||||
|
||||
MaterialComponentNotificationBus::Event(GetEntityId(), &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
|
||||
}
|
||||
|
||||
AZ::u32 EditorMaterialComponent::OnConfigurationChanged()
|
||||
{
|
||||
// Whenever the user makes changes to the editor component data the controller configuration must be rebuilt
|
||||
m_configurationChangeInProgress = true;
|
||||
UpdateController();
|
||||
m_configurationChangeInProgress = false;
|
||||
|
||||
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::OnMaterialAssignmentsChanged()
|
||||
{
|
||||
// [GFX TODO][ATOM-4604] remove flag after mesh component material handling is fixed to not recreate/reload mesh for material changes
|
||||
if (!m_configurationChangeInProgress)
|
||||
{
|
||||
UpdateMaterialSlots();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::OnMaterialsEdited(const MaterialAssignmentMap& materials)
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Materials edited.");
|
||||
SetDirty();
|
||||
|
||||
// The layout of the materials slots is already set.
|
||||
// We just need to read the values from any edited overrides into the editor component
|
||||
// and refresh.
|
||||
for (auto& materialSlotPair : GetMaterialSlots())
|
||||
{
|
||||
EditorMaterialComponentSlot& slot = *materialSlotPair.second;
|
||||
const MaterialAssignment& materialFromController = GetMaterialAssignmentFromMap(materials, slot.m_id);
|
||||
slot.m_materialAsset = materialFromController.m_materialAsset;
|
||||
slot.m_propertyOverrides = materialFromController.m_propertyOverrides;
|
||||
slot.m_matModUvOverrides = materialFromController.m_matModUvOverrides;
|
||||
}
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
|
||||
AzToolsFramework::Refresh_AttributesAndValues);
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::UpdateConfiguration(const MaterialComponentConfig& config)
|
||||
{
|
||||
m_controller.SetMaterialOverrides(config.m_materials);
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::UpdateController()
|
||||
{
|
||||
SetDirty();
|
||||
|
||||
// Build the controller configuration from the editor configuration
|
||||
MaterialComponentConfig config = m_controller.GetConfiguration();
|
||||
config.m_materials.clear();
|
||||
|
||||
for (const auto& materialSlotPair : GetMaterialSlots())
|
||||
{
|
||||
const EditorMaterialComponentSlot* materialSlot = materialSlotPair.second;
|
||||
|
||||
// Do not apply materials for lods if they are disabled
|
||||
if (materialSlot->m_id.m_lodIndex != MaterialAssignmentId::NonLodIndex && !m_materialSlotsByLodEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only material slots with a valid asset IDs or property overrides will be copied
|
||||
// to minimize the amount of data stored in the controller and game component
|
||||
if (materialSlot->m_materialAsset.GetId().IsValid())
|
||||
{
|
||||
MaterialAssignment& materialAssignment = config.m_materials[materialSlot->m_id];
|
||||
materialAssignment.m_materialAsset = materialSlot->m_materialAsset;
|
||||
materialAssignment.m_propertyOverrides = materialSlot->m_propertyOverrides;
|
||||
materialAssignment.m_matModUvOverrides = materialSlot->m_matModUvOverrides;
|
||||
}
|
||||
else if (!materialSlot->m_propertyOverrides.empty() || !materialSlot->m_matModUvOverrides.empty())
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateConfiguration(config);
|
||||
UpdateMaterialSlots();
|
||||
}
|
||||
|
||||
void EditorMaterialComponent::UpdateMaterialSlots()
|
||||
@@ -315,64 +245,18 @@ namespace AZ
|
||||
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)
|
||||
{
|
||||
// Setup the material slot entry
|
||||
EditorMaterialComponentSlot slot;
|
||||
slot.m_entityId = GetEntityId();
|
||||
slot.m_id = materialPair.first;
|
||||
slot.m_materialChangedCallback = [this]() {
|
||||
// This callback is triggered whenever an individual material slot changes outside of normal inspector interactions
|
||||
// So we must manually handle undo, update configuration, and refresh the inspector to display the new values
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Material slot changed.");
|
||||
SetDirty();
|
||||
|
||||
OnConfigurationChanged();
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
|
||||
AzToolsFramework::Refresh_AttributesAndValues);
|
||||
};
|
||||
slot.m_propertyChangedCallback = [this]() {
|
||||
OnConfigurationChanged();
|
||||
};
|
||||
|
||||
const char* UnknownSlotName = "<unknown>";
|
||||
|
||||
// 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;
|
||||
|
||||
slot.m_propertyOverrides = materialFromController.m_propertyOverrides;
|
||||
slot.m_matModUvOverrides = materialFromController.m_matModUvOverrides;
|
||||
|
||||
// Attempt to get the UV names from model meshes.
|
||||
MaterialReceiverRequestBus::EventResult(slot.m_modelUvNames, GetEntityId(), &MaterialReceiverRequestBus::Events::GetModelUvNames);
|
||||
|
||||
if (slot.m_id.IsDefault())
|
||||
{
|
||||
m_defaultMaterialSlot = slot;
|
||||
@@ -388,7 +272,8 @@ namespace AZ
|
||||
if (slot.m_id.IsLodAndSlotId())
|
||||
{
|
||||
// Resize the containers to fit all elements
|
||||
m_materialSlotsByLod.resize(AZ::GetMax<size_t>(m_materialSlotsByLod.size(), aznumeric_cast<size_t>(slot.m_id.m_lodIndex + 1)));
|
||||
m_materialSlotsByLod.resize(
|
||||
AZ::GetMax<size_t>(m_materialSlotsByLod.size(), aznumeric_cast<size_t>(slot.m_id.m_lodIndex + 1)));
|
||||
m_materialSlotsByLod[slot.m_id.m_lodIndex].push_back(slot);
|
||||
continue;
|
||||
}
|
||||
@@ -404,9 +289,10 @@ namespace AZ
|
||||
[](const auto& a, const auto& b) { return a.GetLabel() < b.GetLabel(); });
|
||||
}
|
||||
|
||||
MaterialComponentNotificationBus::Event(GetEntityId(), &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
|
||||
AzToolsFramework::Refresh_EntireTree);
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree);
|
||||
}
|
||||
|
||||
AZ::u32 EditorMaterialComponent::ResetMaterialSlots()
|
||||
@@ -414,15 +300,15 @@ namespace AZ
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Resetting materials.");
|
||||
SetDirty();
|
||||
|
||||
UpdateConfiguration(MaterialComponentConfig());
|
||||
m_controller.SetMaterialOverrides(MaterialAssignmentMap());
|
||||
UpdateMaterialSlots();
|
||||
|
||||
m_materialSlotsByLodEnabled = false;
|
||||
|
||||
// Forcing refresh in case triggered from context menu action
|
||||
MaterialComponentNotificationBus::Event(GetEntityId(), &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
|
||||
AzToolsFramework::Refresh_EntireTree);
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree);
|
||||
|
||||
return AZ::Edit::PropertyRefreshLevels::EntireTree;
|
||||
}
|
||||
@@ -431,26 +317,26 @@ namespace AZ
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Generating materials.");
|
||||
SetDirty();
|
||||
|
||||
|
||||
// First generating a unique set of all material asset IDs that will be used for source data generation
|
||||
AZStd::unordered_map<AZ::Data::AssetId, AZStd::string /*slot name*/> assetIdMap;
|
||||
|
||||
auto materialSlots = GetMaterialSlots();
|
||||
for (auto& materialSlotPair : materialSlots)
|
||||
{
|
||||
Data::AssetId defaultMaterialAssetId = materialSlotPair.second->m_defaultMaterialAsset.GetId();
|
||||
Data::AssetId defaultMaterialAssetId = materialSlotPair.second->GetDefaultAssetId();
|
||||
if (defaultMaterialAssetId.IsValid())
|
||||
{
|
||||
assetIdMap[defaultMaterialAssetId] = materialSlotPair.second->GetLabel();
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the unique set of asset IDs into export items that can be configured in the dialog
|
||||
// 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};
|
||||
EditorMaterialComponentExporter::ExportItem exportItem{ assetIdInfo.first, assetIdInfo.second };
|
||||
exportItems.push_back(exportItem);
|
||||
}
|
||||
|
||||
@@ -474,9 +360,9 @@ namespace AZ
|
||||
if (editorMaterialSlot)
|
||||
{
|
||||
// We need to check whether replaced material corresponds to this slot's default material.
|
||||
if (editorMaterialSlot->m_defaultMaterialAsset.GetId() == exportItem.GetOriginalAssetId())
|
||||
if (editorMaterialSlot->GetDefaultAssetId() == exportItem.GetOriginalAssetId())
|
||||
{
|
||||
editorMaterialSlot->m_materialAsset.Create(assetIdOutcome.GetValue());
|
||||
editorMaterialSlot->SetAsset(assetIdOutcome.GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -484,17 +370,31 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
// Forcing refresh in case triggered from context menu action
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
|
||||
AzToolsFramework::Refresh_AttributesAndValues);
|
||||
MaterialComponentNotificationBus::Event(GetEntityId(), &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
return OnConfigurationChanged();
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
|
||||
|
||||
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
|
||||
}
|
||||
|
||||
AZ::u32 EditorMaterialComponent::OnLodsToggled()
|
||||
{
|
||||
OnConfigurationChanged();
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Toggling LOD materials.");
|
||||
SetDirty();
|
||||
|
||||
if (!m_materialSlotsByLodEnabled)
|
||||
{
|
||||
MaterialComponentConfig config = m_controller.GetConfiguration();
|
||||
AZStd::erase_if(config.m_materials, [](const auto& item) {
|
||||
const auto& [key, value] = item;
|
||||
return key.m_lodIndex != MaterialAssignmentId::NonLodIndex;
|
||||
});
|
||||
m_controller.SetMaterialOverrides(config.m_materials);
|
||||
}
|
||||
|
||||
MaterialComponentNotificationBus::Event(GetEntityId(), &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
return AZ::Edit::PropertyRefreshLevels::EntireTree;
|
||||
}
|
||||
|
||||
@@ -541,11 +441,14 @@ namespace AZ
|
||||
materialSlots[slot.m_id] = &slot;
|
||||
}
|
||||
|
||||
for (auto& slotsForLod : component.m_materialSlotsByLod)
|
||||
if (component.m_materialSlotsByLodEnabled)
|
||||
{
|
||||
for (auto& slot : slotsForLod)
|
||||
for (auto& slotsForLod : component.m_materialSlotsByLod)
|
||||
{
|
||||
materialSlots[slot.m_id] = &slot;
|
||||
for (auto& slot : slotsForLod)
|
||||
{
|
||||
materialSlots[slot.m_id] = &slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,4 +468,3 @@ namespace AZ
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
|
||||
+2
-14
@@ -8,11 +8,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <Atom/Feature/Utils/EditorRenderComponentAdapter.h>
|
||||
#include <Material/MaterialComponent.h>
|
||||
#include <Material/EditorMaterialComponentSlot.h>
|
||||
#include <Material/MaterialComponent.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -49,16 +49,6 @@ namespace AZ
|
||||
//! MaterialReceiverNotificationBus::Handler overrides...
|
||||
void OnMaterialAssignmentsChanged() override;
|
||||
|
||||
//! MaterialComponentNotificationBus::Handler overrides...
|
||||
void OnMaterialsEdited(const MaterialAssignmentMap& materials) override;
|
||||
|
||||
// Apply a material component configuration to the active controller
|
||||
void UpdateConfiguration(const MaterialComponentConfig& config);
|
||||
|
||||
// Converts the editor components material slots to the material component
|
||||
// configuration and updates the controller
|
||||
void UpdateController();
|
||||
|
||||
// Regenerates the editor component material slots based on the material and
|
||||
// LOD mapping from the model or other consumer of materials.
|
||||
// If any corresponding material assignments are found in the component
|
||||
@@ -101,8 +91,6 @@ namespace AZ
|
||||
EditorMaterialComponentSlotsByLodContainer m_materialSlotsByLod;
|
||||
bool m_materialSlotsByLodEnabled = false;
|
||||
|
||||
bool m_configurationChangeInProgress = false; // when true, model changes are ignored
|
||||
|
||||
static const char* GenerateMaterialsButtonText;
|
||||
static const char* GenerateMaterialsToolTipText;
|
||||
static const char* ResetMaterialsButtonText;
|
||||
|
||||
+286
-154
@@ -27,19 +27,16 @@
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConfig.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QApplication>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileInfo>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
@@ -49,26 +46,59 @@ namespace AZ
|
||||
{
|
||||
namespace EditorMaterialComponentInspector
|
||||
{
|
||||
MaterialPropertyInspector::MaterialPropertyInspector(
|
||||
const AZStd::string& slotName, const AZ::Data::AssetId& assetId, PropertyChangedCallback propertyChangedCallback,
|
||||
QWidget* parent)
|
||||
MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent)
|
||||
: AtomToolsFramework::InspectorWidget(parent)
|
||||
, m_slotName(slotName)
|
||||
, m_materialAssetId(assetId)
|
||||
, m_propertyChangedCallback(propertyChangedCallback)
|
||||
{
|
||||
// Create the menu button
|
||||
QToolButton* menuButton = new QToolButton(this);
|
||||
menuButton->setAutoRaise(true);
|
||||
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
|
||||
menuButton->setVisible(true);
|
||||
QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); });
|
||||
AddHeading(menuButton);
|
||||
|
||||
m_messageLabel = new QLabel(this);
|
||||
m_messageLabel->setWordWrap(true);
|
||||
m_messageLabel->setVisible(true);
|
||||
m_messageLabel->setAlignment(Qt::AlignCenter);
|
||||
m_messageLabel->setText(tr("Material not available"));
|
||||
AddHeading(m_messageLabel);
|
||||
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
MaterialPropertyInspector::~MaterialPropertyInspector()
|
||||
{
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::LoadMaterial()
|
||||
bool MaterialPropertyInspector::LoadMaterial(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId)
|
||||
{
|
||||
if (!EditorMaterialComponentUtil::LoadMaterialEditDataFromAssetId(m_materialAssetId, m_editData))
|
||||
UnloadMaterial();
|
||||
|
||||
m_entityId = entityId;
|
||||
m_materialAssignmentId = materialAssignmentId;
|
||||
MaterialComponentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialComponentNotificationBus::Handler::BusConnect(m_entityId);
|
||||
|
||||
AZ::Data::AssetId materialAssetId = {};
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
|
||||
|
||||
if (!materialAssetId.IsValid())
|
||||
{
|
||||
UnloadMaterial();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EditorMaterialComponentUtil::LoadMaterialEditDataFromAssetId(materialAssetId, m_editData))
|
||||
{
|
||||
AZ_Warning("AZ::Render::EditorMaterialComponentInspector", false, "Failed to load material data.");
|
||||
UnloadMaterial();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,6 +107,7 @@ namespace AZ
|
||||
if (!m_materialInstance)
|
||||
{
|
||||
AZ_Error("AZ::Render::EditorMaterialComponentInspector", false, "Material instance could not be created.");
|
||||
UnloadMaterial();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,15 +133,36 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
Populate();
|
||||
m_messageLabel->setVisible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::UnloadMaterial()
|
||||
{
|
||||
Reset();
|
||||
m_editData = EditorMaterialComponentUtil::MaterialEditData();
|
||||
m_materialInstance = {};
|
||||
m_dirtyPropertyFlags.set();
|
||||
m_editorFunctors = {};
|
||||
m_internalEditNotification = {};
|
||||
m_messageLabel->setVisible(true);
|
||||
m_messageLabel->setText(tr("Material not available"));
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::IsLoaded() const
|
||||
{
|
||||
return m_entityId.IsValid() && m_materialInstance && m_editData.m_materialAsset.IsReady();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::Reset()
|
||||
{
|
||||
m_activeProperty = {};
|
||||
m_groups = {};
|
||||
m_dirtyPropertyFlags.set();
|
||||
m_internalEditNotification = {};
|
||||
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::InspectorWidget::Reset();
|
||||
}
|
||||
@@ -150,9 +202,18 @@ namespace AZ
|
||||
QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str());
|
||||
QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str());
|
||||
|
||||
AZStd::string entityName;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(
|
||||
entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId);
|
||||
|
||||
AZStd::string slotName;
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
slotName, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialSlotLabel, m_materialAssignmentId);
|
||||
|
||||
QString materialInfo;
|
||||
materialInfo += tr("<table>");
|
||||
materialInfo += tr("<tr><td><b>Material Slot </b></td><td>%1</td></tr>").arg(m_slotName.c_str());
|
||||
materialInfo += tr("<tr><td><b>Entity </b></td><td>%1</td></tr>").arg(entityName.c_str());
|
||||
materialInfo += tr("<tr><td><b>Material Slot </b></td><td>%1</td></tr>").arg(slotName.c_str());
|
||||
if (!materialFileInfo.fileName().isEmpty())
|
||||
{
|
||||
materialInfo += tr("<tr><td><b>Material </b></td><td>%1</td></tr>").arg(materialFileInfo.fileName());
|
||||
@@ -209,16 +270,8 @@ namespace AZ
|
||||
}
|
||||
|
||||
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
|
||||
const AZ::Crc32 saveStateKey(AZStd::string::format(
|
||||
"MaterialPropertyInspector::PropertyGroup::%s::%s", m_materialAssetId.ToString<AZStd::string>().c_str(),
|
||||
groupNameId.c_str()));
|
||||
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
&group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey,
|
||||
[](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {
|
||||
AZ_UNUSED(source);
|
||||
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
|
||||
return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
|
||||
});
|
||||
&group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupNameId));
|
||||
AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
}
|
||||
|
||||
@@ -262,35 +315,90 @@ namespace AZ
|
||||
}
|
||||
|
||||
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
|
||||
const AZ::Crc32 saveStateKey(AZStd::string::format(
|
||||
"MaterialPropertyInspector::PropertyGroup::%s::%s", m_materialAssetId.ToString<AZStd::string>().c_str(),
|
||||
groupNameId.c_str()));
|
||||
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
|
||||
&group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey,
|
||||
[](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {
|
||||
AZ_UNUSED(source);
|
||||
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
|
||||
return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
|
||||
});
|
||||
&group, nullptr, group.TYPEINFO_Uuid(), this, this, GetSaveStateKeyForGroup(groupNameId));
|
||||
AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget);
|
||||
}
|
||||
|
||||
AddGroupsEnd();
|
||||
|
||||
m_dirtyPropertyFlags.set();
|
||||
RunEditorMaterialFunctors();
|
||||
LoadOverridesFromEntity();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::RunPropertyChangedCallback()
|
||||
void MaterialPropertyInspector::LoadOverridesFromEntity()
|
||||
{
|
||||
if (m_propertyChangedCallback)
|
||||
if (!IsLoaded())
|
||||
{
|
||||
m_propertyChangedCallback(m_editData.m_materialPropertyOverrideMap);
|
||||
return;
|
||||
}
|
||||
|
||||
m_editData.m_materialPropertyOverrideMap.clear();
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
m_editData.m_materialPropertyOverrideMap, m_entityId, &MaterialComponentRequestBus::Events::GetPropertyOverrides,
|
||||
m_materialAssignmentId);
|
||||
|
||||
for (auto& group : m_groups)
|
||||
{
|
||||
for (auto& property : group.second.m_properties)
|
||||
{
|
||||
const AtomToolsFramework::DynamicPropertyConfig& propertyConfig = property.GetConfig();
|
||||
const auto overrideItr = m_editData.m_materialPropertyOverrideMap.find(propertyConfig.m_id);
|
||||
const auto& editValue = overrideItr != m_editData.m_materialPropertyOverrideMap.end() ? overrideItr->second : propertyConfig.m_originalValue;
|
||||
|
||||
// This first converts to an acceptable runtime type in case the value came from script
|
||||
const auto propertyIndex = m_materialInstance->FindPropertyIndex(property.GetId());
|
||||
if (!propertyIndex.IsNull())
|
||||
{
|
||||
const auto runtimeValue = AtomToolsFramework::ConvertToRuntimeType(editValue);
|
||||
if (runtimeValue.IsValid())
|
||||
{
|
||||
property.SetValue(AtomToolsFramework::ConvertToEditableType(runtimeValue));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
property.SetValue(editValue);
|
||||
}
|
||||
|
||||
UpdateMaterialInstanceProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
m_dirtyPropertyFlags.set();
|
||||
RunEditorMaterialFunctors();
|
||||
RefreshAll();
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges)
|
||||
{
|
||||
if (!IsLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId,
|
||||
m_editData.m_materialPropertyOverrideMap);
|
||||
|
||||
if (commitChanges)
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Material slot changed.");
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId);
|
||||
|
||||
m_internalEditNotification = true;
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
m_internalEditNotification = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::RunEditorMaterialFunctors()
|
||||
{
|
||||
if (!IsLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::unordered_set<AZ::Name> changedPropertyNames;
|
||||
AZStd::unordered_set<AZ::Name> changedPropertyGroupNames;
|
||||
|
||||
@@ -337,11 +445,13 @@ namespace AZ
|
||||
// Apply any changes to material property meta data back to the editor property configurations
|
||||
for (auto& groupPair : m_groups)
|
||||
{
|
||||
AZ::Name groupName{groupPair.first};
|
||||
AZ::Name groupName{ groupPair.first };
|
||||
|
||||
if (changedPropertyGroupNames.find(groupName) != changedPropertyGroupNames.end())
|
||||
{
|
||||
SetGroupVisible(groupPair.first, propertyGroupDynamicMetadata[groupName].m_visibility == AZ::RPI::MaterialPropertyGroupVisibility::Enabled);
|
||||
SetGroupVisible(
|
||||
groupPair.first,
|
||||
propertyGroupDynamicMetadata[groupName].m_visibility == AZ::RPI::MaterialPropertyGroupVisibility::Enabled);
|
||||
}
|
||||
|
||||
for (auto& property : groupPair.second.m_properties)
|
||||
@@ -355,12 +465,12 @@ namespace AZ
|
||||
|
||||
if (oldReadOnly != propertyConfig.m_readOnly)
|
||||
{
|
||||
RefreshAll();
|
||||
RefreshGroup(groupPair.first);
|
||||
}
|
||||
|
||||
if (oldVisible != propertyConfig.m_visible)
|
||||
{
|
||||
RebuildAll();
|
||||
RebuildGroup(groupPair.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,57 +478,37 @@ namespace AZ
|
||||
|
||||
void MaterialPropertyInspector::UpdateMaterialInstanceProperty(const AtomToolsFramework::DynamicProperty& property)
|
||||
{
|
||||
if (m_materialInstance)
|
||||
if (!IsLoaded())
|
||||
{
|
||||
const auto propertyIndex = m_materialInstance->FindPropertyIndex(property.GetId());
|
||||
if (!propertyIndex.IsNull())
|
||||
{
|
||||
m_dirtyPropertyFlags.set(propertyIndex.GetIndex());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto runtimeValue = AtomToolsFramework::ConvertToRuntimeType(property.GetValue());
|
||||
if (runtimeValue.IsValid())
|
||||
{
|
||||
m_materialInstance->SetPropertyValue(propertyIndex, runtimeValue);
|
||||
}
|
||||
const auto propertyIndex = m_materialInstance->FindPropertyIndex(property.GetId());
|
||||
if (!propertyIndex.IsNull())
|
||||
{
|
||||
m_dirtyPropertyFlags.set(propertyIndex.GetIndex());
|
||||
|
||||
const auto runtimeValue = AtomToolsFramework::ConvertToRuntimeType(property.GetValue());
|
||||
if (runtimeValue.IsValid())
|
||||
{
|
||||
m_materialInstance->SetPropertyValue(propertyIndex, runtimeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::SetOverrides(const MaterialPropertyOverrideMap& propertyOverrideMap)
|
||||
AZ::Crc32 MaterialPropertyInspector::GetSaveStateKeyForGroup(const AZStd::string& groupNameId) const
|
||||
{
|
||||
m_editData.m_materialPropertyOverrideMap = propertyOverrideMap;
|
||||
return AZ::Crc32(AZStd::string::format(
|
||||
"MaterialPropertyInspector::PropertyGroup::%s::%s", m_editData.m_materialAssetId.ToString<AZStd::string>().c_str(),
|
||||
groupNameId.c_str()));
|
||||
}
|
||||
|
||||
for (auto& group : m_groups)
|
||||
{
|
||||
for (auto& property : group.second.m_properties)
|
||||
{
|
||||
const AtomToolsFramework::DynamicPropertyConfig& propertyConfig = property.GetConfig();
|
||||
const auto overrideItr = m_editData.m_materialPropertyOverrideMap.find(propertyConfig.m_id);
|
||||
const auto& editValue = overrideItr != m_editData.m_materialPropertyOverrideMap.end() ? overrideItr->second : propertyConfig.m_originalValue;
|
||||
|
||||
// This first converts to an acceptable runtime type in case the value came from script
|
||||
const auto propertyIndex = m_materialInstance->FindPropertyIndex(property.GetId());
|
||||
if (!propertyIndex.IsNull())
|
||||
{
|
||||
const auto runtimeValue = AtomToolsFramework::ConvertToRuntimeType(editValue);
|
||||
if (runtimeValue.IsValid())
|
||||
{
|
||||
property.SetValue(AtomToolsFramework::ConvertToEditableType(runtimeValue));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
property.SetValue(editValue);
|
||||
}
|
||||
|
||||
UpdateMaterialInstanceProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
m_dirtyPropertyFlags.set();
|
||||
RunPropertyChangedCallback();
|
||||
RunEditorMaterialFunctors();
|
||||
RebuildAll();
|
||||
bool MaterialPropertyInspector::AreNodePropertyValuesEqual(
|
||||
const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target)
|
||||
{
|
||||
AZ_UNUSED(source);
|
||||
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
|
||||
return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::SaveMaterial() const
|
||||
@@ -446,7 +536,8 @@ namespace AZ
|
||||
|
||||
bool MaterialPropertyInspector::SaveMaterialToSource() const
|
||||
{
|
||||
const QString saveFilePath = AtomToolsFramework::GetSaveFileInfo(m_editData.m_materialSourcePath.c_str()).absoluteFilePath();
|
||||
const QString saveFilePath =
|
||||
AtomToolsFramework::GetSaveFileInfo(m_editData.m_materialSourcePath.c_str()).absoluteFilePath();
|
||||
if (saveFilePath.isEmpty())
|
||||
{
|
||||
return false;
|
||||
@@ -463,13 +554,13 @@ namespace AZ
|
||||
|
||||
bool MaterialPropertyInspector::HasMaterialSource() const
|
||||
{
|
||||
return !m_editData.m_materialSourcePath.empty() &&
|
||||
return IsLoaded() && !m_editData.m_materialSourcePath.empty() &&
|
||||
AZ::StringFunc::Path::IsExtension(m_editData.m_materialSourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension);
|
||||
}
|
||||
|
||||
bool MaterialPropertyInspector::HasMaterialParentSource() const
|
||||
{
|
||||
return !m_editData.m_materialParentSourcePath.empty() &&
|
||||
return IsLoaded() && !m_editData.m_materialParentSourcePath.empty() &&
|
||||
AZ::StringFunc::Path::IsExtension(
|
||||
m_editData.m_materialParentSourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension);
|
||||
}
|
||||
@@ -479,7 +570,7 @@ namespace AZ
|
||||
if (HasMaterialSource())
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::OpenInMaterialEditor, m_editData.m_materialSourcePath);
|
||||
&EditorMaterialSystemComponentRequestBus::Events::OpenMaterialEditor, m_editData.m_materialSourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,10 +579,42 @@ namespace AZ
|
||||
if (HasMaterialParentSource())
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::OpenInMaterialEditor, m_editData.m_materialParentSourcePath);
|
||||
&EditorMaterialSystemComponentRequestBus::Events::OpenMaterialEditor, m_editData.m_materialParentSourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::OpenMenu()
|
||||
{
|
||||
QAction* action = nullptr;
|
||||
|
||||
QMenu menu(this);
|
||||
action = menu.addAction("Clear Overrides", [this] {
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId,
|
||||
MaterialPropertyOverrideMap());
|
||||
QueueUpdateUI();
|
||||
});
|
||||
action->setEnabled(IsLoaded());
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
action = menu.addAction("Save Material", [this] { SaveMaterial(); });
|
||||
action->setEnabled(IsLoaded());
|
||||
|
||||
action = menu.addAction("Save Material To Source", [this] { SaveMaterialToSource(); });
|
||||
action->setEnabled(HasMaterialSource());
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
action = menu.addAction("Open Source Material In Editor", [this] { OpenMaterialSourceInEditor(); });
|
||||
action->setEnabled(HasMaterialSource());
|
||||
|
||||
action = menu.addAction("Open Parent Material In Editor", [this] { OpenMaterialParentSourceInEditor(); });
|
||||
action->setEnabled(HasMaterialParentSource());
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
const EditorMaterialComponentUtil::MaterialEditData& MaterialPropertyInspector::GetEditData() const
|
||||
{
|
||||
return m_editData;
|
||||
@@ -501,7 +624,8 @@ namespace AZ
|
||||
{
|
||||
// For some reason the reflected property editor notifications are not symmetrical
|
||||
// This function is called continuously anytime a property changes until the edit has completed
|
||||
// Because of that, we have to track whether or not we are continuing to edit the same property to know when editing has started and ended
|
||||
// Because of that, we have to track whether or not we are continuing to edit the same property to know when editing has
|
||||
// started and ended
|
||||
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode);
|
||||
if (property)
|
||||
{
|
||||
@@ -521,15 +645,16 @@ namespace AZ
|
||||
{
|
||||
m_editData.m_materialPropertyOverrideMap[m_activeProperty->GetId()] = m_activeProperty->GetValue();
|
||||
UpdateMaterialInstanceProperty(*m_activeProperty);
|
||||
RunPropertyChangedCallback();
|
||||
SaveOverridesToEntity(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialPropertyInspector::SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode)
|
||||
{
|
||||
// As above, there are symmetrical functions on the notification interface for when editing begins and ends and has been completed but they are not being called following that pattern.
|
||||
// when this function executes the changes to the property are ready to be committed or reverted
|
||||
// As above, there are symmetrical functions on the notification interface for when editing begins and ends and has been
|
||||
// completed but they are not being called following that pattern. when this function executes the changes to the property
|
||||
// are ready to be committed or reverted
|
||||
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode);
|
||||
if (property)
|
||||
{
|
||||
@@ -537,85 +662,92 @@ namespace AZ
|
||||
{
|
||||
m_editData.m_materialPropertyOverrideMap[m_activeProperty->GetId()] = m_activeProperty->GetValue();
|
||||
UpdateMaterialInstanceProperty(*m_activeProperty);
|
||||
RunPropertyChangedCallback();
|
||||
SaveOverridesToEntity(true);
|
||||
RunEditorMaterialFunctors();
|
||||
m_activeProperty = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenInspectorDialog(
|
||||
const AZStd::string& slotName, const AZ::Data::AssetId& assetId, MaterialPropertyOverrideMap propertyOverrideMap,
|
||||
PropertyChangedCallback propertyChangedCallback)
|
||||
void MaterialPropertyInspector::OnEntityInitialized(const AZ::EntityId& entityId)
|
||||
{
|
||||
QWidget* activeWindow = nullptr;
|
||||
AzToolsFramework::EditorWindowRequestBus::BroadcastResult(activeWindow, &AzToolsFramework::EditorWindowRequests::GetAppMainWindow);
|
||||
|
||||
// Constructing a dialog with a table to display all configurable material export items
|
||||
QDialog dialog(activeWindow);
|
||||
dialog.setWindowTitle("Material Inspector");
|
||||
|
||||
MaterialPropertyInspector* inspector = new MaterialPropertyInspector(slotName, assetId, propertyChangedCallback, &dialog);
|
||||
if (!inspector->LoadMaterial())
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
return false;
|
||||
UnloadMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
inspector->Populate();
|
||||
inspector->SetOverrides(propertyOverrideMap);
|
||||
void MaterialPropertyInspector::OnEntityDestroyed(const AZ::EntityId& entityId)
|
||||
{
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
UnloadMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
// Create the menu button
|
||||
QToolButton* menuButton = new QToolButton(&dialog);
|
||||
menuButton->setAutoRaise(true);
|
||||
menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg"));
|
||||
menuButton->setVisible(true);
|
||||
QObject::connect(menuButton, &QToolButton::clicked, &dialog, [&]() {
|
||||
QAction* action = nullptr;
|
||||
void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId)
|
||||
{
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
QMenu menu(&dialog);
|
||||
action = menu.addAction("Clear Overrides", [&] { inspector->SetOverrides(MaterialPropertyOverrideMap()); });
|
||||
action = menu.addAction("Revert Changes", [&] { inspector->SetOverrides(propertyOverrideMap); });
|
||||
void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId)
|
||||
{
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
UnloadMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
action = menu.addAction("Save Material", [&] { inspector->SaveMaterial(); });
|
||||
action = menu.addAction("Save Material To Source", [&] { inspector->SaveMaterialToSource(); });
|
||||
action->setEnabled(inspector->HasMaterialSource());
|
||||
void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name)
|
||||
{
|
||||
AZ_UNUSED(name);
|
||||
if (m_entityId == entityId)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
action = menu.addAction("Open Source Material In Editor", [&] { inspector->OpenMaterialSourceInEditor(); });
|
||||
action->setEnabled(inspector->HasMaterialSource());
|
||||
action = menu.addAction("Open Parent Material In Editor", [&] { inspector->OpenMaterialParentSourceInEditor(); });
|
||||
action->setEnabled(inspector->HasMaterialParentSource());
|
||||
menu.exec(QCursor::pos());
|
||||
});
|
||||
void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time)
|
||||
{
|
||||
AZ_UNUSED(time);
|
||||
AZ_UNUSED(deltaTime);
|
||||
UpdateUI();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
QDialogButtonBox* buttonBox = new QDialogButtonBox(&dialog);
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||
QObject::connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
QObject::connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
void MaterialPropertyInspector::OnMaterialsEdited()
|
||||
{
|
||||
if (!m_internalEditNotification)
|
||||
{
|
||||
QueueUpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
QObject::connect(&dialog, &QDialog::rejected, &dialog, [&] { inspector->SetOverrides(propertyOverrideMap); });
|
||||
void MaterialPropertyInspector::UpdateUI()
|
||||
{
|
||||
AZ::Data::AssetId assetId;
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
assetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
|
||||
|
||||
QVBoxLayout* dialogLayout = new QVBoxLayout(&dialog);
|
||||
dialogLayout->addWidget(menuButton);
|
||||
dialogLayout->addWidget(inspector);
|
||||
dialogLayout->addWidget(buttonBox);
|
||||
dialog.setLayout(dialogLayout);
|
||||
dialog.setModal(true);
|
||||
if (IsLoaded() && m_editData.m_materialAssetId == assetId)
|
||||
{
|
||||
LoadOverridesFromEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadMaterial(m_entityId, m_materialAssignmentId);
|
||||
}
|
||||
}
|
||||
|
||||
// Forcing the initial dialog size to accomodate typical content.
|
||||
// Temporarily settng fixed size because dialog.show/exec invokes WindowDecorationWrapper::showEvent.
|
||||
// This forces the dialog to be centered and sized based on the layout of content.
|
||||
// Resizing the dialog after show will not be centered and moving the dialog programatically doesn't m0ve the custmk frame.
|
||||
dialog.setFixedSize(500, 800);
|
||||
dialog.show();
|
||||
|
||||
// Removing fixed size to allow drag resizing
|
||||
dialog.setMinimumSize(0, 0);
|
||||
dialog.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
||||
|
||||
// Return true if the user press the export button
|
||||
return dialog.exec() == QDialog::Accepted;
|
||||
void MaterialPropertyInspector::QueueUpdateUI()
|
||||
{
|
||||
if (!AZ::TickBus::Handler::BusIsConnected())
|
||||
{
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
}
|
||||
}
|
||||
} // namespace EditorMaterialComponentInspector
|
||||
} // namespace Render
|
||||
|
||||
+43
-17
@@ -9,17 +9,22 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
|
||||
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/EntityBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/function/function_base.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h>
|
||||
#include <Material/EditorMaterialComponentUtil.h>
|
||||
#endif
|
||||
|
||||
class QLabel;
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
@@ -31,31 +36,33 @@ namespace AZ
|
||||
class MaterialPropertyInspector
|
||||
: public AtomToolsFramework::InspectorWidget
|
||||
, public AzToolsFramework::IPropertyEditorNotify
|
||||
{
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
, public AZ::TickBus::Handler
|
||||
, public MaterialComponentNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MaterialPropertyInspector, AZ::SystemAllocator, 0);
|
||||
|
||||
explicit MaterialPropertyInspector(
|
||||
const AZStd::string& slotName, const AZ::Data::AssetId& assetId, PropertyChangedCallback propertyChangedCallback,
|
||||
QWidget* parent = nullptr);
|
||||
MaterialPropertyInspector(QWidget* parent = nullptr);
|
||||
~MaterialPropertyInspector() override;
|
||||
|
||||
bool LoadMaterial();
|
||||
bool LoadMaterial(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId);
|
||||
void UnloadMaterial();
|
||||
bool IsLoaded() const;
|
||||
|
||||
// AtomToolsFramework::InspectorRequestBus::Handler overrides...
|
||||
void Reset() override;
|
||||
|
||||
void Populate();
|
||||
|
||||
void SetOverrides(const MaterialPropertyOverrideMap& propertyOverrideMap);
|
||||
|
||||
bool SaveMaterial() const;
|
||||
bool SaveMaterialToSource() const;
|
||||
bool HasMaterialSource() const;
|
||||
bool HasMaterialParentSource() const;
|
||||
void OpenMaterialSourceInEditor() const;
|
||||
void OpenMaterialParentSourceInEditor() const;
|
||||
void OpenMenu();
|
||||
const EditorMaterialComponentUtil::MaterialEditData& GetEditData() const;
|
||||
|
||||
private:
|
||||
@@ -69,28 +76,47 @@ namespace AZ
|
||||
void RequestPropertyContextMenu([[maybe_unused]] AzToolsFramework::InstanceDataNode*, const QPoint&) override {}
|
||||
void PropertySelectionChanged([[maybe_unused]] AzToolsFramework::InstanceDataNode*, bool) override {}
|
||||
|
||||
// AZ::EntitySystemBus::Handler overrides...
|
||||
void OnEntityInitialized(const AZ::EntityId& entityId) override;
|
||||
void OnEntityDestroyed(const AZ::EntityId& entityId) override;
|
||||
void OnEntityActivated(const AZ::EntityId& entityId) override;
|
||||
void OnEntityDeactivated(const AZ::EntityId& entityId) override;
|
||||
void OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) override;
|
||||
|
||||
//! AZ::TickBus::Handler overrides...
|
||||
void OnTick(float deltaTime, ScriptTimePoint time) override;
|
||||
|
||||
//! MaterialComponentNotificationBus::Handler overrides...
|
||||
void OnMaterialsEdited() override;
|
||||
|
||||
void UpdateUI();
|
||||
void QueueUpdateUI();
|
||||
|
||||
void AddDetailsGroup();
|
||||
void AddUvNamesGroup();
|
||||
void RunPropertyChangedCallback();
|
||||
|
||||
void LoadOverridesFromEntity();
|
||||
void SaveOverridesToEntity(bool commitChanges);
|
||||
void RunEditorMaterialFunctors();
|
||||
void UpdateMaterialInstanceProperty(const AtomToolsFramework::DynamicProperty& property);
|
||||
|
||||
AZ::Crc32 GetSaveStateKeyForGroup(const AZStd::string& groupNameId) const;
|
||||
static bool AreNodePropertyValuesEqual(
|
||||
const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target);
|
||||
|
||||
// Tracking the property that is actively being edited in the inspector
|
||||
const AtomToolsFramework::DynamicProperty* m_activeProperty = {};
|
||||
|
||||
AZStd::string m_slotName;
|
||||
AZ::Data::AssetId m_materialAssetId = {};
|
||||
AZ::EntityId m_entityId;
|
||||
AZ::Render::MaterialAssignmentId m_materialAssignmentId;
|
||||
EditorMaterialComponentUtil::MaterialEditData m_editData;
|
||||
PropertyChangedCallback m_propertyChangedCallback = {};
|
||||
AZ::Data::Instance<AZ::RPI::Material> m_materialInstance = {};
|
||||
AZStd::vector<AZ::RPI::Ptr<AZ::RPI::MaterialFunctor>> m_editorFunctors = {};
|
||||
AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {};
|
||||
AZStd::unordered_map<AZStd::string, AtomToolsFramework::DynamicPropertyGroup> m_groups = {};
|
||||
};
|
||||
|
||||
bool OpenInspectorDialog(
|
||||
const AZStd::string& slotName, const AZ::Data::AssetId& assetId, MaterialPropertyOverrideMap propertyOverrideMap,
|
||||
PropertyChangedCallback propertyChangedCallback);
|
||||
bool m_internalEditNotification = {};
|
||||
QLabel* m_messageLabel = {};
|
||||
};
|
||||
} // namespace EditorMaterialComponentInspector
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+93
-62
@@ -80,10 +80,9 @@ namespace AZ
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<EditorMaterialComponentSlot>()
|
||||
->Version(6, &EditorMaterialComponentSlot::ConvertVersion)
|
||||
->Version(7, &EditorMaterialComponentSlot::ConvertVersion)
|
||||
->Field("id", &EditorMaterialComponentSlot::m_id)
|
||||
->Field("materialAsset", &EditorMaterialComponentSlot::m_materialAsset)
|
||||
->Field("defaultMaterialAsset", &EditorMaterialComponentSlot::m_defaultMaterialAsset)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
@@ -114,20 +113,22 @@ namespace AZ
|
||||
->Constructor<const EditorMaterialComponentSlot&>()
|
||||
->Property("id", BehaviorValueProperty(&EditorMaterialComponentSlot::m_id))
|
||||
->Property("materialAsset", BehaviorValueProperty(&EditorMaterialComponentSlot::m_materialAsset))
|
||||
->Property("propertyOverrides", BehaviorValueProperty(&EditorMaterialComponentSlot::m_propertyOverrides))
|
||||
->Property("matModUvOverrides", BehaviorValueProperty(&EditorMaterialComponentSlot::m_matModUvOverrides))
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
AZ::Data::AssetId EditorMaterialComponentSlot::GetDefaultAssetId() const
|
||||
{
|
||||
return m_defaultMaterialAsset.GetId();
|
||||
AZ::Data::AssetId assetId;
|
||||
MaterialComponentRequestBus::EventResult(assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id);
|
||||
return assetId;
|
||||
}
|
||||
|
||||
AZStd::string EditorMaterialComponentSlot::GetLabel() const
|
||||
{
|
||||
return m_label;
|
||||
AZStd::string label;
|
||||
MaterialComponentRequestBus::EventResult(label, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialSlotLabel, m_id);
|
||||
return label;
|
||||
}
|
||||
|
||||
bool EditorMaterialComponentSlot::HasSourceData() const
|
||||
@@ -137,50 +138,45 @@ namespace AZ
|
||||
return !sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension);
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OnMaterialChanged() const
|
||||
void EditorMaterialComponentSlot::SetAsset(const Data::AssetId& assetId)
|
||||
{
|
||||
if (m_materialChangedCallback)
|
||||
{
|
||||
m_materialChangedCallback();
|
||||
}
|
||||
m_materialAsset.Create(assetId);
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
|
||||
OnDataChanged();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OnPropertyChanged() const
|
||||
void EditorMaterialComponentSlot::SetAsset(const Data::Asset<RPI::MaterialAsset>& asset)
|
||||
{
|
||||
if (m_propertyChangedCallback)
|
||||
{
|
||||
m_propertyChangedCallback();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OpenMaterialEditor() const
|
||||
{
|
||||
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
|
||||
if (!sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension))
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(&EditorMaterialSystemComponentRequestBus::Events::OpenInMaterialEditor, sourcePath);
|
||||
}
|
||||
m_materialAsset = asset;
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
|
||||
OnDataChanged();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::Clear()
|
||||
{
|
||||
m_materialAsset = {};
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
|
||||
ClearOverrides();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::ClearToDefaultAsset()
|
||||
{
|
||||
m_materialAsset.Create(GetDefaultAssetId());
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
|
||||
ClearOverrides();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::ClearOverrides()
|
||||
{
|
||||
m_propertyOverrides = {};
|
||||
m_matModUvOverrides = {};
|
||||
OnMaterialChanged();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::ResetToDefaultAsset()
|
||||
{
|
||||
m_materialAsset = m_defaultMaterialAsset;
|
||||
m_propertyOverrides = {};
|
||||
m_matModUvOverrides = {};
|
||||
OnMaterialChanged();
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_id, MaterialPropertyOverrideMap());
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetModelUvOverrides, m_id, AZ::RPI::MaterialModelUvOverrideMap());
|
||||
OnDataChanged();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OpenMaterialExporter()
|
||||
@@ -189,7 +185,7 @@ namespace AZ
|
||||
// But we still need to allow the user to reconfigure it using the dialog
|
||||
EditorMaterialComponentExporter::ExportItemsContainer exportItems;
|
||||
{
|
||||
EditorMaterialComponentExporter::ExportItem exportItem{m_defaultMaterialAsset.GetId(), m_label};
|
||||
EditorMaterialComponentExporter::ExportItem exportItem{ GetDefaultAssetId(), GetLabel() };
|
||||
exportItems.push_back(exportItem);
|
||||
}
|
||||
|
||||
@@ -203,7 +199,8 @@ namespace AZ
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate a new asset ID utilizing the export file path so that we can update this material slot to reference the new asset
|
||||
// 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.GetExportPath(), 0);
|
||||
if (assetIdOutcome)
|
||||
{
|
||||
@@ -219,37 +216,43 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OpenMaterialEditor() const
|
||||
{
|
||||
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
|
||||
if (!sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension))
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::OpenMaterialEditor, sourcePath);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OpenMaterialInspector()
|
||||
{
|
||||
MaterialPropertyOverrideMap initialPropertyOverrides = m_propertyOverrides;
|
||||
auto applyPropertyChangedCallback = [this](const MaterialPropertyOverrideMap& propertyOverrides) {
|
||||
m_propertyOverrides = propertyOverrides;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
|
||||
if (m_materialAsset.GetId().IsValid())
|
||||
{
|
||||
if (EditorMaterialComponentInspector::OpenInspectorDialog(GetLabel(), m_materialAsset.GetId(), m_propertyOverrides, applyPropertyChangedCallback))
|
||||
{
|
||||
OnMaterialChanged();
|
||||
}
|
||||
}
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::OpenMaterialInspector, m_entityId, m_id);
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OpenUvNameMapInspector()
|
||||
{
|
||||
RPI::MaterialModelUvOverrideMap initialUvOverrides = m_matModUvOverrides;
|
||||
auto applyMatModUvOverrideChangedCallback = [this](const RPI::MaterialModelUvOverrideMap& matModUvOverrides) {
|
||||
m_matModUvOverrides = matModUvOverrides;
|
||||
// Treated as a special property. It will be updated together with properties.
|
||||
OnPropertyChanged();
|
||||
};
|
||||
|
||||
if (m_materialAsset.GetId().IsValid())
|
||||
{
|
||||
if (EditorMaterialComponentInspector::OpenInspectorDialog(m_materialAsset.GetId(), m_matModUvOverrides, m_modelUvNames, applyMatModUvOverrideChangedCallback))
|
||||
AZStd::unordered_set<AZ::Name> modelUvNames;
|
||||
MaterialReceiverRequestBus::EventResult(modelUvNames, m_entityId, &MaterialReceiverRequestBus::Events::GetModelUvNames);
|
||||
|
||||
RPI::MaterialModelUvOverrideMap matModUvOverrides;
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
matModUvOverrides, m_entityId, &MaterialComponentRequestBus::Events::GetModelUvOverrides, m_id);
|
||||
|
||||
auto applyMatModUvOverrideChangedCallback = [this](const RPI::MaterialModelUvOverrideMap& matModUvOverrides)
|
||||
{
|
||||
OnMaterialChanged();
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetModelUvOverrides, m_id, matModUvOverrides);
|
||||
};
|
||||
|
||||
if (EditorMaterialComponentInspector::OpenInspectorDialog(
|
||||
m_materialAsset.GetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback))
|
||||
{
|
||||
OnDataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,7 +264,7 @@ namespace AZ
|
||||
QAction* action = nullptr;
|
||||
|
||||
action = menu.addAction("Generate/Manage Source Material...", [this]() { OpenMaterialExporter(); });
|
||||
action->setEnabled(m_defaultMaterialAsset.GetId().IsValid());
|
||||
action->setEnabled(GetDefaultAssetId().IsValid());
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
@@ -276,10 +279,38 @@ namespace AZ
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
MaterialPropertyOverrideMap propertyOverrides;
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
propertyOverrides, m_entityId, &MaterialComponentRequestBus::Events::GetPropertyOverrides, m_id);
|
||||
RPI::MaterialModelUvOverrideMap matModUvOverrides;
|
||||
MaterialComponentRequestBus::EventResult(
|
||||
matModUvOverrides, m_entityId, &MaterialComponentRequestBus::Events::GetModelUvOverrides, m_id);
|
||||
|
||||
action = menu.addAction("Clear Material Instance Overrides", [this]() { ClearOverrides(); });
|
||||
action->setEnabled(!m_propertyOverrides.empty() || !m_matModUvOverrides.empty());
|
||||
action->setEnabled(!propertyOverrides.empty() || !matModUvOverrides.empty());
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OnMaterialChanged() const
|
||||
{
|
||||
MaterialComponentRequestBus::Event(
|
||||
m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId());
|
||||
OnDataChanged();
|
||||
}
|
||||
|
||||
void EditorMaterialComponentSlot::OnDataChanged() const
|
||||
{
|
||||
// This is triggered whenever a material slot changes outside of normal inspector interactions
|
||||
// Handle undo, update configuration, and refresh the inspector to display the new values
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Material slot changed.");
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId);
|
||||
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited);
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+8
-11
@@ -33,29 +33,26 @@ namespace AZ
|
||||
AZ::Data::AssetId GetDefaultAssetId() const;
|
||||
AZStd::string GetLabel() const;
|
||||
bool HasSourceData() const;
|
||||
void OpenMaterialEditor() const;
|
||||
void ResetToDefaultAsset();
|
||||
|
||||
void SetAsset(const Data::AssetId& assetId);
|
||||
void SetAsset(const Data::Asset<RPI::MaterialAsset>& asset);
|
||||
void Clear();
|
||||
void ClearToDefaultAsset();
|
||||
void ClearOverrides();
|
||||
|
||||
void OpenMaterialExporter();
|
||||
void OpenMaterialEditor() const;
|
||||
void OpenMaterialInspector();
|
||||
void OpenUvNameMapInspector();
|
||||
|
||||
AZ::EntityId m_entityId;
|
||||
MaterialAssignmentId m_id;
|
||||
AZStd::string m_label;
|
||||
Data::Asset<RPI::MaterialAsset> m_materialAsset;
|
||||
Data::Asset<RPI::MaterialAsset> m_defaultMaterialAsset;
|
||||
MaterialPropertyOverrideMap m_propertyOverrides;
|
||||
AZStd::function<void()> m_materialChangedCallback;
|
||||
AZStd::function<void()> m_propertyChangedCallback;
|
||||
|
||||
RPI::MaterialModelUvOverrideMap m_matModUvOverrides;
|
||||
AZStd::unordered_set<AZ::Name> m_modelUvNames; // Cached for override options.
|
||||
|
||||
private:
|
||||
void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType);
|
||||
void OnMaterialChanged() const;
|
||||
void OnPropertyChanged() const;
|
||||
void OnDataChanged() const;
|
||||
};
|
||||
|
||||
// Vector of slots for assignable or overridable material data.
|
||||
|
||||
+49
-21
@@ -6,33 +6,31 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Material/EditorMaterialSystemComponent.h>
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/Application/Application.h>
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/ViewPaneOptions.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
|
||||
#include <Editor/LyViewPaneNames.h>
|
||||
#include <Material/EditorMaterialComponentInspector.h>
|
||||
#include <Material/EditorMaterialSystemComponent.h>
|
||||
#include <Material/MaterialThumbnail.h>
|
||||
|
||||
// Disables warning messages triggered by the Qt library
|
||||
// 4251: class needs to have dll-interface to be used by clients of class
|
||||
// 4800: forcing value to bool 'true' or 'false' (performance warning)
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
|
||||
#include <QApplication>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QObject>
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QDockWidget>
|
||||
#include <QObject>
|
||||
#include <QProcessEnvironment>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
void InitMaterialEditorResources()
|
||||
@@ -95,6 +93,7 @@ namespace AZ
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect();
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
|
||||
AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect();
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
||||
|
||||
SetupThumbnails();
|
||||
m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions);
|
||||
@@ -106,6 +105,7 @@ namespace AZ
|
||||
AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect();
|
||||
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
||||
|
||||
TeardownThumbnails();
|
||||
m_materialBrowserInteractions.reset();
|
||||
@@ -117,7 +117,7 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OpenInMaterialEditor(const AZStd::string& sourcePath)
|
||||
void EditorMaterialSystemComponent::OpenMaterialEditor(const AZStd::string& sourcePath)
|
||||
{
|
||||
AZ_TracePrintf("MaterialComponent", "Launching Material Editor");
|
||||
|
||||
@@ -140,6 +140,20 @@ namespace AZ
|
||||
AtomToolsFramework::LaunchTool("MaterialEditor", ".exe", arguments);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OpenMaterialInspector(
|
||||
const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId)
|
||||
{
|
||||
auto dockWidget = AzToolsFramework::InstanceViewPane("Material Property Inspector");
|
||||
if (dockWidget)
|
||||
{
|
||||
auto inspector = static_cast<AZ::Render::EditorMaterialComponentInspector::MaterialPropertyInspector*>(dockWidget->widget());
|
||||
if (inspector)
|
||||
{
|
||||
inspector->LoadMaterial(entityId, materialAssignmentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::OnApplicationAboutToStop()
|
||||
{
|
||||
TeardownThumbnails();
|
||||
@@ -157,11 +171,12 @@ namespace AZ
|
||||
QObject::connect(
|
||||
m_openMaterialEditorAction, &QAction::triggered, m_openMaterialEditorAction, [this]()
|
||||
{
|
||||
OpenInMaterialEditor("");
|
||||
OpenMaterialEditor("");
|
||||
}
|
||||
);
|
||||
|
||||
AzToolsFramework::EditorMenuRequestBus::Broadcast(&AzToolsFramework::EditorMenuRequestBus::Handler::AddMenuAction, "ToolMenu", m_openMaterialEditorAction, true);
|
||||
AzToolsFramework::EditorMenuRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorMenuRequestBus::Handler::AddMenuAction, "ToolMenu", m_openMaterialEditorAction, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,13 +189,25 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::NotifyRegisterViews()
|
||||
{
|
||||
AzToolsFramework::ViewPaneOptions inspectorOptions;
|
||||
inspectorOptions.canHaveMultipleInstances = true;
|
||||
inspectorOptions.preferedDockingArea = Qt::NoDockWidgetArea;
|
||||
inspectorOptions.paneRect = QRect(50, 50, 400, 700);
|
||||
inspectorOptions.showInMenu = false;
|
||||
inspectorOptions.showOnToolsToolbar = false;
|
||||
AzToolsFramework::RegisterViewPane<AZ::Render::EditorMaterialComponentInspector::MaterialPropertyInspector>(
|
||||
"Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions);
|
||||
}
|
||||
|
||||
void EditorMaterialSystemComponent::SetupThumbnails()
|
||||
{
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider,
|
||||
MAKE_TCACHE(Thumbnails::MaterialThumbnailCache),
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache),
|
||||
ThumbnailContext::DefaultContext);
|
||||
}
|
||||
|
||||
@@ -189,12 +216,13 @@ namespace AZ
|
||||
using namespace AzToolsFramework::Thumbnailer;
|
||||
using namespace LyIntegration;
|
||||
|
||||
ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::UnregisterThumbnailProvider,
|
||||
Thumbnails::MaterialThumbnailCache::ProviderName,
|
||||
ThumbnailerRequestsBus::Broadcast(
|
||||
&ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName,
|
||||
ThumbnailContext::DefaultContext);
|
||||
}
|
||||
|
||||
AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails(const char* fullSourceFileName)
|
||||
AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails(
|
||||
const char* fullSourceFileName)
|
||||
{
|
||||
static const char* MaterialTypeIconPath = ":/Icons/materialtype.svg";
|
||||
static const char* MaterialTypeExtension = "materialtype";
|
||||
|
||||
+10
-6
@@ -8,11 +8,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
|
||||
#include <AzFramework/Application/Application.h>
|
||||
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
|
||||
#include <AzToolsFramework/Viewport/ActionBus.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
|
||||
@@ -28,8 +27,9 @@ namespace AZ
|
||||
: public AZ::Component
|
||||
, private EditorMaterialSystemComponentRequestBus::Handler
|
||||
, private AzFramework::ApplicationLifecycleEvents::Bus::Handler
|
||||
, public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
|
||||
, public AzToolsFramework::EditorMenuNotificationBus::Handler
|
||||
, private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
|
||||
, private AzToolsFramework::EditorMenuNotificationBus::Handler
|
||||
, private AzToolsFramework::EditorEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}");
|
||||
@@ -49,7 +49,8 @@ namespace AZ
|
||||
|
||||
private:
|
||||
//! EditorMaterialSystemComponentRequestBus::Handler overrides...
|
||||
void OpenInMaterialEditor(const AZStd::string& sourcePath) override;
|
||||
void OpenMaterialEditor(const AZStd::string& sourcePath) override;
|
||||
void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override;
|
||||
|
||||
// AzFramework::ApplicationLifecycleEvents overrides...
|
||||
void OnApplicationAboutToStop() override;
|
||||
@@ -61,6 +62,9 @@ namespace AZ
|
||||
void OnPopulateToolMenuItems() override;
|
||||
void OnResetToolMenuItems() override;
|
||||
|
||||
// AztoolsFramework::EditorEvents::Bus::Handler overrides...
|
||||
void NotifyRegisterViews() override;
|
||||
|
||||
void SetupThumbnails();
|
||||
void TeardownThumbnails();
|
||||
|
||||
|
||||
+6
-9
@@ -29,16 +29,13 @@ namespace AZ
|
||||
{
|
||||
if (HandlesSource(fullSourceFileName))
|
||||
{
|
||||
openers.push_back(
|
||||
{
|
||||
"Material_Editor",
|
||||
"Open in Material Editor...",
|
||||
QIcon(),
|
||||
openers.push_back({ "Material_Editor", "Open in Material Editor...", QIcon(),
|
||||
[&](const char* fullSourceFileNameInCallback, [[maybe_unused]] const AZ::Uuid& sourceUUID)
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(&EditorMaterialSystemComponentRequestBus::Events::OpenInMaterialEditor, fullSourceFileNameInCallback);
|
||||
}
|
||||
});
|
||||
{
|
||||
EditorMaterialSystemComponentRequestBus::Broadcast(
|
||||
&EditorMaterialSystemComponentRequestBus::Events::OpenMaterialEditor,
|
||||
fullSourceFileNameInCallback);
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+100
-26
@@ -35,6 +35,8 @@ namespace AZ
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
->Event("GetOriginalMaterialAssignments", &MaterialComponentRequestBus::Events::GetOriginalMaterialAssignments)
|
||||
->Event("FindMaterialAssignmentId", &MaterialComponentRequestBus::Events::FindMaterialAssignmentId)
|
||||
->Event("GetDefaultMaterialAssetId", &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId)
|
||||
->Event("GetMaterialSlotLabel", &MaterialComponentRequestBus::Events::GetMaterialSlotLabel)
|
||||
->Event("SetMaterialOverrides", &MaterialComponentRequestBus::Events::SetMaterialOverrides)
|
||||
->Event("GetMaterialOverrides", &MaterialComponentRequestBus::Events::GetMaterialOverrides)
|
||||
->Event("ClearAllMaterialOverrides", &MaterialComponentRequestBus::Events::ClearAllMaterialOverrides)
|
||||
@@ -71,6 +73,7 @@ namespace AZ
|
||||
->Event("ClearPropertyOverride", &MaterialComponentRequestBus::Events::ClearPropertyOverride)
|
||||
->Event("ClearPropertyOverrides", &MaterialComponentRequestBus::Events::ClearPropertyOverrides)
|
||||
->Event("ClearAllPropertyOverrides", &MaterialComponentRequestBus::Events::ClearAllPropertyOverrides)
|
||||
->Event("SetPropertyOverrides", &MaterialComponentRequestBus::Events::SetPropertyOverrides)
|
||||
->Event("GetPropertyOverrides", &MaterialComponentRequestBus::Events::GetPropertyOverrides)
|
||||
;
|
||||
}
|
||||
@@ -168,19 +171,26 @@ namespace AZ
|
||||
const auto& propertyOverrides2 = materialIt->second.m_propertyOverrides;
|
||||
for (auto& propertyPair : propertyOverrides2)
|
||||
{
|
||||
const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first);
|
||||
if (!materialPropertyIndex.IsNull())
|
||||
if (propertyPair.second.empty())
|
||||
{
|
||||
if (propertyPair.second.is<Data::AssetId>())
|
||||
{
|
||||
const auto& assetId = *AZStd::any_cast<Data::AssetId>(&propertyPair.second);
|
||||
Data::Asset<RPI::ImageAsset> imageAsset(assetId, azrtti_typeid<RPI::StreamingImageAsset>());
|
||||
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue(imageAsset));
|
||||
}
|
||||
else
|
||||
{
|
||||
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first);
|
||||
if (materialPropertyIndex.IsNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propertyPair.second.is<Data::AssetId>())
|
||||
{
|
||||
const auto& assetId = *AZStd::any_cast<Data::AssetId>(&propertyPair.second);
|
||||
Data::Asset<RPI::ImageAsset> imageAsset(assetId, azrtti_typeid<RPI::StreamingImageAsset>());
|
||||
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue(imageAsset));
|
||||
}
|
||||
else
|
||||
{
|
||||
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +298,40 @@ namespace AZ
|
||||
return materialAssignmentId;
|
||||
}
|
||||
|
||||
AZ::Data::AssetId MaterialComponentController::GetDefaultMaterialAssetId(const MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
RPI::ModelMaterialSlotMap modelMaterialSlots;
|
||||
MaterialReceiverRequestBus::EventResult(
|
||||
modelMaterialSlots, m_entityId, &MaterialReceiverRequestBus::Events::GetModelMaterialSlots);
|
||||
|
||||
auto slotIter = modelMaterialSlots.find(materialAssignmentId.m_materialSlotStableId);
|
||||
return slotIter != modelMaterialSlots.end() ? slotIter->second.m_defaultMaterialAsset.GetId() : AZ::Data::AssetId();
|
||||
}
|
||||
|
||||
AZStd::string MaterialComponentController::GetMaterialSlotLabel(const MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
if (materialAssignmentId == DefaultMaterialAssignmentId)
|
||||
{
|
||||
return "Default Material";
|
||||
}
|
||||
|
||||
RPI::ModelMaterialSlotMap modelMaterialSlots;
|
||||
MaterialReceiverRequestBus::EventResult(
|
||||
modelMaterialSlots, m_entityId, &MaterialReceiverRequestBus::Events::GetModelMaterialSlots);
|
||||
|
||||
auto slotIter = modelMaterialSlots.find(materialAssignmentId.m_materialSlotStableId);
|
||||
if (slotIter != modelMaterialSlots.end())
|
||||
{
|
||||
const Name& displayName = slotIter->second.m_displayName;
|
||||
if (!displayName.IsEmpty())
|
||||
{
|
||||
return displayName.GetStringView();
|
||||
}
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetMaterialOverrides(const MaterialAssignmentMap& materials)
|
||||
{
|
||||
// this function is called twice once material asset is changed, a temp variable is
|
||||
@@ -309,7 +353,6 @@ namespace AZ
|
||||
{
|
||||
m_configuration.m_materials.clear();
|
||||
QueueMaterialUpdateNotification();
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,12 +377,11 @@ namespace AZ
|
||||
LoadMaterials();
|
||||
}
|
||||
|
||||
const AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const
|
||||
AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
{
|
||||
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -351,7 +393,6 @@ namespace AZ
|
||||
if (m_configuration.m_materials.erase(materialAssignmentId) > 0)
|
||||
{
|
||||
QueueMaterialUpdateNotification();
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +413,6 @@ namespace AZ
|
||||
}
|
||||
|
||||
QueuePropertyChanges(materialAssignmentId);
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrideBool(
|
||||
@@ -450,14 +490,12 @@ namespace AZ
|
||||
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
{
|
||||
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto propertyIt = materialIt->second.m_propertyOverrides.find(AZ::Name(propertyName));
|
||||
if (propertyIt == materialIt->second.m_propertyOverrides.end())
|
||||
{
|
||||
AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -546,14 +584,12 @@ namespace AZ
|
||||
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
{
|
||||
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto propertyIt = materialIt->second.m_propertyOverrides.find(AZ::Name(propertyName));
|
||||
if (propertyIt == materialIt->second.m_propertyOverrides.end())
|
||||
{
|
||||
AZ_Error("MaterialComponentController", false, "Property not found: %s.", propertyName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -565,7 +601,6 @@ namespace AZ
|
||||
}
|
||||
|
||||
QueuePropertyChanges(materialAssignmentId);
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
|
||||
}
|
||||
|
||||
void MaterialComponentController::ClearPropertyOverrides(const MaterialAssignmentId& materialAssignmentId)
|
||||
@@ -573,7 +608,6 @@ namespace AZ
|
||||
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
{
|
||||
AZ_Error("MaterialComponentController", false, "MaterialAssignmentId not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -582,7 +616,6 @@ namespace AZ
|
||||
materialIt->second.m_propertyOverrides = {};
|
||||
materialIt->second.RebuildInstance();
|
||||
QueueMaterialUpdateNotification();
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,21 +635,62 @@ namespace AZ
|
||||
|
||||
if (cleared)
|
||||
{
|
||||
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited, m_configuration.m_materials);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetPropertyOverrides(
|
||||
const MaterialAssignmentId& materialAssignmentId, const MaterialPropertyOverrideMap& propertyOverrides)
|
||||
{
|
||||
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
|
||||
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
|
||||
materialAssignment.m_propertyOverrides = propertyOverrides;
|
||||
|
||||
if (wasEmpty != materialAssignment.m_propertyOverrides.empty())
|
||||
{
|
||||
materialAssignment.RebuildInstance();
|
||||
QueueMaterialUpdateNotification();
|
||||
}
|
||||
|
||||
QueuePropertyChanges(materialAssignmentId);
|
||||
}
|
||||
|
||||
MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
{
|
||||
AZ_Warning("MaterialComponentController", false, "MaterialAssignmentId not found.");
|
||||
return {};
|
||||
}
|
||||
return materialIt->second.m_propertyOverrides;
|
||||
}
|
||||
|
||||
void MaterialComponentController::SetModelUvOverrides(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides)
|
||||
{
|
||||
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
|
||||
const bool wasEmpty = materialAssignment.m_matModUvOverrides.empty();
|
||||
materialAssignment.m_matModUvOverrides = modelUvOverrides;
|
||||
|
||||
if (wasEmpty != materialAssignment.m_matModUvOverrides.empty())
|
||||
{
|
||||
materialAssignment.RebuildInstance();
|
||||
QueueMaterialUpdateNotification();
|
||||
}
|
||||
|
||||
QueuePropertyChanges(materialAssignmentId);
|
||||
}
|
||||
|
||||
AZ::RPI::MaterialModelUvOverrideMap MaterialComponentController::GetModelUvOverrides(
|
||||
const MaterialAssignmentId& materialAssignmentId) const
|
||||
{
|
||||
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
|
||||
if (materialIt == m_configuration.m_materials.end())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return materialIt->second.m_matModUvOverrides;
|
||||
}
|
||||
|
||||
void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId)
|
||||
{
|
||||
m_queuedPropertyOverrides.emplace(materialAssignmentId);
|
||||
|
||||
+8
-1
@@ -47,6 +47,8 @@ namespace AZ
|
||||
//! MaterialComponentRequestBus overrides...
|
||||
MaterialAssignmentMap GetOriginalMaterialAssignments() const override;
|
||||
MaterialAssignmentId FindMaterialAssignmentId(const MaterialAssignmentLodIndex lod, const AZStd::string& label) const override;
|
||||
AZ::Data::AssetId GetDefaultMaterialAssetId(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
AZStd::string GetMaterialSlotLabel(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
void SetMaterialOverrides(const MaterialAssignmentMap& materials) override;
|
||||
const MaterialAssignmentMap& GetMaterialOverrides() const override;
|
||||
void ClearAllMaterialOverrides() override;
|
||||
@@ -54,7 +56,7 @@ namespace AZ
|
||||
const AZ::Data::AssetId GetDefaultMaterialOverride() const override;
|
||||
void ClearDefaultMaterialOverride() override;
|
||||
void SetMaterialOverride(const MaterialAssignmentId& materialAssignmentId, const AZ::Data::AssetId& materialAssetId) override;
|
||||
const AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
AZ::Data::AssetId GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
void ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId) override;
|
||||
|
||||
void SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value) override;
|
||||
@@ -86,7 +88,12 @@ namespace AZ
|
||||
void ClearPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName) override;
|
||||
void ClearPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) override;
|
||||
void ClearAllPropertyOverrides() override;
|
||||
void SetPropertyOverrides(
|
||||
const MaterialAssignmentId& materialAssignmentId, const MaterialPropertyOverrideMap& propertyOverrides) override;
|
||||
MaterialPropertyOverrideMap GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
void SetModelUvOverrides(
|
||||
const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) override;
|
||||
AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user