// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. #include "AnimNodes/AnimNode_CurveSource.h" #include "AnimationRuntime.h" #include "Animation/AnimInstanceProxy.h" FAnimNode_CurveSource::FAnimNode_CurveSource() : SourceBinding(ICurveSourceInterface::DefaultBinding) , Alpha(1.0f) { } void FAnimNode_CurveSource::PreUpdate(const UAnimInstance* AnimInstance) { // re-bind to our named curve source in pre-update // we do this here to allow re-binding of the source without reinitializing the whole // anim graph. If the source goes away (e.g. if an audio component is destroyed) or the // binding changes then we can re-bind to a new object if (CurveSource.GetObject() == nullptr || Cast(CurveSource.GetObject())->Execute_GetBindingName(CurveSource.GetObject()) != SourceBinding) { ICurveSourceInterface* PotentialCurveSource = nullptr; AActor* Actor = AnimInstance->GetOwningActor(); if (Actor) { // check if our actor implements our interface PotentialCurveSource = Cast(Actor); if (PotentialCurveSource && PotentialCurveSource->Execute_GetBindingName(Actor) == SourceBinding) { CurveSource.SetObject(Actor); CurveSource.SetInterface(PotentialCurveSource); } else { for (TFieldIterator PropertyIt(Actor->GetClass(), EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt) { UObjectProperty* ObjProp = *PropertyIt; UActorComponent* ActorComponent = Cast(ObjProp->GetObjectPropertyValue(ObjProp->ContainerPtrToValuePtr(Actor))); PotentialCurveSource = Cast(ActorComponent); if (PotentialCurveSource && PotentialCurveSource->Execute_GetBindingName(ActorComponent) == SourceBinding) { CurveSource.SetObject(ActorComponent); CurveSource.SetInterface(PotentialCurveSource); } } } } } } class FExternalCurveScratchArea : public TThreadSingleton { public: TArray NamedCurveValues; }; void FAnimNode_CurveSource::Evaluate(FPoseContext& Output) { SourcePose.Evaluate(Output); if (CurveSource.GetInterface() != nullptr) { TArray& NamedCurveValues = FExternalCurveScratchArea::Get().NamedCurveValues; NamedCurveValues.Reset(); CurveSource->Execute_GetCurves(CurveSource.GetObject(), NamedCurveValues); USkeleton* Skeleton = Output.AnimInstanceProxy->GetSkeleton(); for (FNamedCurveValue NamedValue : NamedCurveValues) { SmartName::UID_Type NameUID = Skeleton->GetUIDByName(USkeleton::AnimCurveMappingName, NamedValue.Name); if (NameUID != SmartName::MaxUID) { const float CurrentValue = Output.Curve.Get(NameUID); const float ClampedAlpha = FMath::Clamp(Alpha, 0.0f, 1.0f); Output.Curve.Set(NameUID, FMath::Lerp(CurrentValue, NamedValue.Value, ClampedAlpha)); } } } } void FAnimNode_CurveSource::Update(const FAnimationUpdateContext& Context) { // Evaluate any BP logic plugged into this node EvaluateGraphExposedInputs.Execute(Context); }