Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pgraph/sceneGraphAnalyzer.cxx

Go to the documentation of this file.
00001 // Filename: sceneGraphAnalyzer.cxx
00002 // Created by:  drose (02Jul00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "sceneGraphAnalyzer.h"
00020 #include "config_pgraph.h"
00021 
00022 #include "indent.h"
00023 #include "geomNode.h"
00024 #include "geom.h"
00025 #include "geomprimitives.h"
00026 #include "transformState.h"
00027 #include "textureAttrib.h"
00028 #include "pta_ushort.h"
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: SceneGraphAnalyzer::Constructor
00032 //       Access: Public
00033 //  Description:
00034 ////////////////////////////////////////////////////////////////////
00035 SceneGraphAnalyzer::
00036 SceneGraphAnalyzer() {
00037   clear();
00038 }
00039 
00040 ////////////////////////////////////////////////////////////////////
00041 //     Function: SceneGraphAnalyzer::Destructor
00042 //       Access: Public
00043 //  Description:
00044 ////////////////////////////////////////////////////////////////////
00045 SceneGraphAnalyzer::
00046 ~SceneGraphAnalyzer() {
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: SceneGraphAnalyzer::clear
00051 //       Access: Public
00052 //  Description: Resets all of the data in the analyzer in preparation
00053 //               for a new run.
00054 ////////////////////////////////////////////////////////////////////
00055 void SceneGraphAnalyzer::
00056 clear() {
00057   _nodes.clear();
00058   _textures.clear();
00059 
00060   _num_nodes = 0;
00061   _num_instances = 0;
00062   _num_transforms = 0;
00063   _num_nodes_with_attribs = 0;
00064   _num_geom_nodes = 0;
00065   _num_geoms = 0;
00066 
00067   _num_vertices = 0;
00068   _num_normals = 0;
00069   _num_texcoords = 0;
00070   _num_tris = 0;
00071   _num_quads = 0;
00072   _num_polys = 0;
00073   _num_lines = 0;
00074   _num_points = 0;
00075   _num_spheres = 0;
00076 
00077   _num_individual_tris = 0;
00078   _num_tristrips = 0;
00079   _num_triangles_in_strips = 0;
00080   _num_trifans = 0;
00081   _num_triangles_in_fans = 0;
00082 
00083   _texture_bytes = 0;
00084 
00085   _num_long_normals = 0;
00086   _num_short_normals = 0;
00087   _total_normal_length = 0.0f;
00088 }
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: SceneGraphAnalyzer::add_node
00092 //       Access: Public
00093 //  Description: Adds a new node to the set of data for analysis.
00094 //               Normally, this would only be called once, and passed
00095 //               the top of the scene graph, but it's possible to
00096 //               repeatedly pass in subgraphs to get an analysis of
00097 //               all the graphs together.
00098 ////////////////////////////////////////////////////////////////////
00099 void SceneGraphAnalyzer::
00100 add_node(PandaNode *node) {
00101   collect_statistics(node, false);
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: SceneGraphAnalyzer::write
00106 //       Access: Public
00107 //  Description: Describes all the data collected.
00108 ////////////////////////////////////////////////////////////////////
00109 void SceneGraphAnalyzer::
00110 write(ostream &out, int indent_level) const {
00111   indent(out, indent_level)
00112     << _num_nodes << " total nodes (including "
00113     << _num_instances << " instances).\n";
00114 
00115   indent(out, indent_level)
00116     << _num_transforms << " transforms";
00117 
00118   if (_num_nodes != 0) {
00119     out << "; " << 100 * _num_nodes_with_attribs / _num_nodes
00120         << "% of nodes have some render attribute.";
00121   }
00122   out << "\n";
00123 
00124   indent(out, indent_level)
00125     << _num_geoms << " Geoms appear on " << _num_geom_nodes << " GeomNodes.\n";
00126 
00127   indent(out, indent_level)
00128     << _num_vertices << " vertices, " << _num_normals << " normals, "
00129     << _num_texcoords << " texture coordinates.\n";
00130 
00131   if (_num_long_normals != 0 || _num_short_normals != 0) {
00132     indent(out, indent_level)
00133       << _num_long_normals << " normals are too long, "
00134       << _num_short_normals << " are too short.  Average normal length is "
00135       << _total_normal_length / (float)_num_normals << "\n";
00136   }
00137 
00138   indent(out, indent_level)
00139     << _num_tris << " triangles:\n";
00140   indent(out, indent_level + 2)
00141     << _num_triangles_in_strips
00142     << " of these are on " << _num_tristrips << " tristrips";
00143   if (_num_tristrips != 0) {
00144     out << " ("
00145         << (double)_num_triangles_in_strips / (double)_num_tristrips
00146         << " average tris per strip)";
00147   }
00148   out << ".\n";
00149 
00150   indent(out, indent_level + 2)
00151     << _num_triangles_in_fans
00152     << " of these are on " << _num_trifans << " trifans";
00153   if (_num_trifans != 0) {
00154     out << " ("
00155         << (double)_num_triangles_in_fans / (double)_num_trifans
00156         << " average tris per fan)";
00157   }
00158   out << ".\n";
00159 
00160   indent(out, indent_level + 2)
00161     << _num_individual_tris
00162     << " of these are independent triangles.\n";
00163 
00164   indent(out, indent_level)
00165     << _num_quads << " quads, " << _num_polys << " general polygons, "
00166     << _num_lines << " lines, " << _num_points << " points, "
00167     << _num_spheres << " spheres.\n";
00168 
00169   indent(out, indent_level)
00170     << _textures.size() << " textures, estimated minimum "
00171     << (_texture_bytes + 1023) / 1024 << "K texture memory required.\n";
00172 }
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: SceneGraphAnalyzer::collect_statistics
00176 //       Access: Private
00177 //  Description: Recursively visits each node, counting up the
00178 //               statistics.
00179 ////////////////////////////////////////////////////////////////////
00180 void SceneGraphAnalyzer::
00181 collect_statistics(PandaNode *node, bool under_instance) {
00182   _num_nodes++;
00183 
00184   if (!under_instance) {
00185     Nodes::iterator ni = _nodes.find(node);
00186     if (ni == _nodes.end()) {
00187       // This is the first time this node has been encountered.
00188       _nodes.insert(Nodes::value_type(node, 1));
00189     } else {
00190       // This node has been encountered before; that makes it an
00191       // instance.
00192       (*ni).second++;
00193       _num_instances++;
00194       under_instance = true;
00195     }
00196   }
00197 
00198   if (!node->get_state()->is_empty()) {
00199     _num_nodes_with_attribs++;
00200     const RenderAttrib *attrib = 
00201       node->get_attrib(TextureAttrib::get_class_type());
00202     if (attrib != (RenderAttrib *)NULL) {
00203       const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
00204       if (!ta->is_off()) {
00205         collect_statistics(ta->get_texture());
00206       }
00207     }      
00208   }
00209   if (!node->get_transform()->is_identity()) {
00210     _num_transforms++;
00211   }
00212 
00213   if (node->is_geom_node()) {
00214     collect_statistics(DCAST(GeomNode, node));
00215   }
00216 
00217   int num_children = node->get_num_children();
00218   for (int i = 0; i < num_children; i++) {
00219     PandaNode *child = node->get_child(i);
00220     collect_statistics(child, under_instance);
00221   }
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: SceneGraphAnalyzer::collect_statistics
00226 //       Access: Private
00227 //  Description: Recursively visits each node, counting up the
00228 //               statistics.
00229 ////////////////////////////////////////////////////////////////////
00230 void SceneGraphAnalyzer::
00231 collect_statistics(GeomNode *geom_node) {
00232   nassertv(geom_node != (GeomNode *)NULL);
00233 
00234   _num_geom_nodes++;
00235 
00236   int num_geoms = geom_node->get_num_geoms();
00237   _num_geoms += num_geoms;
00238 
00239   for (int i = 0; i < num_geoms; i++) {
00240     Geom *geom = geom_node->get_geom(i);
00241     collect_statistics(DCAST(Geom, geom));
00242 
00243     const RenderState *geom_state = geom_node->get_geom_state(i);
00244 
00245     const RenderAttrib *attrib = 
00246       geom_state->get_attrib(TextureAttrib::get_class_type());
00247     if (attrib != (RenderAttrib *)NULL) {
00248       const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
00249       if (!ta->is_off()) {
00250         collect_statistics(ta->get_texture());
00251       }
00252     }      
00253   }
00254 }
00255 
00256 ////////////////////////////////////////////////////////////////////
00257 //     Function: SceneGraphAnalyzer::collect_statistics
00258 //       Access: Private
00259 //  Description: Recursively visits each node, counting up the
00260 //               statistics.
00261 ////////////////////////////////////////////////////////////////////
00262 void SceneGraphAnalyzer::
00263 collect_statistics(Geom *geom) {
00264   int num_prims;
00265   int num_verts;
00266   int num_components;
00267 
00268   num_prims = geom->get_num_prims();
00269   if (geom->uses_components()) {
00270     num_verts = 0;
00271     num_components = 0;
00272     for (int i = 0; i < num_prims; i++) {
00273       num_verts += geom->get_length(i);
00274       num_components += (geom->get_length(i) - geom->get_num_more_vertices_than_components());
00275     }
00276   } else {
00277     num_verts = num_prims * geom->get_num_vertices_per_prim();
00278     num_components = 1;
00279   }
00280 
00281   _num_vertices += num_verts;
00282 
00283   PTA_Normalf norms;
00284   GeomBindType nbind;
00285   PTA_ushort nindex;
00286   geom->get_normals(norms, nbind, nindex);
00287 
00288   switch (nbind) {
00289   case G_OVERALL:
00290     consider_normals(norms, nindex, 1);
00291     break;
00292 
00293   case G_PER_PRIM:
00294     consider_normals(norms, nindex, num_prims);
00295     break;
00296 
00297   case G_PER_COMPONENT:
00298     consider_normals(norms, nindex, num_components);
00299     break;
00300 
00301   case G_PER_VERTEX:
00302     consider_normals(norms, nindex, num_verts);
00303     break;
00304 
00305   case G_OFF:
00306     break;
00307   }
00308 
00309   if (geom->get_binding(G_TEXCOORD) == G_PER_VERTEX) {
00310     _num_texcoords += num_verts;
00311   }
00312 
00313   if (geom->is_of_type(GeomPoint::get_class_type())) {
00314     _num_points += num_verts;
00315 
00316   } else if (geom->is_of_type(GeomLine::get_class_type())) {
00317     _num_lines += num_prims;
00318 
00319   } else if (geom->is_of_type(GeomLinestrip::get_class_type())) {
00320     _num_lines += num_components;
00321 
00322   } else if (geom->is_of_type(GeomPolygon::get_class_type())) {
00323     _num_polys += num_prims;
00324 
00325   } else if (geom->is_of_type(GeomQuad::get_class_type())) {
00326     _num_quads += num_prims;
00327 
00328   } else if (geom->is_of_type(GeomTri::get_class_type())) {
00329     _num_tris += num_prims;
00330     _num_individual_tris += num_prims;
00331 
00332   } else if (geom->is_of_type(GeomTristrip::get_class_type())) {
00333     _num_tris += num_components;
00334     _num_tristrips += num_prims;
00335     _num_triangles_in_strips += num_components;
00336 
00337   } else if (geom->is_of_type(GeomTrifan::get_class_type())) {
00338     _num_tris += num_components;
00339     _num_trifans += num_prims;
00340     _num_triangles_in_fans += num_components;
00341 
00342   } else if (geom->is_of_type(GeomSphere::get_class_type())) {
00343     _num_spheres += num_prims;
00344 
00345   } else {
00346     pgraph_cat.warning()
00347       << "Unknown GeomType in SceneGraphAnalyzer: "
00348       << geom->get_type() << "\n";
00349   }
00350 }
00351 
00352 ////////////////////////////////////////////////////////////////////
00353 //     Function: SceneGraphAnalyzer::collect_statistics
00354 //       Access: Private
00355 //  Description: Recursively visits each node, counting up the
00356 //               statistics.
00357 ////////////////////////////////////////////////////////////////////
00358 void SceneGraphAnalyzer::
00359 collect_statistics(Texture *texture) {
00360   nassertv(texture != (Texture *)NULL);
00361 
00362   Textures::iterator ti = _textures.find(texture);
00363   if (ti == _textures.end()) {
00364     // This is the first time this texture has been encountered.
00365     _textures.insert(Textures::value_type(texture, 1));
00366 
00367     // Attempt to guess how many bytes of texture memory this one
00368     // requires.
00369     PixelBuffer *pb = texture->_pbuffer;
00370     if (pb != (PixelBuffer *)NULL) {
00371       int bytes =
00372         pb->get_xsize() * pb->get_ysize() * pb->get_num_components() *
00373         pb->get_component_width();
00374 
00375       if (texture->uses_mipmaps()) {
00376         bytes *= 4/3;
00377       }
00378 
00379       _texture_bytes += bytes;
00380     }
00381 
00382   } else {
00383     // This texture has been encountered before; don't count it again.
00384     (*ti).second++;
00385   }
00386 }
00387 
00388 ////////////////////////////////////////////////////////////////////
00389 //     Function: SceneGraphAnalyzer::consider_normals
00390 //       Access: Private
00391 //  Description: Examines the indicated set of normals.
00392 ////////////////////////////////////////////////////////////////////
00393 void SceneGraphAnalyzer::
00394 consider_normals(const Normalf *norms, const unsigned short *nindex,
00395                  int num) {
00396   _num_normals += num;
00397 
00398   if (nindex != (const unsigned short *)NULL) {
00399     // An indexed array.
00400     for (int i = 0; i < num; i++) {
00401       const Normalf &norm = norms[nindex[i]];
00402       float l = norm.length();
00403       if (IS_THRESHOLD_EQUAL(l, 1.0f, 0.01f)) {
00404         // This normal is close enough to unit length to be ok.
00405       } else if (l > 1.0f) {
00406         _num_long_normals++;
00407       } else { // l < 1.0f
00408         _num_short_normals++;
00409       }
00410       _total_normal_length += l;
00411     }
00412   } else {
00413     // A nonindexed array.
00414     for (int i = 0; i < num; i++) {
00415       const Normalf &norm = norms[i];
00416       float l = norm.length();
00417       if (IS_THRESHOLD_EQUAL(l, 1.0f, 0.01f)) {
00418         // This normal is close enough to unit length to be ok.
00419       } else if (l > 1.0f) {
00420         _num_long_normals++;
00421       } else { // l < 1.0
00422         _num_short_normals++;
00423       }
00424       _total_normal_length += l;
00425     }
00426   }
00427 }

Generated on Fri May 2 00:42:20 2003 for Panda by doxygen1.3