// Copyright Epic Games, Inc. All Rights Reserved. #include "Channels/ByteChannelCurveModel.h" #include "Algo/BinarySearch.h" #include "Channels/CurveModelHelpers.h" #include "Channels/ByteChannelKeyProxy.h" #include "Channels/MovieSceneChannelData.h" #include "Channels/MovieSceneChannelHandle.h" #include "Channels/MovieSceneByteChannel.h" #include "Containers/Array.h" #include "Containers/UnrealString.h" #include "CurveDataAbstraction.h" #include "CurveEditorScreenSpace.h" #include "Curves/KeyHandle.h" #include "HAL/PlatformCrt.h" #include "IBufferedCurveModel.h" #include "Internationalization/Text.h" #include "Math/Range.h" #include "Misc/FrameNumber.h" #include "Misc/FrameRate.h" #include "Misc/FrameTime.h" #include "MovieScene.h" #include "MovieSceneSection.h" #include "Templates/Casts.h" #include "Templates/Tuple.h" #include "Templates/UnrealTemplate.h" #include "UObject/Package.h" #include "UObject/UObjectGlobals.h" #include "UObject/UnrealNames.h" #include "UObject/WeakObjectPtr.h" #include "UObject/WeakObjectPtrTemplates.h" class FCurveEditor; class UObject; /** * Buffered curve implementation for a byte channel curve model, stores a copy of the byte channel in order to draw itself. */ class FByteChannelBufferedCurveModel : public IBufferedCurveModel { public: /** Create a copy of the byte channel while keeping the reference to the section */ FByteChannelBufferedCurveModel(const FMovieSceneByteChannel* InMovieSceneByteChannel, TWeakObjectPtr InWeakSection, TArray&& InKeyPositions, TArray&& InKeyAttributes, const FString& InLongDisplayName, const double InValueMin, const double InValueMax) : IBufferedCurveModel(MoveTemp(InKeyPositions), MoveTemp(InKeyAttributes), InLongDisplayName, InValueMin, InValueMax) , Channel(*InMovieSceneByteChannel) , WeakSection(InWeakSection) {} virtual void DrawCurve(const FCurveEditor& InCurveEditor, const FCurveEditorScreenSpace& InScreenSpace, TArray>& OutInterpolatingPoints) const override { UMovieSceneSection* Section = WeakSection.Get(); if (Section) { FFrameRate TickResolution = Section->GetTypedOuter()->GetTickResolution(); TMovieSceneChannelData ChannelData = Channel.GetData(); TArrayView Times = ChannelData.GetTimes(); TArrayView Values = ChannelData.GetValues(); const double StartTimeSeconds = InScreenSpace.GetInputMin(); const double EndTimeSeconds = InScreenSpace.GetInputMax(); const FFrameNumber StartFrame = (StartTimeSeconds * TickResolution).FloorToFrame(); const FFrameNumber EndFrame = (EndTimeSeconds * TickResolution).CeilToFrame(); const int32 StartingIndex = Algo::UpperBound(Times, StartFrame); const int32 EndingIndex = Algo::LowerBound(Times, EndFrame); for (int32 KeyIndex = StartingIndex; KeyIndex < EndingIndex; ++KeyIndex) { OutInterpolatingPoints.Add(MakeTuple(Times[KeyIndex] / TickResolution, double(Values[KeyIndex]))); } } } virtual bool Evaluate(double InTime, double& OutValue) const override { return UE::MovieSceneTools::CurveHelpers::Evaluate(InTime, OutValue, Channel, WeakSection); } private: FMovieSceneByteChannel Channel; TWeakObjectPtr WeakSection; }; FByteChannelCurveModel::FByteChannelCurveModel(TMovieSceneChannelHandle InChannel, UMovieSceneSection* OwningSection, TWeakPtr InWeakSequencer) : FChannelCurveModel(InChannel, OwningSection, InWeakSequencer) { } void FByteChannelCurveModel::CreateKeyProxies(TArrayView InKeyHandles, TArrayView OutObjects) { for (int32 Index = 0; Index < InKeyHandles.Num(); ++Index) { UByteChannelKeyProxy* NewProxy = NewObject(GetTransientPackage(), NAME_None); NewProxy->Initialize(InKeyHandles[Index], GetChannelHandle(), this->GetOwningObjectOrOuter()); OutObjects[Index] = NewProxy; } } TUniquePtr FByteChannelCurveModel::CreateBufferedCurveCopy() const { FMovieSceneByteChannel* Channel = GetChannelHandle().Get(); if (Channel) { TArray TargetKeyHandles; TMovieSceneChannelData ChannelData = Channel->GetData(); TRange TotalRange = ChannelData.GetTotalRange(); ChannelData.GetKeys(TotalRange, nullptr, &TargetKeyHandles); TArray KeyPositions; KeyPositions.SetNumUninitialized(GetNumKeys()); TArray KeyAttributes; KeyAttributes.SetNumUninitialized(GetNumKeys()); GetKeyPositions(TargetKeyHandles, KeyPositions); GetKeyAttributes(TargetKeyHandles, KeyAttributes); double ValueMin = 0.f, ValueMax = 1.f; GetValueRange(ValueMin, ValueMax); return MakeUnique(Channel, this->GetOwningObjectOrOuter(), MoveTemp(KeyPositions), MoveTemp(KeyAttributes), GetLongDisplayName().ToString(), ValueMin, ValueMax); } return nullptr; } void FByteChannelCurveModel::GetCurveAttributes(FCurveAttributes& OutCurveAttributes) const { FMovieSceneByteChannel* Channel = GetChannelHandle().Get(); if (Channel) { OutCurveAttributes.SetPreExtrapolation(Channel->PreInfinityExtrap); OutCurveAttributes.SetPostExtrapolation(Channel->PostInfinityExtrap); } } void FByteChannelCurveModel::SetCurveAttributes(const FCurveAttributes& InCurveAttributes) { FMovieSceneByteChannel* Channel = GetChannelHandle().Get(); UMovieSceneSection* Section = this->GetOwningObjectOrOuter(); if (Channel && Section && !IsReadOnly()) { Section->MarkAsChanged(); if (InCurveAttributes.HasPreExtrapolation()) { Channel->PreInfinityExtrap = InCurveAttributes.GetPreExtrapolation(); } if (InCurveAttributes.HasPostExtrapolation()) { Channel->PostInfinityExtrap = InCurveAttributes.GetPostExtrapolation(); } CurveModifiedDelegate.Broadcast(); } } double FByteChannelCurveModel::GetKeyValue(TArrayView Values, int32 Index) const { return (double)Values[Index]; } void FByteChannelCurveModel::SetKeyValue(int32 Index, double KeyValue) const { FMovieSceneByteChannel* Channel = GetChannelHandle().Get(); if (Channel) { TMovieSceneChannelData ChannelData = Channel->GetData(); ChannelData.GetValues()[Index] = (uint8)KeyValue; } }