void FAnimationRuntime::BlendPosesTogetherPerBone(const TArray<FCompactPose>& SourcePoses, const TArray<FBlendedCurve>& SourceCurves, const UBlendSpaceBase* BlendSpace, const TArray<FBlendSampleData>& BlendSampleDataCache, /*out*/ FCompactPose& ResultPose, /*out*/ FBlendedCurve& ResultCurve)
{
	check(SourcePoses.Num() > 0);

	const TArray<FBoneIndexType> & RequiredBoneIndices = ResultPose.GetBoneContainer().GetBoneIndicesArray();

	TArray<int32> PerBoneIndices;
	PerBoneIndices.AddUninitialized(ResultPose.GetNumBones());
	for (int32 BoneIndex = 0; BoneIndex < PerBoneIndices.Num(); ++BoneIndex)
	{
		PerBoneIndices[BoneIndex] = BlendSpace->GetPerBoneInterpolationIndex(RequiredBoneIndices[BoneIndex], ResultPose.GetBoneContainer());
	}

	BlendPosePerBone<ETransformBlendMode::Overwrite>(PerBoneIndices, BlendSampleDataCache[0], ResultPose, SourcePoses[0]);

	for (int32 i = 1; i < SourcePoses.Num(); ++i)
	{
		BlendPosePerBone<ETransformBlendMode::Accumulate>(PerBoneIndices, BlendSampleDataCache[i], ResultPose, SourcePoses[i]);
	}

	// Ensure that all of the resulting rotations are normalized
	ResultPose.NormalizeRotations();

	if (SourceCurves.Num() > 0)
	{
		TArray<float> SourceWeights;
		SourceWeights.AddUninitialized(BlendSampleDataCache.Num());
		for (int32 CacheIndex=0; CacheIndex<BlendSampleDataCache.Num(); ++CacheIndex)
		{
			SourceWeights[CacheIndex] = BlendSampleDataCache[CacheIndex].TotalWeight;
		}

		BlendCurves(SourceCurves, SourceWeights, ResultCurve);
	}
}
void FAnimationRuntime::AccumulateLocalSpaceAdditivePose(FCompactPose& BasePose, const FCompactPose& AdditivePose, FBlendedCurve& BaseCurve, const FBlendedCurve& AdditiveCurve, float Weight)
{
	if (Weight > ZERO_ANIMWEIGHT_THRESH)
	{
		if (Weight >= (1.f - ZERO_ANIMWEIGHT_THRESH))
		{
			// fast path, no need to weight additive.
			for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex())
			{
				BasePose[BoneIndex].Accumulate(AdditivePose[BoneIndex]);
			}
		}
		else
		{
			// Slower path w/ weighting
			const ScalarRegister VBlendWeight(Weight);
			for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex())
			{
				// copy additive, because BlendFromIdentityAndAccumulate modifies it.
				FTransform Additive = AdditivePose[BoneIndex];
				FTransform::BlendFromIdentityAndAccumulate(BasePose[BoneIndex], Additive, VBlendWeight);
			}
		}
	}
}
void FAnimationRuntime::FillWithRetargetBaseRefPose(FCompactPose& OutPose, const USkeletalMesh* Mesh)
{
	// Copy Target Asset's ref pose.
	if (Mesh)
	{
		for (FCompactPoseBoneIndex BoneIndex : OutPose.ForEachBoneIndex())
		{
			FMeshPoseBoneIndex PoseIndex = OutPose.GetBoneContainer().MakeMeshPoseIndex(BoneIndex);
			OutPose[BoneIndex] = Mesh->RetargetBasePose[PoseIndex.GetInt()];
		}
	}
}
void FAnimationRuntime::ConvertMeshRotationPoseToLocalSpace(FCompactPose& Pose)
{
	// Convert all rotations to mesh space
	// only the root bone doesn't have a parent. So skip it to save a branch in the iteration.
	for (FCompactPoseBoneIndex BoneIndex(Pose.GetNumBones()-1); BoneIndex > 0; --BoneIndex)
	{
		const FCompactPoseBoneIndex ParentIndex = Pose.GetParentBoneIndex(BoneIndex);

		FQuat LocalSpaceRotation = Pose[ParentIndex].GetRotation().Inverse() * Pose[BoneIndex].GetRotation();
		Pose[BoneIndex].SetRotation(LocalSpaceRotation);
	}
}
void FAnimationRuntime::ConvertPoseToMeshRotation(FCompactPose& LocalPose)
{
	// Convert all rotations to mesh space
	// only the root bone doesn't have a parent. So skip it to save a branch in the iteration.
	for (FCompactPoseBoneIndex BoneIndex(1); BoneIndex < LocalPose.GetNumBones(); ++BoneIndex)
	{
		const FCompactPoseBoneIndex ParentIndex = LocalPose.GetParentBoneIndex(BoneIndex);

		const FQuat MeshSpaceRotation = LocalPose[ParentIndex].GetRotation() * LocalPose[BoneIndex].GetRotation();
		LocalPose[BoneIndex].SetRotation(MeshSpaceRotation);
	}
}
void FAnimationRuntime::BlendPosesTogether(
	const TArray<const FCompactPose*>& SourcePoses,
	const TArray<const FBlendedCurve*>& SourceCurves,
	const TArray<float>&	SourceWeights,
	/*out*/ FCompactPose& ResultPose, 
	/*out*/ FBlendedCurve& ResultCurve)
{
	check(SourcePoses.Num() > 0);

	BlendPose<ETransformBlendMode::Overwrite>(*SourcePoses[0], ResultPose, SourceWeights[0]);

	for (int32 PoseIndex = 1; PoseIndex < SourcePoses.Num(); ++PoseIndex)
	{
		BlendPose<ETransformBlendMode::Accumulate>(*SourcePoses[PoseIndex], ResultPose, SourceWeights[PoseIndex]);
	}

	// Ensure that all of the resulting rotations are normalized
	if (SourcePoses.Num() > 1)
	{
		ResultPose.NormalizeRotations();
	}

	if(SourceCurves.Num() > 0)
	{
		BlendCurves(SourceCurves, SourceWeights, ResultCurve);
	}
}
FORCEINLINE void BlendPose(const FCompactPose& SourcePose, FCompactPose& ResultPose, const float BlendWeight)
{
	for (FCompactPoseBoneIndex BoneIndex : SourcePose.ForEachBoneIndex())
	{
		BlendTransform<TRANSFORM_BLEND_MODE>(SourcePose[BoneIndex], ResultPose[BoneIndex], BlendWeight);
	}
}
void FAnimationRuntime::BlendPosesTogetherPerBoneInMeshSpace(TArray<FCompactPose>& SourcePoses, const TArray<FBlendedCurve>& SourceCurves, const UBlendSpaceBase* BlendSpace, const TArray<FBlendSampleData>& BlendSampleDataCache, FCompactPose& ResultPose, FBlendedCurve& ResultCurve)
{
	FQuat NewRotation;
	USkeleton* Skeleton = BlendSpace->GetSkeleton();

	// all this is going to do is to convert SourcePoses.Rotation to be mesh space, and then once it goes through BlendPosesTogetherPerBone, convert back to local
	for (FCompactPose& Pose : SourcePoses)
	{
		for (const FCompactPoseBoneIndex BoneIndex : Pose.ForEachBoneIndex())
		{
			const FCompactPoseBoneIndex ParentIndex = Pose.GetParentBoneIndex(BoneIndex);
			if (ParentIndex != INDEX_NONE)
			{
				NewRotation = Pose[ParentIndex].GetRotation()*Pose[BoneIndex].GetRotation();
				NewRotation.Normalize();
			}
			else
			{
				NewRotation = Pose[BoneIndex].GetRotation();
			}

			// now copy back to SourcePoses
			Pose[BoneIndex].SetRotation(NewRotation);
		}
	}

	// now we have mesh space rotation, call BlendPosesTogetherPerBone
	BlendPosesTogetherPerBone(SourcePoses, SourceCurves, BlendSpace, BlendSampleDataCache, ResultPose, ResultCurve);

	// now result atoms has the output with mesh space rotation. Convert back to local space, start from back
	for (const FCompactPoseBoneIndex BoneIndex : ResultPose.ForEachBoneIndex())
	{
		const FCompactPoseBoneIndex ParentIndex = ResultPose.GetParentBoneIndex(BoneIndex);
		if (ParentIndex != INDEX_NONE)
		{
			FQuat LocalBlendQuat = ResultPose[ParentIndex].GetRotation().Inverse()*ResultPose[BoneIndex].GetRotation();
			ResultPose[BoneIndex].SetRotation(LocalBlendQuat);
			ResultPose[BoneIndex].NormalizeRotation();
		}
	}
}
void FAnimationRuntime::ConvertPoseToAdditive(FCompactPose& TargetPose, const FCompactPose& BasePose)
{
	for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex())
	{
		FTransform& TargetTransform = TargetPose[BoneIndex];
		const FTransform& BaseTransform = BasePose[BoneIndex];

		TargetTransform.SetRotation(TargetTransform.GetRotation() * BaseTransform.GetRotation().Inverse());
		TargetTransform.SetTranslation(TargetTransform.GetTranslation() - BaseTransform.GetTranslation());
		TargetTransform.SetScale3D(TargetTransform.GetScale3D() * BaseTransform.GetSafeScaleReciprocal(BaseTransform.GetScale3D()));
		TargetTransform.NormalizeRotation();
	}
}
void UAnimSingleNodeInstance::InternalBlendSpaceEvaluatePose(class UBlendSpaceBase* BlendSpace, TArray<FBlendSampleData>& BlendSampleDataCache, FPoseContext& OutContext)
{
	USkeletalMeshComponent* Component = GetSkelMeshComponent();

	if (BlendSpace->IsValidAdditive())
	{
		FCompactPose& OutPose = OutContext.Pose;
		FBlendedCurve& OutCurve = OutContext.Curve;
		FCompactPose AdditivePose;
		FBlendedCurve AdditiveCurve;
		AdditivePose.SetBoneContainer(&OutPose.GetBoneContainer());
		AdditiveCurve.InitFrom(OutCurve);

#if WITH_EDITORONLY_DATA
		if (BlendSpace->PreviewBasePose)
		{
			BlendSpace->PreviewBasePose->GetBonePose(/*out*/ OutPose, /*out*/OutCurve, FAnimExtractContext(PreviewPoseCurrentTime));
		}
		else
#endif // WITH_EDITORONLY_DATA
		{
			// otherwise, get ref pose
			OutPose.ResetToRefPose();
		}

		BlendSpace->GetAnimationPose(BlendSampleDataCache, AdditivePose, AdditiveCurve);

		enum EAdditiveAnimationType AdditiveType = BlendSpace->bRotationBlendInMeshSpace? AAT_RotationOffsetMeshSpace : AAT_LocalSpaceBase;

		FAnimationRuntime::AccumulateAdditivePose(OutPose, AdditivePose, OutCurve, AdditiveCurve, 1.f, AdditiveType);
	}
	else
	{
		BlendSpace->GetAnimationPose(BlendSampleDataCache, OutContext.Pose, OutContext.Curve);
	}
}
void FAnimationRuntime::AccumulateAdditivePose(FCompactPose& BasePose, const FCompactPose& AdditivePose, FBlendedCurve& BaseCurve, const FBlendedCurve& AdditiveCurve, float Weight, enum EAdditiveAnimationType AdditiveType)
{
	if (AdditiveType == AAT_RotationOffsetMeshSpace)
	{
		AccumulateMeshSpaceRotationAdditiveToLocalPose(BasePose, AdditivePose, BaseCurve, AdditiveCurve, Weight);
	}
	else
	{
		AccumulateLocalSpaceAdditivePose(BasePose, AdditivePose, BaseCurve, AdditiveCurve, Weight);
	}

	// if curve exists, accumulate with the weight, 
	BaseCurve.Accumulate(AdditiveCurve, Weight);
	// normalize
	BasePose.NormalizeRotations();
}
void FAnimationRuntime::BlendTwoPosesTogether(
	const FCompactPose& SourcePose1,
	const FCompactPose& SourcePose2,
	const FBlendedCurve& SourceCurve1,
	const FBlendedCurve& SourceCurve2,
	const float			WeightOfPose1,
	/*out*/ FCompactPose& ResultPose,
	/*out*/ FBlendedCurve& ResultCurve)
{
	BlendPose<ETransformBlendMode::Overwrite>(SourcePose1, ResultPose, WeightOfPose1);
	BlendPose<ETransformBlendMode::Accumulate>(SourcePose2, ResultPose, 1.f - WeightOfPose1);

	// Ensure that all of the resulting rotations are normalized
	ResultPose.NormalizeRotations();
	ResultCurve.Blend(SourceCurve1, SourceCurve2, 1.f - WeightOfPose1);
}
void BlendPosePerBone(const TArray<int32>& PerBoneIndices, const FBlendSampleData& BlendSampleDataCache, FCompactPose& ResultPose, const FCompactPose& SourcePose)
{
	const float BlendWeight = BlendSampleDataCache.GetWeight();
	TArray<float> PerBoneBlends;
	for (int32 i = 0; i < BlendSampleDataCache.PerBoneBlendData.Num(); ++i)
	{
		PerBoneBlends.Add(FMath::Clamp<float>(BlendSampleDataCache.PerBoneBlendData[i], 0.f, 1.f));
	}

	for (FCompactPoseBoneIndex BoneIndex : SourcePose.ForEachBoneIndex())
	{
		int32 PerBoneIndex = PerBoneIndices[BoneIndex.GetInt()];

		if (PerBoneIndex == INDEX_NONE || !BlendSampleDataCache.PerBoneBlendData.IsValidIndex(PerBoneIndex))
		{
			BlendTransform<TRANSFORM_BLEND_MODE>(SourcePose[BoneIndex], ResultPose[BoneIndex], BlendWeight);
		}
		else
		{
			BlendTransform<TRANSFORM_BLEND_MODE>(SourcePose[BoneIndex], ResultPose[BoneIndex], PerBoneBlends[PerBoneIndex]);
		}
	}
}
void FAnimationRuntime::BlendLocalPosesPerBoneWeights(
	FCompactPose& BasePose,
	const TArray<FCompactPose>& BlendPoses,
	struct FBlendedCurve& BaseCurve,
	const TArray<struct FBlendedCurve>& BlendedCurves,
	const TArray<FPerBoneBlendWeight> & BoneBlendWeights,
	ECurveBlendOption::Type CurveBlendOption,
	/*out*/ FCompactPose& OutPose, 
	/*out*/ struct FBlendedCurve& OutCurve)
{
	check(BasePose.GetNumBones() == BoneBlendWeights.Num());
	int32 PoseNum = BlendPoses.Num();

	TArray<float> MaxPoseWeights;
	MaxPoseWeights.AddZeroed(PoseNum);

	for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex())
	{
		const int32 PoseIndex = BoneBlendWeights[BoneIndex.GetInt()].SourceIndex;
		const FTransform& BaseAtom = BasePose[BoneIndex];

		const float BlendWeight = FMath::Clamp(BoneBlendWeights[BoneIndex.GetInt()].BlendWeight, 0.f, 1.f);
		MaxPoseWeights[PoseIndex] = FMath::Max(MaxPoseWeights[PoseIndex], BlendWeight);

		if (BlendWeight < ZERO_ANIMWEIGHT_THRESH)
		{
			OutPose[BoneIndex] = BaseAtom;
		}
		else if ((1.0 - BlendWeight) < ZERO_ANIMWEIGHT_THRESH)
		{
			OutPose[BoneIndex] = BlendPoses[PoseIndex][BoneIndex];
		}
		else // we want blend here
		{
			FTransform BlendAtom = BaseAtom;
			const FTransform& TargetAtom = BlendPoses[PoseIndex][BoneIndex];
			BlendAtom.BlendWith(TargetAtom, BlendWeight);
			OutPose[BoneIndex] = BlendAtom;
		}
	}

	// time to blend curves
	// the way we blend curve per bone
	// is to find out max weight per that pose, and then apply that weight to the curve
	{
		TArray<const FBlendedCurve*> SourceCurves;
		TArray<float> SourceWegihts;

		SourceCurves.SetNumUninitialized(PoseNum+1);
		SourceWegihts.SetNumUninitialized(PoseNum+1);

		SourceCurves[0] = &BaseCurve;
		SourceWegihts[0] = 1.f;

		for (int32 Idx=0; Idx<PoseNum; ++Idx)
		{
			SourceCurves[Idx+1] = &BlendedCurves[Idx];
			SourceWegihts[Idx+1] = MaxPoseWeights[Idx];
		}
		
		BlendCurves(SourceCurves, SourceWegihts, OutCurve, CurveBlendOption);
	}
}
void UBlendSpaceBase::GetAnimationPose(TArray<FBlendSampleData>& BlendSampleDataCache, /*out*/ FCompactPose& OutPose, /*out*/ FBlendedCurve& OutCurve)
{
	SCOPE_CYCLE_COUNTER(STAT_BlendSpace_GetAnimPose);
	FScopeCycleCounterUObject BlendSpaceScope(this);

	if(BlendSampleDataCache.Num() == 0)
	{
		OutPose.ResetToRefPose();
		return;
	}

	const int32 NumPoses = BlendSampleDataCache.Num();

	TArray<FCompactPose, TInlineAllocator<8>> ChildrenPoses;
	ChildrenPoses.AddZeroed(NumPoses);

	TArray<FBlendedCurve, TInlineAllocator<8>> ChildrenCurves;
	ChildrenCurves.AddZeroed(NumPoses);

	TArray<float, TInlineAllocator<8>> ChildrenWeights;
	ChildrenWeights.AddZeroed(NumPoses);

	for(int32 ChildrenIdx=0; ChildrenIdx<ChildrenPoses.Num(); ++ChildrenIdx)
	{
		ChildrenPoses[ChildrenIdx].SetBoneContainer(&OutPose.GetBoneContainer());
		ChildrenCurves[ChildrenIdx].InitFrom(OutCurve);
	}

	// get all child atoms we interested in
	for(int32 I = 0; I < BlendSampleDataCache.Num(); ++I)
	{
		FCompactPose& Pose = ChildrenPoses[I];

		if(SampleData.IsValidIndex(BlendSampleDataCache[I].SampleDataIndex))
		{
			const FBlendSample& Sample = SampleData[BlendSampleDataCache[I].SampleDataIndex];
			ChildrenWeights[I] = BlendSampleDataCache[I].GetWeight();

			if(Sample.Animation)
			{
				const float Time = FMath::Clamp<float>(BlendSampleDataCache[I].Time, 0.f, Sample.Animation->SequenceLength);

				// first one always fills up the source one
				Sample.Animation->GetAnimationPose(Pose, ChildrenCurves[I], FAnimExtractContext(Time, true));
			}
			else
			{
				Pose.ResetToRefPose();
			}
		}
		else
		{
			Pose.ResetToRefPose();
		}
	}

	TArrayView<FCompactPose> ChildrenPosesView(ChildrenPoses);

	if (PerBoneBlend.Num() > 0)
	{
		if (IsValidAdditive())
		{
			if (bRotationBlendInMeshSpace)
			{
				FAnimationRuntime::BlendPosesTogetherPerBoneInMeshSpace(ChildrenPosesView, ChildrenCurves, this, BlendSampleDataCache, OutPose, OutCurve);
			}
			else
			{
				FAnimationRuntime::BlendPosesTogetherPerBone(ChildrenPosesView, ChildrenCurves, this, BlendSampleDataCache, OutPose, OutCurve);
			}
		}
		else
		{
			FAnimationRuntime::BlendPosesTogetherPerBone(ChildrenPosesView, ChildrenCurves, this, BlendSampleDataCache, OutPose, OutCurve);
		}
	}
	else
	{
		FAnimationRuntime::BlendPosesTogether(ChildrenPosesView, ChildrenCurves, ChildrenWeights, OutPose, OutCurve);
	}

	// Once all the accumulation and blending has been done, normalize rotations.
	OutPose.NormalizeRotations();
}
void UDebugSkelMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* TickFunction)
{
	// Run regular update first so we get RequiredBones up to date.
	Super::RefreshBoneTransforms(NULL); // Pass NULL so we force non threaded work

	const bool bIsPreviewInstance = (PreviewInstance && PreviewInstance == AnimScriptInstance);

	BakedAnimationPoses.Empty();
	if(bDisplayBakedAnimation && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid())
	{
		if(UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset))
		{
			BakedAnimationPoses.AddUninitialized(PreviewInstance->RequiredBones.GetNumBones());
			bool bSavedUseSourceData = AnimScriptInstance->RequiredBones.ShouldUseSourceData();
			AnimScriptInstance->RequiredBones.SetUseRAWData(true);
			AnimScriptInstance->RequiredBones.SetUseSourceData(false);
			PreviewInstance->EnableControllers(false);
			GenSpaceBases(BakedAnimationPoses);
			AnimScriptInstance->RequiredBones.SetUseRAWData(false);
			AnimScriptInstance->RequiredBones.SetUseSourceData(bSavedUseSourceData);
			PreviewInstance->EnableControllers(true);
		}
	}

	SourceAnimationPoses.Empty();
	if(bDisplaySourceAnimation && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid())
	{
		if(UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset))
		{
			SourceAnimationPoses.AddUninitialized(PreviewInstance->RequiredBones.GetNumBones());
			bool bSavedUseSourceData = AnimScriptInstance->RequiredBones.ShouldUseSourceData();
			AnimScriptInstance->RequiredBones.SetUseSourceData(true);
			PreviewInstance->EnableControllers(false);
			GenSpaceBases(SourceAnimationPoses);
			AnimScriptInstance->RequiredBones.SetUseSourceData(bSavedUseSourceData);
			PreviewInstance->EnableControllers(true);
		}
	}

	UncompressedSpaceBases.Empty();
	if (bDisplayRawAnimation && AnimScriptInstance && AnimScriptInstance->RequiredBones.IsValid())
	{
		UncompressedSpaceBases.AddUninitialized(AnimScriptInstance->RequiredBones.GetNumBones());

		AnimScriptInstance->RequiredBones.SetUseRAWData(true);
		GenSpaceBases(UncompressedSpaceBases);
		AnimScriptInstance->RequiredBones.SetUseRAWData(false);
	}

	// Non retargeted pose.
	NonRetargetedSpaceBases.Empty();
	if( bDisplayNonRetargetedPose && AnimScriptInstance && AnimScriptInstance->RequiredBones.IsValid() )
	{
		NonRetargetedSpaceBases.AddUninitialized(AnimScriptInstance->RequiredBones.GetNumBones());
		AnimScriptInstance->RequiredBones.SetDisableRetargeting(true);
		GenSpaceBases(NonRetargetedSpaceBases);
		AnimScriptInstance->RequiredBones.SetDisableRetargeting(false);
	}

	// Only works in PreviewInstance, and not for anim blueprint. This is intended.
	AdditiveBasePoses.Empty();
	if( bDisplayAdditiveBasePose && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid() )
	{
		if (UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset)) 
		{ 
			if (Sequence->IsValidAdditive()) 
			{ 
				FCSPose<FCompactPose> CSAdditiveBasePose;
				{
					FCompactPose AdditiveBasePose;
					FBlendedCurve AdditiveCurve(PreviewInstance);
					AdditiveBasePose.SetBoneContainer(&PreviewInstance->RequiredBones);
					Sequence->GetAdditiveBasePose(AdditiveBasePose, AdditiveCurve, FAnimExtractContext(PreviewInstance->CurrentTime));
					CSAdditiveBasePose.InitPose(AdditiveBasePose);
				}

				for (int32 i = 0; i < AdditiveBasePoses.Num(); ++i)
				{
					FCompactPoseBoneIndex CompactIndex = PreviewInstance->RequiredBones.MakeCompactPoseIndex(FMeshPoseBoneIndex(i));
					AdditiveBasePoses[i] = CSAdditiveBasePose.GetComponentSpaceTransform(CompactIndex);
				}
			}
		}
	}
}
bool UAnimSingleNodeInstance::NativeEvaluateAnimation(FPoseContext& Output)
{
	if (CurrentAsset != NULL)
	{
		//@TODO: animrefactor: Seems like more code duplication than we need
		if (UBlendSpaceBase* BlendSpace = Cast<UBlendSpaceBase>(CurrentAsset))
		{
			InternalBlendSpaceEvaluatePose(BlendSpace, BlendSampleData, Output);
		}
		else if (UAnimSequence* Sequence = Cast<UAnimSequence>(CurrentAsset))
		{
			if (Sequence->IsValidAdditive())
			{
				FAnimExtractContext ExtractionContext(CurrentTime, Sequence->bEnableRootMotion);

				Sequence->GetAdditiveBasePose(Output.Pose, Output.Curve, ExtractionContext);

				FCompactPose AdditivePose;
				FBlendedCurve AdditiveCurve;
				AdditivePose.SetBoneContainer(&Output.Pose.GetBoneContainer());
				AdditiveCurve.InitFrom(Output.Curve);
				Sequence->GetAnimationPose(AdditivePose, AdditiveCurve, ExtractionContext);

				FAnimationRuntime::AccumulateAdditivePose(Output.Pose, AdditivePose, Output.Curve, AdditiveCurve, 1.f, Sequence->AdditiveAnimType);
				Output.Pose.NormalizeRotations();
			}
			else
			{
				// if SkeletalMesh isn't there, we'll need to use skeleton
				Sequence->GetAnimationPose(Output.Pose, Output.Curve, FAnimExtractContext(CurrentTime, Sequence->bEnableRootMotion));
			}
		}
		else if (UAnimComposite* Composite = Cast<UAnimComposite>(CurrentAsset))
		{
			FAnimExtractContext ExtractionContext(CurrentTime, ShouldExtractRootMotion());
			const FAnimTrack& AnimTrack = Composite->AnimationTrack;

			// find out if this is additive animation
			if (AnimTrack.IsAdditive())
			{
#if WITH_EDITORONLY_DATA
				if (Composite->PreviewBasePose)
				{
					Composite->PreviewBasePose->GetAdditiveBasePose(Output.Pose, Output.Curve, ExtractionContext);
				}
				else
#endif
				{
					// get base pose - for now we only support ref pose as base
					Output.Pose.ResetToRefPose();
				}

				EAdditiveAnimationType AdditiveAnimType = AnimTrack.IsRotationOffsetAdditive()? AAT_RotationOffsetMeshSpace : AAT_LocalSpaceBase;

				FCompactPose AdditivePose;
				FBlendedCurve AdditiveCurve;
				AdditivePose.SetBoneContainer(&Output.Pose.GetBoneContainer());
				AdditiveCurve.InitFrom(Output.Curve);
				Composite->GetAnimationPose(AdditivePose, AdditiveCurve, ExtractionContext);

				FAnimationRuntime::AccumulateAdditivePose(Output.Pose, AdditivePose, Output.Curve, AdditiveCurve, 1.f, AdditiveAnimType);
			}
			else
			{
				//doesn't handle additive yet
				Composite->GetAnimationPose(Output.Pose, Output.Curve, ExtractionContext);
			}
		}
		else if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
		{
			// for now only update first slot
			// in the future, add option to see which slot to see
			if (Montage->SlotAnimTracks.Num() > 0)
			{
				FCompactPose SourcePose;
				FBlendedCurve SourceCurve;
				SourcePose.SetBoneContainer(&Output.Pose.GetBoneContainer());
				SourceCurve.InitFrom(Output.Curve);
			
				if (Montage->IsValidAdditive())
				{
#if WITH_EDITORONLY_DATA
					// if montage is additive, we need to have base pose for the slot pose evaluate
					if (Montage->PreviewBasePose && Montage->SequenceLength > 0.f)
					{
						Montage->PreviewBasePose->GetBonePose(SourcePose, SourceCurve, FAnimExtractContext(CurrentTime));
					}
					else
#endif // WITH_EDITORONLY_DATA
					{
						SourcePose.ResetToRefPose();				
					}
				}
				else
				{
					SourcePose.ResetToRefPose();			
				}

				SlotEvaluatePose(Montage->SlotAnimTracks[0].SlotName, SourcePose, SourceCurve, Output.Pose, Output.Curve, 1.f);
			}
		}
	}

	if(CurrentVertexAnim != NULL)
	{
		VertexAnims.Add(FActiveVertexAnim(CurrentVertexAnim, 1.f, CurrentTime));
	}

	return true;
}