mesh_animation.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "resource/mesh_animation.h"
  6. #if CROWN_CAN_COMPILE
  7. # include "core/error/error.inl"
  8. # include "core/json/json_object.inl"
  9. # include "core/json/sjson.h"
  10. # include "core/memory/temp_allocator.inl"
  11. # include "core/strings/dynamic_string.inl"
  12. # include "core/strings/string_id.inl"
  13. # include "device/log.h"
  14. # include "resource/compile_options.inl"
  15. # include "resource/mesh_animation_fbx.h"
  16. # include "resource/mesh_skeleton.h"
  17. # include <algorithm> // std::sort
  18. #define DUMP_KEYS 0
  19. LOG_SYSTEM(MESH_ANIMATION, "mesh_animation")
  20. namespace crown
  21. {
  22. namespace mesh_animation
  23. {
  24. #if DUMP_KEYS
  25. static void dump_keys(AnimationKey *begin, AnimationKey *end)
  26. {
  27. char buf[256];
  28. for (auto cur = begin; cur != end; ++cur)
  29. logi(MESH_ANIMATION, "b %hu t %hu type %hu val %s"
  30. , cur->h.track_id
  31. , cur->h.time
  32. , cur->h.type
  33. , cur->h.type == 0
  34. ? to_string(buf, sizeof(buf), cur->p.value)
  35. : to_string(buf, sizeof(buf), cur->r.value)
  36. );
  37. }
  38. #endif
  39. u16 track_id(MeshAnimation &a, u16 bone_id, u16 parameter_type)
  40. {
  41. CE_ENSURE(bone_id < MESH_SKELETON_MAX_BONES);
  42. CE_ENSURE(parameter_type < AnimationKeyHeader::Type::COUNT);
  43. u16 t = (bone_id << 2) | u16(parameter_type);
  44. u16 track_id_not_found = UINT16_MAX;
  45. u16 track_id = hash_map::get(a.track_ids, t, track_id_not_found);
  46. if (track_id == track_id_not_found) {
  47. track_id = array::size(a.bone_ids);
  48. array::push_back(a.bone_ids, bone_id);
  49. hash_map::set(a.track_ids, t, track_id);
  50. }
  51. return track_id;
  52. }
  53. static s32 generate_sorted_keys(MeshAnimation &ma)
  54. {
  55. #if 0
  56. // Test data.
  57. array::clear(ma.keys);
  58. array::clear(ma.indices);
  59. array::push_back(ma.indices, { { 0, 0, 0 }, array::size(ma.keys), 2 });
  60. array::push_back(ma.keys, { { 0, 0, 0 } });
  61. array::push_back(ma.keys, { { 0, 0, 10 } });
  62. array::push_back(ma.indices, { { 0, 1, 0 }, array::size(ma.keys), 4 });
  63. array::push_back(ma.keys, { { 0, 1, 0 } });
  64. array::push_back(ma.keys, { { 0, 1, 1 } });
  65. array::push_back(ma.keys, { { 0, 1, 5 } });
  66. array::push_back(ma.keys, { { 0, 1, 10 } });
  67. array::push_back(ma.indices, { { 0, 2, 0 }, array::size(ma.keys), 4 });
  68. array::push_back(ma.keys, { { 0, 2, 0 } });
  69. array::push_back(ma.keys, { { 0, 2, 6 } });
  70. array::push_back(ma.keys, { { 0, 2, 8 } });
  71. array::push_back(ma.keys, { { 0, 2, 10 } });
  72. #endif // if 0
  73. // Sort indices by track ID. This ensures that when we encounter multiple keys
  74. // with matching times, we choose the key with the smallest track ID first.
  75. std::sort(array::begin(ma.indices)
  76. , array::end(ma.indices)
  77. , [](const AnimationKeyIndex &a, const AnimationKeyIndex &b) {
  78. return a.h.track_id < b.h.track_id;
  79. });
  80. // Generate a list of animation keys sorted by key access time.
  81. // Start by getting the first two keys for each track.
  82. for (u32 i = 0; i < array::size(ma.indices); ++i) {
  83. AnimationKeyIndex &idx = ma.indices[i];
  84. array::push_back(ma.sorted_keys, ma.keys[idx.offset + idx.cur++]);
  85. array::push_back(ma.sorted_keys, ma.keys[idx.offset + idx.cur++]);
  86. }
  87. while (array::size(ma.sorted_keys) != array::size(ma.keys)) {
  88. AnimationKeyIndex *next_key = NULL;
  89. // For each track, choose the key that will be needed next.
  90. for (u32 i = 0; i < array::size(ma.indices); ++i) {
  91. AnimationKeyIndex &idx = ma.indices[i];
  92. // There are no more keys in this track. Skip it.
  93. if (idx.cur > idx.num - 1)
  94. continue;
  95. // Select this as the next key if none have been selected so far.
  96. if (next_key == NULL) {
  97. next_key = &idx;
  98. continue;
  99. } else {
  100. // If next key's previous time is greater than current
  101. // key's previous time, then we need to get this key next.
  102. auto next_prev_time = ma.keys[next_key->offset + next_key->cur - 1].h.time;
  103. auto this_prev_time = ma.keys[idx.offset + idx.cur - 1].h.time;
  104. if (next_prev_time > this_prev_time)
  105. next_key = &idx;
  106. }
  107. }
  108. CE_ENSURE(next_key != NULL);
  109. array::push_back(ma.sorted_keys, ma.keys[next_key->offset + next_key->cur]);
  110. ++next_key->cur;
  111. }
  112. #if DUMP_KEYS
  113. dump_keys(array::begin(ma.sorted_keys), array::end(ma.sorted_keys));
  114. #endif
  115. return 0;
  116. }
  117. s32 parse(MeshAnimation &ma, Buffer &buf, CompileOptions &opts)
  118. {
  119. TempAllocator4096 ta;
  120. JsonObject obj(ta);
  121. RETURN_IF_ERROR(sjson::parse(obj, buf), opts);
  122. // Parse skeleton.
  123. DynamicString target_skeleton(ta);
  124. RETURN_IF_ERROR(sjson::parse_string(target_skeleton, obj["target_skeleton"]), opts);
  125. RETURN_IF_RESOURCE_MISSING("mesh_skeleton", target_skeleton.c_str(), opts);
  126. opts.add_requirement("mesh_skeleton", target_skeleton.c_str());
  127. ma.target_skeleton = RETURN_IF_ERROR(sjson::parse_resource_name(obj["target_skeleton"]), opts);
  128. // Parse animations.
  129. RETURN_IF_ERROR(sjson::parse_string(ma.stack_name, obj["stack_name"]), opts);
  130. DynamicString source(ta);
  131. if (json_object::has(obj, "source")) {
  132. RETURN_IF_ERROR(sjson::parse_string(source, obj["source"]), opts);
  133. RETURN_IF_FILE_MISSING(source.c_str(), opts);
  134. Buffer fbx_buf = opts.read(source.c_str());
  135. s32 err = fbx::parse(ma, fbx_buf, opts);
  136. ENSURE_OR_RETURN(err == 0, opts);
  137. } else {
  138. RETURN_IF_FALSE(false
  139. , opts
  140. , "Unknown source mesh '%s'"
  141. , source.c_str()
  142. );
  143. }
  144. return generate_sorted_keys(ma);
  145. }
  146. } // namespace mesh_animation
  147. MeshAnimation::MeshAnimation(Allocator &a)
  148. : sorted_keys(a)
  149. , keys(a)
  150. , indices(a)
  151. , num_bones(0u)
  152. , total_time(0.0f)
  153. , target_skeleton(u64(0u))
  154. , stack_name(a)
  155. , track_ids(a)
  156. , bone_ids(a)
  157. {
  158. }
  159. } // namespace crown
  160. #endif // if CROWN_CAN_COMPILE