00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00032
00033
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
00065
00066
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
00087 exit(1);
00088 }
00089 }
00090
00091
00092
00093
00094
00095
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
00115
00116
00117
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
00147
00148
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
00166
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
00196
00197
00198
00199
00200
00201 void BamInfo::
00202 describe_scene_graph(PandaNode *node) {
00203
00204
00205
00206
00207
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
00227
00228
00229
00230 void BamInfo::
00231 describe_texture(Texture *tex) {
00232 tex->write(nout, 2);
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 void BamInfo::
00242 describe_cache_index(BamCacheIndex *index) {
00243 index->write(nout, 2);
00244 }
00245
00246
00247
00248
00249
00250
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
00290
00291
00292
00293
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
00303
00304
00305
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
00351 pystub();
00352
00353 BamInfo prog;
00354 prog.parse_command_line(argc, argv);
00355 prog.run();
00356 return 0;
00357 }