Panda3D
|
00001 // Filename: auto_bind.cxx 00002 // Created by: drose (23Feb99) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 00016 #include "auto_bind.h" 00017 #include "animBundleNode.h" 00018 #include "partBundleNode.h" 00019 #include "config_chan.h" 00020 #include "string_utils.h" 00021 #include "partGroup.h" 00022 00023 typedef pset<AnimBundle *> AnimBundles; 00024 typedef pmap<string, AnimBundles> Anims; 00025 00026 typedef pset<PartBundle *> PartBundles; 00027 typedef pmap<string, PartBundles> Parts; 00028 00029 00030 //////////////////////////////////////////////////////////////////// 00031 // Function: bind_anims 00032 // Description: A support function for auto_bind(), below. Given a 00033 // set of AnimBundles and a set of PartBundles that all 00034 // share the same name, perform whatever bindings make 00035 // sense. 00036 //////////////////////////////////////////////////////////////////// 00037 static void 00038 bind_anims(const PartBundles &parts, const AnimBundles &anims, 00039 AnimControlCollection &controls, 00040 int hierarchy_match_flags) { 00041 PartBundles::const_iterator pbi; 00042 00043 for (pbi = parts.begin(); pbi != parts.end(); ++pbi) { 00044 PartBundle *part = (*pbi); 00045 AnimBundles::const_iterator abi; 00046 for (abi = anims.begin(); abi != anims.end(); ++abi) { 00047 AnimBundle *anim = (*abi); 00048 if (chan_cat.is_info()) { 00049 chan_cat.info() 00050 << "Attempting to bind " << *part << " to " << *anim << "\n"; 00051 } 00052 00053 PT(AnimControl) control = 00054 part->bind_anim(anim, hierarchy_match_flags); 00055 string name = (*abi)->get_name(); 00056 if (name.empty()) { 00057 name = anim->get_name(); 00058 } 00059 if (control != (AnimControl *)NULL) { 00060 if (controls.find_anim(name) != (AnimControl *)NULL) { 00061 // That name's already used; synthesize another one. 00062 int index = 0; 00063 string new_name; 00064 do { 00065 index++; 00066 new_name = name + '.' + format_string(index); 00067 } while (controls.find_anim(new_name) != (AnimControl *)NULL); 00068 name = new_name; 00069 } 00070 00071 controls.store_anim(control, name); 00072 } 00073 00074 if (chan_cat.is_info()) { 00075 if (control == (AnimControl *)NULL) { 00076 chan_cat.info() 00077 << "Bind failed.\n"; 00078 } else { 00079 chan_cat.info() 00080 << "Bind succeeded, index " 00081 << control->get_channel_index() << "; accessible as " 00082 << name << "\n"; 00083 } 00084 } 00085 } 00086 } 00087 } 00088 00089 //////////////////////////////////////////////////////////////////// 00090 // Function: r_find_bundles 00091 // Description: A support function for auto_bind(), below. Walks 00092 // through the hierarchy and finds all of the 00093 // PartBundles and AnimBundles. 00094 //////////////////////////////////////////////////////////////////// 00095 static void 00096 r_find_bundles(PandaNode *node, Anims &anims, Parts &parts) { 00097 if (node->is_of_type(AnimBundleNode::get_class_type())) { 00098 AnimBundleNode *bn = DCAST(AnimBundleNode, node); 00099 AnimBundle *bundle = bn->get_bundle(); 00100 anims[bundle->get_name()].insert(bundle); 00101 00102 } else if (node->is_of_type(PartBundleNode::get_class_type())) { 00103 PartBundleNode *bn = DCAST(PartBundleNode, node); 00104 int num_bundles = bn->get_num_bundles(); 00105 for (int i = 0; i < num_bundles; ++i) { 00106 PartBundle *bundle = bn->get_bundle(i); 00107 parts[bundle->get_name()].insert(bundle); 00108 } 00109 } 00110 00111 PandaNode::Children cr = node->get_children(); 00112 int num_children = cr.get_num_children(); 00113 for (int i = 0; i < num_children; i++) { 00114 r_find_bundles(cr.get_child(i), anims, parts); 00115 } 00116 } 00117 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: auto_bind 00121 // Description: Walks the scene graph or subgraph beginning at the 00122 // indicated node, and attempts to bind any AnimBundles 00123 // found to their matching PartBundles, when possible. 00124 // 00125 // The list of all resulting AnimControls created is 00126 // filled into controls. 00127 //////////////////////////////////////////////////////////////////// 00128 void 00129 auto_bind(PandaNode *root_node, AnimControlCollection &controls, 00130 int hierarchy_match_flags) { 00131 // First, locate all the bundles in the subgraph. 00132 Anims anims; 00133 AnimBundles extra_anims; 00134 Parts parts; 00135 PartBundles extra_parts; 00136 r_find_bundles(root_node, anims, parts); 00137 00138 if (chan_cat.is_debug()) { 00139 int anim_count = 0; 00140 Anims::const_iterator ai; 00141 for (ai = anims.begin(); ai != anims.end(); ++ai) { 00142 anim_count += (int)(*ai).second.size(); 00143 } 00144 chan_cat.debug() 00145 << "Found " << anim_count << " anims:\n"; 00146 for (ai = anims.begin(); ai != anims.end(); ++ai) { 00147 chan_cat.debug(false) 00148 << " " << (*ai).first; 00149 if ((*ai).second.size() != 1) { 00150 chan_cat.debug(false) 00151 << "*" << ((*ai).second.size()); 00152 } 00153 } 00154 chan_cat.debug(false) 00155 << "\n"; 00156 00157 int part_count = 0; 00158 Parts::const_iterator pi; 00159 for (pi = parts.begin(); pi != parts.end(); ++pi) { 00160 part_count += (int)(*pi).second.size(); 00161 } 00162 chan_cat.debug() 00163 << "Found " << part_count << " parts:\n"; 00164 for (pi = parts.begin(); pi != parts.end(); ++pi) { 00165 chan_cat.debug(false) 00166 << " " << (*pi).first; 00167 if ((*pi).second.size() != 1) { 00168 chan_cat.debug(false) 00169 << "*" << ((*pi).second.size()); 00170 } 00171 } 00172 chan_cat.debug(false) 00173 << "\n"; 00174 } 00175 00176 // Now, match up the bundles by name. 00177 00178 Anims::const_iterator ai = anims.begin(); 00179 Parts::const_iterator pi = parts.begin(); 00180 00181 while (ai != anims.end() && pi != parts.end()) { 00182 if ((*ai).first < (*pi).first) { 00183 // Here's an anim with no matching parts. 00184 if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) { 00185 AnimBundles::const_iterator abi; 00186 for (abi = (*ai).second.begin(); abi != (*ai).second.end(); ++abi) { 00187 extra_anims.insert(*abi); 00188 } 00189 } 00190 ++ai; 00191 00192 } else if ((*pi).first < (*ai).first) { 00193 // And here's a part with no matching anims. 00194 if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) { 00195 PartBundles::const_iterator pbi; 00196 for (pbi = (*pi).second.begin(); pbi != (*pi).second.end(); ++pbi) { 00197 extra_parts.insert(*pbi); 00198 } 00199 } 00200 ++pi; 00201 00202 } else { 00203 // But here we have (at least one) match! 00204 bind_anims((*pi).second, (*ai).second, controls, 00205 hierarchy_match_flags); 00206 ++pi; 00207 00208 // We don't increment the anim counter yet. That way, the same 00209 // anim may bind to multiple parts, if they all share the same 00210 // name. 00211 } 00212 } 00213 00214 if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) { 00215 // Continue searching through the remaining anims and parts. 00216 00217 while (ai != anims.end()) { 00218 // Here's an anim with no matching parts. 00219 if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) { 00220 AnimBundles::const_iterator abi; 00221 for (abi = (*ai).second.begin(); abi != (*ai).second.end(); ++abi) { 00222 extra_anims.insert(*abi); 00223 } 00224 } 00225 ++ai; 00226 } 00227 00228 while (pi != parts.end()) { 00229 // And here's a part with no matching anims. 00230 if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) { 00231 PartBundles::const_iterator pbi; 00232 for (pbi = (*pi).second.begin(); pbi != (*pi).second.end(); ++pbi) { 00233 extra_parts.insert(*pbi); 00234 } 00235 } 00236 ++pi; 00237 } 00238 00239 bind_anims(extra_parts, extra_anims, controls, 00240 hierarchy_match_flags); 00241 } 00242 } 00243 00244