1832 lines
56 KiB
C++
1832 lines
56 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ComposureDetailCustomizations.h"
|
|
#include "CompositingElements/CompositingMaterialPass.h"
|
|
#include "DetailLayoutBuilder.h"
|
|
#include "Customizations/MathStructCustomizations.h"
|
|
#include "IDetailChildrenBuilder.h"
|
|
#include "Framework/Views/TableViewMetadata.h"
|
|
#include "IPropertyUtilities.h"
|
|
#include "Customizations/ColorStructCustomization.h"
|
|
#include "ICompElementManager.h"
|
|
#include "Widgets/Input/SButton.h"
|
|
#include "Materials/MaterialInterface.h"
|
|
#include "Widgets/SToolTip.h"
|
|
#include "ComposureEditorStyle.h"
|
|
#include "Widgets/SCompElementPickerWindow.h"
|
|
#include "CompositingElement.h"
|
|
#include "IDetailGroup.h"
|
|
#include "Widgets/Input/SNumericEntryBox.h"
|
|
#include "Widgets/Input/SComboButton.h"
|
|
#include "Widgets/Input/SEditableTextBox.h"
|
|
#include "Editor.h"
|
|
#include "CompositingElements/CompositingElementPasses.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "CompElementEditorModule.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "PropertyCustomizationHelpers.h"
|
|
#include "Widgets/Views/SListView.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "ComposureDetailCustomizations"
|
|
|
|
/* FComposureColorPickerCustomization
|
|
*****************************************************************************/
|
|
|
|
class FComposureColorPickerCustomization : public FColorStructCustomization
|
|
{
|
|
public:
|
|
FComposureColorPickerCustomization(TWeakUIntrfacePtr<ICompImageColorPickerInterface> PickerTarget);
|
|
|
|
public:
|
|
//~ FMathStructCustomization interface
|
|
virtual void MakeHeaderRow(TSharedRef<IPropertyHandle>& InStructPropertyHandle, FDetailWidgetRow& Row) override;
|
|
|
|
private:
|
|
FReply OnOpenPickerClick(TSharedRef<IPropertyHandle> PropertyHandle);
|
|
void OnColorSelected(const FVector2D& /*PickedUV*/, const FLinearColor& PickedColor, bool bInteractive, TSharedRef<IPropertyHandle> PropertyHandle);
|
|
void OnColorReset(TSharedRef<IPropertyHandle> PropertyHandle);
|
|
|
|
private:
|
|
TWeakUIntrfacePtr<ICompImageColorPickerInterface> PickerTarget;
|
|
FString DefaultColorStr;
|
|
|
|
bool bIsInteractive = false;
|
|
};
|
|
|
|
FComposureColorPickerCustomization::FComposureColorPickerCustomization(TWeakUIntrfacePtr<ICompImageColorPickerInterface> InPickerTarget)
|
|
: PickerTarget(InPickerTarget)
|
|
{}
|
|
|
|
void FComposureColorPickerCustomization::MakeHeaderRow(TSharedRef<IPropertyHandle>& InStructPropertyHandle, FDetailWidgetRow& Row)
|
|
{
|
|
Row.NameContent()
|
|
[
|
|
InStructPropertyHandle->CreatePropertyNameWidget()
|
|
]
|
|
.ValueContent()
|
|
.MinDesiredWidth(250.0f)
|
|
.MaxDesiredWidth(250.0f)
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
.FillWidth(1.0f)
|
|
[
|
|
CreateColorWidget(StructPropertyHandle)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(2, 0, 0, 0)
|
|
[
|
|
SNew(SButton)
|
|
.ButtonStyle(FAppStyle::Get(), "HoverHintOnly")
|
|
.OnClicked(this, &FComposureColorPickerCustomization::OnOpenPickerClick, InStructPropertyHandle)
|
|
//.ToolTipText( InArgs._Text )
|
|
.ContentPadding(4.0f)
|
|
.ForegroundColor(FSlateColor::UseForeground())
|
|
.IsFocusable(false)
|
|
[
|
|
SNew(SImage)
|
|
.Image(FComposureEditorStyle::Get().GetBrush("ComposureProperties.Button_ChromaPicker"))
|
|
.ColorAndOpacity(FSlateColor::UseForeground())
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
FReply FComposureColorPickerCustomization::OnOpenPickerClick(TSharedRef<IPropertyHandle> PropertyHandle)
|
|
{
|
|
FCompElementColorPickerArgs PickerArgs;
|
|
PickerArgs.PickerTarget = PickerTarget;
|
|
PickerArgs.OnColorPicked = FColorPickedEventHandler::CreateSP(this, &FComposureColorPickerCustomization::OnColorSelected, PropertyHandle);
|
|
PickerArgs.OnColorPickerCanceled = FSimpleDelegate::CreateSP(this, &FComposureColorPickerCustomization::OnColorReset, PropertyHandle);
|
|
PickerArgs.ParentWidget = ColorPickerParentWidget;
|
|
|
|
TArray<UObject*> OutersList;
|
|
PropertyHandle->GetOuterObjects(OutersList);
|
|
if (OutersList.Num() == 1)
|
|
{
|
|
UObject* Outer = OutersList[0];
|
|
if (Outer)
|
|
{
|
|
FString ObjPathName;
|
|
while (Outer)
|
|
{
|
|
FString OuterStrName;
|
|
if (UCompositingElementPass* AsPass = Cast<UCompositingElementPass>(Outer))
|
|
{
|
|
OuterStrName = AsPass->PassName.ToString();
|
|
}
|
|
else if (ACompositingElement* AsCompShot = Cast<ACompositingElement>(Outer))
|
|
{
|
|
OuterStrName = AsCompShot->GetCompElementName().ToString();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!ObjPathName.IsEmpty())
|
|
{
|
|
OuterStrName += TEXT(".");
|
|
}
|
|
ObjPathName = OuterStrName + ObjPathName;
|
|
|
|
Outer = Outer->GetOuter();
|
|
}
|
|
|
|
if (!ObjPathName.IsEmpty())
|
|
{
|
|
PickerArgs.WindowTitle = FText::Format(LOCTEXT("PickerWindowTitle", "Color Picker ({0})"), FText::FromString(ObjPathName));
|
|
}
|
|
}
|
|
}
|
|
|
|
SCompElementPickerWindow::Open(PickerArgs);
|
|
|
|
DefaultColorStr.Empty(DefaultColorStr.Len());
|
|
PropertyHandle->GetValueAsFormattedString(DefaultColorStr);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
void FComposureColorPickerCustomization::OnColorSelected(const FVector2D& /*PickedUV*/, const FLinearColor& PickedColor, bool bInteractive, TSharedRef<IPropertyHandle> PropertyHandle)
|
|
{
|
|
if (bInteractive != bIsInteractive)
|
|
{
|
|
if (bInteractive)
|
|
{
|
|
GEditor->BeginTransaction(LOCTEXT("PickPlateColorTransaction", "Pick Plate Color"));
|
|
}
|
|
else
|
|
{
|
|
GEditor->EndTransaction();
|
|
}
|
|
bIsInteractive = bInteractive;
|
|
}
|
|
|
|
PropertyHandle->SetValueFromFormattedString(PickedColor.ToString(), bInteractive ? EPropertyValueSetFlags::InteractiveChange : 0);
|
|
PropertyHandle->NotifyFinishedChangingProperties();
|
|
}
|
|
|
|
void FComposureColorPickerCustomization::OnColorReset(TSharedRef<IPropertyHandle> PropertyHandle)
|
|
{
|
|
if (!DefaultColorStr.IsEmpty())
|
|
{
|
|
PropertyHandle->SetValueFromFormattedString(DefaultColorStr);
|
|
PropertyHandle->NotifyFinishedChangingProperties();
|
|
}
|
|
|
|
if (bIsInteractive)
|
|
{
|
|
GEditor->EndTransaction();
|
|
bIsInteractive = false;
|
|
}
|
|
}
|
|
|
|
/* FCompElementDetailsCustomization
|
|
*****************************************************************************/
|
|
|
|
namespace ElementDetailsCustomization_Impl
|
|
{
|
|
static bool NeedsCameraSource(ACompositingElement* Element);
|
|
}
|
|
|
|
static bool ElementDetailsCustomization_Impl::NeedsCameraSource(ACompositingElement* Element)
|
|
{
|
|
if (Element->CameraSource != ESceneCameraLinkType::Unused)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
for (ACompositingElement* Child : Element->GetChildElements())
|
|
{
|
|
if (NeedsCameraSource(Child))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
TSharedRef<IDetailCustomization> FCompElementDetailsCustomization::MakeInstance()
|
|
{
|
|
return MakeShared<FCompElementDetailsCustomization>();
|
|
}
|
|
|
|
void FCompElementDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
|
|
{
|
|
MyLayout = &DetailBuilder;
|
|
|
|
TArray< TWeakObjectPtr<UObject> > SelectedObjects;
|
|
DetailBuilder.GetObjectsBeingCustomized(SelectedObjects);
|
|
|
|
if (SelectedObjects.Num() > 0)
|
|
{
|
|
TWeakObjectPtr<UObject> ObjPtr = SelectedObjects[0];
|
|
if (ObjPtr.IsValid())
|
|
{
|
|
UObject* SelectedObj = ObjPtr.Get();
|
|
if (ACompositingElement* AsElement = Cast<ACompositingElement>(SelectedObj))
|
|
{
|
|
TWeakUIntrfacePtr<ICompImageColorPickerInterface> PickerTarget(AsElement);
|
|
FOnGetPropertyTypeCustomizationInstance CustomColorPickerFactory = FOnGetPropertyTypeCustomizationInstance::CreateLambda(
|
|
[PickerTarget]
|
|
{
|
|
return MakeShared<FComposureColorPickerCustomization>(PickerTarget);
|
|
});
|
|
DetailBuilder.RegisterInstancedCustomPropertyTypeLayout("LinearColor", CustomColorPickerFactory);
|
|
}
|
|
}
|
|
|
|
#define TRINARY_TRUE +1
|
|
#define TRINARY_FALSE -1
|
|
#define TRINARY_IS_FALSE(Value) (Value < 0)
|
|
#define TRINARY_IS_UNSET(Value) (Value == 0)
|
|
// 0 == unset, >0 == true, <0 == false
|
|
int8 bShowResolution = 0;
|
|
int8 bShowResSource = 0;
|
|
int8 bShowCameraProp = 0;
|
|
int8 bShowCamSource = 0;
|
|
int8 bShowPreviewPass = 0;
|
|
int8 bShowPreviewSrc = 0;
|
|
|
|
bool bArchetypeSelected = false;
|
|
for (TWeakObjectPtr<UObject> SelectedObj : SelectedObjects)
|
|
{
|
|
if (ACompositingElement* AsElement = Cast<ACompositingElement>(SelectedObj))
|
|
{
|
|
const bool bIsArchetype = AsElement->IsTemplate();
|
|
bArchetypeSelected |= bIsArchetype;
|
|
|
|
ACompositingElement* Parent = AsElement->GetElementParent();
|
|
if (Parent)
|
|
{
|
|
bShowResSource = TRINARY_TRUE;
|
|
bShowPreviewSrc = TRINARY_TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (TRINARY_IS_UNSET(bShowResSource))
|
|
{
|
|
bShowResSource = TRINARY_FALSE;
|
|
}
|
|
|
|
if (TRINARY_IS_UNSET(bShowPreviewSrc))
|
|
{
|
|
bShowPreviewSrc = TRINARY_FALSE;
|
|
}
|
|
}
|
|
|
|
if (AsElement->ResolutionSource == EInheritedSourceType::Override || !Parent)
|
|
{
|
|
bShowResolution = TRINARY_TRUE;
|
|
}
|
|
else if (TRINARY_IS_UNSET(bShowResolution))
|
|
{
|
|
bShowResolution = TRINARY_FALSE;
|
|
}
|
|
|
|
if (AsElement->PreviewTransformSource == EInheritedSourceType::Override || !Parent)
|
|
{
|
|
bShowPreviewPass = TRINARY_TRUE;
|
|
}
|
|
else if (TRINARY_IS_UNSET(bShowPreviewPass))
|
|
{
|
|
bShowPreviewPass = TRINARY_FALSE;
|
|
}
|
|
|
|
|
|
if ( bIsArchetype || (Parent && ElementDetailsCustomization_Impl::NeedsCameraSource(AsElement)) )
|
|
{
|
|
bShowCamSource = TRINARY_TRUE;
|
|
}
|
|
else if (TRINARY_IS_UNSET(bShowCamSource))
|
|
{
|
|
bShowCamSource = TRINARY_FALSE;
|
|
}
|
|
|
|
if ( AsElement->CameraSource == ESceneCameraLinkType::Override || (!Parent && ElementDetailsCustomization_Impl::NeedsCameraSource(AsElement)) )
|
|
{
|
|
bShowCameraProp = TRINARY_TRUE;
|
|
}
|
|
else if (TRINARY_IS_UNSET(bShowCameraProp))
|
|
{
|
|
bShowCameraProp = TRINARY_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
TSharedPtr<IPropertyHandle> ResolutionSource = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ACompositingElement, ResolutionSource));
|
|
ResolutionSource->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FCompElementDetailsCustomization::ForceRefreshLayout));
|
|
|
|
if (TRINARY_IS_FALSE(bShowResSource))
|
|
{
|
|
DetailBuilder.HideProperty(ResolutionSource);
|
|
}
|
|
if (TRINARY_IS_FALSE(bShowResolution))
|
|
{
|
|
DetailBuilder.HideProperty(TEXT("RenderResolution"));//GET_MEMBER_NAME_CHECKED(ACompositingElement, RenderResolution));
|
|
}
|
|
|
|
TSharedPtr<IPropertyHandle> CameraSource = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ACompositingElement, CameraSource));
|
|
CameraSource->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FCompElementDetailsCustomization::ForceRefreshLayout));
|
|
|
|
if (TRINARY_IS_FALSE(bShowCamSource))
|
|
{
|
|
DetailBuilder.HideProperty(CameraSource);
|
|
}
|
|
else if (!bArchetypeSelected)
|
|
{
|
|
IDetailPropertyRow* CameraSourceRow = DetailBuilder.EditDefaultProperty(CameraSource);
|
|
if (CameraSourceRow)
|
|
{
|
|
CameraSourceRow->CustomWidget()
|
|
.NameContent()
|
|
[
|
|
CameraSource->CreatePropertyNameWidget()
|
|
]
|
|
.ValueContent()
|
|
.MinDesiredWidth(125.f)
|
|
.MaxDesiredWidth(400.f)
|
|
[
|
|
PropertyCustomizationHelpers::MakePropertyComboBox(
|
|
CameraSource,
|
|
FOnGetPropertyComboBoxStrings::CreateSP(this, &FCompElementDetailsCustomization::GetInstanceCameraSourceComboStrings),
|
|
FOnGetPropertyComboBoxValue::CreateSP(this, &FCompElementDetailsCustomization::GetInstanceCameraSourceValueStr, CameraSource),
|
|
FOnPropertyComboBoxValueSelected::CreateSP(this, &FCompElementDetailsCustomization::OnCameraSourceSelected, CameraSource)
|
|
)
|
|
];
|
|
}
|
|
}
|
|
|
|
if (TRINARY_IS_FALSE(bShowCameraProp))
|
|
{
|
|
DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(ACompositingElement, TargetCameraActorPtr));
|
|
}
|
|
|
|
TSharedPtr<IPropertyHandle> PreviewTransformSource = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ACompositingElement, PreviewTransformSource));
|
|
PreviewTransformSource->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FCompElementDetailsCustomization::ForceRefreshLayout));
|
|
|
|
if (TRINARY_IS_FALSE(bShowPreviewSrc))
|
|
{
|
|
DetailBuilder.HideProperty(PreviewTransformSource);
|
|
}
|
|
if (TRINARY_IS_FALSE(bShowPreviewPass))
|
|
{
|
|
DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(ACompositingElement, PreviewTransform));
|
|
}
|
|
|
|
#undef TRINARY_TRUE
|
|
#undef TRINARY_FALSE
|
|
#undef TRINARY_IS_FALSE
|
|
#undef TRINARY_IS_UNSET
|
|
}
|
|
}
|
|
|
|
void FCompElementDetailsCustomization::ForceRefreshLayout()
|
|
{
|
|
if (MyLayout)
|
|
{
|
|
MyLayout->ForceRefreshDetails();
|
|
}
|
|
}
|
|
|
|
void FCompElementDetailsCustomization::GetInstanceCameraSourceComboStrings(TArray<TSharedPtr<FString>>& OutComboBoxStrings, TArray<TSharedPtr<SToolTip>>& OutToolTips, TArray<bool>& OutRestrictedItems)
|
|
{
|
|
const UEnum* CamSourceEnum = StaticEnum<ESceneCameraLinkType>();
|
|
if (ensure(CamSourceEnum))
|
|
{
|
|
for (int32 EnumIndex = 0; EnumIndex < CamSourceEnum->NumEnums()-1; ++EnumIndex)
|
|
{
|
|
if (CamSourceEnum->GetValueByIndex(EnumIndex) != (int64)ESceneCameraLinkType::Unused)
|
|
{
|
|
FText EnumeratorName = CamSourceEnum->GetDisplayNameTextByIndex(EnumIndex);
|
|
|
|
OutComboBoxStrings.Add(MakeShared<FString>(EnumeratorName.ToString()));
|
|
OutToolTips.Add(SNew(SToolTip).Text(EnumeratorName));
|
|
OutRestrictedItems.Add(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FString FCompElementDetailsCustomization::GetInstanceCameraSourceValueStr(TSharedPtr<IPropertyHandle> PropertyHandle)
|
|
{
|
|
FString DisplayStr;
|
|
|
|
uint8 CurrentValue = (uint8)ESceneCameraLinkType::Inherited;
|
|
FPropertyAccess::Result GetValResult = PropertyHandle.IsValid() ? PropertyHandle->GetValue(CurrentValue) : FPropertyAccess::Fail;
|
|
|
|
if (GetValResult == FPropertyAccess::MultipleValues)
|
|
{
|
|
DisplayStr = LOCTEXT("MultipleValues", "Multiple Values").ToString();
|
|
}
|
|
else if (GetValResult == FPropertyAccess::Success)
|
|
{
|
|
if (CurrentValue == (uint8)ESceneCameraLinkType::Unused)
|
|
{
|
|
DisplayStr = LOCTEXT("UnusedDisplayString", "Inherited (Unused/Passthrough)").ToString();
|
|
}
|
|
else
|
|
{
|
|
const UEnum* CamSourceEnum = StaticEnum<ESceneCameraLinkType>();
|
|
if (ensure(CamSourceEnum))
|
|
{
|
|
DisplayStr = CamSourceEnum->GetDisplayNameTextByValue(CurrentValue).ToString();
|
|
}
|
|
}
|
|
}
|
|
|
|
return DisplayStr;
|
|
}
|
|
|
|
void FCompElementDetailsCustomization::OnCameraSourceSelected(const FString& Selection, TSharedPtr<IPropertyHandle> PropertyHandle)
|
|
{
|
|
const UEnum* CamSourceEnum = StaticEnum<ESceneCameraLinkType>();
|
|
if (ensure(CamSourceEnum) && PropertyHandle.IsValid())
|
|
{
|
|
const int64 FoundValue = CamSourceEnum->GetValueByNameString(Selection);
|
|
if (FoundValue == (int64)ESceneCameraLinkType::Override)
|
|
{
|
|
PropertyHandle->SetValue((uint8)FoundValue);
|
|
}
|
|
else if (FoundValue == (int64)ESceneCameraLinkType::Inherited)
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
PropertyHandle->GetOuterObjects(OuterObjects);
|
|
|
|
bool bSetToUnused = true;
|
|
for (UObject* Outer : OuterObjects)
|
|
{
|
|
if (Outer)
|
|
{
|
|
UClass* ObjClass = Outer->GetClass();
|
|
const ACompositingElement* CDO = ObjClass ? Cast<ACompositingElement>(ObjClass->GetDefaultObject(false)): nullptr;
|
|
|
|
if (CDO && CDO->CameraSource != ESceneCameraLinkType::Unused)
|
|
{
|
|
bSetToUnused = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bSetToUnused)
|
|
{
|
|
PropertyHandle->SetValue((uint8)ESceneCameraLinkType::Unused);
|
|
}
|
|
else
|
|
{
|
|
PropertyHandle->SetValue((uint8)ESceneCameraLinkType::Inherited);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* FCompositingMaterialPassCustomization
|
|
*****************************************************************************/
|
|
|
|
FCompositingMaterialPassCustomization::FCompositingMaterialPassCustomization()
|
|
{
|
|
FEditorDelegates::RefreshEditor.AddRaw(this, &FCompositingMaterialPassCustomization::OnRedrawViewports);
|
|
GEditor->RegisterForUndo(this);
|
|
}
|
|
|
|
FCompositingMaterialPassCustomization::~FCompositingMaterialPassCustomization()
|
|
{
|
|
FEditorDelegates::RefreshEditor.RemoveAll(this);
|
|
GEditor->UnregisterForUndo(this);
|
|
}
|
|
|
|
TSharedRef<IPropertyTypeCustomization> FCompositingMaterialPassCustomization::MakeInstance()
|
|
{
|
|
return MakeShareable(new FCompositingMaterialPassCustomization);
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils)
|
|
{
|
|
CachedPropertyHandle = PropertyHandle;
|
|
CachedUtils = CustomizationUtils.GetPropertyUtilities();
|
|
|
|
TArray<UObject*> OuterObjects;
|
|
PropertyHandle->GetOuterObjects(OuterObjects);
|
|
|
|
if (OuterObjects.Num() == 1)
|
|
{
|
|
UObject* Obj = OuterObjects[0];
|
|
if (Obj->IsA<UCompositingElementPass>())
|
|
{
|
|
MaterialPassName = &CastChecked<UCompositingElementPass>(Obj)->PassName;
|
|
}
|
|
}
|
|
|
|
FCompositingMaterialType* MatPass = GetMaterialPass();
|
|
check(MatPass);
|
|
MaterialReference = TWeakObjectPtr<UMaterialInterface>(MatPass->Material);
|
|
|
|
ICompElementEditorModule& ComposureLayersModule = FModuleManager::GetModuleChecked<ICompElementEditorModule>(TEXT("ComposureLayersEditor"));
|
|
CompElementManager = ComposureLayersModule.GetCompElementManager();
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
|
|
{
|
|
check(CachedUtils);
|
|
check(CachedPropertyHandle == StructPropertyHandle);
|
|
|
|
FSimpleDelegate Refresh = FSimpleDelegate::CreateRaw(CachedUtils.Get(), &IPropertyUtilities::ForceRefresh);
|
|
FSimpleDelegate ResetOverrides = FSimpleDelegate::CreateSP(this, &FCompositingMaterialPassCustomization::ResetParameterOverrides);
|
|
|
|
uint32 NumChildren;
|
|
StructPropertyHandle->GetNumChildren(NumChildren);
|
|
|
|
for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex)
|
|
{
|
|
TSharedRef<IPropertyHandle> ChildHandle = StructPropertyHandle->GetChildHandle(ChildIndex).ToSharedRef();
|
|
|
|
if (ChildHandle->GetProperty()->GetFName() == GET_MEMBER_NAME_CHECKED(FCompositingMaterialType, Material))
|
|
{
|
|
MaterialHandle = ChildHandle;
|
|
ChildHandle->SetOnPropertyValueChanged(ResetOverrides);
|
|
}
|
|
|
|
else if (ChildHandle->GetProperty()->GetFName() == FName(TEXT("VectorOverrideProxies")))//GET_MEMBER_NAME_CHECKED(FCompositingMaterialPass, VectorOverrideProxies))
|
|
{
|
|
CachedVectorProxies = ChildHandle;
|
|
continue;
|
|
}
|
|
|
|
else if (ChildHandle->GetProperty()->GetFName() == FName(TEXT("ParamPassMappings")))//GET_MEMBER_NAME_CHECKED(FCompositingMaterialPass, MaterialParamMappings))
|
|
{
|
|
CachedMaterialParamMappings = ChildHandle;
|
|
continue;
|
|
}
|
|
|
|
IDetailPropertyRow& Property = StructBuilder.AddProperty(ChildHandle);
|
|
}
|
|
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
FCompositingMaterialType* MatPass = GetMaterialPass();
|
|
check(MatPass);
|
|
|
|
//Required material params
|
|
if (MatPass->RequiredMaterialParams.Num() > 0)
|
|
{
|
|
IDetailGroup& RequiredParamsGroup = StructBuilder.AddGroup(FName(TEXT("RequiredParamsGroup")), LOCTEXT("RequiredParamsGroup_DisplayName", "Required Material Parameters"));
|
|
|
|
for (TPair<FName, FNamedCompMaterialParam> RequiredParam : MatPass->RequiredMaterialParams)
|
|
{
|
|
const FSlateFontInfo DetailFontInfo = IDetailLayoutBuilder::GetDetailFont();
|
|
TSharedPtr<SComboButton> RequiredParamComboButton = SNew(SComboButton)
|
|
.ContentPadding(FMargin(0, 0, 5, 0))
|
|
.ButtonContent()
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FAppStyle::GetBrush("NoBorder"))
|
|
.Padding(FMargin(0, 0, 5, 0))
|
|
[
|
|
SNew(SEditableTextBox)
|
|
.Text(this, &FCompositingMaterialPassCustomization::GetRequiredParamComboText, RequiredParam.Key)
|
|
.OnTextCommitted(this, &FCompositingMaterialPassCustomization::OnRequiredParamComboTextCommitted, RequiredParam.Key)
|
|
.SelectAllTextWhenFocused(true)
|
|
.RevertTextOnEscape(true)
|
|
.Font(DetailFontInfo)
|
|
]
|
|
];
|
|
|
|
TWeakPtr<SComboButton> WeakParamComboPtr = RequiredParamComboButton;
|
|
RequiredParamComboButton->SetOnGetMenuContent(FOnGetContent::CreateSP(this, &FCompositingMaterialPassCustomization::GetRequiredParamComboMenu, WeakParamComboPtr, RequiredParam.Key, RequiredParam.Value.ParamType));
|
|
|
|
// Populate dropdowns
|
|
RebuildRequiredParamSources();
|
|
|
|
RequiredParamsGroup.AddWidgetRow()
|
|
.NameContent()
|
|
[
|
|
SNew(SBox)
|
|
.Padding(FMargin(15, 0))
|
|
.Content()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromName(RequiredParam.Key))
|
|
.Font(DetailFontInfo)
|
|
]
|
|
]
|
|
.ValueContent()
|
|
.MinDesiredWidth(166.0f)
|
|
[
|
|
RequiredParamComboButton.ToSharedRef()
|
|
];
|
|
}
|
|
}
|
|
|
|
TArray<FMaterialParameterInfo> OutScalarParameterInfo;
|
|
TArray<FGuid> ScalarGuids;
|
|
MaterialReferencePtr->GetAllScalarParameterInfo(OutScalarParameterInfo, ScalarGuids);
|
|
|
|
TArray<FMaterialParameterInfo> OutVectorParameterInfo;
|
|
TArray<FGuid> VectorGuids;
|
|
MaterialReferencePtr->GetAllVectorParameterInfo(OutVectorParameterInfo, VectorGuids);
|
|
|
|
TArray<FMaterialParameterInfo> OutTextureParameterInfo;
|
|
TArray<FGuid> TextureGuids;
|
|
MaterialReferencePtr->GetAllTextureParameterInfo(OutTextureParameterInfo, TextureGuids);
|
|
|
|
if (OutTextureParameterInfo.Num() > 0)
|
|
{
|
|
uint32 TexChildren = 0;
|
|
CachedMaterialParamMappings->GetNumChildren(TexChildren);
|
|
|
|
if (TexChildren > 0)
|
|
{
|
|
IDetailGroup& InputElementsGroup = StructBuilder.AddGroup(FName(TEXT("InputElementsGroup")), LOCTEXT("InputElementsGroup_DisplayName", "Input Elements"));
|
|
|
|
//Texture Params
|
|
|
|
for (uint32 ChildIndex = 0; ChildIndex < TexChildren; ++ChildIndex)
|
|
{
|
|
|
|
TSharedPtr<IPropertyHandle> ChildHandle = CachedMaterialParamMappings->GetChildHandle(ChildIndex);
|
|
FName TextureName;
|
|
ChildHandle->GetKeyHandle()->GetValue(TextureName);
|
|
|
|
bool IsRequiredParam = false;
|
|
|
|
for (TPair<FName, FNamedCompMaterialParam> Param : MatPass->RequiredMaterialParams)
|
|
{
|
|
if ((Param.Value.ParamType == EParamType::TextureParam || Param.Value.ParamType == EParamType::UnknownParamType) && Param.Value.ParamName == TextureName)
|
|
{
|
|
//Texture is in use by a required param, so hide it
|
|
IsRequiredParam = true;
|
|
}
|
|
}
|
|
|
|
TSharedPtr<SWidget> NameWidget;
|
|
TSharedPtr<SWidget> ValueWidget;
|
|
FDetailWidgetRow Row;
|
|
|
|
IDetailPropertyRow& PropertyRow = InputElementsGroup.AddPropertyRow(ChildHandle.ToSharedRef());
|
|
|
|
const FSlateFontInfo DetailFontInfo = IDetailLayoutBuilder::GetDetailFont();
|
|
TSharedPtr<SComboButton> PassComboButton = SNew(SComboButton)
|
|
.ContentPadding(FMargin(0, 0, 5, 0))
|
|
//.IsEnabled(this, &FBlueprintVarActionDetails::GetVariableCategoryChangeEnabled)
|
|
//.ToolTip(CategoryTooltip)
|
|
.ButtonContent()
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FAppStyle::GetBrush("NoBorder"))
|
|
.Padding(FMargin(0, 0, 5, 0))
|
|
[
|
|
SNew(SEditableTextBox)
|
|
.Text(this, &FCompositingMaterialPassCustomization::GetComboText, TextureName)
|
|
.OnTextCommitted(this, &FCompositingMaterialPassCustomization::OnComboTextCommitted, TextureName)
|
|
//.ToolTip(CategoryTooltip)
|
|
.SelectAllTextWhenFocused(true)
|
|
.RevertTextOnEscape(true)
|
|
.Font(DetailFontInfo)
|
|
]
|
|
];
|
|
|
|
TWeakPtr<SComboButton> WeakComboPtr = PassComboButton;
|
|
PassComboButton->SetOnGetMenuContent(FOnGetContent::CreateSP(this, &FCompositingMaterialPassCustomization::GetPassComboMenu, WeakComboPtr, TextureName));
|
|
|
|
RebuildTextureSourceList();
|
|
|
|
FIsResetToDefaultVisible IsResetVisible = FIsResetToDefaultVisible::CreateSP(this, &FCompositingMaterialPassCustomization::TextureShouldShowResetToDefault);
|
|
FResetToDefaultHandler ResetHandler = FResetToDefaultHandler::CreateSP(this, &FCompositingMaterialPassCustomization::TextureResetToDefault, PassComboButton);
|
|
FResetToDefaultOverride ResetOverride = FResetToDefaultOverride::Create(IsResetVisible, ResetHandler);
|
|
|
|
//ChildHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FCompositingMaterialPassCustomization::OnTextureOverrideChanged, ChildHandle));
|
|
|
|
PropertyRow.OverrideResetToDefault(ResetOverride);
|
|
PropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row);
|
|
PropertyRow
|
|
.ShowPropertyButtons(false)
|
|
.IsEnabled(!IsRequiredParam)
|
|
.CustomWidget()
|
|
.NameContent()
|
|
[
|
|
SNew(SBox)
|
|
.Padding(FMargin(15, 0))
|
|
.Content()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(TextureName.ToString()))
|
|
.Font(DetailFontInfo)
|
|
]
|
|
]
|
|
.ValueContent()
|
|
.MinDesiredWidth(166.0f)
|
|
[
|
|
PassComboButton.ToSharedRef()
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OutScalarParameterInfo.Num() + OutVectorParameterInfo.Num() > 0)
|
|
{
|
|
IDetailGroup& MaterialParametersGroup = StructBuilder.AddGroup(FName(TEXT("MaterialParametersGroup")), LOCTEXT("MaterialParametersGroup_DisplayName", "Material Parameters"));
|
|
|
|
//Scalar Params
|
|
|
|
for (FMaterialParameterInfo ScalarParam : OutScalarParameterInfo)
|
|
{
|
|
if (MatPass->EditorHiddenParams.Contains(ScalarParam.Name))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool IsRequiredParam = false;
|
|
|
|
for (TPair<FName, FNamedCompMaterialParam> Param : MatPass->RequiredMaterialParams)
|
|
{
|
|
if ((Param.Value.ParamType == EParamType::ScalarParam || Param.Value.ParamType == EParamType::UnknownParamType) && Param.Value.ParamName == ScalarParam.Name)
|
|
{
|
|
//Scalar is in use by a required param, so hide it
|
|
IsRequiredParam = true;
|
|
}
|
|
}
|
|
|
|
MaterialParametersGroup.AddWidgetRow()
|
|
.NameContent()
|
|
[
|
|
SNew(SBox)
|
|
.Padding(FMargin(15, 0))
|
|
.IsEnabled(!IsRequiredParam)
|
|
.Content()
|
|
[
|
|
SNew(STextBlock)
|
|
.IsEnabled(!IsRequiredParam)
|
|
.Text(FText::FromString(ScalarParam.Name.ToString()))
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
]
|
|
.ValueContent()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
.IsEnabled(!IsRequiredParam)
|
|
+ SHorizontalBox::Slot()
|
|
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
|
|
[
|
|
SNew(SNumericEntryBox<float>)
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
.AllowSpin(true)
|
|
.MinValue(TOptional<float>())
|
|
.MaxValue(TOptional<float>())
|
|
.MinSliderValue(this, &FCompositingMaterialPassCustomization::GetScalarParameterSliderMin, ScalarParam)
|
|
.MaxSliderValue(this, &FCompositingMaterialPassCustomization::GetScalarParameterSliderMax, ScalarParam)
|
|
.Delta(0.0f)
|
|
.Value(this, &FCompositingMaterialPassCustomization::GetScalarParameterValue, ScalarParam)
|
|
.OnBeginSliderMovement(this, &FCompositingMaterialPassCustomization::OnScalarParameterSlideBegin, ScalarParam)
|
|
.OnEndSliderMovement(this, &FCompositingMaterialPassCustomization::OnScalarParameterSlideEnd, ScalarParam)
|
|
.OnValueChanged(this, &FCompositingMaterialPassCustomization::SetScalarParameterValue, ScalarParam)
|
|
.OnValueCommitted(this, &FCompositingMaterialPassCustomization::OnScalarParameterCommitted, ScalarParam)
|
|
]
|
|
+ SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
.Padding(2, 1)
|
|
[
|
|
SNew(SButton)
|
|
.IsFocusable(false)
|
|
.ToolTipText(LOCTEXT("ResetToDefaultToolTip", "Reset to Default"))
|
|
.ButtonStyle(FAppStyle::Get(), "NoBorder")
|
|
.ContentPadding(0)
|
|
.Visibility(this, &FCompositingMaterialPassCustomization::IsResetScalarParameterVisible, ScalarParam)
|
|
.OnClicked(this, &FCompositingMaterialPassCustomization::OnResetScalarParameterClicked, ScalarParam)
|
|
.Content()
|
|
[
|
|
SNew(SImage)
|
|
.Image(FAppStyle::GetBrush("PropertyWindow.DiffersFromDefault"))
|
|
]
|
|
]
|
|
];
|
|
}
|
|
|
|
//Vector Params
|
|
|
|
uint32 children = 0;
|
|
CachedVectorProxies->GetNumChildren(children);
|
|
|
|
for (uint32 ChildIndex = 0; ChildIndex < children; ++ChildIndex)
|
|
{
|
|
|
|
TSharedPtr<IPropertyHandle> ChildHandle = CachedVectorProxies->GetChildHandle(ChildIndex);
|
|
FName VectorName;
|
|
ChildHandle->GetKeyHandle()->GetValue(VectorName);
|
|
|
|
if (MatPass->EditorHiddenParams.Contains(VectorName))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool IsRequiredParam = false;
|
|
|
|
for (TPair<FName, FNamedCompMaterialParam> Param : MatPass->RequiredMaterialParams)
|
|
{
|
|
if ((Param.Value.ParamType == EParamType::VectorParam || Param.Value.ParamType == EParamType::UnknownParamType) && Param.Value.ParamName == VectorName)
|
|
{
|
|
//Texture is in use by a required param, so hide it
|
|
IsRequiredParam = true;
|
|
}
|
|
}
|
|
|
|
FIsResetToDefaultVisible IsResetVisible = FIsResetToDefaultVisible::CreateSP(this, &FCompositingMaterialPassCustomization::VectorShouldShowResetToDefault);
|
|
FResetToDefaultHandler ResetHandler = FResetToDefaultHandler::CreateSP(this, &FCompositingMaterialPassCustomization::VectorResetToDefault);
|
|
FResetToDefaultOverride ResetOverride = FResetToDefaultOverride::Create(IsResetVisible, ResetHandler);
|
|
|
|
ChildHandle->SetOnPropertyValueChanged(FSimpleDelegate::CreateSP(this, &FCompositingMaterialPassCustomization::OnVectorOverrideChanged, ChildHandle));
|
|
|
|
TSharedPtr<SWidget> NameWidget;
|
|
TSharedPtr<SWidget> ValueWidget;
|
|
FDetailWidgetRow Row;
|
|
|
|
IDetailPropertyRow& PropertyRow = MaterialParametersGroup.AddPropertyRow(ChildHandle.ToSharedRef());
|
|
|
|
PropertyRow.OverrideResetToDefault(ResetOverride);
|
|
PropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row);
|
|
PropertyRow
|
|
.ShowPropertyButtons(false)
|
|
.IsEnabled(!IsRequiredParam)
|
|
.CustomWidget()
|
|
.NameContent()
|
|
[
|
|
|
|
SNew(SBox)
|
|
.Padding(FMargin(15, 0))
|
|
.Content()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(VectorName.ToString()))
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
]
|
|
]
|
|
.ValueContent()
|
|
[
|
|
ValueWidget.ToSharedRef()
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::VectorResetToDefault(TSharedPtr<IPropertyHandle> PropertyHandle)
|
|
{
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
FName VectorName;
|
|
PropertyHandle->GetKeyHandle()->GetValue(VectorName);
|
|
|
|
void* Data;
|
|
PropertyHandle->GetValueData(Data);
|
|
FLinearColor* VectorColor = reinterpret_cast<FLinearColor*>(Data);
|
|
|
|
FLinearColor DefaultColor;
|
|
MaterialReferencePtr->GetVectorParameterDefaultValue(VectorName, DefaultColor);
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
MatPass->ResetVectorOverride(VectorName);
|
|
}
|
|
*VectorColor = DefaultColor;
|
|
|
|
}
|
|
}
|
|
|
|
bool FCompositingMaterialPassCustomization::VectorShouldShowResetToDefault(TSharedPtr<IPropertyHandle> PropertyHandle)
|
|
{
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
FName VectorName;
|
|
PropertyHandle->GetKeyHandle()->GetValue(VectorName);
|
|
|
|
void* Data;
|
|
PropertyHandle->GetValueData(Data);
|
|
FLinearColor* VectorColor = reinterpret_cast<FLinearColor*>(Data);
|
|
|
|
FLinearColor DefaultColor;
|
|
MaterialReferencePtr->GetVectorParameterDefaultValue(VectorName, DefaultColor);
|
|
if (VectorColor && DefaultColor != *VectorColor)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::OnVectorOverrideChanged(TSharedPtr<IPropertyHandle> PropertyHandle)
|
|
{
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
FName VectorName;
|
|
PropertyHandle->GetKeyHandle()->GetValue(VectorName);
|
|
|
|
void* Data;
|
|
PropertyHandle->GetValueData(Data);
|
|
FLinearColor* VectorColor = reinterpret_cast<FLinearColor*>(Data);
|
|
|
|
FLinearColor DefaultColor;
|
|
MaterialReferencePtr->GetVectorParameterDefaultValue(VectorName, DefaultColor);
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
if (DefaultColor == *VectorColor)
|
|
{
|
|
MatPass->ResetVectorOverride(VectorName);
|
|
}
|
|
else
|
|
{
|
|
MatPass->SetVectorOverride(VectorName, *VectorColor);
|
|
}
|
|
CompElementManager->RequestRedraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
TOptional<float> FCompositingMaterialPassCustomization::GetScalarParameterSliderMin(FMaterialParameterInfo ScalarParam) const
|
|
{
|
|
float Min = 0.0f, Max = 0.0f;
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
MaterialReferencePtr->GetScalarParameterSliderMinMax(ScalarParam, Min, Max);
|
|
}
|
|
return (Min == Max ? TOptional<float>() : Min);
|
|
}
|
|
|
|
TOptional<float> FCompositingMaterialPassCustomization::GetScalarParameterSliderMax(FMaterialParameterInfo ScalarParam) const
|
|
{
|
|
float Min = 0.0f, Max = 0.0f;
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
MaterialReferencePtr->GetScalarParameterSliderMinMax(ScalarParam, Min, Max);
|
|
}
|
|
return (Min == Max ? TOptional<float>() : Max);
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::OnScalarParameterSlideBegin(FMaterialParameterInfo ScalarParam)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("Begin slide"));
|
|
|
|
GEditor->BeginTransaction(LOCTEXT("ChangeScalarParam", "Change Scalar Param"));
|
|
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
for (UObject* Obj : OuterObjects)
|
|
{
|
|
Obj->Modify();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::OnScalarParameterSlideEnd(const float NewValue, FMaterialParameterInfo ScalarParam)
|
|
{
|
|
GEditor->EndTransaction();
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::OnScalarParameterCommitted(const float NewValue, ETextCommit::Type CommitType, FMaterialParameterInfo ScalarParam)
|
|
{
|
|
SetScalarParameterValue(NewValue, ScalarParam);
|
|
}
|
|
|
|
TOptional<float> FCompositingMaterialPassCustomization::GetScalarParameterValue(FMaterialParameterInfo ScalarParam) const
|
|
{
|
|
float OutVal = 0.0f;
|
|
|
|
FCompositingMaterialType* MatPass = GetMaterialPass();
|
|
if (MatPass && MatPass->GetScalarOverride(ScalarParam.Name, OutVal))
|
|
{
|
|
return OutVal;
|
|
}
|
|
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
MaterialReferencePtr->GetScalarParameterDefaultValue(ScalarParam, OutVal);
|
|
}
|
|
|
|
return OutVal;
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::SetScalarParameterValue(const float NewValue, FMaterialParameterInfo ScalarParam)
|
|
{
|
|
FCompositingMaterialType* MatPass = GetMaterialPass();
|
|
if (!MatPass)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float OutVal = 0.0f;
|
|
MatPass->GetScalarOverride(ScalarParam.Name, OutVal);
|
|
if (NewValue != OutVal)
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("ChangeScalarParam", "Change Scalar Param"));
|
|
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
for (UObject* Obj : OuterObjects)
|
|
{
|
|
Obj->Modify();
|
|
}
|
|
}
|
|
|
|
if (UMaterialInterface* MaterialReferencePtr = MaterialReference.Get())
|
|
{
|
|
float ParamDefault = 0.0f;
|
|
MaterialReferencePtr->GetScalarParameterDefaultValue(ScalarParam, ParamDefault);
|
|
if (NewValue == ParamDefault)
|
|
{
|
|
MatPass->ResetScalarOverride(ScalarParam.Name);
|
|
}
|
|
else
|
|
{
|
|
MatPass->SetScalarOverride(ScalarParam.Name, NewValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MatPass->SetScalarOverride(ScalarParam.Name, NewValue);
|
|
}
|
|
|
|
CompElementManager->RequestRedraw();
|
|
}
|
|
}
|
|
|
|
EVisibility FCompositingMaterialPassCustomization::IsResetScalarParameterVisible(FMaterialParameterInfo ScalarParam) const
|
|
{
|
|
float OverrideVal = 0.0f;
|
|
FCompositingMaterialType* MatPass = GetMaterialPass();
|
|
return (MatPass && MatPass->GetScalarOverride(ScalarParam.Name, OverrideVal))
|
|
? EVisibility::Visible
|
|
: EVisibility::Hidden;
|
|
}
|
|
|
|
FReply FCompositingMaterialPassCustomization::OnResetScalarParameterClicked(FMaterialParameterInfo ScalarParam)
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("ResetScalarParam", "Reset Scalar Param"));
|
|
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
for (UObject* Obj : OuterObjects)
|
|
{
|
|
Obj->Modify();
|
|
}
|
|
}
|
|
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
MatPass->ResetScalarOverride(ScalarParam.Name);
|
|
CompElementManager->RequestRedraw();
|
|
}
|
|
|
|
return FReply::Handled();
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::HandleRequiredParamComboChanged(TSharedPtr<FName> Item, ESelectInfo::Type SelectInfo, TWeakPtr<SComboButton> ComboButtonHandle, FName ParamName)
|
|
{
|
|
FCompositingMaterialType* MatPass = GetMaterialPass();
|
|
if (Item.IsValid() && MatPass)
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("RequiredParamUpdated", "Update Required Parameter"));
|
|
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
for (UObject* Obj : OuterObjects)
|
|
{
|
|
Obj->Modify();
|
|
}
|
|
}
|
|
|
|
MatPass->RequiredMaterialParams[ParamName].ParamName = *Item;
|
|
GEditor->RedrawAllViewports(/*bInvalidateHitProxies =*/false);
|
|
|
|
if (CachedUtils)
|
|
{
|
|
CachedUtils->ForceRefresh();
|
|
}
|
|
}
|
|
|
|
if (ComboButtonHandle.IsValid())
|
|
{
|
|
ComboButtonHandle.Pin()->SetIsOpen(false);
|
|
}
|
|
}
|
|
|
|
FText FCompositingMaterialPassCustomization::GetRequiredParamComboText(FName ParamName) const
|
|
{
|
|
FName ParamNameOut = NAME_None;
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
ParamNameOut = MatPass->RequiredMaterialParams[ParamName];
|
|
}
|
|
/*
|
|
//TODO: Should this apply to required params too?
|
|
if (ParamName.IsNone())
|
|
{
|
|
static const FName PrePassSelfAlias = TEXT("Self");
|
|
static const FName PrePassParamName = TEXT("PrePass");
|
|
IConsoleVariable* CVarUserPrePassParamName = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Composure.CompositingElements.InternalPrePassParamName"));
|
|
FName PrePassUserAlias = CVarUserPrePassParamName ? FName(*CVarUserPrePassParamName->GetString()) : PrePassParamName;
|
|
|
|
if (TexName == PrePassUserAlias || TexName == PrePassSelfAlias || TexName == PrePassParamName)
|
|
{
|
|
ParamName = PrePassParamName;
|
|
}
|
|
else
|
|
{
|
|
for (TSharedPtr<FName> NamePtr : TextureComboSource)
|
|
{
|
|
if (TexName == *NamePtr.Get())
|
|
{
|
|
ParamName = TexName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
return FText::FromName(ParamNameOut);
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::OnRequiredParamComboTextCommitted(const FText& NewText, ETextCommit::Type InTextCommit, FName ParamName)
|
|
{
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("RequiredParamUpdated", "Update Required Parameter"));
|
|
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
for (UObject* Obj : OuterObjects)
|
|
{
|
|
Obj->Modify();
|
|
}
|
|
}
|
|
|
|
MatPass->RequiredMaterialParams[ParamName].ParamName = FName(*NewText.ToString());
|
|
|
|
if (CachedUtils)
|
|
{
|
|
CachedUtils->ForceRefresh();
|
|
}
|
|
GEditor->RedrawAllViewports(/*bInvalidateHitProxies =*/false);
|
|
}
|
|
}
|
|
|
|
TSharedRef<SWidget> FCompositingMaterialPassCustomization::GetRequiredParamComboMenu(TWeakPtr<SComboButton> ComboButtonHandle, FName ParamName, EParamType ParamType)
|
|
{
|
|
//ReBuild combobox sources
|
|
RebuildRequiredParamSources();
|
|
|
|
TArray<TSharedPtr<FName>>* ComboSource = nullptr;
|
|
|
|
switch (ParamType)
|
|
{
|
|
case EParamType::ScalarParam:
|
|
ComboSource = &RequiredParamComboSourceScalar;
|
|
break;
|
|
case EParamType::VectorParam:
|
|
ComboSource = &RequiredParamComboSourceVector;
|
|
break;
|
|
case EParamType::TextureParam:
|
|
ComboSource = &RequiredParamComboSourceTexture;
|
|
break;
|
|
case EParamType::MediaTextureParam:
|
|
ComboSource = &RequiredParamComboSourceMedia;
|
|
break;
|
|
case EParamType::UnknownParamType:
|
|
ComboSource = &RequiredParamComboSourceUnknown;
|
|
break;
|
|
//default:
|
|
//Source list not found
|
|
}
|
|
|
|
|
|
|
|
return SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.MaxHeight(400.0f)
|
|
[
|
|
SNew(SListView< TSharedPtr<FName> >)
|
|
.ListItemsSource(ComboSource)
|
|
.OnGenerateRow(this, &FCompositingMaterialPassCustomization::GenerateComboItem)
|
|
.OnSelectionChanged(this, &FCompositingMaterialPassCustomization::HandleRequiredParamComboChanged, ComboButtonHandle, ParamName)
|
|
];
|
|
}
|
|
|
|
TSharedRef<ITableRow> FCompositingMaterialPassCustomization::GenerateComboItem(TSharedPtr<FName> InItem, const TSharedRef<STableViewBase>& OwnerTable)
|
|
{
|
|
return SNew(STableRow<TSharedPtr<FName>>, OwnerTable)
|
|
[
|
|
SNew(STextBlock).Text(FText::FromName(*InItem))
|
|
];
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::HandleComboChanged(TSharedPtr<FName> Item, ESelectInfo::Type SelectInfo, TWeakPtr<SComboButton> ComboButtonHandle, FName TexName)
|
|
{
|
|
FCompositingMaterialType* MatPass = GetMaterialPass();
|
|
if (Item.IsValid() && MatPass)
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("InputElementUpdated", "Update Input Element"));
|
|
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
for (UObject* Obj : OuterObjects)
|
|
{
|
|
Obj->Modify();
|
|
}
|
|
}
|
|
|
|
MatPass->ParamPassMappings[TexName] = *Item;
|
|
GEditor->RedrawAllViewports(/*bInvalidateHitProxies =*/false);
|
|
}
|
|
|
|
if (ComboButtonHandle.IsValid())
|
|
{
|
|
ComboButtonHandle.Pin()->SetIsOpen(false);
|
|
}
|
|
}
|
|
|
|
FText FCompositingMaterialPassCustomization::GetComboText(FName TexName) const
|
|
{
|
|
FName ParamName = NAME_None;
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
if (MatPass->ParamPassMappings.Contains(TexName))
|
|
{
|
|
ParamName = MatPass->ParamPassMappings[TexName];
|
|
}
|
|
}
|
|
|
|
if (ParamName.IsNone())
|
|
{
|
|
static const FName PrePassSelfAlias = TEXT("Self");
|
|
static const FName PrePassParamName = TEXT("PrePass");
|
|
IConsoleVariable* CVarUserPrePassParamName = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Composure.CompositingElements.InternalPrePassParamName"));
|
|
FName PrePassUserAlias = CVarUserPrePassParamName ? FName(*CVarUserPrePassParamName->GetString()) : PrePassParamName;
|
|
|
|
if (TexName == PrePassUserAlias || TexName == PrePassSelfAlias || TexName == PrePassParamName)
|
|
{
|
|
ParamName = PrePassParamName;
|
|
}
|
|
else
|
|
{
|
|
for (TSharedPtr<FName> NamePtr : TextureComboSource)
|
|
{
|
|
if (TexName == *NamePtr.Get())
|
|
{
|
|
ParamName = TexName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FText::FromName(ParamName);
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::OnComboTextCommitted(const FText& NewText, ETextCommit::Type InTextCommit, FName TexName)
|
|
{
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
FScopedTransaction Transaction(LOCTEXT("InputElementUpdated", "Update Input Element"));
|
|
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
for (UObject* Obj : OuterObjects)
|
|
{
|
|
Obj->Modify();
|
|
}
|
|
}
|
|
|
|
MatPass->ParamPassMappings.Add(TexName, *NewText.ToString());
|
|
GEditor->RedrawAllViewports(/*bInvalidateHitProxies =*/false);
|
|
}
|
|
}
|
|
|
|
TSharedRef<SWidget> FCompositingMaterialPassCustomization::GetPassComboMenu(TWeakPtr<SComboButton> ComboButtonHandle, FName TexName)
|
|
{
|
|
//ReBuild combobox source
|
|
RebuildTextureSourceList();
|
|
|
|
return SNew(SVerticalBox)
|
|
+ SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.MaxHeight(400.0f)
|
|
[
|
|
SNew(SListView< TSharedPtr<FName> >)
|
|
.ListItemsSource(&TextureComboSource)
|
|
.OnGenerateRow(this, &FCompositingMaterialPassCustomization::GenerateComboItem)
|
|
.OnSelectionChanged(this, &FCompositingMaterialPassCustomization::HandleComboChanged, ComboButtonHandle, TexName)
|
|
];
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::TextureResetToDefault(TSharedPtr<IPropertyHandle> PropertyHandle, TSharedPtr<SComboButton> ComboBoxHandle)
|
|
{
|
|
PropertyHandle->SetValue(FName(NAME_None));
|
|
//ComboBoxHandle->ClearSelection();
|
|
}
|
|
|
|
bool FCompositingMaterialPassCustomization::TextureShouldShowResetToDefault(TSharedPtr<IPropertyHandle> PropertyHandle)
|
|
{
|
|
FName ValueName;
|
|
PropertyHandle->GetValue(ValueName);
|
|
return (!ValueName.IsNone());
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::RebuildTextureSourceList()
|
|
{
|
|
TWeakObjectPtr<ACompositingElement> CompElement;
|
|
TextureComboSource.Reset();
|
|
|
|
TArray<UObject*> OuterChain;
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<UObject*> OuterObjects;
|
|
CachedPropertyHandlePin->GetOuterObjects(OuterObjects);
|
|
|
|
if (OuterObjects.Num() == 1)
|
|
{
|
|
UObject* Outer = OuterObjects[0];
|
|
while (Outer != nullptr && !Outer->IsA<ACompositingElement>())
|
|
{
|
|
OuterChain.Add(Outer);
|
|
Outer = Outer->GetOuter();
|
|
}
|
|
if (ACompositingElement* AsElement = Cast<ACompositingElement>(Outer))
|
|
{
|
|
CompElement = AsElement;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CompElement.IsValid())
|
|
{
|
|
ACompositingElement* CompElementPtr = CompElement.Get();
|
|
|
|
// First get earlier passes on this element
|
|
|
|
TArray<FName> InternalPassOptions;
|
|
InternalPassOptions.Reserve(TextureComboSource.GetSlack());
|
|
|
|
auto RecordAvailablePass = [&InternalPassOptions](const FName PassName)
|
|
{
|
|
if (!PassName.IsNone())
|
|
{
|
|
// Since passes can technically override the same name, we need to make sure that this list contains unique entries.
|
|
// We do a Remove() instead of an AddUnique() because we want the list order to reflect render order, and its the
|
|
// later pass that would overwrite the earlier one.
|
|
InternalPassOptions.Remove(PassName);
|
|
InternalPassOptions.Add(PassName);
|
|
}
|
|
};
|
|
|
|
bool FoundSelf = false;
|
|
auto IsSelf = [OuterChain](UCompositingElementPass* Pass)->bool
|
|
{
|
|
return OuterChain.Contains(Pass);
|
|
};
|
|
|
|
TArray<FName> InputIntermediates;
|
|
auto ClearAllInputIntermediates = [&InputIntermediates, &InternalPassOptions]()
|
|
{
|
|
for (const FName& Intermediate : InputIntermediates)
|
|
{
|
|
InternalPassOptions.Remove(Intermediate);
|
|
}
|
|
};
|
|
|
|
for (UCompositingElementInput* Input : CompElementPtr->GetInputsList())
|
|
{
|
|
if (IsSelf(Input))
|
|
{
|
|
FoundSelf = true;
|
|
break;
|
|
}
|
|
else if (Input && Input->IsPassEnabled())
|
|
{
|
|
if (Input->bIntermediate)
|
|
{
|
|
InputIntermediates.Add(Input->PassName);
|
|
}
|
|
else
|
|
{
|
|
// Since passes can technically override names, we want to make sure that an earlier intermediate
|
|
// doesn't keep this pass from being in the list
|
|
InputIntermediates.Remove(Input->PassName);
|
|
}
|
|
RecordAvailablePass(Input->PassName);
|
|
}
|
|
}
|
|
|
|
FName IntermediatePassName = NAME_None;
|
|
if (!FoundSelf)
|
|
{
|
|
for (UCompositingElementTransform* Transform : CompElementPtr->GetTransformsList())
|
|
{
|
|
if (IsSelf(Transform))
|
|
{
|
|
if (!IntermediatePassName.IsNone())
|
|
{
|
|
// Transforms that are intermediate are available to the pass that immediately follows.
|
|
RecordAvailablePass(IntermediatePassName);
|
|
}
|
|
|
|
FoundSelf = true;
|
|
break;
|
|
}
|
|
else if (Transform->IsPassEnabled())
|
|
{
|
|
if (Transform->bIntermediate)
|
|
{
|
|
// Intermediate transforms are only available to the following pass,
|
|
// so don't add this to the list yet (add it once we've found 'Self')
|
|
IntermediatePassName = Transform->PassName;
|
|
}
|
|
else
|
|
{
|
|
IntermediatePassName = NAME_None;
|
|
RecordAvailablePass(Transform->PassName);
|
|
}
|
|
// If 'Self' was the first transform, then we'd have all the inputs available to us,
|
|
// otherwise the intermediate ones get returned to the pool and cannot be used
|
|
ClearAllInputIntermediates();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!FoundSelf)
|
|
{
|
|
TArray<UCompositingElementOutput*> Outputs = CompElementPtr->GetOutputsList();
|
|
for (UObject* Outer : OuterChain)
|
|
{
|
|
if (Outputs.Contains(Cast<UCompositingElementOutput>(Outer)))
|
|
{
|
|
if (!IntermediatePassName.IsNone())
|
|
{
|
|
RecordAvailablePass(IntermediatePassName);
|
|
}
|
|
|
|
FoundSelf = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!FoundSelf)
|
|
{
|
|
// Since we didn't find this material in any of the set passes, we can't guarantee where this material
|
|
// used in the element's pipeline, so don't offer any internal passes as options.
|
|
InternalPassOptions.Empty();
|
|
}
|
|
}
|
|
|
|
if (InternalPassOptions.Num() > 0)
|
|
{
|
|
TextureComboSource.Add(MakeShared<FName>(TEXT("PrePass")));
|
|
}
|
|
for (FName InternalPassName : InternalPassOptions)
|
|
{
|
|
TextureComboSource.Add(MakeShared<FName>(InternalPassName));
|
|
}
|
|
|
|
//Now, get all children passes recursively
|
|
const TArray<ACompositingElement*> Children = CompElementPtr->GetChildElements();
|
|
for (ACompositingElement* Element : Children)
|
|
{
|
|
if (Element)
|
|
{
|
|
TextureComboSource.Append(GetPassNamesRecursive(Element));
|
|
}
|
|
}
|
|
}
|
|
|
|
//TextureComboSource.Sort([](const TSharedPtr<FName> A, const TSharedPtr<FName> B) { return (A->Compare(*B) < 0); });
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::RebuildRequiredParamSources()
|
|
{
|
|
UMaterialInterface* MaterialReferencePtr = MaterialReference.Get();
|
|
check(MaterialReferencePtr);
|
|
|
|
RequiredParamComboSourceUnknown.Reset();
|
|
|
|
RequiredParamComboSourceScalar.Reset();
|
|
TArray<FMaterialParameterInfo> OutScalarParameterInfo;
|
|
TArray<FGuid> ScalarGuids;
|
|
MaterialReferencePtr->GetAllScalarParameterInfo(OutScalarParameterInfo, ScalarGuids);
|
|
for (FMaterialParameterInfo Param : OutScalarParameterInfo)
|
|
{
|
|
RequiredParamComboSourceScalar.Add(MakeShared<FName>(Param.Name));
|
|
RequiredParamComboSourceUnknown.Add(MakeShared<FName>(Param.Name));
|
|
}
|
|
|
|
RequiredParamComboSourceVector.Reset();
|
|
TArray<FMaterialParameterInfo> OutVectorParameterInfo;
|
|
TArray<FGuid> VectorGuids;
|
|
MaterialReferencePtr->GetAllVectorParameterInfo(OutVectorParameterInfo, VectorGuids);
|
|
for (FMaterialParameterInfo Param : OutVectorParameterInfo)
|
|
{
|
|
RequiredParamComboSourceVector.Add(MakeShared<FName>(Param.Name));
|
|
RequiredParamComboSourceUnknown.Add(MakeShared<FName>(Param.Name));
|
|
}
|
|
|
|
RequiredParamComboSourceTexture.Reset();
|
|
TArray<FMaterialParameterInfo> OutTextureParameterInfo;
|
|
TArray<FGuid> TextureGuids;
|
|
MaterialReferencePtr->GetAllTextureParameterInfo(OutTextureParameterInfo, TextureGuids);
|
|
for (FMaterialParameterInfo Param : OutTextureParameterInfo)
|
|
{
|
|
RequiredParamComboSourceTexture.Add(MakeShared<FName>(Param.Name));
|
|
RequiredParamComboSourceUnknown.Add(MakeShared<FName>(Param.Name));
|
|
}
|
|
|
|
|
|
//TODO: Media Texture Params?
|
|
|
|
|
|
}
|
|
|
|
TArray<TSharedPtr<FName>> FCompositingMaterialPassCustomization::GetPassNamesRecursive(ACompositingElement* Element, const FString& InPrefix)
|
|
{
|
|
TArray<TSharedPtr<FName>> NamesToAdd;
|
|
|
|
FString Prefix = InPrefix;
|
|
auto AddPassNameToList = [&NamesToAdd, &Prefix](FName PassName)
|
|
{
|
|
if (!PassName.IsNone())
|
|
{
|
|
FString PathName = Prefix + PassName.ToString();
|
|
NamesToAdd.Add(MakeShared<FName>(*PathName));
|
|
}
|
|
};
|
|
|
|
AddPassNameToList(Element->GetCompElementName());
|
|
Prefix += Element->GetCompElementName().ToString() + TEXT('.');
|
|
|
|
for (UCompositingElementInput* Input : Element->GetInputsList())
|
|
{
|
|
if (Input->IsPassEnabled() && !Input->bIntermediate)
|
|
{
|
|
AddPassNameToList(Input->PassName);
|
|
}
|
|
}
|
|
|
|
for (UCompositingElementTransform* Transform : Element->GetTransformsList())
|
|
{
|
|
if (Transform->IsPassEnabled() && !Transform->bIntermediate)
|
|
{
|
|
AddPassNameToList(Transform->PassName);
|
|
}
|
|
}
|
|
|
|
// NOTE: Outputs aren't available, as they do not return a texture/target to source from.
|
|
|
|
|
|
for (ACompositingElement* ChildElement : Element->GetChildElements())
|
|
{
|
|
if (ChildElement)
|
|
{
|
|
NamesToAdd.Append(GetPassNamesRecursive(ChildElement, Prefix));
|
|
}
|
|
}
|
|
|
|
return NamesToAdd;
|
|
}
|
|
|
|
FCompositingMaterialType* FCompositingMaterialPassCustomization::GetMaterialPass() const
|
|
{
|
|
if (TSharedPtr<IPropertyHandle> CachedPropertyHandlePin = CachedPropertyHandle.Pin())
|
|
{
|
|
TArray<void*> RawData;
|
|
CachedPropertyHandlePin->AccessRawData(RawData);
|
|
|
|
if (RawData.Num() > 0)
|
|
{
|
|
return reinterpret_cast<FCompositingMaterialType*>(RawData[0]);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::ResetParameterOverrides()
|
|
{
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
MatPass->ResetAllParamOverrides();
|
|
MatPass->UpdateProxyMap();
|
|
|
|
if (CachedUtils)
|
|
{
|
|
CachedUtils->ForceRefresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::OnRedrawViewports()
|
|
{
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
MatPass->UpdateProxyMap();
|
|
|
|
if (CachedUtils)
|
|
{
|
|
CachedUtils->ForceRefresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FCompositingMaterialPassCustomization::PostUndo(bool bSuccess)
|
|
{
|
|
if (FCompositingMaterialType* MatPass = GetMaterialPass())
|
|
{
|
|
MatPass->MarkDirty();
|
|
MatPass->ApplyParamOverrides(nullptr);
|
|
CompElementManager->RequestRedraw();
|
|
}
|
|
}
|
|
|
|
/* FCompositingPassCustomization
|
|
*****************************************************************************/
|
|
|
|
#include "Widgets/SCompElementPreviewDialog.h"
|
|
|
|
TSharedRef<IPropertyTypeCustomization> FCompositingPassCustomization::MakeInstance()
|
|
{
|
|
return MakeShareable(new FCompositingPassCustomization);
|
|
}
|
|
|
|
void FCompositingPassCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> PropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& CustomizationUtils)
|
|
{
|
|
TSharedRef<SWidget> DefaultValWidget = PropertyHandle->CreatePropertyValueWidget(/*bDisplayDefaultPropertyButtons =*/false);
|
|
HeaderValueWidget = TSharedPtr<SWidget>(DefaultValWidget);
|
|
|
|
HeaderRow
|
|
.NameContent()
|
|
[
|
|
PropertyHandle->CreatePropertyNameWidget()
|
|
]
|
|
.ValueContent()
|
|
// Match the same Min/Max from ConstructPropertyEditorWidget()
|
|
.MinDesiredWidth(250.f)
|
|
.MaxDesiredWidth(600.f)
|
|
.VAlign(VAlign_Center)
|
|
.HAlign(HAlign_Left)
|
|
[
|
|
DefaultValWidget
|
|
];
|
|
|
|
if (PropertyHandle->GetIndexInArray() != INDEX_NONE)
|
|
{
|
|
TSharedPtr<IPropertyHandle> PassNameHandle = PropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(UCompositingElementPass, PassName));
|
|
if (PassNameHandle.IsValid())
|
|
{
|
|
FName NameValue;
|
|
PassNameHandle->GetValue(NameValue);
|
|
|
|
if (!NameValue.IsNone())
|
|
{
|
|
FText PassNameText;
|
|
PassNameHandle->GetValueAsDisplayText(PassNameText);
|
|
|
|
HeaderRow.NameContent()
|
|
[
|
|
PropertyHandle->CreatePropertyNameWidget(PassNameText)
|
|
];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FCompositingPassCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> PropertyHandle, IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& CustomizationUtils)
|
|
{
|
|
const bool bShowInnerPropsOnly = PropertyHandle->HasMetaData(TEXT("ShowOnlyInnerProperties"));
|
|
|
|
TSharedPtr<IPropertyHandle> ObjectHandle = GetInstancedObjectHandle(PropertyHandle);
|
|
if (ObjectHandle.IsValid())
|
|
{
|
|
TSharedPtr<SWidget> ParentWidget = HeaderValueWidget.IsValid() ? HeaderValueWidget.Pin() : nullptr;
|
|
TSharedPtr<SWidget> PreviewButton = ConditionallyCreatePreviewButton(PropertyHandle, ParentWidget);
|
|
if (PreviewButton.IsValid())
|
|
{
|
|
ChildBuilder.AddCustomRow(LOCTEXT("PreviewLabel", "Preview"))
|
|
.ValueContent()
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SBox)
|
|
.HAlign(HAlign_Right)
|
|
[
|
|
PreviewButton.ToSharedRef()
|
|
]
|
|
];
|
|
}
|
|
|
|
PropertyHandle = ObjectHandle.ToSharedRef();
|
|
}
|
|
|
|
uint32 NumChildren;
|
|
PropertyHandle->GetNumChildren(NumChildren);
|
|
|
|
for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex)
|
|
{
|
|
TSharedRef<IPropertyHandle> ChildHandle = PropertyHandle->GetChildHandle(ChildIndex).ToSharedRef();
|
|
|
|
if (bShowInnerPropsOnly)
|
|
{
|
|
uint32 NumGrandChildren;
|
|
ChildHandle->GetNumChildren(NumGrandChildren);
|
|
|
|
for (uint32 GrandChildIndex = 0; GrandChildIndex < NumGrandChildren; ++GrandChildIndex)
|
|
{
|
|
TSharedRef<IPropertyHandle> GrandChildHandle = ChildHandle->GetChildHandle(GrandChildIndex).ToSharedRef();
|
|
ChildBuilder.AddProperty(GrandChildHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ChildBuilder.AddProperty(ChildHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
TSharedPtr<IPropertyHandle> FCompositingPassCustomization::GetInstancedObjectHandle(TSharedRef<IPropertyHandle> PropertyHandle)
|
|
{
|
|
TSharedPtr<IPropertyHandle> ChildHandle;
|
|
|
|
uint32 NumChildren;
|
|
PropertyHandle->GetNumChildren(NumChildren);
|
|
|
|
if (NumChildren > 0)
|
|
{
|
|
const bool bIsEditInlineObj = PropertyHandle->HasMetaData(TEXT("EditInline"));
|
|
if (bIsEditInlineObj)
|
|
{
|
|
// when the property is a (inlined) object property, the first child will be
|
|
// the object instance, and its properties are the children underneath that
|
|
ensure(NumChildren == 1);
|
|
|
|
ChildHandle = PropertyHandle->GetChildHandle(0);
|
|
}
|
|
}
|
|
|
|
return ChildHandle;
|
|
}
|
|
|
|
TSharedPtr<SWidget> FCompositingPassCustomization::ConditionallyCreatePreviewButton(TSharedRef<IPropertyHandle> PropertyHandle, TSharedPtr<SWidget> ParentWidget)
|
|
{
|
|
TSharedPtr<SWidget> PreviewButton;
|
|
|
|
TSharedPtr<IPropertyHandle> ObjectHandle = GetInstancedObjectHandle(PropertyHandle);
|
|
if (ObjectHandle.IsValid())
|
|
{
|
|
PropertyHandle = ObjectHandle.ToSharedRef();
|
|
|
|
TArray<void*> RawData;
|
|
ObjectHandle->AccessRawData(RawData);
|
|
|
|
if (RawData.Num() > 0)
|
|
{
|
|
UCompositingElementPass* PassObj = reinterpret_cast<UCompositingElementPass*>(RawData[0]);
|
|
|
|
if (PassObj && PassObj->Implements<UCompEditorImagePreviewInterface>())
|
|
{
|
|
TWeakUIntrfacePtr<ICompEditorImagePreviewInterface> WeakPassPtr(PassObj);
|
|
|
|
PreviewButton = SNew(SButton)
|
|
[
|
|
SNew(STextBlock).Text(LOCTEXT("PreviewLabel", "Preview"))
|
|
]
|
|
.OnClicked_Lambda([WeakPassPtr, ParentWidget, PassObj]()->FReply
|
|
{
|
|
FText WindowTitle;
|
|
if (WeakPassPtr.IsValid())
|
|
{
|
|
WindowTitle = FText::Format(LOCTEXT("PreviewWindowTitle", "Preview: {0}"), FText::FromName(PassObj->PassName));
|
|
}
|
|
|
|
SCompElementPreviewDialog::OpenPreviewWindow(WeakPassPtr, ParentWidget, WindowTitle);
|
|
return FReply::Handled();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return PreviewButton;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|