// Copyright Epic Games, Inc. All Rights Reserved. #include "SequencerKeyStructGenerator.h" #include "Channels/MovieSceneChannelData.h" #include "UObject/CoreObjectVersion.h" UMovieSceneKeyStructType::UMovieSceneKeyStructType(const FObjectInitializer& ObjInit) : Super(ObjInit) { SourceValuesProperty = nullptr; SourceTimesProperty = nullptr; DestValueProperty = nullptr; DestTimeProperty = nullptr; } FSequencerKeyStructGenerator& FSequencerKeyStructGenerator::Get() { static FSequencerKeyStructGenerator Instance; return Instance; } UMovieSceneKeyStructType* FSequencerKeyStructGenerator::AllocateNewKeyStruct() { UMovieSceneKeyStructType* NewStruct = NewObject(GetTransientPackage(), NAME_None, RF_Public | RF_Standalone); NewStruct->SetSuperStruct(FGeneratedMovieSceneKeyStruct::StaticStruct()); return NewStruct; } UMovieSceneKeyStructType* FSequencerKeyStructGenerator::AllocateNewKeyStruct(UScriptStruct* ChannelType) { static const FName TimesMetaDataTag("KeyTimes"); static const FName ValuesMetaDataTag("KeyValues"); FArrayProperty* SourceTimes = FindArrayPropertyWithTag(ChannelType, TimesMetaDataTag); FArrayProperty* SourceValues = FindArrayPropertyWithTag(ChannelType, ValuesMetaDataTag); if (!ensureMsgf(SourceTimes, TEXT("No times property could be found for channel type %s. Please add KeyTimes meta data to the array containing the channel's key time."), *ChannelType->GetName())) { return nullptr; } else if (!ensureMsgf(SourceValues, TEXT("No value property could be found for channel type %s. Please add KeyValues meta data to the array containing the channel's key values."), *ChannelType->GetName())) { return nullptr; } UMovieSceneKeyStructType* NewStruct = AllocateNewKeyStruct(); NewStruct->SourceTimesProperty = SourceTimes; NewStruct->SourceValuesProperty = SourceValues; return NewStruct; } UMovieSceneKeyStructType* FSequencerKeyStructGenerator::DefaultInstanceGeneratedStruct(UScriptStruct* ChannelType) { UMovieSceneKeyStructType* Existing = FindGeneratedStruct(ChannelType->GetFName()); if (Existing) { return Existing; } else { UMovieSceneKeyStructType* NewStruct = FSequencerKeyStructGenerator::AllocateNewKeyStruct(ChannelType); if (!NewStruct) { return nullptr; } FProperty* NewValueProperty = CastField(FField::Duplicate(NewStruct->SourceValuesProperty->Inner, NewStruct, "Value")); NewValueProperty->SetPropertyFlags(CPF_Edit); NewValueProperty->SetMetaData("Category", TEXT("Key")); NewValueProperty->SetMetaData("ShowOnlyInnerProperties", TEXT("true")); NewValueProperty->ArrayDim = 1; NewStruct->AddCppProperty(NewValueProperty); NewStruct->DestValueProperty = NewValueProperty; FSequencerKeyStructGenerator::FinalizeNewKeyStruct(NewStruct); AddGeneratedStruct(ChannelType->GetFName(), NewStruct); return NewStruct; } } void FSequencerKeyStructGenerator::FinalizeNewKeyStruct(UMovieSceneKeyStructType* InStruct) { check(InStruct); // Add the time property to the head of the property linked list (so it shows first) FStructProperty* NewTimeProperty = new FStructProperty(InStruct, "Time", RF_NoFlags); NewTimeProperty->SetPropertyFlags(CPF_Edit); NewTimeProperty->SetMetaData("Category", TEXT("Key")); NewTimeProperty->ArrayDim = 1; NewTimeProperty->Struct = TBaseStructure::Get(); InStruct->AddCppProperty(NewTimeProperty); InStruct->DestTimeProperty = NewTimeProperty; // Finalize the struct InStruct->Bind(); InStruct->StaticLink(true); UMovieSceneKeyStructType::DeferCppStructOps(InStruct->GetFName(), new UScriptStruct::TCppStructOps); check(InStruct->IsComplete()); } void FSequencerKeyStructGenerator::AddReferencedObjects( FReferenceCollector& Collector ) { Collector.AddReferencedObjects(InstanceNameToGeneratedStruct); } void FSequencerKeyStructGenerator::AddGeneratedStruct(FName InstancedStructName, UMovieSceneKeyStructType* Struct) { check(!InstanceNameToGeneratedStruct.Contains(InstancedStructName)); InstanceNameToGeneratedStruct.Add(InstancedStructName, Struct); } UMovieSceneKeyStructType* FSequencerKeyStructGenerator::FindGeneratedStruct(FName InstancedStructName) { return InstanceNameToGeneratedStruct.FindRef(InstancedStructName); } FArrayProperty* FSequencerKeyStructGenerator::FindArrayPropertyWithTag(UScriptStruct* ChannelStruct, FName MetaDataTag) { for (FArrayProperty* ArrayProperty : TFieldRange(ChannelStruct)) { if (ArrayProperty->HasMetaData(MetaDataTag)) { return ArrayProperty; } } return nullptr; } TSharedPtr FSequencerKeyStructGenerator::CreateInitialStructInstance(const void* SourceChannel, UMovieSceneKeyStructType* GeneratedStructType, int32 InitialKeyIndex) { check(InitialKeyIndex != INDEX_NONE); TSharedPtr Struct = MakeShared(GeneratedStructType); FGeneratedMovieSceneKeyStruct* StructPtr = reinterpret_cast(Struct->GetStructMemory()); // Copy the initial time into the struct { const uint8* SrcTimeData = GeneratedStructType->SourceTimesProperty->ContainerPtrToValuePtr(SourceChannel); uint8* DestTimeData = GeneratedStructType->DestTimeProperty->ContainerPtrToValuePtr(StructPtr); FScriptArrayHelper SourceTimesArray(GeneratedStructType->SourceTimesProperty.Get(), SrcTimeData); GeneratedStructType->SourceTimesProperty->Inner->CopyCompleteValue(DestTimeData, SourceTimesArray.GetRawPtr(InitialKeyIndex)); } // Copy the initial value into the struct { const uint8* SrcValueData = GeneratedStructType->SourceValuesProperty->ContainerPtrToValuePtr(SourceChannel); uint8* DestValueData = GeneratedStructType->DestValueProperty->ContainerPtrToValuePtr(StructPtr); FScriptArrayHelper SourceValuesArray(GeneratedStructType->SourceValuesProperty.Get(), SrcValueData); GeneratedStructType->SourceValuesProperty->Inner->CopyCompleteValue(DestValueData, SourceValuesArray.GetRawPtr(InitialKeyIndex)); } return Struct; }