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 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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This represents the in-memory index that records the list of files stored in the BamCache.
Definition: bamCacheIndex.h:33
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
The principle public interface to reading and writing Bam disk files.
Definition: bamFile.h:41
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
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
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
get_file_endian
Returns the endian preference indicated by the Bam file currently being read or written.
Definition: bamFile.h:78
bool open_read(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated filename for reading.
Definition: bamFile.cxx:51
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
bool is_eof() const
Returns true if the reader has reached end-of-file, false otherwise.
Definition: bamFile.cxx:98
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
void write_verbose(std::ostream &out, int indent_level) const
Writes a detailed description of all the Geoms in the node.
Definition: geomNode.cxx:801
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2062
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
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_...
This object represents one frame of data in the recorded session file.
Definition: recorderFrame.h:32
This object contains the header information written out at the beginning of a recorded session file.
void add_node(PandaNode *node)
Adds a new node to the set of data for analysis.
void write(std::ostream &out, int indent_level=0) const
Describes all the data collected.
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
bool write(const Filename &fullpath)
Writes the texture to the named filename.
Definition: texture.I:298
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.