// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CurveModel.h" #include namespace UE::CurveEditor { template requires std::is_base_of_v class TInvertedCurveModel : public TBase { public: template explicit TInvertedCurveModel(TArg&&... Arg); virtual void DrawCurve(const FCurveEditor& CurveEditor, const FCurveEditorScreenSpace& ScreenSpace, TArray>& InterpolatingPoints) const override; virtual void GetKeys(double MinTime, double MaxTime, double MinValue, double MaxValue, TArray& OutKeyHandles) const override; virtual void AddKeys(TArrayView InPositions, TArrayView InAttributes, TArrayView>* OutKeyHandles = nullptr) override; virtual void GetKeyPositions(TArrayView InKeys, TArrayView OutKeyPositions) const override; virtual void SetKeyPositions(TArrayView InKeys, TArrayView InKeyPositions, EPropertyChangeType::Type ChangeType = EPropertyChangeType::Unspecified) override; virtual void GetKeyDrawInfo(ECurvePointType PointType, const FKeyHandle InKeyHandle, FKeyDrawInfo& OutDrawInfo) const override; virtual void GetValueRange(double& MinValue, double& MaxValue) const override; virtual bool Evaluate(double InTime, double& OutValue) const override; virtual void GetKeyAttributes(TArrayView InKeys, TArrayView OutAttributes) const override; virtual void GetKeyAttributesIncludingAutoComputed(TArrayView InKeys, TArrayView OutAttributes) const override; virtual void GetKeyAttributesExcludingAutoComputed(TArrayView InKeys, TArrayView OutAttributes) const override; virtual void SetKeyAttributes(TArrayView InKeys, TArrayView InAttributes, EPropertyChangeType::Type ChangeType = EPropertyChangeType::Unspecified) override; virtual TUniquePtr CreateBufferedCurveCopy() const override; }; } namespace UE::CurveEditor { namespace Private { static FKeyPosition InvertKeyPosition(const FKeyPosition& KeyPosition) { return FKeyPosition(KeyPosition.InputValue, -KeyPosition.OutputValue); } template static void InvertKeyPositions(const InT& Input, OutT&& Output) { Algo::Transform(Input, Output, [](const FKeyPosition& KeyPosition) { return InvertKeyPosition(KeyPosition); }); } static void InvertKeyPositions(TArrayView Output) { for (int32 Index = 0; Index < Output.Num(); ++Index) { Output[Index] = InvertKeyPosition(Output[Index]); } } static float InvertTangent(float Tangent) { const float Angle = FMath::Atan(Tangent); return FMath::Tan(-Angle); } static FKeyAttributes InvertKeyAttributes(FKeyAttributes Attributes) { if (Attributes.HasArriveTangent()) { Attributes.SetArriveTangent(InvertTangent(Attributes.GetArriveTangent())); } if (Attributes.HasLeaveTangent()) { Attributes.SetLeaveTangent(InvertTangent(Attributes.GetLeaveTangent())); } return Attributes; } template static void InvertKeyAttributes(const InT& Input, OutT&& Output) { Algo::Transform(Input, Output, [](const FKeyAttributes& Attributes) { return InvertKeyAttributes(Attributes); }); } static void InvertKeyAttributes(TArrayView Output) { for (int32 Index = 0; Index < Output.Num(); ++Index) { Output[Index] = InvertKeyAttributes(Output[Index]); } } static TArray CopyAndInvertKeyPositionsFromBuffer(const IBufferedCurveModel& RealBuffer) { TArray KeyPositions; RealBuffer.GetKeyPositions(KeyPositions); InvertKeyPositions(KeyPositions); return KeyPositions; } static TArray CopyAndInvertKeyAttributesFromBuffer(const IBufferedCurveModel& RealBuffer) { TArray KeyPositions; RealBuffer.GetKeyAttributes(KeyPositions); InvertKeyAttributes(KeyPositions); return KeyPositions; } } template requires std::is_base_of_v template TInvertedCurveModel::TInvertedCurveModel(TArg&&... Arg) : TBase(Forward(Arg)...) {} template requires std::is_base_of_v void TInvertedCurveModel::DrawCurve( const FCurveEditor& CurveEditor, const FCurveEditorScreenSpace& ScreenSpace, TArray>& InterpolatingPoints ) const { TBase::DrawCurve(CurveEditor, ScreenSpace, InterpolatingPoints); for (int32 Index = 0; Index < InterpolatingPoints.Num(); ++Index) { InterpolatingPoints[Index].Value = -InterpolatingPoints[Index].Value; } } template requires std::is_base_of_v void TInvertedCurveModel::GetKeys(double MinTime, double MaxTime, double MinValue, double MaxValue, TArray& OutKeyHandles) const { const double AdjustedMin = FMath::Min(-MinValue, -MaxValue); const double AdjustedMax = FMath::Max(-MinValue, -MaxValue); TBase::GetKeys(MinTime, MaxTime, AdjustedMin, AdjustedMax, OutKeyHandles); } template requires std::is_base_of_v void TInvertedCurveModel::AddKeys( TArrayView InPositions, TArrayView InAttributes, TArrayView>* OutKeyHandles ) { TArray InvertedCopy; TArray InvertedAttributes; Private::InvertKeyPositions(InPositions, InvertedCopy); Private::InvertKeyAttributes(InAttributes, InvertedAttributes); TBase::AddKeys(InvertedCopy, InvertedAttributes, OutKeyHandles); } template requires std::is_base_of_v void TInvertedCurveModel::GetKeyPositions(TArrayView InKeys, TArrayView OutKeyPositions) const { TBase::GetKeyPositions(InKeys, OutKeyPositions); Private::InvertKeyPositions(OutKeyPositions); } template requires std::is_base_of_v void TInvertedCurveModel::SetKeyPositions( TArrayView InKeys, TArrayView InKeyPositions, EPropertyChangeType::Type ChangeType ) { TArray InvertedCopy; Private::InvertKeyPositions(InKeyPositions, InvertedCopy); TBase::SetKeyPositions(InKeys, InvertedCopy, ChangeType); } template requires std::is_base_of_v void TInvertedCurveModel::GetKeyDrawInfo(ECurvePointType PointType, const FKeyHandle InKeyHandle, FKeyDrawInfo& OutDrawInfo) const { TBase::GetKeyDrawInfo(PointType, InKeyHandle, OutDrawInfo); } template requires std::is_base_of_v void TInvertedCurveModel::GetValueRange(double& MinValue, double& MaxValue) const { double RealMin, RealMax; TBase::GetValueRange(RealMin, RealMax); MinValue = FMath::Min(-RealMin, -RealMax); MaxValue = FMath::Max(-RealMin, -RealMax); } template requires std::is_base_of_v bool TInvertedCurveModel::Evaluate(double InTime, double& OutValue) const { if (TBase::Evaluate(InTime, OutValue)) { OutValue = -OutValue; return true; } return true; } template requires std::is_base_of_v void TInvertedCurveModel::GetKeyAttributes(TArrayView InKeys, TArrayView OutAttributes) const { TBase::GetKeyAttributes(InKeys, OutAttributes); Private::InvertKeyAttributes(OutAttributes); } template requires std::is_base_of_v void TInvertedCurveModel::GetKeyAttributesIncludingAutoComputed(TArrayView InKeys, TArrayView OutAttributes) const { TBase::GetKeyAttributesIncludingAutoComputed(InKeys, OutAttributes); Private::InvertKeyAttributes(OutAttributes); } template requires std::is_base_of_v void TInvertedCurveModel::GetKeyAttributesExcludingAutoComputed(TArrayView InKeys, TArrayView OutAttributes) const { TBase::GetKeyAttributesExcludingAutoComputed(InKeys, OutAttributes); Private::InvertKeyAttributes(OutAttributes); } template requires std::is_base_of_v void TInvertedCurveModel::SetKeyAttributes( TArrayView InKeys, TArrayView InAttributes, EPropertyChangeType::Type ChangeType ) { TArray InvertedAttributes; Private::InvertKeyAttributes(InAttributes, InvertedAttributes); TBase::SetKeyAttributes(InKeys, InvertedAttributes, ChangeType); } template requires std::is_base_of_v TUniquePtr TInvertedCurveModel::CreateBufferedCurveCopy() const { // Not supported return nullptr; } }