Panda3D

eggMatrixTablePointer.cxx

00001 // Filename: eggMatrixTablePointer.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 "eggMatrixTablePointer.h"
00016 #include "dcast.h"
00017 #include "eggSAnimData.h"
00018 #include "eggXfmAnimData.h"
00019 #include "eggXfmSAnim.h"
00020 
00021 TypeHandle EggMatrixTablePointer::_type_handle;
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: EggMatrixTablePointer::Constructor
00025 //       Access: Public
00026 //  Description:
00027 ////////////////////////////////////////////////////////////////////
00028 EggMatrixTablePointer::
00029 EggMatrixTablePointer(EggObject *object) {
00030   _table = DCAST(EggTable, object);
00031 
00032   if (_table != (EggTable *)NULL) {
00033     // Now search for the child named "xform".  This contains the
00034     // actual table data.
00035     EggGroupNode::iterator ci;
00036     bool found = false;
00037     for (ci = _table->begin(); ci != _table->end() && !found; ++ci) {
00038       EggNode *child = (*ci);
00039       if (child->get_name() == "xform") {
00040         if (child->is_of_type(EggXfmSAnim::get_class_type())) {
00041           _xform = DCAST(EggXfmSAnim, child);
00042           _xform->normalize();
00043           found = true;
00044 
00045         } else if (child->is_of_type(EggXfmAnimData::get_class_type())) {
00046           // Quietly replace old-style XfmAnim tables with new-style
00047           // XfmSAnim tables.
00048           PT(EggXfmAnimData) anim = DCAST(EggXfmAnimData, child);
00049           _xform = new EggXfmSAnim(*anim);
00050           _table->replace(ci, _xform.p());
00051           found = true;
00052         }
00053       }
00054     }
00055   }
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: EggMatrixTablePointer::get_frame_rate
00060 //       Access: Public, Virtual
00061 //  Description: Returns the stated frame rate of this particular
00062 //               joint, or 0.0 if it doesn't state.
00063 ////////////////////////////////////////////////////////////////////
00064 double EggMatrixTablePointer::
00065 get_frame_rate() const {
00066   if (_xform == (EggXfmSAnim *)NULL || !_xform->has_fps()) {
00067     return 0.0;
00068   } else {
00069     return _xform->get_fps();
00070   }
00071 }
00072 
00073 ////////////////////////////////////////////////////////////////////
00074 //     Function: EggMatrixTablePointer::get_num_frames
00075 //       Access: Public, Virtual
00076 //  Description: Returns the number of frames of animation for this
00077 //               particular joint.
00078 ////////////////////////////////////////////////////////////////////
00079 int EggMatrixTablePointer::
00080 get_num_frames() const {
00081   if (_xform == (EggXfmSAnim *)NULL) {
00082     return 0;
00083   } else {
00084     return _xform->get_num_rows();
00085   }
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: EggMatrixTablePointer::extend_to
00090 //       Access: Public, Virtual
00091 //  Description: Extends the table to the indicated number of frames.
00092 ////////////////////////////////////////////////////////////////////
00093 void EggMatrixTablePointer::
00094 extend_to(int num_frames) {
00095   nassertv(_xform != (EggXfmSAnim *)NULL);
00096   _xform->normalize();
00097   int num_rows = _xform->get_num_rows();
00098   LMatrix4d last_mat;
00099   if (num_rows == 0) {
00100     last_mat = LMatrix4d::ident_mat();
00101   } else {
00102     _xform->get_value(num_rows - 1, last_mat);
00103   }
00104 
00105   while (num_rows < num_frames) {
00106     _xform->add_data(last_mat);
00107     num_rows++;
00108   }
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: EggMatrixTablePointer::get_frame
00113 //       Access: Public, Virtual
00114 //  Description: Returns the transform matrix corresponding to this
00115 //               joint position in the nth frame.
00116 ////////////////////////////////////////////////////////////////////
00117 LMatrix4d EggMatrixTablePointer::
00118 get_frame(int n) const {
00119   if (get_num_frames() == 1) {
00120     // If we have exactly one frame, then we have as many frames as we
00121     // want; just repeat the first frame.
00122     n = 0;
00123 
00124   } else if (get_num_frames() == 0) {
00125     // If we have no frames, we really have the identity matrix.
00126     return LMatrix4d::ident_mat();
00127   }
00128 
00129   nassertr(n >= 0 && n < get_num_frames(), LMatrix4d::ident_mat());
00130   LMatrix4d mat;
00131   _xform->get_value(n, mat);
00132   return mat;
00133 }
00134 
00135 ////////////////////////////////////////////////////////////////////
00136 //     Function: EggMatrixTablePointer::set_frame
00137 //       Access: Public, Virtual
00138 //  Description: Sets the transform matrix corresponding to this
00139 //               joint position in the nth frame.
00140 ////////////////////////////////////////////////////////////////////
00141 void EggMatrixTablePointer::
00142 set_frame(int n, const LMatrix4d &mat) {
00143   nassertv(n >= 0 && n < get_num_frames());
00144   _xform->set_value(n, mat);
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: EggMatrixTablePointer::add_frame
00149 //       Access: Public, Virtual
00150 //  Description: Appends a new frame onto the end of the data, if
00151 //               possible; returns true if not possible, or false
00152 //               otherwise (e.g. for a static joint).
00153 ////////////////////////////////////////////////////////////////////
00154 bool EggMatrixTablePointer::
00155 add_frame(const LMatrix4d &mat) {
00156   if (_xform == (EggXfmSAnim *)NULL) {
00157     return false;
00158   }
00159 
00160   return _xform->add_data(mat);
00161 }
00162 
00163 ////////////////////////////////////////////////////////////////////
00164 //     Function: EggMatrixTablePointer::do_finish_reparent
00165 //       Access: Protected
00166 //  Description: Performs the actual reparenting operation
00167 //               by removing the node from its old parent and
00168 //               associating it with its new parent, if any.
00169 ////////////////////////////////////////////////////////////////////
00170 void EggMatrixTablePointer::
00171 do_finish_reparent(EggJointPointer *new_parent) {
00172   if (new_parent == (EggJointPointer *)NULL) {
00173     // No new parent; unparent the joint.
00174     EggGroupNode *egg_parent = _table->get_parent();
00175     if (egg_parent != (EggGroupNode *)NULL) {
00176       egg_parent->remove_child(_table.p());
00177     }
00178 
00179   } else {
00180     // Reparent the joint to its new parent (implicitly unparenting it
00181     // from its previous parent).
00182     EggMatrixTablePointer *new_node = DCAST(EggMatrixTablePointer, new_parent);
00183     if (new_node->_table != _table->get_parent()) {
00184       new_node->_table->add_child(_table.p());
00185     }
00186   }
00187 }
00188 
00189 ////////////////////////////////////////////////////////////////////
00190 //     Function: EggMatrixTablePointer::do_rebuild
00191 //       Access: Public, Virtual
00192 //  Description: Rebuilds the entire table all at once, based on the
00193 //               frames added by repeated calls to add_rebuild_frame()
00194 //               since the last call to begin_rebuild().
00195 //
00196 //               Until do_rebuild() is called, the animation table is
00197 //               not changed.
00198 //
00199 //               The return value is true if all frames are
00200 //               acceptable, or false if there is some problem.
00201 ////////////////////////////////////////////////////////////////////
00202 bool EggMatrixTablePointer::
00203 do_rebuild(EggCharacterDb &db) {
00204   LMatrix4d mat;
00205   if (!db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, 0, mat)) {
00206     // No rebuild frame; this is OK.
00207     return true;
00208   }
00209 
00210   if (_xform == (EggXfmSAnim *)NULL) {
00211     return false;
00212   }
00213 
00214   bool all_ok = true;
00215   
00216   _xform->clear_data();
00217   if (!_xform->add_data(mat)) {
00218     all_ok = false;
00219   }
00220 
00221   // Assume all frames will be contiguous.
00222   int n = 1;
00223   while (db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, n, mat)) {
00224     if (!_xform->add_data(mat)) {
00225       all_ok = false;
00226     }
00227     ++n;
00228   }
00229 
00230   return all_ok;
00231 }
00232 
00233 ////////////////////////////////////////////////////////////////////
00234 //     Function: EggMatrixTablePointer::optimize
00235 //       Access: Public, Virtual
00236 //  Description: Resets the table before writing to disk so that
00237 //               redundant rows (e.g. i { 1 1 1 1 1 1 1 1 }) are
00238 //               collapsed out.
00239 ////////////////////////////////////////////////////////////////////
00240 void EggMatrixTablePointer::
00241 optimize() {
00242   if (_xform != (EggXfmSAnim *)NULL) {
00243     _xform->optimize();
00244   }
00245 }
00246 
00247 ////////////////////////////////////////////////////////////////////
00248 //     Function: EggMatrixTablePointer::zero_channels
00249 //       Access: Public, Virtual
00250 //  Description: Zeroes out the named components of the transform in
00251 //               the animation frames.
00252 ////////////////////////////////////////////////////////////////////
00253 void EggMatrixTablePointer::
00254 zero_channels(const string &components) {
00255   if (_xform == (EggXfmSAnim *)NULL) {
00256     return;
00257   }
00258 
00259   // This is particularly easy: we only have to remove children from
00260   // the _xform object whose name is listed in the components.
00261   string::const_iterator si;
00262   for (si = components.begin(); si != components.end(); ++si) {
00263     string table_name(1, *si);
00264     EggNode *child = _xform->find_child(table_name);
00265     if (child != (EggNode *)NULL) {
00266       _xform->remove_child(child);
00267     }
00268   }
00269 }
00270 
00271 ////////////////////////////////////////////////////////////////////
00272 //     Function: EggMatrixTablePointer::quantize_channels
00273 //       Access: Public, Virtual
00274 //  Description: Rounds the named components of the transform to the
00275 //               nearest multiple of quantum.
00276 ////////////////////////////////////////////////////////////////////
00277 void EggMatrixTablePointer::
00278 quantize_channels(const string &components, double quantum) {
00279   if (_xform == (EggXfmSAnim *)NULL) {
00280     return;
00281   }
00282 
00283   // This is similar to the above: we quantize children of the _xform
00284   // object whose name is listed in the components.
00285   string::const_iterator si;
00286   for (si = components.begin(); si != components.end(); ++si) {
00287     string table_name(1, *si);
00288     EggNode *child = _xform->find_child(table_name);
00289     if (child != (EggNode *)NULL && 
00290         child->is_of_type(EggSAnimData::get_class_type())) {
00291       EggSAnimData *anim = DCAST(EggSAnimData, child);
00292       anim->quantize(quantum);
00293     }
00294   }
00295 }
00296 
00297 ////////////////////////////////////////////////////////////////////
00298 //     Function: EggMatrixTablePointer::make_new_joint
00299 //       Access: Public, Virtual
00300 //  Description: Creates a new child of the current joint in the
00301 //               egg data, and returns a pointer to it.
00302 ////////////////////////////////////////////////////////////////////
00303 EggJointPointer *EggMatrixTablePointer::
00304 make_new_joint(const string &name) {
00305   EggTable *new_table = new EggTable(name);
00306   _table->add_child(new_table);
00307   CoordinateSystem cs = CS_default;
00308   if (_xform != (EggXfmSAnim *)NULL) {
00309     cs = _xform->get_coordinate_system();
00310   }
00311   EggXfmSAnim *new_xform = new EggXfmSAnim("xform", cs);
00312   new_table->add_child(new_xform);
00313   new_xform->add_data(LMatrix4d::ident_mat());
00314 
00315   return new EggMatrixTablePointer(new_table);
00316 }
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: EggMatrixTablePointer::set_name
00320 //       Access: Public, Virtual
00321 //  Description: Applies the indicated name change to the egg file.
00322 ////////////////////////////////////////////////////////////////////
00323 void EggMatrixTablePointer::
00324 set_name(const string &name) {
00325   _table->set_name(name);
00326 }
 All Classes Functions Variables Enumerations