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