Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimPreviewInstance.cpp
2014-04-23 17:34:31 -04:00

667 lines
18 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "AnimGraphPrivatePCH.h"
#include "AnimPreviewInstance.h"
UAnimPreviewInstance::UAnimPreviewInstance(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
SkeletalControlAlpha = 1.0f;
}
void UAnimPreviewInstance::NativeInitializeAnimation()
{
// Cache our play state from the previous animation otherwise set to play
bool bCachedIsPlaying = (CurrentAsset != NULL) ? bPlaying : true;
Super::NativeInitializeAnimation();
SetPlaying(bCachedIsPlaying);
}
FAnimNode_ModifyBone* UAnimPreviewInstance::FindModifiedBone(const FName& InBoneName)
{
return BoneControllers.FindByPredicate(
[InBoneName](const FAnimNode_ModifyBone& InController) -> bool
{
return InController.BoneToModify.BoneName == InBoneName;
}
);
}
FAnimNode_ModifyBone& UAnimPreviewInstance::ModifyBone(const FName& InBoneName)
{
FAnimNode_ModifyBone* SingleBoneController = FindModifiedBone(InBoneName);
if(SingleBoneController == nullptr)
{
int32 NewIndex = BoneControllers.Add(FAnimNode_ModifyBone());
SingleBoneController = &BoneControllers[NewIndex];
}
SingleBoneController->BoneToModify.BoneName = InBoneName;
SingleBoneController->TranslationMode = BMM_Replace;
SingleBoneController->TranslationSpace = BCS_BoneSpace;
SingleBoneController->RotationMode = BMM_Replace;
SingleBoneController->RotationSpace = BCS_BoneSpace;
return *SingleBoneController;
}
void UAnimPreviewInstance::RemoveBoneModification(const FName& InBoneName)
{
BoneControllers.RemoveAll(
[InBoneName](const FAnimNode_ModifyBone& InController)
{
return InController.BoneToModify.BoneName == InBoneName;
}
);
}
bool UAnimPreviewInstance::NativeEvaluateAnimation(FPoseContext& Output)
{
Super::NativeEvaluateAnimation(Output);
USkeletalMeshComponent* Component = GetSkelMeshComponent();
if (Component && CurrentSkeleton)
{
if(BoneControllers.Num() > 0)
{
FA2CSPose OutMeshPose;
OutMeshPose.AllocateLocalPoses(RequiredBones, Output.Pose);
for(auto& SingleBoneController : BoneControllers)
{
SingleBoneController.BoneToModify.BoneIndex = RequiredBones.GetPoseBoneIndexForBoneName(SingleBoneController.BoneToModify.BoneName);
if (SingleBoneController.BoneToModify.BoneIndex != INDEX_NONE)
{
TArray<FBoneTransform> BoneTransforms;
SingleBoneController.EvaluateBoneTransforms(Component, RequiredBones, OutMeshPose, BoneTransforms);
if (BoneTransforms.Num() > 0)
{
OutMeshPose.LocalBlendCSBoneTransforms(BoneTransforms, 1.0f);
}
}
}
// convert back to local @todo check this
OutMeshPose.ConvertToLocalPoses(Output.Pose);
}
}
return true;
}
/** Set SkeletalControl Alpha**/
void UAnimPreviewInstance::SetSkeletalControlAlpha(float InSkeletalControlAlpha)
{
SkeletalControlAlpha = FMath::Clamp<float>(InSkeletalControlAlpha, 0.f, 1.f);
}
UAnimSequence* UAnimPreviewInstance::GetAnimSequence()
{
return Cast<UAnimSequence>(CurrentAsset);
}
void UAnimPreviewInstance::RestartMontage(UAnimMontage* Montage, FName FromSection)
{
if (Montage == CurrentAsset)
{
MontagePreviewType = EMPT_Normal;
Montage_Play(Montage, PlayRate);
if (FromSection != NAME_None)
{
Montage_JumpToSection(FromSection);
}
MontagePreview_SetLoopNormal(bLooping, Montage->GetSectionIndex(FromSection));
}
}
void UAnimPreviewInstance::MontagePreview_SetLooping(bool bIsLooping)
{
bLooping = bIsLooping;
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
switch (MontagePreviewType)
{
case EMPT_AllSections:
MontagePreview_SetLoopAllSections(bLooping);
break;
case EMPT_Normal:
default:
MontagePreview_SetLoopNormal(bLooping);
break;
}
}
}
void UAnimPreviewInstance::MontagePreview_SetPlaying(bool bIsPlaying)
{
bPlaying = bIsPlaying;
if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance())
{
CurMontageInstance->bPlaying = bIsPlaying;
}
else if (bPlaying)
{
UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset);
if (Montage)
{
switch (MontagePreviewType)
{
case EMPT_AllSections:
MontagePreview_PreviewAllSections();
break;
case EMPT_Normal:
default:
MontagePreview_PreviewNormal();
break;
}
}
}
}
void UAnimPreviewInstance::MontagePreview_SetReverse(bool bInReverse)
{
Super::SetReverse(bInReverse);
if (FAnimMontageInstance * CurMontageInstance = GetActiveMontageInstance())
{
// copy the current playrate
CurMontageInstance->PlayRate = PlayRate;
}
}
void UAnimPreviewInstance::MontagePreview_Restart()
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
switch (MontagePreviewType)
{
case EMPT_AllSections:
MontagePreview_PreviewAllSections();
break;
case EMPT_Normal:
default:
MontagePreview_PreviewNormal();
break;
}
}
}
void UAnimPreviewInstance::MontagePreview_StepForward()
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
bool bWasPlaying = IsPlayingMontage() && (bLooping || bPlaying); // we need to handle non-looped case separately, even if paused during playthrough
MontagePreview_SetReverse(false);
if (! bWasPlaying)
{
if (! bLooping)
{
float StoppedAt = CurrentTime;
if (! bWasPlaying)
{
// play montage but at last known location
MontagePreview_Restart();
SetPosition(StoppedAt, false);
}
int32 LastPreviewSectionIdx = MontagePreview_FindLastSection(MontagePreviewStartSectionIdx);
if (FMath::Abs(CurrentTime - (Montage->CompositeSections[LastPreviewSectionIdx].StartTime + Montage->GetSectionLength(LastPreviewSectionIdx))) <= MontagePreview_CalculateStepLength())
{
// we're at the end, jump right to the end
Montage_JumpToSectionsEnd(Montage->GetSectionName(LastPreviewSectionIdx));
if (! bWasPlaying)
{
MontagePreview_SetPlaying(false);
}
return; // can't go further than beginning of this
}
}
else
{
MontagePreview_Restart();
}
}
MontagePreview_SetPlaying(true);
// Advance a single frame, leaving it paused afterwards
GetSkelMeshComponent()->GlobalAnimRateScale = 1.0f;
GetSkelMeshComponent()->TickAnimation(MontagePreview_CalculateStepLength());
MontagePreview_SetPlaying(false);
}
}
void UAnimPreviewInstance::MontagePreview_StepBackward()
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
bool bWasPlaying = IsPlayingMontage() && (bLooping || bPlaying); // we need to handle non-looped case separately, even if paused during playthrough
MontagePreview_SetReverse(true);
if (! bWasPlaying)
{
if (! bLooping)
{
float StoppedAt = CurrentTime;
if (! bWasPlaying)
{
// play montage but at last known location
MontagePreview_Restart();
SetPosition(StoppedAt, false);
}
int32 LastPreviewSectionIdx = MontagePreview_FindLastSection(MontagePreviewStartSectionIdx);
if (FMath::Abs(CurrentTime - (Montage->CompositeSections[LastPreviewSectionIdx].StartTime + Montage->GetSectionLength(LastPreviewSectionIdx))) <= MontagePreview_CalculateStepLength())
{
// special case as we could stop at the end of our last section which is also beginning of following section - we don't want to get stuck there, but be inside of our starting section
Montage_JumpToSection(Montage->GetSectionName(LastPreviewSectionIdx));
}
else if (FMath::Abs(CurrentTime - Montage->CompositeSections[MontagePreviewStartSectionIdx].StartTime) <= MontagePreview_CalculateStepLength())
{
// we're at the end of playing backward, jump right to the end
Montage_JumpToSectionsEnd(Montage->GetSectionName(MontagePreviewStartSectionIdx));
if (! bWasPlaying)
{
MontagePreview_SetPlaying(false);
}
return; // can't go further than beginning of first section
}
}
else
{
MontagePreview_Restart();
}
}
MontagePreview_SetPlaying(true);
// Advance a single frame, leaving it paused afterwards
GetSkelMeshComponent()->GlobalAnimRateScale = 1.0f;
GetSkelMeshComponent()->TickAnimation(MontagePreview_CalculateStepLength());
MontagePreview_SetPlaying(false);
}
}
float UAnimPreviewInstance::MontagePreview_CalculateStepLength()
{
return 1.0f / 30.0f;
}
void UAnimPreviewInstance::MontagePreview_JumpToStart()
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
int32 SectionIdx = 0;
if (MontagePreviewType == EMPT_Normal)
{
SectionIdx = MontagePreviewStartSectionIdx;
}
// TODO hack - Montage_JumpToSection requires montage being played
bool bWasPlaying = IsPlayingMontage();
if (! bWasPlaying)
{
MontagePreview_Restart();
}
if (PlayRate < 0.f)
{
Montage_JumpToSectionsEnd(Montage->GetSectionName(SectionIdx));
}
else
{
Montage_JumpToSection(Montage->GetSectionName(SectionIdx));
}
if (! bWasPlaying)
{
MontagePreview_SetPlaying(false);
}
}
}
void UAnimPreviewInstance::MontagePreview_JumpToEnd()
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
int32 SectionIdx = 0;
if (MontagePreviewType == EMPT_Normal)
{
SectionIdx = MontagePreviewStartSectionIdx;
}
// TODO hack - Montage_JumpToSectionsEnd requires montage being played
bool bWasPlaying = IsPlayingMontage();
if (! bWasPlaying)
{
MontagePreview_Restart();
}
if (PlayRate < 0.f)
{
Montage_JumpToSection(Montage->GetSectionName(MontagePreview_FindLastSection(SectionIdx)));
}
else
{
Montage_JumpToSectionsEnd(Montage->GetSectionName(MontagePreview_FindLastSection(SectionIdx)));
}
if (! bWasPlaying)
{
MontagePreview_SetPlaying(false);
}
}
}
void UAnimPreviewInstance::MontagePreview_JumpToPreviewStart()
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
int32 SectionIdx = 0;
if (MontagePreviewType == EMPT_Normal)
{
SectionIdx = MontagePreviewStartSectionIdx;
}
// TODO hack - Montage_JumpToSectionsEnd requires montage being played
bool bWasPlaying = IsPlayingMontage();
if (! bWasPlaying)
{
MontagePreview_Restart();
}
Montage_JumpToSection(Montage->GetSectionName(PlayRate > 0.f? SectionIdx : MontagePreview_FindLastSection(SectionIdx)));
if (! bWasPlaying)
{
MontagePreview_SetPlaying(false);
}
}
}
void UAnimPreviewInstance::MontagePreview_JumpToPosition(float NewPosition)
{
SetPosition(NewPosition, false);
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
// this section will be first
int32 NewMontagePreviewStartSectionIdx = MontagePreview_FindFirstSectionAsInMontage(Montage->GetSectionIndexFromPosition(NewPosition));
if (MontagePreviewStartSectionIdx != NewMontagePreviewStartSectionIdx &&
MontagePreviewType == EMPT_Normal)
{
MontagePreviewStartSectionIdx = NewMontagePreviewStartSectionIdx;
}
// setup looping to match normal playback
MontagePreview_SetLooping(bLooping);
}
}
void UAnimPreviewInstance::MontagePreview_RemoveBlendOut()
{
if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance())
{
CurMontageInstance->DefaultBlendTimeMultiplier = 0.0f;
}
}
void UAnimPreviewInstance::MontagePreview_PreviewNormal(int32 FromSectionIdx)
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
int32 PreviewFromSection = FromSectionIdx;
if (FromSectionIdx != INDEX_NONE)
{
MontagePreviewStartSectionIdx = MontagePreview_FindFirstSectionAsInMontage(FromSectionIdx);
}
else
{
FromSectionIdx = MontagePreviewStartSectionIdx;
PreviewFromSection = MontagePreviewStartSectionIdx;
}
MontagePreviewType = EMPT_Normal;
Montage_Play(Montage, PlayRate);
MontagePreview_SetLoopNormal(bLooping, FromSectionIdx);
Montage_JumpToSection(Montage->GetSectionName(PreviewFromSection));
MontagePreview_RemoveBlendOut();
bPlaying = true;
}
}
void UAnimPreviewInstance::MontagePreview_PreviewAllSections()
{
UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset);
if (Montage && Montage->SequenceLength > 0.f)
{
MontagePreviewType = EMPT_AllSections;
Montage_Play(Montage, PlayRate);
MontagePreview_SetLoopAllSections(bLooping);
MontagePreview_JumpToPreviewStart();
MontagePreview_RemoveBlendOut();
bPlaying = true;
}
}
void UAnimPreviewInstance::MontagePreview_SetLoopNormal(bool bIsLooping, int32 PreferSectionIdx)
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
MontagePreview_ResetSectionsOrder();
if (PreferSectionIdx == INDEX_NONE)
{
PreferSectionIdx = Montage->GetSectionIndexFromPosition(CurrentTime);
}
int32 TotalSection = Montage->CompositeSections.Num();
if (TotalSection > 0)
{
int PreferedInChain = TotalSection;
TArray<bool> AlreadyUsed;
AlreadyUsed.AddZeroed(TotalSection);
while (true)
{
// find first not already used section
int32 NotUsedIdx = 0;
while (NotUsedIdx < TotalSection)
{
if (! AlreadyUsed[NotUsedIdx])
{
break;
}
++ NotUsedIdx;
}
if (NotUsedIdx >= TotalSection)
{
break;
}
// find if this is one we're looking for closest to starting one
int32 CurSectionIdx = NotUsedIdx;
int32 InChain = 0;
while (true)
{
// find first that contains this
if (CurSectionIdx == PreferSectionIdx &&
InChain < PreferedInChain)
{
PreferedInChain = InChain;
PreferSectionIdx = NotUsedIdx;
}
AlreadyUsed[CurSectionIdx] = true;
FName NextSection = Montage->CompositeSections[CurSectionIdx].NextSectionName;
CurSectionIdx = Montage->GetSectionIndex(NextSection);
if (CurSectionIdx == INDEX_NONE || AlreadyUsed[CurSectionIdx]) // break loops
{
break;
}
++ InChain;
}
// loop this section
SetMontageLoop(Montage, bIsLooping, Montage->CompositeSections[NotUsedIdx].SectionName);
}
if (Montage->CompositeSections.IsValidIndex(PreferSectionIdx))
{
SetMontageLoop(Montage, bIsLooping, Montage->CompositeSections[PreferSectionIdx].SectionName);
}
}
}
}
void UAnimPreviewInstance::MontagePreview_SetLoopAllSetupSections(bool bIsLooping)
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
MontagePreview_ResetSectionsOrder();
int32 TotalSection = Montage->CompositeSections.Num();
if (TotalSection > 0)
{
FName FirstSection = Montage->CompositeSections[0].SectionName;
FName PreviousSection = FirstSection;
TArray<bool> AlreadyUsed;
AlreadyUsed.AddZeroed(TotalSection);
while (true)
{
// find first not already used section
int32 NotUsedIdx = 0;
while (NotUsedIdx < TotalSection)
{
if (! AlreadyUsed[NotUsedIdx])
{
break;
}
++ NotUsedIdx;
}
if (NotUsedIdx >= TotalSection)
{
break;
}
// go through all connected to join them into one big chain
int CurSectionIdx = NotUsedIdx;
while (true)
{
AlreadyUsed[CurSectionIdx] = true;
FName CurrentSection = Montage->CompositeSections[CurSectionIdx].SectionName;
Montage_SetNextSection(PreviousSection, CurrentSection);
PreviousSection = CurrentSection;
FName NextSection = Montage->CompositeSections[CurSectionIdx].NextSectionName;
CurSectionIdx = Montage->GetSectionIndex(NextSection);
if (CurSectionIdx == INDEX_NONE || AlreadyUsed[CurSectionIdx]) // break loops
{
break;
}
}
}
if (bIsLooping)
{
// and loop all
Montage_SetNextSection(PreviousSection, FirstSection);
}
}
}
}
void UAnimPreviewInstance::MontagePreview_SetLoopAllSections(bool bIsLooping)
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
int32 TotalSection = Montage->CompositeSections.Num();
if (TotalSection > 0)
{
if (bIsLooping)
{
for (int i = 0; i < TotalSection; ++ i)
{
Montage_SetNextSection(Montage->CompositeSections[i].SectionName, Montage->CompositeSections[(i+1) % TotalSection].SectionName);
}
}
else
{
for (int i = 0; i < TotalSection - 1; ++ i)
{
Montage_SetNextSection(Montage->CompositeSections[i].SectionName, Montage->CompositeSections[i+1].SectionName);
}
Montage_SetNextSection(Montage->CompositeSections[TotalSection - 1].SectionName, NAME_None);
}
}
}
}
void UAnimPreviewInstance::MontagePreview_ResetSectionsOrder()
{
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
int32 TotalSection = Montage->CompositeSections.Num();
// restore to default
for (int i = 0; i < TotalSection; ++ i)
{
Montage_SetNextSection(Montage->CompositeSections[i].SectionName, Montage->CompositeSections[i].NextSectionName);
}
}
}
int32 UAnimPreviewInstance::MontagePreview_FindFirstSectionAsInMontage(int32 ForSectionIdx)
{
int32 ResultIdx = ForSectionIdx;
// Montage does not have looping set up, so it should be valid and it gets
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
TArray<bool> AlreadyVisited;
AlreadyVisited.AddZeroed(Montage->CompositeSections.Num());
bool bFoundResult = false;
while (! bFoundResult)
{
int32 UnusedSectionIdx = INDEX_NONE;
for (int32 Idx = 0; Idx < Montage->CompositeSections.Num(); ++ Idx)
{
if (! AlreadyVisited[Idx])
{
UnusedSectionIdx = Idx;
break;
}
}
if (UnusedSectionIdx == INDEX_NONE)
{
break;
}
// check if this has ForSectionIdx
int32 CurrentSectionIdx = UnusedSectionIdx;
while (CurrentSectionIdx != INDEX_NONE && ! AlreadyVisited[CurrentSectionIdx])
{
if (CurrentSectionIdx == ForSectionIdx)
{
ResultIdx = UnusedSectionIdx;
bFoundResult = true;
break;
}
AlreadyVisited[CurrentSectionIdx] = true;
FName NextSection = Montage->CompositeSections[CurrentSectionIdx].NextSectionName;
CurrentSectionIdx = Montage->GetSectionIndex(NextSection);
}
}
}
return ResultIdx;
}
int32 UAnimPreviewInstance::MontagePreview_FindLastSection(int32 StartSectionIdx)
{
int32 ResultIdx = StartSectionIdx;
if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
{
if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance())
{
int32 TotalSection = Montage->CompositeSections.Num();
if (TotalSection > 0)
{
TArray<bool> AlreadyVisited;
AlreadyVisited.AddZeroed(TotalSection);
int32 CurrentSectionIdx = StartSectionIdx;
while (CurrentSectionIdx != INDEX_NONE && ! AlreadyVisited[CurrentSectionIdx])
{
AlreadyVisited[CurrentSectionIdx] = true;
ResultIdx = CurrentSectionIdx;
if (CurMontageInstance->NextSections.IsValidIndex(CurrentSectionIdx))
{
CurrentSectionIdx = CurMontageInstance->NextSections[CurrentSectionIdx];
}
}
}
}
}
return ResultIdx;
}