| 1 | /**************************************************************************/ |
| 2 | /* post_import_plugin_skeleton_track_organizer.cpp */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #include "post_import_plugin_skeleton_track_organizer.h" |
| 32 | |
| 33 | #include "editor/import/scene_import_settings.h" |
| 34 | #include "scene/3d/skeleton_3d.h" |
| 35 | #include "scene/animation/animation_player.h" |
| 36 | #include "scene/resources/bone_map.h" |
| 37 | |
| 38 | void PostImportPluginSkeletonTrackOrganizer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) { |
| 39 | if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) { |
| 40 | r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/except_bone_transform" ), false)); |
| 41 | r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/unimportant_positions" ), true)); |
| 42 | r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/unmapped_bones" ), false)); |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) { |
| 47 | if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) { |
| 48 | // Prepare objects. |
| 49 | Object *map = p_options["retarget/bone_map" ].get_validated_object(); |
| 50 | if (!map) { |
| 51 | return; |
| 52 | } |
| 53 | BoneMap *bone_map = Object::cast_to<BoneMap>(map); |
| 54 | Ref<SkeletonProfile> profile = bone_map->get_profile(); |
| 55 | if (!profile.is_valid()) { |
| 56 | return; |
| 57 | } |
| 58 | Skeleton3D *src_skeleton = Object::cast_to<Skeleton3D>(p_node); |
| 59 | if (!src_skeleton) { |
| 60 | return; |
| 61 | } |
| 62 | bool remove_except_bone = bool(p_options["retarget/remove_tracks/except_bone_transform" ]); |
| 63 | bool remove_positions = bool(p_options["retarget/remove_tracks/unimportant_positions" ]); |
| 64 | bool remove_unmapped_bones = bool(p_options["retarget/remove_tracks/unmapped_bones" ]); |
| 65 | |
| 66 | if (!remove_positions && !remove_unmapped_bones) { |
| 67 | return; |
| 68 | } |
| 69 | |
| 70 | TypedArray<Node> nodes = p_base_scene->find_children("*" , "AnimationPlayer" ); |
| 71 | while (nodes.size()) { |
| 72 | AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back()); |
| 73 | List<StringName> anims; |
| 74 | ap->get_animation_list(&anims); |
| 75 | for (const StringName &name : anims) { |
| 76 | Ref<Animation> anim = ap->get_animation(name); |
| 77 | int track_len = anim->get_track_count(); |
| 78 | Vector<int> remove_indices; |
| 79 | for (int i = 0; i < track_len; i++) { |
| 80 | String track_path = String(anim->track_get_path(i).get_concatenated_names()); |
| 81 | Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); |
| 82 | if (!node) { |
| 83 | if (remove_except_bone) { |
| 84 | remove_indices.push_back(i); |
| 85 | } |
| 86 | continue; |
| 87 | } |
| 88 | Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node); |
| 89 | if (track_skeleton && track_skeleton == src_skeleton) { |
| 90 | if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) { |
| 91 | if (remove_except_bone) { |
| 92 | remove_indices.push_back(i); |
| 93 | } |
| 94 | continue; |
| 95 | } |
| 96 | StringName bn = anim->track_get_path(i).get_subname(0); |
| 97 | if (bn) { |
| 98 | int prof_idx = profile->find_bone(bone_map->find_profile_bone_name(bn)); |
| 99 | if (remove_unmapped_bones && prof_idx < 0) { |
| 100 | remove_indices.push_back(i); |
| 101 | continue; |
| 102 | } |
| 103 | if (remove_positions && anim->track_get_type(i) == Animation::TYPE_POSITION_3D && prof_idx >= 0) { |
| 104 | StringName prof_bn = profile->get_bone_name(prof_idx); |
| 105 | if (prof_bn == profile->get_root_bone() || prof_bn == profile->get_scale_base_bone()) { |
| 106 | continue; |
| 107 | } |
| 108 | remove_indices.push_back(i); |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | if (remove_except_bone) { |
| 113 | remove_indices.push_back(i); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | remove_indices.reverse(); |
| 118 | for (int i = 0; i < remove_indices.size(); i++) { |
| 119 | anim->remove_track(remove_indices[i]); |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | PostImportPluginSkeletonTrackOrganizer::PostImportPluginSkeletonTrackOrganizer() { |
| 127 | } |
| 128 | |