Panda3D
bamInfo.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file bamInfo.cxx
10  * @author drose
11  * @date 2000-07-02
12  */
13 
14 #include "bamInfo.h"
15 
16 #include "bamFile.h"
17 #include "pandaNode.h"
18 #include "geomNode.h"
19 #include "texture.h"
20 #include "recorderHeader.h"
21 #include "recorderFrame.h"
22 #include "recorderTable.h"
23 #include "dcast.h"
24 #include "pvector.h"
25 #include "bamCacheRecord.h"
26 #include "bamCacheIndex.h"
27 
28 /**
29  *
30  */
31 BamInfo::
32 BamInfo() {
33  set_program_brief("describe the contents of .bam files");
34  set_program_description
35  ("This program scans one or more Bam files--Panda's Binary Animation "
36  "and Models native binary format--and describes their contents.");
37 
38  clear_runlines();
39  add_runline("[opts] input.bam [input.bam ... ]");
40 
41  add_option
42  ("ls", "", 0,
43  "List the scene graph hierarchy in the bam file.",
44  &BamInfo::dispatch_none, &_ls);
45 
46  add_option
47  ("t", "", 0,
48  "List explicitly each transition in the hierarchy.",
49  &BamInfo::dispatch_none, &_verbose_transitions);
50 
51  add_option
52  ("g", "", 0,
53  "Output verbose information about the each Geom in the Bam file.",
54  &BamInfo::dispatch_none, &_verbose_geoms);
55 
56  _num_scene_graphs = 0;
57 }
58 
59 
60 /**
61  *
62  */
63 void BamInfo::
64 run() {
65  bool okflag = true;
66 
67  Filenames::const_iterator fi;
68  for (fi = _filenames.begin(); fi != _filenames.end(); ++fi) {
69  if (!get_info(*fi)) {
70  okflag = false;
71  }
72  }
73 
74  if (_num_scene_graphs > 0) {
75  nout << "\nScene graph statistics:\n";
76  _analyzer.write(nout, 2);
77  }
78  nout << "\n";
79 
80  if (!okflag) {
81  // Exit with an error if any of the files was unreadable.
82  exit(1);
83  }
84 }
85 
86 
87 /**
88  *
89  */
90 bool BamInfo::
91 handle_args(ProgramBase::Args &args) {
92  if (args.empty()) {
93  nout << "You must specify the Bam file(s) to read on the command line.\n";
94  return false;
95  }
96 
97  ProgramBase::Args::const_iterator ai;
98  for (ai = args.begin(); ai != args.end(); ++ai) {
99  _filenames.push_back(*ai);
100  }
101 
102  return true;
103 }
104 
105 
106 /**
107  * Reads a single Bam file and displays its contents. Returns true if
108  * successful, false on error.
109  */
110 bool BamInfo::
111 get_info(const Filename &filename) {
112  BamFile bam_file;
113 
114  if (!bam_file.open_read(filename)) {
115  nout << "Unable to read.\n";
116  return false;
117  }
118 
119  const char *endian = "little-endian";
120  if (bam_file.get_file_endian() == BamEnums::BE_bigendian) {
121  endian = "big-endian";
122  }
123  int float_width = 32;
124  if (bam_file.get_file_stdfloat_double()) {
125  float_width = 64;
126  }
127 
128  nout << filename << " : Bam version " << bam_file.get_file_major_ver()
129  << "." << bam_file.get_file_minor_ver()
130  << ", " << endian << ", " << float_width << "-bit floats.\n";
131 
132  Objects objects;
133  TypedWritable *object = bam_file.read_object();
134 
135  if (object != nullptr &&
136  object->is_exact_type(BamCacheRecord::get_class_type())) {
137  // Here's a special case: if the first object in the file is a
138  // BamCacheRecord, it's a cache data file; in this case, we output the
139  // cache record, and then pretend it doesn't exist.
140  DCAST(BamCacheRecord, object)->write(nout, 2);
141  nout << "\n";
142  object = bam_file.read_object();
143  }
144 
145  while (object != nullptr || !bam_file.is_eof()) {
146  if (object != nullptr) {
147  objects.push_back(object);
148  }
149  object = bam_file.read_object();
150  }
151  if (!bam_file.resolve()) {
152  nout << "Unable to fully resolve file.\n";
153  return false;
154  }
155 
156  // We can't close the bam file until we have examined the objects, since
157  // closing it will decrement reference counts.
158 
159  if (objects.size() == 1 &&
160  objects[0]->is_of_type(PandaNode::get_class_type())) {
161  describe_scene_graph(DCAST(PandaNode, objects[0]));
162 
163  } else if (objects.size() == 1 &&
164  objects[0]->is_of_type(Texture::get_class_type())) {
165  describe_texture(DCAST(Texture, objects[0]));
166 
167  } else if (objects.size() == 1 &&
168  objects[0]->is_of_type(BamCacheIndex::get_class_type())) {
169  describe_cache_index(DCAST(BamCacheIndex, objects[0]));
170 
171  } else if (!objects.empty() && objects[0]->is_of_type(RecorderHeader::get_class_type())) {
172  describe_session(DCAST(RecorderHeader, objects[0]), objects);
173 
174  } else {
175  nout << "file contains " << objects.size() << " objects:\n";
176  for (int i = 0; i < (int)objects.size(); i++) {
177  describe_general_object(objects[i]);
178  }
179  }
180 
181  return true;
182 }
183 
184 
185 /**
186  * Called for Bam files that contain a single scene graph and no other
187  * objects. This should describe that scene graph in some meaningful way.
188  */
189 void BamInfo::
190 describe_scene_graph(PandaNode *node) {
191  // Parent the node to our own scene graph root, so we can (a) guarantee it
192  // won't accidentally be deleted before we're done, (b) easily determine the
193  // bounding volume of the scene, and (c) report statistics on all the bam
194  // file's scene graphs together when we've finished.
195 
196  PT(PandaNode) root = new PandaNode("root");
197  root->add_child(node);
198  _num_scene_graphs++;
199 
200  int num_nodes = _analyzer.get_num_nodes();
201  _analyzer.add_node(node);
202  num_nodes = _analyzer.get_num_nodes() - num_nodes;
203 
204  nout << " " << num_nodes << " nodes, bounding volume is "
205  << *root->get_bounds() << "\n";
206 
207  if (_ls || _verbose_geoms || _verbose_transitions) {
208  list_hierarchy(node, 0);
209  }
210 }
211 
212 /**
213  * Called for Bam files that contain a Texture object.
214  */
215 void BamInfo::
216 describe_texture(Texture *tex) {
217  tex->write(nout, 2);
218 }
219 
220 /**
221  * Called for Bam files that contain a BamCacheIndex object.
222  */
223 void BamInfo::
224 describe_cache_index(BamCacheIndex *index) {
225  index->write(nout, 2);
226 }
227 
228 /**
229  * Called for Bam files that contain a recorded session table.
230  */
231 void BamInfo::
232 describe_session(RecorderHeader *header, const BamInfo::Objects &objects) {
233  char time_buffer[1024];
234  strftime(time_buffer, 1024, "%c",
235  localtime(&header->_start_time));
236 
237  pset<std::string> recorders;
238  double last_timestamp = 0.0;
239 
240  for (size_t i = 1; i < objects.size(); i++) {
241  if (objects[i]->is_of_type(RecorderFrame::get_class_type())) {
242  RecorderFrame *frame = DCAST(RecorderFrame, objects[i]);
243  if (frame->_table_changed) {
244  RecorderTable::Recorders::const_iterator ri;
245  for (ri = frame->_table->_recorders.begin();
246  ri != frame->_table->_recorders.end();
247  ++ri) {
248  recorders.insert((*ri).first);
249  }
250  }
251  last_timestamp = frame->_timestamp;
252  }
253  }
254 
255  nout << "Session, " << last_timestamp
256  << " secs, " << objects.size() - 1 << " frames, "
257  << time_buffer << ".\n"
258  << "Recorders:";
259  for (pset<std::string>::iterator ni = recorders.begin();
260  ni != recorders.end();
261  ++ni) {
262  nout << " " << (*ni);
263  }
264  nout << "\n";
265 }
266 
267 /**
268  * Called for Bam files that contain multiple objects which may or may not be
269  * scene graph nodes. This should describe each object in some meaningful
270  * way.
271  */
272 void BamInfo::
273 describe_general_object(TypedWritable *object) {
274  nassertv(object != nullptr);
275  nout << " " << object->get_type() << "\n";
276 }
277 
278 /**
279  * Outputs the hierarchy and all of the verbose GeomNode information.
280  */
281 void BamInfo::
282 list_hierarchy(PandaNode *node, int indent_level) {
283  indent(nout, indent_level) << *node;
284 
285  if (_verbose_transitions) {
286  nout << "\n";
287  if (!node->get_transform()->is_identity()) {
288  node->get_transform()->write(nout, indent_level);
289  }
290  if (!node->get_state()->is_empty()) {
291  node->get_state()->write(nout, indent_level);
292  }
293  if (!node->get_effects()->is_empty()) {
294  node->get_effects()->write(nout, indent_level);
295  }
296 
297  } else {
298  if (!node->get_transform()->is_identity()) {
299  nout << " " << *node->get_transform();
300  }
301  if (!node->get_state()->is_empty()) {
302  nout << " " << *node->get_state();
303  }
304  if (!node->get_effects()->is_empty()) {
305  nout << " " << *node->get_effects();
306  }
307  nout << "\n";
308  }
309 
310  if (_verbose_geoms && node->is_geom_node()) {
311  GeomNode *geom_node;
312  DCAST_INTO_V(geom_node, node);
313  geom_node->write_verbose(nout, indent_level);
314  }
315 
316  int num_children = node->get_num_children();
317  for (int i = 0; i < num_children; i++) {
318  PandaNode *child = node->get_child(i);
319  list_hierarchy(child, indent_level + 2);
320  }
321 }
322 
323 int main(int argc, char *argv[]) {
324  BamInfo prog;
325  prog.parse_command_line(argc, argv);
326  prog.run();
327  return 0;
328 }
void write(std::ostream &out, int indent_level=0) const
Describes all the data collected.
The principle public interface to reading and writing Bam disk files.
Definition: bamFile.h:41
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
bool open_read(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated filename for reading.
Definition: bamFile.cxx:51
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
bool resolve()
This must be called after one or more objects have been read via calls to read_object() in order to r...
Definition: bamFile.cxx:110
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
int get_file_major_ver()
Returns the major version number of the file currently being read, or the system current major versio...
Definition: bamFile.cxx:264
void add_node(PandaNode *node)
Adds a new node to the set of data for analysis.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_file_stdfloat_double
Returns true if the file stores all "standard" floats as 64-bit doubles, or false if they are 32-bit ...
Definition: bamFile.h:79
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
This represents the in-memory index that records the list of files stored in the BamCache.
Definition: bamCacheIndex.h:33
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
bool is_eof() const
Returns true if the reader has reached end-of-file, false otherwise.
Definition: bamFile.cxx:98
void write_verbose(std::ostream &out, int indent_level) const
Writes a detailed description of all the Geoms in the node.
Definition: geomNode.cxx:799
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_file_endian
Returns the endian preference indicated by the Bam file currently being read or written.
Definition: bamFile.h:78
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This object represents one frame of data in the recorded session file.
Definition: recorderFrame.h:32
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This object contains the header information written out at the beginning of a recorded session file.
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2068
int get_file_minor_ver()
Returns the minor version number of the file currently being read, or the system current minor versio...
Definition: bamFile.cxx:277
TypedWritable * read_object()
Reads and returns the next object from the Bam file, or NULL if the end of the file has been reached,...
Definition: bamFile.cxx:85
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool write(const Filename &fullpath)
Writes the texture to the named filename.
Definition: texture.I:298