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 nout << filename << " : Bam version " << bam_file.get_file_major_ver() 00129 << "." << bam_file.get_file_minor_ver() << "\n"; 00130 00131 Objects objects; 00132 TypedWritable *object = bam_file.read_object(); 00133 00134 if (object != (TypedWritable *)NULL && 00135 object->is_exact_type(BamCacheRecord::get_class_type())) { 00136 // Here's a special case: if the first object in the file is a 00137 // BamCacheRecord, it's a cache data file; in this case, we output 00138 // the cache record, and then pretend it doesn't exist. 00139 DCAST(BamCacheRecord, object)->write(nout, 2); 00140 nout << "\n"; 00141 object = bam_file.read_object(); 00142 } 00143 00144 while (object != (TypedWritable *)NULL || !bam_file.is_eof()) { 00145 if (object != (TypedWritable *)NULL) { 00146 objects.push_back(object); 00147 } 00148 object = bam_file.read_object(); 00149 } 00150 if (!bam_file.resolve()) { 00151 nout << "Unable to fully resolve file.\n"; 00152 return false; 00153 } 00154 00155 // We can't close the bam file until we have examined the objects, 00156 // since closing it will decrement reference counts. 00157 00158 if (objects.size() == 1 && 00159 objects[0]->is_of_type(PandaNode::get_class_type())) { 00160 describe_scene_graph(DCAST(PandaNode, objects[0])); 00161 00162 } else if (objects.size() == 1 && 00163 objects[0]->is_of_type(Texture::get_class_type())) { 00164 describe_texture(DCAST(Texture, objects[0])); 00165 00166 } else if (objects.size() == 1 && 00167 objects[0]->is_of_type(BamCacheIndex::get_class_type())) { 00168 describe_cache_index(DCAST(BamCacheIndex, objects[0])); 00169 00170 } else if (!objects.empty() && objects[0]->is_of_type(RecorderHeader::get_class_type())) { 00171 describe_session(DCAST(RecorderHeader, objects[0]), objects); 00172 00173 } else { 00174 nout << "file contains " << objects.size() << " objects:\n"; 00175 for (int i = 0; i < (int)objects.size(); i++) { 00176 describe_general_object(objects[i]); 00177 } 00178 } 00179 00180 return true; 00181 } 00182 00183 00184 //////////////////////////////////////////////////////////////////// 00185 // Function: BamInfo::describe_scene_graph 00186 // Access: Private 00187 // Description: Called for Bam files that contain a single scene 00188 // graph and no other objects. This should describe 00189 // that scene graph in some meaningful way. 00190 //////////////////////////////////////////////////////////////////// 00191 void BamInfo:: 00192 describe_scene_graph(PandaNode *node) { 00193 // Parent the node to our own scene graph root, so we can (a) 00194 // guarantee it won't accidentally be deleted before we're done, (b) 00195 // easily determine the bounding volume of the scene, and (c) report 00196 // statistics on all the bam file's scene graphs together when we've 00197 // finished. 00198 00199 PT(PandaNode) root = new PandaNode("root"); 00200 root->add_child(node); 00201 _num_scene_graphs++; 00202 00203 int num_nodes = _analyzer.get_num_nodes(); 00204 _analyzer.add_node(node); 00205 num_nodes = _analyzer.get_num_nodes() - num_nodes; 00206 00207 nout << " " << num_nodes << " nodes, bounding volume is " 00208 << *root->get_bounds() << "\n"; 00209 00210 if (_ls || _verbose_geoms || _verbose_transitions) { 00211 list_hierarchy(node, 0); 00212 } 00213 } 00214 00215 //////////////////////////////////////////////////////////////////// 00216 // Function: BamInfo::describe_texture 00217 // Access: Private 00218 // Description: Called for Bam files that contain a Texture object. 00219 //////////////////////////////////////////////////////////////////// 00220 void BamInfo:: 00221 describe_texture(Texture *tex) { 00222 tex->write(nout, 2); 00223 } 00224 00225 //////////////////////////////////////////////////////////////////// 00226 // Function: BamInfo::describe_cache_index 00227 // Access: Private 00228 // Description: Called for Bam files that contain a BamCacheIndex 00229 // object. 00230 //////////////////////////////////////////////////////////////////// 00231 void BamInfo:: 00232 describe_cache_index(BamCacheIndex *index) { 00233 index->write(nout, 2); 00234 } 00235 00236 //////////////////////////////////////////////////////////////////// 00237 // Function: BamInfo::describe_session 00238 // Access: Private 00239 // Description: Called for Bam files that contain a recorded session 00240 // table. 00241 //////////////////////////////////////////////////////////////////// 00242 void BamInfo:: 00243 describe_session(RecorderHeader *header, const BamInfo::Objects &objects) { 00244 char time_buffer[1024]; 00245 strftime(time_buffer, 1024, "%c", 00246 localtime(&header->_start_time)); 00247 00248 pset<string> recorders; 00249 double last_timestamp = 0.0; 00250 00251 for (size_t i = 1; i < objects.size(); i++) { 00252 if (objects[i]->is_of_type(RecorderFrame::get_class_type())) { 00253 RecorderFrame *frame = DCAST(RecorderFrame, objects[i]); 00254 if (frame->_table_changed) { 00255 RecorderTable::Recorders::const_iterator ri; 00256 for (ri = frame->_table->_recorders.begin(); 00257 ri != frame->_table->_recorders.end(); 00258 ++ri) { 00259 recorders.insert((*ri).first); 00260 } 00261 } 00262 last_timestamp = frame->_timestamp; 00263 } 00264 } 00265 00266 nout << "Session, " << last_timestamp 00267 << " secs, " << objects.size() - 1 << " frames, " 00268 << time_buffer << ".\n" 00269 << "Recorders:"; 00270 for (pset<string>::iterator ni = recorders.begin(); 00271 ni != recorders.end(); 00272 ++ni) { 00273 nout << " " << (*ni); 00274 } 00275 nout << "\n"; 00276 } 00277 00278 //////////////////////////////////////////////////////////////////// 00279 // Function: BamInfo::describe_general_object 00280 // Access: Private 00281 // Description: Called for Bam files that contain multiple objects 00282 // which may or may not be scene graph nodes. This 00283 // should describe each object in some meaningful way. 00284 //////////////////////////////////////////////////////////////////// 00285 void BamInfo:: 00286 describe_general_object(TypedWritable *object) { 00287 nassertv(object != (TypedWritable *)NULL); 00288 nout << " " << object->get_type() << "\n"; 00289 } 00290 00291 //////////////////////////////////////////////////////////////////// 00292 // Function: BamInfo::list_hierarchy 00293 // Access: Private 00294 // Description: Outputs the hierarchy and all of the verbose GeomNode 00295 // information. 00296 //////////////////////////////////////////////////////////////////// 00297 void BamInfo:: 00298 list_hierarchy(PandaNode *node, int indent_level) { 00299 indent(nout, indent_level) << *node; 00300 00301 if (_verbose_transitions) { 00302 nout << "\n"; 00303 if (!node->get_transform()->is_identity()) { 00304 node->get_transform()->write(nout, indent_level); 00305 } 00306 if (!node->get_state()->is_empty()) { 00307 node->get_state()->write(nout, indent_level); 00308 } 00309 if (!node->get_effects()->is_empty()) { 00310 node->get_effects()->write(nout, indent_level); 00311 } 00312 00313 } else { 00314 if (!node->get_transform()->is_identity()) { 00315 nout << " " << *node->get_transform(); 00316 } 00317 if (!node->get_state()->is_empty()) { 00318 nout << " " << *node->get_state(); 00319 } 00320 if (!node->get_effects()->is_empty()) { 00321 nout << " " << *node->get_effects(); 00322 } 00323 nout << "\n"; 00324 } 00325 00326 if (_verbose_geoms && node->is_geom_node()) { 00327 GeomNode *geom_node; 00328 DCAST_INTO_V(geom_node, node); 00329 geom_node->write_verbose(nout, indent_level); 00330 } 00331 00332 int num_children = node->get_num_children(); 00333 for (int i = 0; i < num_children; i++) { 00334 PandaNode *child = node->get_child(i); 00335 list_hierarchy(child, indent_level + 2); 00336 } 00337 } 00338 00339 int main(int argc, char *argv[]) { 00340 // A call to pystub() to force libpystub.so to be linked in. 00341 pystub(); 00342 00343 BamInfo prog; 00344 prog.parse_command_line(argc, argv); 00345 prog.run(); 00346 return 0; 00347 }