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
23 typedef pset<AnimBundle *> AnimBundles;
24 typedef pmap<string, AnimBundles> Anims;
25
26 typedef pset<PartBundle *> PartBundles;
27 typedef pmap<string, PartBundles> Parts;
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
123 auto_bind(PandaNode *root_node, AnimControlCollection &controls,
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 }
animBundleNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
auto_bind
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
auto_bind.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AnimBundleNode
This is a node that contains a pointer to an AnimBundle.
Definition: animBundleNode.h:29
AnimBundle
This is the root of an AnimChannel hierarchy.
Definition: animBundle.h:29
AnimControlCollection
This is a named collection of AnimControl pointers.
Definition: animControlCollection.h:33
AnimControlCollection::find_anim
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...
Definition: animControlCollection.cxx:71
AnimControlCollection::store_anim
void store_anim(AnimControl *control, const std::string &name)
Associates the given AnimControl with this collection under the given name.
Definition: animControlCollection.cxx:42
AnimControl
Controls the timing of a character animation.
Definition: animControl.h:38
PandaNode::Children
Definition: pandaNode.h:706
PandaNode::Children::get_child
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
PandaNode::Children::get_num_children
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PandaNode::get_children
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:782
PartBundleNode
This is a node that contains a pointer to an PartBundle.
Definition: partBundleNode.h:35
PartBundle
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:46
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
config_chan.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
partBundleNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
partGroup.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.