AnimTestbed/src/AnimGraph/AnimLibrary.h

145 lines
4.2 KiB
C
Raw Normal View History

2025-04-11 19:03:13 +02:00
//
// Created by martin on 11.04.25.
//
#ifndef ANIMLIBRARY_H
#define ANIMLIBRARY_H
2025-04-11 19:03:13 +02:00
#include <iostream>
#include "AnimGraph/AnimGraphData.h"
#include "ozz/base/io/archive.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/log.h"
/** Manage a set of animations used for an AnimGraph.
*
* By default it behaves like a resource that allows to resolve animation names to
* AnimationResources. However, it can also trigger loading of the referenced resources from their
* filenames. This only happens on-demand.
*/
2025-04-11 19:03:13 +02:00
struct AnimLibrary {
typedef std::map<std::string, AnimationResource> AnimationResourceMap;
AnimationResourceMap mAnimations = {};
std::vector<ozz::animation::Animation*> mManagedAnimations = {};
static constexpr const char* EXTERNAL_ANIMATION = "<external>";
2025-04-11 19:03:13 +02:00
AnimLibrary() = default;
~AnimLibrary() { Reset(); }
bool AddAnimation(
const std::string& name,
ozz::animation::Animation* animation) {
AnimationResource animation_resource;
animation_resource.m_name = name;
animation_resource.m_filename = EXTERNAL_ANIMATION;
2025-04-11 19:03:13 +02:00
animation_resource.m_animation = animation;
mAnimations[name] = animation_resource;
return true;
}
bool AddAnimationFile(const std::string& name, const std::string& filename) {
if (mAnimations.find(name) != mAnimations.end()) {
std::cerr << "Cannot add animation '" << name
<< "' to library. Animation already exists." << std::endl;
return false;
}
AnimationResource animation_resource;
animation_resource.m_name = name;
animation_resource.m_animation = nullptr;
2025-04-11 19:03:13 +02:00
animation_resource.m_filename = filename;
mAnimations[name] = animation_resource;
return true;
}
void Reset() {
for (ozz::animation::Animation* animation : mManagedAnimations) {
assert(animation->num_tracks() < 5);
delete animation;
}
mManagedAnimations.clear();
mAnimations.clear();
}
void LoadAnimations() {
for (AnimationResourceMap::iterator iter = mAnimations.begin();
iter != mAnimations.end();
++iter) {
if (iter->second.m_filename == EXTERNAL_ANIMATION) {
continue;
}
if (iter->second.m_animation != nullptr) {
continue;
}
assert(!iter->second.m_filename.empty());
ozz::io::File file(iter->second.m_filename.c_str(), "rb");
if (!file.opened()) {
ozz::log::Err() << "Failed to open animation file "
<< iter->second.m_filename << "." << std::endl;
continue;
}
ozz::io::IArchive archive(&file);
if (!archive.TestTag<ozz::animation::Animation>()) {
ozz::log::Err() << "Failed to load animation instance from file "
<< iter->second.m_filename << "." << std::endl;
continue;
}
iter->second.m_animation = new ozz::animation::Animation;
archive >> *iter->second.m_animation;
mManagedAnimations.push_back(iter->second.m_animation);
}
}
2025-04-11 19:03:13 +02:00
};
inline void to_json(nlohmann::json& j, const AnimLibrary& animation_library) {
j["type"] = "AnimationLibrary";
for (AnimLibrary::AnimationResourceMap::const_iterator iter =
animation_library.mAnimations.cbegin();
iter != animation_library.mAnimations.cend();
++iter) {
j["animations"][iter->first] = iter->second;
}
}
inline void from_json(const nlohmann::json& j, AnimLibrary& animation_library) {
animation_library.Reset();
if (!j.contains("type") || j["type"] != "AnimationLibrary") {
std::cerr << "Invalid type. Expected 'AnimationLibrary'." << std::endl;
}
if (!j.contains("animations")) {
std::cerr << "Invalid AnimationLibrary. Expected 'animations' key."
<< std::endl;
}
for (nlohmann::json::const_iterator iter = j["animations"].begin();
iter != j["animations"].cend();
++iter) {
AnimationResource animation_resource = *iter;
if (!animation_resource.m_filename.empty()) {
animation_library.AddAnimationFile(
iter.key(),
j["animations"][iter.key()]["filename"]);
animation_library.mAnimations[iter.key()].m_sync_track =
animation_resource.m_sync_track;
} else {
animation_library.mAnimations[iter.key()] = *iter;
}
}
}
#endif //ANIMLIBRARY_H