// Copyright Epic Games, Inc. All Rights Reserved. #include "Sections/MovieScene3DTransformSection.h" #include "Channels/IMovieSceneChannelOverrideProvider.h" #include "UObject/StructOnScope.h" #include "UObject/SequencerObjectVersion.h" #include "Algo/AnyOf.h" #include "Channels/MovieSceneChannelProxy.h" #include "Channels/MovieSceneSectionChannelOverrideRegistry.h" #include "GameFramework/Actor.h" #include "EulerTransform.h" #include "Systems/MovieScene3DTransformPropertySystem.h" #include "Tracks/MovieScene3DTransformTrack.h" #include "Tracks/MovieSceneEulerTransformTrack.h" #include "EntitySystem/MovieSceneEntitySystemLinker.h" #include "EntitySystem/MovieSceneEntityBuilder.h" #include "MovieSceneTracksComponentTypes.h" #include "Transform/TransformConstraint.h" #include "Transform/TransformableHandle.h" #include "UObject/ObjectSaveContext.h" #include "Misc/AxisDisplayInfo.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(MovieScene3DTransformSection) #if WITH_EDITOR namespace { FIntVector4 ReverseSwizzleFunc(const FIntVector4& InSwizzle) { FIntVector4 ReverseSwizzle; for (int32 i = 0; i < 4; ++i) { int32 Index = 0; for (int32 j = 0; j < 4; ++j) { if (InSwizzle[j] == i) { Index = j; break; } } ReverseSwizzle[i] = Index; } return ReverseSwizzle; }; } // empty namespace struct F3DTransformChannelEditorData { F3DTransformChannelEditorData(EMovieSceneTransformChannel Mask,int SortOrderStart) { static const TSet PropertyMetaDataKeys = { "UIMin", "UIMax", "SliderExponent", "LinearDeltaSensitivity", "Delta", "ClampMin", "ClampMax", "ForceUnits", "WheelStep" }; auto MakeSubPropertyMap = [](FName FTransformName, FName FEulerTransformName)->TMap { return { { TBaseStructure::Get()->GetFName(), FTransformName }, { TBaseStructure::Get()->GetFName(), FEulerTransformName } }; }; const FProperty* RelativeLocationProperty = USceneComponent::StaticClass()->FindPropertyByName(USceneComponent::GetRelativeLocationPropertyName()); const FProperty* RelativeRotationProperty = USceneComponent::StaticClass()->FindPropertyByName(USceneComponent::GetRelativeRotationPropertyName()); const FProperty* RelativeScale3DProperty = USceneComponent::StaticClass()->FindPropertyByName(USceneComponent::GetRelativeScale3DPropertyName()); const EAxisList::Type XAxis = EAxisList::Forward; const EAxisList::Type YAxis = EAxisList::Left; const EAxisList::Type ZAxis = EAxisList::Up; const FIntVector4 Swizzle = AxisDisplayInfo::GetTransformAxisSwizzle(); const FIntVector4 ReverseSwizzle = ReverseSwizzleFunc(Swizzle); const int32 TranslationOrderOffset = 0; const int32 RotationOrderOffset = TranslationOrderOffset + 3; const int32 ScaleOrderOffset = RotationOrderOffset + 3; FText LocationGroup = NSLOCTEXT("MovieSceneTransformSection", "Location", "Location"); FText RotationGroup = NSLOCTEXT("MovieSceneTransformSection", "Rotation", "Rotation"); FText ScaleGroup = NSLOCTEXT("MovieSceneTransformSection", "Scale", "Scale"); { MetaData[0].SetIdentifiers("Location.X", AxisDisplayInfo::GetAxisDisplayName(XAxis), LocationGroup); MetaData[0].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Translation.X"), TEXT("Location.X")); MetaData[0].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::TranslationX); MetaData[0].Color = AxisDisplayInfo::GetAxisColor(XAxis); MetaData[0].SortOrder = SortOrderStart + TranslationOrderOffset + ReverseSwizzle[0]; MetaData[0].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[0].PropertyMetaData.Add(PropertyMetaDataKey, RelativeLocationProperty->GetMetaData(PropertyMetaDataKey)); } MetaData[1].SetIdentifiers("Location.Y", AxisDisplayInfo::GetAxisDisplayName(YAxis), LocationGroup); MetaData[1].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Translation.Y"), TEXT("Location.Y")); MetaData[1].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::TranslationY); MetaData[1].Color = AxisDisplayInfo::GetAxisColor(YAxis); MetaData[1].SortOrder = SortOrderStart + TranslationOrderOffset + ReverseSwizzle[1]; MetaData[1].bCanCollapseToTrack = false; MetaData[1].bInvertValue = AxisDisplayInfo::GetAxisDisplayCoordinateSystem() == EAxisList::LeftUpForward; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[1].PropertyMetaData.Add(PropertyMetaDataKey, RelativeLocationProperty->GetMetaData(PropertyMetaDataKey)); } MetaData[2].SetIdentifiers("Location.Z", AxisDisplayInfo::GetAxisDisplayName(ZAxis), LocationGroup); MetaData[2].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Translation.Z"), TEXT("Location.Z")); MetaData[2].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::TranslationZ); MetaData[2].Color = AxisDisplayInfo::GetAxisColor(ZAxis); MetaData[2].SortOrder = SortOrderStart + TranslationOrderOffset + ReverseSwizzle[2]; MetaData[2].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[2].PropertyMetaData.Add(PropertyMetaDataKey, RelativeLocationProperty->GetMetaData(PropertyMetaDataKey)); } } { MetaData[3].SetIdentifiers("Rotation.X", NSLOCTEXT("MovieSceneTransformSection", "RotationX", "Roll"), RotationGroup); MetaData[3].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Rotation.X"), TEXT("Rotation.Roll")); MetaData[3].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::RotationX); MetaData[3].Color = AxisDisplayInfo::GetAxisColor(XAxis); MetaData[3].SortOrder = SortOrderStart + RotationOrderOffset + 0; MetaData[3].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[3].PropertyMetaData.Add(PropertyMetaDataKey, RelativeRotationProperty->GetMetaData(PropertyMetaDataKey)); } MetaData[4].SetIdentifiers("Rotation.Y", NSLOCTEXT("MovieSceneTransformSection", "RotationY", "Pitch"), RotationGroup); MetaData[4].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Rotation.Y"), TEXT("Rotation.Pitch")); MetaData[4].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::RotationY); MetaData[4].Color = AxisDisplayInfo::GetAxisColor(YAxis); MetaData[4].SortOrder = SortOrderStart + RotationOrderOffset + 1; MetaData[4].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[4].PropertyMetaData.Add(PropertyMetaDataKey, RelativeRotationProperty->GetMetaData(PropertyMetaDataKey)); } MetaData[5].SetIdentifiers("Rotation.Z", NSLOCTEXT("MovieSceneTransformSection", "RotationZ", "Yaw"), RotationGroup); MetaData[5].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Rotation.Z"), TEXT("Rotation.Yaw")); MetaData[5].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::RotationZ); MetaData[5].Color = AxisDisplayInfo::GetAxisColor(ZAxis); MetaData[5].SortOrder = SortOrderStart + RotationOrderOffset + 2; MetaData[5].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[5].PropertyMetaData.Add(PropertyMetaDataKey, RelativeRotationProperty->GetMetaData(PropertyMetaDataKey)); } } { MetaData[6].SetIdentifiers("Scale.X", AxisDisplayInfo::GetAxisDisplayName(XAxis), ScaleGroup); MetaData[6].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Scale3D.X"), TEXT("Scale.X")); MetaData[6].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::ScaleX); MetaData[6].Color = AxisDisplayInfo::GetAxisColor(XAxis); MetaData[6].SortOrder = SortOrderStart + ScaleOrderOffset + ReverseSwizzle[0]; MetaData[6].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[6].PropertyMetaData.Add(PropertyMetaDataKey, RelativeScale3DProperty->GetMetaData(PropertyMetaDataKey)); } MetaData[7].SetIdentifiers("Scale.Y", AxisDisplayInfo::GetAxisDisplayName(YAxis), ScaleGroup); MetaData[7].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Scale3D.Y"), TEXT("Scale.Y")); MetaData[7].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::ScaleY); MetaData[7].Color = AxisDisplayInfo::GetAxisColor(YAxis); MetaData[7].SortOrder = SortOrderStart + ScaleOrderOffset + ReverseSwizzle[1]; MetaData[7].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[7].PropertyMetaData.Add(PropertyMetaDataKey, RelativeScale3DProperty->GetMetaData(PropertyMetaDataKey)); } MetaData[8].SetIdentifiers("Scale.Z", AxisDisplayInfo::GetAxisDisplayName(ZAxis), ScaleGroup); MetaData[8].SubPropertyPathMap = MakeSubPropertyMap(TEXT("Scale3D.Z"), TEXT("Scale.Z")); MetaData[8].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::ScaleZ); MetaData[8].Color = AxisDisplayInfo::GetAxisColor(ZAxis); MetaData[8].SortOrder = SortOrderStart + ScaleOrderOffset + ReverseSwizzle[2]; MetaData[8].bCanCollapseToTrack = false; for (const FName& PropertyMetaDataKey : PropertyMetaDataKeys) { MetaData[8].PropertyMetaData.Add(PropertyMetaDataKey, RelativeScale3DProperty->GetMetaData(PropertyMetaDataKey)); } } { MetaData[9].SetIdentifiers("Weight", NSLOCTEXT("MovieSceneTransformSection", "Weight", "Weight")); MetaData[9].bEnabled = EnumHasAllFlags(Mask, EMovieSceneTransformChannel::Weight); } ExternalValues[0].OnGetExternalValue = ExtractTranslationX; ExternalValues[1].OnGetExternalValue = ExtractTranslationY; ExternalValues[2].OnGetExternalValue = ExtractTranslationZ; ExternalValues[3].OnGetExternalValue = ExtractRotationX; ExternalValues[4].OnGetExternalValue = ExtractRotationY; ExternalValues[5].OnGetExternalValue = ExtractRotationZ; ExternalValues[6].OnGetExternalValue = ExtractScaleX; ExternalValues[7].OnGetExternalValue = ExtractScaleY; ExternalValues[8].OnGetExternalValue = ExtractScaleZ; } static TOptional GetTranslation(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { const UStruct* TransformStruct = Bindings ? Bindings->GetPropertyStruct(InObject) : nullptr; if (TransformStruct) { if (TransformStruct == TBaseStructure::Get()) { if (TOptional Transform = Bindings->GetOptionalValue(InObject)) { return Transform->GetTranslation(); } } else if (TransformStruct == TBaseStructure::Get()) { if (TOptional EulerTransform = Bindings->GetOptionalValue(InObject)) { return EulerTransform->Location; } } } else if (USceneComponent* SceneComponent = Cast(&InObject)) { return SceneComponent->GetRelativeTransform().GetTranslation(); } else if (AActor* Actor = Cast(&InObject)) { if (USceneComponent* RootComponent = Actor->GetRootComponent()) { return RootComponent->GetRelativeTransform().GetTranslation(); } } return TOptional(); } static TOptional GetRotator(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { const UStruct* TransformStruct = Bindings ? Bindings->GetPropertyStruct(InObject) : nullptr; if (TransformStruct) { if (TransformStruct == TBaseStructure::Get()) { if (TOptional Transform = Bindings->GetOptionalValue(InObject)) { return Transform->GetRotation().Rotator(); } } else if (TransformStruct == TBaseStructure::Get()) { if (TOptional EulerTransform = Bindings->GetOptionalValue(InObject)) { return EulerTransform->Rotation; } } } else if (USceneComponent* SceneComponent = Cast(&InObject)) { return SceneComponent->GetRelativeRotation(); } else if (AActor* Actor = Cast(&InObject)) { if (USceneComponent* RootComponent = Actor->GetRootComponent()) { return RootComponent->GetRelativeRotation(); } } return TOptional(); } static TOptional GetScale(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { const UStruct* TransformStruct = Bindings ? Bindings->GetPropertyStruct(InObject) : nullptr; if (TransformStruct) { if (TransformStruct == TBaseStructure::Get()) { if (TOptional Transform = Bindings->GetOptionalValue(InObject)) { return Transform->GetScale3D(); } } else if (TransformStruct == TBaseStructure::Get()) { if (TOptional EulerTransform = Bindings->GetOptionalValue(InObject)) { return EulerTransform->Scale; } } } else if (USceneComponent* SceneComponent = Cast(&InObject)) { return SceneComponent->GetRelativeTransform().GetScale3D(); } else if (AActor* Actor = Cast(&InObject)) { if (USceneComponent* RootComponent = Actor->GetRootComponent()) { return RootComponent->GetRelativeTransform().GetScale3D(); } } return TOptional(); } static TOptional ExtractTranslationX(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Translation = GetTranslation(InObject, Bindings); return Translation.IsSet() ? Translation->X : TOptional(); } static TOptional ExtractTranslationY(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Translation = GetTranslation(InObject, Bindings); return Translation.IsSet() ? Translation->Y : TOptional(); } static TOptional ExtractTranslationZ(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Translation = GetTranslation(InObject, Bindings); return Translation.IsSet() ? Translation->Z : TOptional(); } static TOptional ExtractRotationX(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Rotator = GetRotator(InObject, Bindings); return Rotator.IsSet() ? Rotator->Roll : TOptional(); } static TOptional ExtractRotationY(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Rotator = GetRotator(InObject, Bindings); return Rotator.IsSet() ? Rotator->Pitch : TOptional(); } static TOptional ExtractRotationZ(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Rotator = GetRotator(InObject, Bindings); return Rotator.IsSet() ? Rotator->Yaw : TOptional(); } static TOptional ExtractScaleX(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Scale = GetScale(InObject, Bindings); return Scale.IsSet() ? Scale->X : TOptional(); } static TOptional ExtractScaleY(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Scale = GetScale(InObject, Bindings); return Scale.IsSet() ? Scale->Y : TOptional(); } static TOptional ExtractScaleZ(UObject& InObject, FTrackInstancePropertyBindings* Bindings) { TOptional Scale = GetScale(InObject, Bindings); return Scale.IsSet() ? Scale->Z : TOptional(); } FMovieSceneChannelMetaData MetaData[10]; TMovieSceneExternalValue ExternalValues[9]; TMovieSceneExternalValue WeightExternalValue; }; #endif // WITH_EDITOR /* FMovieScene3DLocationKeyStruct interface *****************************************************************************/ void FMovieScene3DLocationKeyStruct::PropagateChanges(const FPropertyChangedEvent& ChangeEvent) { KeyStructInterop.Apply(Time); } /* FMovieScene3DRotationKeyStruct interface *****************************************************************************/ void FMovieScene3DRotationKeyStruct::PropagateChanges(const FPropertyChangedEvent& ChangeEvent) { KeyStructInterop.Apply(Time); } /* FMovieScene3DScaleKeyStruct interface *****************************************************************************/ void FMovieScene3DScaleKeyStruct::PropagateChanges(const FPropertyChangedEvent& ChangeEvent) { KeyStructInterop.Apply(Time); } /* FMovieScene3DTransformKeyStruct interface *****************************************************************************/ void FMovieScene3DTransformKeyStruct::PropagateChanges(const FPropertyChangedEvent& ChangeEvent) { KeyStructInterop.Apply(Time); } namespace UE::MovieScene { static constexpr uint32 ConstraintTypeMask = 1 << 31; } /* UMovieScene3DTransformSection interface *****************************************************************************/ UE::MovieScene::FChannelOverrideNames UMovieScene3DTransformSection::ChannelOverrideNames(10, { TEXT("Location.X"), TEXT("Location.Y"), TEXT("Location.Z"), TEXT("Rotation.X"), TEXT("Rotation.Y"), TEXT("Rotation.Z"), TEXT("Scale.X"), TEXT("Scale.Y"), TEXT("Scale.Z"), TEXT("Weight") }); UMovieScene3DTransformSection::UMovieScene3DTransformSection(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , bUseQuaternionInterpolation(false) #if WITH_EDITORONLY_DATA , Show3DTrajectory(EShow3DTrajectory::EST_OnlyWhenSelected) #endif { EvalOptions.EnableAndSetCompletionMode (GetLinkerCustomVersion(FSequencerObjectVersion::GUID) < FSequencerObjectVersion::WhenFinishedDefaultsToRestoreState ? EMovieSceneCompletionMode::KeepState : GetLinkerCustomVersion(FSequencerObjectVersion::GUID) < FSequencerObjectVersion::WhenFinishedDefaultsToProjectDefault ? EMovieSceneCompletionMode::RestoreState : EMovieSceneCompletionMode::ProjectDefault); TransformMask = EMovieSceneTransformChannel::AllTransform; BlendType = EMovieSceneBlendType::Absolute; bSupportsInfiniteRange = true; Translation[0].SetDefault(0.f); Translation[1].SetDefault(0.f); Translation[2].SetDefault(0.f); Rotation[0].SetDefault(0.f); Rotation[1].SetDefault(0.f); Rotation[2].SetDefault(0.f); Scale[0].SetDefault(1.f); Scale[1].SetDefault(1.f); Scale[2].SetDefault(1.f); } void UMovieScene3DTransformSection::OnBindingIDsUpdated(const TMap& OldFixedToNewFixedMap, FMovieSceneSequenceID LocalSequenceID, TSharedRef SharedPlaybackState) { if (Constraints) { for (FConstraintAndActiveChannel& ConstraintChannel : Constraints->ConstraintsChannels) { if (UTickableTransformConstraint* TransformConstraint = Cast< UTickableTransformConstraint>(ConstraintChannel.GetConstraint())) { //Don't do child's we do that in the system, needed for duplication if (TransformConstraint->ParentTRSHandle) { TransformConstraint->ParentTRSHandle->OnBindingIDsUpdated(OldFixedToNewFixedMap, LocalSequenceID, SharedPlaybackState); } } } } } void UMovieScene3DTransformSection::GetReferencedBindings(TArray& OutBindings) { if (Constraints) { for (FConstraintAndActiveChannel& ConstraintChannel : Constraints->ConstraintsChannels) { if (UTickableTransformConstraint* TransformConstraint = Cast< UTickableTransformConstraint>(ConstraintChannel.GetConstraint().Get())) { if (TransformConstraint->ChildTRSHandle && TransformConstraint->ChildTRSHandle->ConstraintBindingID.IsValid()) { OutBindings.Add(TransformConstraint->ChildTRSHandle->ConstraintBindingID.GetGuid()); } if (TransformConstraint->ParentTRSHandle && TransformConstraint->ParentTRSHandle->ConstraintBindingID.IsValid()) { OutBindings.Add(TransformConstraint->ParentTRSHandle->ConstraintBindingID.GetGuid()); } } } } } void UMovieScene3DTransformSection::PreSave(FObjectPreSaveContext SaveContext) { Super::PreSave(SaveContext); } template void UMovieScene3DTransformSection::BuildEntity(BaseBuilderType& InBaseBuilder, UMovieSceneEntitySystemLinker* Linker, const FEntityImportParams& Params, FImportedEntity* OutImportedEntity) { using namespace UE::MovieScene; FBuiltInComponentTypes* BuiltInComponentTypes = FBuiltInComponentTypes::Get(); FMovieSceneTracksComponentTypes* TrackComponents = FMovieSceneTracksComponentTypes::Get(); UMovieScenePropertyTrack* Track = GetTypedOuter(); check(Track); const bool bIsComponentTransform = Track->IsA(); const bool bIsEulerTransform = Track->IsA(); FComponentTypeID PropertyTag = TrackComponents->Transform.PropertyTag; if (bIsComponentTransform) { PropertyTag = TrackComponents->ComponentTransform.PropertyTag; } else if (bIsEulerTransform) { PropertyTag = TrackComponents->EulerTransform.PropertyTag; } EMovieSceneTransformChannel Channels = TransformMask.GetChannels(); const bool ActiveChannelsMask[] = { EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::TranslationX) && Translation[0].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::TranslationY) && Translation[1].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::TranslationZ) && Translation[2].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::RotationX) && Rotation[0].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::RotationY) && Rotation[1].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::RotationZ) && Rotation[2].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::ScaleX) && Scale[0].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::ScaleY) && Scale[1].HasAnyData(), EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::ScaleZ) && Scale[2].HasAnyData(), }; if (!Algo::AnyOf(ActiveChannelsMask)) { return; } TComponentTypeID RotationChannel[3]; if (!bUseQuaternionInterpolation) { RotationChannel[0] = BuiltInComponentTypes->DoubleChannel[3]; RotationChannel[1] = BuiltInComponentTypes->DoubleChannel[4]; RotationChannel[2] = BuiltInComponentTypes->DoubleChannel[5]; } else { RotationChannel[0] = TrackComponents->QuaternionRotationChannel[0]; RotationChannel[1] = TrackComponents->QuaternionRotationChannel[1]; RotationChannel[2] = TrackComponents->QuaternionRotationChannel[2]; } // Let the override registry handle overriden channels const FName ChannelOverrideName = ChannelOverrideNames.GetChannelName(Params.EntityID); // If we are building the entity of an overriden channel, we pass the partial builder we have at this point // (the one with the bindings) and add the tag to it. // Then call into the override repository so it can add a second builder with the override stuff. if (ChannelOverrideName != NAME_None) { if (!ensureMsgf(OverrideRegistry && OverrideRegistry->ContainsChannel(ChannelOverrideName), TEXT("We received an entity ID that corresponds to an override channel, but no such override channel exists in the registry."))) { return; } const int32 ChannelOverrideIndex = (Params.EntityID - ChannelOverrideNames.IndexOffset); if (ChannelOverrideIndex == 9) { if (EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::Weight)) { OutImportedEntity->AddBuilder(InBaseBuilder.AddTag(PropertyTag)); FChannelOverrideEntityImportParams OverrideParams{ ChannelOverrideName, BuiltInComponentTypes->WeightResult }; OverrideRegistry->ImportEntityImpl(OverrideParams, Params, OutImportedEntity); } } else { if (ActiveChannelsMask[ChannelOverrideIndex]) { OutImportedEntity->AddBuilder(InBaseBuilder.AddTag(PropertyTag)); FChannelOverrideEntityImportParams OverrideParams{ ChannelOverrideName, BuiltInComponentTypes->DoubleResult[ChannelOverrideIndex] }; OverrideRegistry->ImportEntityImpl(OverrideParams, Params, OutImportedEntity); } } return; } // Here proceed with the all the normal channels OutImportedEntity->AddBuilder( InBaseBuilder .AddConditional(BuiltInComponentTypes->DoubleChannel[0], &Translation[0], ActiveChannelsMask[0] && !IsChannelOverriden(OverrideRegistry, TEXT("Location.X"))) .AddConditional(BuiltInComponentTypes->DoubleChannel[1], &Translation[1], ActiveChannelsMask[1] && !IsChannelOverriden(OverrideRegistry, TEXT("Location.Y"))) .AddConditional(BuiltInComponentTypes->DoubleChannel[2], &Translation[2], ActiveChannelsMask[2] && !IsChannelOverriden(OverrideRegistry, TEXT("Location.Z"))) .AddConditional(RotationChannel[0], &Rotation[0], ActiveChannelsMask[3] && !IsChannelOverriden(OverrideRegistry, TEXT("Rotation.X"))) .AddConditional(RotationChannel[1], &Rotation[1], ActiveChannelsMask[4] && !IsChannelOverriden(OverrideRegistry, TEXT("Rotation.Y"))) .AddConditional(RotationChannel[2], &Rotation[2], ActiveChannelsMask[5] && !IsChannelOverriden(OverrideRegistry, TEXT("Rotation.Z"))) .AddConditional(BuiltInComponentTypes->DoubleChannel[6], &Scale[0], ActiveChannelsMask[6] && !IsChannelOverriden(OverrideRegistry, TEXT("Scale.X"))) .AddConditional(BuiltInComponentTypes->DoubleChannel[7], &Scale[1], ActiveChannelsMask[7] && !IsChannelOverriden(OverrideRegistry, TEXT("Scale.Y"))) .AddConditional(BuiltInComponentTypes->DoubleChannel[8], &Scale[2], ActiveChannelsMask[8] && !IsChannelOverriden(OverrideRegistry, TEXT("Scale.Z"))) .AddConditional(BuiltInComponentTypes->WeightChannel, &ManualWeight, EnumHasAnyFlags(Channels, EMovieSceneTransformChannel::Weight) && ManualWeight.HasAnyData() && !IsChannelOverriden(OverrideRegistry, TEXT("Weight"))) .AddTag(PropertyTag) ); } void UMovieScene3DTransformSection::PopulateConstraintEntities(const TRange& EffectiveRange, const FMovieSceneEvaluationFieldEntityMetaData& InMetaData, FMovieSceneEntityComponentFieldBuilder* OutFieldBuilder) { check(Constraints); using namespace UE::MovieScene; const int32 MetaDataIndex = OutFieldBuilder->AddMetaData(InMetaData); // Add explicitly typed entities for each constraint // Encode the top bit of the entity ID to mean it is a constraint // We can check this in ImportEntityImpl to import the correct constraint for (int32 ConstraintIndex = 0; ConstraintIndex < Constraints->ConstraintsChannels.Num(); ++ConstraintIndex) { // Entity IDs for constraints are their index within the array, masked with the top bit set const uint32 EntityID = ConstraintIndex | ConstraintTypeMask; OutFieldBuilder->AddPersistentEntity(EffectiveRange, this, EntityID, MetaDataIndex); } } bool UMovieScene3DTransformSection::PopulateEvaluationFieldImpl(const TRange& EffectiveRange, const FMovieSceneEvaluationFieldEntityMetaData& InMetaData, FMovieSceneEntityComponentFieldBuilder* OutFieldBuilder) { if (Constraints) { PopulateConstraintEntities(EffectiveRange, InMetaData, OutFieldBuilder); } if (OverrideRegistry) { // Add evaluation field entries for each channel that runs with a different logic. OverrideRegistry->PopulateEvaluationFieldImpl(EffectiveRange, InMetaData, OutFieldBuilder, *this); } // Return false even if we have an override registry, so that we also add an evaluation field entry for the default // stuff. return false; } void UMovieScene3DTransformSection::ImportConstraintEntity(UMovieSceneEntitySystemLinker* EntityLinker, const FEntityImportParams& Params, FImportedEntity* OutImportedEntity) { using namespace UE::MovieScene; FBuiltInComponentTypes* BuiltInComponentTypes = FBuiltInComponentTypes::Get(); FMovieSceneTracksComponentTypes* TrackComponents = FMovieSceneTracksComponentTypes::Get(); // Constraints must always operate on a USceneComponent. Putting one on a generic FTransform property has no effect (or is not possible). FGuid ObjectBindingID = Params.GetObjectBindingID(); if (ObjectBindingID.IsValid()) { // Mask out the top bit to get the constraint index we encoded into the EntityID. const int32 ConstraintIndex = static_cast(Params.EntityID & ~ConstraintTypeMask); checkf(Constraints->ConstraintsChannels.IsValidIndex(ConstraintIndex), TEXT("Encoded constraint (%d) index is not valid within array size %d. Data must have been manipulated without re-compilaition."), ConstraintIndex, Constraints->ConstraintsChannels.Num()); //add if constraint or spawn copy is valid if (Constraints->ConstraintsChannels[ConstraintIndex].GetConstraint().Get()) { FGuid ConstraintID = Constraints->ConstraintsChannels[ConstraintIndex].GetConstraint()->ConstraintID; //ID's should be the same! FConstraintComponentData ComponentData; ComponentData.ConstraintID = ConstraintID; ComponentData.Section = this; OutImportedEntity->AddBuilder( FEntityBuilder() .Add(BuiltInComponentTypes->BoundObjectResolver, MovieSceneHelpers::ResolveSceneComponentBoundObject) .Add(BuiltInComponentTypes->GenericObjectBinding, ObjectBindingID) .Add(TrackComponents->ConstraintChannel, ComponentData) ); } } } void UMovieScene3DTransformSection::ImportEntityImpl(UMovieSceneEntitySystemLinker* EntityLinker, const FEntityImportParams& Params, FImportedEntity* OutImportedEntity) { using namespace UE::MovieScene; if ((Params.EntityID & ConstraintTypeMask) != 0 && Constraints) { ImportConstraintEntity(EntityLinker, Params, OutImportedEntity); return; } FBuiltInComponentTypes* BuiltInComponentTypes = FBuiltInComponentTypes::Get(); UMovieScenePropertyTrack* Track = GetTypedOuter(); check(Track); FGuid ObjectBindingID = Params.GetObjectBindingID(); auto BaseBuilder = FEntityBuilder() .Add(BuiltInComponentTypes->PropertyBinding, Track->GetPropertyBinding()) // 3D Transform tracks use a scene component binding by default. Every other transform property track must be bound directly to the object. .AddConditional(BuiltInComponentTypes->BoundObjectResolver, MovieSceneHelpers::ResolveSceneComponentBoundObject, Track->IsA()) .AddConditional(BuiltInComponentTypes->GenericObjectBinding, ObjectBindingID, ObjectBindingID.IsValid()); BuildEntity(BaseBuilder, EntityLinker, Params, OutImportedEntity); } void UMovieScene3DTransformSection::InterrogateEntityImpl(UMovieSceneEntitySystemLinker* EntityLinker, const FEntityImportParams& Params, FImportedEntity* OutImportedEntity) { using namespace UE::MovieScene; FBuiltInComponentTypes* BuiltInComponentTypes = FBuiltInComponentTypes::Get(); auto BaseBuilder = FEntityBuilder().AddDefaulted(BuiltInComponentTypes->EvalTime); BuildEntity(BaseBuilder, EntityLinker, Params, OutImportedEntity); } FMovieSceneTransformMask UMovieScene3DTransformSection::GetMask() const { return TransformMask; } void UMovieScene3DTransformSection::SetMask(FMovieSceneTransformMask NewMask) { TransformMask = NewMask; ChannelProxy = nullptr; } FMovieSceneTransformMask UMovieScene3DTransformSection::GetMaskByName(const FName& InName) const { if (InName.ToString() == NSLOCTEXT("MovieSceneTransformSection", "Location", "Location").ToString()) { return EMovieSceneTransformChannel::Translation; } else if (InName == TEXT("Location.X")) { return EMovieSceneTransformChannel::TranslationX; } else if (InName == TEXT("Location.Y")) { return EMovieSceneTransformChannel::TranslationY; } else if (InName == TEXT("Location.Z")) { return EMovieSceneTransformChannel::TranslationZ; } else if (InName.ToString() == NSLOCTEXT("MovieSceneTransformSection", "Rotation", "Rotation").ToString()) { return EMovieSceneTransformChannel::Rotation; } else if (InName == TEXT("Rotation.X")) { return EMovieSceneTransformChannel::RotationX; } else if (InName == TEXT("Rotation.Y")) { return EMovieSceneTransformChannel::RotationY; } else if (InName == TEXT("Rotation.Z")) { return EMovieSceneTransformChannel::RotationZ; } else if (InName.ToString() == NSLOCTEXT("MovieSceneTransformSection", "Scale", "Scale").ToString()) { return EMovieSceneTransformChannel::Scale; } else if (InName == TEXT("Scale.X")) { return EMovieSceneTransformChannel::ScaleX; } else if (InName == TEXT("Scale.Y")) { return EMovieSceneTransformChannel::ScaleY; } else if (InName == TEXT("Scale.Z")) { return EMovieSceneTransformChannel::ScaleZ; } //Constraints aren't masked since they need to be deleted etc via their own API's FString ConstraintString = NSLOCTEXT("MovieSceneTransformSection", "Constraint", "Constraint").ToString(); if (InName.ToString().Contains(ConstraintString)) { return EMovieSceneTransformChannel::None; } return EMovieSceneTransformChannel::All; } EMovieSceneChannelProxyType UMovieScene3DTransformSection::CacheChannelProxy() { using namespace UE::MovieScene; FMovieSceneChannelProxyData Channels; #if WITH_EDITOR auto GetValidConstraint = [](FConstraintAndActiveChannel& ConstraintChannel) { return ConstraintChannel.GetConstraint().Get(); }; #endif //Constraints go on top int32 NumConstraints = 0; if(Constraints) { for (FConstraintAndActiveChannel& ConstraintChannel : Constraints->ConstraintsChannels) { #if WITH_EDITOR TWeakObjectPtr WeakConstraint = GetValidConstraint(ConstraintChannel); if (WeakConstraint.IsValid()) { FText ConstraintGroup = NSLOCTEXT("MovieSceneTransformSection", "Constraints", "Constraints"); const FName& ConstraintName = WeakConstraint->GetFName(); ConstraintChannel.ActiveChannel.ExtraLabel = [WeakConstraint] { if (WeakConstraint.IsValid()) { FString ParentStr; WeakConstraint->GetLabel().Split(TEXT("."), &ParentStr, nullptr); if (!ParentStr.IsEmpty()) { return ParentStr; } } static const FString DummyStr; return DummyStr; }; const FText DisplayText = FText::FromString(WeakConstraint->GetTypeLabel()); FMovieSceneChannelMetaData MetaData(ConstraintName, DisplayText, ConstraintGroup, true /*bInEnabled*/); MetaData.SortOrder = NumConstraints++; MetaData.bCanCollapseToTrack = false; Channels.Add(ConstraintChannel.ActiveChannel, MetaData, TMovieSceneExternalValue()); } #else Channels.Add(ConstraintChannel.ActiveChannel); #endif } } #if WITH_EDITOR F3DTransformChannelEditorData EditorData(TransformMask.GetChannels(), NumConstraints); AddChannelProxy(Channels, OverrideRegistry, TEXT("Location.X"), Translation[0], EditorData.MetaData[0], EditorData.ExternalValues[0]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Location.Y"), Translation[1], EditorData.MetaData[1], EditorData.ExternalValues[1]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Location.Z"), Translation[2], EditorData.MetaData[2], EditorData.ExternalValues[2]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Rotation.X"), Rotation[0], EditorData.MetaData[3], EditorData.ExternalValues[3]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Rotation.Y"), Rotation[1], EditorData.MetaData[4], EditorData.ExternalValues[4]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Rotation.Z"), Rotation[2], EditorData.MetaData[5], EditorData.ExternalValues[5]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Scale.X"), Scale[0], EditorData.MetaData[6], EditorData.ExternalValues[6]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Scale.Y"), Scale[1], EditorData.MetaData[7], EditorData.ExternalValues[7]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Scale.Z"), Scale[2], EditorData.MetaData[8], EditorData.ExternalValues[8]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Weight"), ManualWeight, EditorData.MetaData[9], EditorData.WeightExternalValue); #else AddChannelProxy(Channels, OverrideRegistry, TEXT("Location.X"), Translation[0]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Location.Y"), Translation[1]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Location.Z"), Translation[2]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Rotation.X"), Rotation[0]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Rotation.Y"), Rotation[1]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Rotation.Z"), Rotation[2]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Scale.X"), Scale[0]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Scale.Y"), Scale[1]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Scale.Z"), Scale[2]); AddChannelProxy(Channels, OverrideRegistry, TEXT("Weight"), ManualWeight); #endif ChannelProxy = MakeShared(MoveTemp(Channels)); return EMovieSceneChannelProxyType::Dynamic; } /* UMovieSceneSection interface *****************************************************************************/ TSharedPtr UMovieScene3DTransformSection::GetKeyStruct(TArrayView KeyHandles) { if (!ChannelProxy) { GetChannelProxy(); } FMovieSceneChannelHandle LocationXChannel, LocationYChannel, LocationZChannel; FMovieSceneChannelHandle RotationXChannel, RotationYChannel, RotationZChannel; FMovieSceneChannelHandle ScaleXChannel, ScaleYChannel, ScaleZChannel; #if WITH_EDITOR LocationXChannel = ChannelProxy->GetChannelByName("Location.X"); LocationYChannel = ChannelProxy->GetChannelByName("Location.Y"); LocationZChannel = ChannelProxy->GetChannelByName("Location.Z"); RotationXChannel = ChannelProxy->GetChannelByName("Rotation.X"); RotationYChannel = ChannelProxy->GetChannelByName("Rotation.Y"); RotationZChannel = ChannelProxy->GetChannelByName("Rotation.Z"); ScaleXChannel = ChannelProxy->GetChannelByName("Scale.X"); ScaleYChannel = ChannelProxy->GetChannelByName("Scale.Y"); ScaleZChannel = ChannelProxy->GetChannelByName("Scale.Z"); #endif int32 AnyLocationKeys = 0; int32 AnyRotationKeys = 0; int32 AnyScaleKeys = 0; TOptional> LocationKeys[3]; if (LocationXChannel.Get()) { LocationKeys[0] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(LocationXChannel.Get()), KeyHandles); AnyLocationKeys++; } if (LocationYChannel.Get()) { LocationKeys[1] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(LocationYChannel.Get()), KeyHandles); AnyLocationKeys++; } if (LocationZChannel.Get()) { LocationKeys[2] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(LocationZChannel.Get()), KeyHandles); AnyLocationKeys++; } TOptional> RotationKeys[3]; if (RotationXChannel.Get()) { RotationKeys[0] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(RotationXChannel.Get()), KeyHandles); AnyRotationKeys++; } if (RotationYChannel.Get()) { RotationKeys[1] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(RotationYChannel.Get()), KeyHandles); AnyRotationKeys++; } if (RotationZChannel.Get()) { RotationKeys[2] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(RotationZChannel.Get()), KeyHandles); AnyRotationKeys++; } TOptional> ScaleKeys[3]; if (ScaleXChannel.Get()) { ScaleKeys[0] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(ScaleXChannel.Get()), KeyHandles); AnyScaleKeys++; } if (ScaleYChannel.Get()) { ScaleKeys[1] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(ScaleYChannel.Get()), KeyHandles); AnyScaleKeys++; } if (ScaleZChannel.Get()) { ScaleKeys[2] = FMovieSceneChannelValueHelper::FindFirstKey(static_cast(ScaleZChannel.Get()), KeyHandles); AnyScaleKeys++; } // do we have multiple keys on multiple parts of the transform? if (AnyLocationKeys + AnyRotationKeys + AnyScaleKeys > 1) { TSharedRef KeyStruct = MakeShareable(new FStructOnScope(FMovieScene3DTransformKeyStruct::StaticStruct())); auto Struct = (FMovieScene3DTransformKeyStruct*)KeyStruct->GetStructMemory(); if (LocationKeys[0].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(LocationXChannel.GetChannelIndex()), &Struct->Location.X, LocationKeys[0])); } if (LocationKeys[1].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(LocationYChannel.GetChannelIndex()), &Struct->Location.Y, LocationKeys[1])); } if (LocationKeys[2].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(LocationZChannel.GetChannelIndex()), &Struct->Location.Z, LocationKeys[2])); } if (RotationKeys[0].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(RotationXChannel.GetChannelIndex()), &Struct->Rotation.Roll, RotationKeys[0])); } if (RotationKeys[1].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(RotationYChannel.GetChannelIndex()), &Struct->Rotation.Pitch, RotationKeys[1])); } if (RotationKeys[2].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(RotationZChannel.GetChannelIndex()), &Struct->Rotation.Yaw, RotationKeys[2])); } if (ScaleKeys[0].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(ScaleXChannel.GetChannelIndex()), &Struct->Scale.X, ScaleKeys[0])); } if (ScaleKeys[1].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(ScaleYChannel.GetChannelIndex()), &Struct->Scale.Y, ScaleKeys[1])); } if (ScaleKeys[2].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(ScaleZChannel.GetChannelIndex()), &Struct->Scale.Z, ScaleKeys[2])); } Struct->KeyStructInterop.SetStartingValues(); Struct->Time = Struct->KeyStructInterop.GetUnifiedKeyTime().Get(0); return KeyStruct; } if (AnyLocationKeys) { TSharedRef KeyStruct = MakeShareable(new FStructOnScope(FMovieScene3DLocationKeyStruct::StaticStruct())); auto Struct = (FMovieScene3DLocationKeyStruct*)KeyStruct->GetStructMemory(); if (LocationKeys[0].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(LocationXChannel.GetChannelIndex()), &Struct->Location.X, LocationKeys[0])); } if (LocationKeys[1].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(LocationYChannel.GetChannelIndex()), &Struct->Location.Y, LocationKeys[1])); } if (LocationKeys[2].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(LocationZChannel.GetChannelIndex()), &Struct->Location.Z, LocationKeys[2])); } Struct->KeyStructInterop.SetStartingValues(); Struct->Time = Struct->KeyStructInterop.GetUnifiedKeyTime().Get(0); return KeyStruct; } if (AnyRotationKeys) { TSharedRef KeyStruct = MakeShareable(new FStructOnScope(FMovieScene3DRotationKeyStruct::StaticStruct())); auto Struct = (FMovieScene3DRotationKeyStruct*)KeyStruct->GetStructMemory(); if (RotationKeys[0].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(RotationXChannel.GetChannelIndex()), &Struct->Rotation.Roll, RotationKeys[0])); } if (RotationKeys[1].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(RotationYChannel.GetChannelIndex()), &Struct->Rotation.Pitch, RotationKeys[1])); } if (RotationKeys[2].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(RotationZChannel.GetChannelIndex()), &Struct->Rotation.Yaw, RotationKeys[2])); } Struct->KeyStructInterop.SetStartingValues(); Struct->Time = Struct->KeyStructInterop.GetUnifiedKeyTime().Get(0); return KeyStruct; } if (AnyScaleKeys) { TSharedRef KeyStruct = MakeShareable(new FStructOnScope(FMovieScene3DScaleKeyStruct::StaticStruct())); auto Struct = (FMovieScene3DScaleKeyStruct*)KeyStruct->GetStructMemory(); if (ScaleKeys[0].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(ScaleXChannel.GetChannelIndex()), &Struct->Scale.X, ScaleKeys[0])); } if (ScaleKeys[1].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(ScaleYChannel.GetChannelIndex()), &Struct->Scale.Y, ScaleKeys[1])); } if (ScaleKeys[2].IsSet()) { Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelProxy->MakeHandle(ScaleZChannel.GetChannelIndex()), &Struct->Scale.Z, ScaleKeys[2])); } Struct->KeyStructInterop.SetStartingValues(); Struct->Time = Struct->KeyStructInterop.GetUnifiedKeyTime().Get(0); return KeyStruct; } return nullptr; } bool UMovieScene3DTransformSection::GetUseQuaternionInterpolation() const { return bUseQuaternionInterpolation; } void UMovieScene3DTransformSection::SetUseQuaternionInterpolation(bool bInUseQuaternionInterpolation) { bUseQuaternionInterpolation = bInUseQuaternionInterpolation; } bool UMovieScene3DTransformSection::ShowCurveForChannel(const void *ChannelPtr) const { if (GetUseQuaternionInterpolation()) { return ChannelPtr != &Rotation[0] && ChannelPtr != &Rotation[1] && ChannelPtr != &Rotation[2]; } return true; } void UMovieScene3DTransformSection::SetBlendType(EMovieSceneBlendType InBlendType) { Super::SetBlendType(InBlendType); if (GetSupportedBlendTypes().Contains(InBlendType)) { if (InBlendType == EMovieSceneBlendType::Absolute) { Scale[0].SetDefault(1.f); Scale[1].SetDefault(1.f); Scale[2].SetDefault(1.f); } else if (InBlendType == EMovieSceneBlendType::Additive || InBlendType == EMovieSceneBlendType::Relative) { Scale[0].SetDefault(0.f); Scale[1].SetDefault(0.f); Scale[2].SetDefault(0.f); } } } bool UMovieScene3DTransformSection::HasConstraintChannel(const FGuid& InGuid) const { if (Constraints) { return Constraints->ConstraintsChannels.ContainsByPredicate([InGuid](const FConstraintAndActiveChannel& InChannel) { return InChannel.GetConstraint().Get() ? InChannel.GetConstraint()->ConstraintID == InGuid : false; }); } return false; } FConstraintAndActiveChannel* UMovieScene3DTransformSection::GetConstraintChannel(const FGuid& InConstraintID) { if (Constraints) { const int32 Index = Constraints->ConstraintsChannels.IndexOfByPredicate([InConstraintID](const FConstraintAndActiveChannel& InChannel) { return InChannel.GetConstraint().Get() ? InChannel.GetConstraint()->ConstraintID == InConstraintID : false; }); return (Index != INDEX_NONE) ? &(Constraints->ConstraintsChannels[Index]) : nullptr; } return nullptr; } TArray& UMovieScene3DTransformSection::GetConstraintsChannels() { static TArray< FConstraintAndActiveChannel> EmptyChannels; if (Constraints) { return Constraints->ConstraintsChannels; } return EmptyChannels; } void UMovieScene3DTransformSection::PostLoad() { Super::PostLoad(); } #if WITH_EDITOR bool UMovieScene3DTransformSection::Modify(bool bAlwaysMarkDirty) { using namespace UE::MovieScene; if (Constraints) { Constraints->SetFlags(RF_Transactional); Constraints->Modify(bAlwaysMarkDirty); } bool bModified = Super::Modify(bAlwaysMarkDirty); return bModified; } void UMovieScene3DTransformSection::PostDuplicate(bool bDuplicateForPIE) { Super::PostDuplicate(bDuplicateForPIE); } #endif void UMovieScene3DTransformSection::AddConstraintChannel(UTickableConstraint* InConstraint) { Modify(); if (!Constraints) { Constraints = NewObject(this, NAME_None, RF_Public| RF_Transactional); } if (InConstraint && !HasConstraintChannel(InConstraint->ConstraintID)) { Constraints->SetFlags(RF_Transactional); Constraints->Modify(); const int32 NewIndex = Constraints->ConstraintsChannels.Add(FConstraintAndActiveChannel(InConstraint)); FMovieSceneConstraintChannel* ExistingChannel = &Constraints->ConstraintsChannels[NewIndex].ActiveChannel; ExistingChannel->SetDefault(false); //make copy that we can spawn if it doesn't exist //the rename changes the outer to this section (from any actor manager) InConstraint->Rename(nullptr, this, REN_DontCreateRedirectors); CacheChannelProxy(); if (OnConstraintChannelAdded.IsBound()) { OnConstraintChannelAdded.Broadcast(this, ExistingChannel); } } } void UMovieScene3DTransformSection::ReplaceConstraint(const FName InConstraintName, UTickableConstraint* InConstraint) { if (Constraints) { const int32 Index = Constraints->ConstraintsChannels.IndexOfByPredicate([InConstraintName](const FConstraintAndActiveChannel& InChannel) { return InChannel.GetConstraint().Get() ? InChannel.GetConstraint()->GetFName() == InConstraintName : false; }); if (Index != INDEX_NONE) { Modify(); Constraints->ConstraintsChannels[Index].GetConstraint() = InConstraint; CacheChannelProxy(); } } } void UMovieScene3DTransformSection::RemoveConstraintChannel(const UTickableConstraint* InConstraint) { if (bDoNotRemoveChannel == true) { return; } if (Constraints) { const int32 Index = Constraints->ConstraintsChannels.IndexOfByPredicate([InConstraint](const FConstraintAndActiveChannel& InChannel) { return InChannel.GetConstraint().Get() ? InChannel.GetConstraint().Get() == InConstraint : false; }); if (Constraints->ConstraintsChannels.IsValidIndex(Index)) { Modify(); Constraints->ConstraintsChannels.RemoveAt(Index); CacheChannelProxy(); } } } UMovieSceneSectionChannelOverrideRegistry* UMovieScene3DTransformSection::GetChannelOverrideRegistry(bool bCreateIfMissing) { if (bCreateIfMissing && OverrideRegistry == nullptr) { OverrideRegistry = NewObject(this, NAME_None, RF_Transactional); } return OverrideRegistry; } UE::MovieScene::FChannelOverrideProviderTraitsHandle UMovieScene3DTransformSection::GetChannelOverrideProviderTraits() const { struct F3DTransformChannelOverrideProviderTraits : UE::MovieScene::FChannelOverrideProviderTraits { FName GetDefaultChannelTypeName(FName ChannelName) const override { if (ChannelName == TEXT("Weight")) { return FMovieSceneFloatChannel::StaticStruct()->GetFName(); } else { return FMovieSceneDoubleChannel::StaticStruct()->GetFName(); } } int32 GetChannelOverrideEntityID(FName ChannelName) const override { return UMovieScene3DTransformSection::ChannelOverrideNames.GetIndex(ChannelName); } FName GetChannelOverrideName(int32 EntityID) const override { return UMovieScene3DTransformSection::ChannelOverrideNames.GetChannelName(EntityID); } }; F3DTransformChannelOverrideProviderTraits Traits; return UE::MovieScene::FChannelOverrideProviderTraitsHandle(Traits); } void UMovieScene3DTransformSection::OnConstraintsChanged() { ChannelProxy = nullptr; } void UMovieScene3DTransformSection::OnChannelOverridesChanged() { ChannelProxy = nullptr; } #if WITH_EDITOR void UMovieScene3DTransformSection::PostPaste() { Super::PostPaste(); if (OverrideRegistry) { OverrideRegistry->OnPostPaste(); } if (Constraints) { Constraints->ClearFlags(RF_Transient); } } void UMovieScene3DTransformSectionConstraints::PostEditUndo() { Super::PostEditUndo(); if (UMovieScene3DTransformSection* Section = GetTypedOuter()) { if (IMovieSceneConstrainedSection* ConstrainedSection = Cast(Section)) { ConstrainedSection->OnConstraintsChanged(); } } } #endif