2020-07-20 00:05:22 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# pragma once
# include "CoreMinimal.h"
2021-01-13 10:48:59 -04:00
# include "MetasoundFrontend.h"
# include "MetasoundFrontendDocument.h"
# include "MetasoundFrontendRegistries.h"
2021-04-02 03:03:27 -04:00
# include "MetasoundLog.h"
2020-07-20 00:05:22 -04:00
# include "MetasoundNodeInterface.h"
2020-12-14 15:48:27 -04:00
namespace Metasound
2020-07-20 00:05:22 -04:00
{
2020-12-14 15:48:27 -04:00
// Utility class to ensure that a node class can use the constructor the frontend uses.
template < typename NodeClass >
struct ConstructorTakesNodeInitData {
// Use SFINAE trick to see if we have a valid constructor:
template < typename T >
static uint16 TestForConstructor ( decltype ( T ( : : Metasound : : FNodeInitData ( ) ) ) * ) ;
template < typename T >
static uint8 TestForConstructor ( . . . ) ;
static const bool Value = sizeof ( TestForConstructor < NodeClass > ( nullptr ) ) = = sizeof ( uint16 ) ;
} ;
template < typename FNodeType >
2021-01-28 19:02:51 -04:00
bool RegisterNodeWithFrontend ( const Metasound : : FNodeClassMetadata & InMetadata )
2020-07-20 00:05:22 -04:00
{
2020-12-14 15:48:27 -04:00
// if we reenter this code (because DECLARE_METASOUND_DATA_REFERENCE_TYPES was called twice with the same type),
// we catch it here.
static bool bAlreadyRegisteredThisDataType = false ;
if ( bAlreadyRegisteredThisDataType )
{
2021-04-02 03:03:27 -04:00
UE_LOG ( LogMetaSound , Display , TEXT ( " Tried to call METASOUND_REGISTER_NODE twice with the same class. ignoring the second call. Likely because METASOUND_REGISTER_NODE is in a header that's used in multiple modules. Consider moving it to a private header or cpp file. " ) ) ;
2020-12-14 15:48:27 -04:00
return false ;
}
bAlreadyRegisteredThisDataType = true ;
2021-06-14 16:45:51 -04:00
// Node registry entry specialized to FNodeType.
class FNodeRegistryEntry : public Frontend : : INodeRegistryEntry
{
public :
FNodeRegistryEntry ( const Metasound : : FNodeClassMetadata & InMetadata )
: ClassInfo ( InMetadata )
, FrontendClass ( Metasound : : Frontend : : GenerateClassDescription ( InMetadata ) )
2020-12-14 15:48:27 -04:00
{
}
2021-06-14 16:45:51 -04:00
virtual ~ FNodeRegistryEntry ( ) = default ;
virtual const Frontend : : FNodeClassInfo & GetClassInfo ( ) const override
{
return ClassInfo ;
}
virtual TUniquePtr < INode > CreateNode ( FDefaultNodeConstructorParams & & InParams ) const override
{
return nullptr ;
}
virtual TUniquePtr < INode > CreateNode ( FDefaultLiteralNodeConstructorParams & & InParams ) const override
{
return nullptr ;
}
virtual TUniquePtr < INode > CreateNode ( const FNodeInitData & InParams ) const override
{
return MakeUnique < FNodeType > ( InParams ) ;
}
virtual const FMetasoundFrontendClass & GetFrontendClass ( ) const override
{
return FrontendClass ;
}
virtual TUniquePtr < INodeRegistryEntry > Clone ( ) const
{
return MakeUnique < FNodeRegistryEntry > ( * this ) ;
}
private :
Frontend : : FNodeClassInfo ClassInfo ;
FMetasoundFrontendClass FrontendClass ;
} ;
Frontend : : FNodeRegistryKey Key = FMetasoundFrontendRegistryContainer : : Get ( ) - > RegisterNode ( MakeUnique < FNodeRegistryEntry > ( InMetadata ) ) ;
2021-06-08 10:52:31 -04:00
const bool bSuccessfullyRegisteredNode = Frontend : : IsValidNodeRegistryKey ( Key ) ;
2020-12-14 15:48:27 -04:00
ensureAlwaysMsgf ( bSuccessfullyRegisteredNode , TEXT ( " Registering node class failed. Please check the logs. " ) ) ;
2021-06-14 16:45:51 -04:00
2020-12-14 15:48:27 -04:00
return bSuccessfullyRegisteredNode ;
2020-07-20 00:05:22 -04:00
}
2020-12-14 15:48:27 -04:00
template < typename FNodeType >
bool RegisterNodeWithFrontend ( )
{
// Register a node using a prototype node.
// TODO: may want to add a warning here since we don't want to use this registration pathway.
Metasound : : FNodeInitData InitData ;
TUniquePtr < Metasound : : INode > Node = MakeUnique < FNodeType > ( InitData ) ;
return RegisterNodeWithFrontend < FNodeType > ( Node - > GetMetadata ( ) ) ;
}
2020-11-24 15:24:29 -04:00
}
2020-12-14 15:48:27 -04:00
// TODO: should remove this and force folks to use module startup/shutdown module system.
2020-11-24 15:24:29 -04:00
# define METASOUND_REGISTER_NODE(NodeClass, ...) \
2020-07-20 00:05:22 -04:00
static_assert ( std : : is_base_of < : : Metasound : : INodeBase , NodeClass > : : value , " To be registered as a Metasound Node, " # NodeClass " need to be a derived class from Metasound::INodeBase, Metasound::INode, or Metasound::FNode. " ) ; \
2020-12-14 15:48:27 -04:00
static_assert ( : : Metasound : : ConstructorTakesNodeInitData < NodeClass > : : Value , " In order to be registered as a Metasound Node, " # NodeClass " needs to implement the following public constructor: " # NodeClass " (const Metasound::FNodeInitData& InInitData); " ) ; \
static bool bSuccessfullyRegistered # # NodeClass = FMetasoundFrontendRegistryContainer : : Get ( ) - > EnqueueInitCommand ( [ ] ( ) { : : Metasound : : RegisterNodeWithFrontend < NodeClass > ( __VA_ARGS__ ) ; } ) ; // This static bool is useful for debugging, but also is the only way the compiler will let us call this function outside of an expression.
2020-07-20 00:05:22 -04:00