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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:29
This is a named collection of AnimControl pointers.
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...
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
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:782
This is a node that contains a pointer to an PartBundle.
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:46
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 map.
Definition: pmap.h:49
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.