Panda3D
|
00001 // Filename: bamInfo.cxx 00002 // Created by: drose (02Jul00) 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 "bamInfo.h" 00016 00017 #include "bamFile.h" 00018 #include "pandaNode.h" 00019 #include "geomNode.h" 00020 #include "texture.h" 00021 #include "recorderHeader.h" 00022 #include "recorderFrame.h" 00023 #include "recorderTable.h" 00024 #include "dcast.h" 00025 #include "pvector.h" 00026 #include "bamCacheRecord.h" 00027 #include "bamCacheIndex.h" 00028 #include "pystub.h" 00029 00030 //////////////////////////////////////////////////////////////////// 00031 // Function: BamInfo::Constructor 00032 // Access: Public 00033 // Description: 00034 //////////////////////////////////////////////////////////////////// 00035 BamInfo:: 00036 BamInfo() { 00037 set_program_description 00038 ("This program scans one or more Bam files--Panda's Binary Animation " 00039 "and Models native binary format--and describes their contents."); 00040 00041 clear_runlines(); 00042 add_runline("[opts] input.bam [input.bam ... ]"); 00043 00044 add_option 00045 ("ls", "", 0, 00046 "List the scene graph hierarchy in the bam file.", 00047 &BamInfo::dispatch_none, &_ls); 00048 00049 add_option 00050 ("t", "", 0, 00051 "List explicitly each transition in the hierarchy.", 00052 &BamInfo::dispatch_none, &_verbose_transitions); 00053 00054 add_option 00055 ("g", "", 0, 00056 "Output verbose information about the each Geom in the Bam file.", 00057 &BamInfo::dispatch_none, &_verbose_geoms); 00058 00059 _num_scene_graphs = 0; 00060 } 00061 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: BamInfo::run 00065 // Access: Public 00066 // Description: 00067 //////////////////////////////////////////////////////////////////// 00068 void BamInfo:: 00069 run() { 00070 bool okflag = true; 00071 00072 Filenames::const_iterator fi; 00073 for (fi = _filenames.begin(); fi != _filenames.end(); ++fi) { 00074 if (!get_info(*fi)) { 00075 okflag = false; 00076 } 00077 } 00078 00079 if (_num_scene_graphs > 0) { 00080 nout << "\nScene graph statistics:\n"; 00081 _analyzer.write(nout, 2); 00082 } 00083 nout << "\n"; 00084 00085 if (!okflag) { 00086 // Exit with an error if any of the files was unreadable. 00087 exit(1); 00088 } 00089 } 00090 00091 00092 //////////////////////////////////////////////////////////////////// 00093 // Function: BamInfo::handle_args 00094 // Access: Protected, Virtual 00095 // Description: 00096 //////////////////////////////////////////////////////////////////// 00097 bool BamInfo:: 00098 handle_args(ProgramBase::Args &args) { 00099 if (args.empty()) { 00100 nout << "You must specify the Bam file(s) to read on the command line.\n"; 00101 return false; 00102 } 00103 00104 ProgramBase::Args::const_iterator ai; 00105 for (ai = args.begin(); ai != args.end(); ++ai) { 00106 _filenames.push_back(*ai); 00107 } 00108 00109 return true; 00110 } 00111 00112 00113 //////////////////////////////////////////////////////////////////// 00114 // Function: BamInfo::get_info 00115 // Access: Private 00116 // Description: Reads a single Bam file and displays its contents. 00117 // Returns true if successful, false on error. 00118 //////////////////////////////////////////////////////////////////// 00119 bool BamInfo:: 00120 get_info(const Filename &filename) { 00121 BamFile bam_file; 00122 00123 if (!bam_file.open_read(filename)) { 00124 nout << "Unable to read.\n"; 00125 return false; 00126 } 00127 00128 const char *endian = "little-endian"; 00129 if (bam_file.get_file_endian() == BamEnums::BE_bigendian) { 00130 endian = "big-endian"; 00131 } 00132 int float_width = 32; 00133 if (bam_file.get_file_stdfloat_double()) { 00134 float_width = 64; 00135 } 00136 00137 nout << filename << " : Bam version " << bam_file.get_file_major_ver() 00138 << "." << bam_file.get_file_minor_ver() 00139 << ", " << endian << ", " << float_width << "-bit floats.\n"; 00140 00141 Objects objects; 00142 TypedWritable *object = bam_file.read_object(); 00143 00144 if (object != (TypedWritable *)NULL && 00145 object->is_exact_type(BamCacheRecord::get_class_type())) { 00146 // Here's a special case: if the first object in the file is a 00147 // BamCacheRecord, it's a cache data file; in this case, we output 00148 // the cache record, and then pretend it doesn't exist. 00149 DCAST(BamCacheRecord, object)->write(nout, 2); 00150 nout << "\n"; 00151 object = bam_file.read_object(); 00152 } 00153 00154 while (object != (TypedWritable *)NULL || !bam_file.is_eof()) { 00155 if (object != (TypedWritable *)NULL) { 00156 objects.push_back(object); 00157 } 00158 object = bam_file.read_object(); 00159 } 00160 if (!bam_file.resolve()) { 00161 nout << "Unable to fully resolve file.\n"; 00162 return false; 00163 } 00164 00165 // We can't close the bam file until we have examined the objects, 00166 // since closing it will decrement reference counts. 00167 00168 if (objects.size() == 1 && 00169 objects[0]->is_of_type(PandaNode::get_class_type())) { 00170 describe_scene_graph(DCAST(PandaNode, objects[0])); 00171 00172 } else if (objects.size() == 1 && 00173 objects[0]->is_of_type(Texture::get_class_type())) { 00174 describe_texture(DCAST(Texture, objects[0])); 00175 00176 } else if (objects.size() == 1 && 00177 objects[0]->is_of_type(BamCacheIndex::get_class_type())) { 00178 describe_cache_index(DCAST(BamCacheIndex, objects[0])); 00179 00180 } else if (!objects.empty() && objects[0]->is_of_type(RecorderHeader::get_class_type())) { 00181 describe_session(DCAST(RecorderHeader, objects[0]), objects); 00182 00183 } else { 00184 nout << "file contains " << objects.size() << " objects:\n"; 00185 for (int i = 0; i < (int)objects.size(); i++) { 00186 describe_general_object(objects[i]); 00187 } 00188 } 00189 00190 return true; 00191 } 00192 00193 00194 //////////////////////////////////////////////////////////////////// 00195 // Function: BamInfo::describe_scene_graph 00196 // Access: Private 00197 // Description: Called for Bam files that contain a single scene 00198 // graph and no other objects. This should describe 00199 // that scene graph in some meaningful way. 00200 //////////////////////////////////////////////////////////////////// 00201 void BamInfo:: 00202 describe_scene_graph(PandaNode *node) { 00203 // Parent the node to our own scene graph root, so we can (a) 00204 // guarantee it won't accidentally be deleted before we're done, (b) 00205 // easily determine the bounding volume of the scene, and (c) report 00206 // statistics on all the bam file's scene graphs together when we've 00207 // finished. 00208 00209 PT(PandaNode) root = new PandaNode("root"); 00210 root->add_child(node); 00211 _num_scene_graphs++; 00212 00213 int num_nodes = _analyzer.get_num_nodes(); 00214 _analyzer.add_node(node); 00215 num_nodes = _analyzer.get_num_nodes() - num_nodes; 00216 00217 nout << " " << num_nodes << " nodes, bounding volume is " 00218 << *root->get_bounds() << "\n"; 00219 00220 if (_ls || _verbose_geoms || _verbose_transitions) { 00221 list_hierarchy(node, 0); 00222 } 00223 } 00224 00225 //////////////////////////////////////////////////////////////////// 00226 // Function: BamInfo::describe_texture 00227 // Access: Private 00228 // Description: Called for Bam files that contain a Texture object. 00229 //////////////////////////////////////////////////////////////////// 00230 void BamInfo:: 00231 describe_texture(Texture *tex) { 00232 tex->write(nout, 2); 00233 } 00234 00235 //////////////////////////////////////////////////////////////////// 00236 // Function: BamInfo::describe_cache_index 00237 // Access: Private 00238 // Description: Called for Bam files that contain a BamCacheIndex 00239 // object. 00240 //////////////////////////////////////////////////////////////////// 00241 void BamInfo:: 00242 describe_cache_index(BamCacheIndex *index) { 00243 index->write(nout, 2); 00244 } 00245 00246 //////////////////////////////////////////////////////////////////// 00247 // Function: BamInfo::describe_session 00248 // Access: Private 00249 // Description: Called for Bam files that contain a recorded session 00250 // table. 00251 //////////////////////////////////////////////////////////////////// 00252 void BamInfo:: 00253 describe_session(RecorderHeader *header, const BamInfo::Objects &objects) { 00254 char time_buffer[1024]; 00255 strftime(time_buffer, 1024, "%c", 00256 localtime(&header->_start_time)); 00257 00258 pset<string> recorders; 00259 double last_timestamp = 0.0; 00260 00261 for (size_t i = 1; i < objects.size(); i++) { 00262 if (objects[i]->is_of_type(RecorderFrame::get_class_type())) { 00263 RecorderFrame *frame = DCAST(RecorderFrame, objects[i]); 00264 if (frame->_table_changed) { 00265 RecorderTable::Recorders::const_iterator ri; 00266 for (ri = frame->_table->_recorders.begin(); 00267 ri != frame->_table->_recorders.end(); 00268 ++ri) { 00269 recorders.insert((*ri).first); 00270 } 00271 } 00272 last_timestamp = frame->_timestamp; 00273 } 00274 } 00275 00276 nout << "Session, " << last_timestamp 00277 << " secs, " << objects.size() - 1 << " frames, " 00278 << time_buffer << ".\n" 00279 << "Recorders:"; 00280 for (pset<string>::iterator ni = recorders.begin(); 00281 ni != recorders.end(); 00282 ++ni) { 00283 nout << " " << (*ni); 00284 } 00285 nout << "\n"; 00286 } 00287 00288 //////////////////////////////////////////////////////////////////// 00289 // Function: BamInfo::describe_general_object 00290 // Access: Private 00291 // Description: Called for Bam files that contain multiple objects 00292 // which may or may not be scene graph nodes. This 00293 // should describe each object in some meaningful way. 00294 //////////////////////////////////////////////////////////////////// 00295 void BamInfo:: 00296 describe_general_object(TypedWritable *object) { 00297 nassertv(object != (TypedWritable *)NULL); 00298 nout << " " << object->get_type() << "\n"; 00299 } 00300 00301 //////////////////////////////////////////////////////////////////// 00302 // Function: BamInfo::list_hierarchy 00303 // Access: Private 00304 // Description: Outputs the hierarchy and all of the verbose GeomNode 00305 // information. 00306 //////////////////////////////////////////////////////////////////// 00307 void BamInfo:: 00308 list_hierarchy(PandaNode *node, int indent_level) { 00309 indent(nout, indent_level) << *node; 00310 00311 if (_verbose_transitions) { 00312 nout << "\n"; 00313 if (!node->get_transform()->is_identity()) { 00314 node->get_transform()->write(nout, indent_level); 00315 } 00316 if (!node->get_state()->is_empty()) { 00317 node->get_state()->write(nout, indent_level); 00318 } 00319 if (!node->get_effects()->is_empty()) { 00320 node->get_effects()->write(nout, indent_level); 00321 } 00322 00323 } else { 00324 if (!node->get_transform()->is_identity()) { 00325 nout << " " << *node->get_transform(); 00326 } 00327 if (!node->get_state()->is_empty()) { 00328 nout << " " << *node->get_state(); 00329 } 00330 if (!node->get_effects()->is_empty()) { 00331 nout << " " << *node->get_effects(); 00332 } 00333 nout << "\n"; 00334 } 00335 00336 if (_verbose_geoms && node->is_geom_node()) { 00337 GeomNode *geom_node; 00338 DCAST_INTO_V(geom_node, node); 00339 geom_node->write_verbose(nout, indent_level); 00340 } 00341 00342 int num_children = node->get_num_children(); 00343 for (int i = 0; i < num_children; i++) { 00344 PandaNode *child = node->get_child(i); 00345 list_hierarchy(child, indent_level + 2); 00346 } 00347 } 00348 00349 int main(int argc, char *argv[]) { 00350 // A call to pystub() to force libpystub.so to be linked in. 00351 pystub(); 00352 00353 BamInfo prog; 00354 prog.parse_command_line(argc, argv); 00355 prog.run(); 00356 return 0; 00357 }