2021-07-28 17:12:57 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundFrontendInjectReceiveNodes.h"
# include "MetasoundFacade.h"
# include "MetasoundFrontendGraph.h"
# include "MetasoundFrontendRegistries.h"
2022-03-17 13:14:50 -04:00
# include "MetasoundParamHelper.h"
2021-07-28 17:12:57 -04:00
# include "MetasoundReceiveNode.h"
# include "MetasoundVertex.h"
2022-03-17 13:14:50 -04:00
# define LOCTEXT_NAMESPACE "MetasoundFrontend"
2021-07-28 17:12:57 -04:00
namespace Metasound
{
2022-03-17 13:14:50 -04:00
METASOUND_PARAM ( OutputAddress , " Address " , " Address " )
2021-07-28 17:12:57 -04:00
namespace Frontend
{
namespace MetasoundFrontendInjectReceiveNodesPrivate
{
// Metasound Operator which returns the transmission address for the injected receive node.
class FAddressOperator : public FNoOpOperator
{
public :
static TUniquePtr < IOperator > CreateOperator ( const FCreateOperatorParams & , TArray < TUniquePtr < IOperatorBuildError > > & ) ;
static const FNodeClassMetadata & GetNodeInfo ( ) ;
FAddressOperator ( TDataReadReference < FSendAddress > InAddress )
: Address ( InAddress )
{
}
virtual ~ FAddressOperator ( ) = default ;
virtual FDataReferenceCollection GetOutputs ( ) const override
{
FDataReferenceCollection Outputs ;
2022-03-17 13:14:50 -04:00
Outputs . AddDataReadReference ( METASOUND_GET_PARAM_NAME ( OutputAddress ) , Address ) ;
2021-07-28 17:12:57 -04:00
return Outputs ;
}
private :
TDataReadReference < FSendAddress > Address ;
} ;
// Metasound Node which returns the transmission address for the injected receive node.
class FAddressNode : public FNodeFacade
{
public :
2021-09-13 14:14:37 -04:00
FAddressNode ( const FGuid & InID , const FVertexName & InVertexName , const FName & InTypeName , FReceiveNodeAddressFunction InAddressFunction )
: FNodeFacade ( * FString : : Format ( TEXT ( " ReceiveAddressInject_{0} " ) , { InVertexName . ToString ( ) } ) , InID , TFacadeOperatorClass < FAddressOperator > ( ) )
, VertexKey ( InVertexName )
2021-07-28 17:12:57 -04:00
, TypeName ( InTypeName )
, AddressFunction ( InAddressFunction )
{
}
FSendAddress GetAddress ( const FMetasoundEnvironment & InEnvironment ) const
{
return AddressFunction ( InEnvironment , VertexKey , TypeName ) ;
}
private :
2021-09-13 14:14:37 -04:00
FVertexName VertexKey ;
2021-07-28 17:12:57 -04:00
FName TypeName ;
FReceiveNodeAddressFunction AddressFunction ;
} ;
TUniquePtr < IOperator > FAddressOperator : : CreateOperator ( const FCreateOperatorParams & InParams , TArray < TUniquePtr < IOperatorBuildError > > & OutBuildErrors )
{
const FAddressNode & AddressNode = static_cast < const FAddressNode & > ( InParams . Node ) ;
FSendAddress Address = AddressNode . GetAddress ( InParams . Environment ) ;
return MakeUnique < FAddressOperator > ( TDataReadReference < FSendAddress > : : CreateNew ( Address ) ) ;
}
const FNodeClassMetadata & FAddressOperator : : GetNodeInfo ( )
{
auto CreateVertexInterface = [ ] ( ) - > FVertexInterface
{
FVertexInterface Interface
{
FInputVertexInterface { } ,
FOutputVertexInterface
{
2022-03-31 16:49:59 -04:00
TOutputDataVertex < FSendAddress > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputAddress ) )
2021-07-28 17:12:57 -04:00
}
} ;
return Interface ;
} ;
auto CreateNodeClassMetadata = [ & CreateVertexInterface ] ( ) - > FNodeClassMetadata
{
FNodeClassMetadata Metadata
{
2021-08-09 15:13:40 -04:00
FNodeClassName { " MetasoundFrontendInjectReceiveNodes " , " ReceiveNodeAddress " , " " } ,
2021-07-28 17:12:57 -04:00
1 , // MajorVersion
0 , // MinorVersion
FText : : GetEmpty ( ) , // DisplayName
FText : : GetEmpty ( ) , // Description
2022-02-10 15:07:39 -05:00
FString ( ) , // Author
2021-07-28 17:12:57 -04:00
FText : : GetEmpty ( ) , // Prompt If Missing
CreateVertexInterface ( ) , // DefaultInterface
TArray < FText > ( ) , // CategoryHierachy
2021-08-09 15:13:40 -04:00
TArray < FText > ( ) , // Keywords
FNodeDisplayStyle ( ) // NodeDisplayStyle
2021-07-28 17:12:57 -04:00
} ;
return Metadata ;
} ;
static const FNodeClassMetadata Metadata = CreateNodeClassMetadata ( ) ;
return Metadata ;
}
2021-09-13 14:14:37 -04:00
TUniquePtr < INode > CreateReceiveNodeForDataType ( const FGuid & InID , const FVertexName & InVertexName , const FName & InDataType )
2021-07-28 17:12:57 -04:00
{
FNodeInitData ReceiveNodeInitData
{
2021-09-13 14:14:37 -04:00
* FString : : Format ( TEXT ( " ReceiveInject_{0} " ) , { InVertexName . ToString ( ) } ) ,
2021-07-28 17:12:57 -04:00
InID
} ;
2021-08-19 09:59:27 -04:00
return IDataTypeRegistry : : Get ( ) . CreateReceiveNode ( InDataType , ReceiveNodeInitData ) ;
2021-07-28 17:12:57 -04:00
}
}
bool InjectReceiveNode ( FFrontendGraph & InGraph , const FReceiveNodeAddressFunction & InAddressFunction , const FInputDataDestination & InputDestination )
{
using namespace MetasoundFrontendInjectReceiveNodesPrivate ;
2022-03-17 13:14:50 -04:00
using namespace ReceiveNodeInfo ;
2021-07-28 17:12:57 -04:00
// should never contain null nodes for input destination.
check ( InputDestination . Node ! = nullptr ) ;
2022-03-31 16:49:59 -04:00
const FVertexName & VertexKey = InputDestination . Vertex . VertexName ;
const FName & DataType = InputDestination . Vertex . DataTypeName ;
2021-07-28 17:12:57 -04:00
// Create a receive node.
const FGuid ReceiveNodeID = FGuid : : NewGuid ( ) ;
TSharedPtr < INode > ReceiveNode ( CreateReceiveNodeForDataType ( ReceiveNodeID , VertexKey , DataType ) . Release ( ) ) ;
if ( ! ReceiveNode . IsValid ( ) )
{
2022-05-02 12:35:54 -04:00
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to create receive node while injecting receive node for graph input [VertexName:%s, DataTypeName:%s] " ) , * VertexKey . ToString ( ) , * DataType . ToString ( ) ) ;
2021-07-28 17:12:57 -04:00
return false ;
}
// Create a node for address of receive node.
const FGuid AddressNodeID = FGuid : : NewGuid ( ) ;
TSharedPtr < INode > AddressNode = MakeShared < FAddressNode > ( AddressNodeID , VertexKey , DataType , InAddressFunction ) ;
if ( ! AddressNode . IsValid ( ) )
{
2022-05-02 12:35:54 -04:00
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to create address node while injecting receive node for graph input [VertexName:%s, DataTypeName:%s] " ) , * VertexKey . ToString ( ) , * DataType . ToString ( ) ) ;
2021-07-28 17:12:57 -04:00
return false ;
}
// Add receive node and value node to graph.
InGraph . AddNode ( ReceiveNodeID , ReceiveNode ) ;
InGraph . AddNode ( AddressNodeID , AddressNode ) ;
2021-08-02 16:14:31 -04:00
2022-03-17 13:14:50 -04:00
bool bDataEdgeAdded = InGraph . AddDataEdge ( * AddressNode , METASOUND_GET_PARAM_NAME ( OutputAddress ) , * ReceiveNode , METASOUND_GET_PARAM_NAME ( AddressInput ) ) ;
2021-08-02 16:14:31 -04:00
ensureAlways ( bDataEdgeAdded ) ;
2021-07-28 17:12:57 -04:00
auto IsEdgeConnectedToCurrentInput = [ & InputDestination ] ( const FDataEdge & InEdge )
{
2022-03-31 16:49:59 -04:00
return ( InEdge . From . Node = = InputDestination . Node ) & & ( InEdge . From . Vertex . VertexName = = InputDestination . Vertex . VertexName ) ;
2021-07-28 17:12:57 -04:00
} ;
// Cache previous connections from input node.
TArray < FDataEdge > EdgesFromInput = InGraph . GetDataEdges ( ) . FilterByPredicate ( IsEdgeConnectedToCurrentInput ) ;
// Remove existing connections from input node.
InGraph . RemoveDataEdgeByPredicate ( IsEdgeConnectedToCurrentInput ) ;
// Connect previous connections to receive node output.
2022-03-17 13:14:50 -04:00
FOutputDataSource ReceiveOutputSource { * ReceiveNode , ReceiveNode - > GetVertexInterface ( ) . GetOutputVertex ( METASOUND_GET_PARAM_NAME ( Output ) ) } ;
2021-07-28 17:12:57 -04:00
for ( const FDataEdge & Edge : EdgesFromInput )
{
FDataEdge NewEdge { ReceiveOutputSource , Edge . To } ;
InGraph . AddDataEdge ( FDataEdge { ReceiveOutputSource , Edge . To } ) ;
}
// Connect input node to receive node.
2022-03-17 13:14:50 -04:00
bDataEdgeAdded = InGraph . AddDataEdge ( * InputDestination . Node , VertexKey , * ReceiveNode , METASOUND_GET_PARAM_NAME ( DefaultDataInput ) ) ;
2021-08-02 16:14:31 -04:00
ensureAlways ( bDataEdgeAdded ) ;
2021-07-28 17:12:57 -04:00
return true ;
}
2021-11-22 15:55:50 -05:00
bool InjectReceiveNodes ( FFrontendGraph & InGraph , const FReceiveNodeAddressFunction & InAddressFunction , const TSet < FVertexName > & InInputVertexNames )
2021-07-28 17:12:57 -04:00
{
using namespace Metasound : : Frontend ;
bool bSuccess = true ;
const FInputDataDestinationCollection & InputDestinations = InGraph . GetInputDataDestinations ( ) ;
for ( const FInputDataDestinationCollection : : ElementType & Pair : InputDestinations )
{
const FInputDataDestination & InputDestination = Pair . Value ;
if ( ! ensure ( InputDestination . Node ! = nullptr ) )
{
// should never contain null nodes for input destination.
bSuccess = false ;
continue ;
}
2022-03-31 16:49:59 -04:00
const FVertexName & VertexKey = InputDestination . Vertex . VertexName ;
2021-11-22 15:55:50 -05:00
if ( InInputVertexNames . Contains ( VertexKey ) )
2021-07-28 17:12:57 -04:00
{
2021-11-22 15:55:50 -05:00
const bool bInjectionSuccess = InjectReceiveNode ( InGraph , InAddressFunction , InputDestination ) ;
bSuccess = bSuccess | | bInjectionSuccess ;
2021-07-28 17:12:57 -04:00
}
}
return bSuccess ;
}
}
}
2022-03-17 13:14:50 -04:00
# undef LOCTEXT_NAMESPACE