Started working on AnimationLibrary.
This commit is contained in:
		
							parent
							
								
									89fedce539
								
							
						
					
					
						commit
						5d01dfcca2
					
				| @ -59,7 +59,9 @@ add_library(AnimTestbedCode OBJECT | ||||
|         src/AnimGraph/AnimGraphResource.cc | ||||
|         src/AnimGraph/AnimGraphResource.h | ||||
|         src/AnimGraph/SyncTrack.cc | ||||
|         src/AnimGraph/SyncTrack.h) | ||||
|         src/AnimGraph/SyncTrack.h | ||||
|         src/AnimGraph/AnimLibrary.h | ||||
| ) | ||||
| 
 | ||||
| target_include_directories( | ||||
|         AnimTestbedCode | ||||
| @ -150,6 +152,9 @@ target_sources(runtests PRIVATE | ||||
|         tests/AnimGraphEvalTests.cc | ||||
|         tests/NodeDescriptorTests.cc | ||||
|         tests/SyncTrackTests.cc | ||||
|         tests/AnimDataTests.cc | ||||
|         tests/TestAnimData.cc | ||||
|         tests/TestAnimData.h | ||||
|         tests/main.cc | ||||
|         ${ozz_offline_test_objs} | ||||
| ) | ||||
|  | ||||
| @ -34,6 +34,8 @@ struct AnimDataRef { | ||||
| 
 | ||||
| struct AnimationResource { | ||||
|   std::string m_name; | ||||
|   std::string m_filename; | ||||
| 
 | ||||
|   ozz::animation::Animation* m_animation; | ||||
|   SyncTrack m_sync_track; | ||||
| }; | ||||
| @ -42,8 +44,9 @@ inline void to_json( | ||||
|     nlohmann::json& j, | ||||
|     const AnimationResource& animation_resource) { | ||||
|   j["type"] = "AnimationResource"; | ||||
|   j["synctrack"] = animation_resource.m_sync_track; | ||||
|   j["name"] = animation_resource.m_name; | ||||
|   j["filename"] = animation_resource.m_filename; | ||||
|   j["synctrack"] = animation_resource.m_sync_track; | ||||
| } | ||||
| 
 | ||||
| inline void from_json( | ||||
| @ -51,8 +54,9 @@ inline void from_json( | ||||
|     AnimationResource& animation_resource) { | ||||
|   assert(j["type"] == "AnimationResource"); | ||||
| 
 | ||||
|   animation_resource.m_sync_track = j["synctrack"]; | ||||
|   animation_resource.m_name = j["name"]; | ||||
|   animation_resource.m_filename = j["filename"]; | ||||
|   animation_resource.m_sync_track = j["synctrack"]; | ||||
| } | ||||
| 
 | ||||
| struct AnimDataAllocator { | ||||
|  | ||||
| @ -152,6 +152,7 @@ bool AnimSamplerNode::Init(AnimGraphContext& context) { | ||||
|     archive >> *m_animation; | ||||
| 
 | ||||
|     context.m_animation_map[m_filename] = { | ||||
|         m_filename, | ||||
|         m_filename, | ||||
|         m_animation, | ||||
|         SyncTrack()}; | ||||
|  | ||||
							
								
								
									
										133
									
								
								src/AnimGraph/AnimLibrary.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/AnimGraph/AnimLibrary.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | ||||
| //
 | ||||
| // Created by martin on 11.04.25.
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef ANIMATIONLIBRARY_H | ||||
| #define ANIMATIONLIBRARY_H | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| #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<std::string, AnimationResource> AnimationResourceMap; | ||||
|   AnimationResourceMap mAnimations = {}; | ||||
|   std::vector<ozz::animation::Animation*> 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::animation::Animation>()) { | ||||
|       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
 | ||||
							
								
								
									
										41
									
								
								tests/AnimDataTests.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tests/AnimDataTests.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| //
 | ||||
| // Created by martin on 11.04.25.
 | ||||
| //
 | ||||
| 
 | ||||
| #include "3rdparty/json/json.hpp" | ||||
| #include "AnimGraph/AnimLibrary.h" | ||||
| #include "TestAnimData.h" | ||||
| #include "catch.hpp" | ||||
| 
 | ||||
| using namespace nlohmann; | ||||
| 
 | ||||
| TEST_CASE("Serialize AnimLibrary", "[AnimLibrary]") { | ||||
|   AnimLibrary library; | ||||
| 
 | ||||
|   TestAnimData::SingleBoneSkeleton single_bone_testdata; | ||||
| 
 | ||||
|   REQUIRE(library.AddAnimationFile( | ||||
|       "translation_x", | ||||
|       single_bone_testdata.animation_translate_x_resource.m_filename)); | ||||
|   REQUIRE(library.AddAnimationFile( | ||||
|       "translation_y", | ||||
|       single_bone_testdata.animation_translate_y_resource.m_filename)); | ||||
| 
 | ||||
|   // serialize
 | ||||
|   json library_data; | ||||
|   library_data = library; | ||||
| 
 | ||||
|   // deserialize
 | ||||
|   AnimLibrary library_deserialized; | ||||
|   library_deserialized = library_data; | ||||
| 
 | ||||
|   CHECK(library_deserialized.mAnimations.size() == library.mAnimations.size()); | ||||
|   for (AnimLibrary::AnimationResourceMap::const_iterator iter = | ||||
|            library.mAnimations.cbegin(); | ||||
|        iter != library.mAnimations.cend(); | ||||
|        ++iter) { | ||||
|     CHECK( | ||||
|         library_deserialized.mAnimations.find(iter->first) | ||||
|         != library_deserialized.mAnimations.end()); | ||||
|   } | ||||
| } | ||||
| @ -200,10 +200,12 @@ TEST_CASE_METHOD( | ||||
|   graph_context.m_skeleton = skeleton.get(); | ||||
|   graph_context.m_animation_map["trans_x"] = { | ||||
|       "trans_x", | ||||
|       "", | ||||
|       animation_translate_x.get(), | ||||
|       animation_translate_x_sync_track}; | ||||
|   graph_context.m_animation_map["trans_y"] = { | ||||
|       "trans_y", | ||||
|       "", | ||||
|       animation_translate_y.get(), | ||||
|       animation_translate_y_sync_track}; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										117
									
								
								tests/TestAnimData.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								tests/TestAnimData.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,117 @@ | ||||
| //
 | ||||
| // Created by martin on 11.04.25.
 | ||||
| //
 | ||||
| 
 | ||||
| #include "TestAnimData.h" | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "ozz/animation/offline/animation_builder.h" | ||||
| #include "ozz/animation/offline/raw_animation.h" | ||||
| #include "ozz/animation/offline/raw_skeleton.h" | ||||
| #include "ozz/base/io/archive.h" | ||||
| #include "ozz/base/log.h" | ||||
| 
 | ||||
| namespace TestAnimData { | ||||
| 
 | ||||
| SingleBoneSkeleton::SingleBoneSkeleton() { | ||||
|   using namespace ozz::animation::offline; | ||||
| 
 | ||||
|   RawSkeleton raw_skeleton; | ||||
|   RawSkeleton::Joint raw_joint; | ||||
| 
 | ||||
|   raw_joint.name = "Bone0"; | ||||
|   raw_joint.transform.translation.x = 1.f; | ||||
|   raw_joint.transform.translation.y = 2.f; | ||||
|   raw_joint.transform.translation.z = 3.f; | ||||
| 
 | ||||
|   raw_skeleton.roots.push_back(raw_joint); | ||||
| 
 | ||||
|   SkeletonBuilder skeleton_builder; | ||||
|   skeleton = skeleton_builder(raw_skeleton); | ||||
| 
 | ||||
|   // SingleBoneSkeleton Animations
 | ||||
|   ozz::animation::offline::RawAnimation raw_animation_translation_x; | ||||
|   raw_animation_translation_x.name = "TranslationX"; | ||||
|   RawAnimation::JointTrack bone0_track; | ||||
|   RawAnimation::JointTrack::Translations bone0_translations; | ||||
| 
 | ||||
|   // animation_translate_x
 | ||||
|   RawAnimation::TranslationKey translation_key; | ||||
|   translation_key.time = 0.f; | ||||
|   translation_key.value = ozz::math::Float3(0.f, 0.f, 0.f); | ||||
|   bone0_translations.push_back(translation_key); | ||||
| 
 | ||||
|   translation_key.time = 1.f; | ||||
|   translation_key.value = ozz::math::Float3(1.f, 0.f, 0.f); | ||||
|   bone0_translations.push_back(translation_key); | ||||
| 
 | ||||
|   bone0_track.translations = bone0_translations; | ||||
|   raw_animation_translation_x.tracks.push_back(bone0_track); | ||||
|   raw_animation_translation_x.duration = 1.f; | ||||
|   if (!raw_animation_translation_x.Validate()) { | ||||
|     std::cerr << "Error: could animation raw data invalid!" << std::endl; | ||||
|   } | ||||
| 
 | ||||
|   AnimationBuilder animation_builder; | ||||
|   animation_translate_x = animation_builder(raw_animation_translation_x); | ||||
| 
 | ||||
|   animation_translate_x_resource.m_animation = animation_translate_x.get(); | ||||
|   SaveAnimation("single_bone_translation_z.ozz", animation_translate_x.get()); | ||||
|   animation_translate_x_resource.m_name = "single_bone_translation_z"; | ||||
|   animation_translate_x_resource.m_filename = "single_bone_translation_z.ozz"; | ||||
| 
 | ||||
|   // animation_translate_y
 | ||||
|   ozz::animation::offline::RawAnimation raw_animation_translation_y; | ||||
|   raw_animation_translation_y.name = "TranslationY"; | ||||
|   bone0_translations.clear(); | ||||
| 
 | ||||
|   translation_key.time = 0.f; | ||||
|   translation_key.value = ozz::math::Float3(0.f, 0.f, 0.f); | ||||
|   bone0_translations.push_back(translation_key); | ||||
| 
 | ||||
|   translation_key.time = 1.f; | ||||
|   translation_key.value = ozz::math::Float3(0.f, 1.f, 0.f); | ||||
|   bone0_translations.push_back(translation_key); | ||||
| 
 | ||||
|   bone0_track.translations = bone0_translations; | ||||
|   raw_animation_translation_y.tracks.push_back(bone0_track); | ||||
|   raw_animation_translation_y.duration = 1.f; | ||||
|   if (!raw_animation_translation_y.Validate()) { | ||||
|     std::cerr << "Error: could animation raw data invalid!" << std::endl; | ||||
|   } | ||||
| 
 | ||||
|   animation_translate_y = animation_builder(raw_animation_translation_y); | ||||
| 
 | ||||
|   animation_translate_y_resource.m_animation = animation_translate_y.get(); | ||||
|   SaveAnimation("single_bone_translation_y.ozz", animation_translate_y.get()); | ||||
|   animation_translate_y_resource.m_name = "single_bone_translation_y"; | ||||
|   animation_translate_y_resource.m_filename = "single_bone_translation_y.ozz"; | ||||
| } | ||||
| 
 | ||||
| bool SingleBoneSkeleton::SaveSkeleton( | ||||
|     const char* filename, | ||||
|     ozz::animation::Skeleton* skeleton) { | ||||
|   assert(false); | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| bool SingleBoneSkeleton::SaveAnimation( | ||||
|     const char* filename, | ||||
|     ozz::animation::Animation* animation) { | ||||
|   ozz::io::File file(filename, "wb"); | ||||
|   if (!file.opened()) { | ||||
|     ozz::log::Err() << "Failed to create animation file " << filename << "." | ||||
|                     << std::endl; | ||||
|     delete animation; | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   ozz::io::OArchive archive(&file); | ||||
| 
 | ||||
|   archive << *animation; | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| }  // namespace TestAnimData
 | ||||
							
								
								
									
										37
									
								
								tests/TestAnimData.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								tests/TestAnimData.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| //
 | ||||
| // Created by martin on 11.04.25.
 | ||||
| //
 | ||||
| 
 | ||||
| #ifndef TESTANIMDATA_H | ||||
| #define TESTANIMDATA_H | ||||
| 
 | ||||
| #include "AnimGraph/AnimGraphData.h" | ||||
| #include "AnimGraph/SyncTrack.h" | ||||
| #include "ozz/animation/offline/skeleton_builder.h" | ||||
| #include "ozz/animation/runtime/animation.h" | ||||
| #include "ozz/animation/runtime/skeleton.h" | ||||
| 
 | ||||
| namespace TestAnimData { | ||||
| 
 | ||||
| struct SingleBoneSkeleton { | ||||
|   SingleBoneSkeleton(); | ||||
| 
 | ||||
|   ozz::unique_ptr<ozz::animation::Skeleton> skeleton = nullptr; | ||||
| 
 | ||||
|   ozz::unique_ptr<ozz::animation::Animation> animation_translate_x = nullptr; | ||||
|   AnimationResource animation_translate_x_resource; | ||||
|   SyncTrack animation_translate_x_sync_track = {}; | ||||
| 
 | ||||
|   ozz::unique_ptr<ozz::animation::Animation> animation_translate_y = nullptr; | ||||
|   AnimationResource animation_translate_y_resource; | ||||
|   SyncTrack animation_translate_y_sync_track = {}; | ||||
| 
 | ||||
|   bool SaveSkeleton(const char* filename, ozz::animation::Skeleton* skeleton); | ||||
|   bool SaveAnimation( | ||||
|       const char* filename, | ||||
|       ozz::animation::Animation* animation); | ||||
| }; | ||||
| 
 | ||||
| }  // namespace TestAnimData
 | ||||
| 
 | ||||
| #endif  //TESTANIMDATA_H
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Martin Felis
						Martin Felis