Files
UnrealEngineUWP/Engine/Source/Editor/MaterialEditor/Private/SMaterialParametersOverviewWidget.cpp
sebastien hillaire a831062e45 Sparse volumetexture initial commit.
Sparse Volume Texture asset from imported OpenVDB (only a single float channel for now). Static or animated sequence.
It will be possible to generate SVT at runtime from GPU later.
Using FEditorBulkData for handling raw source without loading everything when not caching or cooking.
BulkData used at runtime for loading. No streaming yet.
Importer with dependency on OpenVDB is in a SparseVolumeTexture module only loaded when in editor

Sparse volume texture can be sampled from any materials (sample, sample parameter) and overridden on material instance and material instance dynamic.

Added support for uint in compiler (fetch from page table, see SparseVolumeTextureGetVoxelCoord)
Volume texture with u8 VirtualTextureLayerIndex!=255 (INDEX_NONE) are sparse texture. The layer index then represent what texture/attribute to sample.

#preflight https://horde.devtools.epicgames.com/job/6346a466f93be0f6345af86c
#rb Patrick.Kelly, Charles.deRousiers

[CL 22551963 by sebastien hillaire in ue5-main branch]
2022-10-16 02:28:34 -04:00

965 lines
32 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SMaterialParametersOverviewWidget.h"
#include "MaterialEditor/DEditorFontParameterValue.h"
#include "MaterialEditor/DEditorMaterialLayersParameterValue.h"
#include "MaterialEditor/DEditorScalarParameterValue.h"
#include "MaterialEditor/DEditorStaticComponentMaskParameterValue.h"
#include "MaterialEditor/DEditorStaticSwitchParameterValue.h"
#include "MaterialEditor/DEditorTextureParameterValue.h"
#include "MaterialEditor/DEditorVectorParameterValue.h"
#include "MaterialEditor/MaterialEditorInstanceConstant.h"
#include "Materials/Material.h"
#include "PropertyHandle.h"
#include "Modules/ModuleManager.h"
#include "PropertyEditorModule.h"
#include "ISinglePropertyView.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Styling/AppStyle.h"
#include "PropertyCustomizationHelpers.h"
#include "ScopedTransaction.h"
#include "IPropertyRowGenerator.h"
#include "Widgets/Views/STreeView.h"
#include "IDetailTreeNode.h"
#include "AssetThumbnail.h"
#include "MaterialEditorInstanceDetailCustomization.h"
#include "MaterialPropertyHelpers.h"
#include "DetailWidgetRow.h"
#include "Widgets/Input/SCheckBox.h"
#include "EditorSupportDelegates.h"
#include "Widgets/Images/SImage.h"
#include "MaterialEditor/MaterialEditorPreviewParameters.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Text/SInlineEditableTextBlock.h"
#include "Materials/MaterialFunctionInstance.h"
#include "Framework/Application/SlateApplication.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Curves/CurveLinearColor.h"
#include "Curves/CurveLinearColorAtlas.h"
#include "Widgets/Views/SExpanderArrow.h"
#include "Widgets/Layout/SWidgetSwitcher.h"
#include "MaterialEditor/DEditorRuntimeVirtualTextureParameterValue.h"
#include "MaterialEditor/DEditorSparseVolumeTextureParameterValue.h"
#include "ThumbnailRendering/ThumbnailManager.h"
#include "Styling/StyleColors.h"
#define LOCTEXT_NAMESPACE "MaterialLayerCustomization"
FString SMaterialParametersOverviewTreeItem::GetCurvePath(UDEditorScalarParameterValue* Parameter) const
{
FString Path = Parameter->AtlasData.Curve->GetPathName();
return Path;
}
const FSlateBrush* SMaterialParametersOverviewTreeItem::GetBorderImage() const
{
return FAppStyle::Get().GetBrush("DetailsView.CategoryMiddle");
}
FSlateColor SMaterialParametersOverviewTreeItem::GetOuterBackgroundColor(TSharedPtr<FSortedParamData> InParamData) const
{
if (IsHovered() || InParamData->StackDataType == EStackDataType::Group)
{
return FAppStyle::Get().GetSlateColor("Colors.Header");
}
return FAppStyle::Get().GetSlateColor("Colors.Panel");
}
void SMaterialParametersOverviewTreeItem::RefreshOnRowChange(const FAssetData& AssetData, TSharedPtr<SMaterialParametersOverviewTree> InTree)
{
if (InTree.IsValid())
{
InTree->CreateGroupsWidget();
}
}
void SMaterialParametersOverviewTreeItem::Construct(const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView)
{
StackParameterData = InArgs._StackParameterData;
MaterialEditorInstance = InArgs._MaterialEditorInstance;
Tree = InArgs._InTree;
TSharedRef<SWidget> LeftSideWidget = SNullWidget::NullWidget;
TSharedRef<SWidget> RightSideWidget = SNullWidget::NullWidget;
FText NameOverride;
TSharedRef<SVerticalBox> WrapperWidget = SNew(SVerticalBox);
// GROUP --------------------------------------------------
if (StackParameterData->StackDataType == EStackDataType::Group)
{
NameOverride = FText::FromName(StackParameterData->Group.GroupName);
LeftSideWidget = SNew(STextBlock)
.TransformPolicy(ETextTransformPolicy::ToUpper)
.Text(NameOverride)
.Font(FAppStyle::Get().GetFontStyle("PropertyWindow.BoldFont"))
.TextStyle(FAppStyle::Get(), "DetailsView.CategoryTextStyle");
}
// END GROUP
// PROPERTY ----------------------------------------------
bool bisPaddedProperty = false;
if (StackParameterData->StackDataType == EStackDataType::Property)
{
UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast<UDEditorStaticComponentMaskParameterValue>(StackParameterData->Parameter);
UDEditorVectorParameterValue* VectorParam = Cast<UDEditorVectorParameterValue>(StackParameterData->Parameter);
UDEditorScalarParameterValue* ScalarParam = Cast<UDEditorScalarParameterValue>(StackParameterData->Parameter);
UDEditorTextureParameterValue* TextureParam = Cast<UDEditorTextureParameterValue>(StackParameterData->Parameter);
TAttribute<bool> IsParamEnabled = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateStatic(&FMaterialPropertyHelpers::IsOverriddenExpression, StackParameterData->Parameter));
NameOverride = FText::FromName(StackParameterData->Parameter->ParameterInfo.Name);
IDetailTreeNode& Node = *StackParameterData->ParameterNode;
TSharedPtr<IDetailPropertyRow> GeneratedRow = StaticCastSharedPtr<IDetailPropertyRow>(Node.GetRow());
IDetailPropertyRow& Row = *GeneratedRow.Get();
Row.DisplayName(NameOverride);
if (VectorParam && VectorParam->bIsUsedAsChannelMask)
{
FOnGetPropertyComboBoxStrings GetMaskStrings = FOnGetPropertyComboBoxStrings::CreateStatic(&FMaterialPropertyHelpers::GetVectorChannelMaskComboBoxStrings);
FOnGetPropertyComboBoxValue GetMaskValue = FOnGetPropertyComboBoxValue::CreateStatic(&FMaterialPropertyHelpers::GetVectorChannelMaskValue, StackParameterData->Parameter);
FOnPropertyComboBoxValueSelected SetMaskValue = FOnPropertyComboBoxValueSelected::CreateStatic(&FMaterialPropertyHelpers::SetVectorChannelMaskValue, StackParameterData->ParameterNode->CreatePropertyHandle(), StackParameterData->Parameter, (UObject*)MaterialEditorInstance);
FDetailWidgetRow& CustomWidget = Row.CustomWidget();
CustomWidget
.FilterString(NameOverride)
.NameContent()
[
SNew(STextBlock)
.Text(NameOverride)
.ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
.ValueContent()
.MaxDesiredWidth(200.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.AutoWidth()
[
PropertyCustomizationHelpers::MakePropertyComboBox(StackParameterData->ParameterNode->CreatePropertyHandle(), GetMaskStrings, GetMaskValue, SetMaskValue)
]
]
];
}
else if (ScalarParam && ScalarParam->AtlasData.bIsUsedAsAtlasPosition)
{
const FText ParameterName = FText::FromName(StackParameterData->Parameter->ParameterInfo.Name);
FDetailWidgetRow& CustomWidget = Row.CustomWidget();
CustomWidget
.FilterString(ParameterName)
.NameContent()
[
SNew(STextBlock)
.Text(ParameterName)
.ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
.ValueContent()
.HAlign(HAlign_Fill)
.MaxDesiredWidth(400.0f)
[
SNew(SObjectPropertyEntryBox)
.ObjectPath(this, &SMaterialParametersOverviewTreeItem::GetCurvePath, ScalarParam)
.AllowedClass(UCurveLinearColor::StaticClass())
.NewAssetFactories(TArray<UFactory*>())
.DisplayThumbnail(true)
.ThumbnailPool(Tree.Pin()->GetTreeThumbnailPool())
.OnShouldFilterAsset(FOnShouldFilterAsset::CreateStatic(&FMaterialPropertyHelpers::OnShouldFilterCurveAsset, ScalarParam->AtlasData.Atlas))
.OnShouldSetAsset(FOnShouldSetAsset::CreateStatic(&FMaterialPropertyHelpers::OnShouldSetCurveAsset, ScalarParam->AtlasData.Atlas))
.OnObjectChanged(FOnSetObject::CreateStatic(&FMaterialPropertyHelpers::SetPositionFromCurveAsset, ScalarParam->AtlasData.Atlas, ScalarParam, StackParameterData->ParameterHandle, (UObject*)MaterialEditorInstance))
.DisplayCompactSize(true)
];
}
else if (TextureParam)
{
UMaterial *Material = MaterialEditorInstance->PreviewMaterial;
if (Material != nullptr)
{
UMaterialExpressionTextureSampleParameter* Expression = Material->FindExpressionByGUID<UMaterialExpressionTextureSampleParameter>(TextureParam->ExpressionId);
if (Expression != nullptr)
{
TWeakObjectPtr<UMaterialExpressionTextureSampleParameter> SamplerExpression = Expression;
TSharedPtr<SWidget> NameWidget;
TSharedPtr<SWidget> ValueWidget;
FDetailWidgetRow DefaultRow;
Row.GetDefaultWidgets(NameWidget, ValueWidget, DefaultRow);
FDetailWidgetRow &DetailWidgetRow = Row.CustomWidget();
TSharedPtr<SVerticalBox> NameVerticalBox;
DetailWidgetRow.NameContent()
[
SAssignNew(NameVerticalBox, SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock)
.Text(FText::FromName(StackParameterData->Parameter->ParameterInfo.Name))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
];
DetailWidgetRow.ValueContent()
.MinDesiredWidth(DefaultRow.ValueWidget.MinWidth)
.MaxDesiredWidth(DefaultRow.ValueWidget.MaxWidth)
[
SNew(SObjectPropertyEntryBox)
.PropertyHandle(StackParameterData->ParameterNode->CreatePropertyHandle())
.AllowedClass(UTexture::StaticClass())
.ThumbnailPool(Tree.Pin()->GetTreeThumbnailPool())
.OnShouldFilterAsset_Lambda([SamplerExpression](const FAssetData& AssetData)
{
if (SamplerExpression.Get())
{
bool VirtualTextured = false;
AssetData.GetTagValue<bool>("VirtualTextureStreaming", VirtualTextured);
bool ExpressionIsVirtualTextured = IsVirtualSamplerType(SamplerExpression->SamplerType);
return VirtualTextured != ExpressionIsVirtualTextured;
}
else
{
return false;
}
})
];
static const FName Red("R");
static const FName Green("G");
static const FName Blue("B");
static const FName Alpha("A");
if (!TextureParam->ChannelNames.R.IsEmpty())
{
NameVerticalBox->AddSlot()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(20.0, 2.0, 4.0, 2.0)
[
SNew(STextBlock)
.Text(FText::FromName(Red))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.Padding(4.0, 2.0)
[
SNew(STextBlock)
.Text(TextureParam->ChannelNames.R)
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
];
}
if (!TextureParam->ChannelNames.G.IsEmpty())
{
NameVerticalBox->AddSlot()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(20.0, 2.0, 4.0, 2.0)
.AutoWidth()
[
SNew(STextBlock)
.Text(FText::FromName(Green))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.Padding(4.0, 2.0)
[
SNew(STextBlock)
.Text(TextureParam->ChannelNames.G)
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
];
}
if (!TextureParam->ChannelNames.B.IsEmpty())
{
NameVerticalBox->AddSlot()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(20.0, 2.0, 4.0, 2.0)
.AutoWidth()
[
SNew(STextBlock)
.Text(FText::FromName(Blue))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.Padding(4.0, 2.0)
[
SNew(STextBlock)
.Text(TextureParam->ChannelNames.B)
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
];
}
if (!TextureParam->ChannelNames.A.IsEmpty())
{
NameVerticalBox->AddSlot()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(20.0, 2.0, 4.0, 2.0)
.AutoWidth()
[
SNew(STextBlock)
.Text(FText::FromName(Alpha))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.BoldFont")))
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.Padding(4.0, 2.0)
[
SNew(STextBlock)
.Text(TextureParam->ChannelNames.A)
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
];
}
}
}
}
else if (CompMaskParam)
{
TSharedPtr<IPropertyHandle> RMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("R");
TSharedPtr<IPropertyHandle> GMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("G");
TSharedPtr<IPropertyHandle> BMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("B");
TSharedPtr<IPropertyHandle> AMaskProperty = StackParameterData->ParameterNode->CreatePropertyHandle()->GetChildHandle("A");
FDetailWidgetRow& CustomWidget = Row.CustomWidget();
CustomWidget
.FilterString(NameOverride)
.NameContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(NameOverride)
.ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
]
.ValueContent()
.MaxDesiredWidth(200.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.FillWidth(1.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.AutoWidth()
[
RMaskProperty->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.AutoWidth()
[
RMaskProperty->CreatePropertyValueWidget()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
.AutoWidth()
[
GMaskProperty->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.AutoWidth()
[
GMaskProperty->CreatePropertyValueWidget()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
.AutoWidth()
[
BMaskProperty->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.AutoWidth()
[
BMaskProperty->CreatePropertyValueWidget()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
.AutoWidth()
[
AMaskProperty->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.AutoWidth()
[
AMaskProperty->CreatePropertyValueWidget()
]
]
];
}
else
{
if (TSharedPtr<IPropertyHandle> PropertyHandle = StackParameterData->ParameterNode->CreatePropertyHandle())
{
PropertyHandle->MarkResetToDefaultCustomized(true);
}
FDetailWidgetDecl* CustomNameWidget = Row.CustomNameWidget();
if (CustomNameWidget)
{
(*CustomNameWidget)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(NameOverride)
.ToolTipText(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance))
.Font(FAppStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont")))
]
];
}
else
{
Row.ToolTip(FMaterialPropertyHelpers::GetParameterExpressionDescription(StackParameterData->Parameter, MaterialEditorInstance));
}
bisPaddedProperty = true;
}
FNodeWidgets NodeWidgets = Node.CreateNodeWidgets();
LeftSideWidget = NodeWidgets.NameWidget.ToSharedRef();
RightSideWidget = NodeWidgets.ValueWidget.ToSharedRef();
}
// END PROPERTY
// PROPERTY CHILD ----------------------------------------
if (StackParameterData->StackDataType == EStackDataType::PropertyChild)
{
FNodeWidgets NodeWidgets = StackParameterData->ParameterNode->CreateNodeWidgets();
LeftSideWidget = NodeWidgets.NameWidget.ToSharedRef();
RightSideWidget = NodeWidgets.ValueWidget.ToSharedRef();
}
// END PROPERTY CHILD
// FINAL WRAPPER
{
FDetailColumnSizeData& ColumnSizeData = InArgs._InTree->GetColumnSizeData();
float ValuePadding = bisPaddedProperty ? 20.0f : 0.0f;
WrapperWidget->AddSlot()
.AutoHeight()
[
SNew(SBorder)
.BorderImage(FAppStyle::Get().GetBrush("DetailsView.GridLine"))
.Padding(FMargin(0, 0, 0, 1))
[
SNew(SBorder)
.Padding(3.0f)
.BorderImage(this, &SMaterialParametersOverviewTreeItem::GetBorderImage)
.BorderBackgroundColor(this, &SMaterialParametersOverviewTreeItem::GetOuterBackgroundColor, StackParameterData)
[
SNew(SSplitter)
.Style(FAppStyle::Get(), "DetailsView.Splitter")
.PhysicalSplitterHandleSize(1.0f)
.HitDetectionSplitterHandleSize(5.0f)
+ SSplitter::Slot()
.Value(ColumnSizeData.GetNameColumnWidth())
.OnSlotResized(ColumnSizeData.GetOnNameColumnResized())
.Value(0.25f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(FMargin(3.0f))
[
SNew(SExpanderArrow, SharedThis(this))
]
+ SHorizontalBox::Slot()
.Padding(FMargin(2.0f))
.VAlign(VAlign_Center)
[
LeftSideWidget
]
]
+ SSplitter::Slot()
.Value(ColumnSizeData.GetValueColumnWidth())
.OnSlotResized(ColumnSizeData.GetOnValueColumnResized())
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(FMargin(5.0f, 2.0f, 5.0, 2.0f))
.HAlign(HAlign_Left)
.VAlign(VAlign_Center)
[
RightSideWidget
]
]
]
]
];
}
this->ChildSlot
[
WrapperWidget
];
STableRow< TSharedPtr<FSortedParamData> >::ConstructInternal(
STableRow::FArguments()
.Style(FAppStyle::Get(), "DetailsView.TreeView.TableRow")
.ShowSelection(false),
InOwnerTableView
);
}
void SMaterialParametersOverviewTree::Construct(const FArguments& InArgs)
{
bHasAnyParameters = false;
MaterialEditorInstance = InArgs._InMaterialEditorInstance;
Owner = InArgs._InOwner;
CreateGroupsWidget();
STreeView<TSharedPtr<FSortedParamData>>::Construct(
STreeView::FArguments()
.TreeItemsSource(&SortedParameters)
.SelectionMode(ESelectionMode::None)
.OnGenerateRow(this, &SMaterialParametersOverviewTree::OnGenerateRowMaterialLayersFunctionsTreeView)
.OnGetChildren(this, &SMaterialParametersOverviewTree::OnGetChildrenMaterialLayersFunctionsTreeView)
.OnExpansionChanged(this, &SMaterialParametersOverviewTree::OnExpansionChanged)
.ExternalScrollbar(InArgs._InScrollbar)
);
}
TSharedRef< ITableRow > SMaterialParametersOverviewTree::OnGenerateRowMaterialLayersFunctionsTreeView(TSharedPtr<FSortedParamData> Item, const TSharedRef< STableViewBase >& OwnerTable)
{
TSharedRef< SMaterialParametersOverviewTreeItem > ReturnRow = SNew(SMaterialParametersOverviewTreeItem, OwnerTable)
.StackParameterData(Item)
.MaterialEditorInstance(MaterialEditorInstance)
.InTree(SharedThis(this));
return ReturnRow;
}
void SMaterialParametersOverviewTree::OnGetChildrenMaterialLayersFunctionsTreeView(TSharedPtr<FSortedParamData> InParent, TArray< TSharedPtr<FSortedParamData> >& OutChildren)
{
OutChildren = InParent->Children;
}
void SMaterialParametersOverviewTree::OnExpansionChanged(TSharedPtr<FSortedParamData> Item, bool bIsExpanded)
{
bool* ExpansionValue = MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Find(Item->NodeKey);
if (ExpansionValue == nullptr)
{
MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Add(Item->NodeKey, bIsExpanded);
}
else if (*ExpansionValue != bIsExpanded)
{
MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Emplace(Item->NodeKey, bIsExpanded);
}
// Expand any children that are also expanded
for (auto Child : Item->Children)
{
bool* ChildExpansionValue = MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Find(Child->NodeKey);
if (ChildExpansionValue != nullptr && *ChildExpansionValue == true)
{
SetItemExpansion(Child, true);
}
}
}
void SMaterialParametersOverviewTree::SetParentsExpansionState()
{
for (const auto& Pair : SortedParameters)
{
if (Pair->Children.Num())
{
bool* bIsExpanded = MaterialEditorInstance->OriginalMaterial->ParameterOverviewExpansion.Find(Pair->NodeKey);
if (bIsExpanded)
{
SetItemExpansion(Pair, *bIsExpanded);
}
else
{
SetItemExpansion(Pair, true);
}
}
}
}
TSharedPtr<class FAssetThumbnailPool> SMaterialParametersOverviewTree::GetTreeThumbnailPool()
{
return UThumbnailManager::Get().GetSharedThumbnailPool();
}
void SMaterialParametersOverviewTree::CreateGroupsWidget()
{
check(MaterialEditorInstance);
UnsortedParameters.Reset();
SortedParameters.Reset();
const TArray<TSharedRef<IDetailTreeNode>> TestData = GetOwner().Pin()->GetGenerator()->GetRootTreeNodes();
if (TestData.Num() == 0)
{
return;
}
TSharedPtr<IDetailTreeNode> Category = TestData[0];
TSharedPtr<IDetailTreeNode> ParameterGroups;
TArray<TSharedRef<IDetailTreeNode>> Children;
Category->GetChildren(Children);
for (int32 ChildIdx = 0; ChildIdx < Children.Num(); ChildIdx++)
{
TSharedPtr<IPropertyHandle> PropertyHandle = Children[ChildIdx]->CreatePropertyHandle();
if (PropertyHandle.IsValid() && PropertyHandle->GetProperty() && PropertyHandle->GetProperty()->GetName() == "ParameterGroups")
{
ParameterGroups = Children[ChildIdx];
break;
}
}
Children.Empty();
// the order should correspond to UnsortedParameters exactly
TArray<TSharedPtr<IPropertyHandle>> DeferredSearches;
if (ParameterGroups.IsValid())
{
ParameterGroups->GetChildren(Children);
for (int32 GroupIdx = 0; GroupIdx < Children.Num(); ++GroupIdx)
{
TArray<void*> GroupPtrs;
TSharedPtr<IPropertyHandle> ChildHandle = Children[GroupIdx]->CreatePropertyHandle();
ChildHandle->AccessRawData(GroupPtrs);
auto GroupIt = GroupPtrs.CreateConstIterator();
const FEditorParameterGroup* ParameterGroupPtr = reinterpret_cast<FEditorParameterGroup*>(*GroupIt);
if (!ParameterGroupPtr)
{
continue;
}
const FEditorParameterGroup& ParameterGroup = *ParameterGroupPtr;
if (ParameterGroup.GroupName == FMaterialPropertyHelpers::LayerParamName)
{
// Don't create or show the material layer parameter info in this UI
continue;
}
for (int32 ParamIdx = 0; ParamIdx < ParameterGroup.Parameters.Num(); ParamIdx++)
{
UDEditorParameterValue* Parameter = ParameterGroup.Parameters[ParamIdx];
if (Parameter->ParameterInfo.Association == EMaterialParameterAssociation::GlobalParameter)
{
bHasAnyParameters = true;
TSharedPtr<IPropertyHandle> ParametersArrayProperty = ChildHandle->GetChildHandle("Parameters");
TSharedPtr<IPropertyHandle> ParameterProperty = ParametersArrayProperty->GetChildHandle(ParamIdx);
TSharedPtr<IPropertyHandle> ParameterValueProperty = ParameterProperty->GetChildHandle("ParameterValue");
FUnsortedParamData NonLayerProperty;
UDEditorScalarParameterValue* ScalarParam = Cast<UDEditorScalarParameterValue>(Parameter);
UDEditorVectorParameterValue* VectorParam = Cast<UDEditorVectorParameterValue>(Parameter);
if (ScalarParam && ScalarParam->SliderMax > ScalarParam->SliderMin)
{
ParameterValueProperty->SetInstanceMetaData("UIMin", FString::Printf(TEXT("%f"), ScalarParam->SliderMin));
ParameterValueProperty->SetInstanceMetaData("UIMax", FString::Printf(TEXT("%f"), ScalarParam->SliderMax));
}
if (VectorParam)
{
static const FName Red("R");
static const FName Green("G");
static const FName Blue("B");
static const FName Alpha("A");
if (!VectorParam->ChannelNames.R.IsEmpty())
{
ParameterProperty->GetChildHandle(Red)->SetPropertyDisplayName(VectorParam->ChannelNames.R);
}
if (!VectorParam->ChannelNames.G.IsEmpty())
{
ParameterProperty->GetChildHandle(Green)->SetPropertyDisplayName(VectorParam->ChannelNames.G);
}
if (!VectorParam->ChannelNames.B.IsEmpty())
{
ParameterProperty->GetChildHandle(Blue)->SetPropertyDisplayName(VectorParam->ChannelNames.B);
}
if (!VectorParam->ChannelNames.A.IsEmpty())
{
ParameterProperty->GetChildHandle(Alpha)->SetPropertyDisplayName(VectorParam->ChannelNames.A);
}
}
NonLayerProperty.Parameter = Parameter;
NonLayerProperty.ParameterGroup = ParameterGroup;
NonLayerProperty.UnsortedName = Parameter->ParameterInfo.Name;
DeferredSearches.Add(ParameterValueProperty);
UnsortedParameters.Add(NonLayerProperty);
}
}
}
}
checkf(UnsortedParameters.Num() == DeferredSearches.Num(), TEXT("Internal inconsistency: number of node searches does not match the number of properties"));
TArray<TSharedPtr<IDetailTreeNode>> DeferredResults = GetOwner().Pin()->GetGenerator()->FindTreeNodes(DeferredSearches);
checkf(UnsortedParameters.Num() == DeferredResults.Num(), TEXT("Internal inconsistency: number of node search results does not match the number of properties"));
for (int Idx = 0, NumUnsorted = UnsortedParameters.Num(); Idx < NumUnsorted; ++Idx)
{
FUnsortedParamData& NonLayerProperty = UnsortedParameters[Idx];
NonLayerProperty.ParameterNode = DeferredResults[Idx];
NonLayerProperty.ParameterHandle = NonLayerProperty.ParameterNode->CreatePropertyHandle();
}
ShowSubParameters();
RequestTreeRefresh();
SetParentsExpansionState();
}
void SMaterialParametersOverviewTree::ShowSubParameters()
{
for (FUnsortedParamData Property : UnsortedParameters)
{
UDEditorParameterValue* Parameter = Property.Parameter;
{
TSharedPtr<FSortedParamData> GroupProperty(new FSortedParamData());
GroupProperty->StackDataType = EStackDataType::Group;
GroupProperty->ParameterInfo.Index = Parameter->ParameterInfo.Index;
GroupProperty->ParameterInfo.Association = Parameter->ParameterInfo.Association;
GroupProperty->Group = Property.ParameterGroup;
GroupProperty->NodeKey = FString::FromInt(GroupProperty->ParameterInfo.Index) + FString::FromInt(GroupProperty->ParameterInfo.Association) + Property.ParameterGroup.GroupName.ToString();
bool bAddNewGroup = true;
for (TSharedPtr<struct FSortedParamData> GroupChild : SortedParameters)
{
if (GroupChild->NodeKey == GroupProperty->NodeKey)
{
bAddNewGroup = false;
}
}
if (bAddNewGroup)
{
SortedParameters.Add(GroupProperty);
}
TSharedPtr<FSortedParamData> ChildProperty(new FSortedParamData());
ChildProperty->StackDataType = EStackDataType::Property;
ChildProperty->Parameter = Parameter;
ChildProperty->ParameterInfo.Index = Parameter->ParameterInfo.Index;
ChildProperty->ParameterInfo.Association = Parameter->ParameterInfo.Association;
ChildProperty->ParameterNode = Property.ParameterNode;
ChildProperty->PropertyName = Property.UnsortedName;
ChildProperty->NodeKey = FString::FromInt(ChildProperty->ParameterInfo.Index) + FString::FromInt(ChildProperty->ParameterInfo.Association) + Property.ParameterGroup.GroupName.ToString() + Property.UnsortedName.ToString();
UDEditorStaticComponentMaskParameterValue* CompMaskParam = Cast<UDEditorStaticComponentMaskParameterValue>(Parameter);
// No children for masks
if (!CompMaskParam)
{
TArray<TSharedRef<IDetailTreeNode>> ParamChildren;
Property.ParameterNode->GetChildren(ParamChildren);
for (int32 ParamChildIdx = 0; ParamChildIdx < ParamChildren.Num(); ParamChildIdx++)
{
TSharedPtr<FSortedParamData> ParamChildProperty(new FSortedParamData());
ParamChildProperty->StackDataType = EStackDataType::PropertyChild;
ParamChildProperty->ParameterNode = ParamChildren[ParamChildIdx];
ParamChildProperty->ParameterHandle = ParamChildProperty->ParameterNode->CreatePropertyHandle();
ParamChildProperty->ParameterInfo.Index = Parameter->ParameterInfo.Index;
ParamChildProperty->ParameterInfo.Association = Parameter->ParameterInfo.Association;
ParamChildProperty->Parameter = ChildProperty->Parameter;
ChildProperty->Children.Add(ParamChildProperty);
}
}
UDEditorRuntimeVirtualTextureParameterValue* VTParameter = Cast<UDEditorRuntimeVirtualTextureParameterValue>(Parameter);
//Don't show VT samples here
if (!VTParameter)
{
for (TSharedPtr<struct FSortedParamData> GroupChild : SortedParameters)
{
if (GroupChild->Group.GroupName == Property.ParameterGroup.GroupName
&& GroupChild->ParameterInfo.Association == ChildProperty->ParameterInfo.Association
&& GroupChild->ParameterInfo.Index == ChildProperty->ParameterInfo.Index)
{
GroupChild->Children.Add(ChildProperty);
}
}
}
UDEditorSparseVolumeTextureParameterValue* SVTParameter = Cast<UDEditorSparseVolumeTextureParameterValue>(Parameter);
if (!SVTParameter)
{
for (TSharedPtr<struct FSortedParamData> GroupChild : SortedParameters)
{
if (GroupChild->Group.GroupName == Property.ParameterGroup.GroupName
&& GroupChild->ParameterInfo.Association == ChildProperty->ParameterInfo.Association
&& GroupChild->ParameterInfo.Index == ChildProperty->ParameterInfo.Index)
{
GroupChild->Children.Add(ChildProperty);
}
}
}
}
}
}
const FSlateBrush* SMaterialParametersOverviewPanel::GetBackgroundImage() const
{
return FAppStyle::GetBrush("DetailsView.CategoryTop");
}
int32 SMaterialParametersOverviewPanel::GetPanelIndex() const
{
return NestedTree && NestedTree->HasAnyParameters() ? 1 : 0;
}
void SMaterialParametersOverviewPanel::Refresh()
{
TSharedPtr<SHorizontalBox> HeaderBox;
NestedTree->CreateGroupsWidget();
FOnClicked OnChildButtonClicked = FOnClicked();
if (MaterialEditorInstance->OriginalFunction)
{
OnChildButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewFunctionInstance, ImplicitConv<UMaterialFunctionInterface*>(MaterialEditorInstance->OriginalFunction), ImplicitConv<UMaterialInterface*>(MaterialEditorInstance->PreviewMaterial), ImplicitConv<UObject*>(MaterialEditorInstance));
}
else
{
OnChildButtonClicked = FOnClicked::CreateStatic(&FMaterialPropertyHelpers::OnClickedSaveNewMaterialInstance, ImplicitConv<UMaterialInterface*>(MaterialEditorInstance->OriginalMaterial), ImplicitConv<UObject*>(MaterialEditorInstance));
}
if (NestedTree->HasAnyParameters())
{
this->ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.Padding(0.0f)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SAssignNew(HeaderBox, SHorizontalBox)
]
+ SVerticalBox::Slot()
.Padding(0.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Fill)
[
NestedTree.ToSharedRef()
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Right)
.AutoWidth()
[
SNew(SBox)
.WidthOverride(16.0f)
[
ExternalScrollbar.ToSharedRef()
]
]
]
]
];
HeaderBox->AddSlot()
.FillWidth(1.0f)
[
SNullWidget::NullWidget
];
if (NestedTree->HasAnyParameters())
{
HeaderBox->AddSlot()
.AutoWidth()
.Padding(2.0f)
[
SNew(SButton)
.Text(LOCTEXT("SaveChild", "Save Child"))
.HAlign(HAlign_Center)
.OnClicked(OnChildButtonClicked)
.ToolTipText(LOCTEXT("SaveToChildInstance", "Save To Child Instance"))
];
}
}
else
{
this->ChildSlot
[
SNew(SBox)
.Padding(10.0f)
.HAlign(HAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("ConnectMaterialParametersToFillList", "Connect a parameter to see it here."))
]
];
}
}
void SMaterialParametersOverviewPanel::Construct(const FArguments& InArgs)
{
ExternalScrollbar = SNew(SScrollBar);
TSharedPtr<IPropertyRowGenerator> InGenerator = InArgs._InGenerator;
Generator = InGenerator;
NestedTree = SNew(SMaterialParametersOverviewTree)
.InMaterialEditorInstance(InArgs._InMaterialEditorInstance)
.InOwner(SharedThis(this))
.InScrollbar(ExternalScrollbar);
MaterialEditorInstance = InArgs._InMaterialEditorInstance;
Refresh();
}
void SMaterialParametersOverviewPanel::UpdateEditorInstance(UMaterialEditorPreviewParameters* InMaterialEditorInstance)
{
NestedTree->MaterialEditorInstance = InMaterialEditorInstance;
Refresh();
}
TSharedPtr<class IPropertyRowGenerator> SMaterialParametersOverviewPanel::GetGenerator()
{
return Generator.Pin();
}
#undef LOCTEXT_NAMESPACE