Panda3D
 All Classes Functions Variables Enumerations
eggXfmAnimData.cxx
00001 // Filename: eggXfmAnimData.cxx
00002 // Created by:  drose (19Feb99)
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 "eggXfmAnimData.h"
00016 #include "eggXfmSAnim.h"
00017 #include "eggSAnimData.h"
00018 #include "eggMiscFuncs.h"
00019 #include "config_egg.h"
00020 
00021 #include "indent.h"
00022 #include "luse.h"
00023 #include "lmatrix.h"
00024 #include "compose_matrix.h"
00025 #include "dcast.h"
00026 
00027 TypeHandle EggXfmAnimData::_type_handle;
00028 
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: EggXfmAnimData::Conversion constructor
00032 //       Access: Public
00033 //  Description: Converts the newer-style XfmSAnim table to the
00034 //               older-style XfmAnim table.
00035 ////////////////////////////////////////////////////////////////////
00036 EggXfmAnimData::
00037 EggXfmAnimData(const EggXfmSAnim &convert_from)
00038   : EggAnimData(convert_from.get_name())
00039 {
00040   if (convert_from.has_order()) {
00041     set_order(convert_from.get_order());
00042   }
00043   if (convert_from.has_fps()) {
00044     set_fps(convert_from.get_fps());
00045   }
00046   _coordsys = convert_from.get_coordinate_system();
00047 
00048   // First, get the table names so we know how to build up our
00049   // contents string.  Also store up the SAnim tables themselves in a
00050   // temporary vector for convenience.
00051 
00052   pvector<EggSAnimData *> subtables;
00053 
00054   EggXfmSAnim::const_iterator ci;
00055   for (ci = convert_from.begin(); ci != convert_from.end(); ++ci) {
00056     if ((*ci)->is_of_type(EggSAnimData::get_class_type())) {
00057       EggSAnimData *sanim = DCAST(EggSAnimData, *ci);
00058       nassertv(sanim->get_name().length() == 1);
00059 
00060       if (sanim->get_num_rows() > 0) {
00061         subtables.push_back(sanim);
00062         _contents += sanim->get_name()[0];
00063       }
00064     }
00065   }
00066 
00067   // Now, go through and extract out all the data.
00068   int num_rows = convert_from.get_num_rows();
00069   for (int row = 0; row < num_rows; row++) {
00070     for (int col = 0; col < (int)subtables.size(); col++) {
00071       EggSAnimData *sanim = subtables[col];
00072       if (sanim->get_num_rows() == 1) {
00073         add_data(sanim->get_value(0));
00074       } else {
00075         nassertv(row < sanim->get_num_rows());
00076         add_data(sanim->get_value(row));
00077       }
00078     }
00079   }
00080 }
00081 
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: EggXfmAnimData::get_value
00085 //       Access: Public
00086 //  Description: Returns the value of the aggregate row of the table
00087 //               as a matrix.  This is a convenience function that
00088 //               treats the 2-d table as if it were a single table of
00089 //               matrices.
00090 ////////////////////////////////////////////////////////////////////
00091 void EggXfmAnimData::
00092 get_value(int row, LMatrix4d &mat) const {
00093   LVector3d scale(1.0, 1.0, 1.0);
00094   LVector3d shear(0.0, 0.0, 0.0);
00095   LVector3d hpr(0.0, 0.0, 0.0);
00096   LVector3d translate(0.0, 0.0, 0.0);
00097 
00098   for (int col = 0; col < get_num_cols(); col++) {
00099     double value = get_value(row, col);
00100 
00101     switch (_contents[col]) {
00102     case 'i':
00103       scale[0] = value;
00104       break;
00105 
00106     case 'j':
00107       scale[1] = value;
00108       break;
00109 
00110     case 'k':
00111       scale[2] = value;
00112       break;
00113 
00114     case 'a':
00115       shear[0] = value;
00116       break;
00117       
00118     case 'b':
00119       shear[1] = value;
00120       break;
00121       
00122     case 'c':
00123       shear[2] = value;
00124       break;
00125 
00126     case 'h':
00127       hpr[0] = value;
00128       break;
00129 
00130     case 'p':
00131       hpr[1] = value;
00132       break;
00133 
00134     case 'r':
00135       hpr[2] = value;
00136       break;
00137 
00138     case 'x':
00139       translate[0] = value;
00140       break;
00141 
00142     case 'y':
00143       translate[1] = value;
00144       break;
00145 
00146     case 'z':
00147       translate[2] = value;
00148       break;
00149 
00150     default:
00151       // The contents string contained an invalid letter.
00152       nassertv(false);
00153     }
00154   }
00155 
00156   // So now we've got the twelve components; build a matrix.
00157   EggXfmSAnim::compose_with_order(mat, scale, shear, hpr, translate, get_order(),
00158                                   _coordsys);
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: EggXfmAnimData::is_anim_matrix
00163 //       Access: Public, Virtual
00164 //  Description: Returns true if this node represents a table of
00165 //               animation transformation data, false otherwise.
00166 ////////////////////////////////////////////////////////////////////
00167 bool EggXfmAnimData::
00168 is_anim_matrix() const {
00169   return true;
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: EggXfmAnimData::write
00174 //       Access: Public, Virtual
00175 //  Description: Writes the data to the indicated output stream in Egg
00176 //               format.
00177 ////////////////////////////////////////////////////////////////////
00178 void EggXfmAnimData::
00179 write(ostream &out, int indent_level) const {
00180   write_header(out, indent_level, "<Xfm$Anim>");
00181 
00182   if (has_fps()) {
00183     indent(out, indent_level + 2)
00184       << "<Scalar> fps { " << get_fps() << " }\n";
00185   }
00186 
00187   if (has_order()) {
00188     indent(out, indent_level + 2)
00189       << "<Char*> order { " << get_order() << " }\n";
00190   }
00191 
00192   if (has_contents()) {
00193     indent(out, indent_level + 2)
00194       << "<Char*> contents { " << get_contents() << " }\n";
00195   }
00196 
00197   indent(out, indent_level + 2) << "<V> {\n";
00198   write_long_list(out, indent_level + 4, _data.begin(), _data.end(),
00199         "", "", 72);
00200   indent(out, indent_level + 2) << "}\n";
00201   indent(out, indent_level) << "}\n";
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: EggXfmAnimData::r_transform
00206 //       Access: Protected, Virtual
00207 //  Description: Applies the indicated transform to all the rows of
00208 //               the table.  This actually forces the generation of a
00209 //               totally new set of rows.
00210 ////////////////////////////////////////////////////////////////////
00211 void EggXfmAnimData::
00212 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
00213             CoordinateSystem to_cs) {
00214   // We need to build an inverse matrix that doesn't reflect the
00215   // translation component.
00216   LMatrix4d inv1 = inv;
00217   inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
00218 
00219   // Now we build a temporary copy of the table as an EggXfmSAnim.  We
00220   // do this because this kind of table is easier to build and
00221   // optimize.
00222 
00223   if (to_cs == CS_default) {
00224     to_cs = _coordsys;
00225   }
00226 
00227   EggXfmSAnim new_table(get_name(), to_cs);
00228   if (has_fps()) {
00229     new_table.set_fps(get_fps());
00230   }
00231 
00232   // We insist on the standard order now.
00233   new_table.set_order(get_standard_order());
00234 
00235   // Now build up the data into the new table.
00236   LMatrix4d orig_mat;
00237   for (int r = 0; r < get_num_rows(); r++) {
00238     get_value(r, orig_mat);
00239     bool result = new_table.add_data(inv1 * orig_mat * mat);
00240 
00241     if (!result) {
00242       egg_cat.error()
00243         << "Transform from " << _coordsys << " to " << to_cs
00244         << " failed!\n";
00245       LVector3d scale, shear, hpr, trans;
00246       bool d = decompose_matrix(orig_mat, scale, shear, hpr, trans, _coordsys);
00247       egg_cat.error(false)
00248         << "orig:\n" << orig_mat
00249         << "d = " << d
00250         << "\n  scale: " << scale
00251         << "\n  shear: " << shear
00252         << "\n  hpr: " << hpr
00253         << "\n  trans: " << trans << "\n";
00254 
00255       LMatrix4d new_mat = inv1 * orig_mat * mat;
00256       d = decompose_matrix(new_mat, scale, shear, hpr, trans, to_cs);
00257       egg_cat.error(false)
00258         << "new:\n" << new_mat
00259         << "d = " << d
00260         << "\n  scale: " << scale
00261         << "\n  shear: " << shear
00262         << "\n  hpr: " << hpr
00263         << "\n  trans: " << trans << "\n";
00264     }
00265 
00266     // If this assertion fails, we attempted to transform by non-affine
00267     // matrix or some such thing that cannot be represented in an anim
00268     // file.
00269     nassertv(result);
00270   }
00271 
00272   // Now clean out the redundant columns we created.
00273   new_table.optimize();
00274 
00275   // And copy that back into EggXfmAnimData table form.
00276   EggXfmAnimData copy_table(new_table);
00277   (*this) = copy_table;
00278 }
00279 
00280 ////////////////////////////////////////////////////////////////////
00281 //     Function: EggXfmAnimData::r_mark_coordsys
00282 //       Access: Protected, Virtual
00283 //  Description: This is only called immediately after loading an egg
00284 //               file from disk, to propagate the value found in the
00285 //               CoordinateSystem entry (or the default Y-up
00286 //               coordinate system) to all nodes that care about what
00287 //               the coordinate system is.
00288 ////////////////////////////////////////////////////////////////////
00289 void EggXfmAnimData::
00290 r_mark_coordsys(CoordinateSystem cs) {
00291   _coordsys = cs;
00292 }
 All Classes Functions Variables Enumerations