void FMovieSceneSkeletalAnimationTrackInstance::PreviewSetAnimPosition(USkeletalMeshComponent* SkeletalMeshComponent, FName SlotName, int32 ChannelIndex, UAnimSequenceBase* InAnimSequence, float InPosition, bool bLooping, bool bFireNotifies, float DeltaTime, bool bPlaying, bool bResetDynamics)
{
	if(CanPlayAnimation(SkeletalMeshComponent, InAnimSequence))
	{
		UAnimMontage* Montage = FAnimMontageInstance::PreviewMatineeSetAnimPositionInner(SlotName, SkeletalMeshComponent, InAnimSequence, InPosition, bLooping, bFireNotifies, DeltaTime);

		// if we are not playing, make sure we dont continue (as skeletal meshes can still tick us onwards)
		UAnimInstance* AnimInst = SkeletalMeshComponent->GetAnimInstance();
		UAnimSingleNodeInstance * SingleNodeInst = SkeletalMeshComponent->GetSingleNodeInstance();
		if(SingleNodeInst)
		{
			SingleNodeInst->SetPlaying(bPlaying);
		}
		else if (AnimInst)
		{
			if(Montage)
			{
				if(bPlaying)
				{
					AnimInst->Montage_Resume(Montage);
				}
				else
				{
					AnimInst->Montage_Pause(Montage);
				}
			}

			if(bResetDynamics)
			{
				// make sure we reset any simulations
				AnimInst->ResetDynamics();
			}
		}
	}
}
void SAnimationSegmentViewport::InitSkeleton()
{
	UObject *Object = NULL;
	AnimRefPropertyHandle->GetValue(Object);
	UAnimSequenceBase *AnimSequence = Cast<UAnimSequenceBase>(Object);
	USkeleton *Skeleton = NULL;
	if(AnimSequence != NULL)
	{
		Skeleton = AnimSequence->GetSkeleton();
	}

	if( PreviewComponent != NULL && Skeleton != NULL )
	{
		USkeletalMesh* PreviewMesh = Skeleton->GetAssetPreviewMesh(AnimSequence);
		if (PreviewMesh)
		{
			UAnimSingleNodeInstance * Preview = PreviewComponent->PreviewInstance;
			if((Preview == NULL || Preview->GetCurrentAsset() != AnimSequence) ||
				(PreviewComponent->SkeletalMesh != PreviewMesh))
			{
				PreviewComponent->SetSkeletalMesh(PreviewMesh);
				PreviewComponent->EnablePreview(true, AnimSequence, NULL);
				PreviewComponent->PreviewInstance->SetLooping(true);

				//Place the camera at a good viewer position
				FVector NewPosition = LevelViewportClient->GetViewLocation();
				NewPosition.Normalize();
				LevelViewportClient->SetViewLocation(NewPosition * (PreviewMesh->GetImportedBounds().SphereRadius*1.5f));
			}
		}
	}

	TargetSkeleton = Skeleton;
}
void FMovieSceneSkeletalAnimationTrackInstance::RefreshInstance( const TArray<TWeakObjectPtr<UObject>>& RuntimeObjects, IMovieScenePlayer& Player, FMovieSceneSequenceInstance& SequenceInstance )
{
	UpdateRefreshBones(RuntimeObjects);

	// When not in preview playback we need to stop any running animations to prevent the animations from being advanced a frame when
	// they are ticked by the engine.
	for ( TWeakObjectPtr<UObject> RuntimeObjectPtr : RuntimeObjects )
	{
		if ( ShouldUsePreviewPlayback( Player, RuntimeObjectPtr.Get() ) == false )
		{
			USkeletalMeshComponent* SkeletalMeshComponent = GetSkeletalMeshComponentFromRuntimeObjectPtr( RuntimeObjectPtr );
			if ( SkeletalMeshComponent != nullptr )
			{
				UAnimInstance* AnimInstance = SkeletalMeshComponent->GetAnimInstance();
				if ( AnimInstance )
				{
					UAnimSingleNodeInstance * SingleNodeInstance = SkeletalMeshComponent->GetSingleNodeInstance();
					if ( SingleNodeInstance )
					{
						SingleNodeInstance->SetPlaying( false );
					}
					// TODO: Anim montage?
				}
			}
		}
	}
}
EPlaybackMode::Type SAnimationSegmentScrubPanel::GetPlaybackMode() const
{
	UAnimSingleNodeInstance* PreviewInst = GetPreviewInstance();
	if (PreviewInst && PreviewInst->IsPlaying())
	{
		return PreviewInst->IsReverse() ? EPlaybackMode::PlayingReverse : EPlaybackMode::PlayingForward;
	}
	return EPlaybackMode::Stopped;
}
float SAnimationSegmentScrubPanel::GetScrubValue() const
{
	if (DoesSyncViewport())
	{
		UAnimSingleNodeInstance* PreviewInst = GetPreviewInstance();
		if (PreviewInst)
		{
			return PreviewInst->GetCurrentTime();
		}
	}
	return 0.f;
}
void USkeletalMeshComponent::SetPlayRate(float Rate)
{
	UAnimSingleNodeInstance* SingleNodeInstance = GetSingleNodeInstance();
	if (SingleNodeInstance)
	{
		SingleNodeInstance->SetPlayRate(Rate);
	}
	else if( AnimScriptInstance != NULL )
	{
		UE_LOG(LogAnimation, Warning, TEXT("Currently in Animation Blueprint mode. Please change AnimationMode to Use Animation Asset"));
	}
}
void USkeletalMeshComponent::SetAnimation(UAnimationAsset* NewAnimToPlay)
{
	UAnimSingleNodeInstance* SingleNodeInstance = GetSingleNodeInstance();
	if (SingleNodeInstance)
	{
		SingleNodeInstance->SetAnimationAsset(NewAnimToPlay, false);
		SingleNodeInstance->bPlaying = false;
	}
	else if( AnimScriptInstance != NULL )
	{
		UE_LOG(LogAnimation, Warning, TEXT("Currently in Animation Blueprint mode. Please change AnimationMode to Use Animation Asset"));
	}
}
void USkeletalMeshComponent::SetVertexAnimation(UVertexAnimation* NewVertexAnimation)
{
	UAnimSingleNodeInstance* SingleNodeInstance = GetSingleNodeInstance();
	if (SingleNodeInstance)
	{
		SingleNodeInstance->SetVertexAnimation(NewVertexAnimation, false);
		// when set the asset, we shouldn't automatically play. 
		SingleNodeInstance->bPlaying = false;
	}
	else if( AnimScriptInstance != NULL )
	{
		UE_LOG(LogAnimation, Warning, TEXT("Currently in Animation Blueprint mode. Please change AnimationMode to Use Animation Asset"));
	}
}
FReply SAnimationSegmentScrubPanel::OnClick_Forward()
{
	UAnimSingleNodeInstance* PreviewInst = GetPreviewInstance();
	if (PreviewInst)
	{
		bool bIsReverse = PreviewInst->IsReverse();
		bool bIsPlaying = PreviewInst->IsPlaying();
		// if current bIsReverse and bIsPlaying, we'd like to just turn off reverse
		if (bIsReverse && bIsPlaying)
		{
			PreviewInst->SetReverse(false);
		}
		// already playing, simply pause
		else if (bIsPlaying) 
		{
			PreviewInst->SetPlaying(false);
		}
		// if not playing, play forward
		else 
		{
			PreviewInst->SetReverse(false);
			PreviewInst->SetPlaying(true);
		}
	}

	return FReply::Handled();
}
void FMovieSceneSkeletalAnimationTrackInstance::SetAnimPosition(USkeletalMeshComponent* SkeletalMeshComponent, FName SlotName, int32 ChannelIndex, UAnimSequenceBase* InAnimSequence, float InPosition, bool bLooping, bool bFireNotifies)
{
	if (CanPlayAnimation(SkeletalMeshComponent, InAnimSequence))
	{
		UAnimMontage* Montage = FAnimMontageInstance::SetMatineeAnimPositionInner(SlotName, SkeletalMeshComponent, InAnimSequence, InPosition, bLooping);

		// Ensure the sequence is not stopped
		UAnimInstance* AnimInst = SkeletalMeshComponent->GetAnimInstance();
		UAnimSingleNodeInstance* SingleNodeInst = SkeletalMeshComponent->GetSingleNodeInstance();
		if(SingleNodeInst)
		{
			SingleNodeInst->SetPlaying(true);
		}
		else if (AnimInst && Montage)
		{
			AnimInst->Montage_Resume(Montage);
		}
	}
}
uint32 SAnimationSegmentScrubPanel::GetNumOfFrames() const
{
	if (DoesSyncViewport())
	{
		UAnimSingleNodeInstance* PreviewInst = GetPreviewInstance();
		float Length = PreviewInst->GetLength();
		// if anim sequence, use correct num frames
		int32 NumFrames = (int32) (Length/0.0333f); 
		if (PreviewInst->GetCurrentAsset() && PreviewInst->GetCurrentAsset()->IsA(UAnimSequenceBase::StaticClass()))
		{
			NumFrames = CastChecked<UAnimSequenceBase>(PreviewInst->GetCurrentAsset())->GetNumberOfFrames();
		}
		return NumFrames;
	}
	else if (LockedSequence)
	{
		return LockedSequence->GetNumberOfFrames();
	}
	return 1;
}
bool SAnimationSegmentScrubPanel::DoesSyncViewport() const
{
	UAnimSingleNodeInstance* PreviewInst = GetPreviewInstance();

	return (( LockedSequence==NULL && PreviewInst ) || ( LockedSequence && PreviewInst && PreviewInst->GetCurrentAsset() == LockedSequence ));
}
bool FBlendSpaceThumbnailScene::SetBlendSpace(class UBlendSpaceBase* InBlendSpace)
{
    PreviewActor->GetSkeletalMeshComponent()->OverrideMaterials.Empty();

    bool bSetSucessfully = false;

    PreviewAnimation = InBlendSpace;

    if (InBlendSpace)
    {
        if (USkeleton* Skeleton = InBlendSpace->GetSkeleton())
        {
            USkeletalMesh* PreviewSkeletalMesh = Skeleton->GetAssetPreviewMesh(InBlendSpace);

            PreviewActor->GetSkeletalMeshComponent()->SetSkeletalMesh(PreviewSkeletalMesh);

            if (PreviewSkeletalMesh)
            {
                bSetSucessfully = true;

                UDebugSkelMeshComponent* MeshComponent = CastChecked<UDebugSkelMeshComponent>(PreviewActor->GetSkeletalMeshComponent());

                // Handle posing the mesh at the middle of the animation
                MeshComponent->EnablePreview(true, InBlendSpace);
                MeshComponent->Play(false);
                MeshComponent->Stop();

                UAnimSingleNodeInstance* AnimInstance = MeshComponent->GetSingleNodeInstance();
                if (AnimInstance)
                {
                    FVector BlendInput(0.f);
                    for (int32 i = 0; i < InBlendSpace->NumOfDimension; ++i)
                    {
                        const FBlendParameter& Param = InBlendSpace->GetBlendParameter(i);
                        BlendInput[i] = (Param.GetRange() / 2.f) + Param.Min;
                    }
                    AnimInstance->UpdateBlendspaceSamples(BlendInput);
                }

                MeshComponent->TickAnimation(0.f, false);
                MeshComponent->RefreshBoneTransforms(nullptr);

                FTransform MeshTransform = FTransform::Identity;

                PreviewActor->SetActorLocation(FVector(0, 0, 0), false);
                PreviewActor->GetSkeletalMeshComponent()->UpdateBounds();

                // Center the mesh at the world origin then offset to put it on top of the plane
                const float BoundsZOffset = GetBoundsZOffset(PreviewActor->GetSkeletalMeshComponent()->Bounds);
                PreviewActor->SetActorLocation(-PreviewActor->GetSkeletalMeshComponent()->Bounds.Origin + FVector(0, 0, BoundsZOffset), false);
                PreviewActor->GetSkeletalMeshComponent()->RecreateRenderState_Concurrent();
            }
        }
    }

    if (!bSetSucessfully)
    {
        CleanupComponentChildren(PreviewActor->GetSkeletalMeshComponent());
        PreviewActor->GetSkeletalMeshComponent()->SetAnimation(NULL);
        PreviewActor->GetSkeletalMeshComponent()->SetSkeletalMesh(nullptr);
    }

    return bSetSucessfully;
}
bool FAnimationSequenceThumbnailScene::SetAnimation(UAnimSequenceBase* InAnimation)
{
    PreviewActor->GetSkeletalMeshComponent()->OverrideMaterials.Empty();

    bool bSetSucessfully = false;

    PreviewAnimation = InAnimation;

    if (InAnimation)
    {
        if (USkeleton* Skeleton = InAnimation->GetSkeleton())
        {
            USkeletalMesh* PreviewSkeletalMesh = Skeleton->GetAssetPreviewMesh(InAnimation);

            PreviewActor->GetSkeletalMeshComponent()->SetSkeletalMesh(PreviewSkeletalMesh);

            if (PreviewSkeletalMesh)
            {
                bSetSucessfully = true;

                if (InAnimation->IsValidToPlay())
                {
                    // Handle posing the mesh at the middle of the animation
                    const float AnimPosition = InAnimation->SequenceLength / 2.f;

                    UDebugSkelMeshComponent* MeshComponent = CastChecked<UDebugSkelMeshComponent>(PreviewActor->GetSkeletalMeshComponent());

                    MeshComponent->EnablePreview(true, InAnimation);
                    MeshComponent->Play(false);
                    MeshComponent->Stop();
                    MeshComponent->SetPosition(AnimPosition, false);

                    UAnimSingleNodeInstance* SingleNodeInstance = PreviewActor->GetSkeletalMeshComponent()->GetSingleNodeInstance();
                    if (SingleNodeInstance)
                    {
                        SingleNodeInstance->UpdateMontageWeightForTimeSkip(AnimPosition);
                    }

                    PreviewActor->GetSkeletalMeshComponent()->RefreshBoneTransforms(nullptr);
                }

                PreviewActor->SetActorLocation(FVector(0, 0, 0), false);
                PreviewActor->GetSkeletalMeshComponent()->UpdateBounds();

                // Center the mesh at the world origin then offset to put it on top of the plane
                const float BoundsZOffset = GetBoundsZOffset(PreviewActor->GetSkeletalMeshComponent()->Bounds);
                PreviewActor->SetActorLocation(-PreviewActor->GetSkeletalMeshComponent()->Bounds.Origin + FVector(0, 0, BoundsZOffset), false);
                PreviewActor->GetSkeletalMeshComponent()->RecreateRenderState_Concurrent();
            }
        }
    }

    if(!bSetSucessfully)
    {
        CleanupComponentChildren(PreviewActor->GetSkeletalMeshComponent());
        PreviewActor->GetSkeletalMeshComponent()->SetAnimation(NULL);
        PreviewActor->GetSkeletalMeshComponent()->SetSkeletalMesh(nullptr);
    }

    return bSetSucessfully;
}