Files
EVEngine/src/modules/editor/AnimationRootMotionPreviewSource.cpp
T

77 lines
3.4 KiB
C++

#include "editor/AnimationRootMotionPreviewSource.h"
#include "common/Diagnostic.h"
#if defined(EVENGINE_HAS_ANIMATION)
#include "animation/AnimClip.h"
#include "animation/AnimClipRegistry.h"
#include "animation/AnimPose.h"
#include "common/Exception.h"
#endif
#include <limits>
#include <string>
namespace eve::editor {
namespace {
Result<std::vector<action::ActionPreviewPoint3>> sampleError(DiagnosticCode code, std::string message,
std::string path = {}) {
return Result<std::vector<action::ActionPreviewPoint3>>::failure(
Diagnostic::error(code, std::move(message), std::move(path)));
}
} // namespace
Result<std::vector<action::ActionPreviewPoint3>> AnimationRootMotionPreviewSource::sampleRootMotion(
std::string_view animationUri, Duration duration, std::uint32_t sampleCount) const {
if (animationUri.empty())
return sampleError(DiagnosticCode::InvalidArgument, "Animation URI must not be empty", "animationUri");
if (duration < Duration::zero())
return sampleError(DiagnosticCode::InvalidArgument, "Preview duration must be non-negative", "duration");
if (sampleCount < 2 || sampleCount > 1024)
return sampleError(DiagnosticCode::InvalidArgument, "Root-motion sample count must be between 2 and 1024",
"sampleCount");
if (rootBone_ > static_cast<std::uint32_t>(std::numeric_limits<int>::max()))
return sampleError(DiagnosticCode::InvalidArgument, "Root-bone index exceeds the animation API range",
"rootBone");
#if !defined(EVENGINE_HAS_ANIMATION)
return sampleError(DiagnosticCode::Unsupported, "Animation module is not available in this build",
std::string(animationUri));
#else
const std::string uri(animationUri);
auto clips = animation::AnimClipRegistry::findByPath(uri);
if (clips.empty())
return sampleError(DiagnosticCode::NotFound, "No registered animation clip matches the preview URI", uri);
if (clips.size() != 1)
return sampleError(DiagnosticCode::Conflict, "Preview URI resolves to more than one animation clip", uri);
animation::AnimClip* clip = clips.front();
if (!clip) return sampleError(DiagnosticCode::StaleHandle, "Animation registry returned a stale clip", uri);
const int rootBone = static_cast<int>(rootBone_);
if (rootBone >= clip->getTrackCount())
return sampleError(DiagnosticCode::InvalidArgument, "Root-bone track is not present in the animation clip",
"rootBone");
std::vector<action::ActionPreviewPoint3> path;
path.reserve(sampleCount);
animation::AnimPose pose;
try {
for (std::uint32_t index = 0; index < sampleCount; ++index) {
const double alpha = static_cast<double>(index) / static_cast<double>(sampleCount - 1);
const float sampleTime = static_cast<float>(duration.seconds() * alpha);
clip->sample(sampleTime, &pose);
const auto& root = pose.local(rootBone);
path.push_back({root.px, root.py, root.pz});
}
} catch (const Exception&) {
return sampleError(DiagnosticCode::Failed, "Animation clip failed while sampling root motion", uri);
}
return Result<std::vector<action::ActionPreviewPoint3>>::success(std::move(path));
#endif
}
} // namespace eve::editor