15 #include "sceneGraphAnalyzer.h" 16 #include "config_pgraph.h" 21 #include "geomVertexData.h" 23 #include "geomPrimitive.h" 24 #include "geomPoints.h" 25 #include "geomLines.h" 26 #include "geomLinestrips.h" 27 #include "geomTriangles.h" 28 #include "geomTristrips.h" 29 #include "geomTrifans.h" 30 #include "geomPatches.h" 31 #include "transformState.h" 32 #include "textureAttrib.h" 33 #include "pta_ushort.h" 34 #include "geomVertexReader.h" 42 SceneGraphAnalyzer() {
53 ~SceneGraphAnalyzer() {
68 _unique_vdatas.clear();
69 _unique_vadatas.clear();
75 _num_nodes_with_attribs = 0;
79 _num_geom_vertex_datas = 0;
80 _num_geom_vertex_formats = 0;
81 _vertex_data_size = 0;
94 _num_individual_tris = 0;
96 _num_triangles_in_strips = 0;
98 _num_triangles_in_fans = 0;
99 _num_vertices_in_patches = 0;
103 _num_long_normals = 0;
104 _num_short_normals = 0;
105 _total_normal_length = 0.0f;
119 collect_statistics(node,
false);
128 write(ostream &out,
int indent_level)
const {
129 indent(out, indent_level)
130 << _num_nodes <<
" total nodes (including " 131 << _num_instances <<
" instances); " << _num_lod_nodes <<
" LODNodes.\n";
133 indent(out, indent_level)
134 << _num_transforms <<
" transforms";
136 if (_num_nodes != 0) {
137 out <<
"; " << 100 * _num_nodes_with_attribs / _num_nodes
138 <<
"% of nodes have some render attribute.";
142 indent(out, indent_level)
143 << _num_geoms <<
" Geoms, with " << _num_geom_vertex_datas
144 <<
" GeomVertexDatas and " << _num_geom_vertex_formats
145 <<
" GeomVertexFormats, appear on " << _num_geom_nodes
148 indent(out, indent_level);
149 if (_num_vertices_64 != 0) {
150 out << _num_vertices_64 <<
" 64-bit vertices, ";
151 if (_num_vertices != _num_vertices_64) {
152 out << _num_vertices - _num_vertices_64 <<
" 32-bit vertices, ";
155 out << _num_vertices <<
" vertices, ";
158 out << _num_normals <<
" normals, " 159 << _num_colors <<
" colors, " 160 << _num_texcoords <<
" texture coordinates.\n";
162 if (_num_long_normals != 0 || _num_short_normals != 0) {
163 indent(out, indent_level)
164 << _num_long_normals <<
" normals are too long, " 165 << _num_short_normals <<
" are too short. Average normal length is " 166 << _total_normal_length / (PN_stdfloat)_num_normals <<
"\n";
169 indent(out, indent_level)
170 <<
"GeomVertexData arrays occupy " << (_vertex_data_size + 1023) / 1024
173 indent(out, indent_level)
174 <<
"GeomPrimitive arrays occupy " << (_prim_data_size + 1023) / 1024
177 int unreferenced_vertices = 0;
178 VDatas::const_iterator vdi;
179 for (vdi = _vdatas.begin(); vdi != _vdatas.end(); ++vdi) {
181 const VDataTracker &tracker = (*vdi).second;
182 int num_unreferenced = vdata->get_num_rows() - tracker._referenced_vertices.get_num_on_bits();
183 nassertv(num_unreferenced >= 0);
184 unreferenced_vertices += num_unreferenced;
186 if (unreferenced_vertices != 0) {
187 indent(out, indent_level)
188 << unreferenced_vertices <<
" vertices are unreferenced by any GeomPrimitives.\n";
190 if (_unique_vdatas.size() != _vdatas.size()) {
191 indent(out, indent_level)
192 << _vdatas.size() - _unique_vdatas.size()
193 <<
" GeomVertexDatas are redundantly duplicated\n";
195 if (_unique_vadatas.size() != _vadatas.size()) {
196 int wasted_bytes = 0;
198 UniqueVADatas::const_iterator uvai;
199 for (uvai = _unique_vadatas.begin();
200 uvai != _unique_vadatas.end();
203 int dup_count = (*uvai).second;
208 indent(out, indent_level)
209 << _vadatas.size() - _unique_vadatas.size()
210 <<
" GeomVertexArrayDatas are redundant, wasting " 211 << (wasted_bytes + 1023) / 1024 <<
"K.\n";
213 if (_unique_prim_vadatas.size() != _prim_vadatas.size()) {
214 int wasted_bytes = 0;
216 UniqueVADatas::const_iterator uvai;
217 for (uvai = _unique_prim_vadatas.begin();
218 uvai != _unique_prim_vadatas.end();
221 int dup_count = (*uvai).second;
226 indent(out, indent_level)
227 << _prim_vadatas.size() - _unique_prim_vadatas.size()
228 <<
" GeomPrimitive arrays are redundant, wasting " 229 << (wasted_bytes + 1023) / 1024 <<
"K.\n";
232 indent(out, indent_level)
233 << _num_tris <<
" triangles:\n";
234 indent(out, indent_level + 2)
235 << _num_triangles_in_strips
236 <<
" of these are on " << _num_tristrips <<
" tristrips";
237 if (_num_tristrips != 0) {
239 << (double)_num_triangles_in_strips / (
double)_num_tristrips
240 <<
" average tris per strip)";
244 if (_num_trifans != 0) {
245 indent(out, indent_level + 2)
246 << _num_triangles_in_fans
247 <<
" of these are on " << _num_trifans <<
" trifans";
248 if (_num_trifans != 0) {
250 << (double)_num_triangles_in_fans / (
double)_num_trifans
251 <<
" average tris per fan)";
256 indent(out, indent_level + 2)
257 << _num_individual_tris
258 <<
" of these are independent triangles.\n";
260 if (_num_patches != 0) {
261 indent(out, indent_level)
262 << _num_patches <<
" patches (" 263 << (double)_num_vertices_in_patches / (
double)_num_patches
264 <<
" average verts per patch).\n";
267 if (_num_lines != 0 || _num_points != 0) {
268 indent(out, indent_level)
269 << _num_lines <<
" lines, " << _num_points <<
" points.\n";
272 indent(out, indent_level)
273 << _textures.size() <<
" textures, estimated minimum " 274 << (_texture_bytes + 1023) / 1024 <<
"K texture memory required.\n";
283 void SceneGraphAnalyzer::
284 collect_statistics(
PandaNode *node,
bool under_instance) {
287 if (!under_instance) {
288 Nodes::iterator ni = _nodes.find(node);
289 if (ni == _nodes.end()) {
291 _nodes.insert(Nodes::value_type(node, 1));
297 under_instance =
true;
301 if (!node->get_state()->is_empty()) {
302 _num_nodes_with_attribs++;
304 node->get_attrib(TextureAttrib::get_class_slot());
312 if (!node->get_transform()->is_identity()) {
317 collect_statistics(DCAST(
GeomNode, node));
329 if (sw >= 0 && sw < node->get_num_children()) {
331 collect_statistics(child, under_instance);
346 for (
int i = 0; i < num_children; i++) {
348 collect_statistics(child, under_instance);
358 void SceneGraphAnalyzer::
359 collect_statistics(
GeomNode *geom_node) {
360 nassertv(geom_node != (
GeomNode *)NULL);
365 _num_geoms += num_geoms;
367 for (
int i = 0; i < num_geoms; i++) {
368 const Geom *geom = geom_node->get_geom(i);
369 collect_statistics(geom);
374 geom_state->get_attrib(TextureAttrib::get_class_slot());
390 void SceneGraphAnalyzer::
391 collect_statistics(
const Geom *geom) {
393 pair<VDatas::iterator, bool> result = _vdatas.insert(VDatas::value_type(vdata, VDataTracker()));
396 ++_num_geom_vertex_datas;
398 CPT(GeomVertexFormat) vformat = vdata->get_format();
399 bool format_inserted = _vformats.insert(vformat).second;
400 if (format_inserted) {
402 ++_num_geom_vertex_formats;
405 int &dup_count = (*(_unique_vdatas.insert(UniqueVDatas::value_type(vdata, 0)).first)).second;
408 int num_rows = vdata->get_num_rows();
409 const GeomVertexFormat *format = vdata->get_format();
410 if (format->has_column(InternalName::get_vertex())) {
411 _num_vertices += num_rows;
412 const GeomVertexColumn *vcolumn = format->get_column(InternalName::get_vertex());
414 _num_vertices_64 += num_rows;
417 if (format->has_column(InternalName::get_normal())) {
418 _num_normals += num_rows;
422 float length = normal.
length();
423 if (IS_NEARLY_EQUAL(length, 1.0f)) {
425 }
else if (length > 1.0f) {
428 ++_num_short_normals;
430 _total_normal_length += length;
433 if (format->has_column(InternalName::get_color())) {
434 _num_colors += num_rows;
436 int num_texcoords = format->get_num_texcoords();
437 _num_texcoords += num_rows * num_texcoords;
439 int num_arrays = vdata->get_num_arrays();
440 for (
int i = 0; i < num_arrays; ++i) {
441 collect_statistics(vdata->get_array(i));
444 VDataTracker &tracker = (*(result.first)).second;
447 int num_primitives = geom->get_num_primitives();
448 for (
int i = 0; i < num_primitives; ++i) {
451 int num_vertices = prim->get_num_vertices();
452 for (
int vi = 0; vi < num_vertices; ++vi) {
453 tracker._referenced_vertices.set_bit(prim->get_vertex(vi));
456 if (prim->is_indexed()) {
457 collect_prim_statistics(prim->get_vertices());
458 if (prim->is_composite()) {
459 collect_statistics(prim->get_mins());
460 collect_statistics(prim->get_maxs());
464 if (prim->is_of_type(GeomPoints::get_class_type())) {
465 _num_points += prim->get_num_primitives();
467 }
else if (prim->is_of_type(GeomLines::get_class_type())) {
468 _num_lines += prim->get_num_primitives();
470 }
else if (prim->is_of_type(GeomLinestrips::get_class_type())) {
471 _num_lines += prim->get_num_faces();
473 }
else if (prim->is_of_type(GeomTriangles::get_class_type())) {
474 _num_tris += prim->get_num_primitives();
475 _num_individual_tris += prim->get_num_primitives();
477 }
else if (prim->is_of_type(GeomTristrips::get_class_type())) {
478 _num_tris += prim->get_num_faces();
479 _num_tristrips += prim->get_num_primitives();
480 _num_triangles_in_strips += prim->get_num_faces();
482 }
else if (prim->is_of_type(GeomTrifans::get_class_type())) {
483 _num_tris += prim->get_num_faces();
484 _num_trifans += prim->get_num_primitives();
485 _num_triangles_in_fans += prim->get_num_faces();
487 }
else if (prim->is_of_type(GeomPatches::get_class_type())) {
488 _num_patches += prim->get_num_primitives();
489 _num_vertices_in_patches += prim->get_num_vertices();
493 <<
"Unknown GeomPrimitive type in SceneGraphAnalyzer: " 494 << prim->get_type() <<
"\n";
505 void SceneGraphAnalyzer::
506 collect_statistics(
Texture *texture) {
507 nassertv(texture != (
Texture *)NULL);
509 Textures::iterator ti = _textures.find(texture);
510 if (ti == _textures.end()) {
512 _textures.insert(Textures::value_type(texture, 1));
524 _texture_bytes += bytes;
538 void SceneGraphAnalyzer::
540 nassertv(vadata != NULL);
541 bool inserted = _vadatas.insert(vadata).second;
545 int &dup_count = (*(_unique_vadatas.insert(UniqueVADatas::value_type(vadata, 0)).first)).second;
558 void SceneGraphAnalyzer::
560 nassertv(vadata != NULL);
561 bool inserted = _prim_vadatas.insert(vadata).second;
565 int &dup_count = (*(_unique_prim_vadatas.insert(UniqueVADatas::value_type(vadata, 0)).first)).second;
const RenderState * get_geom_state(int n) const
Returns the RenderState associated with the nth geom of the node.
A basic node of the scene graph or data graph.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
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-...
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
int get_lowest_switch() const
Returns the index number of the child with the lowest level of detail; that is, the one that is desig...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
const LVecBase3f & get_data3f()
Returns the data associated with the read row, expressed as a 3-component value, and advances the rea...
int get_highest_switch() const
Returns the index number of the child with the highest level of detail; that is, the one that is desi...
int get_num_geoms() const
Returns the number of geoms in the node.
int get_component_width() const
Returns the number of bytes stored for each color component of a texel.
void clear()
Resets all of the data in the analyzer in preparation for a new run.
This defines how a single column is interleaved within a vertex array stored within a Geom...
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Texture * get_on_texture(TextureStage *stage) const
Returns the texture associated with the indicated stage, or NULL if no texture is associated...
bool uses_mipmaps() const
Returns true if the minfilter settings on this texture indicate the use of mipmapping, false otherwise.
void write(ostream &out, int indent_level=0) const
Describes all the data collected.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
TextureStage * get_on_stage(int n) const
Returns the nth stage turned on by the attribute, sorted in render order.
virtual bool is_lod_node() const
A simple downcast check.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
float length() const
Returns the length of the vector, by the Pythagorean theorem.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
int get_y_size() const
Returns the height of the texture image in texels.
bool is_at_end() const
Returns true if the reader is currently at the end of the list of vertices, false otherwise...
int get_num_on_stages() const
Returns the number of stages that are turned on by the attribute.
int get_num_components() const
Returns the number of color components for each texel of the texture image.
virtual bool is_geom_node() const
A simple downcast check.
A node that holds Geom objects, renderable pieces of geometry.
int get_data_size_bytes() const
Returns the number of bytes stored in the array.
int get_x_size() const
Returns the width of the texture image in texels.
This is the data for one array of a GeomVertexData structure.