open_toontown_panda3d/panda/src/chan/auto_bind.cxx

142 lines
4.1 KiB
C++

// Filename: auto_bind.cxx
// Created by: drose (23Feb99)
//
////////////////////////////////////////////////////////////////////
#include "auto_bind.h"
#include "animBundleNode.h"
#include "partBundleNode.h"
#include "config_chan.h"
#include <traverserVisitor.h>
#include <dftraverser.h>
#include <nullTransitionWrapper.h>
#include <nullAttributeWrapper.h>
#include <nullLevelState.h>
#include <renderRelation.h>
typedef set<AnimBundleNode *> AnimNodes;
typedef map<string, AnimNodes> Anims;
typedef set<PartBundleNode *> PartNodes;
typedef map<string, PartNodes> Parts;
////////////////////////////////////////////////////////////////////
// Class : CollectNodes
// Description : This is a traverser visitor that locates bundle nodes
// and adds them to their respective maps.
////////////////////////////////////////////////////////////////////
class CollectNodes :
public TraverserVisitor<NullTransitionWrapper, NullLevelState> {
public:
bool reached_node(Node *node, const NullAttributeWrapper &,
NullLevelState &) {
if (node->is_of_type(AnimBundleNode::get_class_type())) {
AnimBundleNode *bn = DCAST(AnimBundleNode, node);
_anims[bn->get_bundle()->get_name()].insert(bn);
} else if (node->is_of_type(PartBundleNode::get_class_type())) {
PartBundleNode *bn = DCAST(PartBundleNode, node);
_parts[bn->get_bundle()->get_name()].insert(bn);
}
return true;
}
Anims _anims;
Parts _parts;
};
////////////////////////////////////////////////////////////////////
// Function: bind_anims
// Description: A support function for auto_bind(), below. Given a
// set of AnimBundles and a set of PartBundles that all
// share the same name, perform whatever bindings make
// sense.
////////////////////////////////////////////////////////////////////
static void
bind_anims(const PartNodes &parts, const AnimNodes &anims,
AnimControlCollection &controls,
int hierarchy_match_flags) {
PartNodes::const_iterator pni;
for (pni = parts.begin(); pni != parts.end(); ++pni) {
PartBundle *part = (*pni)->get_bundle();
AnimNodes::const_iterator ani;
for (ani = anims.begin(); ani != anims.end(); ++ani) {
AnimBundle *anim = (*ani)->get_bundle();
if (chan_cat.is_info()) {
chan_cat.info()
<< "Attempting to bind " << *part << " to " << *anim << "\n";
}
PT(AnimControl) control =
part->bind_anim(anim, hierarchy_match_flags);
if (control != (AnimControl *)NULL) {
controls.store_anim(control, (*ani)->get_name());
}
if (chan_cat.is_info()) {
if (control == NULL) {
chan_cat.info()
<< "Bind failed.\n";
} else {
chan_cat.info()
<< "Bind succeeded, index "
<< control->get_channel_index() << "\n";
}
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: auto_bind
// Description: Walks the scene graph or subgraph beginning at the
// indicated node, and attempts to bind any AnimBundles
// found to their matching PartBundles, when possible.
//
// The list of all resulting AnimControls created is
// filled into controls.
////////////////////////////////////////////////////////////////////
void auto_bind(Node *root_node, AnimControlCollection &controls,
int hierarchy_match_flags) {
// First, locate all the bundles in the subgraph.
CollectNodes cn;
df_traverse(root_node, cn, NullAttributeWrapper(), NullLevelState(),
RenderRelation::get_class_type());
// Now, match up the bundles by name.
Anims::const_iterator ai = cn._anims.begin();
Parts::const_iterator pi = cn._parts.begin();
while (ai != cn._anims.end() && pi != cn._parts.end()) {
if ((*ai).first < (*pi).first) {
// Here's an anim with no matching parts.
++ai;
} else if ((*pi).first < (*ai).first) {
// And here's a part with no matching anims.
++pi;
} else {
// But here we have (at least one) match!
bind_anims((*pi).second, (*ai).second, controls,
hierarchy_match_flags);
++ai;
++pi;
}
}
}