00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "sceneGraphAnalyzer.h"
00016 #include "config_pgraph.h"
00017
00018 #include "indent.h"
00019 #include "lodNode.h"
00020 #include "geomNode.h"
00021 #include "geomVertexData.h"
00022 #include "geom.h"
00023 #include "geomPrimitive.h"
00024 #include "geomPoints.h"
00025 #include "geomLines.h"
00026 #include "geomLinestrips.h"
00027 #include "geomTriangles.h"
00028 #include "geomTristrips.h"
00029 #include "geomTrifans.h"
00030 #include "transformState.h"
00031 #include "textureAttrib.h"
00032 #include "pta_ushort.h"
00033 #include "geomVertexReader.h"
00034
00035
00036
00037
00038
00039
00040 SceneGraphAnalyzer::
00041 SceneGraphAnalyzer() {
00042 _lod_mode = LM_all;
00043 clear();
00044 }
00045
00046
00047
00048
00049
00050
00051 SceneGraphAnalyzer::
00052 ~SceneGraphAnalyzer() {
00053 }
00054
00055
00056
00057
00058
00059
00060
00061 void SceneGraphAnalyzer::
00062 clear() {
00063 _nodes.clear();
00064 _vdatas.clear();
00065 _vformats.clear();
00066 _vadatas.clear();
00067 _unique_vdatas.clear();
00068 _unique_vadatas.clear();
00069 _textures.clear();
00070
00071 _num_nodes = 0;
00072 _num_instances = 0;
00073 _num_transforms = 0;
00074 _num_nodes_with_attribs = 0;
00075 _num_lod_nodes = 0;
00076 _num_geom_nodes = 0;
00077 _num_geoms = 0;
00078 _num_geom_vertex_datas = 0;
00079 _num_geom_vertex_formats = 0;
00080 _vertex_data_size = 0;
00081 _prim_data_size = 0;
00082
00083 _num_vertices = 0;
00084 _num_vertices_64 = 0;
00085 _num_normals = 0;
00086 _num_colors = 0;
00087 _num_texcoords = 0;
00088 _num_tris = 0;
00089 _num_lines = 0;
00090 _num_points = 0;
00091
00092 _num_individual_tris = 0;
00093 _num_tristrips = 0;
00094 _num_triangles_in_strips = 0;
00095 _num_trifans = 0;
00096 _num_triangles_in_fans = 0;
00097
00098 _texture_bytes = 0;
00099
00100 _num_long_normals = 0;
00101 _num_short_normals = 0;
00102 _total_normal_length = 0.0f;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 void SceneGraphAnalyzer::
00115 add_node(PandaNode *node) {
00116 collect_statistics(node, false);
00117 }
00118
00119
00120
00121
00122
00123
00124 void SceneGraphAnalyzer::
00125 write(ostream &out, int indent_level) const {
00126 indent(out, indent_level)
00127 << _num_nodes << " total nodes (including "
00128 << _num_instances << " instances); " << _num_lod_nodes << " LODNodes.\n";
00129
00130 indent(out, indent_level)
00131 << _num_transforms << " transforms";
00132
00133 if (_num_nodes != 0) {
00134 out << "; " << 100 * _num_nodes_with_attribs / _num_nodes
00135 << "% of nodes have some render attribute.";
00136 }
00137 out << "\n";
00138
00139 indent(out, indent_level)
00140 << _num_geoms << " Geoms, with " << _num_geom_vertex_datas
00141 << " GeomVertexDatas and " << _num_geom_vertex_formats
00142 << " GeomVertexFormats, appear on " << _num_geom_nodes
00143 << " GeomNodes.\n";
00144
00145 indent(out, indent_level);
00146 if (_num_vertices_64 != 0) {
00147 out << _num_vertices_64 << " 64-bit vertices, ";
00148 if (_num_vertices != _num_vertices_64) {
00149 out << _num_vertices - _num_vertices_64 << " 32-bit vertices, ";
00150 }
00151 } else {
00152 out << _num_vertices << " vertices, ";
00153 }
00154
00155 out << _num_normals << " normals, "
00156 << _num_colors << " colors, "
00157 << _num_texcoords << " texture coordinates.\n";
00158
00159 if (_num_long_normals != 0 || _num_short_normals != 0) {
00160 indent(out, indent_level)
00161 << _num_long_normals << " normals are too long, "
00162 << _num_short_normals << " are too short. Average normal length is "
00163 << _total_normal_length / (PN_stdfloat)_num_normals << "\n";
00164 }
00165
00166 indent(out, indent_level)
00167 << "GeomVertexData arrays occupy " << (_vertex_data_size + 1023) / 1024
00168 << "K memory.\n";
00169
00170 indent(out, indent_level)
00171 << "GeomPrimitive arrays occupy " << (_prim_data_size + 1023) / 1024
00172 << "K memory.\n";
00173
00174 int unreferenced_vertices = 0;
00175 VDatas::const_iterator vdi;
00176 for (vdi = _vdatas.begin(); vdi != _vdatas.end(); ++vdi) {
00177 CPT(GeomVertexData) vdata = (*vdi).first;
00178 const VDataTracker &tracker = (*vdi).second;
00179 int num_unreferenced = vdata->get_num_rows() - tracker._referenced_vertices.get_num_on_bits();
00180 nassertv(num_unreferenced >= 0);
00181 unreferenced_vertices += num_unreferenced;
00182 }
00183 if (unreferenced_vertices != 0) {
00184 indent(out, indent_level)
00185 << unreferenced_vertices << " vertices are unreferenced by any GeomPrimitives.\n";
00186 }
00187 if (_unique_vdatas.size() != _vdatas.size()) {
00188 indent(out, indent_level)
00189 << _vdatas.size() - _unique_vdatas.size()
00190 << " GeomVertexDatas are redundantly duplicated\n";
00191 }
00192 if (_unique_vadatas.size() != _vadatas.size()) {
00193 int wasted_bytes = 0;
00194
00195 UniqueVADatas::const_iterator uvai;
00196 for (uvai = _unique_vadatas.begin();
00197 uvai != _unique_vadatas.end();
00198 ++uvai) {
00199 const GeomVertexArrayData *gvad = (*uvai).first;
00200 int dup_count = (*uvai).second;
00201 if (dup_count > 1) {
00202 wasted_bytes += (dup_count - 1) * gvad->get_data_size_bytes();
00203 }
00204 }
00205 indent(out, indent_level)
00206 << _vadatas.size() - _unique_vadatas.size()
00207 << " GeomVertexArrayDatas are redundant, wasting "
00208 << (wasted_bytes + 1023) / 1024 << "K.\n";
00209 }
00210 if (_unique_prim_vadatas.size() != _prim_vadatas.size()) {
00211 int wasted_bytes = 0;
00212
00213 UniqueVADatas::const_iterator uvai;
00214 for (uvai = _unique_prim_vadatas.begin();
00215 uvai != _unique_prim_vadatas.end();
00216 ++uvai) {
00217 const GeomVertexArrayData *gvad = (*uvai).first;
00218 int dup_count = (*uvai).second;
00219 if (dup_count > 1) {
00220 wasted_bytes += (dup_count - 1) * gvad->get_data_size_bytes();
00221 }
00222 }
00223 indent(out, indent_level)
00224 << _prim_vadatas.size() - _unique_prim_vadatas.size()
00225 << " GeomPrimitive arrays are redundant, wasting "
00226 << (wasted_bytes + 1023) / 1024 << "K.\n";
00227 }
00228
00229 indent(out, indent_level)
00230 << _num_tris << " triangles:\n";
00231 indent(out, indent_level + 2)
00232 << _num_triangles_in_strips
00233 << " of these are on " << _num_tristrips << " tristrips";
00234 if (_num_tristrips != 0) {
00235 out << " ("
00236 << (double)_num_triangles_in_strips / (double)_num_tristrips
00237 << " average tris per strip)";
00238 }
00239 out << ".\n";
00240
00241 if (_num_trifans != 0) {
00242 indent(out, indent_level + 2)
00243 << _num_triangles_in_fans
00244 << " of these are on " << _num_trifans << " trifans";
00245 if (_num_trifans != 0) {
00246 out << " ("
00247 << (double)_num_triangles_in_fans / (double)_num_trifans
00248 << " average tris per fan)";
00249 }
00250 out << ".\n";
00251 }
00252
00253 indent(out, indent_level + 2)
00254 << _num_individual_tris
00255 << " of these are independent triangles.\n";
00256
00257 if (_num_lines != 0 || _num_points != 0) {
00258 indent(out, indent_level)
00259 << _num_lines << " lines, " << _num_points << " points.\n";
00260 }
00261
00262 indent(out, indent_level)
00263 << _textures.size() << " textures, estimated minimum "
00264 << (_texture_bytes + 1023) / 1024 << "K texture memory required.\n";
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 void SceneGraphAnalyzer::
00274 collect_statistics(PandaNode *node, bool under_instance) {
00275 _num_nodes++;
00276
00277 if (!under_instance) {
00278 Nodes::iterator ni = _nodes.find(node);
00279 if (ni == _nodes.end()) {
00280
00281 _nodes.insert(Nodes::value_type(node, 1));
00282 } else {
00283
00284
00285 (*ni).second++;
00286 _num_instances++;
00287 under_instance = true;
00288 }
00289 }
00290
00291 if (!node->get_state()->is_empty()) {
00292 _num_nodes_with_attribs++;
00293 const RenderAttrib *attrib =
00294 node->get_attrib(TextureAttrib::get_class_slot());
00295 if (attrib != (RenderAttrib *)NULL) {
00296 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
00297 for (int i = 0; i < ta->get_num_on_stages(); i++) {
00298 collect_statistics(ta->get_on_texture(ta->get_on_stage(i)));
00299 }
00300 }
00301 }
00302 if (!node->get_transform()->is_identity()) {
00303 _num_transforms++;
00304 }
00305
00306 if (node->is_geom_node()) {
00307 collect_statistics(DCAST(GeomNode, node));
00308 }
00309
00310 if (node->is_lod_node()) {
00311 LODNode *lod_node = DCAST(LODNode, node);
00312 ++_num_lod_nodes;
00313
00314 switch (_lod_mode) {
00315 case LM_lowest:
00316 case LM_highest:
00317 {
00318 int sw = (_lod_mode == LM_lowest) ? lod_node->get_lowest_switch() : lod_node->get_highest_switch();
00319 if (sw >= 0 && sw < node->get_num_children()) {
00320 PandaNode *child = node->get_child(sw);
00321 collect_statistics(child, under_instance);
00322 }
00323 return;
00324 }
00325
00326 case LM_none:
00327 return;
00328
00329 case LM_all:
00330
00331 break;
00332 }
00333 }
00334
00335 int num_children = node->get_num_children();
00336 for (int i = 0; i < num_children; i++) {
00337 PandaNode *child = node->get_child(i);
00338 collect_statistics(child, under_instance);
00339 }
00340 }
00341
00342
00343
00344
00345
00346
00347
00348 void SceneGraphAnalyzer::
00349 collect_statistics(GeomNode *geom_node) {
00350 nassertv(geom_node != (GeomNode *)NULL);
00351
00352 ++_num_geom_nodes;
00353
00354 int num_geoms = geom_node->get_num_geoms();
00355 _num_geoms += num_geoms;
00356
00357 for (int i = 0; i < num_geoms; i++) {
00358 const Geom *geom = geom_node->get_geom(i);
00359 collect_statistics(geom);
00360
00361 const RenderState *geom_state = geom_node->get_geom_state(i);
00362
00363 const RenderAttrib *attrib =
00364 geom_state->get_attrib(TextureAttrib::get_class_slot());
00365 if (attrib != (RenderAttrib *)NULL) {
00366 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
00367 for (int i = 0; i < ta->get_num_on_stages(); i++) {
00368 collect_statistics(ta->get_on_texture(ta->get_on_stage(i)));
00369 }
00370 }
00371 }
00372 }
00373
00374
00375
00376
00377
00378
00379
00380 void SceneGraphAnalyzer::
00381 collect_statistics(const Geom *geom) {
00382 CPT(GeomVertexData) vdata = geom->get_vertex_data();
00383 pair<VDatas::iterator, bool> result = _vdatas.insert(VDatas::value_type(vdata, VDataTracker()));
00384 if (result.second) {
00385
00386 ++_num_geom_vertex_datas;
00387
00388 CPT(GeomVertexFormat) vformat = vdata->get_format();
00389 bool format_inserted = _vformats.insert(vformat).second;
00390 if (format_inserted) {
00391
00392 ++_num_geom_vertex_formats;
00393 }
00394
00395 int &dup_count = (*(_unique_vdatas.insert(UniqueVDatas::value_type(vdata, 0)).first)).second;
00396 ++dup_count;
00397
00398 int num_rows = vdata->get_num_rows();
00399 const GeomVertexFormat *format = vdata->get_format();
00400 if (format->has_column(InternalName::get_vertex())) {
00401 _num_vertices += num_rows;
00402 const GeomVertexColumn *vcolumn = format->get_column(InternalName::get_vertex());
00403 if (vcolumn->get_numeric_type() == GeomEnums::NT_float64) {
00404 _num_vertices_64 += num_rows;
00405 }
00406 }
00407 if (format->has_column(InternalName::get_normal())) {
00408 _num_normals += num_rows;
00409 GeomVertexReader rnormal(vdata, InternalName::get_normal());
00410 while (!rnormal.is_at_end()) {
00411 LVector3f normal = rnormal.get_data3f();
00412 float length = normal.length();
00413 if (IS_NEARLY_EQUAL(length, 1.0f)) {
00414
00415 } else if (length > 1.0f) {
00416 ++_num_long_normals;
00417 } else {
00418 ++_num_short_normals;
00419 }
00420 _total_normal_length += length;
00421 }
00422 }
00423 if (format->has_column(InternalName::get_color())) {
00424 _num_colors += num_rows;
00425 }
00426 int num_texcoords = format->get_num_texcoords();
00427 _num_texcoords += num_rows * num_texcoords;
00428
00429 int num_arrays = vdata->get_num_arrays();
00430 for (int i = 0; i < num_arrays; ++i) {
00431 collect_statistics(vdata->get_array(i));
00432 }
00433 }
00434 VDataTracker &tracker = (*(result.first)).second;
00435
00436
00437 int num_primitives = geom->get_num_primitives();
00438 for (int i = 0; i < num_primitives; ++i) {
00439 CPT(GeomPrimitive) prim = geom->get_primitive(i);
00440
00441 int num_vertices = prim->get_num_vertices();
00442 for (int vi = 0; vi < num_vertices; ++vi) {
00443 tracker._referenced_vertices.set_bit(prim->get_vertex(vi));
00444 }
00445
00446 if (prim->is_indexed()) {
00447 collect_prim_statistics(prim->get_vertices());
00448 if (prim->is_composite()) {
00449 collect_statistics(prim->get_mins());
00450 collect_statistics(prim->get_maxs());
00451 }
00452 }
00453
00454 if (prim->is_of_type(GeomPoints::get_class_type())) {
00455 _num_points += prim->get_num_primitives();
00456
00457 } else if (prim->is_of_type(GeomLines::get_class_type())) {
00458 _num_lines += prim->get_num_primitives();
00459
00460 } else if (prim->is_of_type(GeomLinestrips::get_class_type())) {
00461 _num_lines += prim->get_num_faces();
00462
00463 } else if (prim->is_of_type(GeomTriangles::get_class_type())) {
00464 _num_tris += prim->get_num_primitives();
00465 _num_individual_tris += prim->get_num_primitives();
00466
00467 } else if (prim->is_of_type(GeomTristrips::get_class_type())) {
00468 _num_tris += prim->get_num_faces();
00469 _num_tristrips += prim->get_num_primitives();
00470 _num_triangles_in_strips += prim->get_num_faces();
00471
00472 } else if (prim->is_of_type(GeomTrifans::get_class_type())) {
00473 _num_tris += prim->get_num_faces();
00474 _num_trifans += prim->get_num_primitives();
00475 _num_triangles_in_fans += prim->get_num_faces();
00476
00477 } else {
00478 pgraph_cat.warning()
00479 << "Unknown GeomPrimitive type in SceneGraphAnalyzer: "
00480 << prim->get_type() << "\n";
00481 }
00482 }
00483 }
00484
00485
00486
00487
00488
00489
00490
00491 void SceneGraphAnalyzer::
00492 collect_statistics(Texture *texture) {
00493 nassertv(texture != (Texture *)NULL);
00494
00495 Textures::iterator ti = _textures.find(texture);
00496 if (ti == _textures.end()) {
00497
00498 _textures.insert(Textures::value_type(texture, 1));
00499
00500
00501
00502 int bytes =
00503 texture->get_x_size() * texture->get_y_size() *
00504 texture->get_num_components() * texture->get_component_width();
00505
00506 if (texture->uses_mipmaps()) {
00507 bytes *= 4/3;
00508 }
00509
00510 _texture_bytes += bytes;
00511
00512 } else {
00513
00514 (*ti).second++;
00515 }
00516 }
00517
00518
00519
00520
00521
00522
00523
00524 void SceneGraphAnalyzer::
00525 collect_statistics(const GeomVertexArrayData *vadata) {
00526 nassertv(vadata != NULL);
00527 bool inserted = _vadatas.insert(vadata).second;
00528 if (inserted) {
00529
00530 _vertex_data_size += vadata->get_data_size_bytes();
00531 int &dup_count = (*(_unique_vadatas.insert(UniqueVADatas::value_type(vadata, 0)).first)).second;
00532 ++dup_count;
00533 }
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 void SceneGraphAnalyzer::
00545 collect_prim_statistics(const GeomVertexArrayData *vadata) {
00546 nassertv(vadata != NULL);
00547 bool inserted = _prim_vadatas.insert(vadata).second;
00548 if (inserted) {
00549
00550 _prim_data_size += vadata->get_data_size_bytes();
00551 int &dup_count = (*(_unique_prim_vadatas.insert(UniqueVADatas::value_type(vadata, 0)).first)).second;
00552 ++dup_count;
00553 }
00554 }