Panda3D
|
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 }