Panda3D

bamInfo.cxx

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 }
 All Classes Functions Variables Enumerations