void FMovieSceneSequenceInstance::RefreshInstance( IMovieScenePlayer& Player ) { if(MovieSceneSequence.IsValid()) { UMovieScene* MovieScene = MovieSceneSequence->GetMovieScene(); TimeRange = MovieScene->GetPlaybackRange(); UMovieSceneTrack* CameraCutTrack = MovieScene->GetCameraCutTrack(); if (CameraCutTrack != nullptr) { FMovieSceneInstanceMap CameraCutTrackInstanceMap; if (CameraCutTrackInstance.IsValid()) { CameraCutTrackInstanceMap.Add(CameraCutTrack, CameraCutTrackInstance); } TArray<TWeakObjectPtr<UObject>> Objects; TArray<UMovieSceneTrack*> Tracks; Tracks.Add(CameraCutTrack); RefreshInstanceMap(Tracks, Objects, CameraCutTrackInstanceMap, Player); CameraCutTrackInstance = CameraCutTrackInstanceMap.FindRef(CameraCutTrack); } else if(CameraCutTrackInstance.IsValid()) { CameraCutTrackInstance->ClearInstance(Player, *this); CameraCutTrackInstance.Reset(); } // Get all the master tracks and create instances for them if needed const TArray<UMovieSceneTrack*>& MasterTracks = MovieScene->GetMasterTracks(); TArray<TWeakObjectPtr<UObject>> Objects; RefreshInstanceMap( MasterTracks, Objects, MasterTrackInstances, Player ); TSet< FGuid > FoundObjectBindings; // Get all tracks for each object binding and create instances for them if needed const TArray<FMovieSceneBinding>& ObjectBindings = MovieScene->GetBindings(); for( int32 BindingIndex = 0; BindingIndex < ObjectBindings.Num(); ++BindingIndex ) { const FMovieSceneBinding& ObjectBinding = ObjectBindings[BindingIndex]; // Create an instance for this object binding FMovieSceneObjectBindingInstance& BindingInstance = ObjectBindingInstances.FindOrAdd( ObjectBinding.GetObjectGuid() ); BindingInstance.ObjectGuid = ObjectBinding.GetObjectGuid(); FoundObjectBindings.Add( ObjectBinding.GetObjectGuid() ); // Populate the runtime objects for this instance of the binding. // @todo sequencer: SubSequences: We need to know which actors were removed and which actors were added so we know which saved actor state to restore/create BindingInstance.RuntimeObjects.Empty(); Player.GetRuntimeObjects( SharedThis( this ), BindingInstance.ObjectGuid, BindingInstance.RuntimeObjects ); // Refresh the instance's tracks const TArray<UMovieSceneTrack*>& Tracks = ObjectBinding.GetTracks(); RefreshInstanceMap( Tracks, BindingInstance.RuntimeObjects, BindingInstance.TrackInstances, Player ); } IMovieSceneSpawnRegister& SpawnRegister = Player.GetSpawnRegister(); // Remove object binding instances which are no longer bound TMap<FGuid, FMovieSceneObjectBindingInstance>::TIterator It = ObjectBindingInstances.CreateIterator(); for( ; It; ++It ) { if( !FoundObjectBindings.Contains( It.Key() ) ) { SpawnRegister.DestroySpawnedObject(It.Key(), *this, Player); // The instance no longer is bound to an existing guid It.RemoveCurrent(); } } } }
void FSequencerNodeTree::Update() { // @todo Sequencer - This update pass is too aggressive. Some nodes may still be valid Empty(); UMovieScene* MovieScene = Sequencer.GetFocusedMovieSceneSequence()->GetMovieScene(); TArray< TSharedRef<FSequencerDisplayNode> > NewRootNodes; // Get the master tracks so we can get sections from them const TArray<UMovieSceneTrack*>& MasterTracks = MovieScene->GetMasterTracks(); for( UMovieSceneTrack* Track : MasterTracks ) { UMovieSceneTrack& TrackRef = *Track; TSharedRef<FTrackNode> SectionNode = MakeShareable( new FTrackNode( TrackRef.GetTrackName(), TrackRef, NULL, *this ) ); NewRootNodes.Add( SectionNode ); MakeSectionInterfaces( TrackRef, SectionNode ); SectionNode->PinNode(); } const TArray<FMovieSceneBinding>& Bindings = MovieScene->GetBindings(); TMap<FGuid, const FMovieSceneBinding*> GuidToBindingMap; for (const FMovieSceneBinding& Binding : Bindings) { GuidToBindingMap.Add(Binding.GetObjectGuid(), &Binding); } // Make nodes for all object bindings TArray< TSharedRef<FSequencerDisplayNode> > NewObjectNodes; for( const FMovieSceneBinding& Binding : Bindings ) { TSharedRef<FObjectBindingNode> ObjectBindingNode = AddObjectBinding( Binding.GetName(), Binding.GetObjectGuid(), GuidToBindingMap, NewObjectNodes ); const TArray<UMovieSceneTrack*>& Tracks = Binding.GetTracks(); for( UMovieSceneTrack* Track : Tracks ) { UMovieSceneTrack& TrackRef = *Track; FName SectionName = TrackRef.GetTrackName(); check( SectionName != NAME_None ); TSharedRef<FTrackNode> SectionAreaNode = ObjectBindingNode->AddSectionAreaNode( SectionName, TrackRef ); MakeSectionInterfaces( TrackRef, SectionAreaNode ); } } struct FObjectNodeSorter { bool operator()( const TSharedRef<FSequencerDisplayNode>& A, const TSharedRef<FSequencerDisplayNode>& B ) const { if (A->GetType() == ESequencerNode::Object && B->GetType() != ESequencerNode::Object) { return true; } if (A->GetType() != ESequencerNode::Object && B->GetType() == ESequencerNode::Object) { return false; } return A->GetDisplayName().ToString() < B->GetDisplayName().ToString(); } }; NewObjectNodes.Sort( FObjectNodeSorter() ); for (TSharedRef<FSequencerDisplayNode> NewObjectNode : NewObjectNodes) { NewObjectNode->SortChildNodes(FObjectNodeSorter()); } NewRootNodes.Append(NewObjectNodes); // Look for a shot track. It will always come first if it exists UMovieSceneTrack* ShotTrack = MovieScene->GetShotTrack(); if( ShotTrack ) { TSharedRef<FTrackNode> SectionNode = MakeShareable( new FTrackNode( ShotTrack->GetTrackName(), *ShotTrack, NULL, *this ) ); // Shot track always comes first RootNodes.Add( SectionNode ); MakeSectionInterfaces( *ShotTrack, SectionNode ); SectionNode->PinNode(); } // Add all other nodes after the shot track RootNodes.Append( NewRootNodes ); // Set up virtual offsets, and expansion states float VerticalOffset = 0.f; for (auto& Node : RootNodes) { Node->Traverse_ParentFirst([&](FSequencerDisplayNode& InNode){ float VerticalTop = VerticalOffset; VerticalOffset += InNode.GetNodeHeight() + InNode.GetNodePadding().Combined(); InNode.Initialize(VerticalTop, VerticalOffset); return true; }); } // Re-filter the tree after updating // @todo Sequencer - Newly added sections may need to be visible even when there is a filter FilterNodes( FilterString ); }