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