00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00032
00033
00034
00035 SceneGraphAnalyzer::
00036 SceneGraphAnalyzer() {
00037 clear();
00038 }
00039
00040
00041
00042
00043
00044
00045 SceneGraphAnalyzer::
00046 ~SceneGraphAnalyzer() {
00047 }
00048
00049
00050
00051
00052
00053
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
00092
00093
00094
00095
00096
00097
00098
00099 void SceneGraphAnalyzer::
00100 add_node(PandaNode *node) {
00101 collect_statistics(node, false);
00102 }
00103
00104
00105
00106
00107
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
00176
00177
00178
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
00188 _nodes.insert(Nodes::value_type(node, 1));
00189 } else {
00190
00191
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
00226
00227
00228
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
00258
00259
00260
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
00354
00355
00356
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
00365 _textures.insert(Textures::value_type(texture, 1));
00366
00367
00368
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
00384 (*ti).second++;
00385 }
00386 }
00387
00388
00389
00390
00391
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
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
00405 } else if (l > 1.0f) {
00406 _num_long_normals++;
00407 } else {
00408 _num_short_normals++;
00409 }
00410 _total_normal_length += l;
00411 }
00412 } else {
00413
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
00419 } else if (l > 1.0f) {
00420 _num_long_normals++;
00421 } else {
00422 _num_short_normals++;
00423 }
00424 _total_normal_length += l;
00425 }
00426 }
00427 }