Panda3D

xFileToEggConverter.cxx

00001 // Filename: xFileToEggConverter.cxx
00002 // Created by:  drose (21Jun01)
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 "xFileToEggConverter.h"
00016 #include "xFileMesh.h"
00017 #include "xFileMaterial.h"
00018 #include "xFileAnimationSet.h"
00019 #include "config_xfile.h"
00020 
00021 #include "eggData.h"
00022 #include "eggGroup.h"
00023 #include "eggXfmSAnim.h"
00024 #include "eggGroupUniquifier.h"
00025 #include "datagram.h"
00026 #include "eggMaterialCollection.h"
00027 #include "eggTextureCollection.h"
00028 #include "dcast.h"
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: XFileToEggConverter::Constructor
00032 //       Access: Public
00033 //  Description:
00034 ////////////////////////////////////////////////////////////////////
00035 XFileToEggConverter::
00036 XFileToEggConverter() {
00037   _make_char = false;
00038   _frame_rate = 0.0;
00039   _x_file = new XFile(true);
00040   _dart_node = NULL;
00041 }
00042 
00043 ////////////////////////////////////////////////////////////////////
00044 //     Function: XFileToEggConverter::Copy Constructor
00045 //       Access: Public
00046 //  Description:
00047 ////////////////////////////////////////////////////////////////////
00048 XFileToEggConverter::
00049 XFileToEggConverter(const XFileToEggConverter &copy) :
00050   SomethingToEggConverter(copy),
00051   _make_char(copy._make_char)
00052 {
00053   _x_file = new XFile(true);
00054   _dart_node = NULL;
00055 }
00056 
00057 ////////////////////////////////////////////////////////////////////
00058 //     Function: XFileToEggConverter::Destructor
00059 //       Access: Public
00060 //  Description:
00061 ////////////////////////////////////////////////////////////////////
00062 XFileToEggConverter::
00063 ~XFileToEggConverter() {
00064   close();
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: XFileToEggConverter::make_copy
00069 //       Access: Public, Virtual
00070 //  Description: Allocates and returns a new copy of the converter.
00071 ////////////////////////////////////////////////////////////////////
00072 SomethingToEggConverter *XFileToEggConverter::
00073 make_copy() {
00074   return new XFileToEggConverter(*this);
00075 }
00076 
00077 
00078 ////////////////////////////////////////////////////////////////////
00079 //     Function: XFileToEggConverter::get_name
00080 //       Access: Public, Virtual
00081 //  Description: Returns the English name of the file type this
00082 //               converter supports.
00083 ////////////////////////////////////////////////////////////////////
00084 string XFileToEggConverter::
00085 get_name() const {
00086   return "DirectX";
00087 }
00088 
00089 ////////////////////////////////////////////////////////////////////
00090 //     Function: XFileToEggConverter::get_extension
00091 //       Access: Public, Virtual
00092 //  Description: Returns the common extension of the file type this
00093 //               converter supports.
00094 ////////////////////////////////////////////////////////////////////
00095 string XFileToEggConverter::
00096 get_extension() const {
00097   return "x";
00098 }
00099 
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: XFileToEggConverter::supports_compressed
00102 //       Access: Published, Virtual
00103 //  Description: Returns true if this file type can transparently load
00104 //               compressed files (with a .pz extension), false
00105 //               otherwise.
00106 ////////////////////////////////////////////////////////////////////
00107 bool XFileToEggConverter::
00108 supports_compressed() const {
00109   return true;
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: XFileToEggConverter::convert_file
00114 //       Access: Public, Virtual
00115 //  Description: Handles the reading of the input file and converting
00116 //               it to egg.  Returns true if successful, false
00117 //               otherwise.
00118 //
00119 //               This is designed to be as generic as possible,
00120 //               generally in support of run-time loading.
00121 //               Command-line converters may choose to use
00122 //               convert_flt() instead, as it provides more control.
00123 ////////////////////////////////////////////////////////////////////
00124 bool XFileToEggConverter::
00125 convert_file(const Filename &filename) {
00126   close();
00127   clear_error();
00128 
00129   if (!_x_file->read(filename)) {
00130     nout << "Unable to open X file: " << filename << "\n";
00131     return false;
00132   }
00133 
00134   if (_char_name.empty()) {
00135     _char_name = filename.get_basename_wo_extension();
00136   }
00137 
00138   if (_egg_data->get_coordinate_system() == CS_default) {
00139     _egg_data->set_coordinate_system(CS_yup_left);
00140   }
00141 
00142   if (!get_toplevel()) {
00143     return false;
00144   }
00145 
00146   if (!create_polygons()) {
00147     return false;
00148   }
00149 
00150   if (_make_char) {
00151     // Now make sure that each joint has a unique name.
00152     EggGroupUniquifier uniquifier(false);
00153     uniquifier.uniquify(_dart_node);
00154   }
00155 
00156   if (!create_hierarchy()) {
00157     return false;
00158   }
00159 
00160   if (_keep_model && !_keep_animation) {
00161     strip_nodes(EggTable::get_class_type());
00162   }
00163   
00164   if (_keep_animation && !_keep_model) {
00165     strip_nodes(EggGroup::get_class_type());
00166   }
00167   
00168   return !had_error();
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: XFileToEggConverter::close
00173 //       Access: Public
00174 //  Description: Finalizes and closes the file previously opened via
00175 //               convert_file().
00176 ////////////////////////////////////////////////////////////////////
00177 void XFileToEggConverter::
00178 close() {
00179   _x_file->clear();
00180 
00181   // Clean up all the other stuff.
00182   Meshes::const_iterator mi;
00183   for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
00184     delete (*mi);
00185   }
00186   _meshes.clear();
00187   
00188   AnimationSets::const_iterator asi;
00189   for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
00190     delete (*asi);
00191   }
00192   _animation_sets.clear();
00193 
00194   _joints.clear();
00195 }
00196 
00197 ////////////////////////////////////////////////////////////////////
00198 //     Function: XFileToEggConverter::strip_nodes
00199 //       Access: Public
00200 //  Description: Removes all groups of the given type.  This is used
00201 //               to implement the -anim and -model options.
00202 ////////////////////////////////////////////////////////////////////
00203 void XFileToEggConverter::
00204 strip_nodes(TypeHandle t) {
00205   pvector <EggNode *> garbage;
00206   EggGroupNode::iterator i;
00207   for (i=_egg_data->begin(); i!=_egg_data->end(); ++i) {
00208     EggNode *node = (*i);
00209     if (node->is_of_type(t)) {
00210       garbage.push_back(node);
00211     }
00212   }
00213   for (int n=0; n<(int)garbage.size(); n++) {
00214     _egg_data->remove_child(garbage[n]);
00215   }
00216 }
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: XFileToEggConverter::get_dart_node
00220 //       Access: Public
00221 //  Description: Returns the root of the joint hierarchy, if
00222 //               _make_char is true, or NULL otherwise.
00223 ////////////////////////////////////////////////////////////////////
00224 EggGroup *XFileToEggConverter::
00225 get_dart_node() const {
00226   return _dart_node;
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: XFileToEggConverter::create_unique_texture
00231 //       Access: Public
00232 //  Description: Returns an EggTexture pointer whose properties match
00233 //               that of the the given EggTexture, except for the tref
00234 //               name.
00235 ////////////////////////////////////////////////////////////////////
00236 EggTexture *XFileToEggConverter::
00237 create_unique_texture(const EggTexture &copy) {
00238   return _textures.create_unique_texture(copy, ~EggTexture::E_tref_name);
00239 }
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: XFileToEggConverter::create_unique_material
00243 //       Access: Public
00244 //  Description: Returns an EggMaterial pointer whose properties match
00245 //               that of the the given EggMaterial, except for the mref
00246 //               name.
00247 ////////////////////////////////////////////////////////////////////
00248 EggMaterial *XFileToEggConverter::
00249 create_unique_material(const EggMaterial &copy) {
00250   return _materials.create_unique_material(copy, ~EggMaterial::E_mref_name);
00251 }
00252 
00253 ////////////////////////////////////////////////////////////////////
00254 //     Function: XFileToEggConverter::find_joint
00255 //       Access: Public
00256 //  Description: This is called by set_animation_frame, for
00257 //               the purposes of building the frame data for the
00258 //               animation--it needs to know the original rest frame
00259 //               transform.
00260 ////////////////////////////////////////////////////////////////////
00261 EggGroup *XFileToEggConverter::
00262 find_joint(const string &joint_name) {
00263   Joints::iterator ji;
00264   ji = _joints.find(joint_name);
00265   if (ji != _joints.end()) {
00266     EggGroup *joint = (*ji).second;
00267     if (joint == (EggGroup *)NULL) {
00268       // An invalid joint detected earlier.
00269       return NULL;
00270     }
00271 
00272     return joint;
00273   }
00274 
00275   // Joint name is unknown.  Issue a warning, then insert NULL into
00276   // the table so we don't get the same warning again with the next
00277   // polygon.
00278   if (_make_char) {
00279     xfile_cat.warning()
00280       << "Joint name " << joint_name << " in animation data is undefined.\n";
00281   }
00282   _joints[joint_name] = NULL;
00283 
00284   return NULL;
00285 }
00286 
00287 ////////////////////////////////////////////////////////////////////
00288 //     Function: XFileToEggConverter::get_toplevel
00289 //       Access: Private
00290 //  Description: Pulls off all of the top-level objects in the .x file
00291 //               and converts them, and their descendents, to the
00292 //               appropriate egg structures.
00293 ////////////////////////////////////////////////////////////////////
00294 bool XFileToEggConverter::
00295 get_toplevel() {
00296   int num_objects = _x_file->get_num_objects();
00297   int i;
00298 
00299   _ticks_per_second = 4800;  // X File default.
00300 
00301   // First, make a pass through the toplevel objects and see if we
00302   // have frames and/or animation.
00303   _any_frames = false;
00304   _any_animation = false;
00305   for (i = 0; i < num_objects; i++) {
00306     XFileDataNode *child = _x_file->get_object(i);
00307     if (child->is_standard_object("Frame")) {
00308       _any_frames = true;
00309     } else if (child->is_standard_object("AnimationSet")) {
00310       _any_animation = true;
00311     }
00312   }
00313 
00314   // If we have animation, assume we want to convert it as a character.
00315   if (_any_animation) {
00316     _make_char = true;
00317   }
00318 
00319   EggGroupNode *egg_parent = _egg_data;
00320   
00321   // If we are converting an animatable model, make an extra node to
00322   // represent the root of the hierarchy.
00323   if (_make_char) {
00324     _dart_node = new EggGroup(_char_name);
00325     egg_parent->add_child(_dart_node);
00326     _dart_node->set_dart_type(EggGroup::DT_default);
00327     egg_parent = _dart_node;
00328   }
00329 
00330   // Now go back through and convert the objects.
00331   for (i = 0; i < num_objects; i++) {
00332     if (!convert_toplevel_object(_x_file->get_object(i), egg_parent)) {
00333       return false;
00334     }
00335   }
00336 
00337   return true;
00338 }
00339 
00340 ////////////////////////////////////////////////////////////////////
00341 //     Function: XFileToEggConverter::convert_toplevel_object
00342 //       Access: Private
00343 //  Description: Converts the indicated object, encountered outside of
00344 //               any Frames, to the appropriate egg structures.
00345 ////////////////////////////////////////////////////////////////////
00346 bool XFileToEggConverter::
00347 convert_toplevel_object(XFileDataNode *obj, EggGroupNode *egg_parent) {
00348   if (obj->is_standard_object("Header")) {
00349     // Quietly ignore headers.
00350 
00351   } else if (obj->is_standard_object("Material")) {
00352     // Quietly ignore toplevel materials.  These will presumably be
00353     // referenced below.
00354 
00355   } else if (obj->is_standard_object("Frame")) {
00356     if (!convert_frame(obj, egg_parent)) {
00357       return false;
00358     }
00359 
00360   } else if (obj->is_standard_object("AnimationSet")) {
00361     if (!convert_animation_set(obj)) {
00362       return false;
00363     }
00364 
00365   } else if (obj->is_standard_object("AnimTicksPerSecond")) {
00366     _ticks_per_second = (*obj)[0].i();
00367 
00368   } else if (obj->is_standard_object("Mesh")) {
00369     // If there are any Frames at all in the file, then assume a Mesh
00370     // at the toplevel is just present to define a reference that will
00371     // be included below--so we ignore it here.  On the other hand, if
00372     // the file has no Frames, then a Mesh at the toplevel must be
00373     // actual geometry, so convert it now.
00374     if (!_any_frames) {
00375       if (!convert_mesh(obj, egg_parent)) {
00376         return false;
00377       }
00378     }
00379 
00380   } else {
00381     if (xfile_cat.is_debug()) {
00382       xfile_cat.debug()
00383         << "Ignoring toplevel object of unknown type: "
00384         << obj->get_template_name() << "\n";
00385     }
00386   }
00387   
00388   return true;
00389 }
00390 
00391 ////////////////////////////////////////////////////////////////////
00392 //     Function: XFileToEggConverter::convert_object
00393 //       Access: Private
00394 //  Description: Converts the indicated object to the appropriate egg
00395 //               structures.
00396 ////////////////////////////////////////////////////////////////////
00397 bool XFileToEggConverter::
00398 convert_object(XFileDataNode *obj, EggGroupNode *egg_parent) {
00399   if (obj->is_standard_object("Header")) {
00400     // Quietly ignore headers.
00401 
00402   } else if (obj->is_standard_object("Frame")) {
00403     if (!convert_frame(obj, egg_parent)) {
00404       return false;
00405     }
00406 
00407   } else if (obj->is_standard_object("FrameTransformMatrix")) {
00408     if (!convert_transform(obj, egg_parent)) {
00409       return false;
00410     }
00411 
00412   } else if (obj->is_standard_object("Mesh")) {
00413     if (!convert_mesh(obj, egg_parent)) {
00414       return false;
00415     }
00416 
00417   } else {
00418     if (xfile_cat.is_debug()) {
00419       xfile_cat.debug()
00420         << "Ignoring object of unknown type: "
00421         << obj->get_template_name() << "\n";
00422     }
00423   }
00424   
00425   return true;
00426 }
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: XFileToEggConverter::convert_frame
00430 //       Access: Private
00431 //  Description: Converts the indicated frame to the appropriate egg
00432 //               structures.
00433 ////////////////////////////////////////////////////////////////////
00434 bool XFileToEggConverter::
00435 convert_frame(XFileDataNode *obj, EggGroupNode *egg_parent) {
00436 
00437   string name = obj->get_name();
00438   EggGroup *group = new EggGroup(name);
00439   egg_parent->add_child(group);
00440   
00441   if (_make_char) {
00442     group->set_group_type(EggGroup::GT_joint);
00443     if (name.empty()) {
00444       // Make up a name for this unnamed joint.
00445       group->set_name("unnamed");
00446 
00447     } else {
00448       bool inserted = _joints.insert(Joints::value_type(name, group)).second;
00449       if (!inserted) {
00450         xfile_cat.warning()
00451           << "Nonunique Frame name " << name
00452           << " encountered; animation will be ambiguous.\n";
00453       }
00454     }
00455   }
00456 
00457   // Now walk through the children of the frame.
00458   int num_objects = obj->get_num_objects();
00459   for (int i = 0; i < num_objects; i++) {
00460     if (!convert_object(obj->get_object(i), group)) {
00461       return false;
00462     }
00463   }
00464 
00465   return true;
00466 }
00467 
00468 ////////////////////////////////////////////////////////////////////
00469 //     Function: XFileToEggConverter::convert_transform
00470 //       Access: Private
00471 //  Description: Reads a transform matrix, a child of a given frame,
00472 //               and applies it to the node.  Normally this can only
00473 //               be done if the node in question is an EggGroup, which
00474 //               should be the case if the transform was a child of a
00475 //               frame.
00476 ////////////////////////////////////////////////////////////////////
00477 bool XFileToEggConverter::
00478 convert_transform(XFileDataNode *obj, EggGroupNode *egg_parent) {
00479   LMatrix4d mat = (*obj)["frameMatrix"]["matrix"].mat4();
00480 
00481   if (egg_parent->is_of_type(EggGroup::get_class_type())) {
00482     EggGroup *egg_group = DCAST(EggGroup, egg_parent);
00483     egg_group->set_transform3d(mat);
00484 
00485   } else {
00486     xfile_cat.error()
00487       << "Transform " << obj->get_name()
00488       << " encountered without frame!\n";
00489   }
00490 
00491   return true;
00492 }
00493 
00494 ////////////////////////////////////////////////////////////////////
00495 //     Function: XFileToEggConverter::convert_animation_set
00496 //       Access: Private
00497 //  Description: Begins an AnimationSet.  This is the root of one
00498 //               particular animation (table of frames per joint) to
00499 //               be applied to the model within this file.
00500 ////////////////////////////////////////////////////////////////////
00501 bool XFileToEggConverter::
00502 convert_animation_set(XFileDataNode *obj) {
00503   XFileAnimationSet *animation_set = new XFileAnimationSet();
00504   animation_set->set_name(obj->get_name());
00505 
00506   _total_tick_deltas = 0;
00507   _num_ticks = 0;
00508 
00509   // Now walk through the children of the set; each one animates a
00510   // different joint.
00511   int num_objects = obj->get_num_objects();
00512   for (int i = 0; i < num_objects; i++) {
00513     if (!convert_animation_set_object(obj->get_object(i), *animation_set)) {
00514       return false;
00515     }
00516   }
00517 
00518   animation_set->_frame_rate = _frame_rate;
00519   if (_num_ticks != 0 && _frame_rate == 0.0) {
00520     // Compute the frame rate from the timing information.
00521     double delta = (double)_total_tick_deltas / (double)_num_ticks;
00522     if (delta != 0.0) {
00523       animation_set->_frame_rate = (double)_ticks_per_second / delta;
00524     }
00525   }
00526 
00527   _animation_sets.push_back(animation_set);
00528 
00529   return true;
00530 }
00531 
00532 ////////////////////////////////////////////////////////////////////
00533 //     Function: XFileToEggConverter::convert_animation_set_object
00534 //       Access: Private
00535 //  Description: Converts the indicated object, a child of a
00536 //               AnimationSet.
00537 ////////////////////////////////////////////////////////////////////
00538 bool XFileToEggConverter::
00539 convert_animation_set_object(XFileDataNode *obj, 
00540                              XFileAnimationSet &animation_set) {
00541   if (obj->is_standard_object("Animation")) {
00542     if (!convert_animation(obj, animation_set)) {
00543       return false;
00544     }
00545 
00546   } else {
00547     if (xfile_cat.is_debug()) {
00548       xfile_cat.debug()
00549         << "Ignoring animation set object of unknown type: "
00550         << obj->get_template_name() << "\n";
00551     }
00552   }
00553   
00554   return true;
00555 }
00556 
00557 ////////////////////////////////////////////////////////////////////
00558 //     Function: XFileToEggConverter::convert_animation
00559 //       Access: Private
00560 //  Description: Converts the indicated Animation template object.
00561 ////////////////////////////////////////////////////////////////////
00562 bool XFileToEggConverter::
00563 convert_animation(XFileDataNode *obj, XFileAnimationSet &animation_set) {
00564   // Within an Animation template, we expect to find a reference to a
00565   // frame, possibly an AnimationOptions object, and one or more
00566   // AnimationKey objects.
00567 
00568   // First, walk through the list of children, to find the one that is
00569   // the frame reference.  We need to know this up front so we know
00570   // which table we should be building up.
00571   string frame_name;
00572   bool got_frame_name = false;
00573 
00574   int num_objects = obj->get_num_objects();
00575   int i;
00576   for (i = 0; i < num_objects; i++) {
00577     XFileDataNode *child = obj->get_object(i);
00578     if (child->is_reference() && child->is_standard_object("Frame")) {
00579       frame_name = child->get_name();
00580       got_frame_name = true;
00581     }
00582   }
00583 
00584   if (!got_frame_name) {
00585     xfile_cat.error()
00586       << "Animation " << obj->get_name()
00587       << " includes no reference to a frame.\n";
00588     return false;
00589   }
00590 
00591   FrameData &table = animation_set.create_frame_data(frame_name);
00592 
00593   // Now go back again and get the actual data.
00594   for (i = 0; i < num_objects; i++) {
00595     if (!convert_animation_object(obj->get_object(i), frame_name, table)) {
00596       return false;
00597     }
00598   }
00599 
00600   return true;
00601 }
00602 
00603 ////////////////////////////////////////////////////////////////////
00604 //     Function: XFileToEggConverter::convert_animation_object
00605 //       Access: Private
00606 //  Description: Converts the indicated object, a child of a
00607 //               Animation.
00608 ////////////////////////////////////////////////////////////////////
00609 bool XFileToEggConverter::
00610 convert_animation_object(XFileDataNode *obj, const string &joint_name,
00611                          XFileToEggConverter::FrameData &table) {
00612   if (obj->is_standard_object("AnimationOptions")) {
00613     // Quietly ignore AnimationOptions.
00614 
00615   } else if (obj->is_standard_object("Frame")) {
00616     // Quietly ignore frames, since we already got the frame name.
00617 
00618   } else if (obj->is_standard_object("AnimationKey")) {
00619     if (!convert_animation_key(obj, joint_name, table)) {
00620       return false;
00621     }
00622 
00623   } else {
00624     if (xfile_cat.is_debug()) {
00625       xfile_cat.debug()
00626         << "Ignoring animation object of unknown type: "
00627         << obj->get_template_name() << "\n";
00628     }
00629   }
00630   
00631   return true;
00632 }
00633 
00634 ////////////////////////////////////////////////////////////////////
00635 //     Function: XFileToEggConverter::convert_animation_key
00636 //       Access: Private
00637 //  Description: Converts the indicated AnimationKey template object.
00638 ////////////////////////////////////////////////////////////////////
00639 bool XFileToEggConverter::
00640 convert_animation_key(XFileDataNode *obj, const string &joint_name, 
00641                       XFileToEggConverter::FrameData &table) {
00642   int key_type = (*obj)["keyType"].i();
00643   
00644   const XFileDataObject &keys = (*obj)["keys"];
00645 
00646   int last_time = 0;
00647   for (int i = 0; i < keys.size(); i++) {
00648     // The time value is problematic, since it allows x files to
00649     // specify keyframes of arbitrary duration.  Panda doesn't support
00650     // this; all frames in Panda must be of a constant duration.
00651     // Thus, we largely ignore the time value, but we take the average
00652     // of all deltas as the duration.  This will correctly handle .x
00653     // files with uniform keyframes, at least.
00654 
00655     int this_time = keys[i]["time"].i();
00656     if (i != 0) {
00657       int delta = this_time - last_time;
00658       _total_tick_deltas += delta;
00659       ++_num_ticks;
00660     }
00661     last_time = this_time;
00662 
00663     const XFileDataObject &values = keys[i]["tfkeys"]["values"];
00664     if (!set_animation_frame(joint_name, table, i, key_type, values)) {
00665       return false;
00666     }
00667   }
00668 
00669   return true;
00670 }
00671     
00672 ////////////////////////////////////////////////////////////////////
00673 //     Function: XFileToEggConverter::set_animation_frame
00674 //       Access: Private
00675 //  Description: Sets a single frame of the animation data.
00676 ////////////////////////////////////////////////////////////////////
00677 bool XFileToEggConverter::
00678 set_animation_frame(const string &joint_name, 
00679                     XFileToEggConverter::FrameData &table, int frame,
00680                     int key_type, const XFileDataObject &values) {
00681   if ((int)table._entries.size() <= frame) {
00682     nassertr((int)table._entries.size() == frame, false);
00683     table._entries.push_back(XFileAnimationSet::FrameEntry());
00684   }
00685 
00686   XFileAnimationSet::FrameEntry &frame_entry = table._entries[frame];
00687 
00688   // Now modify the last row in the table.
00689   switch (key_type) {
00690   case 0:
00691     // Key type 0: rotation.
00692     // This appears to be a quaternion.  Hope we get the coordinate
00693     // system right.
00694     if (values.size() != 4) {
00695       xfile_cat.error()
00696         << "Incorrect number of values in animation table: "
00697         << values.size() << " for rotation data.\n";
00698       return false;
00699     }
00700     frame_entry._rot.invert_from(LQuaterniond(values.vec4()));
00701     table._flags |= XFileAnimationSet::FDF_rot;
00702     break;
00703 
00704   case 1:
00705     if (values.size() != 3) {
00706       xfile_cat.error()
00707         << "Incorrect number of values in animation table: "
00708         << values.size() << " for scale data.\n";
00709       return false;
00710     }
00711     frame_entry._scale = values.vec3();
00712     table._flags |= XFileAnimationSet::FDF_scale;
00713     break;
00714     
00715   case 2:
00716     // Key type 2: position
00717     if (values.size() != 3) {
00718       xfile_cat.error()
00719         << "Incorrect number of values in animation table: "
00720         << values.size() << " for position data.\n";
00721       return false;
00722     }
00723     frame_entry._trans = values.vec3();
00724     table._flags |= XFileAnimationSet::FDF_trans;
00725     break;
00726 
00727     /*
00728   case 3:
00729     // Key type 3: ????
00730     break;
00731     */
00732 
00733   case 4:
00734     // Key type 4: full matrix
00735     if (values.size() != 16) {
00736       xfile_cat.error()
00737         << "Incorrect number of values in animation table: "
00738         << values.size() << " for matrix data.\n";
00739       return false;
00740     }
00741     frame_entry._mat = values.mat4();
00742     table._flags |= XFileAnimationSet::FDF_mat;
00743     break;
00744 
00745   default:
00746     xfile_cat.error()
00747       << "Unsupported key type " << key_type << " in animation table.\n";
00748     return false;
00749   }
00750   
00751   return true;
00752 }
00753 
00754 ////////////////////////////////////////////////////////////////////
00755 //     Function: XFileToEggConverter::convert_mesh
00756 //       Access: Private
00757 //  Description: Converts the indicated mesh to the appropriate egg
00758 //               structures.
00759 ////////////////////////////////////////////////////////////////////
00760 bool XFileToEggConverter::
00761 convert_mesh(XFileDataNode *obj, EggGroupNode *egg_parent) {
00762   XFileMesh *mesh = new XFileMesh(_egg_data->get_coordinate_system());
00763   mesh->set_name(obj->get_name());
00764   mesh->set_egg_parent(egg_parent);
00765 
00766   if (!mesh->fill_mesh(obj)) {
00767     delete mesh;
00768     return false;
00769   }
00770 
00771   _meshes.push_back(mesh);
00772 
00773   return true;
00774 }
00775 
00776 ////////////////////////////////////////////////////////////////////
00777 //     Function: XFileToEggConverter::create_polygons
00778 //       Access: Private
00779 //  Description: Creates all the polygons associated with
00780 //               previously-saved meshes.
00781 ////////////////////////////////////////////////////////////////////
00782 bool XFileToEggConverter::
00783 create_polygons() {
00784   bool okflag = true;
00785 
00786   Meshes::const_iterator mi;
00787   for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
00788     if (!(*mi)->create_polygons(this)) {
00789       okflag = false;
00790     }
00791     delete (*mi);
00792   }
00793   _meshes.clear();
00794 
00795   return okflag;
00796 }
00797 
00798 ////////////////////////////////////////////////////////////////////
00799 //     Function: XFileToEggConverter::create_hierarchy
00800 //       Access: Private
00801 //  Description: Creates the animation table hierarchies for the
00802 //               previously-saved animation sets.
00803 ////////////////////////////////////////////////////////////////////
00804 bool XFileToEggConverter::
00805 create_hierarchy() {
00806   bool okflag = true;
00807 
00808   AnimationSets::const_iterator asi;
00809   for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
00810     if (_make_char) {
00811       if (!(*asi)->create_hierarchy(this)) {
00812         okflag = false;
00813       }
00814     }
00815     delete (*asi);
00816   }
00817   _animation_sets.clear();
00818 
00819   return okflag;
00820 }
 All Classes Functions Variables Enumerations