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