// 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> { public: void Construct(const FArguments& Args, const TSharedRef& InOwnerTableView, const TSharedPtr& 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 >::ConstructInternal( STableRow::FArguments() //.Style(FAppStyle::Get(), "DetailsView.TreeView.TableRow") .ShowSelection(true) , InOwnerTableView ); } private: TSharedPtr 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(), FMultiBoxCustomization::None, TSharedPtr(), 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>) .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 SMutableGraphViewer::GenerateRowForNodeTree(TSharedPtr InTreeNode, const TSharedRef& InOwnerTable) { TSharedRef Row = SNew(SMutableGraphTreeRow, InOwnerTable, InTreeNode); return Row; } void SMutableGraphViewer::GetChildrenForInfo(TSharedPtr InInfo, TArray>& 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* CachedItem = ItemCache.Find(Key); if (CachedItem) { OutChildren.Add(*CachedItem); } else { TSharedPtr* MainItemPtr = MainItemPerNode.Find(ChildNode); TSharedPtr 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 Item = MakeShareable(new FMutableGraphTreeElement(nullptr, nullptr , Prefix)); OutChildren.Add(Item); } ++InputIndex; }; if (ParentNode->GetType() == mu::NodeObjectNew::GetStaticType()) { mu::NodeObjectNew* ObjectNew = StaticCast(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(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(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(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(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(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(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(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(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(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(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(ParentNode); AddChildFunc(ImageFormatVar->Source.get(), FString::Printf(TEXT("SOURCE IMAGE"))); } else if (ParentNode->GetType() == mu::NodeMeshFormat::GetStaticType()) { mu::NodeMeshFormat* MeshFormatVar = StaticCast(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(ParentNode); AddChildFunc(ModifierMeshClipWithMeshVar->ClipMesh.get(), FString::Printf(TEXT("CLIP MESH"))); } else if (ParentNode->GetType() == mu::NodeModifierMeshClipDeform::GetStaticType()) { mu::NodeModifierMeshClipDeform* ModifierMeshClipDeformVar = StaticCast(ParentNode); AddChildFunc(ModifierMeshClipDeformVar->ClipMesh.get(), FString::Printf(TEXT("CLIP MESH"))); } else if (ParentNode->GetType() == mu::NodeModifierMeshClipWithUVMask::GetStaticType()) { mu::NodeModifierMeshClipWithUVMask* ModifierMeshClipWithUVMaskVar = StaticCast(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(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(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(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(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(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(ParentNode); AddChildFunc(ImageResizeVar->Base.get(), FString::Printf(TEXT("BASE"))); } else if (ParentNode->GetType() == mu::NodeMeshMorph::GetStaticType()) { mu::NodeMeshMorph* MeshMorphVar = StaticCast(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(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(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(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(ParentNode); AddChildFunc(MeshFragmentVar->SourceMesh.get(), FString::Printf(TEXT("MESH"))); } else if (ParentNode->GetType() == mu::NodeColourSampleImage::GetStaticType()) { mu::NodeColourSampleImage* ColorSampleImageVar = StaticCast(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(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(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(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(ParentNode); AddChildFunc(ScalarCurveVar->CurveSampleValue.get(), FString::Printf(TEXT("INPUT"))); } else if (ParentNode->GetType() == mu::NodeMeshMakeMorph::GetStaticType()) { mu::NodeMeshMakeMorph* MeshMakeMorphVar = StaticCast(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(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(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(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(ParentNode); AddChildFunc(ImageInvertVar->Base.get(), TEXT("BASE")); } else if (ParentNode->GetType() == mu::NodeImageMultiLayer::GetStaticType()) { mu::NodeImageMultiLayer* ImageMultilayerVar = StaticCast(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(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(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(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 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 InInfo, bool bExpand) { if (bExpand) { TreeExpandUnique(); } } void SMutableGraphViewer::TreeExpandUnique() { TArray> Pending = RootNodes; TSet> Processed; TArray> Children; while (!Pending.IsEmpty()) { TSharedPtr Item = Pending.Pop(); TreeView->SetItemExpansion(Item, true); Children.SetNum(0); GetChildrenForInfo(Item, Children); Pending.Append(Children); } } #undef LOCTEXT_NAMESPACE