Panda3D
|
00001 // Filename: animBundleMaker.cxx 00002 // Created by: drose (22Feb99) 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 "animBundleMaker.h" 00016 #include "config_egg2pg.h" 00017 00018 #include "eggTable.h" 00019 #include "eggAnimData.h" 00020 #include "eggSAnimData.h" 00021 #include "eggXfmAnimData.h" 00022 #include "eggXfmSAnim.h" 00023 #include "eggGroupNode.h" 00024 #include "animBundle.h" 00025 #include "animBundleNode.h" 00026 #include "animChannelMatrixXfmTable.h" 00027 #include "animChannelScalarTable.h" 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // Function: AnimBundleMaker::Construtor 00031 // Access: Public 00032 // Description: 00033 //////////////////////////////////////////////////////////////////// 00034 AnimBundleMaker:: 00035 AnimBundleMaker(EggTable *root) : _root(root) { 00036 _fps = 0.0f; 00037 _num_frames = 1; 00038 00039 _ok_fps = true; 00040 _ok_num_frames = true; 00041 00042 inspect_tree(root); 00043 00044 if (!_ok_fps) { 00045 egg2pg_cat.warning() 00046 << "AnimBundle " << _root->get_name() 00047 << " specifies contradictory frame rates.\n"; 00048 } else if (_fps == 0.0f) { 00049 egg2pg_cat.warning() 00050 << "AnimBundle " << _root->get_name() 00051 << " does not specify a frame rate.\n"; 00052 _fps = 24.0f; 00053 } 00054 00055 if (!_ok_num_frames) { 00056 egg2pg_cat.warning() 00057 << "AnimBundle " << _root->get_name() 00058 << " specifies contradictory number of frames.\n"; 00059 } 00060 } 00061 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: AnimBundleMaker::make_node 00065 // Access: Public 00066 // Description: 00067 //////////////////////////////////////////////////////////////////// 00068 AnimBundleNode *AnimBundleMaker:: 00069 make_node() { 00070 return new AnimBundleNode(_root->get_name(), make_bundle()); 00071 } 00072 00073 //////////////////////////////////////////////////////////////////// 00074 // Function: AnimBundleMaker::make_bundle 00075 // Access: Private 00076 // Description: 00077 //////////////////////////////////////////////////////////////////// 00078 AnimBundle *AnimBundleMaker:: 00079 make_bundle() { 00080 AnimBundle *bundle = new AnimBundle(_root->get_name(), _fps, _num_frames); 00081 00082 EggTable::const_iterator ci; 00083 for (ci = _root->begin(); ci != _root->end(); ++ci) { 00084 if ((*ci)->is_of_type(EggTable::get_class_type())) { 00085 EggTable *child = DCAST(EggTable, *ci); 00086 build_hierarchy(child, bundle); 00087 } 00088 } 00089 00090 bundle->sort_descendants(); 00091 00092 return bundle; 00093 } 00094 00095 00096 //////////////////////////////////////////////////////////////////// 00097 // Function: AnimBundleMaker::inspect_tree 00098 // Access: Private 00099 // Description: Walks the egg tree, getting out the fps and the 00100 // number of frames. 00101 //////////////////////////////////////////////////////////////////// 00102 void AnimBundleMaker:: 00103 inspect_tree(EggNode *egg_node) { 00104 if (egg_node->is_of_type(EggAnimData::get_class_type())) { 00105 // Check frame rate. 00106 EggAnimData *egg_anim = DCAST(EggAnimData, egg_node); 00107 if (egg_anim->has_fps()) { 00108 if (_fps == 0.0f) { 00109 _fps = egg_anim->get_fps(); 00110 } else if (_fps != egg_anim->get_fps()) { 00111 // Whoops! This table differs in opinion from the other tables. 00112 _fps = min(_fps, (PN_stdfloat)egg_anim->get_fps()); 00113 _ok_fps = false; 00114 } 00115 } 00116 } 00117 00118 if (egg_node->is_of_type(EggXfmSAnim::get_class_type())) { 00119 // Check frame rate. 00120 EggXfmSAnim *egg_anim = DCAST(EggXfmSAnim, egg_node); 00121 if (egg_anim->has_fps()) { 00122 if (_fps == 0.0f) { 00123 _fps = egg_anim->get_fps(); 00124 } else if (_fps != egg_anim->get_fps()) { 00125 // Whoops! This table differs in opinion from the other tables. 00126 _fps = min(_fps, (PN_stdfloat)egg_anim->get_fps()); 00127 _ok_fps = false; 00128 } 00129 } 00130 } 00131 00132 if (egg_node->is_of_type(EggSAnimData::get_class_type())) { 00133 // Check number of frames. 00134 EggSAnimData *egg_anim = DCAST(EggSAnimData, egg_node); 00135 int num_frames = egg_anim->get_num_rows(); 00136 00137 if (num_frames > 1) { 00138 if (_num_frames == 1) { 00139 _num_frames = num_frames; 00140 } else if (_num_frames != num_frames) { 00141 // Whoops! Another disagreement. 00142 _num_frames = min(_num_frames, num_frames); 00143 _ok_num_frames = false; 00144 } 00145 } 00146 } 00147 00148 if (egg_node->is_of_type(EggXfmAnimData::get_class_type())) { 00149 // Check number of frames. 00150 EggXfmAnimData *egg_anim = DCAST(EggXfmAnimData, egg_node); 00151 int num_frames = egg_anim->get_num_rows(); 00152 00153 if (num_frames > 1) { 00154 if (_num_frames == 1) { 00155 _num_frames = num_frames; 00156 } else if (_num_frames != num_frames) { 00157 // Whoops! Another disagreement. 00158 _num_frames = min(_num_frames, num_frames); 00159 _ok_num_frames = false; 00160 } 00161 } 00162 } 00163 00164 if (egg_node->is_of_type(EggGroupNode::get_class_type())) { 00165 // Now recurse. 00166 EggGroupNode *group = DCAST(EggGroupNode, egg_node); 00167 EggGroupNode::const_iterator ci; 00168 for (ci = group->begin(); ci != group->end(); ++ci) { 00169 inspect_tree(*ci); 00170 } 00171 } 00172 } 00173 00174 00175 //////////////////////////////////////////////////////////////////// 00176 // Function: AnimBundleMaker::build_hierarchy 00177 // Access: Private 00178 // Description: Walks the egg tree again, creating the AnimChannels 00179 // as appropriate. 00180 //////////////////////////////////////////////////////////////////// 00181 void AnimBundleMaker:: 00182 build_hierarchy(EggTable *egg_table, AnimGroup *parent) { 00183 AnimGroup *this_node = NULL; 00184 00185 // First, scan the children of egg_table for anim data tables. If 00186 // any of them is named "xform", it's a special case--this one 00187 // stands for the egg_table node itself. Don't ask me why. 00188 00189 EggTable::const_iterator ci; 00190 for (ci = egg_table->begin(); ci != egg_table->end(); ++ci) { 00191 if ((*ci)->get_name() == "xform") { 00192 if (this_node == NULL) { 00193 this_node = create_xfm_channel((*ci), egg_table->get_name(), parent); 00194 } else { 00195 egg2pg_cat.warning() 00196 << "Duplicate xform table under node " 00197 << egg_table->get_name() << "\n"; 00198 } 00199 } 00200 } 00201 00202 // If none of them were named "xform", just create a plain old 00203 // AnimGroup. 00204 if (this_node == NULL) { 00205 this_node = new AnimGroup(parent, egg_table->get_name()); 00206 } 00207 00208 // Now walk the children again, creating any leftover tables, and 00209 // recursing. 00210 for (ci = egg_table->begin(); ci != egg_table->end(); ++ci) { 00211 if ((*ci)->get_name() == "xform") { 00212 // Skip this one. We already got it. 00213 } else if ((*ci)->is_of_type(EggSAnimData::get_class_type())) { 00214 EggSAnimData *egg_anim = DCAST(EggSAnimData, *ci); 00215 create_s_channel(egg_anim, egg_anim->get_name(), this_node); 00216 00217 } else if ((*ci)->is_of_type(EggTable::get_class_type())) { 00218 EggTable *child = DCAST(EggTable, *ci); 00219 build_hierarchy(child, this_node); 00220 } 00221 } 00222 } 00223 00224 00225 //////////////////////////////////////////////////////////////////// 00226 // Function: AnimBundleMaker::create_s_channel 00227 // Access: Private 00228 // Description: Creates an AnimChannelScalarTable corresponding to 00229 // the given EggSAnimData structure. 00230 //////////////////////////////////////////////////////////////////// 00231 AnimChannelScalarTable *AnimBundleMaker:: 00232 create_s_channel(EggSAnimData *egg_anim, const string &name, 00233 AnimGroup *parent) { 00234 AnimChannelScalarTable *table 00235 = new AnimChannelScalarTable(parent, name); 00236 00237 // First we have to copy the table data from PTA_double to 00238 // PTA_stdfloat. 00239 PTA_stdfloat new_data = PTA_stdfloat::empty_array(egg_anim->get_num_rows(), 00240 table->get_class_type()); 00241 for (int i = 0; i < egg_anim->get_num_rows(); i++) { 00242 new_data[i] = (PN_stdfloat)egg_anim->get_value(i); 00243 } 00244 00245 // Now we can assign the table. 00246 table->set_table(new_data); 00247 00248 return table; 00249 } 00250 00251 00252 //////////////////////////////////////////////////////////////////// 00253 // Function: AnimBundleMaker::create_xfm_channel (EggNode) 00254 // Access: Private 00255 // Description: Creates an AnimChannelMatrixXfmTable corresponding to 00256 // the given EggNode structure, if possible. 00257 //////////////////////////////////////////////////////////////////// 00258 AnimChannelMatrixXfmTable *AnimBundleMaker:: 00259 create_xfm_channel(EggNode *egg_node, const string &name, 00260 AnimGroup *parent) { 00261 if (egg_node->is_of_type(EggXfmAnimData::get_class_type())) { 00262 EggXfmAnimData *egg_anim = DCAST(EggXfmAnimData, egg_node); 00263 EggXfmSAnim new_anim(*egg_anim); 00264 return create_xfm_channel(&new_anim, name, parent); 00265 00266 } else if (egg_node->is_of_type(EggXfmSAnim::get_class_type())) { 00267 EggXfmSAnim *egg_anim = DCAST(EggXfmSAnim, egg_node); 00268 return create_xfm_channel(egg_anim, name, parent); 00269 } 00270 00271 egg2pg_cat.warning() 00272 << "Inappropriate node named xform under node " 00273 << name << "\n"; 00274 return NULL; 00275 } 00276 00277 00278 //////////////////////////////////////////////////////////////////// 00279 // Function: AnimBundleMaker::create_xfm_channel (EggXfmSAnim) 00280 // Access: Private 00281 // Description: Creates an AnimChannelMatrixXfmTable corresponding to 00282 // the given EggXfmSAnim structure. 00283 //////////////////////////////////////////////////////////////////// 00284 AnimChannelMatrixXfmTable *AnimBundleMaker:: 00285 create_xfm_channel(EggXfmSAnim *egg_anim, const string &name, 00286 AnimGroup *parent) { 00287 // Ensure that the anim table is optimal and that it is standard 00288 // order. 00289 egg_anim->optimize_to_standard_order(); 00290 00291 AnimChannelMatrixXfmTable *table 00292 = new AnimChannelMatrixXfmTable(parent, name); 00293 00294 // The EggXfmSAnim structure has a number of children which are 00295 // EggSAnimData tables. Each of these represents a separate 00296 // component of the transform data, and will be added to the table. 00297 00298 EggXfmSAnim::const_iterator ci; 00299 for (ci = egg_anim->begin(); ci != egg_anim->end(); ++ci) { 00300 if ((*ci)->is_of_type(EggSAnimData::get_class_type())) { 00301 EggSAnimData *child = DCAST(EggSAnimData, *ci); 00302 00303 if (child->get_name().empty()) { 00304 egg2pg_cat.warning() 00305 << "Unnamed subtable of <Xfm$Anim_S$> " << name 00306 << "\n"; 00307 } else { 00308 char table_id = child->get_name()[0]; 00309 00310 if (child->get_name().length() > 1 || 00311 !table->is_valid_id(table_id)) { 00312 egg2pg_cat.warning() 00313 << "Unexpected table name " << child->get_name() 00314 << ", child of " << name << "\n"; 00315 00316 } else if (table->has_table(table_id)) { 00317 egg2pg_cat.warning() 00318 << "Duplicate table definition for " << table_id 00319 << " under " << name << "\n"; 00320 00321 } else { 00322 00323 // Now we have to copy the table data from PTA_double to 00324 // PTA_stdfloat. 00325 PTA_stdfloat new_data=PTA_stdfloat::empty_array(child->get_num_rows(), 00326 table->get_class_type()); 00327 for (int i = 0; i < child->get_num_rows(); i++) { 00328 new_data[i] = (PN_stdfloat)child->get_value(i); 00329 } 00330 00331 // Now we can assign the table. 00332 table->set_table(table_id, new_data); 00333 } 00334 } 00335 } 00336 } 00337 00338 return table; 00339 }