Panda3D
 All Classes Functions Variables Enumerations
auto_bind.cxx
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 
 All Classes Functions Variables Enumerations