15 #include "sceneGraphReducer.h" 16 #include "config_pgraph.h" 17 #include "accumulatedAttribs.h" 18 #include "boundingSphere.h" 19 #include "modelNode.h" 20 #include "pointerTo.h" 24 #include "config_gobj.h" 27 PStatCollector SceneGraphReducer::_flatten_collector(
"*:Flatten:flatten");
28 PStatCollector SceneGraphReducer::_apply_collector(
"*:Flatten:apply");
29 PStatCollector SceneGraphReducer::_remove_column_collector(
"*:Flatten:remove column");
30 PStatCollector SceneGraphReducer::_compatible_state_collector(
"*:Flatten:compatible colors");
31 PStatCollector SceneGraphReducer::_collect_collector(
"*:Flatten:collect");
32 PStatCollector SceneGraphReducer::_make_nonindexed_collector(
"*:Flatten:make nonindexed");
33 PStatCollector SceneGraphReducer::_unify_collector(
"*:Flatten:unify");
34 PStatCollector SceneGraphReducer::_remove_unused_collector(
"*:Flatten:remove unused vertices");
35 PStatCollector SceneGraphReducer::_premunge_collector(
"*:Premunge");
56 int max_vertices = max_collect_vertices;
59 max_vertices = min(max_vertices, _gsg->get_max_vertices_per_array());
103 int num_total_nodes = 0;
115 for (
int i = 0; i < num_children; i++) {
117 num_pass_nodes += r_flatten(root, child_node, combine_siblings_bits);
120 if (combine_siblings_bits != 0 &&
123 num_pass_nodes += flatten_siblings(root, combine_siblings_bits);
126 num_total_nodes += num_pass_nodes;
132 }
while ((combine_siblings_bits & CS_recurse) != 0 && num_pass_nodes != 0);
134 return num_total_nodes;
149 int count = r_remove_column(root, column, _transformer);
167 PStatTimer timer(_compatible_state_collector);
168 int count = r_make_compatible_state(root, _transformer);
191 if (!preserve_triangle_strips) {
211 int max_indices = max_collect_indices;
213 max_indices = min(max_indices, _gsg->get_max_vertices_per_primitive());
215 r_unify(root, max_indices, preserve_order);
233 r_register_vertices(root, _transformer);
253 if (allow_live_flatten) {
270 void SceneGraphReducer::
273 if (pgraph_cat.is_spam()) {
275 <<
"r_apply_attribs(" << *node <<
"), node's attribs are:\n";
276 node->get_transform()->write(pgraph_cat.spam(
false), 2);
277 node->get_state()->write(pgraph_cat.spam(
false), 2);
278 node->get_effects()->write(pgraph_cat.spam(
false), 2);
282 next_attribs.
collect(node, attrib_types);
284 if (pgraph_cat.is_spam()) {
286 <<
"Got attribs from " << *node <<
"\n" 287 <<
"Accumulated attribs are:\n";
288 next_attribs.write(pgraph_cat.spam(
false), attrib_types, 2);
294 if (pgraph_cat.is_spam()) {
296 <<
"Not applying further; " << *node
297 <<
" doesn't allow flattening below itself.\n";
307 if (pgraph_cat.is_spam()) {
310 <<
" contains a non-transformable effect; leaving transform here.\n";
312 next_attribs._transform = effects->prepare_flatten_transform(next_attribs._transform);
313 apply_types |= TT_transform;
316 if (pgraph_cat.is_spam()) {
318 <<
"Cannot safely transform nodes of type " << node->get_type()
319 <<
"; leaving a transform here but carrying on otherwise.\n";
321 apply_types |= TT_transform;
330 if ((apply_types & TT_transform) == 0) {
331 bool children_transform_friendly =
true;
332 for (i = 0; i < num_children && children_transform_friendly; i++) {
337 if (!children_transform_friendly) {
338 if (pgraph_cat.is_spam()) {
341 <<
" has a child that cannot modify its transform; leaving transform here.\n";
343 apply_types |= TT_transform;
348 next_attribs.
apply_to_node(node, attrib_types & apply_types);
354 bool resist_copy =
false;
355 for (i = 0; i < num_children; i++) {
360 if (pgraph_cat.is_spam()) {
362 <<
"Cannot duplicate nodes of type " << child_node->get_type()
369 if (new_node->get_type() != child_node->get_type()) {
371 <<
"Don't know how to copy nodes of type " 372 << child_node->get_type() <<
"\n";
374 if (no_unsupported_copy) {
380 if (pgraph_cat.is_spam()) {
382 <<
"Duplicated " << *child_node <<
"\n";
387 child_node = new_node;
401 for (i = 0; i < num_children; i++) {
403 r_apply_attribs(child_node, next_attribs, attrib_types, transformer);
414 int SceneGraphReducer::
416 int combine_siblings_bits) {
417 if (pgraph_cat.is_spam()) {
419 <<
"SceneGraphReducer::r_flatten(" << *grandparent_node <<
", " 420 << *parent_node <<
", " << hex << combine_siblings_bits << dec
424 if ((combine_siblings_bits & (CS_geom_node | CS_other | CS_recurse)) != 0) {
427 combine_siblings_bits &= ~CS_within_radius;
433 if (pgraph_cat.is_spam()) {
435 <<
"Not traversing further; " << *parent_node
436 <<
" doesn't allow flattening below itself.\n";
440 if ((combine_siblings_bits & CS_within_radius) != 0) {
442 if (bv->is_of_type(BoundingSphere::get_class_type())) {
444 if (pgraph_cat.is_spam()) {
446 <<
"considering radius of " << *parent_node
447 <<
": " << *bs <<
" vs. " << _combine_radius <<
"\n";
453 if (pgraph_cat.is_spam()) {
455 <<
"node fits within radius; flattening tighter.\n";
457 combine_siblings_bits &= ~CS_within_radius;
458 combine_siblings_bits |= (CS_geom_node | CS_other | CS_recurse);
467 for (
int i = 0; i < num_children; i++) {
469 num_nodes += r_flatten(parent_node, child_node, combine_siblings_bits);
481 if ((combine_siblings_bits & CS_recurse) != 0 &&
484 num_nodes += flatten_siblings(parent_node, combine_siblings_bits);
493 if (consider_child(grandparent_node, parent_node, child_node)) {
497 if (do_flatten_child(grandparent_node, parent_node, child_node)) {
502 parent_node->add_child(child_node, child_sort);
507 if ((combine_siblings_bits & CS_recurse) == 0 &&
508 (combine_siblings_bits & ~CS_recurse) != 0 &&
511 num_nodes += flatten_siblings(parent_node, combine_siblings_bits);
519 if (child_node->
is_exact_type(PandaNode::get_class_type()) &&
521 child_node->get_transform()->is_identity() &&
522 child_node->get_effects()->is_empty()) {
539 INLINE
bool SortByState::
541 if (node1->get_transform() != node2->get_transform()) {
542 return node1->get_transform() < node2->get_transform();
544 if (node1->get_state() != node2->get_state()) {
545 return node1->get_state() < node2->get_state();
547 if (node1->get_effects() != node2->get_effects()) {
548 return node1->get_effects() < node2->get_effects();
571 int SceneGraphReducer::
572 flatten_siblings(
PandaNode *parent_node,
int combine_siblings_bits) {
587 for (
int i = 0; i < num_children; i++) {
590 if (safe_to_combine) {
592 safe_to_combine = (combine_siblings_bits & CS_geom_node) != 0;
594 safe_to_combine = (combine_siblings_bits & CS_other) != 0;
598 if (safe_to_combine) {
599 collected[child_node].push_back(child_node);
608 Collected::iterator ci;
609 for (ci = collected.begin(); ci != collected.end(); ++ci) {
611 if (effects->safe_to_combine()) {
612 NodeList &nodes = (*ci).second;
614 NodeList::iterator ai1;
616 while (ai1 != nodes.end()) {
617 NodeList::iterator ai1_hold = ai1;
620 NodeList::iterator ai2 = ai1;
621 while (ai2 != nodes.end()) {
622 NodeList::iterator ai2_hold = ai2;
626 if (consider_siblings(parent_node, child1, child2)) {
628 do_flatten_siblings(parent_node, child1, child2);
631 (*ai1_hold) = new_node;
632 nodes.erase(ai2_hold);
653 bool SceneGraphReducer::
662 if (parent_node->get_transform() != child_node->get_transform() ||
663 parent_node->get_state() != child_node->get_state() ||
664 parent_node->get_effects() != child_node->get_effects() ||
688 bool SceneGraphReducer::
705 bool SceneGraphReducer::
708 if (pgraph_cat.is_spam()) {
710 <<
"Collapsing " << *parent_node <<
" and " << *child_node <<
"\n";
713 PT(
PandaNode) new_parent = collapse_nodes(parent_node, child_node,
false);
715 if (pgraph_cat.is_spam()) {
717 <<
"Decided not to collapse " << *parent_node
718 <<
" and " << *child_node <<
"\n";
723 choose_name(new_parent, parent_node, child_node);
725 new_parent->replace_node(child_node);
726 new_parent->replace_node(parent_node);
746 if (pgraph_cat.is_spam()) {
748 <<
"Collapsing " << *child1 <<
" and " << *child2 <<
"\n";
751 PT(
PandaNode) new_child = collapse_nodes(child2, child1,
true);
753 if (pgraph_cat.is_spam()) {
755 <<
"Decided not to collapse " << *child1 <<
" and " << *child2 <<
"\n";
760 choose_name(new_child, child2, child1);
765 new_child->replace_node(child1);
784 if (result == NULL) {
797 void SceneGraphReducer::
800 bool got_name =
false;
802 name = source1->get_name();
806 name = source2->get_name();
811 preserve->set_name(name);
820 int SceneGraphReducer::
821 r_remove_column(
PandaNode *node,
const InternalName *column,
833 for (
int i = 0; i < num_children; ++i) {
835 r_remove_column(children.
get_child(i), column, transformer);
846 int SceneGraphReducer::
858 for (
int i = 0; i < num_children; ++i) {
860 r_make_compatible_state(children.
get_child(i), transformer);
872 int SceneGraphReducer::
873 r_collect_vertex_data(
PandaNode *node,
int collect_bits,
875 int num_adjusted = 0;
877 int this_node_bits = 0;
878 if (node->
is_of_type(ModelNode::get_class_type())) {
879 this_node_bits |= CVD_model;
881 if (!node->get_transform()->is_identity()) {
882 this_node_bits |= CVD_transform;
885 this_node_bits |= CVD_one_node_only;
888 if ((collect_bits & this_node_bits) != 0) {
899 for (
int i = 0; i < num_children; ++i) {
901 r_collect_vertex_data(children.
get_child(i), collect_bits, new_transformer, format_only);
915 for (
int i = 0; i < num_children; ++i) {
917 r_collect_vertex_data(children.
get_child(i), collect_bits, transformer, format_only);
931 int SceneGraphReducer::
932 r_make_nonindexed(
PandaNode *node,
int nonindexed_bits) {
938 for (
int i = 0; i < num_geoms; ++i) {
939 const Geom *geom = geom_node->get_geom(i);
944 int this_geom_bits = 0;
945 if (data->
get_format()->get_animation().get_animation_type() !=
947 this_geom_bits |= MN_avoid_animated;
951 this_geom_bits |= MN_avoid_dynamic;
954 if ((nonindexed_bits & this_geom_bits) == 0) {
957 PT(
Geom) mgeom = geom_node->modify_geom(i);
958 num_changed += mgeom->make_nonindexed((nonindexed_bits & MN_composite_only) != 0);
965 for (
int i = 0; i < num_children; ++i) {
967 r_make_nonindexed(children.
get_child(i), nonindexed_bits);
978 void SceneGraphReducer::
979 r_unify(
PandaNode *node,
int max_indices,
bool preserve_order) {
982 geom_node->
unify(max_indices, preserve_order);
987 for (
int i = 0; i < num_children; ++i) {
988 r_unify(children.
get_child(i), max_indices, preserve_order);
1000 void SceneGraphReducer::
1009 for (
int i = 0; i < num_children; ++i) {
1010 r_register_vertices(children.
get_child(i), transformer);
1019 void SceneGraphReducer::
1028 for (
int i = 0; i < num_children; ++i) {
1038 void SceneGraphReducer::
1040 CPT(
RenderState) next_state = state->compose(node->get_state());
1044 geom_node->
do_premunge(_gsg, next_state, _transformer);
1050 for (i = 0; i < num_children; ++i) {
1051 r_premunge(children.
get_child(i), next_state);
1056 for (i = 0; i < num_stashed; ++i) {
1057 r_premunge(stashed.get_stashed(i), next_state);
void remove_unused_vertices(PandaNode *root)
Removes any vertices in GeomVertexDatas that are no longer used at this level and below...
int get_num_children() const
Returns the number of children of the node.
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
A basic node of the scene graph or data graph.
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
This is our own Panda specialization on the default STL map.
int get_num_stashed(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of stashed nodes this node has.
bool replace_child(PandaNode *orig_child, PandaNode *new_child, Thread *current_thread=Thread::get_current_thread())
Searches for the orig_child node in the node's list of children, and replaces it with the new_child i...
virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, GeomTransformer &transformer)
Applies whatever attributes are specified in the AccumulatedAttribs object (and by the attrib_types b...
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
DrawMask get_draw_control_mask() const
Returns the set of bits in draw_show_mask that are considered meaningful.
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
bool is_empty() const
Any kind of volume might be empty.
void collect(PandaNode *node, int attrib_types)
Collects the state and transform from the indicated node and adds it to the accumulator, removing it from the node.
UsageHint get_usage_hint() const
Returns the minimum (i.e.
This defines a bounding sphere, consisting of a center and a radius.
bool is_infinite() const
The other side of the empty coin is an infinite volume.
bool safe_to_transform() const
Returns true if all of the effects in this set can safely be transformed, and therefore the complete ...
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other...
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This is our own Panda specialization on the default STL list.
int get_num_geoms() const
Returns the number of geoms in the node.
void decompose()
Calls decompose() on each Geom with the GeomNode.
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
void clear_gsg()
Specifies that no particular GraphicsStateGuardian will be used to guide the optimization.
PandaNode * get_stashed(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth stashed child of this node.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void decompose(PandaNode *root)
Calls decompose() on every GeomNode at this level and below.
A lightweight class that represents a single element that may be timed and/or counted via stats...
DrawMask get_draw_show_mask() const
Returns the hide/show bits of this particular node.
int remove_column(PandaNode *root, const InternalName *column)
Removes the indicated data column from any GeomVertexDatas found at the indicated root and below...
void do_premunge(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer)
Uses the indicated GSG to premunge the Geoms in this node to optimize them for eventual rendering...
void set_gsg(GraphicsStateGuardianBase *gsg)
Specifies the particular GraphicsStateGuardian that this object will attempt to optimize to...
int compare_tags(const PandaNode *other) const
Returns a number less than 0, 0, or greater than 0, to indicate the similarity of tags between this n...
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
void unify(PandaNode *root, bool preserve_order)
Calls unify() on every GeomNode at this level and below.
const GeomVertexFormat * get_format() const
Returns a pointer to the GeomVertexFormat structure that defines this data.
UsageHint get_usage_hint() const
Returns the usage hint that was passed to the constructor, and which will be passed to each array dat...
bool is_under_scene_root() const
Returns true if this particular node is in a live scene graph: that is, it is a child or descendent o...
virtual PandaNode * dupe_for_flatten() const
This is similar to make_copy(), but it makes a copy for the specific purpose of flatten.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
static GraphicsStateGuardianBase * get_default_gsg()
Returns a pointer to the "default" GSG.
A container for geometry primitives.
virtual bool safe_to_flatten_below() const
Returns true if a flatten operation may safely continue past this node, or false if nodes below this ...
int get_child_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
int flatten(PandaNode *root, int combine_siblings_bits)
Simplifies the graph by removing unnecessary nodes and nodes.
bool check_live_flatten(PandaNode *node)
In a non-release build, returns false if the node is correctly not in a live scene graph...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
int get_num_parents(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of parent nodes this node has.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
void replace_node(PandaNode *other)
Inserts this node into the scene graph in place of the other one, and removes the other node...
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
void unify(int max_indices, bool preserve_order)
Attempts to unify all of the Geoms contained within this node into a single Geom, or at least as few ...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
PandaNode * get_child(int n) const
Returns the nth child of the node.
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of PandaNode by calling the xf...
virtual bool is_geom_node() const
A simple downcast check.
void copy_children(PandaNode *other, Thread *current_thread=Thread::get_current_thread())
Makes another instance of all the children of the other node, copying them to this node...
void apply_to_node(PandaNode *node, int attrib_types)
Stores the indicated attributes in the node's transform and state information; does not attempt to ap...
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
A node that holds Geom objects, renderable pieces of geometry.
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
int make_compatible_state(PandaNode *root)
Searches for GeomNodes that contain multiple Geoms that differ only in their ColorAttribs.