// Copyright Epic Games, Inc. All Rights Reserved. #include "EventChannelCurveModel.h" #include "Algo/BinarySearch.h" #include "Channels/MovieSceneChannelData.h" #include "Channels/MovieSceneEvent.h" #include "Channels/MovieSceneEventChannel.h" #include "CurveDataAbstraction.h" #include "CurveDrawInfo.h" #include "Curves/RealCurve.h" #include "HAL/PlatformCrt.h" #include "Math/Color.h" #include "Math/NumericLimits.h" #include "Math/Vector2D.h" #include "Misc/AssertionMacros.h" #include "Misc/FrameNumber.h" #include "Misc/FrameRate.h" #include "Misc/FrameTime.h" #include "MovieScene.h" #include "MovieSceneSection.h" #include "MovieSceneTrack.h" #include "SequencerSectionPainter.h" #include "Styling/AppStyle.h" #include "Styling/ISlateStyle.h" #include "Templates/UnrealTemplate.h" #include "UObject/WeakObjectPtr.h" class FCurveEditor; class UObject; struct FCurveEditorScreenSpace; ECurveEditorViewID FEventChannelCurveModel::EventView = ECurveEditorViewID::Invalid; FEventChannelCurveModel::FEventChannelCurveModel(TMovieSceneChannelHandle InChannel, UMovieSceneSection* OwningSection, TWeakPtr InWeakSequencer) { ChannelHandle = InChannel; WeakSection = OwningSection; WeakSequencer = InWeakSequencer; SupportedViews = EventView; Color = FSequencerSectionPainter::BlendColor(OwningSection->GetTypedOuter()->GetColorTint()); } const void* FEventChannelCurveModel::GetCurve() const { return ChannelHandle.Get(); } void FEventChannelCurveModel::Modify() { if (UMovieSceneSection* Section = WeakSection.Get()) { Section->Modify(); } } void FEventChannelCurveModel::AddKeys(TArrayView InKeyPositions, TArrayView InKeyAttributes, TArrayView>* OutKeyHandles) { check(InKeyPositions.Num() == InKeyAttributes.Num() && (!OutKeyHandles || OutKeyHandles->Num() == InKeyPositions.Num())); FMovieSceneEventChannel* Channel = ChannelHandle.Get(); UMovieSceneSection* Section = WeakSection.Get(); if (Channel && Section) { Section->Modify(); TMovieSceneChannelData ChannelData = Channel->GetData(); FFrameRate TickResolution = Section->GetTypedOuter()->GetTickResolution(); for (int32 Index = 0; Index < InKeyPositions.Num(); ++Index) { FKeyPosition Position = InKeyPositions[Index]; FKeyAttributes Attributes = InKeyAttributes[Index]; FFrameNumber Time = (Position.InputValue * TickResolution).RoundToFrame(); Section->ExpandToFrame(Time); FMovieSceneEvent Value; FKeyHandle NewHandle = ChannelData.UpdateOrAddKey(Time, Value); if (NewHandle != FKeyHandle::Invalid()) { if (OutKeyHandles) { (*OutKeyHandles)[Index] = NewHandle; } } } } } bool FEventChannelCurveModel::Evaluate(double Time, double& OutValue) const { // Events don't evaluate into a valid value OutValue = 0.0; return false; } void FEventChannelCurveModel::RemoveKeys(TArrayView InKeys, double InCurrentTime) { FMovieSceneEventChannel* Channel = ChannelHandle.Get(); UMovieSceneSection* Section = WeakSection.Get(); if (Channel && Section) { Section->Modify(); TMovieSceneChannelData ChannelData = Channel->GetData(); for (FKeyHandle Handle : InKeys) { int32 KeyIndex = ChannelData.GetIndex(Handle); if (KeyIndex != INDEX_NONE) { ChannelData.RemoveKey(KeyIndex); } } } } void FEventChannelCurveModel::DrawCurve(const FCurveEditor& CurveEditor, const FCurveEditorScreenSpace& ScreenSpace, TArray>& InterpolatingPoints) const { // Event Channels don't draw any lines so there's no need to fill out the Interpolating Points array. } void FEventChannelCurveModel::GetKeys(double MinTime, double MaxTime, double MinValue, double MaxValue, TArray& OutKeyHandles) const { FMovieSceneEventChannel* Channel = ChannelHandle.Get(); UMovieSceneSection* Section = WeakSection.Get(); if (Channel && Section) { FFrameRate TickResolution = Section->GetTypedOuter()->GetTickResolution(); TMovieSceneChannelData ChannelData = Channel->GetData(); TArrayView Times = ChannelData.GetTimes(); const FFrameNumber StartFrame = MinTime <= MIN_int32 ? MIN_int32 : (MinTime * TickResolution).CeilToFrame(); const FFrameNumber EndFrame = MaxTime >= MAX_int32 ? MAX_int32 : (MaxTime * TickResolution).FloorToFrame(); const int32 StartingIndex = Algo::LowerBound(Times, StartFrame); const int32 EndingIndex = Algo::UpperBound(Times, EndFrame); for (int32 KeyIndex = StartingIndex; KeyIndex < EndingIndex; ++KeyIndex) { // Event Channels don't have Values associated with them so we ignore the Min/Max value and always return the key. OutKeyHandles.Add(ChannelData.GetHandle(KeyIndex)); } } } void FEventChannelCurveModel::GetKeyDrawInfo(ECurvePointType PointType, const FKeyHandle InKeyHandle, FKeyDrawInfo& OutDrawInfo) const { OutDrawInfo.Brush = FAppStyle::Get().GetBrush("Sequencer.KeyDiamond"); OutDrawInfo.ScreenSize = FVector2D(10, 10); } void FEventChannelCurveModel::GetKeyPositions(TArrayView InKeys, TArrayView OutKeyPositions) const { FMovieSceneEventChannel* Channel = ChannelHandle.Get(); UMovieSceneSection* Section = WeakSection.Get(); if (Channel && Section) { FFrameRate TickResolution = Section->GetTypedOuter()->GetTickResolution(); TMovieSceneChannelData ChannelData = Channel->GetData(); TArrayView Times = ChannelData.GetTimes(); TArrayView Values = ChannelData.GetValues(); for (int32 Index = 0; Index < InKeys.Num(); ++Index) { int32 KeyIndex = ChannelData.GetIndex(InKeys[Index]); if (KeyIndex != INDEX_NONE) { OutKeyPositions[Index].InputValue = Times[KeyIndex] / TickResolution; // Events have no values so we just output zero. OutKeyPositions[Index].OutputValue = 0.0; } } } } void FEventChannelCurveModel::SetKeyPositions(TArrayView InKeys, TArrayView InKeyPositions, EPropertyChangeType::Type ChangeType) { FMovieSceneEventChannel* Channel = ChannelHandle.Get(); UMovieSceneSection* Section = WeakSection.Get(); if (Channel && Section) { Section->MarkAsChanged(); FFrameRate TickResolution = Section->GetTypedOuter()->GetTickResolution(); TMovieSceneChannelData ChannelData = Channel->GetData(); for (int32 Index = 0; Index < InKeys.Num(); ++Index) { int32 KeyIndex = ChannelData.GetIndex(InKeys[Index]); if (KeyIndex != INDEX_NONE) { FFrameNumber NewTime = (InKeyPositions[Index].InputValue * TickResolution).FloorToFrame(); const bool bRemoveDuplicates = ChangeType == EPropertyChangeType::ValueSet; KeyIndex = ChannelData.MoveKey(KeyIndex, NewTime, bRemoveDuplicates); Section->ExpandToFrame(NewTime); } } } } void FEventChannelCurveModel::GetKeyAttributes(TArrayView InKeys, TArrayView OutAttributes) const { } void FEventChannelCurveModel::SetKeyAttributes(TArrayView InKeys, TArrayView InAttributes, EPropertyChangeType::Type ChangeType) { } void FEventChannelCurveModel::GetCurveAttributes(FCurveAttributes& OutCurveAttributes) const { // Event Channels have no Pre/Post Extrapolation OutCurveAttributes.SetPreExtrapolation(RCCE_None); OutCurveAttributes.SetPostExtrapolation(RCCE_None); } void FEventChannelCurveModel::SetCurveAttributes(const FCurveAttributes& InCurveAttributes) { } void FEventChannelCurveModel::CreateKeyProxies(TArrayView InKeyHandles, TArrayView OutObjects) { } void FEventChannelCurveModel::GetTimeRange(double& MinTime, double& MaxTime) const { FMovieSceneEventChannel* Channel = ChannelHandle.Get(); UMovieSceneSection* Section = WeakSection.Get(); if (Channel && Section) { TArrayView Times = Channel->GetData().GetTimes(); if (Times.Num() == 0) { MinTime = 0.f; MaxTime = 0.f; } else { FFrameRate TickResolution = Section->GetTypedOuter()->GetTickResolution(); double ToTime = TickResolution.AsInterval(); MinTime = static_cast (Times[0].Value) * ToTime; MaxTime = static_cast(Times[Times.Num() - 1].Value) * ToTime; } } } void FEventChannelCurveModel::GetValueRange(double& MinValue, double& MaxValue) const { // Event Tracks have no value, thus their value range is just zero. MinValue = MaxValue = 0.0; } int32 FEventChannelCurveModel::GetNumKeys() const { FMovieSceneEventChannel* Channel = ChannelHandle.Get(); if (Channel) { return Channel->GetData().GetTimes().Num(); } return 0; }