Panda3D
auto_bind.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file auto_bind.cxx
10  * @author drose
11  * @date 1999-02-23
12  */
13 
14 #include "auto_bind.h"
15 #include "animBundleNode.h"
16 #include "partBundleNode.h"
17 #include "config_chan.h"
18 #include "string_utils.h"
19 #include "partGroup.h"
20 
21 using std::string;
22 
25 
28 
29 
30 /**
31  * A support function for auto_bind(), below. Given a set of AnimBundles and
32  * a set of PartBundles that all share the same name, perform whatever
33  * bindings make sense.
34  */
35 static void
36 bind_anims(const PartBundles &parts, const AnimBundles &anims,
37  AnimControlCollection &controls,
38  int hierarchy_match_flags) {
39  PartBundles::const_iterator pbi;
40 
41  for (pbi = parts.begin(); pbi != parts.end(); ++pbi) {
42  PartBundle *part = (*pbi);
43  AnimBundles::const_iterator abi;
44  for (abi = anims.begin(); abi != anims.end(); ++abi) {
45  AnimBundle *anim = (*abi);
46  if (chan_cat.is_info()) {
47  chan_cat.info()
48  << "Attempting to bind " << *part << " to " << *anim << "\n";
49  }
50 
51  PT(AnimControl) control =
52  part->bind_anim(anim, hierarchy_match_flags);
53  string name = (*abi)->get_name();
54  if (name.empty()) {
55  name = anim->get_name();
56  }
57  if (control != nullptr) {
58  if (controls.find_anim(name) != nullptr) {
59  // That name's already used; synthesize another one.
60  int index = 0;
61  string new_name;
62  do {
63  index++;
64  new_name = name + '.' + format_string(index);
65  } while (controls.find_anim(new_name) != nullptr);
66  name = new_name;
67  }
68 
69  controls.store_anim(control, name);
70  }
71 
72  if (chan_cat.is_info()) {
73  if (control == nullptr) {
74  chan_cat.info()
75  << "Bind failed.\n";
76  } else {
77  chan_cat.info()
78  << "Bind succeeded, index "
79  << control->get_channel_index() << "; accessible as "
80  << name << "\n";
81  }
82  }
83  }
84  }
85 }
86 
87 /**
88  * A support function for auto_bind(), below. Walks through the hierarchy and
89  * finds all of the PartBundles and AnimBundles.
90  */
91 static void
92 r_find_bundles(PandaNode *node, Anims &anims, Parts &parts) {
93  if (node->is_of_type(AnimBundleNode::get_class_type())) {
94  AnimBundleNode *bn = DCAST(AnimBundleNode, node);
95  AnimBundle *bundle = bn->get_bundle();
96  anims[bundle->get_name()].insert(bundle);
97 
98  } else if (node->is_of_type(PartBundleNode::get_class_type())) {
99  PartBundleNode *bn = DCAST(PartBundleNode, node);
100  int num_bundles = bn->get_num_bundles();
101  for (int i = 0; i < num_bundles; ++i) {
102  PartBundle *bundle = bn->get_bundle(i);
103  parts[bundle->get_name()].insert(bundle);
104  }
105  }
106 
107  PandaNode::Children cr = node->get_children();
108  int num_children = cr.get_num_children();
109  for (int i = 0; i < num_children; i++) {
110  r_find_bundles(cr.get_child(i), anims, parts);
111  }
112 }
113 
114 
115 /**
116  * Walks the scene graph or subgraph beginning at the indicated node, and
117  * attempts to bind any AnimBundles found to their matching PartBundles, when
118  * possible.
119  *
120  * The list of all resulting AnimControls created is filled into controls.
121  */
122 void
124  int hierarchy_match_flags) {
125  // First, locate all the bundles in the subgraph.
126  Anims anims;
127  AnimBundles extra_anims;
128  Parts parts;
129  PartBundles extra_parts;
130  r_find_bundles(root_node, anims, parts);
131 
132  if (chan_cat.is_debug()) {
133  int anim_count = 0;
134  Anims::const_iterator ai;
135  for (ai = anims.begin(); ai != anims.end(); ++ai) {
136  anim_count += (int)(*ai).second.size();
137  }
138  chan_cat.debug()
139  << "Found " << anim_count << " anims:\n";
140  for (ai = anims.begin(); ai != anims.end(); ++ai) {
141  chan_cat.debug(false)
142  << " " << (*ai).first;
143  if ((*ai).second.size() != 1) {
144  chan_cat.debug(false)
145  << "*" << ((*ai).second.size());
146  }
147  }
148  chan_cat.debug(false)
149  << "\n";
150 
151  int part_count = 0;
152  Parts::const_iterator pi;
153  for (pi = parts.begin(); pi != parts.end(); ++pi) {
154  part_count += (int)(*pi).second.size();
155  }
156  chan_cat.debug()
157  << "Found " << part_count << " parts:\n";
158  for (pi = parts.begin(); pi != parts.end(); ++pi) {
159  chan_cat.debug(false)
160  << " " << (*pi).first;
161  if ((*pi).second.size() != 1) {
162  chan_cat.debug(false)
163  << "*" << ((*pi).second.size());
164  }
165  }
166  chan_cat.debug(false)
167  << "\n";
168  }
169 
170  // Now, match up the bundles by name.
171 
172  Anims::const_iterator ai = anims.begin();
173  Parts::const_iterator pi = parts.begin();
174 
175  while (ai != anims.end() && pi != parts.end()) {
176  if ((*ai).first < (*pi).first) {
177  // Here's an anim with no matching parts.
178  if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) {
179  AnimBundles::const_iterator abi;
180  for (abi = (*ai).second.begin(); abi != (*ai).second.end(); ++abi) {
181  extra_anims.insert(*abi);
182  }
183  }
184  ++ai;
185 
186  } else if ((*pi).first < (*ai).first) {
187  // And here's a part with no matching anims.
188  if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) {
189  PartBundles::const_iterator pbi;
190  for (pbi = (*pi).second.begin(); pbi != (*pi).second.end(); ++pbi) {
191  extra_parts.insert(*pbi);
192  }
193  }
194  ++pi;
195 
196  } else {
197  // But here we have (at least one) match!
198  bind_anims((*pi).second, (*ai).second, controls,
199  hierarchy_match_flags);
200  ++pi;
201 
202  // We don't increment the anim counter yet. That way, the same anim may
203  // bind to multiple parts, if they all share the same name.
204  }
205  }
206 
207  if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) {
208  // Continue searching through the remaining anims and parts.
209 
210  while (ai != anims.end()) {
211  // Here's an anim with no matching parts.
212  if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) {
213  AnimBundles::const_iterator abi;
214  for (abi = (*ai).second.begin(); abi != (*ai).second.end(); ++abi) {
215  extra_anims.insert(*abi);
216  }
217  }
218  ++ai;
219  }
220 
221  while (pi != parts.end()) {
222  // And here's a part with no matching anims.
223  if (hierarchy_match_flags & PartGroup::HMF_ok_wrong_root_name) {
224  PartBundles::const_iterator pbi;
225  for (pbi = (*pi).second.begin(); pbi != (*pi).second.end(); ++pbi) {
226  extra_parts.insert(*pbi);
227  }
228  }
229  ++pi;
230  }
231 
232  bind_anims(extra_parts, extra_anims, controls,
233  hierarchy_match_flags);
234  }
235 }
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:29
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a node that contains a pointer to an PartBundle.
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
This is a named collection of AnimControl pointers.
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:784
AnimControl * find_anim(const std::string &name) const
Returns the AnimControl associated with the given name, or NULL if no such control has been associate...
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:46
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void store_anim(AnimControl *control, const std::string &name)
Associates the given AnimControl with this collection under the given name.
Controls the timing of a character animation.
Definition: animControl.h:38
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
void auto_bind(PandaNode *root_node, AnimControlCollection &controls, int hierarchy_match_flags)
Walks the scene graph or subgraph beginning at the indicated node, and attempts to bind any AnimBundl...
Definition: auto_bind.cxx:123
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a node that contains a pointer to an AnimBundle.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.