26PStatCollector SceneGraphReducer::_flatten_collector(
"*:Flatten:flatten");
27PStatCollector SceneGraphReducer::_apply_collector(
"*:Flatten:apply");
28PStatCollector SceneGraphReducer::_remove_column_collector(
"*:Flatten:remove column");
29PStatCollector SceneGraphReducer::_compatible_state_collector(
"*:Flatten:compatible colors");
30PStatCollector SceneGraphReducer::_collect_collector(
"*:Flatten:collect");
31PStatCollector SceneGraphReducer::_make_nonindexed_collector(
"*:Flatten:make nonindexed");
32PStatCollector SceneGraphReducer::_unify_collector(
"*:Flatten:unify");
33PStatCollector SceneGraphReducer::_remove_unused_collector(
"*:Flatten:remove unused vertices");
34PStatCollector 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());
57 _transformer.set_max_collect_vertices(max_vertices);
68 _transformer.set_max_collect_vertices(max_collect_vertices);
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);
132 _transformer.finish_apply();
146 PStatTimer timer(_compatible_state_collector);
147 int count = r_make_compatible_state(root, _transformer);
148 _transformer.finish_apply();
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);
201 _transformer.finish_apply();
217 if (allow_live_flatten) {
232void 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);
243 AccumulatedAttribs next_attribs(attribs);
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);
267 const RenderEffects *effects = node->get_effects();
269 if (pgraph_cat.is_spam()) {
272 <<
" contains a non-transformable effect; leaving transform here.\n";
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++) {
294 PandaNode *child_node = node->
get_child(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++) {
317 PandaNode *child_node = node->
get_child(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";
347 new_node->copy_children(child_node);
349 child_node = new_node;
358 next_attribs.apply_to_node(node, attrib_types);
363 for (i = 0; i < num_children; i++) {
364 PandaNode *child_node = node->
get_child(i);
365 r_apply_attribs(child_node, next_attribs, attrib_types, transformer);
374int 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) {
401 CPT(BoundingVolume) bv = parent_node->
get_bounds();
402 if (bv->is_of_type(BoundingSphere::get_class_type())) {
403 const BoundingSphere *bs = DCAST(BoundingSphere, bv);
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++) {
427 PT(PandaNode) child_node = cr.
get_child(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);
447 PT(PandaNode) child_node = parent_node->
get_child(0);
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);
475 PandaNode *child_node = parent_node->
get_child(i);
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()) {
493 operator () (
const PandaNode *node1,
const PandaNode *node2)
const;
496INLINE
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();
526int SceneGraphReducer::
527flatten_siblings(
PandaNode *parent_node,
int combine_siblings_bits) {
531 typedef plist< PT(PandaNode) > NodeList;
532 typedef pmap<PandaNode *, NodeList, SortByState> Collected;
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) {
563 const RenderEffects *effects = (*ci).first->get_effects();
565 NodeList &nodes = (*ci).second;
567 NodeList::iterator ai1;
569 while (ai1 != nodes.end()) {
570 NodeList::iterator ai1_hold = ai1;
571 PandaNode *child1 = (*ai1);
573 NodeList::iterator ai2 = ai1;
574 while (ai2 != nodes.end()) {
575 NodeList::iterator ai2_hold = ai2;
576 PandaNode *child2 = (*ai2);
579 if (consider_siblings(parent_node, child1, child2)) {
580 PT(PandaNode) new_node =
581 do_flatten_siblings(parent_node, child1, child2);
582 if (new_node !=
nullptr) {
584 (*ai1_hold) = new_node;
585 nodes.erase(ai2_hold);
604bool 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()) {
636bool SceneGraphReducer::
650bool 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) {
732void SceneGraphReducer::
735 bool got_name =
false;
737 name = source1->get_name();
741 name = source2->get_name();
746 preserve->set_name(name);
753int SceneGraphReducer::
759 if (transformer.
remove_column(DCAST(GeomNode, node), column)) {
766 for (
int i = 0; i < num_children; ++i) {
768 r_remove_column(children.
get_child(i), column, transformer);
777int SceneGraphReducer::
789 for (
int i = 0; i < num_children; ++i) {
791 r_make_compatible_state(children.
get_child(i), transformer);
800int SceneGraphReducer::
801r_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) {
818 GeomTransformer new_transformer(transformer);
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);
838 num_adjusted += transformer.
collect_vertex_data(DCAST(GeomNode, node), collect_bits, 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);
856int SceneGraphReducer::
857r_make_nonindexed(
PandaNode *node,
int nonindexed_bits) {
861 GeomNode *geom_node = DCAST(GeomNode, node);
863 for (
int i = 0; i < num_geoms; ++i) {
864 const Geom *geom = geom_node->get_geom(i);
868 const GeomVertexData *data = geom->get_vertex_data();
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);
901void SceneGraphReducer::
902r_unify(
PandaNode *node,
int max_indices,
bool preserve_order) {
904 GeomNode *geom_node = DCAST(GeomNode, node);
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);
920void SceneGraphReducer::
923 GeomNode *geom_node = DCAST(GeomNode, node);
929 for (
int i = 0; i < num_children; ++i) {
930 r_register_vertices(children.
get_child(i), transformer);
937void SceneGraphReducer::
940 GeomNode *geom_node = DCAST(GeomNode, node);
946 for (
int i = 0; i < num_children; ++i) {
954void SceneGraphReducer::
956 CPT(RenderState) next_state = state->
compose(node->get_state());
959 GeomNode *geom_node = DCAST(GeomNode, node);
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) {
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
bool is_empty() const
Any kind of volume might be empty.
bool is_infinite() const
The other side of the empty coin is an infinite volume.
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.
get_num_geoms
Returns the number of geoms in 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 ...
void decompose()
Calls decompose() on each Geom with the GeomNode.
UsageHint get_usage_hint() const
Returns the minimum (i.e.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
static GraphicsStateGuardianBase * get_default_gsg()
Returns a pointer to the "default" GSG.
Encodes a string name in a hash table, mapping it to a pointer.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
size_t get_num_children() const
Returns the number of children of the node.
PandaNode * get_stashed(size_t n) const
Returns the nth stashed child of the node.
size_t get_num_stashed() const
Returns the number of stashed children of the node.
A basic node of the scene graph or data graph.
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
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...
get_draw_control_mask
Returns the set of bits in draw_show_mask that are considered meaningful.
virtual bool is_geom_node() const
A simple downcast check.
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
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 safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
get_num_parents
Returns the number of parent nodes this node has.
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
get_draw_show_mask
Returns the hide/show bits of this particular 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...
get_child
Returns the nth child node of this 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 ...
virtual PandaNode * dupe_for_flatten() const
This is similar to make_copy(), but it makes a copy for the specific purpose of flatten.
ConstPointerTo< BoundingVolume > get_bounds(Thread *current_thread=Thread::get_current_thread()) const
Returns the external bounding volume of this node: a bounding volume that contains the user bounding ...
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...
void add_child(PandaNode *child_node, int sort=0, Thread *current_thread=Thread::get_current_thread())
Adds a new child to the node.
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...
get_stashed
Returns the nth stashed child of this node.
get_children
Returns an object that can be used to walk through the list of children of the node.
void replace_node(PandaNode *other)
Inserts this node into the scene graph in place of the other one, and removes the other node.
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...
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
get_num_children
Returns the number of child nodes this node has.
bool safe_to_combine() const
Returns true if all of the effects in this set can safely be shared with a sibling node that has the ...
bool safe_to_transform() const
Returns true if all of the effects in this set can safely be transformed, and therefore the complete ...
virtual ConstPointerTo< TransformState > prepare_flatten_transform(const TransformState *net_transform) const
Preprocesses the accumulated transform that is about to be applied to (or through) this node due to a...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
ConstPointerTo< RenderState > compose(const RenderState *other) const
Returns a new RenderState object that represents the composition of this state with the other state.
void set_gsg(GraphicsStateGuardianBase *gsg)
Specifies the particular GraphicsStateGuardian that this object will attempt to optimize to.
int flatten(PandaNode *root, int combine_siblings_bits)
Simplifies the graph by removing unnecessary nodes and nodes.
int make_compatible_state(PandaNode *root)
Searches for GeomNodes that contain multiple Geoms that differ only in their ColorAttribs.
void unify(PandaNode *root, bool preserve_order)
Calls unify() on every GeomNode at this level and below.
void clear_gsg()
Specifies that no particular GraphicsStateGuardian will be used to guide the optimization.
int remove_column(PandaNode *root, const InternalName *column)
Removes the indicated data column from any GeomVertexDatas found at the indicated root and below.
void remove_unused_vertices(PandaNode *root)
Removes any vertices in GeomVertexDatas that are no longer used at this level and below.
bool check_live_flatten(PandaNode *node)
In a non-release build, returns false if the node is correctly not in a live scene graph.
void decompose(PandaNode *root)
Calls decompose() on every GeomNode at this level and below.
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.