Files
UnrealEngineUWP/Engine/Source/Developer/RigVMDeveloper/Private/RigVMModel/Nodes/RigVMTemplateNode.cpp
Helge Mathee 63e119a364 Control Rig: Further template node workflows
Implemented unresolve as well as re-resolve node on already typed pins
Added UI in contextual menu to re-type pins

#rb sara.schvartzman
#jira UE-125892
#preflight https://horde.devtools.epicgames.com/job/622f488f505788e09ffffbe4

[CL 19372564 by Helge Mathee in ue5-main branch]
2022-03-14 10:19:31 -04:00

365 lines
8.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "RigVMModel/Nodes/RigVMTemplateNode.h"
#include "RigVMModel/RigVMController.h"
URigVMTemplateNode::URigVMTemplateNode()
: Super()
, TemplateNotation(NAME_None)
, ResolvedFunctionName()
, CachedTemplate(nullptr)
, CachedFunction(nullptr)
{
}
UScriptStruct* URigVMTemplateNode::GetScriptStruct() const
{
if(const FRigVMFunction* Function = GetResolvedFunction())
{
return Function->Struct;
}
return nullptr;
}
FString URigVMTemplateNode::GetNodeTitle() const
{
if(!IsResolved())
{
if(const FRigVMTemplate* Template = GetTemplate())
{
return Template->GetName().ToString();
}
}
FString ResolvedNodeTitle = Super::GetNodeTitle();
const int32 BracePos = ResolvedNodeTitle.Find(TEXT(" ("));
if(BracePos != INDEX_NONE)
{
ResolvedNodeTitle = ResolvedNodeTitle.Left(BracePos);
}
return ResolvedNodeTitle;
}
FName URigVMTemplateNode::GetMethodName() const
{
if(const FRigVMFunction* Function = GetResolvedFunction())
{
return Function->GetMethodName();
}
return NAME_None;
}
FText URigVMTemplateNode::GetToolTipText() const
{
if(const FRigVMTemplate* Template = GetTemplate())
{
const TArray<int32> PermutationIndices = GetResolvedPermutationIndices();
return Template->GetTooltipText(PermutationIndices);
}
return Super::GetToolTipText();
}
FText URigVMTemplateNode::GetToolTipTextForPin(const URigVMPin* InPin) const
{
const FText SuperToolTip = Super::GetToolTipTextForPin(InPin);
if (const FRigVMTemplate* Template = GetTemplate())
{
const URigVMPin* RootPin = InPin->GetRootPin();
if (RootPin->IsWildCard())
{
if (const FRigVMTemplateArgument* Arg = Template->FindArgument(RootPin->GetFName()))
{
const TArray<int32> PermutationIndices = GetResolvedPermutationIndices();
const FString SupportedTypesJoined = FString::Join(Arg->GetSupportedTypeStrings(PermutationIndices), TEXT("\n"));
FString Tooltip = TEXT("Supported Types:\n\n") + SupportedTypesJoined;
if(!SuperToolTip.IsEmpty())
{
Tooltip += TEXT("\n\n") + SuperToolTip.ToString();
}
return FText::FromString(Tooltip);
}
}
}
return SuperToolTip;
}
FName URigVMTemplateNode::GetNotation() const
{
return TemplateNotation;
}
bool URigVMTemplateNode::SupportsType(const URigVMPin* InPin, const FString& InCPPType, FString* OutCPPType)
{
static const FString WildCardCPPType = RigVMTypeUtils::GetWildCardCPPType();
static const FString WildCardArrayCPPType = RigVMTypeUtils::ArrayTypeFromBaseType(WildCardCPPType);
const URigVMPin* RootPin = InPin->GetRootPin();
// we always support the unknown type
if(((InCPPType == WildCardCPPType) && !InPin->IsArray()) ||
((InCPPType == WildCardArrayCPPType) && InPin->IsArray()))
{
if(const FRigVMTemplate* Template = GetTemplate())
{
if(const FRigVMTemplateArgument* Argument = Template->FindArgument(RootPin->GetFName()))
{
// support this only on non-singleton arguments
if(Argument->IsSingleton())
{
return false;
}
if(OutCPPType)
{
*OutCPPType = InCPPType;
}
return true;
}
}
return false;
}
FString CPPType = InCPPType;
if(InPin->GetParentPin() == RootPin && RootPin->IsArray())
{
CPPType = RigVMTypeUtils::ArrayTypeFromBaseType(CPPType);
}
if (const FRigVMTemplate* Template = GetTemplate())
{
const FString CacheKey = RootPin->GetName() + TEXT("|") + CPPType;
if (const TPair<bool, FRigVMTemplateArgument::FType>* CachedResult = SupportedTypesCache.Find(CacheKey))
{
if(OutCPPType)
{
*OutCPPType = CachedResult->Value.CPPType;
}
return CachedResult->Key;
}
FRigVMTemplate::FTypeMap Types;
for (URigVMPin* Pin : GetPins())
{
if (Pin == RootPin)
{
continue;
}
if (Pin->IsWildCard())
{
continue;
}
Types.Add(Pin->GetFName(), Pin->GetTemplateArgumentType());
}
FRigVMTemplateArgument::FType ResolvedType;
bool bSupportsType = false;
if(RootPin->IsWildCard())
{
bSupportsType = Template->ArgumentSupportsType(RootPin->GetFName(), CPPType, Types, &ResolvedType);
}
else
{
FRigVMTemplate::FTypeMap ResolvedTypes;
bSupportsType = Template->ResolveArgument(RootPin->GetFName(), FRigVMTemplateArgument::FType(CPPType), ResolvedTypes);
if(bSupportsType)
{
ResolvedType = ResolvedTypes.FindChecked(RootPin->GetFName());
}
}
SupportedTypesCache.Add(CacheKey, TPair<bool, FRigVMTemplateArgument::FType>(bSupportsType, ResolvedType));
if(OutCPPType)
{
*OutCPPType = ResolvedType.CPPType;
}
return bSupportsType;
}
if(RootPin->GetCPPType() == CPPType)
{
if(OutCPPType)
{
*OutCPPType = CPPType;
}
return true;
}
return false;
}
bool URigVMTemplateNode::GetTypeMapForNewPinType(const URigVMPin* InPin, const FString& InCPPType, UObject* InCPPTypeObject,
FRigVMTemplate::FTypeMap& OutTypes) const
{
check(InPin);
check(InPin->GetNode() == this);
check(InPin->IsRootPin());
if(const FRigVMTemplate* Template = GetTemplate())
{
OutTypes = GetResolvedTypes();
const FRigVMTemplateArgument::FType ExpectedType(InCPPType, InCPPTypeObject);
return GetTemplate()->ResolveArgument(InPin->GetFName(), ExpectedType, OutTypes);
}
OutTypes.Reset();
return false;
}
TArray<int32> URigVMTemplateNode::GetResolvedPermutationIndices(FRigVMTemplate::FTypeMap* OutTypes) const
{
if (const FRigVMTemplate* Template = GetTemplate())
{
FRigVMTemplate::FTypeMap Types = GetResolvedTypes();
TArray<int32> PermutationIndices;
Template->Resolve(Types, PermutationIndices, false);
if (OutTypes)
{
*OutTypes = Types;
}
return PermutationIndices;
}
return TArray<int32>();
}
TArray<const FRigVMFunction*> URigVMTemplateNode::GetResolvedPermutations(FRigVMTemplate::FTypeMap* OutTypes) const
{
TArray<int32> Indices = GetResolvedPermutationIndices(OutTypes);
TArray<const FRigVMFunction*> Functions;
for(const int32 Index : Indices)
{
Functions.Add(GetTemplate()->GetPermutation(Index));
}
return Functions;
}
const FRigVMTemplate* URigVMTemplateNode::GetTemplate() const
{
if(CachedTemplate == nullptr)
{
CachedTemplate = FRigVMRegistry::Get().FindTemplate(TemplateNotation);
}
return CachedTemplate;
}
FRigVMTemplate::FTypeMap URigVMTemplateNode::GetResolvedTypes() const
{
FRigVMTemplate::FTypeMap Types;
for (URigVMPin* Pin : GetPins())
{
if (Pin->IsWildCard())
{
continue;
}
Types.Add(Pin->GetFName(), Pin->GetTemplateArgumentType());
}
return Types;
}
const FRigVMFunction* URigVMTemplateNode::GetResolvedFunction() const
{
if(CachedFunction == nullptr)
{
if(!ResolvedFunctionName.IsEmpty())
{
CachedFunction = FRigVMRegistry::Get().FindFunction(*ResolvedFunctionName);
}
if(CachedFunction == nullptr)
{
TArray<int32> PermutationIndices = GetResolvedPermutationIndices();
if(PermutationIndices.Num() == 1)
{
CachedFunction = GetTemplate()->GetPermutation(PermutationIndices[0]);
}
}
}
return CachedFunction;
}
bool URigVMTemplateNode::IsResolved() const
{
return GetScriptStruct() != nullptr;
}
bool URigVMTemplateNode::IsFullyUnresolved() const
{
check(GetTemplate());
// all permutations are available means we haven't resolved any wildcard pin
return GetResolvedPermutations().Num() == GetTemplate()->NumPermutations();
}
TArray<UScriptStruct*> URigVMTemplateNode::GetSupportedUnitStructs() const
{
if(const FRigVMTemplate* Template = GetTemplate())
{
return URigVMController::GetUnitStructsForTemplate(Template->GetNotation());
}
return TArray<UScriptStruct*>();
}
FString URigVMTemplateNode::GetInitialDefaultValueForPin(const FName& InRootPinName, const TArray<int32>& InPermutationIndices) const
{
if(GetTemplate() == nullptr)
{
return FString();
}
TArray<int32> PermutationIndices = InPermutationIndices;
if(PermutationIndices.IsEmpty())
{
PermutationIndices = GetResolvedPermutationIndices();
}
FString DefaultValue;
for(const int32 PermutationIndex : PermutationIndices)
{
const FRigVMFunction* Permutation = GetTemplate()->GetPermutation(PermutationIndex);
check(Permutation);
const TSharedPtr<FStructOnScope> StructOnScope = MakeShareable(new FStructOnScope(Permutation->Struct));
const FRigVMStruct* DefaultStruct = (const FRigVMStruct*)StructOnScope->GetStructMemory();
const FString NewDefaultValue = DefaultStruct->ExportToFullyQualifiedText(
Cast<UScriptStruct>(StructOnScope->GetStruct()), InRootPinName);
if(!NewDefaultValue.IsEmpty())
{
if(DefaultValue.IsEmpty())
{
DefaultValue = NewDefaultValue;
}
else if(!NewDefaultValue.Equals(DefaultValue))
{
return FString();
}
}
}
return DefaultValue;
}
void URigVMTemplateNode::InvalidateCache()
{
SupportedTypesCache.Reset();
CachedFunction = nullptr;
for(URigVMPin* Pin : GetPins())
{
if(Pin->IsWildCard())
{
ResolvedFunctionName.Reset();
break;
}
}
}