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