// // Created by martin on 11.04.25. // #ifndef ANIMATIONLIBRARY_H #define ANIMATIONLIBRARY_H #include #include "AnimGraph/AnimGraphData.h" #include "ozz/base/io/archive.h" #include "ozz/base/io/stream.h" #include "ozz/base/log.h" struct AnimLibrary { typedef std::map AnimationResourceMap; AnimationResourceMap mAnimations = {}; std::vector mManagedAnimations = {}; AnimLibrary() = default; ~AnimLibrary() { Reset(); } // Move operators. Needed to avoid duplicate frees on the managed animations. AnimLibrary(AnimLibrary&& other) : mAnimations(std::move(other.mAnimations)), mManagedAnimations(std::move(other.mManagedAnimations)) {}; AnimLibrary& operator=(AnimLibrary&& other) { mAnimations = other.mAnimations; mManagedAnimations = std::move(other.mManagedAnimations); return *this; } bool AddAnimation( const std::string& name, ozz::animation::Animation* animation) { AnimationResource animation_resource; animation_resource.m_name = name; 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; } ozz::animation::Animation* animation = new ozz::animation::Animation; assert(!filename.empty()); ozz::io::File file(filename.c_str(), "rb"); if (!file.opened()) { ozz::log::Err() << "Failed to open animation file " << filename << "." << std::endl; return false; } ozz::io::IArchive archive(&file); if (!archive.TestTag()) { ozz::log::Err() << "Failed to load animation instance from file " << filename << "." << std::endl; return false; } // Once the tag is validated, reading cannot fail. archive >> *animation; mManagedAnimations.push_back(animation); AnimationResource animation_resource; animation_resource.m_name = name; animation_resource.m_animation = animation; 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(); } }; 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 //ANIMATIONLIBRARY_H