2021-10-12 21:21:22 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundFrontendGraphController.h"
# include "Algo/NoneOf.h"
# include "Internationalization/Text.h"
# include "MetasoundFrontendDocument.h"
# include "MetasoundFrontendDocumentAccessPtr.h"
# include "MetasoundFrontendGraph.h"
# include "MetasoundFrontendNodeController.h"
2022-08-10 14:18:10 -04:00
# include "MetasoundFrontendNodeTemplateRegistry.h"
2021-10-12 21:21:22 -04:00
# include "MetasoundFrontendSubgraphNodeController.h"
# include "MetasoundFrontendInvalidController.h"
# include "MetasoundFrontendVariableController.h"
# include "MetasoundOperatorBuilder.h"
# include "MetasoundVariableNodes.h"
# include "Misc/Guid.h"
# include "Templates/SharedPointer.h"
# define LOCTEXT_NAMESPACE "MetasoundFrontendGraphController"
namespace Metasound
{
namespace Frontend
{
//
// FGraphController
//
FGraphController : : FGraphController ( EPrivateToken InToken , const FGraphController : : FInitParams & InParams )
: GraphClassPtr ( InParams . GraphClassPtr )
, OwningDocument ( InParams . OwningDocument )
{
}
FGraphHandle FGraphController : : CreateGraphHandle ( const FGraphController : : FInitParams & InParams )
{
if ( FMetasoundFrontendGraphClass * GraphClass = InParams . GraphClassPtr . Get ( ) )
{
if ( GraphClass - > Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Graph )
{
return MakeShared < FGraphController > ( EPrivateToken : : Token , InParams ) ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to make graph controller [ClassID:%s]. Class must be EMeatsoundFrontendClassType::Graph. " ) , * GraphClass - > ID . ToString ( ) )
}
}
return IGraphController : : GetInvalidHandle ( ) ;
}
FConstGraphHandle FGraphController : : CreateConstGraphHandle ( const FGraphController : : FInitParams & InParams )
{
if ( const FMetasoundFrontendGraphClass * GraphClass = InParams . GraphClassPtr . Get ( ) )
{
if ( GraphClass - > Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Graph )
{
return MakeShared < FGraphController > ( EPrivateToken : : Token , InParams ) ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to make graph controller [ClassID:%s]. Class must be EMeatsoundFrontendClassType::Graph. " ) , * GraphClass - > ID . ToString ( ) )
}
}
return IGraphController : : GetInvalidHandle ( ) ;
}
bool FGraphController : : IsValid ( ) const
{
return ( nullptr ! = GraphClassPtr . Get ( ) ) & & OwningDocument - > IsValid ( ) ;
}
FGuid FGraphController : : GetClassID ( ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > ID ;
}
return Metasound : : FrontendInvalidID ;
}
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-10-12 21:21:22 -04:00
FText FGraphController : : GetDisplayName ( ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Metadata . GetDisplayName ( ) ;
}
return Invalid : : GetInvalidText ( ) ;
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
TArray < FVertexName > FGraphController : : GetInputVertexNames ( ) const
{
TArray < FVertexName > Names ;
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendClassInput & Input : GraphClass - > Interface . Inputs )
{
Names . Add ( Input . Name ) ;
}
}
return Names ;
}
TArray < FVertexName > FGraphController : : GetOutputVertexNames ( ) const
{
TArray < FVertexName > Names ;
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendClassOutput & Output : GraphClass - > Interface . Outputs )
{
Names . Add ( Output . Name ) ;
}
}
return Names ;
}
FConstClassInputAccessPtr FGraphController : : FindClassInputWithName ( const FVertexName & InName ) const
{
return GraphClassPtr . GetInputWithName ( InName ) ;
}
FConstClassOutputAccessPtr FGraphController : : FindClassOutputWithName ( const FVertexName & InName ) const
{
return GraphClassPtr . GetOutputWithName ( InName ) ;
}
FGuid FGraphController : : GetVertexIDForInputVertex ( const FVertexName & InInputName ) const
{
if ( const FMetasoundFrontendClassInput * Input = FindClassInputWithName ( InInputName ) . Get ( ) )
{
return Input - > VertexID ;
}
return Metasound : : FrontendInvalidID ;
}
FGuid FGraphController : : GetVertexIDForOutputVertex ( const FVertexName & InOutputName ) const
{
if ( const FMetasoundFrontendClassOutput * Output = FindClassOutputWithName ( InOutputName ) . Get ( ) )
{
return Output - > VertexID ;
}
return Metasound : : FrontendInvalidID ;
}
TArray < FNodeHandle > FGraphController : : GetNodes ( )
{
return GetNodeHandles ( GetNodesAndClasses ( ) ) ;
}
TArray < FConstNodeHandle > FGraphController : : GetConstNodes ( ) const
{
return GetNodeHandles ( GetNodesAndClasses ( ) ) ;
}
FConstNodeHandle FGraphController : : GetNodeWithID ( FGuid InNodeID ) const
{
auto IsNodeWithSameID = [ & ] ( const FMetasoundFrontendClass & NodeClas , const FMetasoundFrontendNode & Node )
{
return Node . GetID ( ) = = InNodeID ;
} ;
return GetNodeByPredicate ( IsNodeWithSameID ) ;
}
FNodeHandle FGraphController : : GetNodeWithID ( FGuid InNodeID )
{
auto IsNodeWithSameID = [ & ] ( const FMetasoundFrontendClass & NodeClas , const FMetasoundFrontendNode & Node )
{
return Node . GetID ( ) = = InNodeID ;
} ;
return GetNodeByPredicate ( IsNodeWithSameID ) ;
}
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-10-12 21:21:22 -04:00
const FMetasoundFrontendGraphStyle & FGraphController : : GetGraphStyle ( ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Graph . Style ;
}
return Invalid : : GetInvalidGraphStyle ( ) ;
}
2022-03-02 22:11:18 -05:00
const FMetasoundFrontendInterfaceStyle & FGraphController : : GetInputStyle ( ) const
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Interface . GetInputStyle ( ) ;
}
return Invalid : : GetInvalidInterfaceStyle ( ) ;
}
const FMetasoundFrontendInterfaceStyle & FGraphController : : GetOutputStyle ( ) const
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Interface . GetOutputStyle ( ) ;
}
return Invalid : : GetInvalidInterfaceStyle ( ) ;
}
2021-10-12 21:21:22 -04:00
void FGraphController : : SetGraphStyle ( const FMetasoundFrontendGraphStyle & InStyle )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
GraphClass - > Graph . Style = InStyle ;
}
}
2022-03-01 16:31:55 -05:00
void FGraphController : : SetInputStyle ( const FMetasoundFrontendInterfaceStyle & InStyle )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
2022-03-02 22:11:18 -05:00
FMetasoundFrontendInterfaceStyle Style = InStyle ;
TArray < FMetasoundFrontendClassInput > & Inputs = GraphClass - > Interface . Inputs ;
Style . DefaultSortOrder . SetNumZeroed ( Inputs . Num ( ) ) ;
for ( int32 i = 0 ; i < Inputs . Num ( ) ; + + i )
{
Inputs [ i ] . Metadata . SortOrderIndex = InStyle . DefaultSortOrder [ i ] ;
}
GraphClass - > Interface . SetInputStyle ( Style ) ;
2022-03-01 16:31:55 -05:00
}
}
void FGraphController : : SetOutputStyle ( const FMetasoundFrontendInterfaceStyle & InStyle )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
2022-03-02 22:11:18 -05:00
FMetasoundFrontendInterfaceStyle Style = InStyle ;
TArray < FMetasoundFrontendClassOutput > & Outputs = GraphClass - > Interface . Outputs ;
Style . DefaultSortOrder . SetNumZeroed ( Outputs . Num ( ) ) ;
for ( int32 i = 0 ; i < Outputs . Num ( ) ; + + i )
{
Outputs [ i ] . Metadata . SortOrderIndex = InStyle . DefaultSortOrder [ i ] ;
}
GraphClass - > Interface . SetOutputStyle ( Style ) ;
2022-03-01 16:31:55 -05:00
}
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
TArray < FNodeHandle > FGraphController : : GetOutputNodes ( )
{
auto IsOutputNode = [ ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Output ;
} ;
return GetNodesByPredicate ( IsOutputNode ) ;
}
TArray < FNodeHandle > FGraphController : : GetInputNodes ( )
{
auto IsInputNode = [ ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Input ;
} ;
return GetNodesByPredicate ( IsInputNode ) ;
}
FVariableHandle FGraphController : : AddVariable ( const FName & InDataType )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
const IDataTypeRegistry & Registry = IDataTypeRegistry : : Get ( ) ;
FDataTypeRegistryInfo Info ;
if ( ensure ( Registry . GetDataTypeInfo ( InDataType , Info ) ) )
{
FGuid VariableID = FGuid : : NewGuid ( ) ;
FMetasoundFrontendVariable Variable ;
2022-05-02 12:35:54 -04:00
# if WITH_EDITORONLY_DATA
2021-10-12 21:21:22 -04:00
Variable . DisplayName = Info . DataTypeDisplayText ;
2022-05-02 12:35:54 -04:00
# endif // WITH_EDITORONLY_DATA
2021-10-12 21:21:22 -04:00
Variable . TypeName = Info . DataTypeName ;
Variable . Literal . SetFromLiteral ( Registry . CreateDefaultLiteral ( InDataType ) ) ;
Variable . ID = VariableID ;
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddMemberIDModified ( Variable . ID ) ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
FMetasoundFrontendClass VariableNodeClass ;
if ( IDataTypeRegistry : : Get ( ) . GetFrontendVariableClass ( Variable . TypeName , VariableNodeClass ) )
{
FNodeHandle InitNode = AddNode ( VariableNodeClass . Metadata , FGuid : : NewGuid ( ) ) ;
if ( InitNode - > IsValid ( ) )
{
Variable . VariableNodeID = InitNode - > GetID ( ) ;
GraphClass - > Graph . Variables . Add ( MoveTemp ( Variable ) ) ;
}
}
return FindVariable ( VariableID ) ;
}
}
return IVariableController : : GetInvalidHandle ( ) ;
}
FVariableHandle FGraphController : : FindVariable ( const FGuid & InVariableID )
{
FVariableAccessPtr VariablePtr = GraphClassPtr . GetVariableWithID ( InVariableID ) ;
return MakeShared < FVariableController > ( FVariableController : : FInitParams { VariablePtr , this - > AsShared ( ) } ) ;
}
FConstVariableHandle FGraphController : : FindVariable ( const FGuid & InVariableID ) const
{
FConstVariableAccessPtr ConstVariablePtr = GraphClassPtr . GetVariableWithID ( InVariableID ) ;
return MakeShared < FVariableController > ( FVariableController : : FInitParams { ConstCastAccessPtr < FVariableAccessPtr > ( ConstVariablePtr ) , ConstCastSharedRef < IGraphController > ( this - > AsShared ( ) ) } ) ;
}
2021-11-18 14:37:34 -05:00
FVariableHandle FGraphController : : FindVariableContainingNode ( const FGuid & InNodeID )
{
FGuid VariableID = FindVariableIDOfVariableContainingNode ( InNodeID ) ;
if ( VariableID . IsValid ( ) )
{
return FindVariable ( VariableID ) ;
}
return IVariableController : : GetInvalidHandle ( ) ;
}
FConstVariableHandle FGraphController : : FindVariableContainingNode ( const FGuid & InNodeID ) const
{
FGuid VariableID = FindVariableIDOfVariableContainingNode ( InNodeID ) ;
if ( VariableID . IsValid ( ) )
{
return FindVariable ( VariableID ) ;
}
return IVariableController : : GetInvalidHandle ( ) ;
}
2021-10-12 21:21:22 -04:00
bool FGraphController : : RemoveVariable ( const FGuid & InVariableID )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
if ( FMetasoundFrontendVariable * Variable = FindFrontendVariable ( InVariableID ) )
{
FNodeHandle NodeHandle = GetNodeWithID ( Variable - > VariableNodeID ) ;
RemoveNode ( * NodeHandle ) ;
NodeHandle = GetNodeWithID ( Variable - > MutatorNodeID ) ;
RemoveNode ( * NodeHandle ) ;
2021-11-18 14:37:34 -05:00
// Copy ids as node removal will update variable node IDs
TArray < FGuid > AccessorNodeIDs = Variable - > AccessorNodeIDs ;
for ( const FGuid & NodeID : AccessorNodeIDs )
2021-10-12 21:21:22 -04:00
{
NodeHandle = GetNodeWithID ( NodeID ) ;
RemoveNode ( * NodeHandle ) ;
}
2021-11-18 14:37:34 -05:00
// Copy ids as node removal will update variable node IDs
TArray < FGuid > DeferredAccessorNodeIDs = Variable - > DeferredAccessorNodeIDs ;
for ( const FGuid & NodeID : DeferredAccessorNodeIDs )
2021-10-12 21:21:22 -04:00
{
NodeHandle = GetNodeWithID ( NodeID ) ;
RemoveNode ( * NodeHandle ) ;
}
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddMemberIDModified ( InVariableID ) ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
auto IsVariableWithID = [ & ] ( const FMetasoundFrontendVariable & InVariable )
{
return InVariable . ID = = InVariableID ;
} ;
GraphClass - > Graph . Variables . RemoveAllSwap ( IsVariableWithID ) ;
return true ;
}
}
return false ;
}
TArray < FVariableHandle > FGraphController : : GetVariables ( )
{
TArray < FVariableHandle > VariableHandles ;
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendVariable & Variable : GraphClass - > Graph . Variables )
{
VariableHandles . Add ( FindVariable ( Variable . ID ) ) ;
}
}
return VariableHandles ;
}
TArray < FConstVariableHandle > FGraphController : : GetVariables ( ) const
{
TArray < FConstVariableHandle > VariableHandles ;
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendVariable & Variable : GraphClass - > Graph . Variables )
{
VariableHandles . Add ( FindVariable ( Variable . ID ) ) ;
}
}
return VariableHandles ;
}
FNodeHandle FGraphController : : FindOrAddVariableMutatorNode ( const FGuid & InVariableID )
{
2022-03-17 13:14:50 -04:00
using namespace VariableNames ;
2021-10-12 21:21:22 -04:00
if ( FMetasoundFrontendVariable * Variable = FindFrontendVariable ( InVariableID ) )
{
FNodeHandle SetNode = GetNodeWithID ( Variable - > MutatorNodeID ) ;
if ( ! SetNode - > IsValid ( ) )
{
FMetasoundFrontendClass SetNodeClass ;
2021-11-18 14:37:34 -05:00
if ( IDataTypeRegistry : : Get ( ) . GetFrontendVariableMutatorClass ( Variable - > TypeName , SetNodeClass ) )
2021-10-12 21:21:22 -04:00
{
SetNode = AddNode ( SetNodeClass . Metadata , FGuid : : NewGuid ( ) ) ;
if ( SetNode - > IsValid ( ) )
{
2021-12-13 18:15:01 -05:00
// Initialize set default literal value to that of the variable
2022-03-17 13:14:50 -04:00
FInputHandle InputHandle = SetNode - > GetInputWithVertexName ( METASOUND_GET_PARAM_NAME ( InputData ) ) ;
2021-12-13 18:15:01 -05:00
if ( ensure ( InputHandle - > IsValid ( ) ) )
{
InputHandle - > SetLiteral ( Variable - > Literal ) ;
}
2021-10-12 21:21:22 -04:00
Variable - > MutatorNodeID = SetNode - > GetID ( ) ;
FGuid SourceVariableNodeID = Variable - > VariableNodeID ;
// Connect last delayed getter in variable stack.
if ( Variable - > DeferredAccessorNodeIDs . Num ( ) > 0 )
{
SourceVariableNodeID = Variable - > DeferredAccessorNodeIDs . Last ( ) ;
}
FNodeHandle SourceVariableNode = GetNodeWithID ( SourceVariableNodeID ) ;
if ( ensure ( SourceVariableNode - > IsValid ( ) ) )
{
2022-03-17 13:14:50 -04:00
FInputHandle SetNodeInput = SetNode - > GetInputWithVertexName ( METASOUND_GET_PARAM_NAME ( InputVariable ) ) ;
FOutputHandle SourceVariableNodeOutput = SourceVariableNode - > GetOutputWithVertexName ( METASOUND_GET_PARAM_NAME ( OutputVariable ) ) ;
2021-10-12 21:21:22 -04:00
ensure ( SetNodeInput - > Connect ( * SourceVariableNodeOutput ) ) ;
}
// Connect to first inline getter in variable stack
if ( Variable - > AccessorNodeIDs . Num ( ) > 0 )
{
FNodeHandle HeadGetNode = GetNodeWithID ( Variable - > AccessorNodeIDs [ 0 ] ) ;
if ( HeadGetNode - > IsValid ( ) )
{
2022-03-17 13:14:50 -04:00
FOutputHandle SetNodeOutput = SetNode - > GetOutputWithVertexName ( METASOUND_GET_PARAM_NAME ( OutputVariable ) ) ;
FInputHandle GetNodeInput = HeadGetNode - > GetInputWithVertexName ( METASOUND_GET_PARAM_NAME ( InputVariable ) ) ;
2021-10-12 21:21:22 -04:00
ensure ( SetNodeOutput - > Connect ( * GetNodeInput ) ) ;
}
}
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Could not find registered \" set variable \" node class for data type \" %s \" " ) , * Variable - > TypeName . ToString ( ) ) ;
}
}
return SetNode ;
}
return INodeController : : GetInvalidHandle ( ) ;
}
FNodeHandle FGraphController : : AddVariableAccessorNode ( const FGuid & InVariableID )
{
2022-03-17 13:14:50 -04:00
using namespace VariableNames ;
2021-10-12 21:21:22 -04:00
if ( FMetasoundFrontendVariable * Variable = FindFrontendVariable ( InVariableID ) )
{
FMetasoundFrontendClass NodeClass ;
2021-11-18 14:37:34 -05:00
if ( IDataTypeRegistry : : Get ( ) . GetFrontendVariableAccessorClass ( Variable - > TypeName , NodeClass ) )
2021-10-12 21:21:22 -04:00
{
FNodeHandle NewNode = AddNode ( NodeClass . Metadata , FGuid : : NewGuid ( ) ) ;
if ( NewNode - > IsValid ( ) )
{
// Connect new node.
2022-03-17 13:14:50 -04:00
FInputHandle NewInput = NewNode - > GetInputWithVertexName ( METASOUND_GET_PARAM_NAME ( InputVariable ) ) ;
2021-10-12 21:21:22 -04:00
FNodeHandle TailNode = FindTailNodeInVariableStack ( InVariableID ) ;
2021-11-07 23:43:01 -05:00
if ( ! TailNode - > IsValid ( ) )
{
// variable stack is empty. Use connect to varialbe init node.
TailNode = GetNodeWithID ( Variable - > VariableNodeID ) ;
}
2021-10-12 21:21:22 -04:00
2021-11-07 23:43:01 -05:00
if ( ensure ( TailNode - > IsValid ( ) ) )
2021-10-12 21:21:22 -04:00
{
// connect new node to the last "get" node.
2022-03-17 13:14:50 -04:00
FOutputHandle TailNodeOutput = TailNode - > GetOutputWithVertexName ( METASOUND_GET_PARAM_NAME ( OutputVariable ) ) ;
2021-10-12 21:21:22 -04:00
check ( ! TailNodeOutput - > IsConnected ( ) ) ;
const bool bSuccess = TailNodeOutput - > Connect ( * NewInput ) ;
check ( bSuccess ) ;
}
// Add node ID to variable after connecting since the array
// order of node ids is used to determine whether a node
// is the tail node.
Variable - > AccessorNodeIDs . Add ( NewNode - > GetID ( ) ) ;
}
return NewNode ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Could not find registered \" get variable \" node class for data type \" %s \" " ) , * Variable - > TypeName . ToString ( ) ) ;
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
FNodeHandle FGraphController : : AddVariableDeferredAccessorNode ( const FGuid & InVariableID )
{
2022-03-17 13:14:50 -04:00
using namespace VariableNames ;
2021-10-12 21:21:22 -04:00
if ( FMetasoundFrontendVariable * Variable = FindFrontendVariable ( InVariableID ) )
{
FMetasoundFrontendClass NodeClass ;
2021-11-18 14:37:34 -05:00
if ( IDataTypeRegistry : : Get ( ) . GetFrontendVariableDeferredAccessorClass ( Variable - > TypeName , NodeClass ) )
2021-10-12 21:21:22 -04:00
{
FNodeHandle NewNode = AddNode ( NodeClass . Metadata , FGuid : : NewGuid ( ) ) ;
if ( NewNode - > IsValid ( ) )
{
// Connect new node.
2022-03-17 13:14:50 -04:00
FOutputHandle NewNodeOutput = NewNode - > GetOutputWithVertexName ( METASOUND_GET_PARAM_NAME ( OutputVariable ) ) ;
2021-10-12 21:21:22 -04:00
FNodeHandle HeadNode = FindHeadNodeInVariableStack ( InVariableID ) ;
if ( HeadNode - > IsValid ( ) )
{
2022-03-17 13:14:50 -04:00
FInputHandle HeadNodeInput = HeadNode - > GetInputWithVertexName ( METASOUND_GET_PARAM_NAME ( InputVariable ) ) ;
2021-10-12 21:21:22 -04:00
const bool bSuccess = HeadNodeInput - > Connect ( * NewNodeOutput ) ;
check ( bSuccess ) ;
}
2022-03-17 13:14:50 -04:00
FInputHandle NewNodeInput = NewNode - > GetInputWithVertexName ( METASOUND_GET_PARAM_NAME ( InputVariable ) ) ;
2021-10-12 21:21:22 -04:00
FNodeHandle VariableNode = GetNodeWithID ( Variable - > VariableNodeID ) ;
if ( ensure ( VariableNode - > IsValid ( ) ) )
{
2022-03-17 13:14:50 -04:00
FOutputHandle VariableNodeOutput = VariableNode - > GetOutputWithVertexName ( METASOUND_GET_PARAM_NAME ( OutputVariable ) ) ;
2021-10-12 21:21:22 -04:00
const bool bSuccess = VariableNodeOutput - > Connect ( * NewNodeInput ) ;
check ( bSuccess ) ;
}
// Add node ID to variable after connecting since the array
// order of node ids is used to determine whether a node
// is the tail node.
Variable - > DeferredAccessorNodeIDs . Add ( NewNode - > GetID ( ) ) ;
}
return NewNode ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Could not find registered \" get variable \" node class for data type \" %s \" " ) , * Variable - > TypeName . ToString ( ) ) ;
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
FMetasoundFrontendVariable * FGraphController : : FindFrontendVariable ( const FGuid & InVariableID )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsVariableWithID = [ & ] ( const FMetasoundFrontendVariable & InVariable )
{
return InVariable . ID = = InVariableID ;
} ;
return GraphClass - > Graph . Variables . FindByPredicate ( IsVariableWithID ) ;
}
return nullptr ;
}
const FMetasoundFrontendVariable * FGraphController : : FindFrontendVariable ( const FGuid & InVariableID ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsVariableWithID = [ & ] ( const FMetasoundFrontendVariable & InVariable )
{
return InVariable . ID = = InVariableID ;
} ;
return GraphClass - > Graph . Variables . FindByPredicate ( IsVariableWithID ) ;
}
return nullptr ;
}
2021-11-18 14:37:34 -05:00
FGuid FGraphController : : FindVariableIDOfVariableContainingNode ( const FGuid & InNodeID ) const
{
if ( InNodeID . IsValid ( ) )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto ContainsNodeWithID = [ & InNodeID ] ( const FMetasoundFrontendVariable & InVariable )
{
return ( InNodeID = = InVariable . VariableNodeID ) | | ( InNodeID = = InVariable . MutatorNodeID ) | | InVariable . AccessorNodeIDs . Contains ( InNodeID ) | | InVariable . DeferredAccessorNodeIDs . Contains ( InNodeID ) ;
} ;
if ( const FMetasoundFrontendVariable * Variable = GraphClass - > Graph . Variables . FindByPredicate ( ContainsNodeWithID ) )
{
return Variable - > ID ;
}
}
}
return FGuid ( ) ;
}
2021-10-12 21:21:22 -04:00
FNodeHandle FGraphController : : FindHeadNodeInVariableStack ( const FGuid & InVariableID )
{
// The variable "stack" is [GetDelayedNodes, SetNode, GetNodes].
if ( FMetasoundFrontendVariable * Variable = FindFrontendVariable ( InVariableID ) )
{
if ( Variable - > DeferredAccessorNodeIDs . Num ( ) > 0 )
{
return GetNodeWithID ( Variable - > DeferredAccessorNodeIDs [ 0 ] ) ;
}
if ( FrontendInvalidID ! = Variable - > MutatorNodeID )
{
return GetNodeWithID ( Variable - > MutatorNodeID ) ;
}
if ( Variable - > AccessorNodeIDs . Num ( ) > 0 )
{
return GetNodeWithID ( Variable - > AccessorNodeIDs [ 0 ] ) ;
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
FNodeHandle FGraphController : : FindTailNodeInVariableStack ( const FGuid & InVariableID )
{
// The variable "stack" is [GetDelayedNodes, SetNode, GetNodes].
if ( FMetasoundFrontendVariable * Variable = FindFrontendVariable ( InVariableID ) )
{
if ( Variable - > AccessorNodeIDs . Num ( ) > 0 )
{
return GetNodeWithID ( Variable - > AccessorNodeIDs . Last ( ) ) ;
}
if ( FrontendInvalidID ! = Variable - > MutatorNodeID )
{
return GetNodeWithID ( Variable - > MutatorNodeID ) ;
}
if ( Variable - > DeferredAccessorNodeIDs . Num ( ) > 0 )
{
return GetNodeWithID ( Variable - > DeferredAccessorNodeIDs . Last ( ) ) ;
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
2021-11-18 14:37:34 -05:00
void FGraphController : : RemoveNodeIDFromAssociatedVariable ( const INodeController & InNode )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
const FGuid NodeID = InNode . GetID ( ) ;
for ( FMetasoundFrontendVariable & Variable : GraphClass - > Graph . Variables )
{
if ( NodeID = = Variable . VariableNodeID )
{
Variable . VariableNodeID = FGuid ( ) ;
break ;
}
if ( NodeID = = Variable . MutatorNodeID )
{
Variable . MutatorNodeID = FGuid ( ) ;
}
if ( Variable . AccessorNodeIDs . Remove ( NodeID ) > 0 )
{
break ;
}
if ( Variable . DeferredAccessorNodeIDs . Remove ( NodeID ) > 0 )
{
break ;
}
}
}
}
2021-10-12 21:21:22 -04:00
void FGraphController : : SpliceVariableNodeFromVariableStack ( INodeController & InNode )
{
// Variable nodes are organized in a stack to ensure that variables are
// accessed in a consistent manner at runtime. A single variable object is
// shared amongst all nodes associated with a single variable. The variable
// object is shared by daisy-chaining the variable from one node to the
// next.
//
// If a node is removed, that daisy-chain must be preserved. This function
// removes a node while maintaining the daisy-chain.
check ( InNode . IsValid ( ) ) ;
2022-03-17 13:14:50 -04:00
using namespace VariableNames ;
FInputHandle InputToSpliceOut = InNode . GetInputWithVertexName ( METASOUND_GET_PARAM_NAME ( InputVariable ) ) ;
2021-10-12 21:21:22 -04:00
FOutputHandle OutputToReroute = InputToSpliceOut - > GetConnectedOutput ( ) ;
if ( OutputToReroute - > IsValid ( ) )
{
2022-03-17 13:14:50 -04:00
FOutputHandle OutputToSpliceOut = InNode . GetOutputWithVertexName ( METASOUND_GET_PARAM_NAME ( OutputVariable ) ) ;
2021-10-12 21:21:22 -04:00
for ( const FInputHandle & InputToReroute : OutputToSpliceOut - > GetConnectedInputs ( ) )
{
ensure ( InputToReroute - > Connect ( * OutputToReroute ) ) ;
}
}
}
void FGraphController : : ClearGraph ( )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
GraphClass - > Graph . Nodes . Reset ( ) ;
GraphClass - > Graph . Edges . Reset ( ) ;
GraphClass - > Interface . Inputs . Reset ( ) ;
GraphClass - > Interface . Outputs . Reset ( ) ;
2022-02-09 12:52:07 -05:00
GraphClass - > PresetOptions . InputsInheritingDefault . Reset ( ) ;
2021-11-22 15:55:50 -05:00
OwningDocument - > ClearInterfaceVersions ( ) ;
2022-01-19 19:32:01 -05:00
OwningDocument - > RemoveUnreferencedDependencies ( ) ;
2021-10-12 21:21:22 -04:00
}
}
void FGraphController : : IterateNodes ( TFunctionRef < void ( FNodeHandle ) > InFunction , EMetasoundFrontendClassType InClassType )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendNode & Node : GraphClass - > Graph . Nodes )
{
FConstClassAccessPtr NodeClassPtr = OwningDocument - > FindClassWithID ( Node . ClassID ) ;
if ( const FMetasoundFrontendClass * NodeClass = NodeClassPtr . Get ( ) )
{
if ( InClassType = = EMetasoundFrontendClassType : : Invalid | | NodeClass - > Metadata . GetType ( ) = = InClassType )
{
FNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
FNodeHandle NodeHandle = GetNodeHandle ( FGraphController : : FNodeAndClass { NodePtr , NodeClassPtr } ) ;
InFunction ( NodeHandle ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find class for node [NodeID:%s, ClassID:%s] " ) , * Node . GetID ( ) . ToString ( ) , * Node . ClassID . ToString ( ) ) ;
}
}
}
}
void FGraphController : : IterateConstNodes ( TFunctionRef < void ( FConstNodeHandle ) > InFunction , EMetasoundFrontendClassType InClassType ) const
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendNode & Node : GraphClass - > Graph . Nodes )
{
FConstClassAccessPtr NodeClassPtr = OwningDocument - > FindClassWithID ( Node . ClassID ) ;
if ( const FMetasoundFrontendClass * NodeClass = NodeClassPtr . Get ( ) )
{
if ( InClassType = = EMetasoundFrontendClassType : : Invalid | | NodeClass - > Metadata . GetType ( ) = = InClassType )
{
FConstNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
FConstNodeHandle NodeHandle = GetNodeHandle ( FGraphController : : FConstNodeAndClass { NodePtr , NodeClassPtr } ) ;
InFunction ( NodeHandle ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find class for node [NodeID:%s, ClassID:%s] " ) , * Node . GetID ( ) . ToString ( ) , * Node . ClassID . ToString ( ) ) ;
}
}
}
}
TArray < FConstNodeHandle > FGraphController : : GetConstOutputNodes ( ) const
{
auto IsOutputNode = [ ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Output ;
} ;
return GetNodesByPredicate ( IsOutputNode ) ;
}
TArray < FConstNodeHandle > FGraphController : : GetConstInputNodes ( ) const
{
auto IsInputNode = [ ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Input ;
} ;
return GetNodesByPredicate ( IsInputNode ) ;
}
2022-02-09 12:52:07 -05:00
const TSet < FName > & FGraphController : : GetInputsInheritingDefault ( ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
if ( GraphClass - > PresetOptions . bIsPreset )
{
return GraphClass - > PresetOptions . InputsInheritingDefault ;
}
}
return Invalid : : GetInvalidNameSet ( ) ;
}
bool FGraphController : : SetInputInheritsDefault ( FName InName , bool bInputInheritsDefault )
{
if ( bInputInheritsDefault )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
if ( GraphClass - > PresetOptions . bIsPreset )
{
return GraphClass - > PresetOptions . InputsInheritingDefault . Add ( InName ) . IsValidId ( ) ;
}
}
}
else
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
if ( GraphClass - > PresetOptions . bIsPreset )
{
return GraphClass - > PresetOptions . InputsInheritingDefault . Remove ( InName ) > 0 ;
}
}
}
return false ;
}
void FGraphController : : SetInputsInheritingDefault ( TSet < FName > & & InNames )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
GraphClass - > PresetOptions . bIsPreset = true ;
GraphClass - > PresetOptions . InputsInheritingDefault = MoveTemp ( InNames ) ;
}
}
2021-10-12 21:21:22 -04:00
bool FGraphController : : ContainsOutputVertex ( const FVertexName & InName , const FName & InTypeName ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsOutputVertexWithSameNameAndType = [ & ] ( const FMetasoundFrontendClassOutput & ClassOutput )
{
return ClassOutput . Name = = InName & & ClassOutput . TypeName = = InTypeName ;
} ;
return GraphClass - > Interface . Outputs . ContainsByPredicate ( IsOutputVertexWithSameNameAndType ) ;
}
return false ;
}
bool FGraphController : : ContainsOutputVertexWithName ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsOutputVertexWithSameName = [ & ] ( const FMetasoundFrontendClassOutput & ClassOutput )
{
return ClassOutput . Name = = InName ;
} ;
return GraphClass - > Interface . Outputs . ContainsByPredicate ( IsOutputVertexWithSameName ) ;
}
return false ;
}
bool FGraphController : : ContainsInputVertex ( const FVertexName & InName , const FName & InTypeName ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsInputVertexWithSameNameAndType = [ & ] ( const FMetasoundFrontendClassInput & ClassInput )
{
return ClassInput . Name = = InName & & ClassInput . TypeName = = InTypeName ;
} ;
2021-10-25 20:05:28 -04:00
return GraphClass - > Interface . Inputs . ContainsByPredicate ( IsInputVertexWithSameNameAndType ) ;
2021-10-12 21:21:22 -04:00
}
return false ;
}
bool FGraphController : : ContainsInputVertexWithName ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsInputVertexWithSameName = [ & ] ( const FMetasoundFrontendClassInput & ClassInput )
{
return ClassInput . Name = = InName ;
} ;
return GraphClass - > Interface . Inputs . ContainsByPredicate ( IsInputVertexWithSameName ) ;
}
return false ;
}
FConstNodeHandle FGraphController : : GetOutputNodeWithName ( const FVertexName & InName ) const
{
auto IsOutputNodeWithSameName = [ & ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return ( NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Output ) & & ( Node . Name = = InName ) ;
} ;
return GetNodeByPredicate ( IsOutputNodeWithSameName ) ;
}
FConstNodeHandle FGraphController : : GetInputNodeWithName ( const FVertexName & InName ) const
{
auto IsInputNodeWithSameName = [ & ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return ( NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Input ) & & ( Node . Name = = InName ) ;
} ;
return GetNodeByPredicate ( IsInputNodeWithSameName ) ;
}
FNodeHandle FGraphController : : GetOutputNodeWithName ( const FVertexName & InName )
{
auto IsOutputNodeWithSameName = [ & ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return ( NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Output ) & & ( Node . Name = = InName ) ;
} ;
return GetNodeByPredicate ( IsOutputNodeWithSameName ) ;
}
FNodeHandle FGraphController : : GetInputNodeWithName ( const FVertexName & InName )
{
auto IsInputNodeWithSameName = [ & ] ( const FMetasoundFrontendClass & NodeClass , const FMetasoundFrontendNode & Node )
{
return ( NodeClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Input ) & & ( Node . Name = = InName ) ;
} ;
return GetNodeByPredicate ( IsInputNodeWithSameName ) ;
}
FNodeHandle FGraphController : : AddInputVertex ( const FMetasoundFrontendClassInput & InClassInput )
{
using FRegistry = FMetasoundFrontendRegistryContainer ;
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsInputWithSameName = [ & ] ( const FMetasoundFrontendClassInput & ExistingDesc ) { return ExistingDesc . Name = = InClassInput . Name ; } ;
if ( Algo : : NoneOf ( GraphClass - > Interface . Inputs , IsInputWithSameName ) )
{
FNodeRegistryKey Key ;
2022-07-18 17:14:25 -04:00
if ( FRegistry : : GetInputNodeRegistryKeyForDataType ( InClassInput . TypeName , InClassInput . AccessType , Key ) )
2021-10-12 21:21:22 -04:00
{
FConstClassAccessPtr InputClassPtr = OwningDocument - > FindOrAddClass ( Key ) ;
if ( const FMetasoundFrontendClass * InputClass = InputClassPtr . Get ( ) )
{
const FVertexName NewName = InClassInput . Name ;
2022-07-06 15:31:05 -04:00
// Setup input node
FMetasoundFrontendNode & Node = GraphClass - > Graph . Nodes . Emplace_GetRef ( * InputClass ) ;
2021-10-12 21:21:22 -04:00
Node . Name = NewName ;
if ( InClassInput . NodeID . IsValid ( ) )
{
Node . UpdateID ( InClassInput . NodeID ) ;
}
else
{
Node . UpdateID ( FGuid : : NewGuid ( ) ) ;
}
2022-07-06 15:31:05 -04:00
// Set name on related vertices of input node
2021-10-12 21:21:22 -04:00
auto IsVertexWithTypeName = [ & ] ( FMetasoundFrontendVertex & Vertex ) { return Vertex . TypeName = = InClassInput . TypeName ; } ;
if ( FMetasoundFrontendVertex * InputVertex = Node . Interface . Inputs . FindByPredicate ( IsVertexWithTypeName ) )
{
InputVertex - > Name = NewName ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Input node [TypeName:%s] does not contain input vertex with type [TypeName:%s] " ) , * InClassInput . TypeName . ToString ( ) , * InClassInput . TypeName . ToString ( ) ) ;
}
2022-07-06 15:31:05 -04:00
if ( FMetasoundFrontendVertex * OutputVertex = Node . Interface . Outputs . FindByPredicate ( IsVertexWithTypeName ) )
2021-10-12 21:21:22 -04:00
{
OutputVertex - > Name = NewName ;
}
2022-07-06 15:31:05 -04:00
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Input node [TypeName:%s] does not contain output vertex with type [TypeName:%s] " ) , * InClassInput . TypeName . ToString ( ) , * InClassInput . TypeName . ToString ( ) ) ;
}
2021-10-12 21:21:22 -04:00
2022-07-06 15:31:05 -04:00
// Add input to this graph class interface
2021-10-12 21:21:22 -04:00
FMetasoundFrontendClassInput & NewInput = GraphClass - > Interface . Inputs . Add_GetRef ( InClassInput ) ;
2022-07-06 15:31:05 -04:00
2021-10-12 21:21:22 -04:00
NewInput . NodeID = Node . GetID ( ) ;
2022-07-06 15:31:05 -04:00
if ( ! NewInput . VertexID . IsValid ( ) )
{
// Create a new guid if there wasn't a valid guid attached
// to input.
NewInput . VertexID = FGuid : : NewGuid ( ) ;
}
2021-10-12 21:21:22 -04:00
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddMemberIDModified ( NewInput . NodeID ) ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
GraphClass - > Interface . UpdateChangeID ( ) ;
FNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
return GetNodeHandle ( FGraphController : : FNodeAndClass { NodePtr , InputClassPtr } ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to add input. No input node registered for data type [TypeName:%s] " ) , * InClassInput . TypeName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to add input. Input with same name \" %s \" exists in class [ClassID:%s] " ) , * InClassInput . Name . ToString ( ) , * GraphClass - > ID . ToString ( ) ) ;
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
2022-01-26 18:11:52 -05:00
FNodeHandle FGraphController : : AddInputVertex ( const FVertexName & InName , const FName InTypeName , const FMetasoundFrontendLiteral * InDefaultValue )
2021-10-12 21:21:22 -04:00
{
const FGuid VertexID = FGuid : : NewGuid ( ) ;
FMetasoundFrontendClassInput Description ;
Description . Name = InName ;
Description . TypeName = InTypeName ;
Description . VertexID = VertexID ;
if ( InDefaultValue )
{
Description . DefaultLiteral = * InDefaultValue ;
}
else
{
Metasound : : FLiteral Literal = IDataTypeRegistry : : Get ( ) . CreateDefaultLiteral ( InTypeName ) ;
Description . DefaultLiteral . SetFromLiteral ( Literal ) ;
}
return AddInputVertex ( Description ) ;
}
bool FGraphController : : RemoveInputVertex ( const FVertexName & InName )
{
auto IsInputNodeWithSameName = [ & ] ( const FMetasoundFrontendClass & InClass , const FMetasoundFrontendNode & InNode )
{
return InClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Input & & InNode . Name = = InName ;
} ;
const TArray < FGraphController : : FNodeAndClass > NodeAndClassPairs = GetNodesAndClassesByPredicate ( IsInputNodeWithSameName ) ;
for ( const FNodeAndClass & NodeAndClass : NodeAndClassPairs )
{
if ( const FMetasoundFrontendNode * Node = NodeAndClass . Node . Get ( ) )
{
return RemoveInput ( * Node ) ;
}
}
return false ;
}
2022-01-26 18:11:52 -05:00
FNodeHandle FGraphController : : AddOutputVertex ( const FVertexName & InName , const FName InTypeName )
2021-10-12 21:21:22 -04:00
{
const FGuid VertexID = FGuid : : NewGuid ( ) ;
FMetasoundFrontendClassOutput Description ;
Description . Name = InName ;
Description . TypeName = InTypeName ;
Description . VertexID = VertexID ;
return AddOutputVertex ( Description ) ;
}
FNodeHandle FGraphController : : AddOutputVertex ( const FMetasoundFrontendClassOutput & InClassOutput )
{
using FRegistry = FMetasoundFrontendRegistryContainer ;
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsOutputWithSameName = [ & ] ( const FMetasoundFrontendClassOutput & ExistingDesc ) { return ExistingDesc . Name = = InClassOutput . Name ; } ;
if ( Algo : : NoneOf ( GraphClass - > Interface . Outputs , IsOutputWithSameName ) )
{
FNodeRegistryKey Key ;
2022-07-18 17:14:25 -04:00
if ( FRegistry : : GetOutputNodeRegistryKeyForDataType ( InClassOutput . TypeName , InClassOutput . AccessType , Key ) )
2021-10-12 21:21:22 -04:00
{
FConstClassAccessPtr OutputClassPtr = OwningDocument - > FindOrAddClass ( Key ) ;
if ( const FMetasoundFrontendClass * OutputClass = OutputClassPtr . Get ( ) )
{
const FVertexName NewName = InClassOutput . Name ;
2022-07-06 15:31:05 -04:00
FMetasoundFrontendNode & Node = GraphClass - > Graph . Nodes . Add_GetRef ( * OutputClass ) ;
2021-10-12 21:21:22 -04:00
Node . Name = NewName ;
if ( InClassOutput . NodeID . IsValid ( ) )
{
Node . UpdateID ( InClassOutput . NodeID ) ;
}
else
{
Node . UpdateID ( FGuid : : NewGuid ( ) ) ;
}
2022-07-06 15:31:05 -04:00
// Set vertex name on output node
2021-10-12 21:21:22 -04:00
auto IsVertexWithTypeName = [ & ] ( FMetasoundFrontendVertex & Vertex ) { return Vertex . TypeName = = InClassOutput . TypeName ; } ;
2022-07-06 15:31:05 -04:00
if ( FMetasoundFrontendVertex * InputVertex = Node . Interface . Inputs . FindByPredicate ( IsVertexWithTypeName ) )
2021-10-12 21:21:22 -04:00
{
InputVertex - > Name = NewName ;
}
2022-07-06 15:31:05 -04:00
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Output node [TypeName:%s] does not contain input vertex with type [TypeName:%s] " ) , * InClassOutput . TypeName . ToString ( ) , * InClassOutput . TypeName . ToString ( ) ) ;
}
2021-10-12 21:21:22 -04:00
if ( FMetasoundFrontendVertex * OutputVertex = Node . Interface . Outputs . FindByPredicate ( IsVertexWithTypeName ) )
{
OutputVertex - > Name = NewName ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Output node [TypeName:%s] does not contain output vertex with type [TypeName:%s] " ) , * InClassOutput . TypeName . ToString ( ) , * InClassOutput . TypeName . ToString ( ) ) ;
}
2022-07-06 15:31:05 -04:00
// Add output to graph interface
2021-10-12 21:21:22 -04:00
FMetasoundFrontendClassOutput & NewOutput = GraphClass - > Interface . Outputs . Add_GetRef ( InClassOutput ) ;
2022-07-06 15:31:05 -04:00
// Setup new output
2021-10-12 21:21:22 -04:00
NewOutput . NodeID = Node . GetID ( ) ;
2022-07-06 15:31:05 -04:00
if ( ! NewOutput . VertexID . IsValid ( ) )
{
// Create a new guid if there wasn't a valid guid attached
// to output.
NewOutput . VertexID = FGuid : : NewGuid ( ) ;
}
2021-10-12 21:21:22 -04:00
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddMemberIDModified ( NewOutput . VertexID ) ;
}
# endif // WITH_EDITO
2022-07-06 15:31:05 -04:00
// Mark interface as changed.
2021-10-12 21:21:22 -04:00
GraphClass - > Interface . UpdateChangeID ( ) ;
FNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
return GetNodeHandle ( FGraphController : : FNodeAndClass { NodePtr , OutputClassPtr } ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to add output. No output node registered for data type [TypeName:%s] " ) , * InClassOutput . TypeName . ToString ( ) ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Failed to add output. Output with same name \" %s \" exists in class [ClassID:%s] " ) , * InClassOutput . Name . ToString ( ) , * GraphClass - > ID . ToString ( ) ) ;
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
bool FGraphController : : RemoveOutputVertex ( const FVertexName & InName )
{
auto IsOutputNodeWithSameName = [ & ] ( const FMetasoundFrontendClass & InClass , const FMetasoundFrontendNode & InNode )
{
return InClass . Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Output
& & InNode . Name = = InName ;
} ;
const TArray < FGraphController : : FNodeAndClass > NodeAndClassPairs = GetNodesAndClassesByPredicate ( IsOutputNodeWithSameName ) ;
for ( const FNodeAndClass & NodeAndClass : NodeAndClassPairs )
{
if ( const FMetasoundFrontendNode * Node = NodeAndClass . Node . Get ( ) )
{
return RemoveOutput ( * Node ) ;
}
}
return false ;
}
// This can be used to determine what kind of property editor we should use for the data type of a given input.
// Will return Invalid if the input couldn't be found, or if the input doesn't support any kind of literals.
ELiteralType FGraphController : : GetPreferredLiteralTypeForInputVertex ( const FVertexName & InInputName ) const
{
if ( const FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithName ( InInputName ) )
{
return IDataTypeRegistry : : Get ( ) . GetDesiredLiteralType ( Desc - > TypeName ) ;
}
return ELiteralType : : Invalid ;
}
// For inputs whose preferred literal type is UObject or UObjectArray, this can be used to determine the UObject corresponding to that input's datatype.
UClass * FGraphController : : GetSupportedClassForInputVertex ( const FVertexName & InInputName )
{
if ( const FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithName ( InInputName ) )
{
return IDataTypeRegistry : : Get ( ) . GetUClassForDataType ( Desc - > TypeName ) ;
}
return nullptr ;
}
FMetasoundFrontendLiteral FGraphController : : GetDefaultInput ( const FGuid & InVertexID ) const
{
if ( const FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithVertexID ( InVertexID ) )
{
return Desc - > DefaultLiteral ;
}
return FMetasoundFrontendLiteral { } ;
}
bool FGraphController : : SetDefaultInput ( const FGuid & InVertexID , const FMetasoundFrontendLiteral & InLiteral )
{
if ( FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithVertexID ( InVertexID ) )
{
if ( ensure ( IDataTypeRegistry : : Get ( ) . IsLiteralTypeSupported ( Desc - > TypeName , InLiteral . GetType ( ) ) ) )
{
Desc - > DefaultLiteral = InLiteral ;
return true ;
}
else
{
SetDefaultInputToDefaultLiteralOfType ( InVertexID ) ;
}
}
return false ;
}
bool FGraphController : : SetDefaultInputToDefaultLiteralOfType ( const FGuid & InVertexID )
{
if ( FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithVertexID ( InVertexID ) )
{
Metasound : : FLiteral Literal = IDataTypeRegistry : : Get ( ) . CreateDefaultLiteral ( Desc - > TypeName ) ;
Desc - > DefaultLiteral . SetFromLiteral ( Literal ) ;
return Desc - > DefaultLiteral . IsValid ( ) ;
}
return false ;
}
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-10-12 21:21:22 -04:00
const FText & FGraphController : : GetInputDescription ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithName ( InName ) )
{
2022-01-26 18:11:52 -05:00
return Desc - > Metadata . GetDescription ( ) ;
2021-10-12 21:21:22 -04:00
}
return FText : : GetEmpty ( ) ;
}
const FText & FGraphController : : GetOutputDescription ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendClassOutput * Desc = FindOutputDescriptionWithName ( InName ) )
{
2022-01-26 18:11:52 -05:00
return Desc - > Metadata . GetDescription ( ) ;
2021-10-12 21:21:22 -04:00
}
return FText : : GetEmpty ( ) ;
}
2022-03-01 16:31:55 -05:00
int32 FGraphController : : GetSortOrderIndexForInput ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithName ( InName ) )
{
return Desc - > Metadata . SortOrderIndex ;
}
return 0 ;
}
int32 FGraphController : : GetSortOrderIndexForOutput ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendClassOutput * Desc = FindOutputDescriptionWithName ( InName ) )
{
return Desc - > Metadata . SortOrderIndex ;
}
return 0 ;
}
2021-10-12 21:21:22 -04:00
void FGraphController : : SetInputDisplayName ( const FVertexName & InName , const FText & InDisplayName )
{
if ( FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithName ( InName ) )
{
2022-01-26 18:11:52 -05:00
Desc - > Metadata . SetDisplayName ( InDisplayName ) ;
2021-10-12 21:21:22 -04:00
}
}
void FGraphController : : SetOutputDisplayName ( const FVertexName & InName , const FText & InDisplayName )
{
if ( FMetasoundFrontendClassOutput * Desc = FindOutputDescriptionWithName ( InName ) )
{
2022-01-26 18:11:52 -05:00
Desc - > Metadata . SetDisplayName ( InDisplayName ) ;
2021-10-12 21:21:22 -04:00
}
}
void FGraphController : : SetInputDescription ( const FVertexName & InName , const FText & InDescription )
{
if ( FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithName ( InName ) )
{
2022-01-26 18:11:52 -05:00
Desc - > Metadata . SetDescription ( InDescription ) ;
2021-10-12 21:21:22 -04:00
}
}
void FGraphController : : SetOutputDescription ( const FVertexName & InName , const FText & InDescription )
{
if ( FMetasoundFrontendClassOutput * Desc = FindOutputDescriptionWithName ( InName ) )
{
2022-01-26 18:11:52 -05:00
Desc - > Metadata . SetDescription ( InDescription ) ;
2021-10-12 21:21:22 -04:00
}
}
2022-03-01 16:31:55 -05:00
void FGraphController : : SetSortOrderIndexForInput ( const FVertexName & InName , int32 InSortOrderIndex )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
FMetasoundFrontendInterfaceStyle Style = GraphClass - > Interface . GetInputStyle ( ) ;
Style . DefaultSortOrder . Reset ( ) ;
for ( FMetasoundFrontendClassInput & Input : GraphClass - > Interface . Inputs )
{
if ( Input . Name = = InName )
{
Input . Metadata . SortOrderIndex = InSortOrderIndex ;
}
Style . DefaultSortOrder . Add ( Input . Metadata . SortOrderIndex ) ;
}
GraphClass - > Interface . SetInputStyle ( Style ) ;
}
}
void FGraphController : : SetSortOrderIndexForOutput ( const FVertexName & InName , int32 InSortOrderIndex )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
FMetasoundFrontendInterfaceStyle Style = GraphClass - > Interface . GetOutputStyle ( ) ;
Style . DefaultSortOrder . Reset ( ) ;
for ( FMetasoundFrontendClassOutput & Output : GraphClass - > Interface . Outputs )
{
if ( Output . Name = = InName )
{
Output . Metadata . SortOrderIndex = InSortOrderIndex ;
}
Style . DefaultSortOrder . Add ( Output . Metadata . SortOrderIndex ) ;
}
GraphClass - > Interface . SetOutputStyle ( Style ) ;
}
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
// This can be used to clear the current literal for a given input.
// @returns false if the input name couldn't be found.
bool FGraphController : : ClearLiteralForInput ( const FVertexName & InInputName , FGuid InVertexID )
{
if ( FMetasoundFrontendClassInput * Desc = FindInputDescriptionWithName ( InInputName ) )
{
Desc - > DefaultLiteral . Clear ( ) ;
}
return false ;
}
FNodeHandle FGraphController : : AddNode ( const FNodeRegistryKey & InKey , FGuid InNodeGuid )
{
// Construct a FNodeClassInfo from this lookup key.
FConstClassAccessPtr Class = OwningDocument - > FindOrAddClass ( InKey ) ;
const bool bIsValidClass = ( nullptr ! = Class . Get ( ) ) ;
if ( bIsValidClass )
{
return AddNode ( Class , InNodeGuid ) ;
}
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find or add node class info with registry key [Key:%s] " ) , * InKey ) ;
return INodeController : : GetInvalidHandle ( ) ;
}
FNodeHandle FGraphController : : AddNode ( const FMetasoundFrontendClassMetadata & InClassMetadata , FGuid InNodeGuid )
{
2022-09-13 12:30:44 -04:00
ensureAlwaysMsgf ( InClassMetadata . GetType ( ) ! = EMetasoundFrontendClassType : : Template ,
TEXT ( " Cannot implement '%s' template node using 'AddNode'. Template nodes must always "
" be added using AddTemplateNode function and supply the interface to be implemented " ) ,
* InClassMetadata . GetClassName ( ) . ToString ( ) ) ;
2021-10-12 21:21:22 -04:00
return AddNode ( NodeRegistryKey : : CreateKey ( InClassMetadata ) , InNodeGuid ) ;
}
2022-08-10 14:18:10 -04:00
FNodeHandle FGraphController : : AddTemplateNode ( const FNodeRegistryKey & InKey , FMetasoundFrontendNodeInterface & & InNodeInterface , FGuid InNodeGuid )
{
if ( const INodeTemplate * Template = INodeTemplateRegistry : : Get ( ) . FindTemplate ( InKey ) )
{
const bool bIsValidInterface = Template - > IsValidNodeInterface ( InNodeInterface ) ;
if ( ensureAlwaysMsgf ( bIsValidInterface , TEXT ( " Cannot implement interface when attempting to add node using template with key '%s' " ) , * InKey ) )
{
// Construct a FNodeClassInfo from this lookup key.
FConstClassAccessPtr Class = OwningDocument - > FindOrAddClass ( InKey ) ;
const bool bIsValidClass = ( nullptr ! = Class . Get ( ) ) ;
if ( bIsValidClass )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
if ( const FMetasoundFrontendClass * NodeClass = Class . Get ( ) )
{
FMetasoundFrontendNode & Node = GraphClass - > Graph . Nodes . Emplace_GetRef ( * NodeClass ) ;
Node . UpdateID ( InNodeGuid ) ;
Node . Interface = InNodeInterface ;
FNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
return GetNodeHandle ( FGraphController : : FNodeAndClass { NodePtr , Class } ) ;
}
}
}
}
}
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find or add node template class info with registry key [Key:%s] " ) , * InKey ) ;
return INodeController : : GetInvalidHandle ( ) ;
}
2021-10-12 21:21:22 -04:00
FNodeHandle FGraphController : : AddDuplicateNode ( const INodeController & InNode )
{
// TODO: will need to copy node interface when dynamic pins exist.
const FMetasoundFrontendClassMetadata & ClassMetadata = InNode . GetClassMetadata ( ) ;
FConstClassAccessPtr ClassPtr ;
if ( EMetasoundFrontendClassType : : Graph = = ClassMetadata . GetType ( ) )
{
// Add subgraph and dependencies if needed
ClassPtr = OwningDocument - > FindClass ( ClassMetadata ) ;
const bool bIsClassMissing = ( nullptr = = ClassPtr . Get ( ) ) ;
if ( bIsClassMissing )
{
// Class does not exist, need to add the subgraph
OwningDocument - > AddDuplicateSubgraph ( * ( InNode . AsGraph ( ) ) ) ;
ClassPtr = OwningDocument - > FindClass ( ClassMetadata ) ;
}
}
else
{
ClassPtr = OwningDocument - > FindOrAddClass ( ClassMetadata ) ;
}
return AddNode ( ClassPtr , FGuid : : NewGuid ( ) ) ;
}
// Remove the node corresponding to this node handle.
// On success, invalidates the received node handle.
bool FGraphController : : RemoveNode ( INodeController & InNode )
{
const EMetasoundFrontendClassType NodeClassType = InNode . GetClassMetadata ( ) . GetType ( ) ;
2021-11-18 14:37:34 -05:00
const bool bIsVariableNodeClassType = ( NodeClassType = = EMetasoundFrontendClassType : : Variable )
| | ( NodeClassType = = EMetasoundFrontendClassType : : VariableAccessor )
| | ( NodeClassType = = EMetasoundFrontendClassType : : VariableDeferredAccessor )
| | ( NodeClassType = = EMetasoundFrontendClassType : : VariableMutator ) ;
2021-10-12 21:21:22 -04:00
if ( bIsVariableNodeClassType )
{
2021-11-18 14:37:34 -05:00
// Variables hold on to related node IDs. These need to be removed
// from the variable definition.
RemoveNodeIDFromAssociatedVariable ( InNode ) ;
2021-10-12 21:21:22 -04:00
// Variable nodes of the same variable are connected serially.
// Special care is taken to ensure the stack is connected when
// removing a node from the stack.
SpliceVariableNodeFromVariableStack ( InNode ) ;
2021-11-18 14:37:34 -05:00
2021-10-12 21:21:22 -04:00
}
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
FGuid NodeID = InNode . GetID ( ) ;
auto IsNodeWithSameID = [ & ] ( const FMetasoundFrontendNode & InFrontendNode ) { return InFrontendNode . GetID ( ) = = NodeID ; } ;
if ( const FMetasoundFrontendNode * FrontendNode = GraphClass - > Graph . Nodes . FindByPredicate ( IsNodeWithSameID ) )
{
switch ( NodeClassType )
{
case EMetasoundFrontendClassType : : Input :
{
return RemoveInput ( * FrontendNode ) ;
}
case EMetasoundFrontendClassType : : Output :
{
return RemoveOutput ( * FrontendNode ) ;
}
case EMetasoundFrontendClassType : : Variable :
case EMetasoundFrontendClassType : : VariableAccessor :
2021-11-18 14:37:34 -05:00
case EMetasoundFrontendClassType : : VariableDeferredAccessor :
2021-10-12 21:21:22 -04:00
case EMetasoundFrontendClassType : : VariableMutator :
2021-11-18 14:37:34 -05:00
// TODO: remove node from variable.7
2021-10-12 21:21:22 -04:00
case EMetasoundFrontendClassType : : Literal :
case EMetasoundFrontendClassType : : External :
2022-08-10 14:18:10 -04:00
case EMetasoundFrontendClassType : : Template :
2021-10-12 21:21:22 -04:00
case EMetasoundFrontendClassType : : Graph :
{
return RemoveNode ( * FrontendNode ) ;
}
default :
case EMetasoundFrontendClassType : : Invalid :
{
2022-08-10 14:18:10 -04:00
static_assert ( static_cast < int32 > ( EMetasoundFrontendClassType : : Invalid ) = = 10 , " Possible missing switch case coverage for EMetasoundFrontendClassType. " ) ;
2021-10-12 21:21:22 -04:00
checkNoEntry ( ) ;
}
}
}
}
return false ;
}
2022-02-09 12:52:07 -05:00
const FMetasoundFrontendGraphClassPresetOptions & FGraphController : : GetGraphPresetOptions ( ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > PresetOptions ;
}
return Invalid : : GetInvalidGraphClassPresetOptions ( ) ;
}
void FGraphController : : SetGraphPresetOptions ( const FMetasoundFrontendGraphClassPresetOptions & InPresetOptions )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
GraphClass - > PresetOptions = InPresetOptions ;
}
}
2021-10-12 21:21:22 -04:00
const FMetasoundFrontendClassMetadata & FGraphController : : GetGraphMetadata ( ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Metadata ;
}
return Invalid : : GetInvalidClassMetadata ( ) ;
}
void FGraphController : : SetGraphMetadata ( const FMetasoundFrontendClassMetadata & InMetadata )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
GraphClass - > Metadata = InMetadata ;
}
}
FNodeHandle FGraphController : : CreateEmptySubgraph ( const FMetasoundFrontendClassMetadata & InMetadata )
{
if ( InMetadata . GetType ( ) = = EMetasoundFrontendClassType : : Graph )
{
if ( const FMetasoundFrontendClass * ExistingDependency = OwningDocument - > FindClass ( InMetadata ) . Get ( ) )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Cannot add new subgraph. Metasound class already exists with matching metadata Name: \" %s \" , Version %d.%d " ) , * ( ExistingDependency - > Metadata . GetClassName ( ) . GetFullName ( ) . ToString ( ) ) , ExistingDependency - > Metadata . GetVersion ( ) . Major , ExistingDependency - > Metadata . GetVersion ( ) . Minor ) ;
}
else
{
return AddNode ( OwningDocument - > FindOrAddClass ( InMetadata ) , FGuid : : NewGuid ( ) ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Incompatible Metasound NodeType encountered when attempting to create an empty subgraph. NodeType must equal EMetasoundFrontendClassType::Graph " ) ) ;
}
return INodeController : : GetInvalidHandle ( ) ;
}
2022-05-19 14:18:38 -04:00
TUniquePtr < IOperator > FGraphController : : BuildOperator ( const FOperatorSettings & InSettings , const FMetasoundEnvironment & InEnvironment , FBuildResults & OutResults ) const
2021-10-12 21:21:22 -04:00
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
// TODO: bubble up errors.
const TArray < FMetasoundFrontendGraphClass > & Subgraphs = OwningDocument - > GetSubgraphs ( ) ;
const TArray < FMetasoundFrontendClass > & Dependencies = OwningDocument - > GetDependencies ( ) ;
2022-03-04 04:25:00 -05:00
FString UnknownAsset = TEXT ( " UnknownAsset " ) ;
2022-10-10 15:44:28 -04:00
TSet < FName > TransmittableInputNames ;
TUniquePtr < FFrontendGraph > Graph = FFrontendGraphBuilder : : CreateGraph ( * GraphClass , Subgraphs , Dependencies , TransmittableInputNames , UnknownAsset ) ;
2021-10-12 21:21:22 -04:00
if ( ! Graph . IsValid ( ) )
{
return TUniquePtr < IOperator > ( nullptr ) ;
}
2022-05-20 10:11:42 -04:00
FInputVertexInterfaceData InterfaceData ;
FBuildGraphOperatorParams BuildParams { * Graph , InSettings , InterfaceData , InEnvironment } ;
2022-05-19 14:18:38 -04:00
return FOperatorBuilder ( FOperatorBuilderSettings : : GetDefaultSettings ( ) ) . BuildGraphOperator ( BuildParams , OutResults ) ;
2021-10-12 21:21:22 -04:00
}
else
{
return TUniquePtr < IOperator > ( nullptr ) ;
}
}
FDocumentHandle FGraphController : : GetOwningDocument ( )
{
return OwningDocument ;
}
FConstDocumentHandle FGraphController : : GetOwningDocument ( ) const
{
return OwningDocument ;
}
FNodeHandle FGraphController : : AddNode ( FConstClassAccessPtr InExistingDependency , FGuid InNodeGuid )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
if ( const FMetasoundFrontendClass * NodeClass = InExistingDependency . Get ( ) )
{
FMetasoundFrontendNode & Node = GraphClass - > Graph . Nodes . Emplace_GetRef ( * NodeClass ) ;
// Cache the asset name on the node if it node is reference to asset-defined graph.
const FNodeRegistryKey RegistryKey = NodeRegistryKey : : CreateKey ( NodeClass - > Metadata ) ;
if ( IMetaSoundAssetManager * AssetManager = IMetaSoundAssetManager : : Get ( ) )
{
if ( const FSoftObjectPath * Path = AssetManager - > FindObjectPathFromKey ( RegistryKey ) )
{
const FString & AssetName = Path - > GetAssetName ( ) ;
Node . Name = * AssetName ;
}
}
Node . UpdateID ( InNodeGuid ) ;
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddNodeIDModified ( InNodeGuid ) ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
FNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
return GetNodeHandle ( FGraphController : : FNodeAndClass { NodePtr , InExistingDependency } ) ;
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
bool FGraphController : : RemoveNode ( const FMetasoundFrontendNode & InDesc )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsEdgeForThisNode = [ & ] ( const FMetasoundFrontendEdge & ConDesc ) { return ( ConDesc . FromNodeID = = InDesc . GetID ( ) ) | | ( ConDesc . ToNodeID = = InDesc . GetID ( ) ) ; } ;
// Remove any reference connections
int32 NumRemoved = GraphClass - > Graph . Edges . RemoveAll ( IsEdgeForThisNode ) ;
auto IsNodeWithID = [ & ] ( const FMetasoundFrontendNode & Desc ) { return InDesc . GetID ( ) = = Desc . GetID ( ) ; } ;
NumRemoved + = GraphClass - > Graph . Nodes . RemoveAll ( IsNodeWithID ) ;
2022-01-19 19:32:01 -05:00
OwningDocument - > RemoveUnreferencedDependencies ( ) ;
2021-10-12 21:21:22 -04:00
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( NumRemoved > 0 )
{
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddNodeIDModified ( InDesc . GetID ( ) ) ;
}
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
return ( NumRemoved > 0 ) ;
}
return false ;
}
bool FGraphController : : RemoveInput ( const FMetasoundFrontendNode & InNode )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsInputWithSameNodeID = [ & ] ( const FMetasoundFrontendClassInput & ClassInput ) { return ClassInput . NodeID = = InNode . GetID ( ) ; } ;
int32 NumInputsRemoved = GraphClass - > Interface . Inputs . RemoveAll ( IsInputWithSameNodeID ) ;
if ( NumInputsRemoved > 0 )
{
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddMemberIDModified ( InNode . GetID ( ) ) ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
GraphClass - > Interface . UpdateChangeID ( ) ;
}
bool bDidRemoveNode = RemoveNode ( InNode ) ;
return NumInputsRemoved > 0 | | bDidRemoveNode ;
}
return false ;
}
bool FGraphController : : RemoveOutput ( const FMetasoundFrontendNode & InNode )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
auto IsOutputWithSameNodeID = [ & ] ( const FMetasoundFrontendClassOutput & ClassOutput ) { return ClassOutput . NodeID = = InNode . GetID ( ) ; } ;
int32 NumOutputsRemoved = GraphClass - > Interface . Outputs . RemoveAll ( IsOutputWithSameNodeID ) ;
if ( NumOutputsRemoved )
{
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
if ( FMetasoundFrontendDocumentMetadata * DocMetadata = OwningDocument - > GetMetadata ( ) )
{
DocMetadata - > ModifyContext . AddMemberIDModified ( InNode . GetID ( ) ) ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
GraphClass - > Interface . UpdateChangeID ( ) ;
}
bool bDidRemoveNode = RemoveNode ( InNode ) ;
return ( NumOutputsRemoved > 0 ) | | bDidRemoveNode ;
}
return false ;
}
void FGraphController : : UpdateInterfaceChangeID ( )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
GraphClass - > Interface . UpdateChangeID ( ) ;
}
}
bool FGraphController : : ContainsNodesAndClassesByPredicate ( TFunctionRef < bool ( const FMetasoundFrontendClass & , const FMetasoundFrontendNode & ) > InPredicate ) const
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( FMetasoundFrontendNode & Node : GraphClass - > Graph . Nodes )
{
const FMetasoundFrontendClass * NodeClass = OwningDocument - > FindClassWithID ( Node . ClassID ) . Get ( ) ;
if ( nullptr ! = NodeClass )
{
if ( InPredicate ( * NodeClass , Node ) )
{
return true ;
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find class for node [NodeID:%s, ClassID:%s] " ) , * Node . GetID ( ) . ToString ( ) , * Node . ClassID . ToString ( ) ) ;
}
}
}
return false ;
}
TArray < FGraphController : : FNodeAndClass > FGraphController : : GetNodesAndClasses ( )
{
TArray < FNodeAndClass > NodesAndClasses ;
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( FMetasoundFrontendNode & Node : GraphClass - > Graph . Nodes )
{
FNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
FConstClassAccessPtr NodeClassPtr = OwningDocument - > FindClassWithID ( Node . ClassID ) ;
const bool bIsValidNodePtr = ( nullptr ! = NodePtr . Get ( ) ) ;
const bool bIsValidNodeClassPtr = ( nullptr ! = NodeClassPtr . Get ( ) ) ;
if ( bIsValidNodePtr & & bIsValidNodeClassPtr )
{
NodesAndClasses . Add ( FGraphController : : FNodeAndClass { NodePtr , NodeClassPtr } ) ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find class for node [NodeID:%s, ClassID:%s] " ) , * Node . GetID ( ) . ToString ( ) , * Node . ClassID . ToString ( ) ) ;
}
}
}
return NodesAndClasses ;
}
TArray < FGraphController : : FConstNodeAndClass > FGraphController : : GetNodesAndClasses ( ) const
{
TArray < FConstNodeAndClass > NodesAndClasses ;
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendNode & Node : GraphClass - > Graph . Nodes )
{
FConstNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
FConstClassAccessPtr NodeClassPtr = OwningDocument - > FindClassWithID ( Node . ClassID ) ;
const bool bIsValidNodePtr = ( nullptr ! = NodePtr . Get ( ) ) ;
const bool bIsValidNodeClassPtr = ( nullptr ! = NodeClassPtr . Get ( ) ) ;
if ( bIsValidNodePtr & & bIsValidNodeClassPtr )
{
NodesAndClasses . Add ( FGraphController : : FConstNodeAndClass { NodePtr , NodeClassPtr } ) ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find class for node [NodeID:%s, ClassID:%s] " ) , * Node . GetID ( ) . ToString ( ) , * Node . ClassID . ToString ( ) ) ;
}
}
}
return NodesAndClasses ;
}
TArray < FGraphController : : FNodeAndClass > FGraphController : : GetNodesAndClassesByPredicate ( TFunctionRef < bool ( const FMetasoundFrontendClass & , const FMetasoundFrontendNode & ) > InPredicate )
{
TArray < FNodeAndClass > NodesAndClasses ;
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( FMetasoundFrontendNode & Node : GraphClass - > Graph . Nodes )
{
FConstClassAccessPtr NodeClassPtr = OwningDocument - > FindClassWithID ( Node . ClassID ) ;
if ( const FMetasoundFrontendClass * NodeClass = NodeClassPtr . Get ( ) )
{
if ( InPredicate ( * NodeClass , Node ) )
{
FNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
NodesAndClasses . Add ( FGraphController : : FNodeAndClass { NodePtr , NodeClassPtr } ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find class for node [NodeID:%s, ClassID:%s] " ) , * Node . GetID ( ) . ToString ( ) , * Node . ClassID . ToString ( ) ) ;
}
}
}
return NodesAndClasses ;
}
TArray < FGraphController : : FConstNodeAndClass > FGraphController : : GetNodesAndClassesByPredicate ( TFunctionRef < bool ( const FMetasoundFrontendClass & , const FMetasoundFrontendNode & ) > InPredicate ) const
{
TArray < FConstNodeAndClass > NodesAndClasses ;
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
for ( const FMetasoundFrontendNode & Node : GraphClass - > Graph . Nodes )
{
FConstClassAccessPtr NodeClassPtr = OwningDocument - > FindClassWithID ( Node . ClassID ) ;
if ( const FMetasoundFrontendClass * NodeClass = NodeClassPtr . Get ( ) )
{
if ( InPredicate ( * NodeClass , Node ) )
{
FConstNodeAccessPtr NodePtr = GraphClassPtr . GetNodeWithNodeID ( Node . GetID ( ) ) ;
NodesAndClasses . Add ( FGraphController : : FConstNodeAndClass { NodePtr , NodeClassPtr } ) ;
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find class for node [NodeID:%s, ClassID:%s] " ) , * Node . GetID ( ) . ToString ( ) , * Node . ClassID . ToString ( ) ) ;
}
}
}
return NodesAndClasses ;
}
FNodeHandle FGraphController : : GetNodeByPredicate ( TFunctionRef < bool ( const FMetasoundFrontendClass & , const FMetasoundFrontendNode & ) > InPredicate )
{
TArray < FNodeAndClass > NodeAndClass = GetNodesAndClassesByPredicate ( InPredicate ) ;
if ( NodeAndClass . Num ( ) > 0 )
{
return GetNodeHandle ( NodeAndClass [ 0 ] ) ;
}
return INodeController : : GetInvalidHandle ( ) ;
}
FConstNodeHandle FGraphController : : GetNodeByPredicate ( TFunctionRef < bool ( const FMetasoundFrontendClass & , const FMetasoundFrontendNode & ) > InPredicate ) const
{
TArray < FConstNodeAndClass > NodeAndClass = GetNodesAndClassesByPredicate ( InPredicate ) ;
if ( NodeAndClass . Num ( ) > 0 )
{
return GetNodeHandle ( NodeAndClass [ 0 ] ) ;
}
return INodeController : : GetInvalidHandle ( ) ;
}
TArray < FNodeHandle > FGraphController : : GetNodesByPredicate ( TFunctionRef < bool ( const FMetasoundFrontendClass & , const FMetasoundFrontendNode & ) > InFilterFunc )
{
return GetNodeHandles ( GetNodesAndClassesByPredicate ( InFilterFunc ) ) ;
}
TArray < FConstNodeHandle > FGraphController : : GetNodesByPredicate ( TFunctionRef < bool ( const FMetasoundFrontendClass & , const FMetasoundFrontendNode & ) > InFilterFunc ) const
{
return GetNodeHandles ( GetNodesAndClassesByPredicate ( InFilterFunc ) ) ;
}
TArray < FNodeHandle > FGraphController : : GetNodeHandles ( TArrayView < const FGraphController : : FNodeAndClass > InNodesAndClasses )
{
TArray < FNodeHandle > Nodes ;
for ( const FNodeAndClass & NodeAndClass : InNodesAndClasses )
{
FNodeHandle NodeController = GetNodeHandle ( NodeAndClass ) ;
if ( NodeController - > IsValid ( ) )
{
Nodes . Add ( NodeController ) ;
}
}
return Nodes ;
}
TArray < FConstNodeHandle > FGraphController : : GetNodeHandles ( TArrayView < const FGraphController : : FConstNodeAndClass > InNodesAndClasses ) const
{
TArray < FConstNodeHandle > Nodes ;
for ( const FConstNodeAndClass & NodeAndClass : InNodesAndClasses )
{
FConstNodeHandle NodeController = GetNodeHandle ( NodeAndClass ) ;
if ( NodeController - > IsValid ( ) )
{
Nodes . Add ( NodeController ) ;
}
}
return Nodes ;
}
FNodeHandle FGraphController : : GetNodeHandle ( const FGraphController : : FNodeAndClass & InNodeAndClass )
{
FMetasoundFrontendNode * Node = InNodeAndClass . Node . Get ( ) ;
const FMetasoundFrontendClass * NodeClass = InNodeAndClass . Class . Get ( ) ;
if ( ( nullptr ! = Node ) & & ( nullptr ! = NodeClass ) )
{
FGraphHandle OwningGraph = this - > AsShared ( ) ;
FGraphAccessPtr GraphPtr = GraphClassPtr . GetGraph ( ) ;
switch ( NodeClass - > Metadata . GetType ( ) )
{
case EMetasoundFrontendClassType : : Input :
{
FClassInputAccessPtr OwningGraphClassInputPtr = FindInputDescriptionWithNodeID ( Node - > GetID ( ) ) ;
if ( nullptr ! = OwningGraphClassInputPtr . Get ( ) )
{
FInputNodeController : : FInitParams InitParams
{
InNodeAndClass . Node ,
InNodeAndClass . Class ,
OwningGraphClassInputPtr ,
GraphPtr ,
OwningGraph
} ;
return FInputNodeController : : CreateInputNodeHandle ( InitParams ) ;
}
else
{
// TODO: This supports input nodes introduced during subgraph inflation. Input nodes
// should be replaced with value nodes once they are implemented.
FNodeController : : FInitParams InitParams
{
InNodeAndClass . Node ,
InNodeAndClass . Class ,
GraphPtr ,
OwningGraph
} ;
return FNodeController : : CreateNodeHandle ( InitParams ) ;
}
}
break ;
case EMetasoundFrontendClassType : : Output :
{
FClassOutputAccessPtr OwningGraphClassOutputPtr = FindOutputDescriptionWithNodeID ( Node - > GetID ( ) ) ;
if ( nullptr ! = OwningGraphClassOutputPtr . Get ( ) )
{
FOutputNodeController : : FInitParams InitParams
{
InNodeAndClass . Node ,
InNodeAndClass . Class ,
OwningGraphClassOutputPtr ,
GraphPtr ,
OwningGraph
} ;
return FOutputNodeController : : CreateOutputNodeHandle ( InitParams ) ;
}
else
{
// TODO: This supports output nodes introduced during subgraph inflation. Output nodes
// should be replaced with value nodes once they are implemented.
FNodeController : : FInitParams InitParams
{
InNodeAndClass . Node ,
InNodeAndClass . Class ,
GraphPtr ,
OwningGraph
} ;
return FNodeController : : CreateNodeHandle ( InitParams ) ;
}
}
break ;
case EMetasoundFrontendClassType : : Variable :
case EMetasoundFrontendClassType : : VariableAccessor :
2021-11-18 14:37:34 -05:00
case EMetasoundFrontendClassType : : VariableDeferredAccessor :
2021-10-12 21:21:22 -04:00
case EMetasoundFrontendClassType : : VariableMutator :
2021-11-07 23:43:01 -05:00
{
FVariableNodeController : : FInitParams InitParams
{
InNodeAndClass . Node ,
InNodeAndClass . Class ,
GraphPtr ,
OwningGraph
} ;
return FVariableNodeController : : CreateNodeHandle ( InitParams ) ;
}
break ;
2021-10-12 21:21:22 -04:00
case EMetasoundFrontendClassType : : External :
2022-08-10 14:18:10 -04:00
case EMetasoundFrontendClassType : : Template :
2021-10-12 21:21:22 -04:00
{
FNodeController : : FInitParams InitParams
{
InNodeAndClass . Node ,
InNodeAndClass . Class ,
GraphPtr ,
OwningGraph
} ;
return FNodeController : : CreateNodeHandle ( InitParams ) ;
}
break ;
case EMetasoundFrontendClassType : : Graph :
{
FSubgraphNodeController : : FInitParams InitParams
{
InNodeAndClass . Node ,
InNodeAndClass . Class ,
GraphPtr ,
OwningGraph
} ;
return FSubgraphNodeController : : CreateNodeHandle ( InitParams ) ;
}
break ;
default :
checkNoEntry ( ) ;
2022-08-10 14:18:10 -04:00
static_assert ( static_cast < int32 > ( EMetasoundFrontendClassType : : Invalid ) = = 10 , " Possible missing switch case coverage for EMetasoundFrontendClassType. " ) ;
2021-10-12 21:21:22 -04:00
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
FConstNodeHandle FGraphController : : GetNodeHandle ( const FGraphController : : FConstNodeAndClass & InNodeAndClass ) const
{
const FMetasoundFrontendNode * Node = InNodeAndClass . Node . Get ( ) ;
const FMetasoundFrontendClass * NodeClass = InNodeAndClass . Class . Get ( ) ;
if ( ( nullptr ! = Node ) & & ( nullptr ! = NodeClass ) )
{
FConstGraphHandle OwningGraph = this - > AsShared ( ) ;
FConstGraphAccessPtr GraphPtr = GraphClassPtr . GetGraph ( ) ;
switch ( NodeClass - > Metadata . GetType ( ) )
{
case EMetasoundFrontendClassType : : Input :
{
FConstClassInputAccessPtr OwningGraphClassInputPtr = FindInputDescriptionWithNodeID ( Node - > GetID ( ) ) ;
if ( nullptr ! = OwningGraphClassInputPtr . Get ( ) )
{
FInputNodeController : : FInitParams InitParams
{
ConstCastAccessPtr < FNodeAccessPtr > ( InNodeAndClass . Node ) ,
InNodeAndClass . Class ,
ConstCastAccessPtr < FClassInputAccessPtr > ( OwningGraphClassInputPtr ) ,
ConstCastAccessPtr < FGraphAccessPtr > ( GraphPtr ) ,
ConstCastSharedRef < IGraphController > ( OwningGraph )
} ;
return FInputNodeController : : CreateConstInputNodeHandle ( InitParams ) ;
}
}
break ;
case EMetasoundFrontendClassType : : Output :
{
FConstClassOutputAccessPtr OwningGraphClassOutputPtr = FindOutputDescriptionWithNodeID ( Node - > GetID ( ) ) ;
if ( nullptr ! = OwningGraphClassOutputPtr . Get ( ) )
{
FOutputNodeController : : FInitParams InitParams
{
ConstCastAccessPtr < FNodeAccessPtr > ( InNodeAndClass . Node ) ,
InNodeAndClass . Class ,
ConstCastAccessPtr < FClassOutputAccessPtr > ( OwningGraphClassOutputPtr ) ,
ConstCastAccessPtr < FGraphAccessPtr > ( GraphPtr ) ,
ConstCastSharedRef < IGraphController > ( OwningGraph )
} ;
return FOutputNodeController : : CreateConstOutputNodeHandle ( InitParams ) ;
}
}
break ;
2021-11-07 23:43:01 -05:00
case EMetasoundFrontendClassType : : Variable :
case EMetasoundFrontendClassType : : VariableAccessor :
2021-11-18 14:37:34 -05:00
case EMetasoundFrontendClassType : : VariableDeferredAccessor :
2021-11-07 23:43:01 -05:00
case EMetasoundFrontendClassType : : VariableMutator :
{
FVariableNodeController : : FInitParams InitParams
{
ConstCastAccessPtr < FNodeAccessPtr > ( InNodeAndClass . Node ) ,
InNodeAndClass . Class ,
ConstCastAccessPtr < FGraphAccessPtr > ( GraphPtr ) ,
ConstCastSharedRef < IGraphController > ( OwningGraph )
} ;
return FVariableNodeController : : CreateConstNodeHandle ( InitParams ) ;
}
break ;
2021-10-12 21:21:22 -04:00
case EMetasoundFrontendClassType : : External :
2022-08-10 14:18:10 -04:00
case EMetasoundFrontendClassType : : Template :
2021-10-12 21:21:22 -04:00
{
FNodeController : : FInitParams InitParams
{
ConstCastAccessPtr < FNodeAccessPtr > ( InNodeAndClass . Node ) ,
InNodeAndClass . Class ,
ConstCastAccessPtr < FGraphAccessPtr > ( GraphPtr ) ,
ConstCastSharedRef < IGraphController > ( OwningGraph )
} ;
return FNodeController : : CreateConstNodeHandle ( InitParams ) ;
}
break ;
2021-11-07 23:43:01 -05:00
case EMetasoundFrontendClassType : : Graph :
{
FSubgraphNodeController : : FInitParams InitParams
{
ConstCastAccessPtr < FNodeAccessPtr > ( InNodeAndClass . Node ) ,
InNodeAndClass . Class ,
ConstCastAccessPtr < FGraphAccessPtr > ( GraphPtr ) ,
ConstCastSharedRef < IGraphController > ( OwningGraph )
} ;
return FSubgraphNodeController : : CreateConstNodeHandle ( InitParams ) ;
}
break ;
2021-10-12 21:21:22 -04:00
default :
checkNoEntry ( ) ;
2022-08-10 14:18:10 -04:00
static_assert ( static_cast < int32 > ( EMetasoundFrontendClassType : : Invalid ) = = 10 , " Possible missing switch case coverage for EMetasoundFrontendClassType. " ) ;
2021-10-12 21:21:22 -04:00
}
}
return INodeController : : GetInvalidHandle ( ) ;
}
FMetasoundFrontendClassInput * FGraphController : : FindInputDescriptionWithName ( const FVertexName & InName )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
FMetasoundFrontendClassInput * ClassInput = GraphClass - > Interface . Inputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassInput & Desc ) { return Desc . Name = = InName ; } ) ;
if ( ClassInput )
{
// TODO: This assumes the class input is being mutated due to the adjacent const correct call not being utilized.
// Make this more explicit rather than risking whether or not the caller is using proper const correctness.
GraphClass - > Interface . UpdateChangeID ( ) ;
return ClassInput ;
}
}
return nullptr ;
}
const FMetasoundFrontendClassInput * FGraphController : : FindInputDescriptionWithName ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Interface . Inputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassInput & Desc ) { return Desc . Name = = InName ; } ) ;
}
return nullptr ;
}
FMetasoundFrontendClassOutput * FGraphController : : FindOutputDescriptionWithName ( const FVertexName & InName )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
FMetasoundFrontendClassOutput * ClassOutput = GraphClass - > Interface . Outputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassOutput & Desc ) { return Desc . Name = = InName ; } ) ;
if ( ClassOutput )
{
// TODO: This assumes the class input is being mutated due to the adjacent const correct call not being utilized.
// Make this more explicit rather than risking whether or not the caller is using proper const correctness.
GraphClass - > Interface . UpdateChangeID ( ) ;
return ClassOutput ;
}
}
return nullptr ;
}
const FMetasoundFrontendClassOutput * FGraphController : : FindOutputDescriptionWithName ( const FVertexName & InName ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Interface . Outputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassOutput & Desc ) { return Desc . Name = = InName ; } ) ;
}
return nullptr ;
}
FMetasoundFrontendClassInput * FGraphController : : FindInputDescriptionWithVertexID ( const FGuid & InVertexID )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
FMetasoundFrontendClassInput * ClassInput = GraphClass - > Interface . Inputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassInput & Desc ) { return Desc . VertexID = = InVertexID ; } ) ;
if ( ClassInput )
{
// TODO: This assumes the class input is being mutated due to the adjacent const correct call not being utilized.
// Make this more explicit rather than risking whether or not the caller is using proper const correctness.
GraphClass - > Interface . UpdateChangeID ( ) ;
return ClassInput ;
}
}
return nullptr ;
}
const FMetasoundFrontendClassInput * FGraphController : : FindInputDescriptionWithVertexID ( const FGuid & InVertexID ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Interface . Inputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassInput & Desc ) { return Desc . VertexID = = InVertexID ; } ) ;
}
return nullptr ;
}
FMetasoundFrontendClassOutput * FGraphController : : FindOutputDescriptionWithVertexID ( const FGuid & InVertexID )
{
if ( FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
FMetasoundFrontendClassOutput * ClassOutput = GraphClass - > Interface . Outputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassOutput & Desc ) { return Desc . VertexID = = InVertexID ; } ) ;
if ( ClassOutput )
{
// TODO: This assumes the class input is being mutated due to the adjacent const correct call not being utilized.
// Make this more explicit rather than risking whether or not the caller is using proper const correctness.
GraphClass - > Interface . UpdateChangeID ( ) ;
return ClassOutput ;
}
}
return nullptr ;
}
const FMetasoundFrontendClassOutput * FGraphController : : FindOutputDescriptionWithVertexID ( const FGuid & InVertexID ) const
{
if ( const FMetasoundFrontendGraphClass * GraphClass = GraphClassPtr . Get ( ) )
{
return GraphClass - > Interface . Outputs . FindByPredicate ( [ & ] ( const FMetasoundFrontendClassOutput & Desc ) { return Desc . VertexID = = InVertexID ; } ) ;
}
return nullptr ;
}
FClassInputAccessPtr FGraphController : : FindInputDescriptionWithNodeID ( FGuid InNodeID )
{
return GraphClassPtr . GetInputWithNodeID ( InNodeID ) ;
}
FConstClassInputAccessPtr FGraphController : : FindInputDescriptionWithNodeID ( FGuid InNodeID ) const
{
return GraphClassPtr . GetInputWithNodeID ( InNodeID ) ;
}
FClassOutputAccessPtr FGraphController : : FindOutputDescriptionWithNodeID ( FGuid InNodeID )
{
return GraphClassPtr . GetOutputWithNodeID ( InNodeID ) ;
}
FConstClassOutputAccessPtr FGraphController : : FindOutputDescriptionWithNodeID ( FGuid InNodeID ) const
{
return GraphClassPtr . GetOutputWithNodeID ( InNodeID ) ;
}
FDocumentAccess FGraphController : : ShareAccess ( )
{
FDocumentAccess Access ;
Access . GraphClass = GraphClassPtr ;
Access . ConstGraphClass = GraphClassPtr ;
return Access ;
}
FConstDocumentAccess FGraphController : : ShareAccess ( ) const
{
FConstDocumentAccess Access ;
Access . ConstGraphClass = GraphClassPtr ;
return Access ;
}
}
}
# undef LOCTEXT_NAMESPACE