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;
420 while (!rnormal.is_at_end()) {
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;
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;
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...
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-...
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
int get_data_size_bytes() const
Returns the number of bytes stored in the array.
int get_num_on_stages() const
Returns the number of stages that are turned on by the attribute.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
virtual bool is_lod_node() const
A simple downcast check.
TextureStage * get_on_stage(int n) const
Returns the nth stage turned on by the attribute, sorted in render order.
void clear()
Resets all of the data in the analyzer in preparation for a new run.
bool uses_mipmaps() const
Returns true if the minfilter settings on this texture indicate the use of mipmapping, false otherwise.
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...
float length() const
Returns the length of the vector, by the Pythagorean theorem.
int get_num_components() const
Returns the number of color components for each texel of the texture image.
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
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...
Texture * get_on_texture(TextureStage *stage) const
Returns the texture associated with the indicated stage, or NULL if no texture is associated...
void write(ostream &out, int indent_level=0) const
Describes all the data collected.
const RenderAttrib * get_attrib(TypeHandle type) const
Looks for a RenderAttrib of the indicated type in the state, and returns it if it is found...
const RenderState * get_geom_state(int n) const
Returns the RenderState associated with the nth geom of the node.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
NumericType get_numeric_type() const
Returns the token representing the numeric type of the data storage.
int get_component_width() const
Returns the number of bytes stored for each color component of a texel.
virtual bool is_geom_node() const
A simple downcast check.
int get_y_size() const
Returns the height of the texture image in texels.
int get_x_size() const
Returns the width of the texture image in texels.
A node that holds Geom objects, renderable pieces of geometry.
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.
This is the data for one array of a GeomVertexData structure.
int get_num_primitives() const
Returns the number of GeomPrimitive objects stored within the Geom, each of which represents a number...
int get_num_rows() const
Returns the number of rows stored within all the arrays.