| 1033 | } |
| 1034 | |
| 1035 | void load_all_animations(entt::registry & registry, const std::vector<entt::entity> & node_entities) |
| 1036 | { |
| 1037 | std::vector<entt::entity> entities{gltf.animations.size()}; |
| 1038 | registry.create(entities.begin(), entities.end()); |
| 1039 | |
| 1040 | // Create all animation components first |
| 1041 | registry.insert<components::animation>(entities.begin(), entities.end()); |
| 1042 | |
| 1043 | for (const auto & [entity, gltf_animation]: std::ranges::zip_view(entities, gltf.animations)) |
| 1044 | { |
| 1045 | auto & animation = registry.get<components::animation>(entity); |
| 1046 | animation.name = gltf_animation.name; |
| 1047 | animation.tracks.reserve(gltf_animation.channels.size()); |
| 1048 | |
| 1049 | for (const auto & channel: gltf_animation.channels) |
| 1050 | { |
| 1051 | if (not channel.nodeIndex.has_value() or *channel.nodeIndex > node_entities.size()) |
| 1052 | // Ignore this channel |
| 1053 | continue; |
| 1054 | |
| 1055 | const auto & sampler = gltf_animation.samplers.at(channel.samplerIndex); |
| 1056 | const auto & time = gltf.accessors.at(sampler.inputAccessor); |
| 1057 | const auto & value = gltf.accessors.at(sampler.outputAccessor); |
| 1058 | const auto interpolation = convert(sampler.interpolation); |
| 1059 | |
| 1060 | switch (interpolation) |
| 1061 | { |
| 1062 | case components::animation_track_base::interpolation_t::step: |
| 1063 | case components::animation_track_base::interpolation_t::linear: |
| 1064 | if (time.count != value.count) |
| 1065 | // There must be the same number of elements |
| 1066 | continue; |
| 1067 | break; |
| 1068 | |
| 1069 | case components::animation_track_base::interpolation_t::cubic_spline: |
| 1070 | // TODO: does not work for morph targets |
| 1071 | if (3 * time.count != value.count or time.count < 2) |
| 1072 | continue; |
| 1073 | break; |
| 1074 | } |
| 1075 | |
| 1076 | size_t count = time.count; |
| 1077 | switch (channel.path) |
| 1078 | { |
| 1079 | // TODO: templatize the switch |
| 1080 | case fastgltf::AnimationPath::Translation: { |
| 1081 | components::animation_track_position track; |
| 1082 | track.target = node_entities.at(*channel.nodeIndex); |
| 1083 | track.interpolation = interpolation; |
| 1084 | track.timestamp.resize(time.count); |
| 1085 | track.value.resize(value.count); |
| 1086 | |
| 1087 | fastgltf::iterateAccessorWithIndex<float>(gltf, time, [&](float t, size_t index) { |
| 1088 | track.timestamp[index] = t; |
| 1089 | animation.duration = std::max(animation.duration, t); |
| 1090 | }); |
| 1091 | |
| 1092 | fastgltf::iterateAccessorWithIndex<glm::vec3>(gltf, value, [&](glm::vec3 value, size_t index) { |