Skip to content

File NightSkyAnimSequenceUserData.cpp

File List > Animation > NightSkyAnimSequenceUserData.cpp

Go to the documentation of this file

// Fill out your copyright notice in the Description page of Project Settings.


#include "NightSkyAnimSequenceUserData.h"

#include "NightSkyAnimMetaData.h"
#include "NightSkyEngine/Battle/Misc/Globals.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(NightSkyAnimSequenceUserData)

void UNightSkyAnimSequenceUserData::Serialize(FArchive& Ar)
{
    Super::Serialize(Ar);

    Ar << MeshSpaceBoneTransforms;
    Ar << RootTranslation;
}

void UNightSkyAnimSequenceUserData::PostEditChangeOwner(const FPropertyChangedEvent& PropertyChangedEvent)
{
    Super::PostEditChangeOwner(PropertyChangedEvent);

    // We can't call blueprint implemented functions while routing post load
    if (FUObjectThreadContext::Get().IsRoutingPostLoad)
    {
        return;
    }

    // Skip interactive changes
    if (PropertyChangedEvent.ChangeType == EPropertyChangeType::Interactive)
    {
        return;
    }

    MeshSpaceBoneTransforms.Empty();
    RootTranslation.Empty();

    auto AnimSequence = Cast<UAnimSequence>(GetOuter());
    if (!IsValid(AnimSequence)) return;

    UNightSkyAnimMetaData* AnimMetaData = nullptr;

    for (auto& MetaData : AnimSequence->GetMetaData())
    {
        AnimMetaData = Cast<UNightSkyAnimMetaData>(MetaData);
        if (IsValid(MetaData)) break;
    }

    if (!IsValid(AnimMetaData))
    {
        ConditionalBeginDestroy();
        return;
    }

    FrameCount = AnimSequence->GetPlayLength() * AnimSequence->GetSamplingFrameRate().AsDecimal();
    FrameRate = AnimSequence->GetSamplingFrameRate().AsDecimal();

    auto ReferenceSkeleton = AnimSequence->GetSkeleton()->GetReferenceSkeleton();

    for (auto& BoneName : AnimMetaData->CachedBoneNames)
    {
        if (ReferenceSkeleton.FindBoneIndex(BoneName) == INDEX_NONE) continue;
        TMap<int32, FAnimTransform> BoneTransforms;

        for (int i = 0; i < FrameCount; i++)
        {
            FTransform Transform;
            FAnimExtractContext Context{
                static_cast<double>(i) / AnimSequence->GetSamplingFrameRate().AsDecimal()
            };
            AnimSequence->GetBoneTransform(
                Transform, FSkeletonPoseBoneIndex(ReferenceSkeleton.FindBoneIndex(BoneName)),
                Context, true);

            FAnimTransform AnimTransform;
            AnimTransform.Position.X = Transform.GetTranslation().X * COORD_SCALE;
            AnimTransform.Position.Y = Transform.GetTranslation().Y * COORD_SCALE;
            AnimTransform.Position.Z = Transform.GetTranslation().Z * COORD_SCALE;

            auto Rotation = Transform.GetRotation().Rotator();
            AnimTransform.Rotation.Pitch = Rotation.Pitch * 1000;
            AnimTransform.Rotation.Yaw = Rotation.Yaw * 1000;
            AnimTransform.Rotation.Roll = Rotation.Roll * 1000;

            AnimTransform.Scale.X = Transform.GetScale3D().X * 1000;
            AnimTransform.Scale.Y = Transform.GetScale3D().Y * 1000;
            AnimTransform.Scale.Z = Transform.GetScale3D().Z * 1000;

            BoneTransforms.Add(i, AnimTransform);
        }

        MeshSpaceBoneTransforms.Add(BoneName, BoneTransforms);
    }

    for (int i = 0; i < FrameCount; i++)
    {
        FAnimExtractContext Context{
            static_cast<double>(i) / AnimSequence->GetSamplingFrameRate().AsDecimal(),
            true,
        };

        FVector Translation = AnimSequence->ExtractRootTrackTransform(Context, nullptr).GetTranslation();
        FAnimVector AnimTranslation;

        AnimTranslation.X = Translation.X * COORD_SCALE;
        AnimTranslation.Y = Translation.Y * COORD_SCALE;
        AnimTranslation.Z = Translation.Z * COORD_SCALE;

        RootTranslation.Add(i, AnimTranslation);
    }
}

FAnimVector UNightSkyAnimSequenceUserData::GetRootTranslationAtTime(int32 Time) const
{
    if (!RootTranslation.Contains(Time)) return FAnimVector{};
    return RootTranslation[Time];
}

FAnimTransform UNightSkyAnimSequenceUserData::GetCachedBoneTransformAtTime(FName BoneName, int32 Time,
                                                                           bool bRelativeToRoot) const
{
    if (!MeshSpaceBoneTransforms.Contains(BoneName)) return FAnimTransform{};
    if (!MeshSpaceBoneTransforms[BoneName].Contains(Time)) return FAnimTransform{};
    auto Transform = MeshSpaceBoneTransforms[BoneName][Time];

    if (!bRelativeToRoot) return Transform;
    if (!RootTranslation.Contains(Time)) return Transform;

    auto Root = RootTranslation[Time];
    Transform.Position.X += Root.X;
    Transform.Position.Y += Root.Y;
    Transform.Position.Z += Root.Z;
    return Transform;
}

FAnimVector UNightSkyAnimSequenceUserData::GetCachedBoneLocationAtTime(FName BoneName, int32 Time,
    bool bRelativeToRoot) const
{
    if (!MeshSpaceBoneTransforms.Contains(BoneName)) return FAnimVector{};
    if (!MeshSpaceBoneTransforms[BoneName].Contains(Time)) return FAnimVector{};
    auto Transform = MeshSpaceBoneTransforms[BoneName][Time];

    if (!bRelativeToRoot) return Transform.Position;
    if (!RootTranslation.Contains(Time)) return Transform.Position;

    auto Root = RootTranslation[Time];
    Transform.Position.X += Root.X;
    Transform.Position.Y += Root.Y;
    Transform.Position.Z += Root.Z;
    return Transform.Position;
}