1 | /**************************************************************************/ |
2 | /* bone_map.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 "bone_map.h" |
32 | |
33 | bool BoneMap::_set(const StringName &p_path, const Variant &p_value) { |
34 | String path = p_path; |
35 | if (path.begins_with("bone_map/" )) { |
36 | String which = path.get_slicec('/', 1); |
37 | set_skeleton_bone_name(which, p_value); |
38 | return true; |
39 | } |
40 | return true; |
41 | } |
42 | |
43 | bool BoneMap::_get(const StringName &p_path, Variant &r_ret) const { |
44 | String path = p_path; |
45 | if (path.begins_with("bone_map/" )) { |
46 | String which = path.get_slicec('/', 1); |
47 | r_ret = get_skeleton_bone_name(which); |
48 | return true; |
49 | } |
50 | return true; |
51 | } |
52 | |
53 | void BoneMap::_get_property_list(List<PropertyInfo> *p_list) const { |
54 | HashMap<StringName, StringName>::ConstIterator E = bone_map.begin(); |
55 | while (E) { |
56 | p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bone_map/" + E->key, PROPERTY_HINT_NONE, "" , PROPERTY_USAGE_NO_EDITOR)); |
57 | ++E; |
58 | } |
59 | } |
60 | |
61 | Ref<SkeletonProfile> BoneMap::get_profile() const { |
62 | return profile; |
63 | } |
64 | |
65 | void BoneMap::set_profile(const Ref<SkeletonProfile> &p_profile) { |
66 | bool is_changed = profile != p_profile; |
67 | if (is_changed) { |
68 | if (!profile.is_null() && profile->is_connected("profile_updated" , callable_mp(this, &BoneMap::_update_profile))) { |
69 | profile->disconnect("profile_updated" , callable_mp(this, &BoneMap::_update_profile)); |
70 | } |
71 | profile = p_profile; |
72 | if (!profile.is_null()) { |
73 | profile->connect("profile_updated" , callable_mp(this, &BoneMap::_update_profile)); |
74 | } |
75 | _update_profile(); |
76 | } |
77 | notify_property_list_changed(); |
78 | } |
79 | |
80 | StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const { |
81 | ERR_FAIL_COND_V(!bone_map.has(p_profile_bone_name), StringName()); |
82 | return bone_map.get(p_profile_bone_name); |
83 | } |
84 | |
85 | void BoneMap::_set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) { |
86 | ERR_FAIL_COND(!bone_map.has(p_profile_bone_name)); |
87 | bone_map.insert(p_profile_bone_name, p_skeleton_bone_name); |
88 | } |
89 | |
90 | void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) { |
91 | _set_skeleton_bone_name(p_profile_bone_name, p_skeleton_bone_name); |
92 | emit_signal("bone_map_updated" ); |
93 | } |
94 | |
95 | StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) const { |
96 | StringName profile_bone_name; |
97 | HashMap<StringName, StringName>::ConstIterator E = bone_map.begin(); |
98 | while (E) { |
99 | if (E->value == p_skeleton_bone_name) { |
100 | profile_bone_name = E->key; |
101 | break; |
102 | } |
103 | ++E; |
104 | } |
105 | return profile_bone_name; |
106 | } |
107 | |
108 | int BoneMap::get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const { |
109 | int count = 0; |
110 | HashMap<StringName, StringName>::ConstIterator E = bone_map.begin(); |
111 | while (E) { |
112 | if (E->value == p_skeleton_bone_name) { |
113 | ++count; |
114 | } |
115 | ++E; |
116 | } |
117 | return count; |
118 | } |
119 | |
120 | void BoneMap::_update_profile() { |
121 | _validate_bone_map(); |
122 | emit_signal("profile_updated" ); |
123 | } |
124 | |
125 | void BoneMap::_validate_bone_map() { |
126 | Ref<SkeletonProfile> current_profile = get_profile(); |
127 | if (current_profile.is_valid()) { |
128 | // Insert missing profile bones into bone map. |
129 | int len = current_profile->get_bone_size(); |
130 | StringName profile_bone_name; |
131 | for (int i = 0; i < len; i++) { |
132 | profile_bone_name = current_profile->get_bone_name(i); |
133 | if (!bone_map.has(profile_bone_name)) { |
134 | bone_map.insert(profile_bone_name, StringName()); |
135 | } |
136 | } |
137 | // Remove bones that do not exist in the profile from the map. |
138 | Vector<StringName> delete_bones; |
139 | StringName k; |
140 | HashMap<StringName, StringName>::ConstIterator E = bone_map.begin(); |
141 | while (E) { |
142 | k = E->key; |
143 | if (!current_profile->has_bone(k)) { |
144 | delete_bones.push_back(k); |
145 | } |
146 | ++E; |
147 | } |
148 | len = delete_bones.size(); |
149 | for (int i = 0; i < len; i++) { |
150 | bone_map.erase(delete_bones[i]); |
151 | } |
152 | } else { |
153 | bone_map.clear(); |
154 | } |
155 | } |
156 | |
157 | void BoneMap::_bind_methods() { |
158 | ClassDB::bind_method(D_METHOD("get_profile" ), &BoneMap::get_profile); |
159 | ClassDB::bind_method(D_METHOD("set_profile" , "profile" ), &BoneMap::set_profile); |
160 | |
161 | ClassDB::bind_method(D_METHOD("get_skeleton_bone_name" , "profile_bone_name" ), &BoneMap::get_skeleton_bone_name); |
162 | ClassDB::bind_method(D_METHOD("set_skeleton_bone_name" , "profile_bone_name" , "skeleton_bone_name" ), &BoneMap::set_skeleton_bone_name); |
163 | |
164 | ClassDB::bind_method(D_METHOD("find_profile_bone_name" , "skeleton_bone_name" ), &BoneMap::find_profile_bone_name); |
165 | |
166 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "profile" , PROPERTY_HINT_RESOURCE_TYPE, "SkeletonProfile" ), "set_profile" , "get_profile" ); |
167 | ADD_ARRAY("bonemap" , "bonemap" ); |
168 | |
169 | ADD_SIGNAL(MethodInfo("bone_map_updated" )); |
170 | ADD_SIGNAL(MethodInfo("profile_updated" )); |
171 | } |
172 | |
173 | void BoneMap::_validate_property(PropertyInfo &property) const { |
174 | if (property.name == "bonemap" || property.name == "profile" ) { |
175 | property.usage = PROPERTY_USAGE_NO_EDITOR; |
176 | } |
177 | } |
178 | |
179 | BoneMap::BoneMap() { |
180 | _validate_bone_map(); |
181 | } |
182 | |
183 | BoneMap::~BoneMap() { |
184 | } |
185 | |
186 | ////////////////////////////////////// |
187 | |