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