Files
UnrealEngine/Engine/Source/Runtime/MovieScene/Private/Tracks/MovieSceneBindingLifetimeTrack.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

194 lines
6.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Tracks/MovieSceneBindingLifetimeTrack.h"
#include "MovieSceneCommonHelpers.h"
#include "Sections/MovieSceneBindingLifetimeSection.h"
#include "Serialization/ObjectReader.h"
#include "Serialization/ObjectWriter.h"
#include "MovieScene.h"
#include "MovieSceneTimeHelpers.h"
#include "EntitySystem/BuiltInComponentTypes.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(MovieSceneBindingLifetimeTrack)
#define LOCTEXT_NAMESPACE "MovieSceneBindingLifetimeTrack"
/* UMovieSceneBindingLifetimeTrack structors
*****************************************************************************/
UMovieSceneBindingLifetimeTrack::UMovieSceneBindingLifetimeTrack(const FObjectInitializer& Obj)
: Super(Obj)
{
#if WITH_EDITORONLY_DATA
TrackTint = FColor(26, 117, 49, 150);
bSupportsConditions = false;
#endif
}
bool UMovieSceneBindingLifetimeTrack::SupportsType(TSubclassOf<UMovieSceneSection> SectionClass) const
{
return SectionClass == UMovieSceneBindingLifetimeSection::StaticClass();
}
UMovieSceneSection* UMovieSceneBindingLifetimeTrack::CreateNewSection()
{
return NewObject<UMovieSceneBindingLifetimeSection>(this, NAME_None, RF_Transactional);
}
bool UMovieSceneBindingLifetimeTrack::HasSection(const UMovieSceneSection& Section) const
{
return Sections.ContainsByPredicate([&](const UMovieSceneSection* In) { return In == &Section; });
}
void UMovieSceneBindingLifetimeTrack::AddSection(UMovieSceneSection& Section)
{
Sections.Add(&Section);
}
void UMovieSceneBindingLifetimeTrack::RemoveSection(UMovieSceneSection& Section)
{
Sections.RemoveAll([&](const UMovieSceneSection* In) { return In == &Section; });
}
void UMovieSceneBindingLifetimeTrack::RemoveSectionAt(int32 SectionIndex)
{
Sections.RemoveAt(SectionIndex);
}
void UMovieSceneBindingLifetimeTrack::RemoveAllAnimationData()
{
Sections.Empty();
}
bool UMovieSceneBindingLifetimeTrack::IsEmpty() const
{
return Sections.Num() == 0;
}
const TArray<UMovieSceneSection*>& UMovieSceneBindingLifetimeTrack::GetAllSections() const
{
return Sections;
}
#if WITH_EDITORONLY_DATA
FText UMovieSceneBindingLifetimeTrack::GetDisplayName() const
{
return LOCTEXT("TrackName", "Binding Lifetime");
}
#endif
void UMovieSceneBindingLifetimeTrack::ImportEntityImpl(UMovieSceneEntitySystemLinker* EntityLinker, const FEntityImportParams& Params, FImportedEntity* OutImportedEntity)
{
using namespace UE::MovieScene;
FBuiltInComponentTypes* BuiltInComponentTypes = FBuiltInComponentTypes::Get();
OutImportedEntity->AddBuilder(
FEntityBuilder()
.Add(BuiltInComponentTypes->GenericObjectBinding, Params.GetObjectBindingID())
.AddConditional(BuiltInComponentTypes->BindingLifetime, FMovieSceneBindingLifetimeComponentData{ EMovieSceneBindingLifetimeState::Inactive }, Params.GetObjectBindingID().IsValid())
);
}
TArray<FFrameNumberRange> UMovieSceneBindingLifetimeTrack::CalculateInverseLifetimeRange(const TArray<FFrameNumberRange>& Ranges)
{
TArray<FFrameNumberRange> InverseLifetimeRange;
InverseLifetimeRange.Add(FFrameNumberRange::All());
// Iterate through our sections, removing them from the range
auto RemoveRangeFromSet = [&](FFrameNumberRange SectionRange) {
for (int32 Index = 0; Index < InverseLifetimeRange.Num(); ++Index)
{
const FFrameNumberRange& Current = InverseLifetimeRange[Index];
if (Current.Overlaps(SectionRange))
{
// Special case that difference doesn't handle well
if (!SectionRange.HasLowerBound() && !SectionRange.HasUpperBound())
{
InverseLifetimeRange.Reset();
return;
}
TArray<FFrameNumberRange> SplitRanges = FFrameNumberRange::Difference(Current, SectionRange);
for (const FFrameNumberRange& NewRange : SplitRanges)
{
// Splitting infinite ranges keeps an infinite range, which we don't want to keep
if (!NewRange.HasLowerBound() && !NewRange.HasUpperBound())
{
continue;
}
InverseLifetimeRange.Add(NewRange);
}
InverseLifetimeRange.RemoveAtSwap(Index--);
}
}
};
TArray<TRange<FFrameNumber>> SectionRanges;
for (const FFrameNumberRange& Range : Ranges)
{
if (Algo::AnyOf(SectionRanges, [&](const TRange<FFrameNumber> OtherRange) { return !OtherRange.IsDegenerate() && !Range.IsDegenerate() && OtherRange.Overlaps(Range); }))
{
// Lifetime Range sections have managed to overlap, which should not be allowed.
ensure(false);
InverseLifetimeRange.Reset();
return InverseLifetimeRange;
}
SectionRanges.Add(Range);
RemoveRangeFromSet(Range);
}
return InverseLifetimeRange;
}
bool UMovieSceneBindingLifetimeTrack::PopulateEvaluationFieldImpl(const TRange<FFrameNumber>& EffectiveRange, const FMovieSceneEvaluationFieldEntityMetaData& InMetaData, FMovieSceneEntityComponentFieldBuilder* OutFieldBuilder)
{
const FMovieSceneTrackEvaluationField& LocalEvaluationField = GetEvaluationField();
TArray<FFrameNumberRange> Ranges;
Algo::Transform(LocalEvaluationField.Entries, Ranges, [](const FMovieSceneTrackEvaluationFieldEntry& Entry) { return Entry.Range; });
TArray<FFrameNumberRange> InverseLifetimeRange = CalculateInverseLifetimeRange(Ranges);
// Add an entity for each section of the inverse range to define areas where our lifetime is inactive.
for (const FFrameNumberRange& InverseRange : InverseLifetimeRange)
{
OutFieldBuilder->AddPersistentEntity(InverseRange, this, 0, OutFieldBuilder->AddMetaData(InMetaData));
}
for (const FMovieSceneTrackEvaluationFieldEntry& Entry : LocalEvaluationField.Entries)
{
UMovieSceneBindingLifetimeSection* BindingLifetimeSection = Cast<UMovieSceneBindingLifetimeSection>(Entry.Section);
if (BindingLifetimeSection)
{
FFrameNumberRange SectionEffectiveRange = FFrameNumberRange::Intersection(EffectiveRange, Entry.Range);
if (!SectionEffectiveRange.IsEmpty())
{
FMovieSceneEvaluationFieldEntityMetaData SectionMetaData = InMetaData;
SectionMetaData.Flags = Entry.Flags;
if (Entry.Section)
{
SectionMetaData.Condition = MovieSceneHelpers::GetSequenceCondition(this, Entry.Section, true);
}
BindingLifetimeSection->ExternalPopulateEvaluationField(SectionEffectiveRange, SectionMetaData, OutFieldBuilder);
}
}
}
return true;
}
#undef LOCTEXT_NAMESPACE