// 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); template class TTriggerCompareNodeOperator : public TExecutableOperator> { public: static const FVertexInterface& GetDefaultInterface() { using namespace TriggerCompareVertexNames; using namespace MetasoundTriggerCompareNodePrivate; static const FVertexInterface DefaultInterface( FInputVertexInterface( TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputCompare)), TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputParamA)), TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputParamB)), TInputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(InputCompareType), (int32)ETriggerComparisonType::Equals) ), FOutputVertexInterface( TOutputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(OutputOnTrue)), TOutputDataVertex(METASOUND_GET_PARAM_NAME_AND_METADATA(OutputOnFalse)) ) ); return DefaultInterface; } static const FNodeClassMetadata& GetNodeInfo() { auto CreateNodeClassMetadata = []() -> FNodeClassMetadata { const FName DataTypeName = GetMetasoundDataTypeName(); const FName OperatorName = TEXT("Clamp"); const FText NodeDisplayName = METASOUND_LOCTEXT_FORMAT("TriggerCompareDisplayPattern", "Trigger Compare ({0})", GetMetasoundDataTypeDisplayText()); const FText NodeDescription = METASOUND_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 FBuildOperatorParams& InParams, FBuildResults& OutResults) { using namespace TriggerCompareVertexNames; const FInputVertexInterfaceData& InputData = InParams.InputData; FTriggerReadRef InOnTriggerCompare = InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputCompare), InParams.OperatorSettings); TDataReadReference InValueA = InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputParamA), InParams.OperatorSettings); TDataReadReference InValueB = InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputParamB), InParams.OperatorSettings); FEnumTriggerComparisonTypeReadRef InComparison = InputData.GetOrCreateDefaultDataReadReference(METASOUND_GET_PARAM_NAME(InputCompareType), InParams.OperatorSettings); 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 void BindInputs(FInputVertexInterfaceData& InOutVertexData) override { using namespace TriggerCompareVertexNames; InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputCompare), OnCompareTrigger); InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputParamA), ValueA); InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputParamB), ValueB); InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(InputCompareType), TriggerComparisonType); } virtual void BindOutputs(FOutputVertexInterfaceData& InOutVertexData) override { using namespace TriggerCompareVertexNames; InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(OutputOnTrue), TriggerOutOnTrue); InOutVertexData.BindReadVertex(METASOUND_GET_PARAM_NAME(OutputOnFalse), TriggerOutOnFalse); } 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); } } ); } void Reset(const IOperator::FResetParams& InParams) { TriggerOutOnTrue->Reset(); TriggerOutOnFalse->Reset(); } private: FTriggerReadRef OnCompareTrigger; TDataReadReference ValueA; TDataReadReference ValueB; FEnumTriggerComparisonTypeReadRef TriggerComparisonType; FTriggerWriteRef TriggerOutOnTrue; FTriggerWriteRef TriggerOutOnFalse; }; /** TTriggerCompareNode * * Compares two inputs against enumerated comparison types. */ template using TTriggerCompareNode = TNodeFacade>; } #undef LOCTEXT_NAMESPACE