void FSlomoTrackEditor::HandleAddSlomoTrackMenuEntryExecute() { UMovieScene* MovieScene = GetFocusedMovieScene(); if (MovieScene == nullptr) { return; } UMovieSceneTrack* SlomoTrack = MovieScene->FindMasterTrack<UMovieSceneSlomoTrack>(); if (SlomoTrack != nullptr) { return; } const FScopedTransaction Transaction(NSLOCTEXT("Sequencer", "AddSlomoTrack_Transaction", "Add Play Rate Track")); MovieScene->Modify(); SlomoTrack = FindOrCreateMasterTrack<UMovieSceneSlomoTrack>().Track; ensure(SlomoTrack); UMovieSceneSection* NewSection = SlomoTrack->CreateNewSection(); ensure(NewSection); SlomoTrack->AddSection(*NewSection); GetSequencer()->NotifyMovieSceneDataChanged(); }
void FSequencer::DeleteSection(class UMovieSceneSection* Section) { UMovieScene* MovieScene = GetFocusedMovieScene(); bool bAnythingRemoved = false; UMovieSceneTrack* Track = CastChecked<UMovieSceneTrack>( Section->GetOuter() ); // If this check fails then the section is outered to a type that doesnt know about the section //checkSlow( Track->HasSection(Section) ); Track->SetFlags( RF_Transactional ); FScopedTransaction DeleteSectionTransaction( NSLOCTEXT("Sequencer", "DeleteSection_Transaction", "Delete Section") ); Track->Modify(); Track->RemoveSection(Section); bAnythingRemoved = true; if( bAnythingRemoved ) { UpdateRuntimeInstances(); } }
void FSequencer::FilterToShotSections(const TArray< TWeakObjectPtr<class UMovieSceneSection> >& ShotSections, bool bZoomToShotBounds ) { TArray< TWeakObjectPtr<UMovieSceneSection> > ActualShotSections; for (int32 i = 0; i < ShotSections.Num(); ++i) { if (ShotSections[i]->IsA<UMovieSceneShotSection>()) { ActualShotSections.Add(ShotSections[i]); } } bool bWasPreviouslyFiltering = IsShotFilteringOn(); bool bIsNowFiltering = ActualShotSections.Num() > 0; FilteringShots.Empty(); UnfilterableSections.Empty(); UnfilterableObjects.Empty(); if (bIsNowFiltering) { for ( int32 ShotSectionIndex = 0; ShotSectionIndex < ActualShotSections.Num(); ++ShotSectionIndex ) { FilteringShots.Add( ActualShotSections[ShotSectionIndex] ); } // populate unfilterable shots - shots that started not filtered TArray< TWeakObjectPtr<class UMovieSceneSection> > TempUnfilterableSections; const TArray<UMovieSceneSection*>& AllSections = GetFocusedMovieScene()->GetAllSections(); for (int32 SectionIndex = 0; SectionIndex < AllSections.Num(); ++SectionIndex) { UMovieSceneSection* Section = AllSections[SectionIndex]; if (!Section->IsA<UMovieSceneShotSection>() && IsSectionVisible(Section)) { TempUnfilterableSections.Add(Section); } } // wait until after we've collected them all before applying in order to // prevent wastefully searching through UnfilterableSections in IsSectionVisible UnfilterableSections = TempUnfilterableSections; } if (!bWasPreviouslyFiltering && bIsNowFiltering) { OverlayAnimation.Play( SequencerWidget.ToSharedRef() ); } else if (bWasPreviouslyFiltering && !bIsNowFiltering) { OverlayAnimation.PlayReverse( SequencerWidget.ToSharedRef() ); } if( bZoomToShotBounds ) { // zoom in OnViewRangeChanged(GetTimeBounds(), true); } SequencerWidget->UpdateBreadcrumbs(ActualShotSections); }
void FSequencer::OnActorsDropped( const TArray<TWeakObjectPtr<AActor> >& Actors ) { bool bPossessableAdded = false; for( TWeakObjectPtr<AActor> WeakActor : Actors ) { AActor* Actor = WeakActor.Get(); if( Actor != NULL ) { // Grab the MovieScene that is currently focused. We'll add our Blueprint as an inner of the // MovieScene asset. UMovieScene* OwnerMovieScene = GetFocusedMovieScene(); // @todo sequencer: Undo doesn't seem to be working at all const FScopedTransaction Transaction( LOCTEXT("UndoPossessingObject", "Possess Object with MovieScene") ); // Possess the object! { // Create a new possessable OwnerMovieScene->Modify(); const FGuid PossessableGuid = OwnerMovieScene->AddPossessable( Actor->GetActorLabel(), Actor->GetClass() ); if ( IsShotFilteringOn() ) { AddUnfilterableObject(PossessableGuid); } ObjectBindingManager->BindPossessableObject( PossessableGuid, *Actor ); bPossessableAdded = true; } } } if( bPossessableAdded ) { SpawnOrDestroyPuppetObjects( GetFocusedMovieSceneInstance() ); NotifyMovieSceneDataChanged(); } }
void FSequencer::AddSubMovieScene( UMovieScene* SubMovieScene ) { // @todo Sequencer - sub-moviescenes This should be moved to the sub-moviescene editor SubMovieScene->SetFlags( RF_Transactional ); // Grab the MovieScene that is currently focused. THis is the movie scene that will contain the sub-moviescene UMovieScene* OwnerMovieScene = GetFocusedMovieScene(); // @todo sequencer: Undo doesn't seem to be working at all const FScopedTransaction Transaction( LOCTEXT("UndoAddingObject", "Add Object to MovieScene") ); OwnerMovieScene->Modify(); UMovieSceneTrack* Type = OwnerMovieScene->FindMasterTrack( USubMovieSceneTrack::StaticClass() ) ; if( !Type ) { Type = OwnerMovieScene->AddMasterTrack( USubMovieSceneTrack::StaticClass() ); } USubMovieSceneTrack* SubMovieSceneType = CastChecked<USubMovieSceneTrack>( Type ); SubMovieSceneType->AddMovieSceneSection( SubMovieScene, ScrubPosition ); }
TRange<float> FSequencer::GetTimeBounds() const { // When recording, we never want to constrain the time bound range. You might not even have any sections or keys yet // but we need to be able to move the time cursor during playback so you can capture data in real-time if( PlaybackState == EMovieScenePlayerStatus::Recording ) { return TRange<float>( -100000.0f, 100000.0f ); } const UMovieScene* MovieScene = GetFocusedMovieScene(); const UMovieSceneTrack* AnimatableShot = MovieScene->FindMasterTrack( UMovieSceneDirectorTrack::StaticClass() ); if (AnimatableShot) { // try getting filtered shot boundaries TRange<float> Bounds = GetFilteringShotsTimeBounds(); if (!Bounds.IsEmpty()) {return Bounds;} // try getting the bounds of all shots Bounds = AnimatableShot->GetSectionBoundaries(); if (!Bounds.IsEmpty()) {return Bounds;} } return MovieScene->GetTimeRange(); }
FGuid FSequencer::AddSpawnableForAssetOrClass( UObject* Object, UObject* CounterpartGamePreviewObject ) { FGuid NewSpawnableGuid; if( ObjectBindingManager->AllowsSpawnableObjects() ) { // Grab the MovieScene that is currently focused. We'll add our Blueprint as an inner of the // MovieScene asset. UMovieScene* OwnerMovieScene = GetFocusedMovieScene(); // @todo sequencer: Undo doesn't seem to be working at all const FScopedTransaction Transaction( LOCTEXT("UndoAddingObject", "Add Object to MovieScene") ); // Use the class as the spawnable's name if this is an actor class, otherwise just use the object name (asset) const bool bIsActorClass = Object->IsA( AActor::StaticClass() ) && !Object->HasAnyFlags( RF_ArchetypeObject ); const FName AssetName = bIsActorClass ? Object->GetClass()->GetFName() : Object->GetFName(); // Inner objects don't need a name (it will be auto-generated by the UObject system), but we want one in this case // because the class of any actors that are created from this Blueprint may end up being user-facing. const FName BlueprintName = MakeUniqueObjectName( OwnerMovieScene, UBlueprint::StaticClass(), AssetName ); // Use the asset name as the initial spawnable name const FString NewSpawnableName = AssetName.ToString(); // @todo sequencer: Need UI to allow user to rename these slots // Create our new blueprint! UBlueprint* NewBlueprint = NULL; { // @todo sequencer: Add support for forcing specific factories for an asset UActorFactory* FactoryToUse = NULL; if( bIsActorClass ) { // Placing an actor class directly:: FactoryToUse = GEditor->FindActorFactoryForActorClass( Object->GetClass() ); } else { // Placing an asset FactoryToUse = FActorFactoryAssetProxy::GetFactoryForAssetObject( Object ); } if( FactoryToUse != NULL ) { // Create the blueprint NewBlueprint = FactoryToUse->CreateBlueprint( Object, OwnerMovieScene, BlueprintName ); } else if( bIsActorClass ) { // We don't have a factory, but we can still try to create a blueprint for this actor class NewBlueprint = FKismetEditorUtilities::CreateBlueprint( Object->GetClass(), OwnerMovieScene, BlueprintName, EBlueprintType::BPTYPE_Normal, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass() ); } } if( ensure( NewBlueprint != NULL ) ) { if( NewBlueprint->GeneratedClass != NULL && FBlueprintEditorUtils::IsActorBased( NewBlueprint ) ) { AActor* ActorCDO = CastChecked< AActor >( NewBlueprint->GeneratedClass->ClassDefaultObject ); // If we have a counterpart object, then copy the properties from that object back into our blueprint's CDO // @todo sequencer livecapture: This isn't really good enough to handle complex actors. The dynamically-spawned actor could have components that // were created in its construction script or via straight-up C++ code. Instead what we should probably do is duplicate the PIE actor and generate // our CDO from that duplicate. It could get pretty complex though. if( CounterpartGamePreviewObject != NULL ) { AActor* CounterpartGamePreviewActor = CastChecked< AActor >( CounterpartGamePreviewObject ); CopyActorProperties( CounterpartGamePreviewActor, ActorCDO ); } else { // Place the new spawnable in front of the camera (unless we were automatically created from a PIE actor) PlaceActorInFrontOfCamera( ActorCDO ); } } NewSpawnableGuid = OwnerMovieScene->AddSpawnable( NewSpawnableName, NewBlueprint, CounterpartGamePreviewObject ); if (IsShotFilteringOn()) { AddUnfilterableObject(NewSpawnableGuid); } } } return NewSpawnableGuid; }
void FSequencer::OnRequestNodeDeleted( TSharedRef<const FSequencerDisplayNode>& NodeToBeDeleted ) { bool bAnySpawnablesRemoved = false; bool bAnythingRemoved = false; TSharedRef<FMovieSceneInstance> MovieSceneInstance = GetFocusedMovieSceneInstance(); UMovieScene* OwnerMovieScene = MovieSceneInstance->GetMovieScene(); // Only object nodes or section areas can be deleted if( NodeToBeDeleted->GetType() == ESequencerNode::Object ) { OwnerMovieScene->SetFlags( RF_Transactional ); const FGuid& BindingToRemove = StaticCastSharedRef<const FObjectBindingNode>( NodeToBeDeleted )->GetObjectBinding(); //@todo Sequencer - add transaction // Try to remove as a spawnable first bool bRemoved = OwnerMovieScene->RemoveSpawnable( BindingToRemove ); if( bRemoved ) { bAnySpawnablesRemoved = true; } if( !bRemoved ) { // The guid should be associated with a possessable if it wasnt a spawnable bRemoved = OwnerMovieScene->RemovePossessable( BindingToRemove ); // @todo Sequencer - undo needs to work here ObjectBindingManager->UnbindPossessableObjects( BindingToRemove ); // If this check fails the guid was not associated with a spawnable or possessable so there was an invalid guid being stored on a node check( bRemoved ); } bAnythingRemoved = true; } else if( NodeToBeDeleted->GetType() == ESequencerNode::Track ) { TSharedRef<const FTrackNode> SectionAreaNode = StaticCastSharedRef<const FTrackNode>( NodeToBeDeleted ); UMovieSceneTrack* Track = SectionAreaNode->GetTrack(); UMovieScene* FocusedMovieScene = GetFocusedMovieScene(); FocusedMovieScene->SetFlags( RF_Transactional ); if( FocusedMovieScene->IsAMasterTrack( Track ) ) { FocusedMovieScene->RemoveMasterTrack( Track ); } else { FocusedMovieScene->RemoveTrack( Track ); } bAnythingRemoved = true; } if( bAnythingRemoved ) { if( bAnySpawnablesRemoved ) { // @todo Sequencer Sub-MovieScenes needs to destroy objects for all movie scenes that had this node SpawnOrDestroyPuppetObjects( MovieSceneInstance ); } NotifyMovieSceneDataChanged(); } }