// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "MetasoundBuilderInterface.h" #include "MetasoundDataReferenceCollection.h" #include "MetasoundEnumRegistrationMacro.h" #include "MetasoundExecutableOperator.h" #include "MetasoundFacade.h" #include "MetasoundNode.h" #include "MetasoundNodeInterface.h" #include "MetasoundNodeRegistrationMacro.h" #include "MetasoundDataTypeRegistrationMacro.h" #include "MetasoundOperatorInterface.h" #include "MetasoundPrimitives.h" #include "MetasoundStandardNodesNames.h" #include "MetasoundStandardNodesCategories.h" #include "MetasoundParamHelper.h" #define LOCTEXT_NAMESPACE "MetasoundStandardNodes_CompareNode" namespace Metasound { namespace TriggerCompareVertexNames { METASOUND_PARAM(InputCompare, "Compare", "Trigger to compare A and B."); METASOUND_PARAM(InputParamA, "A", "The first value, A, to compare against."); METASOUND_PARAM(InputParamB, "B", "The first value, B, to compare against."); METASOUND_PARAM(InputCompareType, "Type", "How to compare A and B."); METASOUND_PARAM(OutputOnTrue, "True", "Output trigger for when the comparison is true."); METASOUND_PARAM(OutputOnFalse, "False", "Output trigger for when the comparison is false."); } namespace MetasoundTriggerCompareNodePrivate { METASOUNDSTANDARDNODES_API FNodeClassMetadata CreateNodeClassMetadata(const FName& InDataTypeName, const FName& InOperatorName, const FText& InDisplayName, const FText& InDescription, const FVertexInterface& InDefaultInterface); } enum class ETriggerComparisonType { Equals, NotEquals, LessThan, GreaterThan, LessThanOrEquals, GreaterThanOrEquals }; DECLARE_METASOUND_ENUM(ETriggerComparisonType, ETriggerComparisonType::Equals, METASOUNDSTANDARDNODES_API, FEnumTriggerComparisonType, FEnumTriggerComparisonTypeInfo, FEnumTriggerComparisonTypeReadRef, FEnumTriggerComparisonTypeWriteRef); DEFINE_METASOUND_ENUM_BEGIN(ETriggerComparisonType, FEnumTriggerComparisonType, "TriggerComparisonType") DEFINE_METASOUND_ENUM_ENTRY(ETriggerComparisonType::Equals, LOCTEXT("EqualsDescription", "Equals"), LOCTEXT("EqualsDescriptionTT", "True if A and B are equal.")), DEFINE_METASOUND_ENUM_ENTRY(ETriggerComparisonType::NotEquals, LOCTEXT("NotEqualsDescriptioin", "Not Equals"), LOCTEXT("NotEqualsTT", "True if A and B are not equal.")), DEFINE_METASOUND_ENUM_ENTRY(ETriggerComparisonType::LessThan, LOCTEXT("LessThanDescription", "Less Than"), LOCTEXT("LessThanTT", "True if A is less than B.")), DEFINE_METASOUND_ENUM_ENTRY(ETriggerComparisonType::GreaterThan, LOCTEXT("GreaterThanDescription", "Greater Than"), LOCTEXT("GreaterThanTT", "True if A is greater than B.")), DEFINE_METASOUND_ENUM_ENTRY(ETriggerComparisonType::LessThanOrEquals, LOCTEXT("LessThanOrEqualsDescription", "Less Than Or Equals"), LOCTEXT("LessThanOrEqualsTT", "True if A is less than or equal to B.")), DEFINE_METASOUND_ENUM_ENTRY(ETriggerComparisonType::GreaterThanOrEquals, LOCTEXT("GreaterThanOrEqualsDescription", "Greater Than Or Equals"), LOCTEXT("GreaterThanOrEqualsTT", "True if A is greater than or equal to B.")), DEFINE_METASOUND_ENUM_END() template class TTriggerCompareNodeOperator : public TExecutableOperator> { public: static const FVertexInterface& GetDefaultInterface() { using namespace TriggerCompareVertexNames; using namespace MetasoundTriggerCompareNodePrivate; static const FVertexInterface DefaultInterface( FInputVertexInterface( TInputDataVertexModel(METASOUND_GET_PARAM_NAME_AND_TT(InputCompare)), TInputDataVertexModel(METASOUND_GET_PARAM_NAME_AND_TT(InputParamA)), TInputDataVertexModel(METASOUND_GET_PARAM_NAME_AND_TT(InputParamB)), TInputDataVertexModel(METASOUND_GET_PARAM_NAME_AND_TT(InputCompareType)) ), FOutputVertexInterface( TOutputDataVertexModel(METASOUND_GET_PARAM_NAME_AND_TT(OutputOnTrue)), TOutputDataVertexModel(METASOUND_GET_PARAM_NAME_AND_TT(OutputOnFalse)) ) ); return DefaultInterface; } static const FNodeClassMetadata& GetNodeInfo() { auto CreateNodeClassMetadata = []() -> FNodeClassMetadata { const FName DataTypeName = GetMetasoundDataTypeName(); const FName OperatorName = TEXT("Clamp"); const FText NodeDisplayName = FText::Format(LOCTEXT("TriggerCompareDisplayPattern", "Trigger Compare ({0})"), GetMetasoundDataTypeDisplayText()); const FText NodeDescription = LOCTEXT("TriggerCompareDisc", "Output triggers (True or False) based on comparing inputs, A and B."); const FVertexInterface NodeInterface = GetDefaultInterface(); return MetasoundTriggerCompareNodePrivate::CreateNodeClassMetadata(DataTypeName, OperatorName, NodeDisplayName, NodeDescription, NodeInterface); }; static const FNodeClassMetadata Metadata = CreateNodeClassMetadata(); return Metadata; } static TUniquePtr CreateOperator(const FCreateOperatorParams& InParams, TArray>& OutErrors) { using namespace TriggerCompareVertexNames; const FDataReferenceCollection& InputCollection = InParams.InputDataReferences; const FInputVertexInterface& InputInterface = GetDefaultInterface().GetInputInterface(); FTriggerReadRef InOnTriggerCompare = InputCollection.GetDataReadReferenceOrConstruct(METASOUND_GET_PARAM_NAME(InputCompare), InParams.OperatorSettings); TDataReadReference InValueA = InputCollection.GetDataReadReferenceOrConstructWithVertexDefault(InputInterface, METASOUND_GET_PARAM_NAME(InputParamA), InParams.OperatorSettings); TDataReadReference InValueB = InputCollection.GetDataReadReferenceOrConstructWithVertexDefault(InputInterface, METASOUND_GET_PARAM_NAME(InputParamB), InParams.OperatorSettings); FEnumTriggerComparisonTypeReadRef InComparison = InputCollection.GetDataReadReferenceOrConstruct(METASOUND_GET_PARAM_NAME(InputCompareType)); return MakeUnique>(InParams.OperatorSettings, InOnTriggerCompare, InValueA, InValueB, InComparison); } TTriggerCompareNodeOperator( const FOperatorSettings& InSettings, const FTriggerReadRef& InOnCompareTrigger, const TDataReadReference& InValueA, const TDataReadReference& InValueB, const FEnumTriggerComparisonTypeReadRef& InTriggerComparisonType) : OnCompareTrigger(InOnCompareTrigger) , ValueA(InValueA) , ValueB(InValueB) , TriggerComparisonType(InTriggerComparisonType) , TriggerOutOnTrue(FTriggerWriteRef::CreateNew(InSettings)) , TriggerOutOnFalse(FTriggerWriteRef::CreateNew(InSettings)) { } virtual ~TTriggerCompareNodeOperator() = default; virtual FDataReferenceCollection GetInputs() const override { using namespace TriggerCompareVertexNames; FDataReferenceCollection Inputs; Inputs.AddDataReadReference(METASOUND_GET_PARAM_NAME(InputCompare), OnCompareTrigger); Inputs.AddDataReadReference(METASOUND_GET_PARAM_NAME(InputParamA), ValueA); Inputs.AddDataReadReference(METASOUND_GET_PARAM_NAME(InputParamB), ValueB); Inputs.AddDataReadReference(METASOUND_GET_PARAM_NAME(InputCompareType), TriggerComparisonType); return Inputs; } virtual FDataReferenceCollection GetOutputs() const override { using namespace TriggerCompareVertexNames; FDataReferenceCollection Outputs; Outputs.AddDataReadReference(METASOUND_GET_PARAM_NAME(OutputOnTrue), TriggerOutOnTrue); Outputs.AddDataReadReference(METASOUND_GET_PARAM_NAME(OutputOnFalse), TriggerOutOnFalse); return Outputs; } void Execute() { TriggerOutOnTrue->AdvanceBlock(); TriggerOutOnFalse->AdvanceBlock(); OnCompareTrigger->ExecuteBlock( [&](int32 StartFrame, int32 EndFrame) { }, [this](int32 StartFrame, int32 EndFrame) { ValueType CurrValA = *ValueA; ValueType CurrValB = *ValueB; bool bIsTrue = false; switch (*TriggerComparisonType) { case ETriggerComparisonType::Equals: bIsTrue = (CurrValA == CurrValB); break; case ETriggerComparisonType::NotEquals: bIsTrue = (CurrValA != CurrValB); break; case ETriggerComparisonType::LessThan: bIsTrue = (CurrValA < CurrValB); break; case ETriggerComparisonType::GreaterThan: bIsTrue = (CurrValA > CurrValB); break; case ETriggerComparisonType::LessThanOrEquals: bIsTrue = (CurrValA <= CurrValB); break; case ETriggerComparisonType::GreaterThanOrEquals: bIsTrue = (CurrValA >= CurrValB); break; } if (bIsTrue) { TriggerOutOnTrue->TriggerFrame(StartFrame); } else { TriggerOutOnFalse->TriggerFrame(StartFrame); } } ); } private: FTriggerReadRef OnCompareTrigger; TDataReadReference ValueA; TDataReadReference ValueB; FEnumTriggerComparisonTypeReadRef TriggerComparisonType; FTriggerWriteRef TriggerOutOnTrue; FTriggerWriteRef TriggerOutOnFalse; }; /** TTriggerCompareNode * * Compares two inputs against enumerated comparison types. */ template class METASOUNDSTANDARDNODES_API TTriggerCompareNode : public FNodeFacade { public: /** * Constructor used by the Metasound Frontend. */ TTriggerCompareNode(const FNodeInitData& InInitData) : FNodeFacade(InInitData.InstanceName, InInitData.InstanceID, TFacadeOperatorClass>()) {} virtual ~TTriggerCompareNode() = default; }; } #undef LOCTEXT_NAMESPACE