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.");
39 add_runline(
"[opts] input.bam [input.bam ... ]");
43 "List the scene graph hierarchy in the bam file.",
44 &BamInfo::dispatch_none, &_ls);
48 "List explicitly each transition in the hierarchy.",
49 &BamInfo::dispatch_none, &_verbose_transitions);
53 "Output verbose information about the each Geom in the Bam file.",
54 &BamInfo::dispatch_none, &_verbose_geoms);
56 _num_scene_graphs = 0;
67 Filenames::const_iterator fi;
68 for (fi = _filenames.begin(); fi != _filenames.end(); ++fi) {
74 if (_num_scene_graphs > 0) {
75 nout <<
"\nScene graph statistics:\n";
76 _analyzer.
write(nout, 2);
93 nout <<
"You must specify the Bam file(s) to read on the command line.\n";
97 ProgramBase::Args::const_iterator ai;
98 for (ai = args.begin(); ai != args.end(); ++ai) {
99 _filenames.push_back(*ai);
111 get_info(
const Filename &filename) {
115 nout <<
"Unable to read.\n";
119 const char *endian =
"little-endian";
121 endian =
"big-endian";
123 int float_width = 32;
130 <<
", " << endian <<
", " << float_width <<
"-bit floats.\n";
135 if (
object !=
nullptr &&
145 while (
object !=
nullptr || !bam_file.
is_eof()) {
146 if (
object !=
nullptr) {
147 objects.push_back(
object);
152 nout <<
"Unable to fully resolve file.\n";
159 if (objects.size() == 1 &&
160 objects[0]->is_of_type(PandaNode::get_class_type())) {
161 describe_scene_graph(DCAST(
PandaNode, objects[0]));
163 }
else if (objects.size() == 1 &&
164 objects[0]->is_of_type(Texture::get_class_type())) {
165 describe_texture(DCAST(
Texture, objects[0]));
167 }
else if (objects.size() == 1 &&
168 objects[0]->is_of_type(BamCacheIndex::get_class_type())) {
171 }
else if (!objects.empty() && objects[0]->is_of_type(RecorderHeader::get_class_type())) {
175 nout <<
"file contains " << objects.size() <<
" objects:\n";
176 for (
int i = 0; i < (int)objects.size(); i++) {
177 describe_general_object(objects[i]);
197 root->add_child(node);
200 int num_nodes = _analyzer.get_num_nodes();
202 num_nodes = _analyzer.get_num_nodes() - num_nodes;
204 nout <<
" " << num_nodes <<
" nodes, bounding volume is "
205 << *root->get_bounds() <<
"\n";
207 if (_ls || _verbose_geoms || _verbose_transitions) {
208 list_hierarchy(node, 0);
216 describe_texture(
Texture *tex) {
225 index->write(nout, 2);
233 char time_buffer[1024];
234 strftime(time_buffer, 1024,
"%c",
235 localtime(&header->_start_time));
238 double last_timestamp = 0.0;
240 for (
size_t i = 1; i < objects.size(); i++) {
241 if (objects[i]->is_of_type(RecorderFrame::get_class_type())) {
243 if (frame->_table_changed) {
244 RecorderTable::Recorders::const_iterator ri;
245 for (ri = frame->_table->_recorders.begin();
246 ri != frame->_table->_recorders.end();
248 recorders.insert((*ri).first);
251 last_timestamp = frame->_timestamp;
255 nout <<
"Session, " << last_timestamp
256 <<
" secs, " << objects.size() - 1 <<
" frames, "
257 << time_buffer <<
".\n"
260 ni != recorders.end();
262 nout <<
" " << (*ni);
274 nassertv(
object !=
nullptr);
275 nout <<
" " <<
object->get_type() <<
"\n";
282 list_hierarchy(
PandaNode *node,
int indent_level) {
283 indent(nout, indent_level) << *node;
285 if (_verbose_transitions) {
287 if (!node->get_transform()->is_identity()) {
288 node->get_transform()->write(nout, indent_level);
290 if (!node->get_state()->is_empty()) {
291 node->get_state()->write(nout, indent_level);
293 if (!node->get_effects()->is_empty()) {
294 node->get_effects()->write(nout, indent_level);
298 if (!node->get_transform()->is_identity()) {
299 nout <<
" " << *node->get_transform();
301 if (!node->get_state()->is_empty()) {
302 nout <<
" " << *node->get_state();
304 if (!node->get_effects()->is_empty()) {
305 nout <<
" " << *node->get_effects();
312 DCAST_INTO_V(geom_node, node);
317 for (
int i = 0; i < num_children; i++) {
319 list_hierarchy(child, indent_level + 2);
323 int main(
int argc,
char *argv[]) {