Files
UnrealEngineUWP/Engine/Plugins/Runtime/Metasound/Source/MetasoundFrontend/Private/MetasoundFrontendInputController.cpp
aurel cordonnier a12d56ff31 Merge from Release-Engine-Staging @ 17791557 to Release-Engine-Test
This represents UE4/Main @17774255, Release-5.0 @17791557 and Dev-PerfTest @17789485

[CL 17794212 by aurel cordonnier in ue5-release-engine-test branch]
2021-10-12 21:21:22 -04:00

531 lines
15 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MetasoundFrontendInputController.h"
#include "Internationalization/Text.h"
#include "MetasoundFrontendController.h"
#include "MetasoundFrontendDocumentAccessPtr.h"
#include "MetasoundFrontendInvalidController.h"
#include "Misc/Guid.h"
#define LOCTEXT_NAMESPACE "MetasoundFrontendInputController"
namespace Metasound
{
namespace Frontend
{
//
// FBaseInputController
//
FBaseInputController::FBaseInputController(const FBaseInputController::FInitParams& InParams)
: ID(InParams.ID)
, NodeVertexPtr(InParams.NodeVertexPtr)
, ClassInputPtr(InParams.ClassInputPtr)
, GraphPtr(InParams.GraphPtr)
, OwningNode(InParams.OwningNode)
{
}
bool FBaseInputController::IsValid() const
{
return OwningNode->IsValid() && (nullptr != NodeVertexPtr.Get()) && (nullptr != GraphPtr.Get());
}
FGuid FBaseInputController::GetID() const
{
return ID;
}
const FName& FBaseInputController::GetDataType() const
{
if (const FMetasoundFrontendVertex* Vertex = NodeVertexPtr.Get())
{
return Vertex->TypeName;
}
return Invalid::GetInvalidName();
}
const FVertexName& FBaseInputController::GetName() const
{
if (const FMetasoundFrontendVertex* Vertex = NodeVertexPtr.Get())
{
return Vertex->Name;
}
return Invalid::GetInvalidName();
}
FText FBaseInputController::GetDisplayName() const
{
if (const FMetasoundFrontendClassInput* ClassInput = ClassInputPtr.Get())
{
if (!ClassInput->Metadata.DisplayName.IsEmptyOrWhitespace())
{
return ClassInput->Metadata.DisplayName;
}
return FText::FromName(GetName());
}
return Invalid::GetInvalidText();
}
const FMetasoundFrontendLiteral* FBaseInputController::GetLiteral() const
{
if (const FMetasoundFrontendVertex* Vertex = NodeVertexPtr.Get())
{
return OwningNode->GetInputLiteral(Vertex->VertexID);
}
return nullptr;
}
void FBaseInputController::SetLiteral(const FMetasoundFrontendLiteral& InLiteral)
{
if (const FMetasoundFrontendVertex* Vertex = NodeVertexPtr.Get())
{
if (const FMetasoundFrontendLiteral* ClassLiteral = GetClassDefaultLiteral())
{
// Clear if equivalent to class default as fallback is the class default
if (ClassLiteral->IsEquivalent(InLiteral))
{
OwningNode->ClearInputLiteral(Vertex->VertexID);
return;
}
}
OwningNode->SetInputLiteral(FMetasoundFrontendVertexLiteral{ Vertex->VertexID, InLiteral });
}
}
const FMetasoundFrontendLiteral* FBaseInputController::GetClassDefaultLiteral() const
{
if (const FMetasoundFrontendClassInput* ClassInput = ClassInputPtr.Get())
{
return &(ClassInput->DefaultLiteral);
}
return nullptr;
}
const FText& FBaseInputController::GetTooltip() const
{
if (const FMetasoundFrontendClassInput* ClassInput = ClassInputPtr.Get())
{
return ClassInput->Metadata.Description;
}
return Invalid::GetInvalidText();
}
const FMetasoundFrontendVertexMetadata& FBaseInputController::GetMetadata() const
{
if (const FMetasoundFrontendClassInput* ClassInput = ClassInputPtr.Get())
{
return ClassInput->Metadata;
}
return Invalid::GetInvalidVertexMetadata();
}
bool FBaseInputController::IsConnected() const
{
return (nullptr != FindEdge());
}
FGuid FBaseInputController::GetOwningNodeID() const
{
return OwningNode->GetID();
}
FNodeHandle FBaseInputController::GetOwningNode()
{
return OwningNode;
}
FConstNodeHandle FBaseInputController::GetOwningNode() const
{
return OwningNode;
}
FOutputHandle FBaseInputController::GetConnectedOutput()
{
if (const FMetasoundFrontendEdge* Edge = FindEdge())
{
// Create output handle from output node.
FGraphHandle Graph = OwningNode->GetOwningGraph();
FNodeHandle OutputNode = Graph->GetNodeWithID(Edge->FromNodeID);
return OutputNode->GetOutputWithID(Edge->FromVertexID);
}
return IOutputController::GetInvalidHandle();
}
FConstOutputHandle FBaseInputController::GetConnectedOutput() const
{
if (const FMetasoundFrontendEdge* Edge = FindEdge())
{
// Create output handle from output node.
FConstGraphHandle Graph = OwningNode->GetOwningGraph();
FConstNodeHandle OutputNode = Graph->GetNodeWithID(Edge->FromNodeID);
return OutputNode->GetOutputWithID(Edge->FromVertexID);
}
return IOutputController::GetInvalidHandle();
}
FConnectability FBaseInputController::CanConnectTo(const IOutputController& InController) const
{
FConnectability OutConnectability;
OutConnectability.Connectable = FConnectability::EConnectable::No;
const FName& DataType = GetDataType();
const FName& OtherDataType = InController.GetDataType();
if (DataType == Invalid::GetInvalidName())
{
return OutConnectability;
}
if (OtherDataType == DataType)
{
// If data types are equal, connection can happen.
OutConnectability.Connectable = FConnectability::EConnectable::Yes;
return OutConnectability;
}
// If data types are not equal, check for converter nodes which could
// convert data type.
OutConnectability.PossibleConverterNodeClasses = FRegistry::Get()->GetPossibleConverterNodes(OtherDataType, DataType);
if (OutConnectability.PossibleConverterNodeClasses.Num() > 0)
{
OutConnectability.Connectable = FConnectability::EConnectable::YesWithConverterNode;
return OutConnectability;
}
return OutConnectability;
}
bool FBaseInputController::Connect(IOutputController& InController)
{
const FName& DataType = GetDataType();
const FName& OtherDataType = InController.GetDataType();
if (DataType == Invalid::GetInvalidName())
{
return false;
}
if (FMetasoundFrontendGraph* Graph = GraphPtr.Get())
{
if (ensureAlwaysMsgf(OtherDataType == DataType, TEXT("Cannot connect incompatible types.")))
{
// Overwrite an existing connection if it exists.
FMetasoundFrontendEdge* Edge = FindEdge();
if (!Edge)
{
Edge = &Graph->Edges.AddDefaulted_GetRef();
Edge->ToNodeID = GetOwningNodeID();
Edge->ToVertexID = GetID();
}
Edge->FromNodeID = InController.GetOwningNodeID();
Edge->FromVertexID = InController.GetID();
return true;
}
}
return false;
}
bool FBaseInputController::ConnectWithConverterNode(IOutputController& InController, const FConverterNodeInfo& InConverterInfo)
{
FGraphHandle OwningGraph = OwningNode->GetOwningGraph();
// Generate the converter node.
FNodeHandle ConverterNode = OwningGraph->AddNode(InConverterInfo.NodeKey);
FInputHandle ConverterInput = ConverterNode->GetInputWithVertexName(InConverterInfo.PreferredConverterInputPin);
FOutputHandle ConverterOutput = ConverterNode->GetOutputWithVertexName(InConverterInfo.PreferredConverterOutputPin);
if (!ConverterInput->IsValid())
{
UE_LOG(LogMetaSound, Warning, TEXT("Converter node [Name: %s] does not support preferred input vertex [Vertex: %s]"), *ConverterNode->GetNodeName().ToString(), *InConverterInfo.PreferredConverterInputPin.ToString());
return false;
}
if (!ConverterOutput->IsValid())
{
UE_LOG(LogMetaSound, Warning, TEXT("Converter node [Name: %s] does not support preferred output vertex [Vertex: %s]"), *ConverterNode->GetNodeName().ToString(), *InConverterInfo.PreferredConverterOutputPin.ToString());
return false;
}
// Connect the output InController to the converter, than connect the converter to this input.
if (ConverterInput->Connect(InController) && Connect(*ConverterOutput))
{
return true;
}
return false;
}
bool FBaseInputController::Disconnect(IOutputController& InController)
{
if (FMetasoundFrontendGraph* Graph = GraphPtr.Get())
{
FGuid FromNodeID = InController.GetOwningNodeID();
FGuid FromVertexID = InController.GetID();
FGuid ToNodeID = GetOwningNodeID();
FGuid ToVertexID = GetID();
auto IsMatchingEdge = [&](const FMetasoundFrontendEdge& Edge)
{
return (Edge.FromNodeID == FromNodeID) && (Edge.FromVertexID == FromVertexID) && (Edge.ToNodeID == ToNodeID) && (Edge.ToVertexID == ToVertexID);
};
int32 NumRemoved = Graph->Edges.RemoveAllSwap(IsMatchingEdge);
return NumRemoved > 0;
}
return false;
}
bool FBaseInputController::Disconnect()
{
if (FMetasoundFrontendGraph* Graph = GraphPtr.Get())
{
const FGuid NodeID = GetOwningNodeID();
FGuid VertexID = GetID();
auto EdgeHasMatchingDestination = [&](const FMetasoundFrontendEdge& Edge)
{
return (Edge.ToNodeID == NodeID) && (Edge.ToVertexID == VertexID);
};
int32 NumRemoved = Graph->Edges.RemoveAllSwap(EdgeHasMatchingDestination);
return NumRemoved > 0;
}
return false;
}
const FMetasoundFrontendEdge* FBaseInputController::FindEdge() const
{
if (const FMetasoundFrontendGraph* Graph = GraphPtr.Get())
{
const FGuid NodeID = GetOwningNodeID();
FGuid VertexID = GetID();
auto EdgeHasMatchingDestination = [&](const FMetasoundFrontendEdge& Edge)
{
return (Edge.ToNodeID == NodeID) && (Edge.ToVertexID == VertexID);
};
return Graph->Edges.FindByPredicate(EdgeHasMatchingDestination);
}
return nullptr;
}
FMetasoundFrontendEdge* FBaseInputController::FindEdge()
{
if (FMetasoundFrontendGraph* Graph = GraphPtr.Get())
{
const FGuid NodeID = GetOwningNodeID();
FGuid VertexID = GetID();
auto EdgeHasMatchingDestination = [&](const FMetasoundFrontendEdge& Edge)
{
return (Edge.ToNodeID == NodeID) && (Edge.ToVertexID == VertexID);
};
return Graph->Edges.FindByPredicate(EdgeHasMatchingDestination);
}
return nullptr;
}
FDocumentAccess FBaseInputController::ShareAccess()
{
FDocumentAccess Access;
Access.ConstVertex = NodeVertexPtr;
Access.ConstClassInput = ClassInputPtr;
Access.Graph = GraphPtr;
Access.ConstGraph = GraphPtr;
return Access;
}
FConstDocumentAccess FBaseInputController::ShareAccess() const
{
FConstDocumentAccess Access;
Access.ConstVertex = NodeVertexPtr;
Access.ConstClassInput = ClassInputPtr;
Access.ConstGraph = GraphPtr;
return Access;
}
//
// FOutputNodeInputController
//
FOutputNodeInputController::FOutputNodeInputController(const FOutputNodeInputController::FInitParams& InParams)
: FBaseInputController({InParams.ID, InParams.NodeVertexPtr, InParams.ClassInputPtr, InParams.GraphPtr, InParams.OwningNode})
, OwningGraphClassOutputPtr(InParams.OwningGraphClassOutputPtr)
{
}
bool FOutputNodeInputController::IsValid() const
{
return FBaseInputController::IsValid() && (nullptr != OwningGraphClassOutputPtr.Get());
}
FText FOutputNodeInputController::GetDisplayName() const
{
if (const FMetasoundFrontendClassOutput* OwningOutput = OwningGraphClassOutputPtr.Get())
{
if (const FMetasoundFrontendClassInput* ClassInput = ClassInputPtr.Get())
{
// If there the ClassInput exists, combine the variable name and class input name.
// of the variable should be added to the names of the vertices.
CachedDisplayName = FText::Format(LOCTEXT("OutputNodeInputControllerFormat", "{1} {0}"), OwningOutput->Metadata.DisplayName, ClassInput->Metadata.DisplayName);
}
else
{
// If there is not ClassInput, then use the variable name.
CachedDisplayName = OwningOutput->Metadata.DisplayName;
}
}
return CachedDisplayName;
}
const FText& FOutputNodeInputController::GetTooltip() const
{
if (const FMetasoundFrontendClassOutput* OwningOutput = OwningGraphClassOutputPtr.Get())
{
return OwningOutput->Metadata.Description;
}
return Invalid::GetInvalidText();
}
const FMetasoundFrontendVertexMetadata& FOutputNodeInputController::GetMetadata() const
{
if (const FMetasoundFrontendClassOutput* OwningOutput = OwningGraphClassOutputPtr.Get())
{
return OwningOutput->Metadata;
}
return Invalid::GetInvalidVertexMetadata();
}
void FOutputNodeInputController::SetName(const FVertexName& InName)
{
if (FMetasoundFrontendVertex* Vertex = ConstCastAccessPtr<FVertexAccessPtr>(NodeVertexPtr).Get())
{
Vertex->Name = InName;
}
}
FDocumentAccess FOutputNodeInputController::ShareAccess()
{
FDocumentAccess Access = FBaseInputController::ShareAccess();
Access.ConstClassOutput = OwningGraphClassOutputPtr;
return Access;
}
FConstDocumentAccess FOutputNodeInputController::ShareAccess() const
{
FConstDocumentAccess Access = FBaseInputController::ShareAccess();
Access.ConstClassOutput = OwningGraphClassOutputPtr;
return Access;
}
//
// FInputNodeInputController
//
FInputNodeInputController::FInputNodeInputController(const FInputNodeInputController::FInitParams& InParams)
: FBaseInputController({InParams.ID, InParams.NodeVertexPtr, InParams.ClassInputPtr, InParams.GraphPtr, InParams.OwningNode})
, OwningGraphClassInputPtr(InParams.OwningGraphClassInputPtr)
{
}
bool FInputNodeInputController::IsValid() const
{
return FBaseInputController::IsValid() && (nullptr != OwningGraphClassInputPtr.Get());
}
FText FInputNodeInputController::GetDisplayName() const
{
if (const FMetasoundFrontendClassInput* OwningInput = OwningGraphClassInputPtr.Get())
{
if (!OwningInput->Metadata.DisplayName.IsEmptyOrWhitespace())
{
return OwningInput->Metadata.DisplayName;
}
return FText::FromName(GetName());
}
return Invalid::GetInvalidText();
}
const FText& FInputNodeInputController::GetTooltip() const
{
if (const FMetasoundFrontendClassInput* OwningInput = OwningGraphClassInputPtr.Get())
{
return OwningInput->Metadata.Description;
}
return Invalid::GetInvalidText();
}
const FMetasoundFrontendVertexMetadata& FInputNodeInputController::GetMetadata() const
{
if (const FMetasoundFrontendClassInput* OwningInput = OwningGraphClassInputPtr.Get())
{
return OwningInput->Metadata;
}
return Invalid::GetInvalidVertexMetadata();
}
void FInputNodeInputController::SetName(const FVertexName& InName)
{
if (FMetasoundFrontendVertex* Vertex = ConstCastAccessPtr<FVertexAccessPtr>(NodeVertexPtr).Get())
{
Vertex->Name = InName;
}
}
FConnectability FInputNodeInputController::CanConnectTo(const IOutputController& InController) const
{
static const FConnectability Connectability = {FConnectability::EConnectable::No};
return Connectability;
}
bool FInputNodeInputController::Connect(IOutputController& InController)
{
return false;
}
bool FInputNodeInputController::ConnectWithConverterNode(IOutputController& InController, const FConverterNodeInfo& InNodeClassName)
{
return false;
}
}
}
#undef LOCTEXT_NAMESPACE