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

panda/src/egg/eggXfmSAnim.cxx

Go to the documentation of this file.
00001 // Filename: eggXfmSAnim.cxx
00002 // Created by:  drose (19Feb99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "eggXfmSAnim.h"
00020 #include "eggSAnimData.h"
00021 #include "eggXfmAnimData.h"
00022 #include "eggParameters.h"
00023 #include "config_egg.h"
00024 
00025 #include <indent.h>
00026 #include <compose_matrix.h>
00027 
00028 #include <math.h>
00029 
00030 TypeHandle EggXfmSAnim::_type_handle;
00031 
00032 //string EggXfmSAnim::_standard_order = "srpht";
00033 
00034 // For now, the standard order is sphrt.  This matches the old,
00035 // incorrect behavior of decompose_matrix().  When we have a new
00036 // egg-optchar, we can safely remove the old decompose_matrix() and
00037 // restore the correct standard order (above).
00038 string EggXfmSAnim::_standard_order = "sphrt";
00039 
00040 
00041 ////////////////////////////////////////////////////////////////////
00042 //     Function: EggXfmSAnim::Conversion constructor
00043 //       Access: Public
00044 //  Description: Converts the older-style XfmAnim table to the
00045 //               newer-style XfmSAnim table.
00046 ////////////////////////////////////////////////////////////////////
00047 EggXfmSAnim::
00048 EggXfmSAnim(const EggXfmAnimData &convert_from)
00049   : EggGroupNode(convert_from.get_name())
00050 {
00051   _has_fps = false;
00052   _coordsys = convert_from.get_coordinate_system();
00053 
00054   if (convert_from.has_order()) {
00055     set_order(convert_from.get_order());
00056   }
00057   if (convert_from.has_fps()) {
00058     set_fps(convert_from.get_fps());
00059   }
00060 
00061   const string &contents = convert_from.get_contents();
00062   for (int col = 0; col < convert_from.get_num_cols(); col++) {
00063     EggSAnimData *sanim = new EggSAnimData(contents.substr(col, 1));
00064     add_child(sanim);
00065     for (int row = 0; row < convert_from.get_num_rows(); row++) {
00066       sanim->add_data(convert_from.get_value(row, col));
00067     }
00068   }
00069 }
00070 
00071 ////////////////////////////////////////////////////////////////////
00072 //     Function: EggXfmSAnim::optimize
00073 //       Access: Public
00074 //  Description: Optimizes the table by collapsing redundant
00075 //               sub-tables.
00076 ////////////////////////////////////////////////////////////////////
00077 void EggXfmSAnim::
00078 optimize() {
00079   iterator ci = begin();
00080   while (ci != end()) {
00081     iterator ci_next = ci;
00082     ++ci_next;
00083 
00084     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00085       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00086       sanim->optimize();
00087 
00088       if (sanim->get_num_rows() == 1) {
00089         // If we've optimized down to one value, check to see if it is
00090         // a default value.
00091         double value = sanim->get_value(0);
00092         double default_value;
00093         if (sanim->has_name() && strchr("ijk", sanim->get_name()[0]) != NULL) {
00094           default_value = 1.0;
00095         } else {
00096           default_value = 0.0;
00097         }
00098 
00099         if (fabs(value - default_value) < egg_parameters->_table_threshold) {
00100           // It's a default-valued table, and therefore redundant:
00101           // remove it.
00102           erase(ci);
00103         }
00104       }
00105     }
00106 
00107     ci = ci_next;
00108   }
00109 }
00110 
00111 ////////////////////////////////////////////////////////////////////
00112 //     Function: EggXfmSAnim::optimize_to_standard_order
00113 //       Access: Public
00114 //  Description: Optimizes the table by collapsing redundant
00115 //               sub-tables, and simultaneously ensures that the order
00116 //               string is the standard order (which is the same as
00117 //               that supported by compose_matrix() and
00118 //               decompose_matrix()).
00119 ////////////////////////////////////////////////////////////////////
00120 void EggXfmSAnim::
00121 optimize_to_standard_order() {
00122   if (get_order() != get_standard_order()) {
00123     normalize_by_rebuilding();
00124   }
00125   optimize();
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 //     Function: EggXfmSAnim::normalize
00130 //       Access: Public
00131 //  Description: The inverse operation of optimize(), this ensures
00132 //               that all the sub-tables have the same length by
00133 //               duplicating rows as necessary.  This is needed before
00134 //               doing operations like add_data() or set_value() on an
00135 //               existing table.
00136 ////////////////////////////////////////////////////////////////////
00137 void EggXfmSAnim::
00138 normalize() {
00139   if (get_order() != get_standard_order()) {
00140     // If our order string is wrong, we must fix it now.  This will
00141     // incidentally also normalize the table, because we are totally
00142     // rebuilding it.
00143     normalize_by_rebuilding();
00144 
00145   } else {
00146     // Otherwise, if the order string is already the standard order
00147     // string, we can do this the easy way (from a computational
00148     // standpoint), which is just to lengthen the tables directly.
00149     normalize_by_expanding();
00150   }
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: EggXfmSAnim::write
00155 //       Access: Public, Virtual
00156 //  Description: Writes the data to the indicated output stream in Egg
00157 //               format.
00158 ////////////////////////////////////////////////////////////////////
00159 void EggXfmSAnim::
00160 write(ostream &out, int indent_level) const {
00161   test_under_integrity();
00162 
00163   write_header(out, indent_level, "<Xfm$Anim_S$>");
00164 
00165   if (has_fps()) {
00166     indent(out, indent_level + 2) << "<Scalar> fps { " << get_fps() << " }\n";
00167   }
00168 
00169   if (has_order()) {
00170     indent(out, indent_level + 2)
00171       << "<Char*> order { " << get_order() << " }\n";
00172   }
00173 
00174   EggGroupNode::write(out, indent_level + 2);
00175   indent(out, indent_level) << "}\n";
00176 }
00177 
00178 
00179 ////////////////////////////////////////////////////////////////////
00180 //     Function: EggXfmSAnim::compose_with_order
00181 //       Access: Public, Static
00182 //  Description: Composes a matrix out of the nine individual
00183 //               components, respecting the order string.  The
00184 //               components will be applied in the order indicated by
00185 //               the string.
00186 ////////////////////////////////////////////////////////////////////
00187 void EggXfmSAnim::
00188 compose_with_order(LMatrix4d &mat,
00189                    const LVecBase3d &scale,
00190                    const LVecBase3d &hpr,
00191                    const LVecBase3d &trans,
00192                    const string &order,
00193                    CoordinateSystem cs) {
00194 
00195   mat = LMatrix4d::ident_mat();
00196 
00197   bool reverse_roll = false;
00198 
00199   if (order == "sphrt" && egg_support_old_anims) {
00200     // As a special case, if the order string is exactly "sphrt"
00201     // (which is what all our legacy anim files used), we interpret
00202     // roll in the opposite direction (as our legacy anim files did).
00203     reverse_roll = true;
00204   }
00205 
00206   string::const_iterator pi;
00207   for (pi = order.begin(); pi != order.end(); ++pi) {
00208     switch (*pi) {
00209     case 's':
00210       mat = mat * LMatrix4d::scale_mat(scale);
00211       break;
00212 
00213     case 'h':
00214       mat = mat * LMatrix4d::rotate_mat_normaxis(hpr[0], LVector3d::up(cs), cs);
00215       break;
00216 
00217     case 'p':
00218       mat = mat * LMatrix4d::rotate_mat_normaxis(hpr[1], LVector3d::right(cs), cs);
00219       break;
00220 
00221     case 'r':
00222       if (reverse_roll) {
00223         mat = mat * LMatrix4d::rotate_mat_normaxis(-hpr[2], LVector3d::forward(cs), cs);
00224       } else {
00225         mat = mat * LMatrix4d::rotate_mat_normaxis(hpr[2], LVector3d::forward(cs), cs);
00226       }
00227       break;
00228 
00229     case 't':
00230       mat = mat * LMatrix4d::translate_mat(trans);
00231       break;
00232 
00233     default:
00234       egg_cat.warning()
00235         << "Invalid letter in order string: " << *pi << "\n";
00236     }
00237   }
00238 }
00239 
00240 ////////////////////////////////////////////////////////////////////
00241 //     Function: EggXfmSAnim::get_num_rows
00242 //       Access: Public
00243 //  Description: Returns the effective number of rows in the table.
00244 //               This is actually the number of rows of the smallest
00245 //               subtable larger than one row.  This is a convenience
00246 //               function that treats the table of tables as if it
00247 //               were a single table of matrices.
00248 ////////////////////////////////////////////////////////////////////
00249 int EggXfmSAnim::
00250 get_num_rows() const {
00251   bool found_any = false;
00252   int min_rows = 1;
00253 
00254   const_iterator ci;
00255   for (ci = begin(); ci != end(); ++ci) {
00256     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00257       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00258       if (sanim->get_num_rows() > 1) {
00259         if (!found_any) {
00260           min_rows = sanim->get_num_rows();
00261 
00262         } else {
00263           min_rows = min(min_rows, sanim->get_num_rows());
00264         }
00265       }
00266     }
00267   }
00268 
00269   return min_rows;
00270 }
00271 
00272 ////////////////////////////////////////////////////////////////////
00273 //     Function: EggXfmSAnim::get_value
00274 //       Access: Public
00275 //  Description: Returns the value of the aggregate row of the table
00276 //               as a matrix.  This is a convenience function that
00277 //               treats the table of tables as if it were a single
00278 //               table of matrices.  It is an error to call this if
00279 //               any SAnimData children of this node have an improper
00280 //               name (e.g. not a single letter, or not one of
00281 //               "ijkhprxyz").
00282 ////////////////////////////////////////////////////////////////////
00283 void EggXfmSAnim::
00284 get_value(int row, LMatrix4d &mat) const {
00285   LVector3d scale(1.0, 1.0, 1.0);
00286   LVector3d hpr(0.0, 0.0, 0.0);
00287   LVector3d translate(0.0, 0.0, 0.0);
00288 
00289   const_iterator ci;
00290   for (ci = begin(); ci != end(); ++ci) {
00291     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00292       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00293 
00294       if (sanim->get_num_rows() == 0) {
00295         // If the table is totally empty, let's keep the default
00296         // value.
00297         break;
00298       }
00299 
00300       double value;
00301       if (sanim->get_num_rows() == 1) {
00302         value = sanim->get_value(0);
00303       } else {
00304         nassertv(row < sanim->get_num_rows());
00305         value = sanim->get_value(row);
00306       }
00307 
00308       // Each child SAnimData table should have a one-letter name.
00309       nassertv(sanim->get_name().length() == 1);
00310 
00311       switch (sanim->get_name()[0]) {
00312       case 'i':
00313         scale[0] = value;
00314         break;
00315 
00316       case 'j':
00317         scale[1] = value;
00318         break;
00319 
00320       case 'k':
00321         scale[2] = value;
00322         break;
00323 
00324       case 'h':
00325         hpr[0] = value;
00326         break;
00327 
00328       case 'p':
00329         hpr[1] = value;
00330         break;
00331 
00332       case 'r':
00333         hpr[2] = value;
00334         break;
00335 
00336       case 'x':
00337         translate[0] = value;
00338         break;
00339 
00340       case 'y':
00341         translate[1] = value;
00342         break;
00343 
00344       case 'z':
00345         translate[2] = value;
00346         break;
00347 
00348       default:
00349         // One of the child tables had an invalid name.
00350         nassertv(false);
00351       }
00352     }
00353   }
00354 
00355   // So now we've got the nine components; build a matrix.
00356   compose_with_order(mat, scale, hpr, translate, get_order(), _coordsys);
00357 }
00358 
00359 ////////////////////////////////////////////////////////////////////
00360 //     Function: EggXfmSAnim::set_value
00361 //       Access: Public
00362 //  Description: Replaces the indicated row of the table with the
00363 //               given matrix.
00364 //
00365 //               This function can only be called if all the
00366 //               constraints of add_data(), below, are met.  Call
00367 //               normalize() first if you are not sure.
00368 //
00369 //               The return value is true if the matrix can be
00370 //               decomposed and stored as scale, rotate, and
00371 //               translate, or false otherwise.
00372 ////////////////////////////////////////////////////////////////////
00373 bool EggXfmSAnim::
00374 set_value(int row, const LMatrix4d &mat) {
00375   nassertr(get_order() == get_standard_order(), false);
00376 
00377   LVector3d scale, hpr, translate;
00378   bool result = decompose_matrix(mat, scale, hpr, translate, _coordsys);
00379   if (!result) {
00380     return false;
00381   }
00382 
00383   // Sanity check our sub-tables.
00384 #ifndef NDEBUG
00385   int table_length = -1;
00386   int num_tables = 0;
00387 #endif
00388 
00389   const_iterator ci;
00390   for (ci = begin(); ci != end(); ++ci) {
00391     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00392       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00393 
00394 #ifndef NDEBUG
00395       num_tables++;
00396 
00397       // Each table must have the same length.
00398       if (table_length < 0) {
00399         table_length = sanim->get_num_rows();
00400       } else {
00401         nassertr(sanim->get_num_rows() == table_length, false);
00402       }
00403 #endif
00404 
00405       // Each child SAnimData table should have a one-letter name.
00406       nassertr(sanim->get_name().length() == 1, false);
00407 
00408       switch (sanim->get_name()[0]) {
00409       case 'i':
00410         sanim->set_value(row, scale[0]);
00411         break;
00412 
00413       case 'j':
00414         sanim->set_value(row, scale[1]);
00415         break;
00416 
00417       case 'k':
00418         sanim->set_value(row, scale[2]);
00419         break;
00420 
00421       case 'h':
00422         sanim->set_value(row, hpr[0]);
00423         break;
00424 
00425       case 'p':
00426         sanim->set_value(row, hpr[1]);
00427         break;
00428 
00429       case 'r':
00430         sanim->set_value(row, hpr[2]);
00431         break;
00432 
00433       case 'x':
00434         sanim->set_value(row, translate[0]);
00435         break;
00436 
00437       case 'y':
00438         sanim->set_value(row, translate[1]);
00439         break;
00440 
00441       case 'z':
00442         sanim->set_value(row, translate[2]);
00443         break;
00444 
00445       default:
00446         // One of the child tables had an invalid name.
00447         nassertr(false, false);
00448       }
00449     }
00450   }
00451 
00452   nassertr(num_tables == 9, false);
00453   return true;
00454 }
00455 
00456 ////////////////////////////////////////////////////////////////////
00457 //     Function: EggXfmSAnim::add_data
00458 //       Access: Public
00459 //  Description: Adds a new matrix to the table, by adding a new row
00460 //               to each of the subtables.
00461 //
00462 //               This is a convenience function that
00463 //               treats the table of tables as if it were a single
00464 //               table of matrices.  It is an error to call this if
00465 //               any SAnimData children of this node have an improper
00466 //               name (e.g. not a single letter, or not one of
00467 //               "ijkhprxyz").
00468 //
00469 //               This function has the further requirement that all
00470 //               nine of the subtables must exist and be of the same
00471 //               length.  Furthermore, the order string must be the
00472 //               standard order string, "ijkrphxyz", which matches the
00473 //               system compose_matrix() and decompose_matrix()
00474 //               functions.
00475 //
00476 //               Thus, you probably cannot take an existing
00477 //               EggXfmSAnim object and start adding matrices to the
00478 //               end; you must clear out the original data first.  (As
00479 //               a special exception, if no tables exist, they will be
00480 //               created.)  The method normalize() will do this for
00481 //               you on an existing EggXfmSAnim.
00482 //
00483 //               This function may fail silently if the matrix cannot
00484 //               be decomposed into scale, rotate, and translate.  In
00485 //               this case, nothing is done and the function returns
00486 //               false.
00487 ////////////////////////////////////////////////////////////////////
00488 bool EggXfmSAnim::
00489 add_data(const LMatrix4d &mat) {
00490   LVector3d scale, hpr, translate;
00491   bool result = decompose_matrix(mat, scale, hpr, translate, _coordsys);
00492   if (!result) {
00493     return false;
00494   }
00495 
00496   if (empty()) {
00497     // If we have no children, create all nine tables now.
00498     const char *table_ids = "ijkhprxyz";
00499     for (const char *p = table_ids; *p; p++) {
00500       EggSAnimData *sanim = new EggSAnimData(string(1, *p));
00501       add_child(sanim);
00502     }
00503 
00504     // Also insist on the correct ordering right off the bat.
00505     set_order(get_standard_order());
00506   }
00507 
00508   nassertr(get_order() == get_standard_order(), false);
00509 
00510 #ifndef NDEBUG
00511   int table_length = -1;
00512   int num_tables = 0;
00513 #endif
00514 
00515   const_iterator ci;
00516   for (ci = begin(); ci != end(); ++ci) {
00517     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00518       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00519 
00520 #ifndef NDEBUG
00521       num_tables++;
00522 
00523       // Each table must have the same length.
00524       if (table_length < 0) {
00525         table_length = sanim->get_num_rows();
00526       } else {
00527         nassertr(sanim->get_num_rows() == table_length, false);
00528       }
00529 #endif
00530 
00531       // Each child SAnimData table should have a one-letter name.
00532       nassertr(sanim->get_name().length() == 1, false);
00533 
00534       switch (sanim->get_name()[0]) {
00535       case 'i':
00536         sanim->add_data(scale[0]);
00537         break;
00538 
00539       case 'j':
00540         sanim->add_data(scale[1]);
00541         break;
00542 
00543       case 'k':
00544         sanim->add_data(scale[2]);
00545         break;
00546 
00547       case 'h':
00548         sanim->add_data(hpr[0]);
00549         break;
00550 
00551       case 'p':
00552         sanim->add_data(hpr[1]);
00553         break;
00554 
00555       case 'r':
00556         sanim->add_data(hpr[2]);
00557         break;
00558 
00559       case 'x':
00560         sanim->add_data(translate[0]);
00561         break;
00562 
00563       case 'y':
00564         sanim->add_data(translate[1]);
00565         break;
00566 
00567       case 'z':
00568         sanim->add_data(translate[2]);
00569         break;
00570 
00571       default:
00572         // One of the child tables had an invalid name.
00573         nassertr(false, false);
00574       }
00575     }
00576   }
00577 
00578   nassertr(num_tables == 9, false);
00579   return true;
00580 }
00581 
00582 ////////////////////////////////////////////////////////////////////
00583 //     Function: EggXfmSAnim::r_transform
00584 //       Access: Protected, Virtual
00585 //  Description: Applies the indicated transform to all the rows of
00586 //               the table.  This actually forces the generation of a
00587 //               totally new set of rows, and will quietly change the
00588 //               order to the standard order (if it is different).
00589 ////////////////////////////////////////////////////////////////////
00590 void EggXfmSAnim::
00591 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
00592             CoordinateSystem to_cs) {
00593   // We need to build an inverse matrix that doesn't reflect the
00594   // translation component.
00595   LMatrix4d inv1 = inv;
00596   inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
00597 
00598   // Save a temporary copy of the original data.
00599   EggXfmSAnim original;
00600   original.steal_children(*this);
00601   original = (*this);
00602 
00603   // Now we have no children, so our data is clear.  Rebuild it.
00604   if (to_cs != CS_default) {
00605     _coordsys = to_cs;
00606   }
00607 
00608   int num_rows = original.get_num_rows();
00609   LMatrix4d orig_mat;
00610   for (int r = 0; r < num_rows; r++) {
00611     original.get_value(r, orig_mat);
00612     bool result = add_data(inv1 * orig_mat * mat);
00613 
00614     // If this assertion fails, we attempted to transform by a skew
00615     // matrix or some such thing that cannot be represented in an anim
00616     // file.
00617     nassertv(result);
00618   }
00619 
00620   // Now clean out the redundant columns we created.
00621   optimize();
00622 }
00623 
00624 ////////////////////////////////////////////////////////////////////
00625 //     Function: EggXfmSAnim::r_mark_coordsys
00626 //       Access: Protected, Virtual
00627 //  Description: This is only called immediately after loading an egg
00628 //               file from disk, to propagate the value found in the
00629 //               CoordinateSystem entry (or the default Y-up
00630 //               coordinate system) to all nodes that care about what
00631 //               the coordinate system is.
00632 ////////////////////////////////////////////////////////////////////
00633 void EggXfmSAnim::
00634 r_mark_coordsys(CoordinateSystem cs) {
00635   _coordsys = cs;
00636 }
00637 
00638 ////////////////////////////////////////////////////////////////////
00639 //     Function: EggXfmSAnim::normalize_by_rebuilding
00640 //       Access: Private
00641 //  Description: One implementation of normalize() that rebuilds the
00642 //               entire table by composing and decomposing the rows.
00643 //               This has the advantage that it will also reset the
00644 //               order string to the standard order string, but it is
00645 //               more computationally intensive and is subject to
00646 //               roundoff error.
00647 ////////////////////////////////////////////////////////////////////
00648 void EggXfmSAnim::
00649 normalize_by_rebuilding() {
00650   // Save a temporary copy of the original data.
00651   EggXfmSAnim original;
00652   original.steal_children(*this);
00653   original = (*this);
00654 
00655   // Now we have no children, so our data is clear.  Rebuild it.
00656   int num_rows = original.get_num_rows();
00657   LMatrix4d orig_mat;
00658   for (int r = 0; r < num_rows; r++) {
00659     original.get_value(r, orig_mat);
00660     bool result = add_data(orig_mat);
00661 
00662     // If this assertion fails, we somehow got a matrix out of the
00663     // original table that we could not represent in the new table.
00664     // That shouldn't be possible; there's probably something wrong
00665     // in decompose_matrix().
00666     nassertv(result);
00667   }
00668 }
00669 
00670 ////////////////////////////////////////////////////////////////////
00671 //     Function: EggXfmSAnim::normalize_by_expanding
00672 //       Access: Private
00673 //  Description: Another implementation of normalize() that simply
00674 //               expands any one-row tables and creates default-valued
00675 //               tables where none were before.  This will not change
00676 //               the order string, but is much faster and does not
00677 //               introduce roundoff error.
00678 ////////////////////////////////////////////////////////////////////
00679 void EggXfmSAnim::
00680 normalize_by_expanding() {
00681   iterator ci;
00682 
00683   // First, determine which tables we already have, and how long they
00684   // are.
00685   int num_tables = 0;
00686   int table_length = 1;
00687   string remaining_tables = "ijkhprxyz";
00688 
00689   for (ci = begin(); ci != end(); ++ci) {
00690     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00691       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00692 
00693       nassertv(sanim->get_name().length() == 1);
00694       char name = sanim->get_name()[0];
00695       size_t p = remaining_tables.find(name);
00696       nassertv(p != string::npos);
00697       remaining_tables[p] = ' ';
00698 
00699       num_tables++;
00700       if (sanim->get_num_rows() > 1) {
00701         if (table_length == 1) {
00702           table_length = sanim->get_num_rows();
00703         } else {
00704           nassertv(sanim->get_num_rows() == table_length);
00705         }
00706       }
00707     }
00708   }
00709 
00710   if (num_tables < 9) {
00711     // Create new, default, children for each table we lack.
00712     for (size_t p = 0; p < remaining_tables.length(); p++) {
00713       if (remaining_tables[p] != ' ') {
00714         double default_value;
00715         switch (remaining_tables[p]) {
00716         case 'i':
00717         case 'j':
00718         case 'k':
00719           default_value = 1.0;
00720           break;
00721 
00722         default:
00723           default_value = 0.0;
00724         }
00725 
00726         string name(1, remaining_tables[p]);
00727         EggSAnimData *sanim = new EggSAnimData(name);
00728         add_child(sanim);
00729         sanim->add_data(default_value);
00730       }
00731     }
00732   }
00733 
00734   // Now expand any one-row tables as needed.
00735   for (ci = begin(); ci != end(); ++ci) {
00736     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00737       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00738       if (sanim->get_num_rows() == 1) {
00739         double value = sanim->get_value(0);
00740         for (int i = 1; i < table_length; i++) {
00741           sanim->add_data(value);
00742         }
00743       }
00744       nassertv(sanim->get_num_rows() == table_length);
00745     }
00746   }
00747 }

Generated on Fri May 2 00:38:06 2003 for Panda by doxygen1.3