2022-08-12 14:22:05 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "NodeTemplates/MetasoundFrontendNodeTemplateReroute.h"
|
|
|
|
|
|
2022-08-16 16:19:43 -04:00
|
|
|
#include "Algo/AnyOf.h"
|
2022-08-12 14:22:05 -04:00
|
|
|
#include "MetasoundFrontendDataTypeRegistry.h"
|
|
|
|
|
#include "MetasoundFrontendRegistries.h"
|
2022-08-16 16:19:43 -04:00
|
|
|
#include "NodeTemplates/MetasoundFrontendDocumentTemplatePreprocessor.h"
|
2022-08-12 14:22:05 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Metasound
|
|
|
|
|
{
|
|
|
|
|
namespace Frontend
|
|
|
|
|
{
|
|
|
|
|
namespace ReroutePrivate
|
|
|
|
|
{
|
2022-08-16 16:19:43 -04:00
|
|
|
class FRerouteNodeTemplatePreprocessTransform : public FNodeTemplatePreprocessTransformBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FRerouteNodeTemplatePreprocessTransform(FMetasoundFrontendDocument& InDocument)
|
|
|
|
|
: FNodeTemplatePreprocessTransformBase(InDocument)
|
|
|
|
|
{
|
2022-08-17 13:34:02 -04:00
|
|
|
TArray<FMetasoundFrontendEdge>& Edges = Graph.Edges;
|
2022-08-16 16:19:43 -04:00
|
|
|
for (int32 i = 0; i < Edges.Num(); ++i)
|
|
|
|
|
{
|
|
|
|
|
FMetasoundFrontendEdge& Edge = Edges[i];
|
2023-03-07 17:01:52 -05:00
|
|
|
InputEdgeMap.Add(Edge.GetToVertexHandle(), &Edge);
|
|
|
|
|
OutputEdgeMap.FindOrAdd(Edge.GetFromVertexHandle()).Add(&Edge);
|
2022-08-16 16:19:43 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual ~FRerouteNodeTemplatePreprocessTransform() = default;
|
|
|
|
|
|
|
|
|
|
virtual bool Transform(FMetasoundFrontendNode& InOutNode) const override;
|
|
|
|
|
|
|
|
|
|
private:
|
2023-03-07 17:01:52 -05:00
|
|
|
mutable TMap<FMetasoundFrontendVertexHandle, FMetasoundFrontendEdge*> InputEdgeMap;
|
|
|
|
|
mutable TMap<FMetasoundFrontendVertexHandle, TArray<FMetasoundFrontendEdge*>> OutputEdgeMap;
|
2022-08-16 16:19:43 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool FRerouteNodeTemplatePreprocessTransform::Transform(FMetasoundFrontendNode& InOutNode) const
|
|
|
|
|
{
|
|
|
|
|
using namespace ReroutePrivate;
|
2023-02-27 17:59:05 -05:00
|
|
|
|
|
|
|
|
// Find the input and output edges for this node
|
2022-08-16 16:19:43 -04:00
|
|
|
const FMetasoundFrontendEdge* InputEdge = nullptr;
|
|
|
|
|
{
|
|
|
|
|
if (!ensure(InOutNode.Interface.Inputs.Num() == 1))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FMetasoundFrontendVertex& InputVertex = InOutNode.Interface.Inputs.Last();
|
2023-03-07 17:01:52 -05:00
|
|
|
FMetasoundFrontendVertexHandle InputNodeVertexHandle { InOutNode.GetID(), InputVertex.VertexID };
|
|
|
|
|
InputEdge = InputEdgeMap.FindRef(InputNodeVertexHandle);
|
2022-08-16 16:19:43 -04:00
|
|
|
|
|
|
|
|
// This can happen if the reroute node isn't provided an input, so its perfectly
|
|
|
|
|
// acceptable to just ignore this node as it ultimately provides no sourced input.
|
|
|
|
|
if (!InputEdge)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TArray<FMetasoundFrontendEdge*>* OutputEdges = nullptr;
|
2023-02-27 17:59:05 -05:00
|
|
|
const FMetasoundFrontendVertex& OutputVertex = InOutNode.Interface.Outputs.Last();
|
2023-03-07 17:01:52 -05:00
|
|
|
const FMetasoundFrontendVertexHandle OutputVertexHandle { InOutNode.GetID(), OutputVertex.VertexID };
|
2022-08-16 16:19:43 -04:00
|
|
|
{
|
|
|
|
|
if (!ensure(InOutNode.Interface.Outputs.Num() == 1))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 17:01:52 -05:00
|
|
|
OutputEdges = OutputEdgeMap.Find(OutputVertexHandle);
|
2022-08-16 16:19:43 -04:00
|
|
|
|
|
|
|
|
// This can happen if the reroute node isn't provided any outputs to connect to, so its
|
|
|
|
|
// perfectly acceptable to just ignore this node as it ultimately provides no sourced input.
|
|
|
|
|
if (!OutputEdges)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 17:59:05 -05:00
|
|
|
// Update the output edges with the input edge
|
2023-03-07 17:01:52 -05:00
|
|
|
FMetasoundFrontendVertexHandle NewOutputEdgeNodeVertexHandle { InputEdge->FromNodeID, InputEdge->FromVertexID };
|
2023-02-27 17:59:05 -05:00
|
|
|
|
2022-08-16 16:19:43 -04:00
|
|
|
for (FMetasoundFrontendEdge* OutputEdge : *OutputEdges)
|
|
|
|
|
{
|
2023-03-07 17:01:52 -05:00
|
|
|
OutputEdge->FromNodeID = NewOutputEdgeNodeVertexHandle.NodeID;
|
|
|
|
|
OutputEdge->FromVertexID = NewOutputEdgeNodeVertexHandle.VertexID;
|
2022-08-16 16:19:43 -04:00
|
|
|
}
|
|
|
|
|
|
2023-03-07 17:01:52 -05:00
|
|
|
OutputEdgeMap.FindOrAdd(NewOutputEdgeNodeVertexHandle).Append(*OutputEdges);
|
|
|
|
|
OutputEdgeMap.Remove(OutputVertexHandle);
|
2023-02-27 17:59:05 -05:00
|
|
|
|
2022-08-16 16:19:43 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
2022-08-12 14:22:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FMetasoundFrontendClassName FRerouteNodeTemplate::ClassName { "UE", "Reroute", "" };
|
|
|
|
|
|
|
|
|
|
const FMetasoundFrontendVersion FRerouteNodeTemplate::Version { ClassName.GetFullName(), { 1, 0 } };
|
|
|
|
|
|
2022-08-16 16:19:43 -04:00
|
|
|
TUniquePtr<INodeTransform> FRerouteNodeTemplate::GenerateNodeTransform(FMetasoundFrontendDocument& InPreprocessedDocument) const
|
2022-08-12 14:22:05 -04:00
|
|
|
{
|
2022-08-16 16:19:43 -04:00
|
|
|
using namespace ReroutePrivate;
|
|
|
|
|
return TUniquePtr<INodeTransform>(new FRerouteNodeTemplatePreprocessTransform(InPreprocessedDocument));
|
2022-08-12 14:22:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FMetasoundFrontendClass& FRerouteNodeTemplate::GetFrontendClass() const
|
|
|
|
|
{
|
|
|
|
|
auto CreateFrontendClass = []()
|
|
|
|
|
{
|
|
|
|
|
FMetasoundFrontendClass Class;
|
|
|
|
|
Class.Metadata.SetClassName(ClassName);
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
Class.Metadata.SetSerializeText(false);
|
|
|
|
|
Class.Metadata.SetAuthor(Metasound::PluginAuthor);
|
|
|
|
|
Class.Metadata.SetDescription(Metasound::PluginNodeMissingPrompt);
|
|
|
|
|
|
|
|
|
|
FMetasoundFrontendClassStyleDisplay& StyleDisplay = Class.Style.Display;
|
|
|
|
|
StyleDisplay.ImageName = "MetasoundEditor.Graph.Node.Class.Reroute";
|
|
|
|
|
StyleDisplay.bShowInputNames = false;
|
|
|
|
|
StyleDisplay.bShowOutputNames = false;
|
|
|
|
|
StyleDisplay.bShowLiterals = false;
|
|
|
|
|
StyleDisplay.bShowName = false;
|
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
Class.Metadata.SetType(EMetasoundFrontendClassType::Template);
|
|
|
|
|
Class.Metadata.SetVersion(Version.Number);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Class;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const FMetasoundFrontendClass FrontendClass = CreateFrontendClass();
|
|
|
|
|
return FrontendClass;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FMetasoundFrontendNodeInterface FRerouteNodeTemplate::CreateNodeInterfaceFromDataType(FName InDataType)
|
|
|
|
|
{
|
|
|
|
|
auto CreateNewVertex = [&] { return FMetasoundFrontendVertex { "Value", InDataType, FGuid::NewGuid() }; };
|
|
|
|
|
|
|
|
|
|
FMetasoundFrontendNodeInterface NewInterface;
|
|
|
|
|
NewInterface.Inputs.Add(CreateNewVertex());
|
|
|
|
|
NewInterface.Outputs.Add(CreateNewVertex());
|
|
|
|
|
|
|
|
|
|
return NewInterface;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FNodeRegistryKey& FRerouteNodeTemplate::GetRegistryKey()
|
|
|
|
|
{
|
|
|
|
|
static const FNodeRegistryKey RegistryKey = NodeRegistryKey::CreateKey(
|
|
|
|
|
EMetasoundFrontendClassType::Template,
|
|
|
|
|
ClassName.ToString(),
|
|
|
|
|
Version.Number.Major,
|
|
|
|
|
Version.Number.Minor);
|
|
|
|
|
|
|
|
|
|
return RegistryKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FMetasoundFrontendVersion& FRerouteNodeTemplate::GetVersion() const
|
|
|
|
|
{
|
|
|
|
|
return Version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
bool FRerouteNodeTemplate::HasRequiredConnections(FConstNodeHandle InNodeHandle) const
|
|
|
|
|
{
|
|
|
|
|
TArray<FConstOutputHandle> Outputs = InNodeHandle->GetConstOutputs();
|
|
|
|
|
TArray<FConstInputHandle> Inputs = InNodeHandle->GetConstInputs();
|
2022-09-13 21:51:22 -04:00
|
|
|
|
|
|
|
|
const bool bConnectedToNonRerouteOutputs = Algo::AnyOf(Outputs, [](const FConstOutputHandle& OutputHandle) { return Frontend::FindReroutedOutput(OutputHandle)->IsValid(); });
|
2022-08-12 14:22:05 -04:00
|
|
|
const bool bConnectedToNonRerouteInputs = Algo::AnyOf(Inputs, [](const FConstInputHandle& InputHandle)
|
|
|
|
|
{
|
|
|
|
|
TArray<FConstInputHandle> Inputs;
|
2022-09-13 21:51:22 -04:00
|
|
|
Frontend::FindReroutedInputs(InputHandle, Inputs);
|
2022-08-12 14:22:05 -04:00
|
|
|
return !Inputs.IsEmpty();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return bConnectedToNonRerouteOutputs || bConnectedToNonRerouteOutputs == bConnectedToNonRerouteInputs;
|
|
|
|
|
}
|
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
bool FRerouteNodeTemplate::IsValidNodeInterface(const FMetasoundFrontendNodeInterface& InNodeInterface) const
|
|
|
|
|
{
|
|
|
|
|
if (InNodeInterface.Inputs.Num() != 1)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (InNodeInterface.Outputs.Num() != 1)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FName DataType = InNodeInterface.Inputs.Last().TypeName;
|
|
|
|
|
if (DataType != InNodeInterface.Outputs.Last().TypeName)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IDataTypeRegistry::Get().IsRegistered(DataType);
|
|
|
|
|
}
|
|
|
|
|
} // namespace Frontend
|
|
|
|
|
} // namespace Metasound
|