// Copyright Epic Games, Inc. All Rights Reserved. #include "Graph/ControlRigGraph.h" #include "ControlRigBlueprint.h" #include "ControlRig.h" #include "RigVMModel/RigVMGraph.h" #include "Units/RigUnit.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(ControlRigGraph) #define LOCTEXT_NAMESPACE "ControlRigGraph" UControlRigGraph::UControlRigGraph() { bSuspendModelNotifications = false; bIsTemporaryGraphForCopyPaste = false; LastHierarchyTopologyVersion = INDEX_NONE; bIsFunctionDefinition = false; } void UControlRigGraph::InitializeFromBlueprint(URigVMBlueprint* InBlueprint) { DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC() Super::InitializeFromBlueprint(InBlueprint); const UControlRigBlueprint* ControlRigBlueprint = CastChecked(InBlueprint); URigHierarchy* Hierarchy = ControlRigBlueprint->Hierarchy; if(UControlRig* ControlRig = Cast(ControlRigBlueprint->GetObjectBeingDebugged())) { Hierarchy = ControlRig->GetHierarchy(); } if(Hierarchy) { CacheNameLists(Hierarchy, &ControlRigBlueprint->DrawContainer, ControlRigBlueprint->ShapeLibraries); } } #if WITH_EDITOR TArray> UControlRigGraph::EmptyElementNameList; const TArray>* UControlRigGraph::GetNameListForWidget(const FString& InWidgetName) const { if (InWidgetName == TEXT("BoneName")) { return GetBoneNameList(); } if (InWidgetName == TEXT("ControlName")) { return GetControlNameListWithoutAnimationChannels(); } if (InWidgetName == TEXT("SpaceName")) { return GetNullNameList(); } if (InWidgetName == TEXT("CurveName")) { return GetCurveNameList(); } return nullptr; } void UControlRigGraph::CacheNameLists(URigHierarchy* InHierarchy, const FRigVMDrawContainer* DrawContainer, TArray> ShapeLibraries) { if (UControlRigGraph* OuterGraph = Cast(GetOuter())) { return; } check(InHierarchy); check(DrawContainer); UControlRig* ControlRig = InHierarchy->GetTypedOuter(); if(LastHierarchyTopologyVersion != InHierarchy->GetTopologyVersion()) { ElementNameLists.FindOrAdd(ERigElementType::All); ElementNameLists.FindOrAdd(ERigElementType::Bone); ElementNameLists.FindOrAdd(ERigElementType::Null); ElementNameLists.FindOrAdd(ERigElementType::Control); ElementNameLists.FindOrAdd(ERigElementType::Curve); ElementNameLists.FindOrAdd(ERigElementType::Physics); ElementNameLists.FindOrAdd(ERigElementType::Reference); ElementNameLists.FindOrAdd(ERigElementType::Connector); ElementNameLists.FindOrAdd(ERigElementType::Socket); TArray>& AllNameList = ElementNameLists.FindChecked(ERigElementType::All); TArray>& BoneNameList = ElementNameLists.FindChecked(ERigElementType::Bone); TArray>& NullNameList = ElementNameLists.FindChecked(ERigElementType::Null); TArray>& ControlNameList = ElementNameLists.FindChecked(ERigElementType::Control); TArray>& CurveNameList = ElementNameLists.FindChecked(ERigElementType::Curve); TArray>& PhysicsNameList = ElementNameLists.FindChecked(ERigElementType::Physics); TArray>& ReferenceNameList = ElementNameLists.FindChecked(ERigElementType::Reference); TArray>& ConnectorNameList = ElementNameLists.FindChecked(ERigElementType::Connector); TArray>& SocketNameList = ElementNameLists.FindChecked(ERigElementType::Socket); CacheNameListForHierarchy(ControlRig, InHierarchy, AllNameList, false); CacheNameListForHierarchy(ControlRig, InHierarchy, BoneNameList, false); CacheNameListForHierarchy(ControlRig, InHierarchy, NullNameList, false); CacheNameListForHierarchy(ControlRig, InHierarchy, ControlNameList, false); CacheNameListForHierarchy(ControlRig, InHierarchy, ControlNameListWithoutAnimationChannels, true); CacheNameListForHierarchy(ControlRig, InHierarchy, CurveNameList, false); CacheNameListForHierarchy(ControlRig, InHierarchy, ReferenceNameList, false); CacheNameListForHierarchy(ControlRig, InHierarchy, ConnectorNameList, false); CacheNameListForHierarchy(ControlRig, InHierarchy, SocketNameList, false); LastHierarchyTopologyVersion = InHierarchy->GetTopologyVersion(); } CacheNameList(*DrawContainer, DrawingNameList); // always update the connector name list since the connector may have been re-resolved TArray>& ConnectorNameList = ElementNameLists.FindChecked(ERigElementType::Connector); CacheNameListForHierarchy(ControlRig, InHierarchy, ConnectorNameList, false); ShapeNameList.Reset(); ShapeNameList.Add(MakeShared(FName(NAME_None).ToString())); TMap LibraryNameMap; if(ControlRig) { LibraryNameMap = ControlRig->ShapeLibraryNameMap; } for(const TSoftObjectPtr& ShapeLibrary : ShapeLibraries) { if(ShapeLibrary.IsNull() || !ShapeLibrary.IsValid()) { ShapeLibrary.LoadSynchronous(); } if(ShapeLibrary.IsNull() || !ShapeLibrary.IsValid()) { continue; } const bool bUseNameSpace = ShapeLibraries.Num() > 1; FString LibraryName = ShapeLibrary->GetName(); if(const FString* RemappedName = LibraryNameMap.Find(LibraryName)) { LibraryName = *RemappedName; } const FString NameSpace = bUseNameSpace ? LibraryName + TEXT(".") : FString(); ShapeNameList.Add(MakeShared(UControlRigShapeLibrary::GetShapeName(ShapeLibrary.Get(), bUseNameSpace, LibraryNameMap, ShapeLibrary->DefaultShape))); for (const FControlRigShapeDefinition& Shape : ShapeLibrary->Shapes) { ShapeNameList.Add(MakeShared(UControlRigShapeLibrary::GetShapeName(ShapeLibrary.Get(), bUseNameSpace, LibraryNameMap, Shape))); } } } const TArray>* UControlRigGraph::GetElementNameList(ERigElementType InElementType) const { if (UControlRigGraph* OuterGraph = Cast(GetOuter())) { return OuterGraph->GetElementNameList(InElementType); } if(InElementType == ERigElementType::None) { return &EmptyElementNameList; } if(!ElementNameLists.Contains(InElementType)) { const UControlRigBlueprint* Blueprint = Cast(GetBlueprint()); if(Blueprint == nullptr) { return &EmptyElementNameList; } UControlRigGraph* MutableThis = (UControlRigGraph*)this; URigHierarchy* Hierarchy = Blueprint->Hierarchy; if(UControlRig* ControlRig = Cast(Blueprint->GetObjectBeingDebugged())) { Hierarchy = ControlRig->GetHierarchy(); } MutableThis->CacheNameLists(Hierarchy, &Blueprint->DrawContainer, Blueprint->ShapeLibraries); } return &ElementNameLists.FindChecked(InElementType); } const TArray>* UControlRigGraph::GetElementNameList(URigVMPin* InPin) const { if (InPin) { if (URigVMPin* ParentPin = InPin->GetParentPin()) { if (ParentPin->GetCPPTypeObject() == FRigElementKey::StaticStruct()) { if (URigVMPin* TypePin = ParentPin->FindSubPin(TEXT("Type"))) { FString DefaultValue = TypePin->GetDefaultValue(); if (!DefaultValue.IsEmpty()) { ERigElementType Type = (ERigElementType)StaticEnum()->GetValueByNameString(DefaultValue); return GetElementNameList(Type); } } } } } return GetBoneNameList(nullptr); } const TArray> UControlRigGraph::GetSelectedElementsNameList() const { TArray> Result; if (UControlRigGraph* OuterGraph = Cast(GetOuter())) { return OuterGraph->GetSelectedElementsNameList(); } const UControlRigBlueprint* Blueprint = CastChecked(GetBlueprint()); if(Blueprint == nullptr) { return Result; } TArray Keys = Blueprint->Hierarchy->GetSelectedKeys(); for (const FRigElementKey& Key : Keys) { FString ValueStr; FRigElementKey::StaticStruct()->ExportText(ValueStr, &Key, nullptr, nullptr, PPF_None, nullptr); Result.Add(MakeShared(ValueStr)); } return Result; } const TArray>* UControlRigGraph::GetDrawingNameList(URigVMPin* InPin) const { if (UControlRigGraph* OuterGraph = Cast(GetOuter())) { return OuterGraph->GetDrawingNameList(InPin); } return &DrawingNameList; } const TArray>* UControlRigGraph::GetShapeNameList(URigVMPin* InPin) const { if (UControlRigGraph* OuterGraph = Cast(GetOuter())) { return OuterGraph->GetShapeNameList(InPin); } return &ShapeNameList; } FReply UControlRigGraph::HandleGetSelectedClicked(URigVMEdGraph* InEdGraph, URigVMPin* InPin, FString InDefaultValue) { UControlRigBlueprint* RigVMBlueprint = CastChecked(InEdGraph->GetBlueprint()); if(InPin->GetCustomWidgetName() == TEXT("ElementName")) { if (URigVMPin* ParentPin = InPin->GetParentPin()) { InEdGraph->GetController()->SetPinDefaultValue(ParentPin->GetPinPath(), InDefaultValue, true, true, false, true); return FReply::Handled(); } } else if (InPin->GetCustomWidgetName() == TEXT("BoneName")) { URigHierarchy* Hierarchy = RigVMBlueprint->Hierarchy; TArray Keys = Hierarchy->GetSelectedKeys(); FRigBaseElement* Element = Hierarchy->FindChecked(Keys[0]); if (Element->GetType() == ERigElementType::Bone) { InEdGraph->GetController()->SetPinDefaultValue(InPin->GetPinPath(), Keys[0].Name.ToString(), true, true, false, true); return FReply::Handled(); } } // if we don't have a key pin - this is just a plain name. // let's derive the type of element this node deals with from its name. // there's nothing better in place for now. else if(const URigVMUnitNode* UnitNode = Cast(InPin->GetNode())) { const int32 LastIndex = StaticEnum()->GetIndexByName(TEXT("Last")); const FString UnitName = UnitNode->GetScriptStruct()->GetStructCPPName(); for(int32 EnumIndex = 0; EnumIndex < LastIndex; EnumIndex++) { const FString EnumDisplayName = StaticEnum()->GetDisplayNameTextByIndex(EnumIndex).ToString(); if(UnitName.Contains(EnumDisplayName)) { const ERigElementType ElementType = (ERigElementType)StaticEnum()->GetValueByIndex(EnumIndex); FRigElementKey Key; FRigElementKey::StaticStruct()->ImportText(*InDefaultValue, &Key, nullptr, EPropertyPortFlags::PPF_None, nullptr, FRigElementKey::StaticStruct()->GetName(), true); if (Key.IsValid()) { if(Key.Type == ElementType) { InEdGraph->GetController()->SetPinDefaultValue(InPin->GetPinPath(), Key.Name.ToString(), true, true, false, true); return FReply::Handled(); } } break; } } } return FReply::Unhandled(); } FReply UControlRigGraph::HandleBrowseClicked(URigVMEdGraph* InEdGraph, URigVMPin* InPin, FString InDefaultValue) { UControlRigBlueprint* RigVMBlueprint = CastChecked(InEdGraph->GetBlueprint()); URigVMPin* KeyPin = InPin->GetParentPin(); if(KeyPin && KeyPin->GetCPPTypeObject() == FRigElementKey::StaticStruct()) { // browse to rig element key FString DefaultValue = InPin->GetParentPin()->GetDefaultValue(); if (!DefaultValue.IsEmpty()) { FRigElementKey Key; FRigElementKey::StaticStruct()->ImportText(*DefaultValue, &Key, nullptr, EPropertyPortFlags::PPF_None, nullptr, FRigElementKey::StaticStruct()->GetName(), true); if (Key.IsValid()) { RigVMBlueprint->GetHierarchyController()->SetSelection({Key}); } } } else if (InPin->GetCustomWidgetName() == TEXT("BoneName")) { // browse to named bone const FString DefaultValue = InPin->GetDefaultValue(); FRigElementKey Key(*DefaultValue, ERigElementType::Bone); RigVMBlueprint->GetHierarchyController()->SetSelection({Key}); } else { // if we don't have a key pin - this is just a plain name. // let's derive the type of element this node deals with from its name. // there's nothing better in place for now. if(const URigVMUnitNode* UnitNode = Cast(InPin->GetNode())) { const int32 LastIndex = StaticEnum()->GetIndexByName(TEXT("Last")); const FString UnitName = UnitNode->GetScriptStruct()->GetStructCPPName(); for(int32 EnumIndex = 0; EnumIndex < LastIndex; EnumIndex++) { const FString EnumDisplayName = StaticEnum()->GetDisplayNameTextByIndex(EnumIndex).ToString(); if(UnitName.Contains(EnumDisplayName)) { const FString DefaultValue = InPin->GetDefaultValue(); const ERigElementType ElementType = (ERigElementType)StaticEnum()->GetValueByIndex(EnumIndex); FRigElementKey Key(*DefaultValue, ElementType); RigVMBlueprint->GetHierarchyController()->SetSelection({Key}); break; } } } } return FReply::Handled(); } #endif bool UControlRigGraph::HandleModifiedEvent_Internal(ERigVMGraphNotifType InNotifType, URigVMGraph* InGraph, UObject* InSubject) { DECLARE_SCOPE_HIERARCHICAL_COUNTER_FUNC() if(!Super::HandleModifiedEvent_Internal(InNotifType, InGraph, InSubject)) { return false; } switch (InNotifType) { case ERigVMGraphNotifType::PinDefaultValueChanged: { if (URigVMPin* ModelPin = Cast(InSubject)) { if (UControlRigGraphNode* RigNode = Cast(FindNodeForModelNodeName(ModelPin->GetNode()->GetFName()))) { if (Cast(ModelPin->GetNode())) { // if the node contains a rig element key - invalidate the node if(RigNode->GetAllPins().ContainsByPredicate([](UEdGraphPin* Pin) -> bool { return Pin->PinType.PinSubCategoryObject == FRigElementKey::StaticStruct(); })) { // we do this to enforce the refresh of the element name widgets RigNode->SynchronizeGraphPinValueWithModelPin(ModelPin); } } } } break; } default: { break; } } return true; } #undef LOCTEXT_NAMESPACE