Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/eggcharbase/eggCharacterCollection.cxx

Go to the documentation of this file.
00001 // Filename: eggCharacterCollection.cxx
00002 // Created by:  drose (26Feb01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "eggCharacterCollection.h"
00020 #include "eggCharacterData.h"
00021 #include "eggJointData.h"
00022 #include "eggSliderData.h"
00023 
00024 #include "dcast.h"
00025 #include "eggGroup.h"
00026 #include "eggTable.h"
00027 #include "eggPrimitive.h"
00028 #include "eggVertex.h"
00029 #include "eggMorphList.h"
00030 #include "eggSAnimData.h"
00031 #include "indirectCompareNames.h"
00032 #include "indent.h"
00033 
00034 #include <algorithm>
00035 
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: EggCharacterCollection::Constructor
00039 //       Access: Public
00040 //  Description:
00041 ////////////////////////////////////////////////////////////////////
00042 EggCharacterCollection::
00043 EggCharacterCollection() {
00044   _next_model_index = 0;
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: EggCharacterCollection::Destructor
00049 //       Access: Public, Virtual
00050 //  Description:
00051 ////////////////////////////////////////////////////////////////////
00052 EggCharacterCollection::
00053 ~EggCharacterCollection() {
00054   Characters::iterator ci;
00055 
00056   for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
00057     delete (*ci);
00058   }
00059 }
00060 
00061 ////////////////////////////////////////////////////////////////////
00062 //     Function: EggCharacterCollection::add_egg
00063 //       Access: Public
00064 //  Description: Adds a new egg file to the list of models and
00065 //               animation files for this particular character.
00066 //
00067 //               Returns the new egg_index if the file is successfully
00068 //               added, or -1 if there is some problem (for instance,
00069 //               it does not contain a character model or animation
00070 //               table).
00071 //
00072 //               If the joint hierarchy does not match the existing
00073 //               joint hierarchy, a best match is attempted.
00074 ////////////////////////////////////////////////////////////////////
00075 int EggCharacterCollection::
00076 add_egg(EggData *egg) {
00077   _top_egg_nodes.clear();
00078 
00079   if (!scan_hierarchy(egg)) {
00080     return -1;
00081   }
00082 
00083   int egg_index = _eggs.size();
00084   _eggs.push_back(EggInfo());
00085   EggInfo &egg_info = _eggs.back();
00086   egg_info._egg = egg;
00087   egg_info._first_model_index = 0;
00088 
00089   // Now, for each model, add an entry in the egg_info and match the
00090   // joint hierarchy to the known joints.
00091   TopEggNodesByName::iterator tni;
00092   for (tni = _top_egg_nodes.begin(); tni != _top_egg_nodes.end(); ++tni) {
00093     string character_name = (*tni).first;
00094     TopEggNodes &top_nodes = (*tni).second;
00095     EggCharacterData *char_data = make_character(character_name);
00096     EggJointData *root_joint = char_data->get_root_joint();
00097 
00098     TopEggNodes::iterator ti;
00099     for (ti = top_nodes.begin(); ti != top_nodes.end(); ++ti) {
00100       EggNode *model_root = (*ti).first;
00101       EggNodeList &egg_nodes = (*ti).second;
00102 
00103       int model_index = _next_model_index++;
00104       if (egg_info._models.empty()) {
00105         egg_info._first_model_index = model_index;
00106       }
00107       egg_info._models.push_back(model_root);
00108 
00109       char_data->add_model(model_index, model_root);
00110       nassertr(model_index == (int)_characters_by_model_index.size(), -1);
00111       _characters_by_model_index.push_back(char_data);
00112 
00113       match_egg_nodes(char_data, root_joint, egg_nodes,
00114                       egg_index, model_index);
00115 
00116       scan_for_morphs(model_root, model_index, char_data);
00117       scan_for_sliders(model_root, model_index, char_data);
00118     }
00119   }
00120 
00121   return egg_index;
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: EggCharacterCollection::get_character_by_name
00126 //       Access: Public
00127 //  Description: Returns the Character with the indicated name, if it
00128 //               exists in the collection, or NULL if it does not.
00129 ////////////////////////////////////////////////////////////////////
00130 EggCharacterData *EggCharacterCollection::
00131 get_character_by_name(const string &character_name) const {
00132   Characters::const_iterator ci;
00133   for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
00134     EggCharacterData *char_data = (*ci);
00135     if (char_data->get_name() == character_name) {
00136       return char_data;
00137     }
00138   }
00139 
00140   return (EggCharacterData *)NULL;
00141 }
00142 
00143 
00144 ////////////////////////////////////////////////////////////////////
00145 //     Function: EggCharacterCollection::make_character_data
00146 //       Access: Public, Virtual
00147 //  Description: Allocates and returns a new EggCharacterData
00148 //               structure.  This is primarily intended as a hook so
00149 //               derived classes can customize the type of
00150 //               EggCharacterData nodes used to represent the
00151 //               characters in this collection.
00152 ////////////////////////////////////////////////////////////////////
00153 EggCharacterData *EggCharacterCollection::
00154 make_character_data() {
00155   return new EggCharacterData(this);
00156 }
00157 
00158 ////////////////////////////////////////////////////////////////////
00159 //     Function: EggCharacterCollection::make_joint_data
00160 //       Access: Public, Virtual
00161 //  Description: Allocates and returns a new EggJointData structure
00162 //               for the given character.  This is primarily intended
00163 //               as a hook so derived classes can customize the type
00164 //               of EggJointData nodes used to represent the joint
00165 //               hierarchy.
00166 ////////////////////////////////////////////////////////////////////
00167 EggJointData *EggCharacterCollection::
00168 make_joint_data(EggCharacterData *char_data) {
00169   return new EggJointData(this, char_data);
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: EggCharacterCollection::make_slider_data
00174 //       Access: Public, Virtual
00175 //  Description: Allocates and returns a new EggSliderData structure
00176 //               for the given character.  This is primarily intended
00177 //               as a hook so derived classes can customize the type
00178 //               of EggSliderData nodes used to represent the slider
00179 //               list.
00180 ////////////////////////////////////////////////////////////////////
00181 EggSliderData *EggCharacterCollection::
00182 make_slider_data(EggCharacterData *char_data) {
00183   return new EggSliderData(this, char_data);
00184 }
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: EggCharacterCollection::make_character
00188 //       Access: Protected
00189 //  Description: Allocates and returns a new EggCharacterData object
00190 //               representing the named character, if there is not
00191 //               already a character by that name.
00192 ////////////////////////////////////////////////////////////////////
00193 EggCharacterData *EggCharacterCollection::
00194 make_character(const string &character_name) {
00195   // Does the named character exist yet?
00196 
00197   Characters::iterator ci;
00198   for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
00199     EggCharacterData *char_data = (*ci);
00200     if (char_data->get_name() == character_name) {
00201       return char_data;
00202     }
00203   }
00204 
00205   // Define a new character.
00206   EggCharacterData *char_data = make_character_data();
00207   char_data->set_name(character_name);
00208   _characters.push_back(char_data);
00209   return char_data;
00210 }
00211 
00212 ////////////////////////////////////////////////////////////////////
00213 //     Function: EggCharacterCollection::scan_hierarchy
00214 //       Access: Private
00215 //  Description: Walks the given egg data's hierarchy, looking for
00216 //               either the start of an animation channel or the start
00217 //               of a character model.  Returns true if either (or
00218 //               both) is found, false if the model appears to have
00219 //               nothing to do with characters.
00220 //
00221 //               Fills up the _top_egg_nodes according to the nodes
00222 //               found.
00223 ////////////////////////////////////////////////////////////////////
00224 bool EggCharacterCollection::
00225 scan_hierarchy(EggNode *egg_node) {
00226   if (egg_node->is_of_type(EggGroup::get_class_type())) {
00227     EggGroup *group = DCAST(EggGroup, egg_node);
00228     if (group->get_dart_type() != EggGroup::DT_none) {
00229       // A group with a <Dart> flag begins a character model.
00230       scan_for_top_joints(group, group, group->get_name());
00231       return true;
00232     }
00233 
00234   } else if (egg_node->is_of_type(EggTable::get_class_type())) {
00235     EggTable *table = DCAST(EggTable, egg_node);
00236     if (table->get_table_type() == EggTable::TT_bundle) {
00237       // A <Bundle> begins an animation table.
00238       scan_for_top_tables(table, table, table->get_name());
00239       return true;
00240     }
00241   }
00242 
00243   bool character_found = false;
00244   if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
00245     EggGroupNode *group = DCAST(EggGroupNode, egg_node);
00246     EggGroupNode::iterator gi;
00247     for (gi = group->begin(); gi != group->end(); ++gi) {
00248       if (scan_hierarchy(*gi)) {
00249         character_found = true;
00250       }
00251     }
00252   }
00253 
00254   return character_found;
00255 }
00256 
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: EggCharacterCollection::scan_for_top_joints
00259 //       Access: Private
00260 //  Description: Once a character model has been found, continue
00261 //               scanning the egg hierarchy to look for the topmost
00262 //               <Joint> nodes encountered.
00263 ////////////////////////////////////////////////////////////////////
00264 void EggCharacterCollection::
00265 scan_for_top_joints(EggNode *egg_node, EggNode *model_root,
00266                     const string &character_name) {
00267   if (egg_node->is_of_type(EggGroup::get_class_type())) {
00268     EggGroup *group = DCAST(EggGroup, egg_node);
00269 
00270     if (group->has_lod()) {
00271       // This flag has an LOD specification.
00272       model_root = group;
00273     }
00274     if (group->get_group_type() == EggGroup::GT_joint) {
00275       // A <Joint> node begins a model hierarchy.
00276       _top_egg_nodes[character_name][model_root].push_back(group);
00277       return;
00278     }
00279   }
00280 
00281   if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
00282     EggGroupNode *group = DCAST(EggGroupNode, egg_node);
00283     EggGroupNode::iterator gi;
00284     for (gi = group->begin(); gi != group->end(); ++gi) {
00285       scan_for_top_joints(*gi, model_root, character_name);
00286     }
00287   }
00288 }
00289 
00290 ////////////////////////////////////////////////////////////////////
00291 //     Function: EggCharacterCollection::scan_for_top_tables
00292 //       Access: Private
00293 //  Description: Once an animation has been found, continue scanning
00294 //               the egg hierarchy to look for the topmost <Table>
00295 //               nodes encountered.
00296 ////////////////////////////////////////////////////////////////////
00297 void EggCharacterCollection::
00298 scan_for_top_tables(EggTable *bundle, EggNode *model_root,
00299                     const string &character_name) {
00300   // We really only need to check the immediate children of the bundle
00301   // for a table node called "<skeleton>".
00302   EggGroupNode::iterator gi;
00303   for (gi = bundle->begin(); gi != bundle->end(); ++gi) {
00304     EggNode *child = (*gi);
00305     if (child->is_of_type(EggTable::get_class_type())) {
00306       EggTable *table = DCAST(EggTable, child);
00307       if (table->get_name() == "<skeleton>") {
00308         // Here it is!  Now the immediate children of this node are
00309         // the top tables.
00310 
00311         EggGroupNode::iterator cgi;
00312         for (cgi = table->begin(); cgi != table->end(); ++cgi) {
00313           EggNode *grandchild = (*cgi);
00314           if (grandchild->is_of_type(EggTable::get_class_type())) {
00315             _top_egg_nodes[character_name][model_root].push_back(grandchild);
00316           }
00317         }
00318       }
00319     }
00320   }
00321 }
00322 
00323 ////////////////////////////////////////////////////////////////////
00324 //     Function: EggCharacterCollection::scan_for_morphs
00325 //       Access: Private
00326 //  Description: Go back through a model's hierarchy and look for
00327 //               morph targets on the vertices and primitives.
00328 ////////////////////////////////////////////////////////////////////
00329 void EggCharacterCollection::
00330 scan_for_morphs(EggNode *egg_node, int model_index,
00331                 EggCharacterData *char_data) {
00332   if (egg_node->is_of_type(EggPrimitive::get_class_type())) {
00333     EggPrimitive *prim = DCAST(EggPrimitive, egg_node);
00334     // Check for morphs on the primitive.
00335     add_morph_back_pointers(prim, prim, model_index, char_data);
00336 
00337     // Also check for morphs on each of the prim's vertices.
00338     EggPrimitive::const_iterator vi;
00339     for (vi = prim->begin(); vi != prim->end(); ++vi) {
00340       EggVertex *vertex = (*vi);
00341 
00342       add_morph_back_pointers(vertex, vertex, model_index, char_data);
00343 
00344       EggMorphVertexList::const_iterator mvi;
00345       for (mvi = vertex->_dxyzs.begin();
00346            mvi != vertex->_dxyzs.end();
00347            ++mvi) {
00348         const EggMorphVertex &morph = (*mvi);
00349         char_data->make_slider(morph.get_name())->add_back_pointer(model_index, vertex);
00350       }
00351     }
00352   }
00353 
00354   if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
00355     EggGroupNode *group = DCAST(EggGroupNode, egg_node);
00356     EggGroupNode::iterator gi;
00357     for (gi = group->begin(); gi != group->end(); ++gi) {
00358       scan_for_morphs(*gi, model_index, char_data);
00359     }
00360   }
00361 }
00362 
00363 ////////////////////////////////////////////////////////////////////
00364 //     Function: EggCharacterCollection::scan_for_sliders
00365 //       Access: Private
00366 //  Description: Go back to the animation tables and look for morph
00367 //               slider animation channels.
00368 ////////////////////////////////////////////////////////////////////
00369 void EggCharacterCollection::
00370 scan_for_sliders(EggNode *egg_node, int model_index,
00371                  EggCharacterData *char_data) {
00372   if (egg_node->is_of_type(EggTable::get_class_type())) {
00373     EggTable *bundle = DCAST(EggTable, egg_node);
00374 
00375     // We really only need to check the immediate children of the
00376     // bundle for a table node called "morph".  This is a sibling of
00377     // "<skeleton>", which we found a minute ago, but we weren't ready
00378     // to scan for the morph sliders at the time, so we have to look
00379     // again now.
00380 
00381     EggGroupNode::iterator gi;
00382     for (gi = bundle->begin(); gi != bundle->end(); ++gi) {
00383       EggNode *child = (*gi);
00384       if (child->is_of_type(EggTable::get_class_type())) {
00385         EggTable *table = DCAST(EggTable, child);
00386         if (table->get_name() == "morph") {
00387           // Here it is!  Now the immediate children of this node are
00388           // all the slider channels.
00389 
00390           EggGroupNode::iterator cgi;
00391           for (cgi = table->begin(); cgi != table->end(); ++cgi) {
00392             EggNode *grandchild = (*cgi);
00393             if (grandchild->is_of_type(EggSAnimData::get_class_type())) {
00394               char_data->make_slider(grandchild->get_name())->add_back_pointer(model_index, grandchild);
00395             }
00396           }
00397         }
00398       }
00399     }
00400   }
00401 }
00402 
00403 ////////////////////////////////////////////////////////////////////
00404 //     Function: EggCharacterCollection::add_morph_back_pointers
00405 //       Access: Private
00406 //  Description: Adds the back pointers for the kinds of morphs we
00407 //               might find in an EggAttributes object.
00408 ////////////////////////////////////////////////////////////////////
00409 void EggCharacterCollection::
00410 add_morph_back_pointers(EggAttributes *attrib, EggObject *egg_object,
00411                         int model_index, EggCharacterData *char_data) {
00412   EggMorphNormalList::const_iterator mni;
00413   for (mni = attrib->_dnormals.begin();
00414        mni != attrib->_dnormals.end();
00415        ++mni) {
00416     const EggMorphNormal &morph = (*mni);
00417     char_data->make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
00418   }
00419 
00420   EggMorphTexCoordList::const_iterator mti;
00421   for (mti = attrib->_duvs.begin();
00422        mti != attrib->_duvs.end();
00423        ++mti) {
00424     const EggMorphTexCoord &morph = (*mti);
00425     char_data->make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
00426   }
00427 
00428   EggMorphColorList::const_iterator mci;
00429   for (mci = attrib->_drgbas.begin();
00430        mci != attrib->_drgbas.end();
00431        ++mci) {
00432     const EggMorphColor &morph = (*mci);
00433     char_data->make_slider(morph.get_name())->add_back_pointer(model_index, egg_object);
00434   }
00435 }
00436 
00437 ////////////////////////////////////////////////////////////////////
00438 //     Function: EggCharacterCollection::match_egg_nodes
00439 //       Access: Private
00440 //  Description: Attempts to match up the indicated list of egg_nodes
00441 //               with the children of the given joint_data, by name if
00442 //               possible.
00443 //
00444 //               Also recurses on each matched joint to build up the
00445 //               entire joint hierarchy.
00446 ////////////////////////////////////////////////////////////////////
00447 void EggCharacterCollection::
00448 match_egg_nodes(EggCharacterData *char_data, EggJointData *joint_data,
00449                 EggNodeList &egg_nodes, int egg_index, int model_index) {
00450   // Sort the list of egg_nodes in order by name.  This will make the
00451   // matching up by names easier and more reliable.
00452   sort(egg_nodes.begin(), egg_nodes.end(), IndirectCompareNames<Namable>());
00453 
00454   if (joint_data->_children.empty()) {
00455     // If the EggJointData has no children yet, we must be the first.
00456     // Gleefully define all the joints.
00457     EggNodeList::iterator ei;
00458     for (ei = egg_nodes.begin(); ei != egg_nodes.end(); ++ei) {
00459       EggNode *egg_node = (*ei);
00460       EggJointData *data = make_joint_data(char_data);
00461       joint_data->_children.push_back(data);
00462       data->_parent = joint_data;
00463       found_egg_match(char_data, data, egg_node, egg_index, model_index);
00464     }
00465 
00466   } else {
00467     // The EggJointData already has children; therefore, we have to
00468     // match our joints up with the already-existing ones.
00469 
00470     EggNodeList extra_egg_nodes;
00471     EggJointData::Children extra_data;
00472 
00473     EggNodeList::iterator ei;
00474     EggJointData::Children::iterator di;
00475 
00476     ei = egg_nodes.begin();
00477     di = joint_data->_children.begin();
00478 
00479     while (ei != egg_nodes.end() && di != joint_data->_children.end()) {
00480       EggNode *egg_node = (*ei);
00481       EggJointData *data = (*di);
00482 
00483       if (egg_node->get_name() < data->get_name()) {
00484         // Here's a joint in the egg file, unmatched in the data.
00485         extra_egg_nodes.push_back(egg_node);
00486         ++ei;
00487 
00488       } else if (data->get_name() < egg_node->get_name()) {
00489         // Here's a joint in the data, umatched by the egg file.
00490         extra_data.push_back(data);
00491         ++di;
00492 
00493       } else {
00494         // Hey, these two match!  Hooray!
00495         found_egg_match(char_data, data, egg_node, egg_index, model_index);
00496         ++ei;
00497         ++di;
00498       }
00499     }
00500 
00501     while (ei != egg_nodes.end()) {
00502       EggNode *egg_node = (*ei);
00503 
00504       // Here's a joint in the egg file, unmatched in the data.
00505       extra_egg_nodes.push_back(egg_node);
00506       ++ei;
00507     }
00508 
00509     while (di != joint_data->_children.end()) {
00510       EggJointData *data = (*di);
00511 
00512       // Here's a joint in the data, umatched by the egg file.
00513       extra_data.push_back(data);
00514       ++di;
00515     }
00516 
00517     if (!extra_egg_nodes.empty()) {
00518       // If we have some extra egg_nodes, we have to find a place to
00519       // match them.  (If we only had extra data, we don't care.)
00520 
00521       // First, check to see if any of the names match any past-used
00522       // name.
00523 
00524       EggNodeList more_egg_nodes;
00525 
00526       for (ei = extra_egg_nodes.begin(); ei != extra_egg_nodes.end(); ++ei) {
00527         EggNode *egg_node = (*ei);
00528         bool matched = false;
00529         for (di = extra_data.begin();
00530              di != extra_data.end() && !matched;
00531              ++di) {
00532           EggJointData *data = (*di);
00533           if (data->matches_name(egg_node->get_name())) {
00534             matched = true;
00535             found_egg_match(char_data, data, egg_node, egg_index, model_index);
00536             extra_data.erase(di);
00537           }
00538         }
00539 
00540         if (!matched) {
00541           // This joint name was never seen before.
00542           more_egg_nodes.push_back(egg_node);
00543         }
00544       }
00545       extra_egg_nodes.swap(more_egg_nodes);
00546     }
00547 
00548     if (!extra_egg_nodes.empty()) {
00549       // Ok, we've still got to find a home for these remaining
00550       // egg_nodes.
00551       if (extra_egg_nodes.size() == extra_data.size()) {
00552         // Match 'em up one-for-one.
00553         size_t i;
00554         for (i = 0; i < extra_egg_nodes.size(); i++) {
00555           EggNode *egg_node = extra_egg_nodes[i];
00556           EggJointData *data = extra_data[i];
00557           found_egg_match(char_data, data, egg_node, egg_index, model_index);
00558         }
00559 
00560       } else {
00561         // Just tack 'em on the end.
00562         EggNodeList::iterator ei;
00563         for (ei = extra_egg_nodes.begin(); ei != extra_egg_nodes.end(); ++ei) {
00564           EggNode *egg_node = (*ei);
00565           EggJointData *data = make_joint_data(char_data);
00566           joint_data->_children.push_back(data);
00567           data->_parent = joint_data;
00568           found_egg_match(char_data, data, egg_node, egg_index, model_index);
00569         }
00570       }
00571     }
00572   }
00573 
00574   // Now sort the generated joint data hierarchy by name, just to be
00575   // sure.
00576   sort(joint_data->_children.begin(), joint_data->_children.end(),
00577        IndirectCompareNames<Namable>());
00578 }
00579 
00580 ////////////////////////////////////////////////////////////////////
00581 //     Function: EggCharacterCollection::found_egg_match
00582 //       Access: Private
00583 //  Description: Marks a one-to-one association between the indicated
00584 //               EggJointData and the indicated EggNode, and then
00585 //               recurses below.
00586 ////////////////////////////////////////////////////////////////////
00587 void EggCharacterCollection::
00588 found_egg_match(EggCharacterData *char_data, EggJointData *joint_data,
00589                 EggNode *egg_node, int egg_index, int model_index) {
00590   if (egg_node->has_name()) {
00591     joint_data->add_name(egg_node->get_name());
00592   }
00593   joint_data->add_back_pointer(model_index, egg_node);
00594 
00595   if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
00596     EggGroupNode *group_node = DCAST(EggGroupNode, egg_node);
00597 
00598     // Now consider all the children of egg_node that are themselves
00599     // joints or tables.
00600     EggNodeList egg_nodes;
00601 
00602     // Two approaches: either we are scanning a model with joints, or
00603     // an animation bundle with tables.
00604 
00605     if (egg_node->is_of_type(EggGroup::get_class_type())) {
00606       // A model with joints.
00607       EggGroupNode::iterator gi;
00608       for (gi = group_node->begin(); gi != group_node->end(); ++gi) {
00609         EggNode *child = (*gi);
00610         if (child->is_of_type(EggGroup::get_class_type())) {
00611           EggGroup *group = DCAST(EggGroup, child);
00612           if (group->get_group_type() == EggGroup::GT_joint) {
00613             egg_nodes.push_back(group);
00614           }
00615         }
00616       }
00617 
00618     } else {
00619       // An animation bundle with tables.
00620       EggGroupNode::iterator gi;
00621       for (gi = group_node->begin(); gi != group_node->end(); ++gi) {
00622         EggNode *child = (*gi);
00623         if (child->is_of_type(EggTable::get_class_type())) {
00624           EggTable *table = DCAST(EggTable, child);
00625           if (!(table->get_name() == "xform")) {
00626             egg_nodes.push_back(table);
00627           }
00628         }
00629       }
00630     }
00631 
00632     if (!egg_nodes.empty()) {
00633       match_egg_nodes(char_data, joint_data, egg_nodes,
00634                       egg_index, model_index);
00635     }
00636   }
00637 }
00638 
00639 ////////////////////////////////////////////////////////////////////
00640 //     Function: EggCharacterCollection::write
00641 //       Access: Public, Virtual
00642 //  Description:
00643 ////////////////////////////////////////////////////////////////////
00644 void EggCharacterCollection::
00645 write(ostream &out, int indent_level) const {
00646   Characters::const_iterator ci;
00647 
00648   for (ci = _characters.begin(); ci != _characters.end(); ++ci) {
00649     EggCharacterData *char_data = (*ci);
00650     char_data->write(out, indent_level);
00651   }
00652 }

Generated on Fri May 2 03:18:41 2003 for Panda-Tool by doxygen1.3