void FSlomoTrackEditor::HandleAddSlomoTrackMenuEntryExecute() { UMovieSceneSequence* FocusedSequence = GetSequencer()->GetFocusedMovieSceneSequence(); UMovieScene* MovieScene = FocusedSequence->GetMovieScene(); if (MovieScene == nullptr) { return; } UMovieSceneTrack* SlomoTrack = MovieScene->FindMasterTrack( UMovieSceneSlomoTrack::StaticClass() ); if (SlomoTrack != nullptr) { return; } const FScopedTransaction Transaction(NSLOCTEXT("Sequencer", "AddSlomoTrack_Transaction", "Add Play Rate Track")); MovieScene->Modify(); SlomoTrack = GetMasterTrack( UMovieSceneSlomoTrack::StaticClass() ); ensure(SlomoTrack); SlomoTrack->AddSection(SlomoTrack->CreateNewSection()); GetSequencer()->NotifyMovieSceneDataChanged(); }
void FMovieSceneSequenceInstance::OnSpawnedObjectDestroyed(const FGuid& ObjectId, IMovieScenePlayer& Player) { if(MovieSceneSequence.IsValid()) { auto* BindingInstance = ObjectBindingInstances.Find(ObjectId); if (!BindingInstance) { return; } SpawnedObjects.Remove(ObjectId); // Destroy the object BindingInstance->RuntimeObjects.Reset(); // Update any child possessable object bindings UMovieSceneSequence* Sequence = GetSequence(); FMovieSceneSpawnable* Spawnable = Sequence ? Sequence->GetMovieScene()->FindSpawnable(ObjectId) : nullptr; if (Spawnable) { for (const FGuid& Child : Spawnable->GetChildPossessables()) { UpdateObjectBinding(Child, Player); } } } }
void FMovieSceneSequenceInstance::OnObjectSpawned(const FGuid& ObjectId, UObject& SpawnedObject, IMovieScenePlayer& Player) { if(MovieSceneSequence.IsValid()) { auto* BindingInstance = ObjectBindingInstances.Find(ObjectId); if (!BindingInstance) { return; } SpawnedObjects.Add(ObjectId, &SpawnedObject); // Add it to the instance's runtime objects array, and update any child possessable binding instances BindingInstance->RuntimeObjects.Reset(); BindingInstance->RuntimeObjects.Emplace(&SpawnedObject); UMovieSceneSequence* Sequence = GetSequence(); FMovieSceneSpawnable* Spawnable = Sequence ? Sequence->GetMovieScene()->FindSpawnable(ObjectId) : nullptr; if (Spawnable) { UpdateObjectBinding(ObjectId, Player); for (const FGuid& Child : Spawnable->GetChildPossessables()) { UpdateObjectBinding(Child, Player); } } } }
void FMovieSceneSequenceInstance::UpdateObjectBinding(const FGuid& ObjectId, IMovieScenePlayer& Player) { if(MovieSceneSequence.IsValid()) { UMovieSceneSequence* Sequence = MovieSceneSequence.Get(); auto* BindingInstance = ObjectBindingInstances.Find(ObjectId); if (!BindingInstance || !Sequence) { return; } // Update the runtime objects BindingInstance->RuntimeObjects.Reset(); TWeakObjectPtr<UObject>* WeakSpawnedObject = SpawnedObjects.Find(ObjectId); if (WeakSpawnedObject) { UObject* SpawnedObject = WeakSpawnedObject->Get(); if (SpawnedObject) { BindingInstance->RuntimeObjects.Add(SpawnedObject); } } else { Player.GetRuntimeObjects(SharedThis(this), BindingInstance->ObjectGuid, BindingInstance->RuntimeObjects); } const FMovieSceneBinding* ObjectBinding = Sequence->GetMovieScene()->GetBindings().FindByPredicate([&](const FMovieSceneBinding& In){ return In.GetObjectGuid() == ObjectId; }); // Refresh the instance map, if we found the binding itself if (ObjectBinding) { RefreshInstanceMap(ObjectBinding->GetTracks(), BindingInstance->RuntimeObjects, BindingInstance->TrackInstances, Player); } } }
void FSpawnTrackEditor::BuildObjectBindingTrackMenu(FMenuBuilder& MenuBuilder, const FGuid& ObjectBinding, const UClass* ObjectClass) { UMovieSceneSequence* MovieSequence = GetSequencer()->GetFocusedMovieSceneSequence(); if (!MovieSequence || MovieSequence->GetClass()->GetName() != TEXT("LevelSequence") || !MovieSequence->GetMovieScene()->FindSpawnable(ObjectBinding)) { return; } MenuBuilder.AddMenuEntry( LOCTEXT("AddSpawnTrack", "Spawn Track"), LOCTEXT("AddSpawnTrackTooltip", "Adds a new track that controls the lifetime of the track's spawnable object."), FSlateIcon(), FUIAction( FExecuteAction::CreateRaw(this, &FSpawnTrackEditor::HandleAddSpawnTrackMenuEntryExecute, ObjectBinding), FCanExecuteAction::CreateSP(this, &FSpawnTrackEditor::CanAddSpawnTrack, ObjectBinding) ) ); }
void FColorPropertySection::ConsolidateColorCurves( TArray< TKeyValuePair<float, FLinearColor> >& OutColorKeys, const UMovieSceneColorSection* Section ) const { // Get the default color of the first instance FLinearColor DefaultColor( 0.0f, 0.0f, 0.0f, 0.0f ); static const FName SlateColorName( "SlateColor" ); UMovieSceneSequence* Sequence = Sequencer->GetFocusedMovieSceneSequence(); const TArray<FMovieSceneBinding>& MovieSceneBindings = Sequence->GetMovieScene()->GetBindings(); bool bFoundColor = false; for ( int32 BindingIndex = 0; BindingIndex < MovieSceneBindings.Num() && !bFoundColor; ++BindingIndex ) { const FMovieSceneBinding& MovieSceneBinding = MovieSceneBindings[BindingIndex]; for ( int32 TrackIndex = 0; TrackIndex < MovieSceneBinding.GetTracks().Num() && !bFoundColor; ++TrackIndex ) { if ( MovieSceneBinding.GetTracks()[TrackIndex] == Track ) { UObject* RuntimeObject = Sequence->FindObject( MovieSceneBinding.GetObjectGuid() ); if ( RuntimeObject != nullptr ) { UProperty* Property = RuntimeObject->GetClass()->FindPropertyByName( CastChecked<UMovieSceneColorTrack>( Track )->GetPropertyName() ); UStructProperty* ColorStructProp = Cast<UStructProperty>( Property ); if ( ColorStructProp && ColorStructProp->Struct ) { if ( ColorStructProp->Struct->GetFName() == SlateColorName ) { DefaultColor = (*Property->ContainerPtrToValuePtr<FSlateColor>( RuntimeObject )).GetSpecifiedColor(); } else if ( ColorStructProp->Struct->GetFName() == NAME_LinearColor ) { DefaultColor = *Property->ContainerPtrToValuePtr<FLinearColor>( RuntimeObject ); } else { DefaultColor = Property->ContainerPtrToValuePtr<FColor>( RuntimeObject )->ReinterpretAsLinear(); } bFoundColor = true; break; } } } } } // @todo Sequencer Optimize - This could all get cached, instead of recalculating everything every OnPaint const FRichCurve* Curves[4] = { &Section->GetRedCurve(), &Section->GetGreenCurve(), &Section->GetBlueCurve(), &Section->GetAlphaCurve() }; // @todo Sequencer Optimize - This is a O(n^2) loop! // Our times are floats, which means we can't use a map and // do a quick lookup to see if the keys already exist // because the keys are ordered, we could take advantage of that, however TArray<float> TimesWithKeys; for ( int32 i = 0; i < 4; ++i ) { const FRichCurve* Curve = Curves[i]; for ( auto It( Curve->GetKeyIterator() ); It; ++It ) { float KeyTime = It->Time; bool bShouldAddKey = true; int32 InsertKeyIndex = INDEX_NONE; for ( int32 k = 0; k < TimesWithKeys.Num(); ++k ) { if ( FMath::IsNearlyEqual( TimesWithKeys[k], KeyTime ) ) { bShouldAddKey = false; break; } else if ( TimesWithKeys[k] > KeyTime ) { InsertKeyIndex = k; break; } } if ( InsertKeyIndex == INDEX_NONE && bShouldAddKey ) { InsertKeyIndex = TimesWithKeys.Num(); } if ( bShouldAddKey ) { TimesWithKeys.Insert( KeyTime, InsertKeyIndex ); } } } // @todo Sequencer Optimize - This another O(n^2) loop, since Eval is O(n)! for ( int32 i = 0; i < TimesWithKeys.Num(); ++i ) { OutColorKeys.Add( TKeyValuePair<float, FLinearColor>( TimesWithKeys[i], Section->Eval( TimesWithKeys[i], DefaultColor ) ) ); } }