// Copyright Epic Games, Inc. All Rights Reserved. #include "MatineeImportTools.h" #include "MovieSceneSequence.h" #include "Tracks/MovieSceneAudioTrack.h" #include "ScopedTransaction.h" #include "MovieSceneCommonHelpers.h" #include "MovieSceneTimeHelpers.h" #include "IMovieScenePlayer.h" #include "Channels/MovieSceneChannelProxy.h" #include "MovieScene.h" #include "MovieSceneSequenceEditor.h" #include "Channels/MovieSceneEvent.h" #include "K2Node_CustomEvent.h" #include "MovieSceneSequenceEditor.h" #include "Kismet2/KismetEditorUtilities.h" #include "MovieSceneEventUtils.h" #include "Animation/SkeletalMeshActor.h" #include "EngineUtils.h" #include "Matinee/MatineeActor.h" #include "Matinee/InterpData.h" #include "Matinee/InterpGroupInst.h" #include "Matinee/InterpTrackFloatMaterialParam.h" #include "Matinee/InterpTrackVectorMaterialParam.h" #include "Matinee/InterpTrackLinearColorProp.h" #include "Matinee/InterpTrackColorProp.h" #include "Matinee/InterpTrackBoolProp.h" #include "Matinee/InterpTrackMoveAxis.h" #include "Matinee/InterpTrackAnimControl.h" #include "Matinee/InterpTrackSound.h" #include "Matinee/InterpTrackFade.h" #include "Matinee/InterpTrackDirector.h" #include "Matinee/InterpTrackEvent.h" #include "Matinee/InterpTrackVectorProp.h" #include "Matinee/InterpTrackVisibility.h" #include "Matinee/InterpTrackSlomo.h" #include "Tracks/MovieSceneBoolTrack.h" #include "Tracks/MovieSceneFloatTrack.h" #include "Tracks/MovieSceneMaterialTrack.h" #include "Tracks/MovieSceneColorTrack.h" #include "Tracks/MovieScene3DTransformTrack.h" #include "Tracks/MovieSceneParticleTrack.h" #include "Tracks/MovieSceneSkeletalAnimationTrack.h" #include "Tracks/MovieSceneFadeTrack.h" #include "Tracks/MovieSceneCameraCutTrack.h" #include "Tracks/MovieSceneEventTrack.h" #include "Tracks/MovieSceneVisibilityTrack.h" #include "Tracks/MovieSceneAudioTrack.h" #include "Tracks/MovieSceneVectorTrack.h" #include "Tracks/MovieSceneSlomoTrack.h" #include "Sections/MovieSceneColorSection.h" #include "Sections/MovieSceneBoolSection.h" #include "Sections/MovieSceneFloatSection.h" #include "Sections/MovieScene3DTransformSection.h" #include "Sections/MovieSceneSkeletalAnimationSection.h" #include "Sections/MovieSceneAudioSection.h" #include "Sections/MovieSceneFadeSection.h" #include "Sections/MovieSceneCameraCutSection.h" #include "Sections/MovieSceneEventSection.h" #include "Sections/MovieSceneEventTriggerSection.h" #include "Sections/MovieSceneVectorSection.h" #include "Sections/MovieSceneParameterSection.h" #include "Sections/MovieSceneSlomoSection.h" #include "Animation/AnimSequence.h" EMatineeImportSectionRangeMode FMatineeImportTools::SectionRangeMode = EMatineeImportSectionRangeMode::All; ERichCurveInterpMode FMatineeImportTools::MatineeInterpolationToRichCurveInterpolation( EInterpCurveMode CurveMode ) { switch ( CurveMode ) { case CIM_Constant: return ERichCurveInterpMode::RCIM_Constant; case CIM_CurveAuto: case CIM_CurveAutoClamped: case CIM_CurveBreak: case CIM_CurveUser: return ERichCurveInterpMode::RCIM_Cubic; case CIM_Linear: return ERichCurveInterpMode::RCIM_Linear; default: return ERichCurveInterpMode::RCIM_None; } } ERichCurveTangentMode FMatineeImportTools::MatineeInterpolationToRichCurveTangent( EInterpCurveMode CurveMode ) { switch ( CurveMode ) { case CIM_CurveBreak: return ERichCurveTangentMode::RCTM_Break; case CIM_CurveUser: // Import auto-clamped curves as user curves because rich curves don't have support for clamped tangents, and if the // user moves the converted keys, the tangents will get mangled. case CIM_CurveAutoClamped: return ERichCurveTangentMode::RCTM_User; default: return ERichCurveTangentMode::RCTM_Auto; } } void CleanupCurveKeys(FMovieSceneDoubleChannel* InChannel) { FKeyDataOptimizationParams Params; Params.bAutoSetInterpolation = true; UE::MovieScene::Optimize(InChannel, Params); } void CleanupCurveKeys(FMovieSceneFloatChannel* InChannel) { FKeyDataOptimizationParams Params; Params.bAutoSetInterpolation = true; UE::MovieScene::Optimize(InChannel, Params); } bool FMatineeImportTools::TryConvertMatineeToggleToOutParticleKey( ETrackToggleAction ToggleAction, EParticleKey& OutParticleKey ) { switch ( ToggleAction ) { case ETrackToggleAction::ETTA_On: OutParticleKey = EParticleKey::Activate; return true; case ETrackToggleAction::ETTA_Off: OutParticleKey = EParticleKey::Deactivate; return true; case ETrackToggleAction::ETTA_Trigger: OutParticleKey = EParticleKey::Trigger; return true; } return false; } void FMatineeImportTools::SetOrAddKey(TMovieSceneChannelData& ChannelData, FFrameNumber Time, float Value, float ArriveTangent, float LeaveTangent, EInterpCurveMode MatineeInterpMode, FFrameRate FrameRate , ERichCurveTangentWeightMode WeightedMode, float ArriveTangentWeight, float LeaveTangentWeight) { if (ChannelData.FindKey(Time) == INDEX_NONE) { FMovieSceneFloatValue NewKey(Value); NewKey.InterpMode = MatineeInterpolationToRichCurveInterpolation( MatineeInterpMode ); NewKey.TangentMode = MatineeInterpolationToRichCurveTangent( MatineeInterpMode ); NewKey.Tangent.ArriveTangent = ArriveTangent / FrameRate.AsDecimal(); NewKey.Tangent.LeaveTangent = LeaveTangent / FrameRate.AsDecimal(); NewKey.Tangent.TangentWeightMode = WeightedMode; NewKey.Tangent.ArriveTangentWeight = ArriveTangentWeight; NewKey.Tangent.LeaveTangentWeight = LeaveTangentWeight; ChannelData.AddKey( Time, NewKey ); } } void FMatineeImportTools::SetOrAddKey(TMovieSceneChannelData& ChannelData, FFrameNumber Time, double Value, float ArriveTangent, float LeaveTangent, EInterpCurveMode MatineeInterpMode, FFrameRate FrameRate , ERichCurveTangentWeightMode WeightedMode, float ArriveTangentWeight, float LeaveTangentWeight) { if (ChannelData.FindKey(Time) == INDEX_NONE) { FMovieSceneDoubleValue NewKey(Value); NewKey.InterpMode = MatineeInterpolationToRichCurveInterpolation( MatineeInterpMode ); NewKey.TangentMode = MatineeInterpolationToRichCurveTangent( MatineeInterpMode ); NewKey.Tangent.ArriveTangent = ArriveTangent / FrameRate.AsDecimal(); NewKey.Tangent.LeaveTangent = LeaveTangent / FrameRate.AsDecimal(); NewKey.Tangent.TangentWeightMode = WeightedMode; NewKey.Tangent.ArriveTangentWeight = ArriveTangentWeight; NewKey.Tangent.LeaveTangentWeight = LeaveTangentWeight; ChannelData.AddKey( Time, NewKey ); } } bool FMatineeImportTools::CopyInterpBoolTrack( UInterpTrackBoolProp* MatineeBoolTrack, UMovieSceneBoolTrack* BoolTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeFBoolTrack", "Paste Matinee Bool Track" ) ); bool bSectionCreated = false; BoolTrack->Modify(); FFrameRate FrameRate = BoolTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeBoolTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieSceneBoolSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( BoolTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( BoolTrack->CreateNewSection() ); BoolTrack->AddSection( *Section ); Section->SetRange(TRange::All()); bSectionCreated = true; if (MatineeBoolTrack->BoolTrack.Num() == 1) { Section->GetChannel().SetDefault(MatineeBoolTrack->BoolTrack[0].Value); } } if (Section->TryModify()) { if (MatineeBoolTrack->BoolTrack.Num() > 1) { TRange KeyRange = TRange::Empty(); TMovieSceneChannelData ChannelData = Section->GetChannelProxy().GetChannel(0)->GetData(); for ( const auto& Point : MatineeBoolTrack->BoolTrack ) { FFrameNumber KeyTime = (Point.Time * FrameRate).RoundToFrame(); ChannelData.UpdateOrAddKey(KeyTime, Point.Value); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !KeyRange.IsEmpty()) { Section->SetRange( KeyRange ); } } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpFloatTrack( UInterpTrackFloatBase* MatineeFloatTrack, UMovieSceneFloatTrack* FloatTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeFloatTrack", "Paste Matinee Float Track" ) ); bool bSectionCreated = false; FloatTrack->Modify(); FFrameRate FrameRate = FloatTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeFloatTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame();; UMovieSceneFloatSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( FloatTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( FloatTrack->CreateNewSection() ); FloatTrack->AddSection( *Section ); Section->SetRange(TRange::All()); bSectionCreated = true; if (MatineeFloatTrack->FloatTrack.Points.Num() == 1) { FMovieSceneFloatChannel* FloatChannel = Section->GetChannelProxy().GetChannel(0); FloatChannel->SetDefault(MatineeFloatTrack->FloatTrack.Points[0].OutVal); } } if (Section->TryModify()) { if (MatineeFloatTrack->FloatTrack.Points.Num() > 1) { TRange KeyRange = TRange::Empty(); FMovieSceneFloatChannel* Channel = Section->GetChannelProxy().GetChannel(0); TMovieSceneChannelData ChannelData = Channel->GetData(); for ( const auto& Point : MatineeFloatTrack->FloatTrack.Points ) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( ChannelData, KeyTime, Point.OutVal, Point.ArriveTangent, Point.LeaveTangent, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } CleanupCurveKeys(Channel); if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !KeyRange.IsEmpty()) { Section->SetRange( KeyRange ); } } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpMaterialParamTrack(UInterpTrackFloatMaterialParam* MatineeMaterialParamTrack, UMovieSceneComponentMaterialTrack * MaterialTrack) { const FScopedTransaction Transaction(NSLOCTEXT("Sequencer", "PasteMatineeFloatMaterialParamTrack", "Paste Matinee Float Material Param Track")); bool bSectionCreated = false; MaterialTrack->Modify(); FFrameRate FrameRate = MaterialTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeMaterialParamTrack->GetKeyframeTime(0) * FrameRate).RoundToFrame(); UMovieSceneParameterSection* Section = Cast(MovieSceneHelpers::FindSectionAtTime(MaterialTrack->GetAllSections(), FirstKeyTime)); if (Section == nullptr) { Section = Cast(MaterialTrack->CreateNewSection()); MaterialTrack->AddSection(*Section); Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { auto FirstPoint = MatineeMaterialParamTrack->FloatTrack.Points[0]; FFrameNumber KeyTime = (FirstPoint.InVal * FrameRate).RoundToFrame(); // The section needs a key added to be initialized, so add the first key from the matinee track. Section->AddScalarParameterKey(MatineeMaterialParamTrack->ParamName, KeyTime, FirstPoint.OutVal); TArray ScalarParms = Section->GetScalarParameterNamesAndCurves(); FMovieSceneFloatChannel* Channel = nullptr; int32 CurveIndex = 0; for (FScalarParameterNameAndCurve NameAndCurve : ScalarParms) { if (NameAndCurve.ParameterName == MatineeMaterialParamTrack->ParamName) { Channel = Section->GetChannelProxy().GetChannel(CurveIndex); break; } ++CurveIndex; } if (!Channel) { return false; } TMovieSceneChannelData ChannelData = Channel->GetData(); for (const auto& Point : MatineeMaterialParamTrack->FloatTrack.Points) { FFrameNumber CurrentKeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey(ChannelData, CurrentKeyTime, Point.OutVal, Point.ArriveTangent, Point.LeaveTangent, Point.InterpMode, FrameRate); } CleanupCurveKeys(Channel); } return bSectionCreated; } bool FMatineeImportTools::CopyInterpMaterialParamTrack(UInterpTrackVectorMaterialParam * MatineeMaterialParamTrack, UMovieSceneComponentMaterialTrack * MaterialTrack) { const FScopedTransaction Transaction(NSLOCTEXT("Sequencer", "PasteMatineeFloatMaterialParamTrack", "Paste Matinee Float Material Param Track")); bool bSectionCreated = false; MaterialTrack->Modify(); FFrameRate FrameRate = MaterialTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeMaterialParamTrack->GetKeyframeTime(0) * FrameRate).RoundToFrame(); UMovieSceneParameterSection* Section = Cast(MovieSceneHelpers::FindSectionAtTime(MaterialTrack->GetAllSections(), FirstKeyTime)); if (Section == nullptr) { Section = Cast(MaterialTrack->CreateNewSection()); MaterialTrack->AddSection(*Section); Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { FInterpCurvePointVector FirstPoint = MatineeMaterialParamTrack->VectorTrack.Points[0]; FFrameNumber KeyTime = (FirstPoint.InVal * FrameRate).RoundToFrame(); // The section needs a key added to be initialized, so add the first key from the matinee track. Section->AddVectorParameterKey(MatineeMaterialParamTrack->ParamName, KeyTime, FirstPoint.OutVal); TArray ScalarParms = Section->GetScalarParameterNamesAndCurves(); FMovieSceneFloatChannel* Channel = nullptr; int32 CurveIndex = 0; for (FScalarParameterNameAndCurve NameAndCurve : ScalarParms) { if (NameAndCurve.ParameterName == MatineeMaterialParamTrack->ParamName) { Channel = Section->GetChannelProxy().GetChannel(CurveIndex); break; } ++CurveIndex; } TArrayView Channels = Section->GetChannelProxy().GetChannels(); TMovieSceneChannelData ChannelData[3] = { Channels[CurveIndex]->GetData(), Channels[CurveIndex + 1]->GetData(), Channels[CurveIndex + 2]->GetData() }; for (const auto& Point : MatineeMaterialParamTrack->VectorTrack.Points) { FFrameNumber CurrentKeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey(ChannelData[0], CurrentKeyTime, Point.OutVal.X, Point.ArriveTangent.X, Point.LeaveTangent.X, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey(ChannelData[1], CurrentKeyTime, Point.OutVal.Y, Point.ArriveTangent.Y, Point.LeaveTangent.Y, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey(ChannelData[2], CurrentKeyTime, Point.OutVal.Z, Point.ArriveTangent.Z, Point.LeaveTangent.Z, Point.InterpMode, FrameRate); } CleanupCurveKeys(Channels[0]); CleanupCurveKeys(Channels[1]); CleanupCurveKeys(Channels[2]); } return bSectionCreated; } bool FMatineeImportTools::CopyInterpVectorTrack( UInterpTrackVectorProp* MatineeVectorTrack, UMovieSceneFloatVectorTrack* VectorTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeVectorTrack", "Paste Matinee Vector Track" ) ); bool bSectionCreated = false; VectorTrack->Modify(); FFrameRate FrameRate = VectorTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeVectorTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieSceneFloatVectorSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( VectorTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( VectorTrack->CreateNewSection() ); VectorTrack->AddSection( *Section ); Section->SetRange(TRange::All()); bSectionCreated = true; if (MatineeVectorTrack->VectorTrack.Points.Num() == 1) { if (Section->GetChannelsUsed() == 3) { const FInterpCurvePoint FirstPoint = MatineeVectorTrack->VectorTrack.Points[0]; TArrayView Channels = Section->GetChannelProxy().GetChannels(); Channels[0]->SetDefault(FirstPoint.OutVal.X); Channels[1]->SetDefault(FirstPoint.OutVal.Y); Channels[2]->SetDefault(FirstPoint.OutVal.Z); } } } if (Section->TryModify()) { if (MatineeVectorTrack->VectorTrack.Points.Num() > 1) { TRange KeyRange = TRange::Empty(); if (Section->GetChannelsUsed() == 3) { TArrayView Channels = Section->GetChannelProxy().GetChannels(); TMovieSceneChannelData ChannelData[3] = { Channels[0]->GetData(), Channels[1]->GetData(), Channels[2]->GetData() }; for ( const auto& Point : MatineeVectorTrack->VectorTrack.Points ) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( ChannelData[0], KeyTime, Point.OutVal.X, Point.ArriveTangent.X, Point.LeaveTangent.X, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[1], KeyTime, Point.OutVal.Y, Point.ArriveTangent.Y, Point.LeaveTangent.Y, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[2], KeyTime, Point.OutVal.Z, Point.ArriveTangent.Z, Point.LeaveTangent.Z, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } CleanupCurveKeys(Channels[0]); CleanupCurveKeys(Channels[1]); CleanupCurveKeys(Channels[2]); } if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !KeyRange.IsEmpty()) { Section->SetRange( KeyRange ); } } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpColorTrack( UInterpTrackColorProp* ColorPropTrack, UMovieSceneColorTrack* ColorTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeColorTrack", "Paste Matinee Color Track" ) ); bool bSectionCreated = false; ColorTrack->Modify(); FFrameRate FrameRate = ColorTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (ColorPropTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieSceneColorSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( ColorTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( ColorTrack->CreateNewSection() ); ColorTrack->AddSection( *Section ); TArrayView FloatChannels = Section->GetChannelProxy().GetChannels(); FloatChannels[0]->SetDefault(0.f); FloatChannels[1]->SetDefault(0.f); FloatChannels[2]->SetDefault(0.f); FloatChannels[3]->SetDefault(1.f); if (ColorPropTrack->VectorTrack.Points.Num() == 1) { const FInterpCurvePoint FirstPoint = ColorPropTrack->VectorTrack.Points[0]; TArrayView Channels = Section->GetChannelProxy().GetChannels(); Channels[0]->SetDefault(FirstPoint.OutVal.X); Channels[1]->SetDefault(FirstPoint.OutVal.Y); Channels[2]->SetDefault(FirstPoint.OutVal.Z); } Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { if (ColorPropTrack->VectorTrack.Points.Num() > 1) { TArrayView Channels = Section->GetChannelProxy().GetChannels(); TMovieSceneChannelData ChannelData[3] = { Channels[0]->GetData(), Channels[1]->GetData(), Channels[2]->GetData() }; TRange KeyRange = TRange::Empty(); for ( const FInterpCurvePoint& Point : ColorPropTrack->VectorTrack.Points ) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( ChannelData[0], KeyTime, Point.OutVal.X, Point.ArriveTangent.X, Point.LeaveTangent.X, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[1], KeyTime, Point.OutVal.Y, Point.ArriveTangent.Y, Point.LeaveTangent.Y, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[2], KeyTime, Point.OutVal.Z, Point.ArriveTangent.Z, Point.LeaveTangent.Z, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } CleanupCurveKeys(Channels[0]); CleanupCurveKeys(Channels[1]); CleanupCurveKeys(Channels[2]); if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !KeyRange.IsEmpty()) { Section->SetRange( KeyRange ); } } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpLinearColorTrack( UInterpTrackLinearColorProp* LinearColorPropTrack, UMovieSceneColorTrack* ColorTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeLinearColorTrack", "Paste Matinee Linear Color Track" ) ); bool bSectionCreated = false; ColorTrack->Modify(); FFrameRate FrameRate = ColorTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (LinearColorPropTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieSceneColorSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( ColorTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( ColorTrack->CreateNewSection() ); ColorTrack->AddSection( *Section ); TArrayView FloatChannels = Section->GetChannelProxy().GetChannels(); FloatChannels[0]->SetDefault(0.f); FloatChannels[1]->SetDefault(0.f); FloatChannels[2]->SetDefault(0.f); FloatChannels[3]->SetDefault(1.f); if (LinearColorPropTrack->LinearColorTrack.Points.Num() == 1) { const FInterpCurvePoint FirstPoint = LinearColorPropTrack->LinearColorTrack.Points[0]; TArrayView Channels = Section->GetChannelProxy().GetChannels(); Channels[0]->SetDefault(FirstPoint.OutVal.R); Channels[1]->SetDefault(FirstPoint.OutVal.G); Channels[2]->SetDefault(FirstPoint.OutVal.B); Channels[3]->SetDefault(FirstPoint.OutVal.A); } Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { if (LinearColorPropTrack->LinearColorTrack.Points.Num() > 1) { TRange KeyRange = TRange::Empty(); TArrayView Channels = Section->GetChannelProxy().GetChannels(); TMovieSceneChannelData ChannelData[4] = { Channels[0]->GetData(), Channels[1]->GetData(), Channels[2]->GetData(), Channels[3]->GetData() }; for ( const auto& Point : LinearColorPropTrack->LinearColorTrack.Points ) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( ChannelData[0], KeyTime, Point.OutVal.R, Point.ArriveTangent.R, Point.LeaveTangent.R, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[1], KeyTime, Point.OutVal.G, Point.ArriveTangent.G, Point.LeaveTangent.G, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[2], KeyTime, Point.OutVal.B, Point.ArriveTangent.B, Point.LeaveTangent.B, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[3], KeyTime, Point.OutVal.A, Point.ArriveTangent.A, Point.LeaveTangent.A, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } CleanupCurveKeys(Channels[0]); CleanupCurveKeys(Channels[1]); CleanupCurveKeys(Channels[2]); CleanupCurveKeys(Channels[3]); if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !KeyRange.IsEmpty()) { Section->SetRange( KeyRange ); } } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpMoveTrack( UInterpTrackMove* MoveTrack, UMovieScene3DTransformTrack* TransformTrack, const FVector& DefaultScale ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeMoveTrack", "Paste Matinee Move Track" ) ); bool bSectionCreated = false; TransformTrack->Modify(); FFrameRate FrameRate = TransformTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MoveTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieScene3DTransformSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( TransformTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( TransformTrack->CreateNewSection() ); TransformTrack->AddSection( *Section ); Section->SetRange(TRange::All()); bSectionCreated = true; TArrayView DoubleChannels = Section->GetChannelProxy().GetChannels(); DoubleChannels[6]->SetDefault(DefaultScale.X); DoubleChannels[7]->SetDefault(DefaultScale.Y); DoubleChannels[8]->SetDefault(DefaultScale.Z); } if (Section->TryModify()) { TRange KeyRange = TRange::Empty(); TArrayView Channels = Section->GetChannelProxy().GetChannels(); TMovieSceneChannelData ChannelData[6] = { Channels[0]->GetData(), Channels[1]->GetData(), Channels[2]->GetData(), Channels[3]->GetData(), Channels[4]->GetData(), Channels[5]->GetData() }; for ( const auto& Point : MoveTrack->PosTrack.Points ) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( ChannelData[0], KeyTime, Point.OutVal.X, Point.ArriveTangent.X, Point.LeaveTangent.X, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[1], KeyTime, Point.OutVal.Y, Point.ArriveTangent.Y, Point.LeaveTangent.Y, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[2], KeyTime, Point.OutVal.Z, Point.ArriveTangent.Z, Point.LeaveTangent.Z, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } for ( const auto& Point : MoveTrack->EulerTrack.Points ) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( ChannelData[3], KeyTime, Point.OutVal.X, Point.ArriveTangent.X, Point.LeaveTangent.X, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[4], KeyTime, Point.OutVal.Y, Point.ArriveTangent.Y, Point.LeaveTangent.Y, Point.InterpMode, FrameRate); FMatineeImportTools::SetOrAddKey( ChannelData[5], KeyTime, Point.OutVal.Z, Point.ArriveTangent.Z, Point.LeaveTangent.Z, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } for (auto SubTrack : MoveTrack->SubTracks) { if (SubTrack->IsA(UInterpTrackMoveAxis::StaticClass())) { UInterpTrackMoveAxis* MoveSubTrack = Cast(SubTrack); if (MoveSubTrack) { int32 ChannelIndex = INDEX_NONE; if (MoveSubTrack->MoveAxis == EInterpMoveAxis::AXIS_TranslationX) { ChannelIndex = 0; } else if (MoveSubTrack->MoveAxis == EInterpMoveAxis::AXIS_TranslationY) { ChannelIndex = 1; } else if (MoveSubTrack->MoveAxis == EInterpMoveAxis::AXIS_TranslationZ) { ChannelIndex = 2; } else if (MoveSubTrack->MoveAxis == EInterpMoveAxis::AXIS_RotationX) { ChannelIndex = 3; } else if (MoveSubTrack->MoveAxis == EInterpMoveAxis::AXIS_RotationY) { ChannelIndex = 4; } else if (MoveSubTrack->MoveAxis == EInterpMoveAxis::AXIS_RotationZ) { ChannelIndex = 5; } if (ChannelIndex != INDEX_NONE) { for (const auto& Point : MoveSubTrack->FloatTrack.Points) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( ChannelData[ChannelIndex], KeyTime, Point.OutVal, Point.ArriveTangent, Point.LeaveTangent, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } } } } } CleanupCurveKeys(Channels[0]); CleanupCurveKeys(Channels[1]); CleanupCurveKeys(Channels[2]); CleanupCurveKeys(Channels[3]); CleanupCurveKeys(Channels[4]); CleanupCurveKeys(Channels[5]); if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !UE::MovieScene::IsEmptyOrZeroSize(KeyRange)) { Section->SetRange( KeyRange ); } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpParticleTrack( UInterpTrackToggle* MatineeToggleTrack, UMovieSceneParticleTrack* ParticleTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeParticleTrack", "Paste Matinee Particle Track" ) ); bool bSectionCreated = false; ParticleTrack->Modify(); FFrameRate FrameRate = ParticleTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeToggleTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieSceneParticleSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( ParticleTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( ParticleTrack->CreateNewSection() ); ParticleTrack->AddSection( *Section ); Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { TRange KeyRange = TRange::Empty(); FMovieSceneParticleChannel* ParticleChannel = Section->GetChannelProxy().GetChannel(0); check(ParticleChannel); TMovieSceneChannelData ChannelData = ParticleChannel->GetData(); for ( const auto& Key : MatineeToggleTrack->ToggleTrack ) { FFrameNumber KeyTime = (Key.Time * FrameRate).RoundToFrame(); EParticleKey ParticleKey; if ( TryConvertMatineeToggleToOutParticleKey( Key.ToggleAction, ParticleKey ) ) { ChannelData.AddKey( KeyTime, (uint8)ParticleKey ); } KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !UE::MovieScene::IsEmptyOrZeroSize(KeyRange)) { Section->SetRange( KeyRange ); } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpAnimControlTrack( UInterpTrackAnimControl* MatineeAnimControlTrack, UMovieSceneSkeletalAnimationTrack* SkeletalAnimationTrack, FFrameNumber EndPlaybackRange ) { // @todo - Sequencer - Add support for slot names once they are implemented. const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeAnimTrack", "Paste Matinee Anim Track" ) ); bool bSectionCreated = false; FFrameRate FrameRate = SkeletalAnimationTrack->GetTypedOuter()->GetTickResolution(); SkeletalAnimationTrack->Modify(); SkeletalAnimationTrack->RemoveAllAnimationData(); for (int32 i = 0; i < MatineeAnimControlTrack->AnimSeqs.Num(); i++) { const auto& AnimSeq = MatineeAnimControlTrack->AnimSeqs[i]; float EndTime; if( AnimSeq.bLooping ) { if( i < MatineeAnimControlTrack->AnimSeqs.Num() - 1 ) { EndTime = MatineeAnimControlTrack->AnimSeqs[i + 1].StartTime; } else { EndTime = EndPlaybackRange / FrameRate; } } else { EndTime = AnimSeq.StartTime + ( ( ( AnimSeq.AnimSeq->GetPlayLength() - AnimSeq.AnimEndOffset ) - AnimSeq.AnimStartOffset ) / AnimSeq.AnimPlayRate ); // Clamp to next clip's start time if (i+1 < MatineeAnimControlTrack->AnimSeqs.Num()) { float NextStartTime = MatineeAnimControlTrack->AnimSeqs[i+1].StartTime; EndTime = FMath::Min(NextStartTime, EndTime); } } UMovieSceneSkeletalAnimationSection* NewSection = Cast( SkeletalAnimationTrack->CreateNewSection() ); NewSection->SetRange( TRange((AnimSeq.StartTime * FrameRate).RoundToFrame(), (EndTime * FrameRate).RoundToFrame() + 1) ); NewSection->Params.StartFrameOffset = FrameRate.AsFrameNumber(AnimSeq.AnimStartOffset); NewSection->Params.EndFrameOffset = FrameRate.AsFrameNumber(AnimSeq.AnimEndOffset); NewSection->Params.PlayRate = AnimSeq.AnimPlayRate; NewSection->Params.Animation = AnimSeq.AnimSeq; NewSection->Params.SlotName = MatineeAnimControlTrack->SlotName; // Matinee behavior is that animation sections hold their value after they end but Sequencer properly handles save/load restore // so we need to change the default behavior of the section to mimick Matinee more. NewSection->SetCompletionMode(EMovieSceneCompletionMode::KeepState); SkeletalAnimationTrack->AddSection( *NewSection ); bSectionCreated = true; } return bSectionCreated; } bool FMatineeImportTools::CopyInterpSoundTrack( UInterpTrackSound* MatineeSoundTrack, UMovieSceneAudioTrack* AudioTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeSoundTrack", "Paste Matinee Sound Track" ) ); bool bSectionCreated = false; FFrameRate FrameRate = AudioTrack->GetTypedOuter()->GetTickResolution(); AudioTrack->Modify(); int MaxSectionRowIndex = -1; for ( UMovieSceneSection* Section : AudioTrack->GetAllSections() ) { MaxSectionRowIndex = FMath::Max( MaxSectionRowIndex, Section->GetRowIndex() ); } for ( const FSoundTrackKey& SoundTrackKey : MatineeSoundTrack->Sounds ) { // AddNewSound automatically adds the new section to the track list, so no need to do it later. AudioTrack->AddNewSound( SoundTrackKey.Sound, (SoundTrackKey.Time * FrameRate).RoundToFrame() ); UMovieSceneAudioSection* NewAudioSection = Cast(AudioTrack->GetAllSections().Last()); NewAudioSection->SetRowIndex( MaxSectionRowIndex + 1 ); TArrayView FloatChannels = NewAudioSection->GetChannelProxy().GetChannels(); FloatChannels[0]->SetDefault(SoundTrackKey.Volume); FloatChannels[1]->SetDefault(SoundTrackKey.Pitch); bSectionCreated = true; } return bSectionCreated; } bool FMatineeImportTools::CopyInterpFadeTrack( UInterpTrackFade* MatineeFadeTrack, UMovieSceneFadeTrack* FadeTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeFadeTrack", "Paste Matinee Fade Track" ) ); bool bSectionCreated = false; FadeTrack->Modify(); FFrameRate FrameRate = FadeTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeFadeTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieSceneFadeSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( FadeTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( FadeTrack->CreateNewSection() ); FadeTrack->AddSection( *Section ); Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { TRange KeyRange = TRange::Empty(); FMovieSceneFloatChannel* FadeChannel = Section->GetChannelProxy().GetChannel(0); check(FadeChannel); TMovieSceneChannelData FadeInterface = FadeChannel->GetData(); for ( const auto& Point : MatineeFadeTrack->FloatTrack.Points ) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey( FadeInterface, KeyTime, Point.OutVal, Point.ArriveTangent, Point.LeaveTangent, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !UE::MovieScene::IsEmptyOrZeroSize(KeyRange)) { Section->SetRange( KeyRange ); } Section->FadeColor = MatineeFadeTrack->FadeColor; Section->bFadeAudio = MatineeFadeTrack->bFadeAudio; } return bSectionCreated; } bool FMatineeImportTools::CopyInterpDirectorTrack( UInterpTrackDirector* DirectorTrack, UMovieSceneCameraCutTrack* CameraCutTrack, AMatineeActor* MatineeActor, IMovieScenePlayer& Player ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeDirectorTrack", "Paste Matinee Director Track" ) ); bool bCutsAdded = false; FFrameRate FrameRate = CameraCutTrack->GetTypedOuter()->GetTickResolution(); CameraCutTrack->Modify(); for (FDirectorTrackCut TrackCut : DirectorTrack->CutTrack) { int32 GroupIndex = MatineeActor->MatineeData->FindGroupByName(TrackCut.TargetCamGroup); UInterpGroupInst* ViewGroupInst = (GroupIndex != INDEX_NONE) ? MatineeActor->FindFirstGroupInstByName( TrackCut.TargetCamGroup.ToString() ) : NULL; if ( GroupIndex != INDEX_NONE && ViewGroupInst ) { // Find a valid move track for this cut. UInterpGroup* Group = MatineeActor->MatineeData->InterpGroups[GroupIndex]; if (Group) { AActor* CameraActor = ViewGroupInst->GetGroupActor(); FGuid CameraHandle = Player.FindObjectId(*CameraActor, MovieSceneSequenceID::Root); if (CameraHandle.IsValid()) { CameraCutTrack->AddNewCameraCut(UE::MovieScene::FRelativeObjectBindingID(CameraHandle), (TrackCut.Time * FrameRate).RoundToFrame()); bCutsAdded = true; } } } } return bCutsAdded; } bool FMatineeImportTools::CopyInterpEventTrack( UInterpTrackEvent* MatineeEventTrack, UMovieSceneEventTrack* EventTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeEventTrack", "Paste Matinee Event Track" ) ); bool bSectionCreated = false; EventTrack->Modify(); if (MatineeEventTrack->EventTrack.Num()) { FFrameRate FrameRate = EventTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeEventTrack->EventTrack[0].Time * FrameRate).RoundToFrame(); UMovieSceneEventTriggerSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( EventTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( EventTrack->CreateNewSection() ); Section->SetRange(TRange::All()); EventTrack->AddSection(*Section); bSectionCreated = true; } UMovieSceneSequence* Sequence = Section->GetTypedOuter(); if (Section->TryModify()) { FMovieSceneSequenceEditor* SequenceEditor = FMovieSceneSequenceEditor::Find(Sequence); UBlueprint* SequenceDirectorBP = SequenceEditor ? SequenceEditor->GetOrCreateDirectorBlueprint(Sequence) : nullptr; if (SequenceDirectorBP) { SequenceDirectorBP->Modify(); FMovieSceneEventUtils::BindEventSectionToBlueprint(Section, SequenceDirectorBP); } TRange KeyRange = TRange::Empty(); FMovieSceneEventChannel* EventChannel = Section->GetChannelProxy().GetChannel(0); check(EventChannel); TMovieSceneChannelData ChannelData = EventChannel->GetData(); TMap EventMap; for (const FEventTrackKey& EventTrackKey : MatineeEventTrack->EventTrack) { FFrameNumber KeyTime = (EventTrackKey.Time * FrameRate).RoundToFrame(); FMovieSceneEvent Event; UK2Node_CustomEvent* ExistingEndpoint = EventMap.FindRef(EventTrackKey.EventName); if (ExistingEndpoint) { FMovieSceneEventUtils::SetEndpoint(&Event, Section, ExistingEndpoint, nullptr); } else if (SequenceDirectorBP) { FMovieSceneEventEndpointParameters Params; Params.SanitizedEventName = TEXT("MatineeEvent"); UK2Node_CustomEvent* NewEndpoint = FMovieSceneEventUtils::CreateUserFacingEvent(SequenceDirectorBP, Params); EventMap.Add(EventTrackKey.EventName, NewEndpoint); FMovieSceneEventUtils::SetEndpoint(&Event, Section, NewEndpoint, nullptr); } ChannelData.AddKey(KeyTime, Event); } } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpVisibilityTrack( UInterpTrackVisibility* MatineeVisibilityTrack, UMovieSceneVisibilityTrack* VisibilityTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeVisibilityTrack", "Paste Matinee Visibility track" ) ); bool bSectionCreated = false; VisibilityTrack->Modify(); if (MatineeVisibilityTrack->VisibilityTrack.Num()) { FFrameRate FrameRate = VisibilityTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeVisibilityTrack->GetKeyframeTime( 0 ) * FrameRate).RoundToFrame(); UMovieSceneBoolSection* Section = Cast( MovieSceneHelpers::FindSectionAtTime( VisibilityTrack->GetAllSections(), FirstKeyTime ) ); if ( Section == nullptr ) { Section = Cast( VisibilityTrack->CreateNewSection() ); VisibilityTrack->AddSection( *Section ); Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { TRange KeyRange = TRange::Empty(); bool bVisible = true; FMovieSceneBoolChannel* VisibilityChannel = Section->GetChannelProxy().GetChannel(0); check(VisibilityChannel); TMovieSceneChannelData ChannelData = VisibilityChannel->GetData(); for (FVisibilityTrackKey VisibilityTrackKey : MatineeVisibilityTrack->VisibilityTrack) { if (VisibilityTrackKey.Action == EVisibilityTrackAction::EVTA_Hide) { bVisible = false; } else if (VisibilityTrackKey.Action == EVisibilityTrackAction::EVTA_Show) { bVisible = true; } else if (VisibilityTrackKey.Action == EVisibilityTrackAction::EVTA_Toggle) { bVisible = !bVisible; } FFrameNumber KeyTime = (VisibilityTrackKey.Time * FrameRate).RoundToFrame(); ChannelData.UpdateOrAddKey(KeyTime, bVisible); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !UE::MovieScene::IsEmptyOrZeroSize(KeyRange)) { Section->SetRange( KeyRange ); } } } return bSectionCreated; } bool FMatineeImportTools::CopyInterpSlomoTrack(UInterpTrackSlomo* MatineeSlomoTrack, UMovieSceneSlomoTrack* SlomoTrack) { const FScopedTransaction Transaction(NSLOCTEXT("Sequencer", "PasteMatineeSlomoTrack", "Paste Matinee Slomo Track")); bool bSectionCreated = false; SlomoTrack->Modify(); FFrameRate FrameRate = SlomoTrack->GetTypedOuter()->GetTickResolution(); FFrameNumber FirstKeyTime = (MatineeSlomoTrack->GetKeyframeTime(0) * FrameRate).RoundToFrame(); UMovieSceneSlomoSection* Section = Cast(MovieSceneHelpers::FindSectionAtTime(SlomoTrack->GetAllSections(), FirstKeyTime)); if (Section == nullptr) { Section = Cast(SlomoTrack->CreateNewSection()); SlomoTrack->AddSection(*Section); Section->SetRange(TRange::All()); bSectionCreated = true; } if (Section->TryModify()) { TRange KeyRange = TRange::Empty(); FMovieSceneFloatChannel* SlomoChannel = Section->GetChannelProxy().GetChannel(0); check(SlomoChannel); TMovieSceneChannelData SlomoInterface = SlomoChannel->GetData(); for (const auto& Point : MatineeSlomoTrack->FloatTrack.Points) { FFrameNumber KeyTime = (Point.InVal * FrameRate).RoundToFrame(); FMatineeImportTools::SetOrAddKey(SlomoInterface, KeyTime, Point.OutVal, Point.ArriveTangent, Point.LeaveTangent, Point.InterpMode, FrameRate); KeyRange = TRange::Hull(KeyRange, TRange(KeyTime)); } CleanupCurveKeys(SlomoChannel); if (SectionRangeMode == EMatineeImportSectionRangeMode::KeysHull && !UE::MovieScene::IsEmptyOrZeroSize(KeyRange)) { Section->SetRange(KeyRange); } } return bSectionCreated; }