예제 #1
0
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 ) ) );
	}
}