Files
UnrealEngineUWP/Engine/Source/Editor/AnimationBlueprintLibrary/Private/AnimationAttributeBlueprintLibrary.cpp
Marc Audy de2c3cb8e0 [Backout] - CL20593017, 20594056, 20625634, 20645670, 20649179, 20649223, 20649380, 20658535
Add new custom version to specify a certain window of AnimSequences are not loadable
#fyi Jurre.deBaare
#robomerge EngineMerge
Original CL Desc
-----------------------------------------------------------------
**New**
- Engine
	- IAnimationDataModel interface
- AnimationData plugin
	- AnimSequencerDataModel, sequencer based implementation of IAnimationDataModel
	- AnimSequencerDataController, controller for above (implementation of IAnimationDataController)
- Added FCompressedRichCurve::PopulateCurve, allowing users to convert back to a FRichCurve for validation/debugging
- Added DefaultFrameRate to AnimationSettings, this replaces the hardcoded 30FPS in code
- Added ::GetKeyIndicesFromTime which takes FFrameRate
- Added AnimSequenceBase::OnAnimModelLoaded, this is required for correct postloading behaviour of data model (specifically AnimSequencerDataModel, as it depends on data from its outer ? anim sequence)
- Added IAnimationDataModel ::Evaluate which now takes responsibility for evaluating raw animation bone, curve and attribute data. And moved all trackbased evaluation code into AnimDataModel.cpp
- Added a.ForceEvalRawData allowing to force evaluation of source data
- Added a.SkipDDC to force compressing animation data locally

**Changed**
- Reparent UAnimDataModel to IAnimationDataModel interface, and rejig behaviour
- AnimSequenceBase now reference AnimDataModel as IAnimationDataModel
- Upgrade path for legacy to IAnimationDataModel and existing UAnimDataModel to IAnimationDataModel through IAnimationDataController::PopulateWithExisting
- IAnimationDataModel data is now frame(number/rate/time) based rather than seconds/keyindices. This enforces frameborder aligned data from now on.
- Moved RichCurve evaluation code from RichCurve.cpp to separate file and consolidated all instances of copy-pasta behaviour
- Updated/removed deprecated EngineTests around AnimSequences
- Changed many instances to use a FFrameTime together with a known FFrameRate versus seconds and sequencelength in float involving frame \/ time calculations (including instances of FAnimKeyHelper)
- Switched anim sequence evaluation to use double in Extraction context for time value and patched up places with static\_cast\<double\>
- FRichCurve::Eval
	- Make sure we always evaluate keys when T >= Key0.Time and T <= KeyN.Time to deal with crazy userweighted tangents
- Fixed WeightedKeyDataAdapter::GetKeyInterpMode/GetKeyTangentWeightMode retrieving invalid values, as it was indexing according to KeyIndex rather than KeyIndex\*2. This made it so that values were misinterpreted.
- Fixed WeightedEvalForTwoKeys for compressed data retrieving GetKeyInterpMode and GetKeyTangentWeightMode using the wrong index value. As they are not indexed using KeyDataHandle type.
- Fixed issue where compression could crash when containing zero-key scale additivebase track (tries to retrieve)
- Replaced instances of NULL with nullptr
- Moved required decompression information into FAnimSequenceDecompressionContext and reimplemented decompression within UE::Anim::Decompression namespace and new file
- Deprecated ::GetRawDataGuid and replaced with GetDataModel()->GenerateGuid()
- Fixed UAnimStreamable evaluation/compression (previously broken with MVC refactor)
- Updated Animation exporting pipeline to be frame-based rather than seconds
- Deprecated RetargetPose, replaced with FRetargetingScope (used within AnimModel::Evaluate)
- Fixed BaseAdditiveAnimation array become invalid/incorrect when removing zero-additve tracks during compression
- Updated EngineTest animation sequence related tests to new APIs (while maintaining deprecated path testing as well for now)
- AnimDataController / Animation Sequence tests now generate a USkeleton for the transient animation sequence (used to perform the test on)

**Removed**
- Unused file/class AnimData/AnimDataNotifyCollector.h

#rb Thomas.Sarkanen, Martin.Wilson, Alexis.Matte, Mike.Zyracki
#jira UE-131296
#preflight 62a308a8b0150a87f9d6891b

[CL 20677979 by Marc Audy in ue5-main branch]
2022-06-15 18:24:46 -04:00

296 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimationAttributeBlueprintLibrary.h"
#include "Animation/AnimData/AnimDataModel.h"
#define LOCTEXT_NAMESPACE "AnimationAttributeBlueprintLibrary"
bool UAnimationAttributeBlueprintLibrary::SetAttributeKey(TScriptInterface<IAnimationDataController> AnimationDataController, const FAnimationAttributeIdentifier& AttributeIdentifier, float Time, const int32& Value)
{
// We should never hit this! Stubbed to avoid NoExport on the class.
check(0);
return false;
}
bool UAnimationAttributeBlueprintLibrary::Generic_SetAttributeKey(TScriptInterface<IAnimationDataController> AnimationDataController, const FAnimationAttributeIdentifier& AttributeIdentifier, float Time, UScriptStruct* ScriptStruct, const void* ValuePtr)
{
return AnimationDataController->SetAttributeKey(AttributeIdentifier, Time, ValuePtr, ScriptStruct);
}
DEFINE_FUNCTION(UAnimationAttributeBlueprintLibrary::execSetAttributeKey)
{
P_GET_TINTERFACE(IAnimationDataController, AnimationDataController);
P_GET_STRUCT_REF(FAnimationAttributeIdentifier, AttributeIdentifier);
P_GET_PROPERTY(FFloatProperty, TimeInterval);
Stack.MostRecentProperty = nullptr;
Stack.MostRecentPropertyAddress = nullptr;
Stack.StepCompiledIn<FStructProperty>(nullptr);
const FStructProperty* ItemProperty = CastField<FStructProperty>(Stack.MostRecentProperty);
void* ItemDataPtr = Stack.MostRecentPropertyAddress;
P_FINISH;
if (!ItemProperty || !ItemDataPtr)
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("SetAttributeKey_InvalidValue", "Failed to resolve the attribute value parameter for SetAttributeKey.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
if (!AnimationDataController.GetObject())
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("SetAttributeKey_InvalidController", "Accessed None attempting to call SetAttributeKey.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
bool bResult = false;
if (AnimationDataController && ItemProperty)
{
P_NATIVE_BEGIN;
bResult = Generic_SetAttributeKey(AnimationDataController, AttributeIdentifier, TimeInterval, ItemProperty->Struct, ItemDataPtr);
P_NATIVE_END;
}
*(bool*)RESULT_PARAM = bResult;
}
bool UAnimationAttributeBlueprintLibrary::SetAttributeKeys(TScriptInterface<IAnimationDataController> AnimationDataController, const FAnimationAttributeIdentifier& AttributeIdentifier, const TArray<float>& Times, const TArray<int32>& Values)
{
// We should never hit this! Stubbed to avoid NoExport on the class.
check(0);
return false;
}
bool UAnimationAttributeBlueprintLibrary::Generic_SetAttributeKeys(TScriptInterface<IAnimationDataController> AnimationDataController, const FAnimationAttributeIdentifier& AttributeIdentifier, const TArray<float>& Times, const void* ValuesArray, const FArrayProperty* ValuesArrayProperty)
{
FScriptArrayHelper ArrayHelper(ValuesArrayProperty, ValuesArray);
TArray<const void*> ItemPtrs;
const int32 NumberOfItems = ArrayHelper.Num();
ItemPtrs.SetNumZeroed(NumberOfItems);
for (int32 Index = 0; Index < NumberOfItems; ++Index)
{
ItemPtrs[Index] = ArrayHelper.GetRawPtr(Index);
}
const FStructProperty* InnerStructProperty = CastField<const FStructProperty>(ValuesArrayProperty->Inner);
return AnimationDataController->SetAttributeKeys(AttributeIdentifier, MakeArrayView(Times), MakeArrayView(ItemPtrs), InnerStructProperty->Struct);
}
DEFINE_FUNCTION(UAnimationAttributeBlueprintLibrary::execSetAttributeKeys)
{
P_GET_TINTERFACE(IAnimationDataController, AnimationDataController);
P_GET_STRUCT_REF(FAnimationAttributeIdentifier, AttributeIdentifier);
P_GET_TARRAY_REF(float, TimeIntervals);
Stack.MostRecentProperty = nullptr;
Stack.MostRecentPropertyAddress = nullptr;
Stack.StepCompiledIn<FArrayProperty>(nullptr);
void* ArrayAddr = Stack.MostRecentPropertyAddress;
FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Stack.MostRecentProperty);
P_FINISH;
if (!ArrayAddr || !ArrayProperty)
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("SetAttributeKeys_InvalidValue", "Failed to resolve the attribute values parameter for SetAttributeKeys.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
if (!AnimationDataController.GetObject())
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("SetAttributeKeys_InvalidController", "Accessed None attempting to call SetAttributeKeys.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
bool bResult = false;
if (AnimationDataController)
{
P_NATIVE_BEGIN;
bResult = Generic_SetAttributeKeys(AnimationDataController, AttributeIdentifier, TimeIntervals, ArrayAddr, ArrayProperty);
P_NATIVE_END;
}
*(bool*)RESULT_PARAM = bResult;
}
bool UAnimationAttributeBlueprintLibrary::GetAttributeKey(UAnimDataModel* AnimationDataModel, const FAnimationAttributeIdentifier& AttributeIdentifier, float Time, int32& Value)
{
// We should never hit this! Stubbed to avoid NoExport on the class.
check(0);
return false;
}
bool UAnimationAttributeBlueprintLibrary::Generic_GetAttributeKey(UAnimDataModel* AnimationDataModel, const FAnimationAttributeIdentifier& AttributeIdentifier, float Time, UScriptStruct* ScriptStruct, void* ValuePtr)
{
const FAnimatedBoneAttribute* AttributePtr = AnimationDataModel->FindAttribute(AttributeIdentifier);
// Find attribute
if (AttributePtr && ScriptStruct)
{
// And the key on its attribute curve
const FAttributeCurve& Curve = AttributePtr->Curve;
check(ScriptStruct == Curve.GetScriptStruct());
const FKeyHandle KeyHandle = Curve.FindKey(Time);
if (KeyHandle != FKeyHandle::Invalid())
{
// Copy out the value to ptr
const FAttributeKey& Key = Curve.GetKey(KeyHandle);
ScriptStruct->CopyScriptStruct(ValuePtr, Key.GetValuePtr<void>(), 1);
return true;
}
}
return false;
}
DEFINE_FUNCTION(UAnimationAttributeBlueprintLibrary::execGetAttributeKey)
{
P_GET_OBJECT(UAnimDataModel, AnimationDataModel);
P_GET_STRUCT_REF(FAnimationAttributeIdentifier, AttributeIdentifier);
P_GET_PROPERTY(FFloatProperty, TimeInterval);
Stack.MostRecentProperty = nullptr;
Stack.MostRecentPropertyAddress = nullptr;
Stack.StepCompiledIn<FStructProperty>(nullptr);
const FStructProperty* ItemProperty = CastField<FStructProperty>(Stack.MostRecentProperty);
void* ItemDataPtr = Stack.MostRecentPropertyAddress;
P_FINISH;
if (!ItemProperty || !ItemDataPtr)
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("GetAttributeKey_InvalidValue", "Failed to resolve the attribute value parameter for GetAttributeKey.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
if (!AnimationDataModel)
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("GetAttributeKey_InvalidController", "Accessed None attempting to call GetAttributeKey.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
bool bResult = false;
if (AnimationDataModel && ItemProperty)
{
P_NATIVE_BEGIN;
bResult = Generic_GetAttributeKey(AnimationDataModel, AttributeIdentifier, TimeInterval, ItemProperty->Struct, ItemDataPtr);
P_NATIVE_END;
}
*(bool*)RESULT_PARAM = bResult;
}
bool UAnimationAttributeBlueprintLibrary::GetAttributeKeys(UAnimDataModel* AnimationDataModel, const FAnimationAttributeIdentifier& AttributeIdentifier, TArray<float>& OutTimes, TArray<int32>& OutValues)
{
// We should never hit this! Stubbed to avoid NoExport on the class.
check(0);
return false;
}
bool UAnimationAttributeBlueprintLibrary::Generic_GetAttributeKeys(UAnimDataModel* AnimationDataModel, const FAnimationAttributeIdentifier& AttributeIdentifier, TArray<float>& Times, void* ValuesArray, const FArrayProperty* ValuesArrayProperty)
{
const FAnimatedBoneAttribute* AttributePtr = AnimationDataModel->FindAttribute(AttributeIdentifier);
// Find attribute
if (AttributePtr && ValuesArrayProperty)
{
const FStructProperty* InnerStructProperty = CastField<const FStructProperty>(ValuesArrayProperty->Inner);
// And the key on its attribute curve
const FAttributeCurve& Curve = AttributePtr->Curve;
check(InnerStructProperty->Struct == Curve.GetScriptStruct());
const TArray<FAttributeKey>& Keys = Curve.GetConstRefOfKeys();
FScriptArrayHelper ArrayHelper(ValuesArrayProperty, ValuesArray);
ArrayHelper.Resize(Keys.Num());
Times.SetNum(Keys.Num());
for (int32 KeyIndex = 0; KeyIndex < Keys.Num(); ++KeyIndex)
{
const FAttributeKey& Key = Keys[KeyIndex];
Times[KeyIndex] = Key.Time;
uint8* ValuePtr = ArrayHelper.GetRawPtr(KeyIndex);
InnerStructProperty->Struct->CopyScriptStruct(ValuePtr, Key.GetValuePtr<void>(), 1);
}
}
return false;
}
DEFINE_FUNCTION(UAnimationAttributeBlueprintLibrary::execGetAttributeKeys)
{
P_GET_OBJECT(UAnimDataModel, AnimationDataModel);
P_GET_STRUCT_REF(FAnimationAttributeIdentifier, AttributeIdentifier);
P_GET_TARRAY_REF(float, TimeIntervals);
Stack.MostRecentProperty = nullptr;
Stack.MostRecentPropertyAddress = nullptr;
Stack.StepCompiledIn<FArrayProperty>(nullptr);
void* ArrayAddr = Stack.MostRecentPropertyAddress;
FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Stack.MostRecentProperty);
P_FINISH;
if (!ArrayAddr || !ArrayProperty)
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("GetAttributeKeys_InvalidValue", "Failed to resolve the attribute values parameter for GetAttributeKeys.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
if (!AnimationDataModel)
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AccessViolation,
LOCTEXT("GetAttributeKeys_InvalidController", "Accessed None attempting to call GetAttributeKeys.")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
bool bResult = false;
if (AnimationDataModel)
{
P_NATIVE_BEGIN;
bResult = Generic_GetAttributeKeys(AnimationDataModel, AttributeIdentifier, TimeIntervals, ArrayAddr, ArrayProperty);
P_NATIVE_END;
}
*(bool*)RESULT_PARAM = bResult;
}
#undef LOCTEXT_NAMESPACE