26 PStatCollector SceneGraphReducer::_flatten_collector(
"*:Flatten:flatten");
27 PStatCollector SceneGraphReducer::_apply_collector(
"*:Flatten:apply");
28 PStatCollector SceneGraphReducer::_remove_column_collector(
"*:Flatten:remove column");
29 PStatCollector SceneGraphReducer::_compatible_state_collector(
"*:Flatten:compatible colors");
30 PStatCollector SceneGraphReducer::_collect_collector(
"*:Flatten:collect");
31 PStatCollector SceneGraphReducer::_make_nonindexed_collector(
"*:Flatten:make nonindexed");
32 PStatCollector SceneGraphReducer::_unify_collector(
"*:Flatten:unify");
33 PStatCollector SceneGraphReducer::_remove_unused_collector(
"*:Flatten:remove unused vertices");
34 PStatCollector SceneGraphReducer::_premunge_collector(
"*:Premunge");
51 int max_vertices = max_collect_vertices;
53 if (_gsg !=
nullptr) {
54 max_vertices = std::min(max_vertices, _gsg->get_max_vertices_per_array());
89 int num_total_nodes = 0;
101 for (
int i = 0; i < num_children; i++) {
103 num_pass_nodes += r_flatten(root, child_node, combine_siblings_bits);
106 if (combine_siblings_bits != 0 &&
109 num_pass_nodes += flatten_siblings(root, combine_siblings_bits);
112 num_total_nodes += num_pass_nodes;
117 }
while ((combine_siblings_bits & CS_recurse) != 0 && num_pass_nodes != 0);
119 return num_total_nodes;
131 int count = r_remove_column(root, column, _transformer);
146 PStatTimer timer(_compatible_state_collector);
147 int count = r_make_compatible_state(root, _transformer);
166 if (!preserve_triangle_strips) {
182 int max_indices = max_collect_indices;
183 if (_gsg !=
nullptr) {
184 max_indices = std::min(max_indices, _gsg->get_max_vertices_per_primitive());
186 r_unify(root, max_indices, preserve_order);
200 r_register_vertices(root, _transformer);
217 if (allow_live_flatten) {
232 void SceneGraphReducer::
235 if (pgraph_cat.is_spam()) {
237 <<
"r_apply_attribs(" << *node <<
"), node's attribs are:\n";
238 node->get_transform()->write(pgraph_cat.spam(
false), 2);
239 node->get_state()->write(pgraph_cat.spam(
false), 2);
240 node->get_effects()->write(pgraph_cat.spam(
false), 2);
244 next_attribs.collect(node, attrib_types);
246 if (pgraph_cat.is_spam()) {
248 <<
"Got attribs from " << *node <<
"\n" 249 <<
"Accumulated attribs are:\n";
250 next_attribs.write(pgraph_cat.spam(
false), attrib_types, 2);
256 if (pgraph_cat.is_spam()) {
258 <<
"Not applying further; " << *node
259 <<
" doesn't allow flattening below itself.\n";
261 next_attribs.apply_to_node(node, attrib_types);
269 if (pgraph_cat.is_spam()) {
272 <<
" contains a non-transformable effect; leaving transform here.\n";
274 next_attribs._transform = effects->prepare_flatten_transform(next_attribs._transform);
275 apply_types |= TT_transform;
278 if (pgraph_cat.is_spam()) {
280 <<
"Cannot safely transform nodes of type " << node->get_type()
281 <<
"; leaving a transform here but carrying on otherwise.\n";
283 apply_types |= TT_transform;
291 if ((apply_types & TT_transform) == 0) {
292 bool children_transform_friendly =
true;
293 for (i = 0; i < num_children && children_transform_friendly; i++) {
298 if (!children_transform_friendly) {
299 if (pgraph_cat.is_spam()) {
302 <<
" has a child that cannot modify its transform; leaving transform here.\n";
304 apply_types |= TT_transform;
309 next_attribs.apply_to_node(node, attrib_types & apply_types);
315 bool resist_copy =
false;
316 for (i = 0; i < num_children; i++) {
321 if (pgraph_cat.is_spam()) {
323 <<
"Cannot duplicate nodes of type " << child_node->get_type()
330 if (new_node->get_type() != child_node->get_type()) {
332 <<
"Don't know how to copy nodes of type " 333 << child_node->get_type() <<
"\n";
335 if (no_unsupported_copy) {
336 nassert_raise(
"unsupported copy");
342 if (pgraph_cat.is_spam()) {
344 <<
"Duplicated " << *child_node <<
"\n";
349 child_node = new_node;
358 next_attribs.apply_to_node(node, attrib_types);
363 for (i = 0; i < num_children; i++) {
365 r_apply_attribs(child_node, next_attribs, attrib_types, transformer);
374 int SceneGraphReducer::
376 int combine_siblings_bits) {
377 if (pgraph_cat.is_spam()) {
379 <<
"SceneGraphReducer::r_flatten(" << *grandparent_node <<
", " 380 << *parent_node <<
", " << std::hex << combine_siblings_bits << std::dec
384 if ((combine_siblings_bits & (CS_geom_node | CS_other | CS_recurse)) != 0) {
387 combine_siblings_bits &= ~CS_within_radius;
393 if (pgraph_cat.is_spam()) {
395 <<
"Not traversing further; " << *parent_node
396 <<
" doesn't allow flattening below itself.\n";
400 if ((combine_siblings_bits & CS_within_radius) != 0) {
402 if (bv->is_of_type(BoundingSphere::get_class_type())) {
404 if (pgraph_cat.is_spam()) {
406 <<
"considering radius of " << *parent_node
407 <<
": " << *bs <<
" vs. " << _combine_radius <<
"\n";
412 if (pgraph_cat.is_spam()) {
414 <<
"node fits within radius; flattening tighter.\n";
416 combine_siblings_bits &= ~CS_within_radius;
417 combine_siblings_bits |= (CS_geom_node | CS_other | CS_recurse);
426 for (
int i = 0; i < num_children; i++) {
428 num_nodes += r_flatten(parent_node, child_node, combine_siblings_bits);
439 if ((combine_siblings_bits & CS_recurse) != 0 &&
442 num_nodes += flatten_siblings(parent_node, combine_siblings_bits);
450 if (consider_child(grandparent_node, parent_node, child_node)) {
454 if (do_flatten_child(grandparent_node, parent_node, child_node)) {
459 parent_node->add_child(child_node, child_sort);
464 if ((combine_siblings_bits & CS_recurse) == 0 &&
465 (combine_siblings_bits & ~CS_recurse) != 0 &&
468 num_nodes += flatten_siblings(parent_node, combine_siblings_bits);
476 if (child_node->
is_exact_type(PandaNode::get_class_type()) &&
478 child_node->get_transform()->is_identity() &&
479 child_node->get_effects()->is_empty()) {
496 INLINE
bool SortByState::
498 if (node1->get_transform() != node2->get_transform()) {
499 return node1->get_transform() < node2->get_transform();
501 if (node1->get_state() != node2->get_state()) {
502 return node1->get_state() < node2->get_state();
504 if (node1->get_effects() != node2->get_effects()) {
505 return node1->get_effects() < node2->get_effects();
526 int SceneGraphReducer::
527 flatten_siblings(
PandaNode *parent_node,
int combine_siblings_bits) {
540 for (
int i = 0; i < num_children; i++) {
543 if (safe_to_combine) {
545 safe_to_combine = (combine_siblings_bits & CS_geom_node) != 0;
547 safe_to_combine = (combine_siblings_bits & CS_other) != 0;
551 if (safe_to_combine) {
552 collected[child_node].push_back(child_node);
561 Collected::iterator ci;
562 for (ci = collected.begin(); ci != collected.end(); ++ci) {
564 if (effects->safe_to_combine()) {
565 NodeList &nodes = (*ci).second;
567 NodeList::iterator ai1;
569 while (ai1 != nodes.end()) {
570 NodeList::iterator ai1_hold = ai1;
573 NodeList::iterator ai2 = ai1;
574 while (ai2 != nodes.end()) {
575 NodeList::iterator ai2_hold = ai2;
579 if (consider_siblings(parent_node, child1, child2)) {
581 do_flatten_siblings(parent_node, child1, child2);
582 if (new_node !=
nullptr) {
584 (*ai1_hold) = new_node;
585 nodes.erase(ai2_hold);
604 bool SceneGraphReducer::
613 if (parent_node->get_transform() != child_node->get_transform() ||
614 parent_node->get_state() != child_node->get_state() ||
615 parent_node->get_effects() != child_node->get_effects() ||
623 if (!parent_node->get_effects()->safe_to_combine()) {
636 bool SceneGraphReducer::
650 bool SceneGraphReducer::
653 if (pgraph_cat.is_spam()) {
655 <<
"Collapsing " << *parent_node <<
" and " << *child_node <<
"\n";
658 PT(
PandaNode) new_parent = collapse_nodes(parent_node, child_node,
false);
659 if (new_parent ==
nullptr) {
660 if (pgraph_cat.is_spam()) {
662 <<
"Decided not to collapse " << *parent_node
663 <<
" and " << *child_node <<
"\n";
668 choose_name(new_parent, parent_node, child_node);
670 new_parent->replace_node(child_node);
671 new_parent->replace_node(parent_node);
687 if (pgraph_cat.is_spam()) {
689 <<
"Collapsing " << *child1 <<
" and " << *child2 <<
"\n";
692 PT(
PandaNode) new_child = collapse_nodes(child2, child1,
true);
693 if (new_child ==
nullptr) {
694 if (pgraph_cat.is_spam()) {
696 <<
"Decided not to collapse " << *child1 <<
" and " << *child2 <<
"\n";
701 choose_name(new_child, child2, child1);
706 new_child->replace_node(child1);
721 if (result ==
nullptr) {
732 void SceneGraphReducer::
735 bool got_name =
false;
737 name = source1->get_name();
741 name = source2->get_name();
746 preserve->set_name(name);
753 int SceneGraphReducer::
766 for (
int i = 0; i < num_children; ++i) {
768 r_remove_column(children.
get_child(i), column, transformer);
777 int SceneGraphReducer::
789 for (
int i = 0; i < num_children; ++i) {
791 r_make_compatible_state(children.
get_child(i), transformer);
800 int SceneGraphReducer::
801 r_collect_vertex_data(
PandaNode *node,
int collect_bits,
803 int num_adjusted = 0;
805 int this_node_bits = 0;
806 if (node->
is_of_type(ModelNode::get_class_type())) {
807 this_node_bits |= CVD_model;
809 if (!node->get_transform()->is_identity()) {
810 this_node_bits |= CVD_transform;
813 this_node_bits |= CVD_one_node_only;
816 if ((collect_bits & this_node_bits) != 0) {
822 num_adjusted += new_transformer.collect_vertex_data(DCAST(
GeomNode, node), collect_bits, format_only);
827 for (
int i = 0; i < num_children; ++i) {
829 r_collect_vertex_data(children.
get_child(i), collect_bits, new_transformer, format_only);
832 num_adjusted += new_transformer.finish_collect(format_only);
843 for (
int i = 0; i < num_children; ++i) {
845 r_collect_vertex_data(children.
get_child(i), collect_bits, transformer, format_only);
856 int SceneGraphReducer::
857 r_make_nonindexed(
PandaNode *node,
int nonindexed_bits) {
863 for (
int i = 0; i < num_geoms; ++i) {
864 const Geom *geom = geom_node->get_geom(i);
869 int this_geom_bits = 0;
870 if (data->get_format()->get_animation().get_animation_type() !=
872 this_geom_bits |= MN_avoid_animated;
874 if (data->get_usage_hint() != Geom::UH_static ||
876 this_geom_bits |= MN_avoid_dynamic;
879 if ((nonindexed_bits & this_geom_bits) == 0) {
882 PT(
Geom) mgeom = geom_node->modify_geom(i);
883 num_changed += mgeom->make_nonindexed((nonindexed_bits & MN_composite_only) != 0);
890 for (
int i = 0; i < num_children; ++i) {
892 r_make_nonindexed(children.
get_child(i), nonindexed_bits);
901 void SceneGraphReducer::
902 r_unify(
PandaNode *node,
int max_indices,
bool preserve_order) {
905 geom_node->
unify(max_indices, preserve_order);
910 for (
int i = 0; i < num_children; ++i) {
911 r_unify(children.
get_child(i), max_indices, preserve_order);
920 void SceneGraphReducer::
929 for (
int i = 0; i < num_children; ++i) {
930 r_register_vertices(children.
get_child(i), transformer);
937 void SceneGraphReducer::
946 for (
int i = 0; i < num_children; ++i) {
954 void SceneGraphReducer::
956 CPT(
RenderState) next_state = state->compose(node->get_state());
960 geom_node->
do_premunge(_gsg, next_state, _transformer);
966 for (i = 0; i < num_children; ++i) {
967 r_premunge(children.
get_child(i), next_state);
972 for (i = 0; i < num_stashed; ++i) {
void remove_unused_vertices(PandaNode *root)
Removes any vertices in GeomVertexDatas that are no longer used at this level and below.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode * get_stashed(size_t n) const
Returns the nth stashed child of the node.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
bool is_empty() const
Any kind of volume might be empty.
get_num_parents
Returns the number of parent nodes this node has.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool safe_to_transform() const
Returns true if all of the effects in this set can safely be transformed, and therefore the complete ...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_draw_control_mask
Returns the set of bits in draw_show_mask that are considered meaningful.
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.
int remove_column(PandaNode *root, const InternalName *column)
Removes the indicated data column from any GeomVertexDatas found at the indicated root and below.
PT(PandaNode) SceneGraphReducer
Collapses the two nodes into a single node, if possible.
get_draw_show_mask
Returns the hide/show bits of this particular node.
get_num_children
Returns the number of child nodes this node has.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
size_t get_num_children() const
Returns the number of children of the node.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for geometry primitives.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_children
Returns an object that can be used to walk through the list of children of the node.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Encodes a string name in a hash table, mapping it to a pointer.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_stashed
Returns the nth stashed child of this node.
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.
get_num_geoms
Returns the number of geoms in the node.
size_t get_num_stashed() const
Returns the number of stashed 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.
get_child
Returns the nth child node of this 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.
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.