2021-07-12 17:35:43 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "CoreMinimal.h"
# include "MetasoundBuilderInterface.h"
# include "MetasoundDataReferenceCollection.h"
# include "MetasoundExecutableOperator.h"
# include "MetasoundFacade.h"
# include "MetasoundNode.h"
# include "MetasoundNodeInterface.h"
# include "MetasoundNodeRegistrationMacro.h"
# include "MetasoundOperatorInterface.h"
# include "MetasoundPrimitives.h"
# include "MetasoundSampleCounter.h"
# include "MetasoundStandardNodesNames.h"
# include "MetasoundStandardNodesCategories.h"
# include "MetasoundParamHelper.h"
# define LOCTEXT_NAMESPACE "MetasoundStandardNodes_TriggerOnceNode"
namespace Metasound
{
namespace TriggerOnceVertexNames
{
METASOUND_PARAM ( InputEnter , " Trigger In " , " The input trigger. After the first time this is triggered, no subsequent triggers will pass through. " ) ;
METASOUND_PARAM ( InputReset , " Reset " , " When triggered, opens the node to allow another trigger through. " ) ;
METASOUND_PARAM ( InputStartClosed , " Start Closed " , " Whether the node should be closed when the Metasound begins. " ) ;
METASOUND_PARAM ( OutputExit , " Trigger Out " , " The output trigger. " ) ;
}
class FTriggerOnceOperator : public TExecutableOperator < FTriggerOnceOperator >
{
public :
static const FNodeClassMetadata & GetNodeInfo ( ) ;
static const FVertexInterface & GetVertexInterface ( ) ;
static TUniquePtr < IOperator > CreateOperator ( const FCreateOperatorParams & InParams , FBuildErrorArray & OutErrors ) ;
FTriggerOnceOperator ( const FOperatorSettings & InSettings ,
const FTriggerReadRef & InTriggerEnter ,
const FTriggerReadRef & InTriggerReset ,
const FBoolReadRef & InStartClosed ) ;
2023-05-22 13:28:27 -04:00
virtual void BindInputs ( FInputVertexInterfaceData & InOutVertexData ) override ;
virtual void BindOutputs ( FOutputVertexInterfaceData & InOutVertexData ) override ;
2021-07-12 17:35:43 -04:00
virtual FDataReferenceCollection GetInputs ( ) const override ;
virtual FDataReferenceCollection GetOutputs ( ) const override ;
void Execute ( ) ;
2023-03-02 14:40:35 -05:00
void Reset ( const IOperator : : FResetParams & InParams ) ;
2021-07-12 17:35:43 -04:00
private :
// Try to go through gate
FTriggerReadRef TriggerEnterInput ;
// Open the gate
FTriggerReadRef TriggerResetInput ;
// Whether the gate starts closed
FBoolReadRef bStartClosedInput ;
// If gate is open, sends trigger
FTriggerWriteRef TriggerExitOutput ;
// Status of the gate
bool bIsGateOpen ;
} ;
FTriggerOnceOperator : : FTriggerOnceOperator ( const FOperatorSettings & InSettings ,
const FTriggerReadRef & InTriggerEnter ,
const FTriggerReadRef & InTriggerReset ,
const FBoolReadRef & InStartClosed )
: TriggerEnterInput ( InTriggerEnter )
, TriggerResetInput ( InTriggerReset )
, bStartClosedInput ( InStartClosed )
, TriggerExitOutput ( FTriggerWriteRef : : CreateNew ( InSettings ) )
, bIsGateOpen ( ! * bStartClosedInput )
{
}
2023-05-22 13:28:27 -04:00
void FTriggerOnceOperator : : BindInputs ( FInputVertexInterfaceData & InOutVertexData )
2021-07-12 17:35:43 -04:00
{
using namespace TriggerOnceVertexNames ;
2023-05-22 13:28:27 -04:00
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputEnter ) , TriggerEnterInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputReset ) , TriggerResetInput ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputStartClosed ) , bStartClosedInput ) ;
}
2021-07-12 17:35:43 -04:00
2023-05-22 13:28:27 -04:00
void FTriggerOnceOperator : : BindOutputs ( FOutputVertexInterfaceData & InOutVertexData )
{
using namespace TriggerOnceVertexNames ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputExit ) , TriggerExitOutput ) ;
}
FDataReferenceCollection FTriggerOnceOperator : : GetInputs ( ) const
{
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
checkNoEntry ( ) ;
return { } ;
2021-07-12 17:35:43 -04:00
}
FDataReferenceCollection FTriggerOnceOperator : : GetOutputs ( ) const
{
2023-05-22 13:28:27 -04:00
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
checkNoEntry ( ) ;
return { } ;
2021-07-12 17:35:43 -04:00
}
void FTriggerOnceOperator : : Execute ( )
{
TriggerExitOutput - > AdvanceBlock ( ) ;
// Pass through trigger if gate is open
TriggerEnterInput - > ExecuteBlock (
[ ] ( int32 , int32 )
{
} ,
[ this ] ( int32 StartFrame , int32 EndFrame )
{
if ( bIsGateOpen )
{
bIsGateOpen = false ;
TriggerExitOutput - > TriggerFrame ( StartFrame ) ;
}
}
) ;
// Open Gate
TriggerResetInput - > ExecuteBlock (
[ ] ( int32 , int32 )
{
} ,
[ this ] ( int32 StartFrame , int32 EndFrame )
{
bIsGateOpen = true ;
}
) ;
}
2023-03-02 14:40:35 -05:00
void FTriggerOnceOperator : : Reset ( const IOperator : : FResetParams & InParams )
{
TriggerExitOutput - > Reset ( ) ;
bIsGateOpen = ! ( * bStartClosedInput ) ;
}
2021-07-12 17:35:43 -04:00
TUniquePtr < IOperator > FTriggerOnceOperator : : CreateOperator ( const FCreateOperatorParams & InParams , FBuildErrorArray & OutErrors )
{
using namespace TriggerOnceVertexNames ;
const FInputVertexInterface & InputInterface = GetVertexInterface ( ) . GetInputInterface ( ) ;
FTriggerReadRef TriggerEnterIn = InParams . InputDataReferences . GetDataReadReferenceOrConstruct < FTrigger > ( METASOUND_GET_PARAM_NAME ( InputEnter ) , InParams . OperatorSettings ) ;
FTriggerReadRef TriggerResetIn = InParams . InputDataReferences . GetDataReadReferenceOrConstruct < FTrigger > ( METASOUND_GET_PARAM_NAME ( InputReset ) , InParams . OperatorSettings ) ;
FBoolReadRef bStartClosedIn = InParams . InputDataReferences . GetDataReadReferenceOrConstructWithVertexDefault < bool > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputStartClosed ) , InParams . OperatorSettings ) ;
return MakeUnique < FTriggerOnceOperator > ( InParams . OperatorSettings , TriggerEnterIn , TriggerResetIn , bStartClosedIn ) ;
}
const FVertexInterface & FTriggerOnceOperator : : GetVertexInterface ( )
{
using namespace TriggerOnceVertexNames ;
static const FVertexInterface Interface (
FInputVertexInterface (
2022-03-31 16:49:59 -04:00
TInputDataVertex < FTrigger > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputEnter ) ) ,
TInputDataVertex < FTrigger > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputReset ) ) ,
TInputDataVertex < bool > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputStartClosed ) , false )
2021-07-12 17:35:43 -04:00
) ,
FOutputVertexInterface (
2022-03-31 16:49:59 -04:00
TOutputDataVertex < FTrigger > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputExit ) )
2021-07-12 17:35:43 -04:00
)
) ;
return Interface ;
}
const FNodeClassMetadata & FTriggerOnceOperator : : GetNodeInfo ( )
{
auto InitNodeInfo = [ ] ( ) - > FNodeClassMetadata
{
FNodeClassMetadata Info ;
2021-08-09 16:56:05 -04:00
Info . ClassName = { Metasound : : StandardNodes : : Namespace , " Trigger Once " , FName ( ) } ;
2021-07-12 17:35:43 -04:00
Info . MajorVersion = 1 ;
Info . MinorVersion = 0 ;
2022-02-10 18:36:47 -05:00
Info . DisplayName = METASOUND_LOCTEXT ( " Metasound_TriggerOnceNodeDisplayName " , " Trigger Once " ) ;
Info . Description = METASOUND_LOCTEXT ( " Metasound_TriggerOnceNodeDescription " , " Sends an output trigger the first time the node is triggered, and ignores all others (can be re-opened). " ) ;
2021-07-12 17:35:43 -04:00
Info . Author = PluginAuthor ;
Info . PromptIfMissing = PluginNodeMissingPrompt ;
Info . DefaultInterface = GetVertexInterface ( ) ;
2021-08-09 16:56:05 -04:00
Info . CategoryHierarchy . Emplace ( NodeCategories : : Trigger ) ;
2021-07-12 17:35:43 -04:00
return Info ;
} ;
static const FNodeClassMetadata Info = InitNodeInfo ( ) ;
return Info ;
}
// Node Class
class FTriggerOnceNode : public FNodeFacade
{
public :
FTriggerOnceNode ( const FNodeInitData & InitData )
: FNodeFacade ( InitData . InstanceName , InitData . InstanceID , TFacadeOperatorClass < FTriggerOnceOperator > ( ) )
{
}
} ;
METASOUND_REGISTER_NODE ( FTriggerOnceNode )
}
# undef LOCTEXT_NAMESPACE