Files
UnrealEngine/Engine/Plugins/Mutable/Source/CustomizableObjectEditor/Private/MuCOE/SMutableGraphViewer.cpp
2025-05-18 13:04:45 +08:00

925 lines
30 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MuCOE/SMutableGraphViewer.h"
#include "DesktopPlatformModule.h"
#include "EditorDirectories.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Framework/Views/TableViewMetadata.h"
#include "IDesktopPlatform.h"
#include "Misc/Paths.h"
#include "MuCOE/CustomizableObjectCompileRunnable.h"
#include "MuCOE/CustomizableObjectEditorStyle.h"
#include "MuCOE/SMutableCodeViewer.h"
#include "MuCOE/UnrealEditorPortabilityHelpers.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/Input/STextComboBox.h"
#include "Widgets/Input/SNumericDropDown.h"
#include "Widgets/Views/STreeView.h"
#include "ScopedTransaction.h"
#include "MuT/NodeColourConstant.h"
#include "MuT/NodeColourFromScalars.h"
#include "MuT/NodeColourParameter.h"
#include "MuT/NodeColourSampleImage.h"
#include "MuT/NodeColourSwitch.h"
#include "MuT/NodeComponentEdit.h"
#include "MuT/NodeComponentSwitch.h"
#include "MuT/NodeImageFormat.h"
#include "MuT/NodeImageInterpolate.h"
#include "MuT/NodeImageInvert.h"
#include "MuT/NodeImageLayer.h"
#include "MuT/NodeImageLayerColour.h"
#include "MuT/NodeImageMipmap.h"
#include "MuT/NodeImageMultiLayer.h"
#include "MuT/NodeImagePlainColour.h"
#include "MuT/NodeImageProject.h"
#include "MuT/NodeImageResize.h"
#include "MuT/NodeImageSwitch.h"
#include "MuT/NodeImageSwizzle.h"
#include "MuT/NodeImageTable.h"
#include "MuT/NodeObjectGroup.h"
#include "MuT/NodeObjectNew.h"
#include "MuT/NodeSurfaceNew.h"
#include "MuT/NodeSurfaceSwitch.h"
#include "MuT/NodeSurfaceVariation.h"
#include "MuT/NodeLOD.h"
#include "MuT/NodeMeshConstant.h"
#include "MuT/NodeMeshFormat.h"
#include "MuT/NodeMeshFragment.h"
#include "MuT/NodeMeshMakeMorph.h"
#include "MuT/NodeMeshMorph.h"
#include "MuT/NodeMeshTable.h"
#include "MuT/NodeModifierMeshClipDeform.h"
#include "MuT/NodeModifierMeshClipMorphPlane.h"
#include "MuT/NodeModifierMeshClipWithUVMask.h"
#include "MuT/NodeModifierMeshClipMorphPlane.h"
#include "MuT/NodeModifierSurfaceEdit.h"
#include "MuT/NodeScalarConstant.h"
#include "MuT/NodeScalarCurve.h"
#include "MuT/NodeScalarSwitch.h"
#include "MuT/NodeScalarTable.h"
#include "MuT/NodeObjectNew.h"
#include "MuT/NodeModifierMeshTransformInMesh.h"
#include "Widgets/MutableExpanderArrow.h"
class FExtender;
class FReferenceCollector;
class FUICommandList;
class ITableRow;
class SWidget;
struct FGeometry;
struct FSlateBrush;
#define LOCTEXT_NAMESPACE "SMutableDebugger"
// \todo: multi-column tree
namespace MutableGraphTreeViewColumns
{
static const FName Name("Name");
};
static const char* MutableNodeNames[] =
{
"None",
"Node",
"Mesh",
"MeshConstant",
"MeshTable",
"MeshFormat",
"MeshTangents",
"MeshMorph",
"MeshMakeMorph",
"MeshSwitch",
"MeshFragment",
"MeshTransform",
"MeshClipMorphPlane",
"MeshClipWithMesh",
"MeshApplyPose",
"MeshVariation",
"MeshReshape",
"MeshClipDeform",
"MeshParameter",
"Image",
"ImageConstant",
"ImageInterpolate",
"ImageSaturate",
"ImageTable",
"ImageSwizzle",
"ImageColorMap",
"ImageGradient",
"ImageBinarise",
"ImageLuminance",
"ImageLayer",
"ImageLayerColour",
"ImageResize",
"ImagePlainColour",
"ImageProject",
"ImageMipmap",
"ImageSwitch",
"ImageConditional",
"ImageFormat",
"ImageParameter",
"ImageMultiLayer",
"ImageInvert",
"ImageVariation",
"ImageNormalComposite",
"ImageTransform",
"Bool",
"BoolConstant",
"BoolParameter",
"BoolNot",
"BoolAnd",
"Color",
"ColorConstant",
"ColorParameter",
"ColorSampleImage",
"ColorTable",
"ColorImageSize",
"ColorFromScalars",
"ColorArithmeticOperation",
"ColorSwitch",
"ColorVariation",
"Scalar",
"ScalarConstant",
"ScalarParameter",
"ScalarEnumParameter",
"ScalarCurve",
"ScalarSwitch",
"ScalarArithmeticOperation",
"ScalarVariation",
"ScalarTable",
"String",
"StringConstant",
"StringParameter",
"Projector",
"ProjectorConstant",
"ProjectorParameter",
"Range",
"RangeFromScalar",
"Layout",
"PatchImage",
"PatchMesh",
"Surface",
"SurfaceNew",
"SurfaceSwitch",
"SurfaceVariation",
"LOD",
"Component",
"ComponentNew",
"ComponentEdit",
"ComponentSwitch",
"ComponentVariation",
"Object",
"ObjectNew",
"ObjectGroup",
"Modifier",
"ModifierMeshClipMorphPlane",
"ModifierMeshClipWithMesh",
"ModifierMeshClipDeform",
"ModifierMeshClipWithUVMask",
"ModifierSurfaceEdit",
"ModifierTransformInMesh",
"ExtensionData",
"ExtensionDataConstant",
"ExtensionDataSwitch",
"ExtensionDataVariation",
"Matrix",
"MatrixConstant",
"MatrixParameter",
};
static_assert(UE_ARRAY_COUNT(MutableNodeNames) == SIZE_T(mu::Node::EType::Count));
class SMutableGraphTreeRow : public STableRow<TSharedPtr<FMutableGraphTreeElement>>
{
public:
void Construct(const FArguments& Args, const TSharedRef<STableViewBase>& InOwnerTableView, const TSharedPtr<FMutableGraphTreeElement>& InRowItem)
{
RowItem = InRowItem;
FText MainLabel = FText::GetEmpty();
if (RowItem->MutableNode)
{
mu::Node::EType MutableType = RowItem->MutableNode->GetType()->Type;
FString NodeName = MutableNodeNames[int32(MutableType)];
const FString LabelString = RowItem->Prefix.IsEmpty()
? FString::Printf( TEXT("%s"), *NodeName)
: FString::Printf( TEXT("%s : %s"), *RowItem->Prefix, *NodeName);
MainLabel = FText::FromString(LabelString);
if (RowItem->DuplicatedOf)
{
MainLabel = FText::FromString( FString::Printf(TEXT("%s (Duplicated)"), *NodeName));
}
}
else
{
MainLabel = FText::FromString( *RowItem->Prefix);
}
this->ChildSlot
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SMutableExpanderArrow, SharedThis(this))
]
+ SHorizontalBox::Slot()
[
SNew(STextBlock)
.Text(MainLabel)
]
];
STableRow< TSharedPtr<FMutableGraphTreeElement> >::ConstructInternal(
STableRow::FArguments()
//.Style(FAppStyle::Get(), "DetailsView.TreeView.TableRow")
.ShowSelection(true)
, InOwnerTableView
);
}
private:
TSharedPtr<FMutableGraphTreeElement> RowItem;
};
void SMutableGraphViewer::AddReferencedObjects(FReferenceCollector& Collector)
{
// Add UObjects here if we own any at some point
//Collector.AddReferencedObject(CustomizableObject);
}
FString SMutableGraphViewer::GetReferencerName() const
{
return TEXT("SMutableGraphViewer");
}
void SMutableGraphViewer::Construct(const FArguments& InArgs, const mu::NodePtr& InRootNode)
{
DataTag = InArgs._DataTag;
ReferencedRuntimeTextures = InArgs._ReferencedRuntimeTextures;
ReferencedCompileTextures = InArgs._ReferencedCompileTextures;
RootNode = InRootNode;
FToolBarBuilder ToolbarBuilder(TSharedPtr<const FUICommandList>(), FMultiBoxCustomization::None, TSharedPtr<FExtender>(), true);
ToolbarBuilder.SetLabelVisibility(EVisibility::Visible);
ToolbarBuilder.SetStyle(&FAppStyle::Get(), "SlimToolBar");
ToolbarBuilder.AddWidget(SNew(STextBlock).Text(MakeAttributeLambda([this]() { return FText::FromString(DataTag); })));
ChildSlot
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
.VAlign(VAlign_Center)
[
ToolbarBuilder.MakeWidget()
]
+ SVerticalBox::Slot()
.VAlign(VAlign_Fill)
[
SNew(SSplitter)
.Orientation(EOrientation::Orient_Horizontal)
+ SSplitter::Slot()
.Value(0.25f)
[
SNew(SBorder)
.BorderImage(UE_MUTABLE_GET_BRUSH("ToolPanel.GroupBorder"))
.Padding(FMargin(4.0f, 4.0f))
[
SAssignNew(TreeView, STreeView<TSharedPtr<FMutableGraphTreeElement>>)
.TreeItemsSource(&RootNodes)
.OnGenerateRow(this,&SMutableGraphViewer::GenerateRowForNodeTree)
.OnGetChildren(this, &SMutableGraphViewer::GetChildrenForInfo)
.OnSetExpansionRecursive(this, &SMutableGraphViewer::TreeExpandRecursive)
.OnContextMenuOpening(this, &SMutableGraphViewer::OnTreeContextMenuOpening)
.SelectionMode(ESelectionMode::Single)
.HeaderRow
(
SNew(SHeaderRow)
+ SHeaderRow::Column(MutableGraphTreeViewColumns::Name)
.FillWidth(25.f)
.DefaultLabel(LOCTEXT("Node Name", "Node Name"))
)
]
]
+ SSplitter::Slot()
.Value(0.75f)
[
SNew(SBorder)
.BorderImage(UE_MUTABLE_GET_BRUSH("ToolPanel.GroupBorder"))
.Padding(FMargin(4.0f, 4.0f))
//[
// SubjectsTreeView->AsShared()
//]
]
]
];
RebuildTree();
}
void SMutableGraphViewer::RebuildTree()
{
RootNodes.Reset();
ItemCache.Reset();
MainItemPerNode.Reset();
RootNodes.Add(MakeShareable(new FMutableGraphTreeElement(RootNode)));
TreeView->RequestTreeRefresh();
TreeExpandUnique();
}
TSharedRef<ITableRow> SMutableGraphViewer::GenerateRowForNodeTree(TSharedPtr<FMutableGraphTreeElement> InTreeNode, const TSharedRef<STableViewBase>& InOwnerTable)
{
TSharedRef<SMutableGraphTreeRow> Row = SNew(SMutableGraphTreeRow, InOwnerTable, InTreeNode);
return Row;
}
void SMutableGraphViewer::GetChildrenForInfo(TSharedPtr<FMutableGraphTreeElement> InInfo, TArray<TSharedPtr<FMutableGraphTreeElement>>& OutChildren)
{
// This is necessary because of problems with rtti information in other platforms. In any case, this part of the debugger is only useful in the standard editor.
#if PLATFORM_WINDOWS
if (!InInfo->MutableNode)
{
return;
}
// If this is a duplicated of another row, don't provide its children.
if (InInfo->DuplicatedOf)
{
return;
}
mu::Node* ParentNode = InInfo->MutableNode.get();
uint32 InputIndex = 0;
auto AddChildFunc = [this, ParentNode, &InputIndex, &OutChildren](mu::Node* ChildNode, const FString& Prefix)
{
if (ChildNode)
{
FItemCacheKey Key = { ParentNode, ChildNode, InputIndex };
TSharedPtr<FMutableGraphTreeElement>* CachedItem = ItemCache.Find(Key);
if (CachedItem)
{
OutChildren.Add(*CachedItem);
}
else
{
TSharedPtr<FMutableGraphTreeElement>* MainItemPtr = MainItemPerNode.Find(ChildNode);
TSharedPtr<FMutableGraphTreeElement> Item = MakeShareable(new FMutableGraphTreeElement(ChildNode, MainItemPtr, Prefix));
OutChildren.Add(Item);
ItemCache.Add(Key, Item);
if (!MainItemPtr)
{
MainItemPerNode.Add(ChildNode, Item);
}
}
}
else
{
// No mutable node has been provided so create a dummy tree element
TSharedPtr<FMutableGraphTreeElement> Item = MakeShareable(new FMutableGraphTreeElement(nullptr, nullptr , Prefix));
OutChildren.Add(Item);
}
++InputIndex;
};
if (ParentNode->GetType() == mu::NodeObjectNew::GetStaticType())
{
mu::NodeObjectNew* ObjectNew = StaticCast<mu::NodeObjectNew*>(ParentNode);
for (int32 l = 0; l < ObjectNew->Components.Num(); ++l)
{
AddChildFunc(ObjectNew->Components[l].get(), TEXT("COMP") );
}
for (int32 Modifier = 0; Modifier < ObjectNew->Modifiers.Num(); Modifier++)
{
AddChildFunc(ObjectNew->Modifiers[Modifier].get(), FString::Printf(TEXT("MOD [%d]"), Modifier));
}
for (int32 l = 0; l < ObjectNew->Children.Num(); ++l)
{
AddChildFunc(ObjectNew->Children[l].get(), TEXT("CHILD"));
}
}
else if (ParentNode->GetType() == mu::NodeObjectGroup::GetStaticType())
{
mu::NodeObjectGroup* ObjectGroup = StaticCast<mu::NodeObjectGroup*>(ParentNode);
for (int32 l = 0; l < ObjectGroup->Children.Num(); ++l)
{
AddChildFunc(ObjectGroup->Children[l].get(), TEXT("CHILD"));
}
}
else if (ParentNode->GetType() == mu::NodeSurfaceNew::GetStaticType())
{
mu::NodeSurfaceNew* SurfaceNew = StaticCast<mu::NodeSurfaceNew*>(ParentNode);
AddChildFunc(SurfaceNew->Mesh.get(), TEXT("MESH"));
for (int32 l = 0; l < SurfaceNew->Images.Num(); ++l)
{
AddChildFunc(SurfaceNew->Images[l].Image.get(), FString::Printf(TEXT("IMAGE [%s]"), *SurfaceNew->Images[l].Name));
}
for (int32 l = 0; l < SurfaceNew->Vectors.Num(); ++l)
{
AddChildFunc(SurfaceNew->Vectors[l].Vector.get(), FString::Printf(TEXT("VECTOR [%s]"), *SurfaceNew->Vectors[l].Name));
}
for (int32 l = 0; l < SurfaceNew->Scalars.Num(); ++l)
{
AddChildFunc(SurfaceNew->Scalars[l].Scalar.get(), FString::Printf(TEXT("SCALAR [%s]"), *SurfaceNew->Scalars[l].Name));
}
for (int32 l = 0; l < SurfaceNew->Strings.Num(); ++l)
{
AddChildFunc(SurfaceNew->Strings[l].String.get(), FString::Printf(TEXT("STRING [%s]"), *SurfaceNew->Strings[l].Name));
}
}
else if (ParentNode->GetType() == mu::NodeModifierSurfaceEdit::GetStaticType())
{
mu::NodeModifierSurfaceEdit* SurfaceEdit = StaticCast<mu::NodeModifierSurfaceEdit*>(ParentNode);
AddChildFunc(SurfaceEdit->MorphFactor.get(), FString::Printf(TEXT("MORPH_FACTOR [%s]"), *SurfaceEdit->MeshMorph));
for (int32 LODIndex = 0; LODIndex < SurfaceEdit->LODs.Num(); ++LODIndex)
{
AddChildFunc(SurfaceEdit->LODs[LODIndex].MeshAdd.get(), FString::Printf(TEXT("LOD%d MESH_ADD"), LODIndex));
AddChildFunc(SurfaceEdit->LODs[LODIndex].MeshRemove.get(), FString::Printf(TEXT("LOD%d MESH_REMOVE"), LODIndex));
for (int32 l = 0; l < SurfaceEdit->LODs[LODIndex].Textures.Num(); ++l)
{
AddChildFunc(SurfaceEdit->LODs[LODIndex].Textures[l].Extend.get(), FString::Printf(TEXT("LOD%d EXTEND [%d]"), LODIndex, l));
AddChildFunc(SurfaceEdit->LODs[LODIndex].Textures[l].PatchImage.get(), FString::Printf(TEXT("LOD%d PATCH IMAGE [%d]"), LODIndex, l));
AddChildFunc(SurfaceEdit->LODs[LODIndex].Textures[l].PatchMask.get(), FString::Printf(TEXT("LOD%d PATCH MASK [%d]"), LODIndex, l));
}
}
}
else if (ParentNode->GetType() == mu::NodeSurfaceSwitch::GetStaticType())
{
mu::NodeSurfaceSwitch* SurfaceSwitch = StaticCast<mu::NodeSurfaceSwitch*>(ParentNode);
AddChildFunc(SurfaceSwitch->Parameter.get(), TEXT("PARAM"));
for (int32 l = 0; l < SurfaceSwitch->Options.Num(); ++l)
{
AddChildFunc(SurfaceSwitch->Options[l].get(), FString::Printf(TEXT("OPTION [%d]"), l));
}
}
else if (ParentNode->GetType() == mu::NodeSurfaceVariation::GetStaticType())
{
mu::NodeSurfaceVariation* SurfaceVar = StaticCast<mu::NodeSurfaceVariation*>(ParentNode);
for (int32 l = 0; l < SurfaceVar->DefaultSurfaces.Num(); ++l)
{
AddChildFunc(SurfaceVar->DefaultSurfaces[l].get(), FString::Printf(TEXT("DEF SURF [%d]"), l));
}
for (int32 l = 0; l < SurfaceVar->DefaultModifiers.Num(); ++l)
{
AddChildFunc(SurfaceVar->DefaultModifiers[l].get(), FString::Printf(TEXT("DEF MOD [%d]"), l));
}
for (int32 v = 0; v < SurfaceVar->Variations.Num(); ++v)
{
const mu::NodeSurfaceVariation::FVariation Var = SurfaceVar->Variations[v];
for (int32 l = 0; l < Var.Surfaces.Num(); ++l)
{
AddChildFunc(Var.Surfaces[l].get(), FString::Printf(TEXT("VAR [%s] SURF [%d]"), *Var.Tag, l));
}
for (int32 l = 0; l < Var.Modifiers.Num(); ++l)
{
AddChildFunc(Var.Modifiers[l].get(), FString::Printf(TEXT("VAR [%s] MOD [%d]"), *Var.Tag, l));
}
}
}
else if (ParentNode->GetType() == mu::NodeLOD::GetStaticType())
{
mu::NodeLOD* LodVar = StaticCast<mu::NodeLOD*>(ParentNode);
for (int32 SurfaceIndex = 0; SurfaceIndex < LodVar->Surfaces.Num(); SurfaceIndex++)
{
AddChildFunc(LodVar->Surfaces[SurfaceIndex].get(), FString::Printf(TEXT("SURFACE [%d]"), SurfaceIndex));
}
}
else if (ParentNode->GetType() == mu::NodeComponentNew::GetStaticType())
{
mu::NodeComponentNew* ComponentVar = StaticCast<mu::NodeComponentNew*>(ParentNode);
for (int32 LODIndex = 0; LODIndex < ComponentVar->LODs.Num(); LODIndex++)
{
AddChildFunc(ComponentVar->LODs[LODIndex].get(), FString::Printf(TEXT("LOD [%d]"), LODIndex));
}
AddChildFunc(ComponentVar->OverlayMaterial.get(), TEXT("OVERLAY MATERIAL"));
}
else if (ParentNode->GetType() == mu::NodeComponentEdit::GetStaticType())
{
mu::NodeComponentEdit* ComponentVar = StaticCast<mu::NodeComponentEdit*>(ParentNode);
for (int32 LODIndex = 0; LODIndex < ComponentVar->LODs.Num(); LODIndex++)
{
AddChildFunc(ComponentVar->LODs[LODIndex].get(), FString::Printf(TEXT("LOD [%d]"), LODIndex));
}
}
else if (ParentNode->GetType() == mu::NodeComponentSwitch::GetStaticType())
{
mu::NodeComponentSwitch* ComponentSwitch = StaticCast<mu::NodeComponentSwitch*>(ParentNode);
AddChildFunc(ComponentSwitch->Parameter.get(), TEXT("PARAM"));
for (int32 OptionIndex = 0; OptionIndex < ComponentSwitch->Options.Num(); OptionIndex++)
{
AddChildFunc(ComponentSwitch->Options[OptionIndex].get(), FString::Printf(TEXT("OPTION [%d]"), OptionIndex));
}
}
else if (ParentNode->GetType() == mu::NodeMeshConstant::GetStaticType())
{
mu::NodeMeshConstant* MeshConstantVar = StaticCast<mu::NodeMeshConstant*>(ParentNode);
for (int32 LayoutIndex = 0; LayoutIndex < MeshConstantVar->Layouts.Num(); LayoutIndex++)
{
AddChildFunc(MeshConstantVar->Layouts[LayoutIndex].get(), FString::Printf(TEXT("LAYOUT [%d]"), LayoutIndex));
}
}
else if (ParentNode->GetType() == mu::NodeImageFormat::GetStaticType())
{
mu::NodeImageFormat* ImageFormatVar = StaticCast<mu::NodeImageFormat*>(ParentNode);
AddChildFunc(ImageFormatVar->Source.get(), FString::Printf(TEXT("SOURCE IMAGE")));
}
else if (ParentNode->GetType() == mu::NodeMeshFormat::GetStaticType())
{
mu::NodeMeshFormat* MeshFormatVar = StaticCast<mu::NodeMeshFormat*>(ParentNode);
AddChildFunc(MeshFormatVar->Source.get(), FString::Printf(TEXT("SOURCE MESH")));
}
else if (ParentNode->GetType() == mu::NodeModifierMeshClipMorphPlane::GetStaticType())
{
// Nothing to show
}
else if (ParentNode->GetType() == mu::NodeModifierMeshClipWithMesh::GetStaticType())
{
mu::NodeModifierMeshClipWithMesh* ModifierMeshClipWithMeshVar = StaticCast<mu::NodeModifierMeshClipWithMesh*>(ParentNode);
AddChildFunc(ModifierMeshClipWithMeshVar->ClipMesh.get(), FString::Printf(TEXT("CLIP MESH")));
}
else if (ParentNode->GetType() == mu::NodeModifierMeshClipDeform::GetStaticType())
{
mu::NodeModifierMeshClipDeform* ModifierMeshClipDeformVar = StaticCast<mu::NodeModifierMeshClipDeform*>(ParentNode);
AddChildFunc(ModifierMeshClipDeformVar->ClipMesh.get(), FString::Printf(TEXT("CLIP MESH")));
}
else if (ParentNode->GetType() == mu::NodeModifierMeshClipWithUVMask::GetStaticType())
{
mu::NodeModifierMeshClipWithUVMask* ModifierMeshClipWithUVMaskVar = StaticCast<mu::NodeModifierMeshClipWithUVMask*>(ParentNode);
AddChildFunc(ModifierMeshClipWithUVMaskVar->ClipMask.get(), FString::Printf(TEXT("CLIP MASK")));
AddChildFunc(ModifierMeshClipWithUVMaskVar->ClipLayout.get(), FString::Printf(TEXT("CLIP LAYOUT")));
}
else if (ParentNode->GetType() == mu::NodeModifierMeshTransformInMesh::GetStaticType())
{
mu::NodeModifierMeshTransformInMesh* ModifierMeshTransformInMeshVar = StaticCast<mu::NodeModifierMeshTransformInMesh*>(ParentNode);
AddChildFunc(ModifierMeshTransformInMeshVar->BoundingMesh.get(), FString::Printf(TEXT("BOUNDING MESH")));
AddChildFunc(ModifierMeshTransformInMeshVar->MatrixNode.get(), FString::Printf(TEXT("MESH TRANSFORM")));
}
else if (ParentNode->GetType() == mu::NodeImageSwitch::GetStaticType())
{
mu::NodeImageSwitch* ImageSwitchVar = StaticCast<mu::NodeImageSwitch*>(ParentNode);
AddChildFunc(ImageSwitchVar->Parameter.get(), FString::Printf(TEXT("PARAM")));
for (int32 OptionIndex = 0; OptionIndex < ImageSwitchVar->Options.Num(); OptionIndex++)
{
AddChildFunc(ImageSwitchVar->Options[OptionIndex].get(), FString::Printf(TEXT("OPTION [%d]"), OptionIndex));
}
}
else if (ParentNode->GetType() == mu::NodeImageMipmap::GetStaticType())
{
mu::NodeImageMipmap* ImageMipMapVar = StaticCast<mu::NodeImageMipmap*>(ParentNode);
AddChildFunc(ImageMipMapVar->Source.get(), FString::Printf(TEXT("SOURCE")));
AddChildFunc(ImageMipMapVar->Factor.get(), FString::Printf(TEXT("FACTOR")));
}
else if (ParentNode->GetType() == mu::NodeImageLayer::GetStaticType())
{
mu::NodeImageLayer* ImageLayerVar = StaticCast<mu::NodeImageLayer*>(ParentNode);
AddChildFunc(ImageLayerVar->Base.get(), FString::Printf(TEXT("BASE")));
AddChildFunc(ImageLayerVar->Mask.get(), FString::Printf(TEXT("MASK")));
AddChildFunc(ImageLayerVar->Blended.get(), FString::Printf(TEXT("BLEND")));
}
else if (ParentNode->GetType() == mu::NodeImageLayerColour::GetStaticType())
{
mu::NodeImageLayerColour* ImageLayerColourVar = StaticCast<mu::NodeImageLayerColour*>(ParentNode);
AddChildFunc(ImageLayerColourVar->Base.get(), FString::Printf(TEXT("BASE")));
AddChildFunc(ImageLayerColourVar->Mask.get(), FString::Printf(TEXT("MASK")));
AddChildFunc(ImageLayerColourVar->Colour.get(), FString::Printf(TEXT("COLOR")));
}
else if (ParentNode->GetType() == mu::NodeImageResize::GetStaticType())
{
mu::NodeImageResize* ImageResizeVar = StaticCast<mu::NodeImageResize*>(ParentNode);
AddChildFunc(ImageResizeVar->Base.get(), FString::Printf(TEXT("BASE")));
}
else if (ParentNode->GetType() == mu::NodeMeshMorph::GetStaticType())
{
mu::NodeMeshMorph* MeshMorphVar = StaticCast<mu::NodeMeshMorph*>(ParentNode);
AddChildFunc(MeshMorphVar->Base.get(), FString::Printf(TEXT("BASE")));
AddChildFunc(MeshMorphVar->Morph.get(), FString::Printf(TEXT("MORPH")));
AddChildFunc(MeshMorphVar->Factor.get(), FString::Printf(TEXT("FACTOR")));
}
else if (ParentNode->GetType() == mu::NodeImageProject::GetStaticType())
{
mu::NodeImageProject* ImageProjectVar = StaticCast<mu::NodeImageProject*>(ParentNode);
AddChildFunc(ImageProjectVar->Projector.get(), FString::Printf(TEXT("PROJECTOR")));
AddChildFunc(ImageProjectVar->Mesh.get(), FString::Printf(TEXT("MESH")));
AddChildFunc(ImageProjectVar->Image.get(), FString::Printf(TEXT("IMAGE")));
AddChildFunc(ImageProjectVar->Mask.get(), FString::Printf(TEXT("MASK")));
AddChildFunc(ImageProjectVar->AngleFadeStart.get(), FString::Printf(TEXT("FADE START ANGLE")));
AddChildFunc(ImageProjectVar->AngleFadeEnd.get(), FString::Printf(TEXT("FADE END ANGLE")));
}
else if (ParentNode->GetType() == mu::NodeImagePlainColour::GetStaticType())
{
mu::NodeImagePlainColour* ImagePlainColourVar = StaticCast<mu::NodeImagePlainColour*>(ParentNode);
AddChildFunc(ImagePlainColourVar->Colour.get(), FString::Printf(TEXT("COLOR")));
}
else if (ParentNode->GetType() == mu::NodeLayout::GetStaticType())
{
// Nothing to show
}
else if (ParentNode->GetType() == mu::NodeScalarEnumParameter::GetStaticType())
{
mu::NodeScalarEnumParameter* ScalarEnumParameterVar = StaticCast<mu::NodeScalarEnumParameter*>(ParentNode);
for (int32 RangeIndex = 0; RangeIndex < ScalarEnumParameterVar->Ranges.Num(); RangeIndex++)
{
AddChildFunc(ScalarEnumParameterVar->Ranges[RangeIndex].get(), FString::Printf(TEXT("RANGE [%d]"), RangeIndex));
}
}
else if (ParentNode->GetType() == mu::NodeMeshFragment::GetStaticType())
{
mu::NodeMeshFragment* MeshFragmentVar = StaticCast<mu::NodeMeshFragment*>(ParentNode);
AddChildFunc(MeshFragmentVar->SourceMesh.get(), FString::Printf(TEXT("MESH")));
}
else if (ParentNode->GetType() == mu::NodeColourSampleImage::GetStaticType())
{
mu::NodeColourSampleImage* ColorSampleImageVar = StaticCast<mu::NodeColourSampleImage*>(ParentNode);
AddChildFunc(ColorSampleImageVar->Image.get(), FString::Printf(TEXT("IMAGE")));
AddChildFunc(ColorSampleImageVar->X.get(), FString::Printf(TEXT("X")));
AddChildFunc(ColorSampleImageVar->Y.get(), FString::Printf(TEXT("Y")));
}
else if (ParentNode->GetType() == mu::NodeImageInterpolate::GetStaticType())
{
mu::NodeImageInterpolate* ImageInterpolateVar = StaticCast<mu::NodeImageInterpolate*>(ParentNode);
AddChildFunc(ImageInterpolateVar->Factor.get(), FString::Printf(TEXT("FACTOR")));
for (int32 TargetIndex = 0; TargetIndex < ImageInterpolateVar->Targets.Num(); TargetIndex++)
{
AddChildFunc(ImageInterpolateVar->Targets[TargetIndex].get(), FString::Printf(TEXT("TARGET [%d]"), TargetIndex));
}
}
else if (ParentNode->GetType() == mu::NodeScalarConstant::GetStaticType())
{
// Nothing to show
}
else if (ParentNode->GetType() == mu::NodeScalarParameter::GetStaticType())
{
mu::NodeScalarParameter* ScalarParameterVar = StaticCast<mu::NodeScalarParameter*>(ParentNode);
for (int32 RangeIndex = 0; RangeIndex < ScalarParameterVar->Ranges.Num(); RangeIndex++)
{
AddChildFunc(ScalarParameterVar->Ranges[RangeIndex].get(), FString::Printf(TEXT("RANGE [%d]"), RangeIndex));
}
}
else if (ParentNode->GetType() == mu::NodeColourParameter::GetStaticType())
{
mu::NodeColourParameter* ColorParameterVar = StaticCast<mu::NodeColourParameter*>(ParentNode);
for (int32 RangeIndex = 0; RangeIndex < ColorParameterVar->Ranges.Num(); RangeIndex++)
{
AddChildFunc(ColorParameterVar->Ranges[RangeIndex].get(), FString::Printf(TEXT("RANGE [%d]"), RangeIndex));
}
}
else if (ParentNode->GetType() == mu::NodeColourConstant::GetStaticType())
{
// Nothing to show
}
else if (ParentNode->GetType() == mu::NodeImageConstant::GetStaticType())
{
// Nothing to show
}
else if (ParentNode->GetType() == mu::NodeScalarCurve::GetStaticType())
{
mu::NodeScalarCurve* ScalarCurveVar = StaticCast<mu::NodeScalarCurve*>(ParentNode);
AddChildFunc(ScalarCurveVar->CurveSampleValue.get(), FString::Printf(TEXT("INPUT")));
}
else if (ParentNode->GetType() == mu::NodeMeshMakeMorph::GetStaticType())
{
mu::NodeMeshMakeMorph* MeshMakeMorphVar = StaticCast<mu::NodeMeshMakeMorph*>(ParentNode);
AddChildFunc(MeshMakeMorphVar->Base.get(), FString::Printf(TEXT("BASE")));
AddChildFunc(MeshMakeMorphVar->Target.get(), FString::Printf(TEXT("TARGET")));
}
else if (ParentNode->GetType() == mu::NodeProjectorParameter::GetStaticType())
{
mu::NodeProjectorParameter* ProjectorParameterVar = StaticCast<mu::NodeProjectorParameter*>(ParentNode);
for (int32 RangeIndex = 0; RangeIndex < ProjectorParameterVar->Ranges.Num(); RangeIndex++)
{
AddChildFunc(ProjectorParameterVar->Ranges[RangeIndex].get(), FString::Printf(TEXT("RANGE [%d]"), RangeIndex));
}
}
else if (ParentNode->GetType() == mu::NodeProjectorConstant::GetStaticType())
{
// Nothing to show
}
else if (ParentNode->GetType() == mu::NodeColourSwitch::GetStaticType())
{
mu::NodeColourSwitch* ColorSwitchVar = StaticCast<mu::NodeColourSwitch*>(ParentNode);
AddChildFunc(ColorSwitchVar->Parameter.get(), TEXT("PARAM"));
for (int32 OptionIndex = 0; OptionIndex < ColorSwitchVar->Options.Num(); ++OptionIndex)
{
AddChildFunc(ColorSwitchVar->Options[OptionIndex].get(), FString::Printf(TEXT("OPTION [%d]"), OptionIndex));
}
}
else if (ParentNode->GetType() == mu::NodeImageSwizzle::GetStaticType())
{
mu::NodeImageSwizzle* ImageSwizzleVar = StaticCast<mu::NodeImageSwizzle*>(ParentNode);
for (int32 SourceIndex = 0; SourceIndex < ImageSwizzleVar->Sources.Num(); ++SourceIndex)
{
AddChildFunc(ImageSwizzleVar->Sources[SourceIndex].get(), FString::Printf(TEXT("SOURCE [%d]"), SourceIndex));
}
}
else if (ParentNode->GetType() == mu::NodeImageInvert::GetStaticType())
{
mu::NodeImageInvert* ImageInvertVar = StaticCast<mu::NodeImageInvert*>(ParentNode);
AddChildFunc(ImageInvertVar->Base.get(), TEXT("BASE"));
}
else if (ParentNode->GetType() == mu::NodeImageMultiLayer::GetStaticType())
{
mu::NodeImageMultiLayer* ImageMultilayerVar = StaticCast<mu::NodeImageMultiLayer*>(ParentNode);
AddChildFunc(ImageMultilayerVar->Base.get(), FString::Printf(TEXT("BASE")));
AddChildFunc(ImageMultilayerVar->Mask.get(), FString::Printf(TEXT("MASK")));
AddChildFunc(ImageMultilayerVar->Blended.get(), FString::Printf(TEXT("BLEND")));
AddChildFunc(ImageMultilayerVar->Range.get(), FString::Printf(TEXT("RANGE")));
}
else if (ParentNode->GetType() == mu::NodeImageTable::GetStaticType())
{
// No nodes to show
}
else if (ParentNode->GetType() == mu::NodeMeshTable::GetStaticType())
{
mu::NodeMeshTable* MeshTableVar = StaticCast<mu::NodeMeshTable*>(ParentNode);
for (int32 LayoutIndex = 0; LayoutIndex < MeshTableVar->Layouts.Num(); ++LayoutIndex)
{
AddChildFunc(MeshTableVar->Layouts[LayoutIndex].get(), FString::Printf(TEXT("LAYOUT [%d]"), LayoutIndex));
}
}
else if (ParentNode->GetType() == mu::NodeScalarTable::GetStaticType())
{
// Nothing to show
}
else if (ParentNode->GetType() == mu::NodeScalarSwitch::GetStaticType())
{
mu::NodeScalarSwitch* ScalarSwitchVar = StaticCast<mu::NodeScalarSwitch*>(ParentNode);
AddChildFunc(ScalarSwitchVar->Parameter.get(), TEXT("PARAM"));
for (int32 OptionIndex = 0; OptionIndex < ScalarSwitchVar->Options.Num(); ++OptionIndex)
{
AddChildFunc(ScalarSwitchVar->Options[OptionIndex].get(), FString::Printf(TEXT("OPTION [%d]"), OptionIndex));
}
}
else if (ParentNode->GetType() == mu::NodeColourFromScalars::GetStaticType())
{
mu::NodeColourFromScalars* ScalarTableVar = StaticCast<mu::NodeColourFromScalars*>(ParentNode);
AddChildFunc(ScalarTableVar->X.get(), TEXT("X"));
AddChildFunc(ScalarTableVar->Y.get(), TEXT("Y"));
AddChildFunc(ScalarTableVar->Z.get(), TEXT("Z"));
AddChildFunc(ScalarTableVar->W.get(), TEXT("W"));
}
else
{
UE_LOG(LogMutable,Error,TEXT("The node of type %d has not been implemented, so its children won't be added to the tree."), int32(ParentNode->GetType()->Type));
// Add a placeholder to the tree
const FString Prefix = FString::Printf(TEXT("[%d] NODE TYPE NOT IMPLEMENTED"), int32(ParentNode->GetType()->Type));
AddChildFunc(nullptr, Prefix);
}
#endif
}
TSharedPtr<SWidget> SMutableGraphViewer::OnTreeContextMenuOpening()
{
FMenuBuilder MenuBuilder(true, nullptr);
MenuBuilder.AddMenuEntry(
LOCTEXT("Graph_Expand_Instance", "Expand Instance-Level Operations"),
LOCTEXT("Graph_Expand_Instance_Tooltip", "Expands all the operations in the tree that are instance operations (not images, meshes, booleans, etc.)."),
FSlateIcon(),
FUIAction(FExecuteAction::CreateSP(this, &SMutableGraphViewer::TreeExpandUnique)
//, FCanExecuteAction::CreateSP(this, &SMutableCodeViewer::HasAnyItemInPalette)
)
);
return MenuBuilder.MakeWidget();
}
void SMutableGraphViewer::TreeExpandRecursive(TSharedPtr<FMutableGraphTreeElement> InInfo, bool bExpand)
{
if (bExpand)
{
TreeExpandUnique();
}
}
void SMutableGraphViewer::TreeExpandUnique()
{
TArray<TSharedPtr<FMutableGraphTreeElement>> Pending = RootNodes;
TSet<TSharedPtr<FMutableGraphTreeElement>> Processed;
TArray<TSharedPtr<FMutableGraphTreeElement>> Children;
while (!Pending.IsEmpty())
{
TSharedPtr<FMutableGraphTreeElement> Item = Pending.Pop();
TreeView->SetItemExpansion(Item, true);
Children.SetNum(0);
GetChildrenForInfo(Item, Children);
Pending.Append(Children);
}
}
#undef LOCTEXT_NAMESPACE