Panda3D
pandaNode.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file pandaNode.cxx
10  * @author drose
11  * @date 2002-02-20
12  */
13 
14 #include "pandaNode.h"
15 #include "config_pgraph.h"
16 #include "nodePathComponent.h"
17 #include "bamReader.h"
18 #include "bamWriter.h"
19 #include "indent.h"
21 #include "sceneGraphReducer.h"
22 #include "accumulatedAttribs.h"
23 #include "clipPlaneAttrib.h"
24 #include "boundingSphere.h"
25 #include "boundingBox.h"
26 #include "pStatTimer.h"
27 #include "config_mathutil.h"
28 #include "lightReMutexHolder.h"
30 
31 using std::ostream;
32 using std::ostringstream;
33 using std::string;
34 
35 // This category is just temporary for debugging convenience.
36 NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
37 NotifyCategoryDef(drawmask, "");
38 
39 TypeHandle PandaNode::BamReaderAuxDataDown::_type_handle;
40 
41 PandaNode::SceneRootFunc *PandaNode::_scene_root_func;
42 
43 PandaNodeChain PandaNode::_dirty_prev_transforms("_dirty_prev_transforms");
44 DrawMask PandaNode::_overall_bit = DrawMask::bit(31);
45 
46 PStatCollector PandaNode::_reset_prev_pcollector("App:Collisions:Reset");
47 PStatCollector PandaNode::_update_bounds_pcollector("*:Bounds");
48 
49 TypeHandle PandaNode::_type_handle;
50 TypeHandle PandaNode::CData::_type_handle;
51 TypeHandle PandaNodePipelineReader::_type_handle;
52 
53 /*
54  * There are two different interfaces here for making and breaking parent-
55  * child connections: the fundamental PandaNode interface, via add_child() and
56  * remove_child() (and related functions), and the NodePath support interface,
57  * via attach(), detach(), and reparent(). They both do essentially the same
58  * thing, but with slightly different inputs. The PandaNode interfaces try to
59  * guess which NodePaths should be updated as a result of the scene graph
60  * change, while the NodePath interfaces already know. The NodePath support
61  * interface functions are strictly called from within the NodePath class, and
62  * are used to implement NodePath::reparent_to() and NodePath::remove_node(),
63  * etc. The fundamental interface, on the other hand, is intended to be
64  * called directly by the user. The fundamental interface has a slightly
65  * lower overhead because it does not need to create a NodePathComponent chain
66  * where one does not already exist; however, the NodePath support interface
67  * is more useful when the NodePath already does exist, because it ensures
68  * that the particular NodePath calling it is kept appropriately up-to-date.
69  */
70 
71 
72 /**
73  *
74  */
75 PandaNode::
76 PandaNode(const string &name) :
77  Namable(name),
78  _paths_lock("PandaNode::_paths_lock"),
79  _dirty_prev_transform(false)
80 {
81  if (pgraph_cat.is_debug()) {
82  pgraph_cat.debug()
83  << "Constructing " << (void *)this << ", " << get_name() << "\n";
84  }
85 
86 #ifdef DO_MEMORY_USAGE
87  MemoryUsage::update_type(this, this);
88 #endif
89 }
90 
91 /**
92  *
93  */
94 PandaNode::
95 ~PandaNode() {
96  if (pgraph_cat.is_debug()) {
97  pgraph_cat.debug()
98  << "Destructing " << (void *)this << ", " << get_name() << "\n";
99  }
100 
101  if (_dirty_prev_transform) {
102  // Need to have this held before we grab any other locks.
103  LightMutexHolder holder(_dirty_prev_transforms._lock);
104  do_clear_dirty_prev_transform();
105  }
106 
107  // We shouldn't have any parents left by the time we destruct, or there's a
108  // refcount fault somewhere.
109 
110  // Actually, that's not necessarily true anymore, since we might be updating
111  // a node dynamically via the bam reader, which doesn't necessarily keep
112  // related pairs of nodes in sync with each other.
113  /*
114 #ifndef NDEBUG
115  {
116  CDReader cdata(_cycler);
117  nassertv(cdata->get_up()->empty());
118  }
119 #endif // NDEBUG
120  */
121 
123 }
124 
125 /**
126  * Do not call the copy constructor directly; instead, use make_copy() or
127  * copy_subgraph() to make a copy of a node.
128  */
129 PandaNode::
130 PandaNode(const PandaNode &copy) :
132  Namable(copy),
133  _paths_lock("PandaNode::_paths_lock"),
134  _dirty_prev_transform(false),
135  _python_tag_data(copy._python_tag_data),
136  _unexpected_change_flags(0)
137 {
138  if (pgraph_cat.is_debug()) {
139  pgraph_cat.debug()
140  << "Copying " << (void *)this << ", " << get_name() << "\n";
141  }
142 #ifdef DO_MEMORY_USAGE
143  MemoryUsage::update_type(this, this);
144 #endif
145 
146  // Need to have this held before we grab any other locks.
147  LightMutexHolder holder(_dirty_prev_transforms._lock);
148 
149  // Copy the other node's state.
150  {
151  CDReader copy_cdata(copy._cycler);
152  CDWriter cdata(_cycler, true);
153  cdata->_state = copy_cdata->_state;
154  cdata->_transform = copy_cdata->_transform;
155  cdata->_prev_transform = copy_cdata->_prev_transform;
156  if (cdata->_transform != cdata->_prev_transform) {
157  do_set_dirty_prev_transform();
158  }
159 
160  cdata->_effects = copy_cdata->_effects;
161  cdata->_tag_data = copy_cdata->_tag_data;
162  cdata->_draw_control_mask = copy_cdata->_draw_control_mask;
163  cdata->_draw_show_mask = copy_cdata->_draw_show_mask;
164  cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
165  cdata->_bounds_type = copy_cdata->_bounds_type;
166  cdata->_user_bounds = copy_cdata->_user_bounds;
167  cdata->_internal_bounds = nullptr;
168  cdata->_internal_bounds_computed = UpdateSeq::initial();
169  cdata->_internal_bounds_mark = UpdateSeq::initial();
170  ++cdata->_internal_bounds_mark;
171  cdata->_final_bounds = copy_cdata->_final_bounds;
172  cdata->_fancy_bits = copy_cdata->_fancy_bits;
173  }
174 }
175 
176 /**
177  * This is similar to make_copy(), but it makes a copy for the specific
178  * purpose of flatten. Typically, this will be a new PandaNode with a new
179  * pointer, but all of the internal data will always be shared with the
180  * original; whereas the new node returned by make_copy() might not share the
181  * internal data.
182  */
184 dupe_for_flatten() const {
185  return make_copy();
186 }
187 
188 /**
189  * Returns true if it is generally safe to flatten out this particular kind of
190  * PandaNode by duplicating instances (by calling dupe_for_flatten()), false
191  * otherwise (for instance, a Camera cannot be safely flattened, because the
192  * Camera pointer itself is meaningful).
193  */
195 safe_to_flatten() const {
196  return true;
197 }
198 
199 /**
200  * Returns true if it is generally safe to transform this particular kind of
201  * PandaNode by calling the xform() method, false otherwise.
202  */
204 safe_to_transform() const {
205  return true;
206 }
207 
208 /**
209  * Returns true if it is safe to automatically adjust the transform on this
210  * kind of node. Usually, this is only a bad idea if the user expects to find
211  * a particular transform on the node.
212  *
213  * ModelNodes with the preserve_transform flag set are presently the only
214  * kinds of nodes that should not have their transform even adjusted.
215  */
217 safe_to_modify_transform() const {
218  return true;
219 }
220 
221 /**
222  * Returns true if it is generally safe to combine this particular kind of
223  * PandaNode with other kinds of PandaNodes of compatible type, adding
224  * children or whatever. For instance, an LODNode should not be combined with
225  * any other PandaNode, because its set of children is meaningful.
226  */
228 safe_to_combine() const {
229  return true;
230 }
231 
232 /**
233  * Returns true if it is generally safe to combine the children of this
234  * PandaNode with each other. For instance, an LODNode's children should not
235  * be combined with each other, because the set of children is meaningful.
236  */
238 safe_to_combine_children() const {
239  return true;
240 }
241 
242 /**
243  * Returns true if a flatten operation may safely continue past this node, or
244  * false if nodes below this node may not be molested.
245  */
247 safe_to_flatten_below() const {
248  return true;
249 }
250 
251 /**
252  * Returns true if the node's name has extrinsic meaning and must be preserved
253  * across a flatten operation, false otherwise.
254  */
256 preserve_name() const {
257  return false;
258 }
259 
260 /**
261  * Returns the union of all attributes from SceneGraphReducer::AttribTypes
262  * that may not safely be applied to the vertices of this node. If this is
263  * nonzero, these attributes must be dropped at this node as a state change.
264  *
265  * This is a generalization of safe_to_transform().
266  */
269  return 0;
270 }
271 
272 /**
273  * Applies whatever attributes are specified in the AccumulatedAttribs object
274  * (and by the attrib_types bitmask) to the vertices on this node, if
275  * appropriate. If this node uses geom arrays like a GeomNode, the supplied
276  * GeomTransformer may be used to unify shared arrays across multiple
277  * different nodes.
278  *
279  * This is a generalization of xform().
280  */
282 apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
283  GeomTransformer &transformer) {
284  if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
285  const LMatrix4 &mat = attribs._transform->get_mat();
286  xform(mat);
287 
288  Thread *current_thread = Thread::get_current_thread();
289  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
290  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
291  cdata->_effects = cdata->_effects->xform(mat);
292  cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
293  }
294  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
295  }
297 }
298 
299 /**
300  * Transforms the contents of this PandaNode by the indicated matrix, if it
301  * means anything to do so. For most kinds of PandaNodes, this does nothing.
302  */
304 xform(const LMatrix4 &) {
305 }
306 
307 /**
308  * Collapses this PandaNode with the other PandaNode, if possible, and returns
309  * a pointer to the combined PandaNode, or NULL if the two PandaNodes cannot
310  * safely be combined.
311  *
312  * The return value may be this, other, or a new PandaNode altogether.
313  *
314  * This function is called from GraphReducer::flatten(), and need not deal
315  * with children; its job is just to decide whether to collapse the two
316  * PandaNodes and what the collapsed PandaNode should look like.
317  */
319 combine_with(PandaNode *other) {
320  // An unadorned PandaNode always combines with any other PandaNodes by
321  // yielding completely. However, if we are actually some fancy PandaNode
322  // type that derives from PandaNode but didn't redefine this function, we
323  // should refuse to combine.
324  if (is_exact_type(get_class_type())) {
325  // No, we're an ordinary PandaNode.
326  return other;
327 
328  } else if (other->is_exact_type(get_class_type())) {
329  // We're not an ordinary PandaNode, but the other one is.
330  return this;
331  }
332 
333  // We're something other than an ordinary PandaNode. Don't combine.
334  return nullptr;
335 }
336 
337 /**
338  * This is used to support NodePath::calc_tight_bounds(). It is not intended
339  * to be called directly, and it has nothing to do with the normal Panda
340  * bounding-volume computation.
341  *
342  * If the node contains any geometry, this updates min_point and max_point to
343  * enclose its bounding box. found_any is to be set true if the node has any
344  * geometry at all, or left alone if it has none. This method may be called
345  * over several nodes, so it may enter with min_point, max_point, and
346  * found_any already set.
347  *
348  * This function is recursive, and the return value is the transform after it
349  * has been modified by this node's transform.
350  */
351 CPT(TransformState) PandaNode::
352 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any,
353  const TransformState *transform, Thread *current_thread) const {
354  CPT(TransformState) next_transform = transform->compose(get_transform());
355 
356  Children cr = get_children(current_thread);
357  int num_children = cr.get_num_children();
358  for (int i = 0; i < num_children; i++) {
359  cr.get_child(i)->calc_tight_bounds(min_point, max_point,
360  found_any, next_transform,
361  current_thread);
362  }
363 
364  return next_transform;
365 }
366 
367 /**
368  * This function will be called during the cull traversal to perform any
369  * additional operations that should be performed at cull time. This may
370  * include additional manipulation of render state or additional
371  * visible/invisible decisions, or any other arbitrary operation.
372  *
373  * Note that this function will *not* be called unless set_cull_callback() is
374  * called in the constructor of the derived class. It is necessary to call
375  * set_cull_callback() to indicated that we require cull_callback() to be
376  * called.
377  *
378  * By the time this function is called, the node has already passed the
379  * bounding-volume test for the viewing frustum, and the node's transform and
380  * state have already been applied to the indicated CullTraverserData object.
381  *
382  * The return value is true if this node should be visible, or false if it
383  * should be culled.
384  */
385 bool PandaNode::
386 cull_callback(CullTraverser *, CullTraverserData &) {
387  return true;
388 }
389 
390 /**
391  * Should be overridden by derived classes to return true if this kind of node
392  * has some restrictions on the set of children that should be rendered. Node
393  * with this property include LODNodes, SwitchNodes, and SequenceNodes.
394  *
395  * If this function returns true, get_first_visible_child() and
396  * get_next_visible_child() will be called to walk through the list of
397  * children during cull, instead of iterating through the entire list. This
398  * method is called after cull_callback(), so cull_callback() may be
399  * responsible for the decisions as to which children are visible at the
400  * moment.
401  */
403 has_selective_visibility() const {
404  return false;
405 }
406 
407 /**
408  * Returns the index number of the first visible child of this node, or a
409  * number >= get_num_children() if there are no visible children of this node.
410  * This is called during the cull traversal, but only if
411  * has_selective_visibility() has already returned true. See
412  * has_selective_visibility().
413  */
415 get_first_visible_child() const {
416  return 0;
417 }
418 
419 /**
420  * Returns the index number of the next visible child of this node following
421  * the indicated child, or a number >= get_num_children() if there are no more
422  * visible children of this node. See has_selective_visibility() and
423  * get_first_visible_child().
424  */
426 get_next_visible_child(int n) const {
427  return n + 1;
428 }
429 
430 /**
431  * Should be overridden by derived classes to return true if this kind of node
432  * has the special property that just one of its children is visible at any
433  * given time, and furthermore that the particular visible child can be
434  * determined without reference to any external information (such as a
435  * camera). At present, only SequenceNodes and SwitchNodes fall into this
436  * category.
437  *
438  * If this function returns true, get_visible_child() can be called to return
439  * the index of the currently-visible child.
440  */
443  return false;
444 }
445 
446 /**
447  * Returns the index number of the currently visible child of this node. This
448  * is only meaningful if has_single_child_visibility() has returned true.
449  */
451 get_visible_child() const {
452  return 0;
453 }
454 
455 /**
456  * Returns true if there is some value to visiting this particular node during
457  * the cull traversal for any camera, false otherwise. This will be used to
458  * optimize the result of get_net_draw_show_mask(), so that any subtrees that
459  * contain only nodes for which is_renderable() is false need not be visited.
460  */
462 is_renderable() const {
463  return false;
464 }
465 
466 /**
467  * Adds the node's contents to the CullResult we are building up during the
468  * cull traversal, so that it will be drawn at render time. For most nodes
469  * other than GeomNodes, this is a do-nothing operation.
470  */
473 }
474 
475 /**
476  * Returns a newly-allocated PandaNode that is a shallow copy of this one. It
477  * will be a different pointer, but its internal data may or may not be shared
478  * with that of the original PandaNode. No children will be copied.
479  */
481 make_copy() const {
482  return new PandaNode(*this);
483 }
484 
485 /**
486  * Allocates and returns a complete copy of this PandaNode and the entire
487  * scene graph rooted at this PandaNode. Some data may still be shared from
488  * the original (e.g. vertex index tables), but nothing that will impede
489  * normal use of the PandaNode.
490  */
491 PT(PandaNode) PandaNode::
492 copy_subgraph(Thread *current_thread) const {
493  InstanceMap inst_map;
494  return r_copy_subgraph(inst_map, current_thread);
495 }
496 
497 /**
498  * Returns the number of nodes at and below this level.
499  */
500 int PandaNode::
501 count_num_descendants() const {
502  int count = 1;
503  Children children = get_children();
504  int num_children = children.get_num_children();
505 
506  for (int i = 0; i < num_children; ++i) {
507  PandaNode *child = children.get_child(i);
508  count += child->count_num_descendants();
509  }
510 
511  return count;
512 }
513 
514 /**
515  * Adds a new child to the node. The child is added in the relative position
516  * indicated by sort; if all children have the same sort index, the child is
517  * added at the end.
518  *
519  * If the same child is added to a node more than once, the previous instance
520  * is first removed.
521  */
522 void PandaNode::
523 add_child(PandaNode *child_node, int sort, Thread *current_thread) {
524  nassertv(child_node != nullptr);
525 
526  if (!verify_child_no_cycles(child_node)) {
527  // Whoops, adding this child node would introduce a cycle in the scene
528  // graph.
529  return;
530  }
531 
532  // Ensure the child_node is not deleted while we do this.
533  PT(PandaNode) keep_child = child_node;
534  remove_child(child_node);
535 
536  // Apply this operation to the current stage as well as to all upstream
537  // stages.
538  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
539  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
540  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
541 
542  cdata->modify_down()->insert(DownConnection(child_node, sort));
543  cdata_child->modify_up()->insert(UpConnection(this));
544  }
545  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
546 
547  OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
548  new_connection(this, child_node, pipeline_stage, current_thread);
549  }
550  CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
551 
552  force_bounds_stale();
553 
554  children_changed();
555  child_node->parents_changed();
557  child_node->mark_bam_modified();
558 }
559 
560 /**
561  * Removes the nth child from the node.
562  */
564 remove_child(int child_index, Thread *current_thread) {
565  int pipeline_stage = current_thread->get_pipeline_stage();
566  nassertv(pipeline_stage == 0);
567 
568  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
569  PT(Down) down = cdata->modify_down();
570  nassertv(child_index >= 0 && child_index < (int)down->size());
571 
572  PT(PandaNode) child_node = (*down)[child_index].get_child();
573  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
574  current_thread);
575  PT(Up) up = cdata_child->modify_up();
576 
577  down->erase(down->begin() + child_index);
578  int num_erased = up->erase(UpConnection(this));
579  nassertv(num_erased == 1);
580 
581  sever_connection(this, child_node, pipeline_stage, current_thread);
582  force_bounds_stale(pipeline_stage, current_thread);
583 
584  children_changed();
585  child_node->parents_changed();
587  child_node->mark_bam_modified();
588 }
589 
590 /**
591  * Removes the indicated child from the node. Returns true if the child was
592  * removed, false if it was not already a child of the node. This will also
593  * successfully remove the child if it had been stashed.
594  */
596 remove_child(PandaNode *child_node, Thread *current_thread) {
597  nassertr(child_node != nullptr, false);
598 
599  // Make sure the child node is not destructed during the execution of this
600  // method.
601  PT(PandaNode) keep_child = child_node;
602 
603  // We have to do this for each upstream pipeline stage.
604  bool any_removed = false;
605 
606  OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
607  if (stage_remove_child(child_node, pipeline_stage, current_thread)) {
608  any_removed = true;
609 
610  sever_connection(this, child_node, pipeline_stage, current_thread);
611  force_bounds_stale(pipeline_stage, current_thread);
612  }
613  }
614  CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
615 
616  if (any_removed) {
617  // Call callback hooks.
618  children_changed();
619  child_node->parents_changed();
620  }
621 
622  return any_removed;
623 }
624 
625 /**
626  * Searches for the orig_child node in the node's list of children, and
627  * replaces it with the new_child instead. Returns true if the replacement is
628  * made, or false if the node is not a child or if there is some other
629  * problem.
630  */
632 replace_child(PandaNode *orig_child, PandaNode *new_child,
633  Thread *current_thread) {
634  nassertr(orig_child != nullptr, false);
635  nassertr(new_child != nullptr, false);
636 
637  if (orig_child == new_child) {
638  // Trivial no-op.
639  return true;
640  }
641 
642  if (!verify_child_no_cycles(new_child)) {
643  // Whoops, adding this child node would introduce a cycle in the scene
644  // graph.
645  return false;
646  }
647 
648  // Make sure the orig_child node is not destructed during the execution of
649  // this method.
650  PT(PandaNode) keep_orig_child = orig_child;
651 
652  // We have to do this for each upstream pipeline stage.
653  bool any_replaced = false;
654 
655  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
656  if (stage_replace_child(orig_child, new_child, pipeline_stage, current_thread)) {
657  any_replaced = true;
658  }
659  }
660  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
661 
662  if (any_replaced) {
663  children_changed();
664  orig_child->parents_changed();
665  new_child->parents_changed();
666  }
667 
668  return any_replaced;
669 }
670 
671 
672 /**
673  * Stashes the indicated child node. This removes the child from the list of
674  * active children and puts it on a special list of stashed children. This
675  * child node no longer contributes to the bounding volume of the PandaNode,
676  * and is not visited in normal traversals. It is invisible and uncollidable.
677  * The child may later be restored by calling unstash_child().
678  *
679  * This can only be called from the top pipeline stage (i.e. from App).
680  */
682 stash_child(int child_index, Thread *current_thread) {
683  int pipeline_stage = current_thread->get_pipeline_stage();
684  nassertv(pipeline_stage == 0);
685  nassertv(child_index >= 0 && child_index < get_num_children());
686 
687  // Save a reference count for ourselves.
688  PT(PandaNode) self = this;
689 
690  PT(PandaNode) child_node = get_child(child_index);
691  int sort = get_child_sort(child_index);
692 
693  remove_child(child_index);
694 
695  {
696  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
697  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
698 
699  cdata->modify_stashed()->insert(DownConnection(child_node, sort));
700  cdata_child->modify_up()->insert(UpConnection(this));
701  }
702 
703  new_connection(this, child_node, pipeline_stage, current_thread);
704  force_bounds_stale(pipeline_stage, current_thread);
705 
706  children_changed();
707  child_node->parents_changed();
709  child_node->mark_bam_modified();
710 }
711 
712 /**
713  * Returns the indicated stashed node to normal child status. This removes
714  * the child from the list of stashed children and puts it on the normal list
715  * of active children. This child node once again contributes to the bounding
716  * volume of the PandaNode, and will be visited in normal traversals. It is
717  * visible and collidable.
718  *
719  * This can only be called from the top pipeline stage (i.e. from App).
720  */
722 unstash_child(int stashed_index, Thread *current_thread) {
723  int pipeline_stage = current_thread->get_pipeline_stage();
724  nassertv(pipeline_stage == 0);
725  nassertv(stashed_index >= 0 && stashed_index < get_num_stashed());
726 
727  // Save a reference count for ourselves. I don't think this should be
728  // necessary, but there are occasional crashes in stash() during furniture
729  // moving mode. Perhaps this will eliminate those crashes.
730  PT(PandaNode) self = this;
731 
732  PT(PandaNode) child_node = get_stashed(stashed_index);
733  int sort = get_stashed_sort(stashed_index);
734 
735  remove_stashed(stashed_index);
736 
737  {
738  CDWriter cdata(_cycler);
739  CDWriter cdata_child(child_node->_cycler);
740 
741  cdata->modify_down()->insert(DownConnection(child_node, sort));
742  cdata_child->modify_up()->insert(UpConnection(this));
743  }
744 
745  new_connection(this, child_node, pipeline_stage, current_thread);
746 
747  force_bounds_stale();
748  children_changed();
749  child_node->parents_changed();
751  child_node->mark_bam_modified();
752 }
753 
754 /**
755  * Adds a new child to the node, directly as a stashed child. The child is
756  * not added in the normal sense, but will be revealed if unstash_child() is
757  * called on it later.
758  *
759  * If the same child is added to a node more than once, the previous instance
760  * is first removed.
761  *
762  * This can only be called from the top pipeline stage (i.e. from App).
763  */
765 add_stashed(PandaNode *child_node, int sort, Thread *current_thread) {
766  int pipeline_stage = current_thread->get_pipeline_stage();
767  nassertv(pipeline_stage == 0);
768 
769  if (!verify_child_no_cycles(child_node)) {
770  // Whoops, adding this child node would introduce a cycle in the scene
771  // graph.
772  return;
773  }
774 
775  // Ensure the child_node is not deleted while we do this.
776  PT(PandaNode) keep_child = child_node;
777  remove_child(child_node);
778 
779  {
780  CDWriter cdata(_cycler);
781  CDWriter cdata_child(child_node->_cycler);
782 
783  cdata->modify_stashed()->insert(DownConnection(child_node, sort));
784  cdata_child->modify_up()->insert(UpConnection(this));
785  }
786 
787  new_connection(this, child_node, pipeline_stage, current_thread);
788 
789  // Call callback hooks.
790  children_changed();
791  child_node->parents_changed();
793  child_node->mark_bam_modified();
794 }
795 
796 /**
797  * Removes the nth stashed child from the node.
798  */
800 remove_stashed(int child_index, Thread *current_thread) {
801  int pipeline_stage = current_thread->get_pipeline_stage();
802  nassertv(pipeline_stage == 0);
803 
804  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
805  Down &stashed = *cdata->modify_stashed();
806  nassertv(child_index >= 0 && child_index < (int)stashed.size());
807 
808  PT(PandaNode) child_node = stashed[child_index].get_child();
809  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
810 
811  stashed.erase(stashed.begin() + child_index);
812  int num_erased = cdata_child->modify_up()->erase(UpConnection(this));
813  nassertv(num_erased == 1);
814 
815  sever_connection(this, child_node, pipeline_stage, current_thread);
816  force_bounds_stale(pipeline_stage, current_thread);
817 
818  children_changed();
819  child_node->parents_changed();
821  child_node->mark_bam_modified();
822 }
823 
824 /**
825  * Removes all the children from the node at once, including stashed children.
826  *
827  * This can only be called from the top pipeline stage (i.e. from App).
828  */
830 remove_all_children(Thread *current_thread) {
831  // We have to do this for each upstream pipeline stage.
832  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
833  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
834  PT(Down) down = cdata->modify_down();
835  Down::iterator di;
836  for (di = down->begin(); di != down->end(); ++di) {
837  PT(PandaNode) child_node = (*di).get_child();
838  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
839  current_thread);
840  cdata_child->modify_up()->erase(UpConnection(this));
841 
842  sever_connection(this, child_node, pipeline_stage, current_thread);
843  child_node->parents_changed();
844  child_node->mark_bam_modified();
845  }
846  down->clear();
847 
848  Down &stashed = *cdata->modify_stashed();
849  for (di = stashed.begin(); di != stashed.end(); ++di) {
850  PT(PandaNode) child_node = (*di).get_child();
851  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
852  current_thread);
853  cdata_child->modify_up()->erase(UpConnection(this));
854 
855  sever_connection(this, child_node, pipeline_stage, current_thread);
856  child_node->parents_changed();
857  child_node->mark_bam_modified();
858  }
859  stashed.clear();
860  }
861  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
862 
863  force_bounds_stale();
864  children_changed();
866 }
867 
868 /**
869  * Moves all the children from the other node onto this node.
870  *
871  * Any NodePaths to child nodes of the other node are truncated, rather than
872  * moved to the new parent.
873  */
875 steal_children(PandaNode *other, Thread *current_thread) {
876  if (other == this) {
877  // Trivial.
878  return;
879  }
880 
881  // We do this through the high-level interface for convenience. This could
882  // begin to be a problem if we have a node with hundreds of children to
883  // copy; this could break down the ov_set.insert() method, which is an
884  // O(n^2) operation. If this happens, we should rewrite this to do a
885  // simpler add_child() operation that involves push_back() instead of
886  // insert(), and then sort the down list at the end.
887 
888  int num_children = other->get_num_children();
889  int i;
890  for (i = 0; i < num_children; i++) {
891  PandaNode *child_node = other->get_child(i);
892  int sort = other->get_child_sort(i);
893  add_child(child_node, sort, current_thread);
894  }
895  int num_stashed = other->get_num_stashed();
896  for (i = 0; i < num_stashed; i++) {
897  PandaNode *child_node = other->get_stashed(i);
898  int sort = other->get_stashed_sort(i);
899  add_stashed(child_node, sort, current_thread);
900  }
901 
902  other->remove_all_children(current_thread);
903 }
904 
905 /**
906  * Makes another instance of all the children of the other node, copying them
907  * to this node.
908  */
910 copy_children(PandaNode *other, Thread *current_thread) {
911  if (other == this) {
912  // Trivial.
913  return;
914  }
915  Children children = other->get_children(current_thread);
916  Stashed stashed = other->get_stashed(current_thread);
917  int num_children = children.get_num_children();
918  int i;
919  for (i = 0; i < num_children; i++) {
920  PandaNode *child_node = children.get_child(i);
921  int sort = children.get_child_sort(i);
922  add_child(child_node, sort, current_thread);
923  }
924  int num_stashed = stashed.get_num_stashed();
925  for (i = 0; i < num_stashed; i++) {
926  PandaNode *child_node = stashed.get_stashed(i);
927  int sort = stashed.get_stashed_sort(i);
928  add_stashed(child_node, sort, current_thread);
929  }
930 }
931 
932 /**
933  * Adds the indicated render attribute to the scene graph on this node. This
934  * attribute will now apply to this node and everything below. If there was
935  * already an attribute of the same type, it is replaced.
936  */
938 set_attrib(const RenderAttrib *attrib, int override) {
939  // Apply this operation to the current stage as well as to all upstream
940  // stages.
941  bool any_changed = false;
942  Thread *current_thread = Thread::get_current_thread();
943  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
944  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
945 
946  CPT(RenderState) new_state = cdata->_state->set_attrib(attrib, override);
947  if (cdata->_state != new_state) {
948  cdata->_state = new_state;
949  cdata->set_fancy_bit(FB_state, true);
950  any_changed = true;
951  }
952  }
953  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
954 
955  // Maybe we changed a ClipPlaneAttrib.
956  if (any_changed) {
957  mark_bounds_stale(current_thread);
958  state_changed();
960  }
961 }
962 
963 /**
964  * Removes the render attribute of the given type from this node. This node,
965  * and the subgraph below, will now inherit the indicated render attribute
966  * from the nodes above this one.
967  */
968 void PandaNode::
969 clear_attrib(int slot) {
970  bool any_changed = false;
971 
972  Thread *current_thread = Thread::get_current_thread();
973  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
974  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
975 
976  CPT(RenderState) new_state = cdata->_state->remove_attrib(slot);
977  if (cdata->_state != new_state) {
978  cdata->_state = new_state;
979  cdata->set_fancy_bit(FB_state, !new_state->is_empty());
980  any_changed = true;
981  }
982  }
983  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
984 
985  // We mark the bounds stale when the state changes, in case we have changed
986  // a ClipPlaneAttrib.
987  if (any_changed) {
988  mark_bounds_stale(current_thread);
989  state_changed();
991  }
992 }
993 
994 /**
995  * Adds the indicated render effect to the scene graph on this node. If there
996  * was already an effect of the same type, it is replaced.
997  */
999 set_effect(const RenderEffect *effect) {
1000  // Apply this operation to the current stage as well as to all upstream
1001  // stages.
1002  Thread *current_thread = Thread::get_current_thread();
1003  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1004  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1005  cdata->_effects = cdata->_effects->add_effect(effect);
1006  cdata->set_fancy_bit(FB_effects, true);
1007  }
1008  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1010 }
1011 
1012 /**
1013  * Removes the render effect of the given type from this node.
1014  */
1016 clear_effect(TypeHandle type) {
1017  Thread *current_thread = Thread::get_current_thread();
1018  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1019  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1020  cdata->_effects = cdata->_effects->remove_effect(type);
1021  cdata->set_fancy_bit(FB_effects, !cdata->_effects->is_empty());
1022  }
1023  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1025 }
1026 
1027 /**
1028  * Sets the complete RenderState that will be applied to all nodes at this
1029  * level and below. (The actual state that will be applied to lower nodes is
1030  * based on the composition of RenderStates from above this node as well).
1031  * This completely replaces whatever has been set on this node via repeated
1032  * calls to set_attrib().
1033  */
1034 void PandaNode::
1035 set_state(const RenderState *state, Thread *current_thread) {
1036  // Apply this operation to the current stage as well as to all upstream
1037  // stages.
1038  bool any_changed = false;
1039  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1040  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1041  if (cdata->_state != state) {
1042  cdata->_state = state;
1043  cdata->set_fancy_bit(FB_state, !state->is_empty());
1044  any_changed = true;
1045  }
1046  }
1047  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1048 
1049  // Maybe we have changed a ClipPlaneAttrib.
1050  if (any_changed) {
1051  mark_bounds_stale(current_thread);
1052  state_changed();
1054  }
1055 }
1056 
1057 /**
1058  * Sets the complete RenderEffects that will be applied this node. This
1059  * completely replaces whatever has been set on this node via repeated calls
1060  * to set_attrib().
1061  */
1062 void PandaNode::
1063 set_effects(const RenderEffects *effects, Thread *current_thread) {
1064  // Apply this operation to the current stage as well as to all upstream
1065  // stages.
1066  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1067  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1068  cdata->_effects = effects;
1069  cdata->set_fancy_bit(FB_effects, !effects->is_empty());
1070  }
1071  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1073 }
1074 
1075 /**
1076  * Sets the transform that will be applied to this node and below. This
1077  * defines a new coordinate space at this point in the scene graph and below.
1078  */
1079 void PandaNode::
1080 set_transform(const TransformState *transform, Thread *current_thread) {
1081  nassertv(!transform->is_invalid());
1082 
1083  // Need to have this held before we grab any other locks.
1084  LightMutexHolder holder(_dirty_prev_transforms._lock);
1085 
1086  // Apply this operation to the current stage as well as to all upstream
1087  // stages.
1088  bool any_changed = false;
1089  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1090  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1091  if (cdata->_transform != transform) {
1092  cdata->_transform = transform;
1093  cdata->set_fancy_bit(FB_transform, !transform->is_identity());
1094  any_changed = true;
1095 
1096  if (pipeline_stage == 0) {
1097  if (cdata->_transform != cdata->_prev_transform) {
1098  do_set_dirty_prev_transform();
1099  }
1100  }
1101  }
1102  }
1103  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1104 
1105  if (any_changed) {
1106  mark_bounds_stale(current_thread);
1107  transform_changed();
1109  }
1110 }
1111 
1112 /**
1113  * Sets the transform that represents this node's "previous" position, one
1114  * frame ago, for the purposes of detecting motion for accurate collision
1115  * calculations.
1116  */
1118 set_prev_transform(const TransformState *transform, Thread *current_thread) {
1119  nassertv(!transform->is_invalid());
1120 
1121  // Need to have this held before we grab any other locks.
1122  LightMutexHolder holder(_dirty_prev_transforms._lock);
1123 
1124  // Apply this operation to the current stage as well as to all upstream
1125  // stages.
1126  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1127  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1128  cdata->_prev_transform = transform;
1129  if (pipeline_stage == 0) {
1130  if (cdata->_transform != cdata->_prev_transform) {
1131  do_set_dirty_prev_transform();
1132  } else {
1133  do_clear_dirty_prev_transform();
1134  }
1135  }
1136  }
1137  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1139 }
1140 
1141 /**
1142  * Resets the transform that represents this node's "previous" position to the
1143  * same as the current transform. This is not the same thing as clearing it
1144  * to identity.
1145  */
1147 reset_prev_transform(Thread *current_thread) {
1148  // Need to have this held before we grab any other locks.
1149  LightMutexHolder holder(_dirty_prev_transforms._lock);
1150  do_clear_dirty_prev_transform();
1151 
1152  // Apply this operation to the current stage as well as to all upstream
1153  // stages.
1154 
1155  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1156  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1157  cdata->_prev_transform = cdata->_transform;
1158  }
1159  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1161 }
1162 
1163 /**
1164  * Visits all nodes in the world with the _dirty_prev_transform flag--that is,
1165  * all nodes whose _prev_transform is different from the _transform in
1166  * pipeline stage 0--and resets the _prev_transform to be the same as
1167  * _transform.
1168  */
1170 reset_all_prev_transform(Thread *current_thread) {
1171  nassertv(current_thread->get_pipeline_stage() == 0);
1172 
1173  PStatTimer timer(_reset_prev_pcollector, current_thread);
1174  LightMutexHolder holder(_dirty_prev_transforms._lock);
1175 
1176  LinkedListNode *list_node = _dirty_prev_transforms._next;
1177  while (list_node != &_dirty_prev_transforms) {
1178  PandaNode *panda_node = (PandaNode *)list_node;
1179  nassertv(panda_node->_dirty_prev_transform);
1180  panda_node->_dirty_prev_transform = false;
1181 
1182  CDStageWriter cdata(panda_node->_cycler, 0, current_thread);
1183  cdata->_prev_transform = cdata->_transform;
1184 
1185  list_node = panda_node->_next;
1186 #ifndef NDEBUG
1187  panda_node->_prev = nullptr;
1188  panda_node->_next = nullptr;
1189 #endif // NDEBUG
1190  panda_node->mark_bam_modified();
1191  }
1192 
1193  _dirty_prev_transforms._prev = &_dirty_prev_transforms;
1194  _dirty_prev_transforms._next = &_dirty_prev_transforms;
1195 }
1196 
1197 /**
1198  * Associates a user-defined value with a user-defined key which is stored on
1199  * the node. This value has no meaning to Panda; but it is stored
1200  * indefinitely on the node until it is requested again.
1201  *
1202  * Each unique key stores a different string value. There is no effective
1203  * limit on the number of different keys that may be stored or on the length
1204  * of any one key's value.
1205  */
1206 void PandaNode::
1207 set_tag(const string &key, const string &value, Thread *current_thread) {
1208  // Apply this operation to the current stage as well as to all upstream
1209  // stages.
1210  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1211  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1212  cdata->_tag_data.store(key, value);
1213  cdata->set_fancy_bit(FB_tag, true);
1214  }
1215  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1217 }
1218 
1219 /**
1220  * Removes the value defined for this key on this particular node. After a
1221  * call to clear_tag(), has_tag() will return false for the indicated key.
1222  */
1223 void PandaNode::
1224 clear_tag(const string &key, Thread *current_thread) {
1225  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1226  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1227  cdata->_tag_data.remove(key);
1228  cdata->set_fancy_bit(FB_tag, !cdata->_tag_data.is_empty());
1229  }
1230  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1232 }
1233 
1234 /**
1235  * Copies all of the tags stored on the other node onto this node. If a
1236  * particular tag exists on both nodes, the contents of this node's value is
1237  * replaced by that of the other.
1238  */
1240 copy_tags(PandaNode *other) {
1241  if (other == this) {
1242  // Trivial.
1243  return;
1244  }
1245 
1246  // Apply this operation to the current stage as well as to all upstream
1247  // stages.
1248  Thread *current_thread = Thread::get_current_thread();
1249  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1250  CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1251  CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1252 
1253  for (size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
1254  cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
1255  }
1256  cdataw->set_fancy_bit(FB_tag, !cdataw->_tag_data.is_empty());
1257  }
1258  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1259 
1260  // It's okay to copy the tags by pointer, because get_python_tags does a
1261  // copy-on-write.
1262  _python_tag_data = other->_python_tag_data;
1263 
1265 }
1266 
1267 /**
1268  * Writes a list of all the tag keys assigned to the node to the indicated
1269  * stream. Writes one instance of the separator following each key (but does
1270  * not write a terminal separator). The value associated with each key is not
1271  * written.
1272  *
1273  * This is mainly for the benefit of the realtime user, to see the list of all
1274  * of the associated tag keys.
1275  */
1277 list_tags(ostream &out, const string &separator) const {
1278  CDReader cdata(_cycler);
1279  for (size_t n = 0; n < cdata->_tag_data.size(); ++n) {
1280  if (n > 0) {
1281  out << separator;
1282  }
1283  out << cdata->_tag_data.get_key(n);
1284  }
1285 
1286  // We used to list the Python tags here. That's a bit awkward, though,
1287  // since that means calling up into Python code to print the keys. If
1288  // someone finds it useful, we can implement it in an extension method.
1289 }
1290 
1291 /**
1292  * Fills the given vector up with the list of tags on this PandaNode.
1293  *
1294  * It is the user's responsibility to ensure that the keys vector is empty
1295  * before making this call; otherwise, the new keys will be appended to it.
1296  */
1298 get_tag_keys(vector_string &keys) const {
1299  CDReader cdata(_cycler);
1300  for (size_t n = 0; n < cdata->_tag_data.size(); ++n) {
1301  keys.push_back(cdata->_tag_data.get_key(n));
1302  }
1303 }
1304 
1305 /**
1306  * Returns a number less than 0, 0, or greater than 0, to indicate the
1307  * similarity of tags between this node and the other one. If this returns 0,
1308  * the tags are identical. If it returns other than 0, then the tags are
1309  * different; and the nodes may be sorted into a consistent (but arbitrary)
1310  * ordering based on this number.
1311  */
1313 compare_tags(const PandaNode *other) const {
1314  CDReader cdata(_cycler);
1315  CDReader cdata_other(other->_cycler);
1316 
1317  const TagData &a_data = cdata->_tag_data;
1318  const TagData &b_data = cdata_other->_tag_data;
1319 
1320  size_t ai = 0;
1321  size_t bi = 0;
1322  while (ai < a_data.size() && bi < b_data.size()) {
1323  int cmp = strcmp(a_data.get_key(ai).c_str(), b_data.get_key(bi).c_str());
1324  if (cmp != 0) {
1325  return cmp;
1326  }
1327 
1328  cmp = strcmp(a_data.get_key(ai).c_str(), b_data.get_key(bi).c_str());
1329  if (cmp != 0) {
1330  return cmp;
1331  }
1332 
1333  ++ai;
1334  ++bi;
1335  }
1336  if (ai < a_data.size()) {
1337  // list A is longer.
1338  return 1;
1339  }
1340  if (bi < b_data.size()) {
1341  // list B is longer.
1342  return -1;
1343  }
1344 
1345  // We compare these by pointer, since it's problematic to call up into
1346  // Python from arbitrary C++ code.
1347  if (_python_tag_data != other->_python_tag_data) {
1348  return (_python_tag_data < other->_python_tag_data) ? -1 : 1;
1349  }
1350 
1351  return 0;
1352 }
1353 
1354 /**
1355  * Copies the TransformState, RenderState, RenderEffects, tags, Python tags,
1356  * and the show/hide state from the other node onto this one. Typically this
1357  * is used to prepare a node to replace another node in the scene graph (also
1358  * see replace_node()).
1359  */
1362  if (other == this) {
1363  // Trivial.
1364  return;
1365  }
1366 
1367  // Need to have this held before we grab any other locks.
1368  LightMutexHolder holder(_dirty_prev_transforms._lock);
1369 
1370  bool any_transform_changed = false;
1371  bool any_state_changed = false;
1372  bool any_draw_mask_changed = false;
1373  Thread *current_thread = Thread::get_current_thread();
1374  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1375  CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
1376  CDStageReader cdatar(other->_cycler, pipeline_stage, current_thread);
1377 
1378  if (cdataw->_transform != cdatar->_transform) {
1379  any_transform_changed = true;
1380  }
1381  if (cdataw->_state != cdatar->_state) {
1382  any_state_changed = true;
1383  }
1384  if (cdataw->_draw_control_mask != cdatar->_draw_control_mask ||
1385  cdataw->_draw_show_mask != cdatar->_draw_show_mask) {
1386  any_draw_mask_changed = true;
1387  }
1388 
1389  cdataw->_transform = cdatar->_transform;
1390  cdataw->_prev_transform = cdatar->_prev_transform;
1391  cdataw->_state = cdatar->_state;
1392  cdataw->_effects = cdatar->_effects;
1393  cdataw->_draw_control_mask = cdatar->_draw_control_mask;
1394  cdataw->_draw_show_mask = cdatar->_draw_show_mask;
1395 
1396  // The collide mask becomes the union of the two masks. This is important
1397  // to preserve properties such as the default GeomNode bitmask.
1398  cdataw->_into_collide_mask |= cdatar->_into_collide_mask;
1399 
1400  for (size_t n = 0; n < cdatar->_tag_data.size(); ++n) {
1401  cdataw->_tag_data.store(cdatar->_tag_data.get_key(n), cdatar->_tag_data.get_data(n));
1402  }
1403 
1404  static const int change_bits = (FB_transform | FB_state | FB_effects |
1405  FB_tag | FB_draw_mask);
1406  cdataw->_fancy_bits =
1407  (cdataw->_fancy_bits & ~change_bits) |
1408  (cdatar->_fancy_bits & change_bits);
1409 
1410  if (pipeline_stage == 0) {
1411  if (cdataw->_transform != cdataw->_prev_transform) {
1412  do_set_dirty_prev_transform();
1413  }
1414  }
1415  }
1416  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1417 
1418  // It's okay to copy the tags by pointer, because get_python_tags does a
1419  // copy-on-write.
1420  _python_tag_data = other->_python_tag_data;
1421 
1422  if (any_transform_changed || any_state_changed || any_draw_mask_changed) {
1423  mark_bounds_stale(current_thread);
1424 
1425  if (any_transform_changed) {
1426  transform_changed();
1427  }
1428  if (any_state_changed) {
1429  state_changed();
1430  }
1431  if (any_draw_mask_changed) {
1432  draw_mask_changed();
1433  }
1435  }
1436 }
1437 
1438 /**
1439  * Inserts this node into the scene graph in place of the other one, and
1440  * removes the other node. All scene graph attributes (TransformState,
1441  * RenderState, etc.) are copied to this node.
1442  *
1443  * All children are moved to this node, and removed from the old node. The
1444  * new node is left in the same place in the old node's parent's list of
1445  * children.
1446  *
1447  * Even NodePaths that reference the old node are updated in-place to
1448  * reference the new node instead.
1449  *
1450  * This method is intended to be used to replace a node of a given type in the
1451  * scene graph with a node of a different type.
1452  */
1454 replace_node(PandaNode *other) {
1455  // nassertv(Thread::get_current_pipeline_stage() == 0);
1456 
1457  if (other == this) {
1458  // Trivial.
1459  return;
1460  }
1461 
1462  // Make sure the other node is not destructed during the execution of this
1463  // method.
1464  PT(PandaNode) keep_other = other;
1465 
1466  // Get all the important scene graph properties.
1467  copy_all_properties(other);
1468 
1469  // Fix up the NodePaths.
1470  {
1471  LightReMutexHolder holder1(other->_paths_lock);
1472  LightReMutexHolder holder2(_paths_lock);
1473  Paths::iterator pi;
1474  for (pi = other->_paths.begin(); pi != other->_paths.end(); ++pi) {
1475  (*pi)->_node = this;
1476  _paths.insert(*pi);
1477  }
1478  other->_paths.clear();
1479  }
1480 
1481  // Get the children.
1482  steal_children(other);
1483 
1484  // Switch the parents.
1485  Thread *current_thread = Thread::get_current_thread();
1486  Parents other_parents = other->get_parents();
1487  for (size_t i = 0; i < other_parents.get_num_parents(); ++i) {
1488  PandaNode *parent = other_parents.get_parent(i);
1489  if (find_parent(parent) != -1) {
1490  // This node was already a child of this parent; don't change it.
1491  parent->remove_child(other);
1492  } else {
1493  // This node was not yet a child of this parent; now it is.
1494  parent->replace_child(other, this, current_thread);
1495  }
1496  }
1497 }
1498 
1499 /**
1500  * Sets one or more of the PandaNode::UnexpectedChange bits on, indicating
1501  * that the corresponding property should not change again on this node. Once
1502  * one of these bits has been set, if the property changes, an assertion
1503  * failure will be raised, which is designed to assist the developer in
1504  * identifying the troublesome code that modified the property unexpectedly.
1505  *
1506  * The input parameter is the union of bits that are to be set. To clear
1507  * these bits later, use clear_unexpected_change().
1508  *
1509  * Since this is a developer debugging tool only, this function does nothing
1510  * in a production (NDEBUG) build.
1511  */
1513 set_unexpected_change(unsigned int flags) {
1514 #ifndef NDEBUG
1515  _unexpected_change_flags |= flags;
1516 #endif // !NDEBUG
1517 }
1518 
1519 /**
1520  * Returns nonzero if any of the bits in the input parameter are set on this
1521  * node, or zero if none of them are set. More specifically, this returns the
1522  * particular set of bits (masked by the input parameter) that have been set
1523  * on this node. See set_unexpected_change().
1524  *
1525  * Since this is a developer debugging tool only, this function always returns
1526  * zero in a production (NDEBUG) build.
1527  */
1528 unsigned int PandaNode::
1529 get_unexpected_change(unsigned int flags) const {
1530 #ifndef NDEBUG
1531  return _unexpected_change_flags & flags;
1532 #else
1533  return 0;
1534 #endif // !NDEBUG
1535 }
1536 
1537 /**
1538  * Sets one or more of the PandaNode::UnexpectedChange bits off, indicating
1539  * that the corresponding property may once again change on this node. See
1540  * set_unexpected_change().
1541  *
1542  * The input parameter is the union of bits that are to be cleared.
1543  *
1544  * Since this is a developer debugging tool only, this function does nothing
1545  * in a production (NDEBUG) build.
1546  */
1548 clear_unexpected_change(unsigned int flags) {
1549 #ifndef NDEBUG
1550  _unexpected_change_flags &= ~flags;
1551 #endif // !NDEBUG
1552 }
1553 
1554 /**
1555  * Adjusts the hide/show bits of this particular node.
1556  *
1557  * These three parameters can be used to adjust the _draw_control_mask and
1558  * _draw_show_mask independently, which work together to provide per-camera
1559  * visibility for the node and its descendents.
1560  *
1561  * _draw_control_mask indicates the bits in _draw_show_mask that are
1562  * significant. Each different bit corresponds to a different camera (and
1563  * these bits are assigned via Camera::set_camera_mask()).
1564  *
1565  * Where _draw_control_mask has a 1 bit, a 1 bit in _draw_show_mask indicates
1566  * the node is visible to that camera, and a 0 bit indicates the node is
1567  * hidden to that camera. Where _draw_control_mask is 0, the node is hidden
1568  * only if a parent node is hidden.
1569  *
1570  * The meaning of the three parameters is as follows:
1571  *
1572  * * Wherever show_mask is 1, _draw_show_mask and _draw_control_mask will be
1573  * set 1. Thus, show_mask indicates the set of cameras to which the node
1574  * should be shown.
1575  *
1576  * * Wherever hide_mask is 1, _draw_show_mask will be set 0 and
1577  * _draw_control_mask will be set 1. Thus, hide_mask indicates the set of
1578  * cameras from which the node should be hidden.
1579  *
1580  * * Wherever clear_mask is 1, _draw_control_mask will be set 0. Thus,
1581  * clear_mask indicates the set of cameras from which the hidden state should
1582  * be inherited from a parent.
1583  */
1585 adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask) {
1586  bool any_changed = false;
1587 
1588  Thread *current_thread = Thread::get_current_thread();
1589  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1590  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1591 
1592  DrawMask draw_control_mask = (cdata->_draw_control_mask | show_mask | hide_mask) & ~clear_mask;
1593  DrawMask draw_show_mask = (cdata->_draw_show_mask | show_mask) & ~hide_mask;
1594  // The uncontrolled bits are implicitly on.
1595  draw_show_mask |= ~draw_control_mask;
1596 
1597  if (cdata->_draw_control_mask != draw_control_mask ||
1598  cdata->_draw_show_mask != draw_show_mask) {
1599  cdata->_draw_control_mask = draw_control_mask;
1600  cdata->_draw_show_mask = draw_show_mask;
1601  any_changed = true;
1602  }
1603  cdata->set_fancy_bit(FB_draw_mask, !draw_control_mask.is_zero());
1604  }
1605  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1606 
1607  if (any_changed) {
1608  mark_bounds_stale(current_thread);
1609  draw_mask_changed();
1611  }
1612 }
1613 
1614 /**
1615  * Returns the set of bits in get_net_draw_show_mask() that have been
1616  * explicitly set via adjust_draw_mask(), rather than implicitly inherited.
1617  *
1618  * A 1 bit in any position of this mask indicates that (a) this node has
1619  * renderable children, and (b) some child of this node has made an explicit
1620  * hide() or show_through() call for the corresponding bit.
1621  */
1623 get_net_draw_control_mask() const {
1624  Thread *current_thread = Thread::get_current_thread();
1625  int pipeline_stage = current_thread->get_pipeline_stage();
1626  CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1627  if (cdata->_last_update != cdata->_next_update) {
1628  // The cache is stale; it needs to be rebuilt.
1629  PStatTimer timer(_update_bounds_pcollector);
1630  CDStageWriter cdataw =
1631  ((PandaNode *)this)->update_cached(false, pipeline_stage, cdata);
1632  return cdataw->_net_draw_control_mask;
1633  }
1634  return cdata->_net_draw_control_mask;
1635 }
1636 
1637 /**
1638  * Returns the union of all draw_show_mask values--of renderable nodes only--
1639  * at this level and below. If any bit in this mask is 0, there is no reason
1640  * to traverse below this node for a camera with the corresponding
1641  * camera_mask.
1642  *
1643  * The bits in this mask that do not correspond to a 1 bit in the
1644  * net_draw_control_mask are meaningless (and will be set to 1). For bits
1645  * that *do* correspond to a 1 bit in the net_draw_control_mask, a 1 bit
1646  * indicates that at least one child should be visible, while a 0 bit
1647  * indicates that all children are hidden.
1648  */
1650 get_net_draw_show_mask() const {
1651  Thread *current_thread = Thread::get_current_thread();
1652  int pipeline_stage = current_thread->get_pipeline_stage();
1653  CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1654  if (cdata->_last_update != cdata->_next_update) {
1655  // The cache is stale; it needs to be rebuilt.
1656  PStatTimer timer(_update_bounds_pcollector);
1657  CDStageWriter cdataw =
1658  ((PandaNode *)this)->update_cached(false, pipeline_stage, cdata);
1659  return cdataw->_net_draw_show_mask;
1660  }
1661  return cdata->_net_draw_show_mask;
1662 }
1663 
1664 /**
1665  * Sets the "into" CollideMask.
1666  *
1667  * This specifies the set of bits that must be shared with a CollisionNode's
1668  * "from" CollideMask in order for the CollisionNode to detect a collision
1669  * with this particular node.
1670  *
1671  * The actual CollideMask that will be set is masked by the return value from
1672  * get_legal_collide_mask(). Thus, the into_collide_mask cannot be set to
1673  * anything other than nonzero except for those types of nodes that can be
1674  * collided into, such as CollisionNodes and GeomNodes.
1675  */
1676 void PandaNode::
1678  mask &= get_legal_collide_mask();
1679 
1680  bool any_changed = false;
1681  Thread *current_thread = Thread::get_current_thread();
1682  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1683  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1684  if (cdata->_into_collide_mask != mask) {
1685  cdata->_into_collide_mask = mask;
1686  any_changed = true;
1687  }
1688  }
1689  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1690 
1691  if (any_changed) {
1692  mark_bounds_stale(current_thread);
1694  }
1695 }
1696 
1697 /**
1698  * Returns the subset of CollideMask bits that may be set for this particular
1699  * type of PandaNode. For most nodes, this is 0; it doesn't make sense to set
1700  * a CollideMask for most kinds of nodes.
1701  *
1702  * For nodes that can be collided with, such as GeomNode and CollisionNode,
1703  * this returns all bits on.
1704  */
1706 get_legal_collide_mask() const {
1707  return CollideMask::all_off();
1708 }
1709 
1710 /**
1711  * Returns the union of all into_collide_mask() values set at CollisionNodes
1712  * at this level and below.
1713  */
1715 get_net_collide_mask(Thread *current_thread) const {
1716  int pipeline_stage = current_thread->get_pipeline_stage();
1717  CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1718  if (cdata->_last_update != cdata->_next_update) {
1719  // The cache is stale; it needs to be rebuilt.
1720  PStatTimer timer(_update_bounds_pcollector);
1721  CDStageWriter cdataw =
1722  ((PandaNode *)this)->update_cached(false, pipeline_stage, cdata);
1723  return cdataw->_net_collide_mask;
1724  }
1725  return cdata->_net_collide_mask;
1726 }
1727 
1728 /**
1729  * Returns a ClipPlaneAttrib which represents the union of all of the clip
1730  * planes that have been turned *off* at this level and below.
1731  */
1732 CPT(RenderAttrib) PandaNode::
1733 get_off_clip_planes(Thread *current_thread) const {
1734  int pipeline_stage = current_thread->get_pipeline_stage();
1735  CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1736  if (cdata->_last_update != cdata->_next_update) {
1737  // The cache is stale; it needs to be rebuilt.
1738  PStatTimer timer(_update_bounds_pcollector);
1739  CDStageWriter cdataw =
1740  ((PandaNode *)this)->update_cached(false, pipeline_stage, cdata);
1741  return cdataw->_off_clip_planes;
1742  }
1743  return cdata->_off_clip_planes;
1744 }
1745 
1746 /**
1747  * Walks through the scene graph beginning at this node, and does whatever
1748  * initialization is required to render the scene properly with the indicated
1749  * GSG. It is not strictly necessary to call this, since the GSG will
1750  * initialize itself when the scene is rendered, but this may take some of the
1751  * overhead away from that process.
1752  *
1753  * In particular, this will ensure that textures and vertex buffers within the
1754  * scene are loaded into graphics memory.
1755  */
1756 void PandaNode::
1757 prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state) {
1758  GeomTransformer transformer;
1759  Thread *current_thread = Thread::get_current_thread();
1760  r_prepare_scene(gsg, node_state, transformer, current_thread);
1761 }
1762 
1763 /**
1764  * Returns true if this particular node is known to be the render root of some
1765  * active DisplayRegion associated with the global GraphicsEngine, false
1766  * otherwise.
1767  */
1769 is_scene_root() const {
1770  // This function pointer has to be filled in when the global GraphicsEngine
1771  // is created, because we can't link with the GraphicsEngine functions
1772  // directly.
1773  if (_scene_root_func != nullptr) {
1774  return (*_scene_root_func)(this);
1775  }
1776  return false;
1777 }
1778 
1779 /**
1780  * Returns true if this particular node is in a live scene graph: that is, it
1781  * is a child or descendent of a node that is itself a scene root. If this is
1782  * true, this node may potentially be traversed by the render traverser.
1783  * Stashed nodes don't count for this purpose, but hidden nodes do.
1784  */
1786 is_under_scene_root() const {
1787  if (is_scene_root()) {
1788  return true;
1789  }
1790 
1791  Parents parents = get_parents();
1792  for (size_t i = 0; i < parents.get_num_parents(); ++i) {
1793  PandaNode *parent = parents.get_parent(i);
1794  if (parent->find_stashed((PandaNode *)this) == -1) {
1795  if (parent->is_under_scene_root()) {
1796  return true;
1797  }
1798  }
1799  }
1800  return false;
1801 }
1802 
1803 /**
1804  *
1805  */
1806 void PandaNode::
1807 output(ostream &out) const {
1808  out << get_type() << " " << get_name();
1809 }
1810 
1811 /**
1812  *
1813  */
1814 void PandaNode::
1815 write(ostream &out, int indent_level) const {
1816  indent(out, indent_level) << *this;
1817  if (has_tags()) {
1818  out << " [";
1819  list_tags(out, " ");
1820  out << "]";
1821  }
1822  CPT(TransformState) transform = get_transform();
1823  if (!transform->is_identity()) {
1824  out << " " << *transform;
1825  }
1826  CPT(RenderState) state = get_state();
1827  if (!state->is_empty()) {
1828  out << " " << *state;
1829  }
1830  CPT(RenderEffects) effects = get_effects();
1831  if (!effects->is_empty()) {
1832  out << " " << *effects;
1833  }
1834  DrawMask draw_control_mask = get_draw_control_mask();
1835  if (!draw_control_mask.is_zero()) {
1836  DrawMask draw_show_mask = get_draw_show_mask();
1837  if (!(draw_control_mask & _overall_bit).is_zero()) {
1838  if (!(draw_show_mask & _overall_bit).is_zero()) {
1839  out << " (show_through)";
1840  } else {
1841  out << " (hidden)";
1842  }
1843  }
1844  if (!(draw_control_mask & ~_overall_bit).is_zero()) {
1845  draw_control_mask &= ~_overall_bit;
1846  if (!(draw_show_mask & draw_control_mask).is_zero()) {
1847  out << " (per-camera show_through)";
1848  }
1849  if (!(~draw_show_mask & draw_control_mask).is_zero()) {
1850  out << " (per-camera hidden)";
1851  }
1852  }
1853  }
1854  out << "\n";
1855 }
1856 
1857 /**
1858  * Specifies the desired type of bounding volume that will be created for this
1859  * node. This is normally BoundingVolume::BT_default, which means to set the
1860  * type according to the config variable "bounds-type".
1861  *
1862  * If this is BT_sphere or BT_box, a BoundingSphere or BoundingBox is
1863  * explicitly created. If it is BT_best, the appropriate type to best enclose
1864  * the node's children is created.
1865  *
1866  * This affects the bounding volume returned by get_bounds(), which is not
1867  * exactly the same bounding volume modified by set_bounds(), because a new
1868  * bounding volume has to be created that includes this node and all of its
1869  * children.
1870  */
1872 set_bounds_type(BoundingVolume::BoundsType bounds_type) {
1873  Thread *current_thread = Thread::get_current_thread();
1874  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1875  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1876  cdata->_bounds_type = bounds_type;
1877  mark_bounds_stale(pipeline_stage, current_thread);
1878 
1879  // GeomNodes, CollisionNodes, and PGItems all have an internal bounds that
1880  // may need to be updated when the bounds_type changes.
1881  mark_internal_bounds_stale(pipeline_stage, current_thread);
1883  }
1884  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1885 }
1886 
1887 /**
1888  * Returns the bounding volume type set with set_bounds_type().
1889  */
1890 BoundingVolume::BoundsType PandaNode::
1891 get_bounds_type() const {
1892  CDReader cdata(_cycler);
1893  return cdata->_bounds_type;
1894 }
1895 
1896 /**
1897  * Resets the bounding volume so that it is the indicated volume. When it is
1898  * explicitly set, the bounding volume will no longer be automatically
1899  * computed according to the contents of the node itself, for nodes like
1900  * GeomNodes and TextNodes that contain substance (but the bounding volume
1901  * will still be automatically expanded to include its children).
1902  *
1903  * Call clear_bounds() if you would like to return the bounding volume to its
1904  * default behavior later.
1905  */
1907 set_bounds(const BoundingVolume *volume) {
1908  Thread *current_thread = Thread::get_current_thread();
1909  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
1910  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
1911  if (volume == nullptr) {
1912  cdata->_user_bounds = nullptr;
1913  } else {
1914  cdata->_user_bounds = volume->make_copy();
1915  }
1916  mark_bounds_stale(pipeline_stage, current_thread);
1918  }
1919  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
1920 }
1921 
1922 /**
1923  * Deprecated. Use set_bounds() instead.
1924  */
1926 set_bound(const BoundingVolume *volume) {
1927  pgraph_cat.warning()
1928  << "Deprecated PandaNode::set_bound() called. Use set_bounds() instead.\n";
1929  set_bounds(volume);
1930 }
1931 
1932 /**
1933  * Returns the external bounding volume of this node: a bounding volume that
1934  * contains the user bounding volume, the internal bounding volume, and all of
1935  * the children's bounding volumes.
1936  */
1937 CPT(BoundingVolume) PandaNode::
1938 get_bounds(Thread *current_thread) const {
1939  int pipeline_stage = current_thread->get_pipeline_stage();
1940  CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1941  if (cdata->_last_bounds_update != cdata->_next_update) {
1942  // The cache is stale; it needs to be rebuilt.
1943  CPT(BoundingVolume) result;
1944  {
1945  PStatTimer timer(_update_bounds_pcollector);
1946  CDStageWriter cdataw =
1947  ((PandaNode *)this)->update_cached(true, pipeline_stage, cdata);
1948  result = cdataw->_external_bounds;
1949  }
1950  return result;
1951  }
1952  return cdata->_external_bounds;
1953 }
1954 
1955 /**
1956  * This flavor of get_bounds() return the external bounding volume, and also
1957  * fills in seq with the bounding volume's current sequence number. When this
1958  * sequence number changes, it indicates that the bounding volume might have
1959  * changed, e.g. because some nested child's bounding volume has changed.
1960  *
1961  * Although this might occasionally increment without changing the bounding
1962  * volume, the bounding volume will never change without incrementing this
1963  * counter, so as long as this counter remains unchanged you can be confident
1964  * the bounding volume is also unchanged.
1965  */
1966 CPT(BoundingVolume) PandaNode::
1967 get_bounds(UpdateSeq &seq, Thread *current_thread) const {
1968  int pipeline_stage = current_thread->get_pipeline_stage();
1969  CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1970  if (cdata->_last_bounds_update != cdata->_next_update) {
1971  // The cache is stale; it needs to be rebuilt.
1972  CPT(BoundingVolume) result;
1973  {
1974  PStatTimer timer(_update_bounds_pcollector);
1975  CDStageWriter cdataw =
1976  ((PandaNode *)this)->update_cached(true, pipeline_stage, cdata);
1977  result = cdataw->_external_bounds;
1978  seq = cdataw->_last_bounds_update;
1979  }
1980  return result;
1981  }
1982  seq = cdata->_last_bounds_update;
1983  return cdata->_external_bounds;
1984 }
1985 
1986 /**
1987  * Returns the total number of vertices that will be rendered by this node and
1988  * all of its descendents.
1989  *
1990  * This is not necessarily an accurate count of vertices that will actually be
1991  * rendered, since this will include all vertices of all LOD's, and it will
1992  * also include hidden nodes. It may also omit or only approximate certain
1993  * kinds of dynamic geometry. However, it will not include stashed nodes.
1994  */
1995 int PandaNode::
1996 get_nested_vertices(Thread *current_thread) const {
1997  int pipeline_stage = current_thread->get_pipeline_stage();
1998  CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
1999  if (cdata->_last_bounds_update != cdata->_next_update) {
2000  // The cache is stale; it needs to be rebuilt.
2001  int result;
2002  {
2003  PStatTimer timer(_update_bounds_pcollector);
2004  CDStageWriter cdataw =
2005  ((PandaNode *)this)->update_cached(true, pipeline_stage, cdata);
2006  result = cdataw->_nested_vertices;
2007  }
2008  return result;
2009  }
2010  return cdata->_nested_vertices;
2011 }
2012 
2013 /**
2014  * Indicates that the bounding volume, or something that influences the
2015  * bounding volume (or any of the other things stored in CData, like
2016  * net_collide_mask), may have changed for this node, and that it must be
2017  * recomputed.
2018  *
2019  * With no parameters, this means to iterate through all stages including and
2020  * upstream of the current pipeline stage.
2021  *
2022  * This method is intended for internal use; usually it is not necessary for a
2023  * user to call this directly. It will be called automatically by derived
2024  * classes when appropriate.
2025  */
2026 void PandaNode::
2027 mark_bounds_stale(Thread *current_thread) const {
2028  OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2029  mark_bounds_stale(pipeline_stage, current_thread);
2030  }
2031  CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2032 }
2033 
2034 /**
2035  * Should be called by a derived class to mark the internal bounding volume
2036  * stale, so that compute_internal_bounds() will be called when the bounding
2037  * volume is next requested.
2038  *
2039  * With no parameters, this means to iterate through all stages including and
2040  * upstream of the current pipeline stage.
2041  *
2042  * It is normally not necessary to call this method directly; each node should
2043  * be responsible for calling it when its internals have changed.
2044  */
2045 void PandaNode::
2046 mark_internal_bounds_stale(Thread *current_thread) {
2047  OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2048  mark_internal_bounds_stale(pipeline_stage, current_thread);
2049  }
2050  CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2051 }
2052 
2053 /**
2054  * A simple downcast check. Returns true if this kind of node happens to
2055  * inherit from GeomNode, false otherwise.
2056  *
2057  * This is provided as a a faster alternative to calling
2058  * is_of_type(GeomNode::get_class_type()), since this test is so important to
2059  * rendering.
2060  */
2062 is_geom_node() const {
2063  return false;
2064 }
2065 
2066 /**
2067  * A simple downcast check. Returns true if this kind of node happens to
2068  * inherit from LODNode, false otherwise.
2069  *
2070  * This is provided as a a faster alternative to calling
2071  * is_of_type(LODNode::get_class_type()).
2072  */
2074 is_lod_node() const {
2075  return false;
2076 }
2077 
2078 /**
2079  * A simple downcast check. Returns true if this kind of node happens to
2080  * inherit from CollisionNode, false otherwise.
2081  *
2082  * This is provided as a a faster alternative to calling
2083  * is_of_type(CollisionNode::get_class_type()).
2084  */
2086 is_collision_node() const {
2087  return false;
2088 }
2089 
2090 /**
2091  * Cross-casts the node to a Light pointer, if it is one of the four kinds of
2092  * Light nodes, or returns NULL if it is not.
2093  */
2095 as_light() {
2096  return nullptr;
2097 }
2098 
2099 /**
2100  * Returns true if this is an AmbientLight, false if it is not a light, or it
2101  * is some other kind of light.
2102  */
2104 is_ambient_light() const {
2105  return false;
2106 }
2107 
2108 /**
2109  * Reads the bytes created by a previous call to encode_to_bam_stream(), and
2110  * extracts and returns the single object on those bytes. Returns NULL on
2111  * error.
2112  *
2113  * This method is intended to replace decode_raw_from_bam_stream() when you
2114  * know the stream in question returns an object of type PandaNode, allowing
2115  * for easier reference count management. Note that the caller is still
2116  * responsible for maintaining the reference count on the return value.
2117  */
2118 PT(PandaNode) PandaNode::
2119 decode_from_bam_stream(vector_uchar data, BamReader *reader) {
2120  TypedWritable *object;
2121  ReferenceCount *ref_ptr;
2122 
2123  if (TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, std::move(data), reader)) {
2124  return DCAST(PandaNode, object);
2125  } else {
2126  return nullptr;
2127  }
2128 }
2129 
2130 /**
2131  * Returns the node's internal bounding volume. This is the bounding volume
2132  * around the node alone, without including children.
2133  */
2134 CPT(BoundingVolume) PandaNode::
2135 get_internal_bounds(int pipeline_stage, Thread *current_thread) const {
2136  while (true) {
2137  UpdateSeq mark;
2138  {
2139  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2140  if (cdata->_user_bounds != nullptr) {
2141  return cdata->_user_bounds;
2142  }
2143 
2144  if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2145  return cdata->_internal_bounds;
2146  }
2147 
2148  mark = cdata->_internal_bounds_mark;
2149  }
2150 
2151  // First, call compute_internal_bounds without acquiring the lock. This
2152  // avoids a deadlock condition.
2153  CPT(BoundingVolume) internal_bounds;
2154  int internal_vertices;
2155  compute_internal_bounds(internal_bounds, internal_vertices,
2156  pipeline_stage, current_thread);
2157  nassertr(!internal_bounds.is_null(), nullptr);
2158 
2159  // Now, acquire the lock, and apply the above-computed bounds.
2160  CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage);
2161  if (cdataw->_internal_bounds_mark == mark) {
2162  cdataw->_internal_bounds_computed = mark;
2163  cdataw->_internal_bounds = internal_bounds;
2164  cdataw->_internal_vertices = internal_vertices;
2165  ((PandaNode *)this)->mark_bam_modified();
2166  return cdataw->_internal_bounds;
2167  }
2168 
2169  // Dang, someone in another thread incremented _internal_bounds_mark while
2170  // we weren't holding the lock. That means we need to go back and do it
2171  // again.
2172  }
2173 }
2174 
2175 /**
2176  * Returns the total number of vertices that will be rendered by this
2177  * particular node alone, not accounting for its children.
2178  *
2179  * This may not include all vertices for certain dynamic effects.
2180  */
2181 int PandaNode::
2182 get_internal_vertices(int pipeline_stage, Thread *current_thread) const {
2183  while (true) {
2184  UpdateSeq mark;
2185  {
2186  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2187  if (cdata->_internal_bounds_mark == cdata->_internal_bounds_computed) {
2188  return cdata->_internal_vertices;
2189  }
2190 
2191  mark = cdata->_internal_bounds_mark;
2192  }
2193 
2194  // First, call compute_internal_bounds without acquiring the lock. This
2195  // avoids a deadlock condition.
2196  CPT(BoundingVolume) internal_bounds;
2197  int internal_vertices;
2198  compute_internal_bounds(internal_bounds, internal_vertices,
2199  pipeline_stage, current_thread);
2200  nassertr(!internal_bounds.is_null(), 0);
2201 
2202  // Now, acquire the lock, and apply the above-computed bounds.
2203  CDStageWriter cdataw(((PandaNode *)this)->_cycler, pipeline_stage);
2204  if (cdataw->_internal_bounds_mark == mark) {
2205  cdataw->_internal_bounds_computed = mark;
2206  cdataw->_internal_bounds = internal_bounds;
2207  cdataw->_internal_vertices = internal_vertices;
2208  ((PandaNode *)this)->mark_bam_modified();
2209  return cdataw->_internal_vertices;
2210  }
2211 
2212  // Dang, someone in another thread incremented _internal_bounds_mark while
2213  // we weren't holding the lock. That means we need to go back and do it
2214  // again.
2215  }
2216 }
2217 
2218 /**
2219  * This is provided as an alternate way for a node to set its own internal
2220  * bounds, rather than overloading compute_internal_bounds(). If this method
2221  * is called, the internal bounding volume will immediately be set to the
2222  * indicated pointer.
2223  */
2224 void PandaNode::
2225 set_internal_bounds(const BoundingVolume *volume) {
2226  Thread *current_thread = Thread::get_current_thread();
2227  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2228  CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
2229  cdataw->_internal_bounds = volume;
2230  cdataw->_internal_bounds_computed = cdataw->_internal_bounds_mark;
2231  }
2232  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2233  mark_bounds_stale(current_thread);
2235 }
2236 
2237 /**
2238  * Similar to mark_bounds_stale(), except that the parents of this node marked
2239  * stale even if this node was already considered stale.
2240  *
2241  * With no parameters, this means to iterate through all stages including and
2242  * upstream of the current pipeline stage.
2243  */
2244 void PandaNode::
2245 force_bounds_stale(Thread *current_thread) {
2246  OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler, current_thread) {
2247  force_bounds_stale(pipeline_stage, current_thread);
2248  }
2249  CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(_cycler);
2250 }
2251 
2252 /**
2253  * Similar to mark_bounds_stale(), except that the parents of this node marked
2254  * stale even if this node was already considered stale.
2255  */
2256 void PandaNode::
2257 force_bounds_stale(int pipeline_stage, Thread *current_thread) {
2258  {
2259  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2260  ++cdata->_next_update;
2262 
2263  // It is important that we allow this lock to be dropped before we
2264  // continue up the graph; otherwise, we risk deadlock from another thread
2265  // walking down the graph.
2266  }
2267 
2268  // It is similarly important that we use get_parents() here to copy the
2269  // parents list, instead of keeping the lock open while we walk through the
2270  // parents list directly on the node.
2271  Parents parents;
2272  {
2273  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
2274  parents = Parents(cdata);
2275  }
2276  int num_parents = parents.get_num_parents();
2277  for (int i = 0; i < num_parents; ++i) {
2278  PandaNode *parent = parents.get_parent(i);
2279  parent->mark_bounds_stale(pipeline_stage, current_thread);
2280  }
2281 }
2282 
2283 /**
2284  * Recursively calls Geom::mark_bounds_stale() on every Geom at this node and
2285  * below.
2286  */
2287 void PandaNode::
2288 r_mark_geom_bounds_stale(Thread *current_thread) {
2289  Children children = get_children(current_thread);
2290 
2291  size_t i;
2292  for (i = 0; i < children.get_num_children(); i++) {
2293  PandaNode *child = children.get_child(i);
2294  child->r_mark_geom_bounds_stale(current_thread);
2295  }
2296 
2297  Stashed stashed = get_stashed(current_thread);
2298  for (i = 0; i < stashed.get_num_stashed(); i++) {
2299  PandaNode *child = stashed.get_stashed(i);
2300  child->r_mark_geom_bounds_stale(current_thread);
2301  }
2302 }
2303 
2304 /**
2305  * Returns a newly-allocated BoundingVolume that represents the internal
2306  * contents of the node. Should be overridden by PandaNode classes that
2307  * contain something internally.
2308  */
2309 void PandaNode::
2310 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
2311  int &internal_vertices,
2312  int pipeline_stage,
2313  Thread *current_thread) const {
2314  internal_bounds = new BoundingSphere;
2315  internal_vertices = 0;
2316 }
2317 
2318 /**
2319  * Called after a scene graph update that either adds or remove parents from
2320  * this node, this just provides a hook for derived PandaNode objects that
2321  * need to update themselves based on the set of parents the node has.
2322  */
2323 void PandaNode::
2324 parents_changed() {
2325  nassertv((_unexpected_change_flags & UC_parents) == 0);
2326 }
2327 
2328 /**
2329  * Called after a scene graph update that either adds or remove children from
2330  * this node, this just provides a hook for derived PandaNode objects that
2331  * need to update themselves based on the set of children the node has.
2332  */
2333 void PandaNode::
2334 children_changed() {
2335  nassertv((_unexpected_change_flags & UC_children) == 0);
2336 }
2337 
2338 /**
2339  * Called after the node's transform has been changed for any reason, this
2340  * just provides a hook so derived classes can do something special in this
2341  * case.
2342  */
2343 void PandaNode::
2344 transform_changed() {
2345  nassertv((_unexpected_change_flags & UC_transform) == 0);
2346 }
2347 
2348 /**
2349  * Called after the node's RenderState has been changed for any reason, this
2350  * just provides a hook so derived classes can do something special in this
2351  * case.
2352  */
2353 void PandaNode::
2354 state_changed() {
2355  nassertv((_unexpected_change_flags & UC_state) == 0);
2356 }
2357 
2358 /**
2359  * Called after the node's DrawMask has been changed for any reason, this just
2360  * provides a hook so derived classes can do something special in this case.
2361  */
2362 void PandaNode::
2363 draw_mask_changed() {
2364  nassertv((_unexpected_change_flags & UC_draw_mask) == 0);
2365 }
2366 
2367 /**
2368  * This is the recursive implementation of copy_subgraph(). It returns a copy
2369  * of the entire subgraph rooted at this node.
2370  *
2371  * Note that it includes the parameter inst_map, which is a map type, and is
2372  * not (and cannot be) exported from PANDA.DLL. Thus, any derivative of
2373  * PandaNode that is not also a member of PANDA.DLL *cannot* access this map.
2374  */
2375 PT(PandaNode) PandaNode::
2376 r_copy_subgraph(PandaNode::InstanceMap &inst_map, Thread *current_thread) const {
2377  PT(PandaNode) copy = make_copy();
2378  nassertr(copy != nullptr, nullptr);
2379  if (copy->get_type() != get_type()) {
2380  pgraph_cat.warning()
2381  << "Don't know how to copy nodes of type " << get_type() << "\n";
2382 
2383  if (no_unsupported_copy) {
2384  nassert_raise("unsupported copy");
2385  return nullptr;
2386  }
2387  }
2388 
2389  copy->r_copy_children(this, inst_map, current_thread);
2390  return copy;
2391 }
2392 
2393 /**
2394  * This is called by r_copy_subgraph(); the copy has already been made of this
2395  * particular node (and this is the copy); this function's job is to copy all
2396  * of the children from the original.
2397  *
2398  * Note that it includes the parameter inst_map, which is a map type, and is
2399  * not (and cannot be) exported from PANDA.DLL. Thus, any derivative of
2400  * PandaNode that is not also a member of PANDA.DLL *cannot* access this map,
2401  * and probably should not even override this function.
2402  */
2403 void PandaNode::
2404 r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
2405  Thread *current_thread) {
2406  CDReader from_cdata(from->_cycler, current_thread);
2407  CPT(Down) from_down = from_cdata->get_down();
2408  Down::const_iterator di;
2409  for (di = from_down->begin(); di != from_down->end(); ++di) {
2410  int sort = (*di).get_sort();
2411  PandaNode *source_child = (*di).get_child();
2412  PT(PandaNode) dest_child;
2413 
2414  // Check to see if we have already copied this child. If we have, use the
2415  // copy. In this way, a subgraph that contains instances will be
2416  // correctly duplicated into another subgraph that also contains its own
2417  // instances.
2418  InstanceMap::const_iterator ci;
2419  ci = inst_map.find(source_child);
2420  if (ci != inst_map.end()) {
2421  dest_child = (*ci).second;
2422  } else {
2423  dest_child = source_child->r_copy_subgraph(inst_map, current_thread);
2424  inst_map[source_child] = dest_child;
2425  }
2426 
2427  quick_add_new_child(dest_child, sort, current_thread);
2428  }
2429 }
2430 
2431 /**
2432  * The recursive implementation of prepare_scene(). Don't call this directly;
2433  * call PandaNode::prepare_scene() or NodePath::prepare_scene() instead.
2434  */
2436 r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state,
2437  GeomTransformer &transformer, Thread *current_thread) {
2438  Children children = get_children(current_thread);
2439  // We must call get_num_children() each time through the loop, in case we're
2440  // running SIMPLE_THREADS and we get interrupted.
2441  size_t i;
2442  for (i = 0; i < children.get_num_children(); i++) {
2443  PandaNode *child = children.get_child(i);
2444  CPT(RenderState) child_state = node_state->compose(child->get_state());
2445  child->r_prepare_scene(gsg, child_state, transformer, current_thread);
2446  }
2447 
2448  Stashed stashed = get_stashed(current_thread);
2449  for (i = 0; i < stashed.get_num_stashed(); i++) {
2450  PandaNode *child = stashed.get_stashed(i);
2451  CPT(RenderState) child_state = node_state->compose(child->get_state());
2452  child->r_prepare_scene(gsg, child_state, transformer, current_thread);
2453  }
2454 }
2455 
2456 /**
2457  * Intended to be called in the constructor by any subclass that defines
2458  * cull_callback(), this sets up the flags to indicate that the cullback needs
2459  * to be called.
2460  */
2461 void PandaNode::
2462 set_cull_callback() {
2463  Thread *current_thread = Thread::get_current_thread();
2464  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2465  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2466  cdata->set_fancy_bit(FB_cull_callback, true);
2467  }
2468  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2470 }
2471 
2472 /**
2473  * disables the call back
2474  */
2475 void PandaNode::
2476 disable_cull_callback() {
2477  Thread *current_thread = Thread::get_current_thread();
2478  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2479  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2480  cdata->set_fancy_bit(FB_cull_callback, false);
2481  }
2482  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2484 }
2485 
2486 /**
2487  * The private implementation of remove_child(), for a particular pipeline
2488  * stage.
2489  */
2490 bool PandaNode::
2491 stage_remove_child(PandaNode *child_node, int pipeline_stage,
2492  Thread *current_thread) {
2493  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2494 
2495  // First, look for the parent in the child's up list, to ensure the child is
2496  // known.
2497  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage,
2498  current_thread);
2499  int parent_index = child_node->do_find_parent(this, cdata_child);
2500  if (parent_index < 0) {
2501  // Nope, no relation.
2502  return false;
2503  }
2504 
2505  PT(Down) down = cdata->modify_down();
2506  int child_index = do_find_child(child_node, down);
2507  if (child_index >= 0) {
2508  // The child exists; remove it.
2509  down->erase(down->begin() + child_index);
2510  int num_erased = cdata_child->modify_up()->erase(UpConnection(this));
2511  nassertr(num_erased == 1, false);
2512  return true;
2513  }
2514 
2515  PT(Down) stashed = cdata->modify_stashed();
2516  int stashed_index = do_find_child(child_node, stashed);
2517  if (stashed_index >= 0) {
2518  // The child has been stashed; remove it.
2519  stashed->erase(stashed->begin() + stashed_index);
2520  int num_erased = cdata_child->modify_up()->erase(UpConnection(this));
2521  nassertr(num_erased == 1, false);
2522  return true;
2523  }
2524 
2525  // Never heard of this child. This shouldn't be possible, because the
2526  // parent was in the child's up list, above. Must be some internal error.
2527  nassertr(false, false);
2528  return false;
2529 }
2530 
2531 /**
2532  * The private implementation of replace_child(), for a particular pipeline
2533  * stage.
2534  */
2535 bool PandaNode::
2536 stage_replace_child(PandaNode *orig_child, PandaNode *new_child,
2537  int pipeline_stage, Thread *current_thread) {
2538  {
2539  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2540  CDStageWriter cdata_orig_child(orig_child->_cycler, pipeline_stage, current_thread);
2541  CDStageWriter cdata_new_child(new_child->_cycler, pipeline_stage, current_thread);
2542 
2543  // First, look for the parent in the child's up list, to ensure the child
2544  // is known.
2545  int parent_index = orig_child->do_find_parent(this, cdata_orig_child);
2546  if (parent_index < 0) {
2547  // Nope, no relation.
2548  return false;
2549  }
2550 
2551  if (orig_child == new_child) {
2552  // Trivial no-op.
2553  return true;
2554  }
2555 
2556  // Don't let orig_child be destructed yet.
2557  PT(PandaNode) keep_orig_child = orig_child;
2558 
2559  // If we already have new_child as a child, remove it first.
2560  if (stage_remove_child(new_child, pipeline_stage, current_thread)) {
2561  sever_connection(this, new_child, pipeline_stage, current_thread);
2562  }
2563 
2564  PT(Down) down = cdata->modify_down();
2565  int child_index = do_find_child(orig_child, down);
2566  if (child_index >= 0) {
2567  // The child exists; replace it.
2568  DownConnection &dc = (*down)[child_index];
2569  nassertr(dc.get_child() == orig_child, false);
2570  dc.set_child(new_child);
2571 
2572  } else {
2573  PT(Down) stashed = cdata->modify_stashed();
2574  int stashed_index = do_find_child(orig_child, stashed);
2575  if (stashed_index >= 0) {
2576  // The child has been stashed; remove it.
2577  DownConnection &dc = (*stashed)[stashed_index];
2578  nassertr(dc.get_child() == orig_child, false);
2579  dc.set_child(new_child);
2580 
2581  } else {
2582  // Never heard of this child. This shouldn't be possible, because the
2583  // parent was in the child's up list, above. Must be some internal
2584  // error.
2585  nassertr(false, false);
2586  return false;
2587  }
2588  }
2589 
2590  // Now adjust the bookkeeping on both children.
2591  cdata_new_child->modify_up()->insert(UpConnection(this));
2592  int num_erased = cdata_orig_child->modify_up()->erase(UpConnection(this));
2593  nassertr(num_erased == 1, false);
2594  }
2595 
2596  sever_connection(this, orig_child, pipeline_stage, current_thread);
2597  new_connection(this, new_child, pipeline_stage, current_thread);
2598 
2599  force_bounds_stale(pipeline_stage, current_thread);
2600  orig_child->parents_changed();
2601  new_child->parents_changed();
2603  orig_child->mark_bam_modified();
2604  new_child->mark_bam_modified();
2605 
2606  return true;
2607 }
2608 
2609 /**
2610  * Similar to add_child(), but performs fewer checks. The purpose of this
2611  * method is to add a child node that was newly constructed, to a parent node
2612  * that was newly constructed, so we know we have to make fewer sanity checks.
2613  * This is a private method; do not call it directly.
2614  */
2615 void PandaNode::
2616 quick_add_new_child(PandaNode *child_node, int sort, Thread *current_thread) {
2617  // Apply this operation to the current stage as well as to all upstream
2618  // stages.
2619  OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler, current_thread) {
2620  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
2621  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2622 
2623  cdata->modify_down()->insert(DownConnection(child_node, sort));
2624  cdata_child->modify_up()->insert(UpConnection(this));
2625  }
2626  CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler);
2627 }
2628 
2629 /**
2630  * Raises an assertion when a graph cycle attempt is detected (and aborted).
2631  */
2632 void PandaNode::
2633 report_cycle(PandaNode *child_node) {
2634  ostringstream strm;
2635  strm << "Detected attempt to create a cycle in the scene graph: "
2636  << NodePath::any_path(this) << " : " << *child_node;
2637  nassert_raise(strm.str());
2638 }
2639 
2640 /**
2641  * Returns true if the indicated node is this node, or any ancestor of this
2642  * node; or false if it is not in this node's ancestry.
2643  */
2644 bool PandaNode::
2645 find_node_above(PandaNode *node) {
2646  if (node == this) {
2647  return true;
2648  }
2649 
2650  Parents parents = get_parents();
2651  for (size_t i = 0; i < parents.get_num_parents(); ++i) {
2652  PandaNode *parent = parents.get_parent(i);
2653  if (parent->find_node_above(node)) {
2654  return true;
2655  }
2656  }
2657 
2658  return false;
2659 }
2660 
2661 /**
2662  * Creates a new parent-child relationship, and returns the new
2663  * NodePathComponent. If the child was already attached to the indicated
2664  * parent, repositions it and returns the original NodePathComponent.
2665  *
2666  * This operation is automatically propagated back up to pipeline 0, from the
2667  * specified pipeline stage.
2668  */
2669 PT(NodePathComponent) PandaNode::
2670 attach(NodePathComponent *parent, PandaNode *child_node, int sort,
2671  int pipeline_stage, Thread *current_thread) {
2672  if (parent == nullptr) {
2673  // Attaching to NULL means to create a new "instance" with no attachments,
2674  // and no questions asked.
2675  PT(NodePathComponent) child =
2676  new NodePathComponent(child_node, nullptr,
2677  pipeline_stage, current_thread);
2678  LightReMutexHolder holder(child_node->_paths_lock);
2679  child_node->_paths.insert(child);
2680  return child;
2681  }
2682 
2683  // See if the child was already attached to the parent. If it was, we'll
2684  // use that same NodePathComponent.
2685  PT(NodePathComponent) child = get_component(parent, child_node, pipeline_stage, current_thread);
2686 
2687  if (child == nullptr) {
2688  // The child was not already attached to the parent, so get a new
2689  // component.
2690  child = get_top_component(child_node, true, pipeline_stage, current_thread);
2691  }
2692 
2693  reparent(parent, child, sort, false, pipeline_stage, current_thread);
2694 
2695  return child;
2696 }
2697 
2698 /**
2699  * Breaks a parent-child relationship.
2700  *
2701  * This operation is automatically propagated back up to pipeline 0, from the
2702  * specified pipeline stage.
2703  */
2704 void PandaNode::
2705 detach(NodePathComponent *child, int pipeline_stage, Thread *current_thread) {
2706  nassertv(child != nullptr);
2707 
2708  for (int pipeline_stage_i = pipeline_stage;
2709  pipeline_stage_i >= 0;
2710  --pipeline_stage_i) {
2711  detach_one_stage(child, pipeline_stage_i, current_thread);
2712  }
2713 
2714  child->get_node()->parents_changed();
2715 }
2716 
2717 /**
2718  * Breaks a parent-child relationship.
2719  *
2720  * This operation is not automatically propagated upstream. It is applied to
2721  * the indicated pipeline stage only.
2722  */
2723 void PandaNode::
2724 detach_one_stage(NodePathComponent *child, int pipeline_stage,
2725  Thread *current_thread) {
2726  nassertv(child != nullptr);
2727  if (child->is_top_node(pipeline_stage, current_thread)) {
2728  return;
2729  }
2730 
2731  PT(PandaNode) child_node = child->get_node();
2732  PT(PandaNode) parent_node = child->get_next(pipeline_stage, current_thread)->get_node();
2733 
2734  CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
2735  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2736  int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2737  if (parent_index >= 0) {
2738  // Now look for the child and break the actual connection.
2739 
2740  // First, look for and remove the parent node from the child's up list.
2741  int num_erased = cdata_child->modify_up()->erase(UpConnection(parent_node));
2742  nassertv(num_erased == 1);
2743 
2744  // Now, look for and remove the child node from the parent's down list.
2745  // We also check in the stashed list, in case the child node has been
2746  // stashed.
2747  Down::iterator di;
2748  bool found = false;
2749  PT(Down) down = cdata_parent->modify_down();
2750  for (di = down->begin(); di != down->end(); ++di) {
2751  if ((*di).get_child() == child_node) {
2752  down->erase(di);
2753  found = true;
2754  break;
2755  }
2756  }
2757  if (!found) {
2758  PT(Down) stashed = cdata_parent->modify_stashed();
2759  for (di = stashed->begin(); di != stashed->end(); ++di) {
2760  if ((*di).get_child() == child_node) {
2761  stashed->erase(di);
2762  found = true;
2763  break;
2764  }
2765  }
2766  }
2767  nassertv(found);
2768  }
2769 
2770  // Finally, break the NodePathComponent connection.
2771  sever_connection(parent_node, child_node, pipeline_stage, current_thread);
2772 
2773  parent_node->force_bounds_stale(pipeline_stage, current_thread);
2774  parent_node->children_changed();
2775  parent_node->mark_bam_modified();
2776 }
2777 
2778 /**
2779  * Switches a node from one parent to another. Returns true if the new
2780  * connection is allowed, or false if it conflicts with another instance (that
2781  * is, another instance of the child is already attached to the indicated
2782  * parent).
2783  *
2784  * This operation is automatically propagated back up to pipeline 0, from the
2785  * specified pipeline stage.
2786  */
2787 bool PandaNode::
2788 reparent(NodePathComponent *new_parent, NodePathComponent *child, int sort,
2789  bool as_stashed, int pipeline_stage, Thread *current_thread) {
2790  bool any_ok = false;
2791 
2792  if (new_parent != nullptr &&
2793  !new_parent->get_node()->verify_child_no_cycles(child->get_node())) {
2794  // Whoops, adding this child node would introduce a cycle in the scene
2795  // graph.
2796  return false;
2797  }
2798 
2799  for (int pipeline_stage_i = pipeline_stage;
2800  pipeline_stage_i >= 0;
2801  --pipeline_stage_i) {
2802  if (reparent_one_stage(new_parent, child, sort, as_stashed,
2803  pipeline_stage_i, current_thread)) {
2804  any_ok = true;
2805  }
2806  }
2807 
2808  if (new_parent != nullptr) {
2809  new_parent->get_node()->children_changed();
2810  new_parent->get_node()->mark_bam_modified();
2811  }
2812  child->get_node()->parents_changed();
2813  child->get_node()->mark_bam_modified();
2814 
2815  return any_ok;
2816 }
2817 
2818 /**
2819  * Switches a node from one parent to another. Returns true if the new
2820  * connection is allowed, or false if it conflicts with another instance (that
2821  * is, another instance of the child is already attached to the indicated
2822  * parent).
2823  *
2824  * This operation is not automatically propagated upstream. It is applied to
2825  * the indicated pipeline stage only.
2826  */
2827 bool PandaNode::
2828 reparent_one_stage(NodePathComponent *new_parent, NodePathComponent *child,
2829  int sort, bool as_stashed, int pipeline_stage,
2830  Thread *current_thread) {
2831  nassertr(child != nullptr, false);
2832 
2833  // Keep a reference count to the new parent, since detaching the child might
2834  // lose the count.
2835  PT(NodePathComponent) keep_parent = new_parent;
2836 
2837  if (!child->is_top_node(pipeline_stage, current_thread)) {
2838  detach(child, pipeline_stage, current_thread);
2839  }
2840 
2841  if (new_parent != nullptr) {
2842  PandaNode *child_node = child->get_node();
2843  PandaNode *parent_node = new_parent->get_node();
2844 
2845  {
2846  CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2847  int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2848 
2849  if (parent_index >= 0) {
2850  // Whoops, there's already another instance of the child there.
2851  return false;
2852  }
2853  }
2854 
2855  // Redirect the connection to the indicated new parent.
2856  child->set_next(new_parent, pipeline_stage, current_thread);
2857 
2858  // Now reattach the child node at the indicated sort position.
2859  {
2860  CDStageWriter cdata_parent(parent_node->_cycler, pipeline_stage, current_thread);
2861  CDStageWriter cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2862 
2863  if (as_stashed) {
2864  cdata_parent->modify_stashed()->insert(DownConnection(child_node, sort));
2865  } else {
2866  cdata_parent->modify_down()->insert(DownConnection(child_node, sort));
2867  }
2868  cdata_child->modify_up()->insert(UpConnection(parent_node));
2869 
2870 #ifndef NDEBUG
2871  // The NodePathComponent should already be in the set.
2872  {
2873  LightReMutexHolder holder(child_node->_paths_lock);
2874  nassertr(child_node->_paths.find(child) != child_node->_paths.end(), false);
2875  }
2876 #endif // NDEBUG
2877  }
2878 
2879  child_node->fix_path_lengths(pipeline_stage, current_thread);
2880  parent_node->force_bounds_stale(pipeline_stage, current_thread);
2881  }
2882 
2883  return true;
2884 }
2885 
2886 /**
2887  * Returns the NodePathComponent based on the indicated child of the given
2888  * parent, or NULL if there is no such parent-child relationship.
2889  */
2890 PT(NodePathComponent) PandaNode::
2891 get_component(NodePathComponent *parent, PandaNode *child_node,
2892  int pipeline_stage, Thread *current_thread) {
2893  nassertr(parent != nullptr, nullptr);
2894  PandaNode *parent_node = parent->get_node();
2895 
2896  LightReMutexHolder holder(child_node->_paths_lock);
2897 
2898  // First, walk through the list of NodePathComponents we already have on the
2899  // child, looking for one that already exists, referencing the indicated
2900  // parent component.
2901  Paths::const_iterator pi;
2902  for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
2903  if ((*pi)->get_next(pipeline_stage, current_thread) == parent) {
2904  // If we already have such a component, just return it.
2905  return (*pi);
2906  }
2907  }
2908 
2909  // We don't already have a NodePathComponent referring to this parent-child
2910  // relationship. Are they actually related?
2911  CDStageReader cdata_child(child_node->_cycler, pipeline_stage, current_thread);
2912  int parent_index = child_node->do_find_parent(parent_node, cdata_child);
2913 
2914  if (parent_index >= 0) {
2915  // They are. Create and return a new one.
2916  PT(NodePathComponent) child =
2917  new NodePathComponent(child_node, parent, pipeline_stage, current_thread);
2918  child_node->_paths.insert(child);
2919  return child;
2920  } else {
2921  // They aren't related. Return NULL.
2922  return nullptr;
2923  }
2924 }
2925 
2926 /**
2927  * Returns a NodePathComponent referencing the indicated node as a singleton.
2928  * It is invalid to call this for a node that has parents, unless you are
2929  * about to create a new instance (and immediately reconnect the
2930  * NodePathComponent elsewhere).
2931  *
2932  * If force is true, this will always return something, even if it needs to
2933  * create a new top component; otherwise, if force is false, it will return
2934  * NULL if there is not already a top component available.
2935  */
2936 PT(NodePathComponent) PandaNode::
2937 get_top_component(PandaNode *child_node, bool force, int pipeline_stage,
2938  Thread *current_thread) {
2939  LightReMutexHolder holder(child_node->_paths_lock);
2940 
2941  // Walk through the list of NodePathComponents we already have on the child,
2942  // looking for one that already exists as a top node.
2943  Paths::const_iterator pi;
2944  for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
2945  if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
2946  // If we already have such a component, just return it.
2947  return (*pi);
2948  }
2949  }
2950 
2951  if (!force) {
2952  // If we don't care to force the point, return NULL to indicate there's
2953  // not already a top component.
2954  return nullptr;
2955  }
2956 
2957  // We don't already have such a NodePathComponent; create and return a new
2958  // one.
2959  PT(NodePathComponent) child =
2960  new NodePathComponent(child_node, nullptr,
2961  pipeline_stage, current_thread);
2962  child_node->_paths.insert(child);
2963 
2964  return child;
2965 }
2966 
2967 /**
2968  * Returns a NodePathComponent referencing this node as a path from the root.
2969  *
2970  * Unless accept_ambiguity is true, it is only valid to call this if there is
2971  * an unambiguous path from the root; otherwise, a warning will be issued and
2972  * one path will be chosen arbitrarily.
2973  */
2974 PT(NodePathComponent) PandaNode::
2975 get_generic_component(bool accept_ambiguity, int pipeline_stage,
2976  Thread *current_thread) {
2977  bool ambiguity_detected = false;
2978  PT(NodePathComponent) result =
2979  r_get_generic_component(accept_ambiguity, ambiguity_detected,
2980  pipeline_stage, current_thread);
2981 
2982  if (!accept_ambiguity && ambiguity_detected) {
2983  pgraph_cat.warning()
2984  << "Chose: " << *result << "\n";
2985  nassertr(!unambiguous_graph, result);
2986  }
2987 
2988  return result;
2989 }
2990 
2991 /**
2992  * The recursive implementation of get_generic_component, this simply sets the
2993  * flag when the ambiguity is detected (so we can report the bottom node that
2994  * started the ambiguous search).
2995  */
2996 PT(NodePathComponent) PandaNode::
2997 r_get_generic_component(bool accept_ambiguity, bool &ambiguity_detected,
2998  int pipeline_stage, Thread *current_thread) {
2999  PT(PandaNode) parent_node;
3000 
3001  {
3002  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3003 
3004  int num_parents = cdata->get_up()->size();
3005  if (num_parents == 0) {
3006  // No parents; no ambiguity. This is the root.
3007  return get_top_component(this, true, pipeline_stage, current_thread);
3008  }
3009 
3010  PT(NodePathComponent) result;
3011  if (num_parents == 1) {
3012  // Only one parent; no ambiguity.
3013  PT(NodePathComponent) parent =
3014  get_parent(0)->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3015  return get_component(parent, this, pipeline_stage, current_thread);
3016  }
3017 
3018  // Oops, multiple parents; the NodePath is ambiguous.
3019  if (!accept_ambiguity) {
3020  pgraph_cat.warning()
3021  << *this << " has " << num_parents
3022  << " parents; choosing arbitrary path to root.\n";
3023  }
3024  ambiguity_detected = true;
3025  CPT(Up) up = cdata->get_up();
3026  parent_node = (*up)[0].get_parent();
3027  }
3028 
3029  // Now that the lock is released, it's safe to recurse.
3030  PT(NodePathComponent) parent =
3031  parent_node->r_get_generic_component(accept_ambiguity, ambiguity_detected, pipeline_stage, current_thread);
3032  return get_component(parent, this, pipeline_stage, current_thread);
3033 }
3034 
3035 /**
3036  * Removes a NodePathComponent from the set prior to its deletion. This
3037  * should only be called by the NodePathComponent destructor.
3038  */
3039 void PandaNode::
3040 delete_component(NodePathComponent *component) {
3041  LightReMutexHolder holder(_paths_lock);
3042  int num_erased = _paths.erase(component);
3043  nassertv(num_erased == 1);
3044 }
3045 
3046 /**
3047  * This is called internally when a parent-child connection is broken to
3048  * update the NodePathComponents that reflected this connection.
3049  *
3050  * It severs any NodePathComponents on the child node that reference the
3051  * indicated parent node. These components remain unattached; there may
3052  * therefore be multiple "instances" of a node that all have no parent, even
3053  * while there are other instances that do have parents.
3054  *
3055  * This operation is not automatically propagated upstream. It is applied to
3056  * the indicated pipeline stage only.
3057  */
3058 void PandaNode::
3059 sever_connection(PandaNode *parent_node, PandaNode *child_node,
3060  int pipeline_stage, Thread *current_thread) {
3061  {
3062  LightReMutexHolder holder(child_node->_paths_lock);
3063  Paths::iterator pi;
3064  for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3065  if (!(*pi)->is_top_node(pipeline_stage, current_thread) &&
3066  (*pi)->get_next(pipeline_stage, current_thread)->get_node() == parent_node) {
3067  // Sever the component here.
3068  (*pi)->set_top_node(pipeline_stage, current_thread);
3069  }
3070  }
3071  }
3072  child_node->fix_path_lengths(pipeline_stage, current_thread);
3073 }
3074 
3075 /**
3076  * This is called internally when a parent-child connection is established to
3077  * update the NodePathComponents that might be involved.
3078  *
3079  * It adjusts any NodePathComponents the child has that reference the child as
3080  * a top node. Any other components we can leave alone, because we are making
3081  * a new instance of the child.
3082  *
3083  * This operation is not automatically propagated upstream. It is applied to
3084  * the indicated pipeline stage only.
3085  */
3086 void PandaNode::
3087 new_connection(PandaNode *parent_node, PandaNode *child_node,
3088  int pipeline_stage, Thread *current_thread) {
3089  {
3090  LightReMutexHolder holder(child_node->_paths_lock);
3091  Paths::iterator pi;
3092  for (pi = child_node->_paths.begin(); pi != child_node->_paths.end(); ++pi) {
3093  if ((*pi)->is_top_node(pipeline_stage, current_thread)) {
3094  (*pi)->set_next(parent_node->get_generic_component(false, pipeline_stage, current_thread), pipeline_stage, current_thread);
3095  }
3096  }
3097  }
3098  child_node->fix_path_lengths(pipeline_stage, current_thread);
3099 }
3100 
3101 /**
3102  * Recursively fixes the _length member of each NodePathComponent at this
3103  * level and below, after an add or delete child operation that might have
3104  * messed these up.
3105  *
3106  * This operation is not automatically propagated upstream. It is applied to
3107  * the indicated pipeline stage only.
3108  */
3109 void PandaNode::
3110 fix_path_lengths(int pipeline_stage, Thread *current_thread) {
3111  LightReMutexHolder holder(_paths_lock);
3112 
3113  bool any_wrong = false;
3114 
3115  Paths::const_iterator pi;
3116  for (pi = _paths.begin(); pi != _paths.end(); ++pi) {
3117  if ((*pi)->fix_length(pipeline_stage, current_thread)) {
3118  any_wrong = true;
3119  }
3120  }
3121 
3122  // If any paths were updated, we have to recurse on all of our children,
3123  // since any one of those paths might be shared by any of our child nodes.
3124  // Don't hold any locks while we recurse.
3125  if (any_wrong) {
3126  Children children;
3127  Stashed stashed;
3128  {
3129  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
3130  children = Children(cdata);
3131  stashed = Stashed(cdata);
3132  }
3133 
3134  int num_children = children.get_num_children();
3135  int i;
3136  for (i = 0; i < num_children; ++i) {
3137  PandaNode *child_node = children.get_child(i);
3138  child_node->fix_path_lengths(pipeline_stage, current_thread);
3139  }
3140  int num_stashed = stashed.get_num_stashed();
3141  for (i = 0; i < num_stashed; ++i) {
3142  PandaNode *child_node = stashed.get_stashed(i);
3143  child_node->fix_path_lengths(pipeline_stage, current_thread);
3144  }
3145  }
3146 }
3147 
3148 /**
3149  * The recursive implementation of ls().
3150  */
3151 void PandaNode::
3152 r_list_descendants(ostream &out, int indent_level) const {
3153  write(out, indent_level);
3154 
3155  Children children = get_children();
3156  int num_children = children.get_num_children();
3157 
3158  for (int i = 0; i < num_children; ++i) {
3159  PandaNode *child = children.get_child(i);
3160  child->r_list_descendants(out, indent_level + 2);
3161  }
3162 
3163  // Also report the number of stashed nodes at this level.
3164  int num_stashed = get_num_stashed();
3165  if (num_stashed != 0) {
3166  indent(out, indent_level) << "(" << num_stashed << " stashed)\n";
3167  }
3168 }
3169 
3170 /**
3171  * The private implementation of find_child().
3172  */
3173 int PandaNode::
3174 do_find_child(PandaNode *node, const PandaNode::Down *down) const {
3175  nassertr(node != nullptr, -1);
3176 
3177  // We have to search for the child by brute force, since we don't know what
3178  // sort index it was added as.
3179  Down::const_iterator di;
3180  for (di = down->begin(); di != down->end(); ++di) {
3181  if ((*di).get_child() == node) {
3182  return di - down->begin();
3183  }
3184  }
3185 
3186  return -1;
3187 }
3188 
3189 /**
3190  * Updates the cached values of the node that are dependent on its children,
3191  * such as the external bounding volume, the _net_collide_mask, and the
3192  * _off_clip_planes.
3193  *
3194  * If update_bounds is false, it will not update the bounding volume or vertex
3195  * count.
3196  *
3197  * The old value should be passed in; it will be released. The new value is
3198  * returned.
3199  */
3200 PandaNode::CDStageWriter PandaNode::
3201 update_cached(bool update_bounds, int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
3202  // We might need to try this a couple of times, in case someone else steps
3203  // on our result.
3204  if (drawmask_cat.is_debug()) {
3205  drawmask_cat.debug(false)
3206  << *this << "::update_cached() {\n";
3207  }
3208  Thread *current_thread = cdata.get_current_thread();
3209 
3210  do {
3211  // Grab the last_update counter.
3212  UpdateSeq last_update = cdata->_last_update;
3213  UpdateSeq next_update = cdata->_next_update;
3214  UpdateSeq last_bounds_update = cdata->_last_bounds_update;
3215  nassertr(last_update != next_update ||
3216  (update_bounds && last_bounds_update != next_update),
3217  CDStageWriter(_cycler, pipeline_stage, cdata));
3218 
3219  // Start with a clean slate.
3220  CollideMask net_collide_mask = cdata->_into_collide_mask;
3221  DrawMask net_draw_control_mask, net_draw_show_mask;
3222  bool renderable = is_renderable();
3223 
3224  if (renderable) {
3225  // If this node is itself renderable, it contributes to the net draw
3226  // mask.
3227  net_draw_control_mask = cdata->_draw_control_mask;
3228  net_draw_show_mask = cdata->_draw_show_mask;
3229  }
3230 
3231  if (drawmask_cat.is_debug()) {
3232  drawmask_cat.debug(false)
3233  << "net_draw_control_mask = " << net_draw_control_mask
3234  << "\nnet_draw_show_mask = " << net_draw_show_mask
3235  << "\n";
3236  }
3237  CPT(RenderAttrib) off_clip_planes = cdata->_state->get_attrib(ClipPlaneAttrib::get_class_slot());
3238  if (off_clip_planes == nullptr) {
3239  off_clip_planes = ClipPlaneAttrib::make();
3240  }
3241 
3242  // Also get the list of the node's children.
3243  Children children(cdata);
3244 
3245  int num_vertices = cdata->_internal_vertices;
3246 
3247  // Now that we've got all the data we need from the node, we can release
3248  // the lock.
3249  _cycler.release_read_stage(pipeline_stage, cdata.take_pointer());
3250 
3251  int num_children = children.get_num_children();
3252 
3253  // We need to keep references to the bounding volumes, since in a threaded
3254  // environment the pointers might go away while we're working (since we're
3255  // not holding a lock on our set of children right now). But we also need
3256  // the regular pointers, to pass to BoundingVolume::around().
3257  const BoundingVolume **child_volumes;
3258 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3259  pvector<CPT(BoundingVolume) > child_volumes_ref;
3260  if (update_bounds) {
3261  child_volumes_ref.reserve(num_children + 1);
3262  }
3263 #endif
3264  int child_volumes_i = 0;
3265 
3266  bool all_box = true;
3267  CPT(BoundingVolume) internal_bounds = nullptr;
3268 
3269  if (update_bounds) {
3270  child_volumes = (const BoundingVolume **)alloca(sizeof(BoundingVolume *) * (num_children + 1));
3271  internal_bounds = get_internal_bounds(pipeline_stage, current_thread);
3272 
3273  if (!internal_bounds->is_empty()) {
3274 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3275  child_volumes_ref.push_back(internal_bounds);
3276 #endif
3277  nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3278  child_volumes[child_volumes_i++] = internal_bounds;
3279  if (internal_bounds->as_bounding_box() == nullptr) {
3280  all_box = false;
3281  }
3282  }
3283  }
3284 
3285  // Now expand those contents to include all of our children.
3286 
3287  for (int i = 0; i < num_children; ++i) {
3288  PandaNode *child = children.get_child(i);
3289 
3290  const ClipPlaneAttrib *orig_cp = DCAST(ClipPlaneAttrib, off_clip_planes);
3291 
3292  CDLockedStageReader child_cdata(child->_cycler, pipeline_stage, current_thread);
3293 
3294  UpdateSeq last_child_update = update_bounds
3295  ? child_cdata->_last_bounds_update
3296  : child_cdata->_last_update;
3297 
3298  if (last_child_update != child_cdata->_next_update) {
3299  // Child needs update.
3300  CDStageWriter child_cdataw = child->update_cached(update_bounds, pipeline_stage, child_cdata);
3301 
3302  net_collide_mask |= child_cdataw->_net_collide_mask;
3303 
3304  if (drawmask_cat.is_debug()) {
3305  drawmask_cat.debug(false)
3306  << "\nchild update " << *child << ":\n";
3307  }
3308 
3309  DrawMask child_control_mask = child_cdataw->_net_draw_control_mask;
3310  DrawMask child_show_mask = child_cdataw->_net_draw_show_mask;
3311  if (!(child_control_mask | child_show_mask).is_zero()) {
3312  // This child includes a renderable node or subtree. Thus, we
3313  // should propagate its draw masks.
3314  renderable = true;
3315 
3316  // For each bit position in the masks, we have assigned the
3317  // following semantic meaning. The number on the left represents
3318  // the pairing of the corresponding bit from the control mask and
3319  // from the show mask:
3320 
3321  // 00 : not a renderable node (control 0, show 0) 01 : a normally
3322  // visible node (control 0, show 1) 10 : a hidden node
3323  // (control 1, show 0) 11 : a show-through node (control 1, show
3324  // 1)
3325 
3326  // Now, when we accumulate these masks, we want to do so according
3327  // to the following table, for each bit position:
3328 
3329  // 00 01 10 11 (child) --------------------- 00 | 00 01
3330  // 10 11 01 | 01 01 01* 11 10 | 10 01* 10 11 11 | 11
3331  // 11 11 11 (parent)
3332 
3333  // This table is almost the same as the union of both masks, with
3334  // one exception, marked with a * in the above table: if one is 10
3335  // and the other is 01--that is, one is hidden and the other is
3336  // normally visible--then the result should be 01, normally visible.
3337  // This is because we only want to propagate the hidden bit upwards
3338  // if *all* renderable nodes are hidden.
3339 
3340  // Get the set of exception bits for which the above rule applies.
3341  // These are the bits for which both bits have flipped, but which
3342  // were not the same in the original.
3343  DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3344  exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3345 
3346  if (drawmask_cat.is_debug()) {
3347  drawmask_cat.debug(false)
3348  << "exception_mask = " << exception_mask << "\n";
3349  }
3350 
3351  // Now compute the union, applying the above exception.
3352  net_draw_control_mask |= child_control_mask;
3353  net_draw_show_mask |= child_show_mask;
3354 
3355  net_draw_control_mask &= ~exception_mask;
3356  net_draw_show_mask |= exception_mask;
3357  }
3358 
3359  if (drawmask_cat.is_debug()) {
3360  drawmask_cat.debug(false)
3361  << "child_control_mask = " << child_control_mask
3362  << "\nchild_show_mask = " << child_show_mask
3363  << "\nnet_draw_control_mask = " << net_draw_control_mask
3364  << "\nnet_draw_show_mask = " << net_draw_show_mask
3365  << "\n";
3366  }
3367 
3368  off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes);
3369 
3370  if (update_bounds) {
3371  if (!child_cdataw->_external_bounds->is_empty()) {
3372 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3373  child_volumes_ref.push_back(child_cdataw->_external_bounds);
3374 #endif
3375  nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3376  child_volumes[child_volumes_i++] = child_cdataw->_external_bounds;
3377  if (child_cdataw->_external_bounds->as_bounding_box() == nullptr) {
3378  all_box = false;
3379  }
3380  }
3381  num_vertices += child_cdataw->_nested_vertices;
3382  }
3383 
3384  } else {
3385  // Child is good.
3386  net_collide_mask |= child_cdata->_net_collide_mask;
3387 
3388  // See comments in similar block above.
3389  if (drawmask_cat.is_debug()) {
3390  drawmask_cat.debug(false)
3391  << "\nchild fresh " << *child << ":\n";
3392  }
3393  DrawMask child_control_mask = child_cdata->_net_draw_control_mask;
3394  DrawMask child_show_mask = child_cdata->_net_draw_show_mask;
3395  if (!(child_control_mask | child_show_mask).is_zero()) {
3396  renderable = true;
3397 
3398  DrawMask exception_mask = (net_draw_control_mask ^ child_control_mask) & (net_draw_show_mask ^ child_show_mask);
3399  exception_mask &= (net_draw_control_mask ^ net_draw_show_mask);
3400 
3401  if (drawmask_cat.is_debug()) {
3402  drawmask_cat.debug(false)
3403  << "exception_mask = " << exception_mask << "\n";
3404  }
3405 
3406  // Now compute the union, applying the above exception.
3407  net_draw_control_mask |= child_control_mask;
3408  net_draw_show_mask |= child_show_mask;
3409 
3410  net_draw_control_mask &= ~exception_mask;
3411  net_draw_show_mask |= exception_mask;
3412  }
3413 
3414  if (drawmask_cat.is_debug()) {
3415  drawmask_cat.debug(false)
3416  << "child_control_mask = " << child_control_mask
3417  << "\nchild_show_mask = " << child_show_mask
3418  << "\nnet_draw_control_mask = " << net_draw_control_mask
3419  << "\nnet_draw_show_mask = " << net_draw_show_mask
3420  << "\n";
3421  }
3422 
3423  off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes);
3424 
3425  if (update_bounds) {
3426  if (!child_cdata->_external_bounds->is_empty()) {
3427 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
3428  child_volumes_ref.push_back(child_cdata->_external_bounds);
3429 #endif
3430  nassertr(child_volumes_i < num_children + 1, CDStageWriter(_cycler, pipeline_stage, cdata));
3431  child_volumes[child_volumes_i++] = child_cdata->_external_bounds;
3432  if (child_cdata->_external_bounds->as_bounding_box() == nullptr) {
3433  all_box = false;
3434  }
3435  }
3436  num_vertices += child_cdata->_nested_vertices;
3437  }
3438  }
3439  }
3440 
3441  {
3442  // Now grab the write lock on this node.
3443  CDStageWriter cdataw(_cycler, pipeline_stage, current_thread);
3444  if (last_update == cdataw->_last_update &&
3445  next_update == cdataw->_next_update) {
3446  // Great, no one has monkeyed with these while we were computing the
3447  // cache. Safe to store the computed values and return.
3448  cdataw->_net_collide_mask = net_collide_mask;
3449 
3450  if (renderable) {
3451  // Any explicit draw control mask on this node trumps anything
3452  // inherited from below, except a show-through.
3453  DrawMask draw_control_mask = cdataw->_draw_control_mask;
3454  DrawMask draw_show_mask = cdataw->_draw_show_mask;
3455 
3456  DrawMask show_through_mask = net_draw_control_mask & net_draw_show_mask;
3457 
3458  net_draw_control_mask |= draw_control_mask;
3459  net_draw_show_mask = (net_draw_show_mask & ~draw_control_mask) | (draw_show_mask & draw_control_mask);
3460 
3461  net_draw_show_mask |= show_through_mask;
3462 
3463  // There are renderable nodes below, so the implicit draw bits are
3464  // all on.
3465  cdataw->_net_draw_control_mask = net_draw_control_mask;
3466  cdataw->_net_draw_show_mask = net_draw_show_mask | ~net_draw_control_mask;
3467  if (drawmask_cat.is_debug()) {
3468  drawmask_cat.debug(false)
3469  << "renderable, set mask " << cdataw->_net_draw_show_mask << "\n";
3470  }
3471  } else {
3472  // There are no renderable nodes below, so the implicit draw bits
3473  // are all off. Also, we don't care about the draw mask on this
3474  // particular node (since nothing below it is renderable anyway).
3475  cdataw->_net_draw_control_mask = net_draw_control_mask;
3476  cdataw->_net_draw_show_mask = net_draw_show_mask;
3477  if (drawmask_cat.is_debug()) {
3478  drawmask_cat.debug(false)
3479  << "not renderable, set mask " << cdataw->_net_draw_show_mask << "\n";
3480  }
3481  }
3482 
3483  cdataw->_off_clip_planes = off_clip_planes;
3484 
3485  if (update_bounds) {
3486  cdataw->_nested_vertices = num_vertices;
3487 
3488  CPT(TransformState) transform = get_transform(current_thread);
3489  PT(GeometricBoundingVolume) gbv;
3490 
3491  BoundingVolume::BoundsType btype = cdataw->_bounds_type;
3492  if (btype == BoundingVolume::BT_default) {
3493  btype = bounds_type;
3494  }
3495 
3496  if (btype == BoundingVolume::BT_box ||
3497  (btype != BoundingVolume::BT_sphere && all_box && transform->is_identity())) {
3498  // If all of the child volumes are a BoundingBox, and we have no
3499  // transform, then our volume is also a BoundingBox.
3500 
3501  gbv = new BoundingBox;
3502  } else {
3503  // Otherwise, it's a sphere.
3504  gbv = new BoundingSphere;
3505  }
3506 
3507  if (child_volumes_i > 0) {
3508  const BoundingVolume **child_begin = &child_volumes[0];
3509  const BoundingVolume **child_end = child_begin + child_volumes_i;
3510  ((BoundingVolume *)gbv)->around(child_begin, child_end);
3511 
3512  // If we have a transform, apply it to the bounding volume we just
3513  // computed.
3514  if (!transform->is_identity()) {
3515  gbv->xform(transform->get_mat());
3516  }
3517  }
3518 
3519  cdataw->_external_bounds = gbv;
3520  cdataw->_last_bounds_update = next_update;
3521  }
3522 
3523  cdataw->_last_update = next_update;
3524 
3525  if (drawmask_cat.is_debug()) {
3526  drawmask_cat.debug(false)
3527  << "} " << *this << "::update_cached();\n";
3528  }
3529 
3530  nassertr(cdataw->_last_update == cdataw->_next_update, cdataw);
3531 
3532  // Even though implicit bounding volume is not (yet?) part of the bam
3533  // stream.
3535  return cdataw;
3536  }
3537 
3538  if (cdataw->_last_update == cdataw->_next_update &&
3539  (!update_bounds || cdataw->_last_bounds_update == cdataw->_next_update)) {
3540  // Someone else has computed the cache for us. OK.
3541  return cdataw;
3542  }
3543  }
3544 
3545  // We need to go around again. Release the write lock, and grab the read
3546  // lock back.
3547  cdata = CDLockedStageReader(_cycler, pipeline_stage, current_thread);
3548 
3549  if (cdata->_last_update == cdata->_next_update &&
3550  (!update_bounds || cdata->_last_bounds_update == cdata->_next_update)) {
3551  // Someone else has computed the cache for us while we were diddling
3552  // with the locks. OK.
3553  return CDStageWriter(_cycler, pipeline_stage, cdata);
3554  }
3555 
3556  } while (true);
3557 }
3558 
3559 /**
3560  * This is used by the GraphicsEngine to hook in a pointer to the
3561  * scene_root_func(), the function to determine whether the node is an active
3562  * scene root. This back-pointer is necessary because we can't make calls
3563  * directly into GraphicsEngine, which is in the display module.
3564  */
3566 set_scene_root_func(SceneRootFunc *func) {
3567  _scene_root_func = func;
3568 }
3569 
3570 /**
3571  * Tells the BamReader how to create objects of type PandaNode.
3572  */
3575  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
3576 }
3577 
3578 /**
3579  * Writes the contents of this object to the datagram for shipping out to a
3580  * Bam file.
3581  */
3583 write_datagram(BamWriter *manager, Datagram &dg) {
3584  TypedWritable::write_datagram(manager, dg);
3585  dg.add_string(get_name());
3586 
3587  manager->write_cdata(dg, _cycler);
3588 }
3589 
3590 /**
3591  * Called by the BamWriter when this object has not itself been modified
3592  * recently, but it should check its nested objects for updates.
3593  */
3595 update_bam_nested(BamWriter *manager) {
3596  CDReader cdata(_cycler);
3597  cdata->update_bam_nested(manager);
3598 }
3599 
3600 /**
3601  * This method is provided for the benefit of classes (like MouseRecorder)
3602  * that inherit from PandaMode and also RecorderBase. It's not virtual at
3603  * this level since it doesn't need to be (it's called up from the derived
3604  * class).
3605  *
3606  * This method acts very like write_datagram, but it writes the node as
3607  * appropriate for writing a RecorderBase object as described in the beginning
3608  * of a session file, meaning it doesn't need to write things such as
3609  * children. It balances with fillin_recorder().
3610  */
3613  dg.add_string(get_name());
3614 }
3615 
3616 /**
3617  * This function is called by the BamReader's factory when a new object of
3618  * type PandaNode is encountered in the Bam file. It should create the
3619  * PandaNode and extract its information from the file.
3620  */
3621 TypedWritable *PandaNode::
3622 make_from_bam(const FactoryParams &params) {
3623  PandaNode *node = new PandaNode("");
3624  DatagramIterator scan;
3625  BamReader *manager;
3626 
3627  parse_params(params, scan, manager);
3628  node->fillin(scan, manager);
3629 
3630  return node;
3631 }
3632 
3633 /**
3634  * This internal function is called by make_from_bam to read in all of the
3635  * relevant data from the BamFile for the new PandaNode.
3636  */
3637 void PandaNode::
3638 fillin(DatagramIterator &scan, BamReader *manager) {
3639  TypedWritable::fillin(scan, manager);
3640 
3642 
3643  string name = scan.get_string();
3644  set_name(name);
3645 
3646  manager->read_cdata(scan, _cycler);
3647 }
3648 
3649 /**
3650  * This internal function is called by make_recorder (in classes derived from
3651  * RecorderBase, such as MouseRecorder) to read in all of the relevant data
3652  * from the session file. It balances with write_recorder().
3653  */
3654 void PandaNode::
3655 fillin_recorder(DatagramIterator &scan, BamReader *) {
3656  string name = scan.get_string();
3657  set_name(name);
3658 }
3659 
3660 /**
3661  *
3662  */
3663 PandaNode::CData::
3664 CData() :
3665  _state(RenderState::make_empty()),
3666  _transform(TransformState::make_identity()),
3667  _prev_transform(TransformState::make_identity()),
3668 
3669  _effects(RenderEffects::make_empty()),
3670  _draw_control_mask(DrawMask::all_off()),
3671  _draw_show_mask(DrawMask::all_on()),
3672  _into_collide_mask(CollideMask::all_off()),
3673  _bounds_type(BoundingVolume::BT_default),
3674  _user_bounds(nullptr),
3675  _final_bounds(false),
3676  _fancy_bits(0),
3677 
3678  _net_collide_mask(CollideMask::all_off()),
3679  _net_draw_control_mask(DrawMask::all_off()),
3680  _net_draw_show_mask(DrawMask::all_off()),
3681 
3682  _down(new PandaNode::Down(PandaNode::get_class_type())),
3683  _stashed(new PandaNode::Down(PandaNode::get_class_type())),
3684  _up(new PandaNode::Up(PandaNode::get_class_type()))
3685 {
3686  ++_next_update;
3687 }
3688 
3689 /**
3690  *
3691  */
3692 PandaNode::CData::
3693 CData(const PandaNode::CData &copy) :
3694  BoundsData(copy),
3695  _state(copy._state),
3696  _transform(copy._transform),
3697  _prev_transform(copy._prev_transform),
3698 
3699  _effects(copy._effects),
3700  _tag_data(copy._tag_data),
3701  _draw_control_mask(copy._draw_control_mask),
3702  _draw_show_mask(copy._draw_show_mask),
3703  _into_collide_mask(copy._into_collide_mask),
3704  _bounds_type(copy._bounds_type),
3705  _user_bounds(copy._user_bounds),
3706  _final_bounds(copy._final_bounds),
3707  _fancy_bits(copy._fancy_bits),
3708 
3709  _net_collide_mask(copy._net_collide_mask),
3710  _net_draw_control_mask(copy._net_draw_control_mask),
3711  _net_draw_show_mask(copy._net_draw_show_mask),
3712  _off_clip_planes(copy._off_clip_planes),
3713  _nested_vertices(copy._nested_vertices),
3714  _external_bounds(copy._external_bounds),
3715  _last_update(copy._last_update),
3716  _next_update(copy._next_update),
3717  _last_bounds_update(copy._last_bounds_update),
3718 
3719  _down(copy._down),
3720  _stashed(copy._stashed),
3721  _up(copy._up)
3722 {
3723  // Note that this copy constructor is not used by the PandaNode copy
3724  // constructor! Any elements that must be copied between nodes should also
3725  // be explicitly copied there.
3726 }
3727 
3728 /**
3729  *
3730  */
3731 PandaNode::CData::
3732 ~CData() {
3733 }
3734 
3735 /**
3736  *
3737  */
3738 CycleData *PandaNode::CData::
3739 make_copy() const {
3740  return new CData(*this);
3741 }
3742 
3743 /**
3744  * Writes the contents of this object to the datagram for shipping out to a
3745  * Bam file.
3746  */
3747 void PandaNode::CData::
3748 write_datagram(BamWriter *manager, Datagram &dg) const {
3749  manager->write_pointer(dg, _state);
3750  manager->write_pointer(dg, _transform);
3751 
3752 
3753  manager->write_pointer(dg, _effects);
3754 
3755  dg.add_uint32(_draw_control_mask.get_word());
3756  dg.add_uint32(_draw_show_mask.get_word());
3757  dg.add_uint32(_into_collide_mask.get_word());
3758  dg.add_uint8(_bounds_type);
3759 
3760  dg.add_uint32(_tag_data.size());
3761  for (size_t n = 0; n < _tag_data.size(); ++n) {
3762  dg.add_string(_tag_data.get_key(n));
3763  dg.add_string(_tag_data.get_data(n));
3764  }
3765 
3766  write_up_list(*get_up(), manager, dg);
3767  write_down_list(*get_down(), manager, dg);
3768  write_down_list(*get_stashed(), manager, dg);
3769 }
3770 
3771 /**
3772  * Called by the BamWriter when this object has not itself been modified
3773  * recently, but it should check its nested objects for updates.
3774  */
3775 void PandaNode::CData::
3776 update_bam_nested(BamWriter *manager) const {
3777  // No need to check the state pointers for updates, since they're all
3778  // immutable objects. manager->consider_update(_state);
3779  // manager->consider_update(_transform); manager->consider_update(_effects);
3780 
3781  update_up_list(*get_up(), manager);
3782  update_down_list(*get_down(), manager);
3783  update_down_list(*get_stashed(), manager);
3784 }
3785 
3786 /**
3787  * Receives an array of pointers, one for each time manager->read_pointer()
3788  * was called in fillin(). Returns the number of pointers processed.
3789  */
3790 int PandaNode::CData::
3791 complete_pointers(TypedWritable **p_list, BamReader *manager) {
3792  int pi = CycleData::complete_pointers(p_list, manager);
3793 
3794  // Get the state and transform pointers.
3795  RenderState *state;
3796  DCAST_INTO_R(state, p_list[pi++], pi);
3797  _state = state;
3798 
3799  TransformState *transform;
3800  DCAST_INTO_R(transform, p_list[pi++], pi);
3801  _prev_transform = _transform = transform;
3802 
3803 /*
3804  * Finalize these pointers now to decrement their artificially-held reference
3805  * counts. We do this now, rather than later, in case some other object
3806  * reassigns them a little later on during initialization, before they can
3807  * finalize themselves normally (for instance, the character may change the
3808  * node's transform). If that happens, the pointer may discover that no one
3809  * else holds its reference count when it finalizes, which will constitute a
3810  * memory leak (see the comments in TransformState::finalize(), etc.).
3811  */
3812  manager->finalize_now((RenderState *)_state.p());
3813  manager->finalize_now((TransformState *)_transform.p());
3814 
3815 
3816 
3817  // Get the effects pointer.
3818  RenderEffects *effects;
3819  DCAST_INTO_R(effects, p_list[pi++], pi);
3820  _effects = effects;
3821 
3822 /*
3823  * Finalize these pointers now to decrement their artificially-held reference
3824  * counts. We do this now, rather than later, in case some other object
3825  * reassigns them a little later on during initialization, before they can
3826  * finalize themselves normally (for instance, the character may change the
3827  * node's transform). If that happens, the pointer may discover that no one
3828  * else holds its reference count when it finalizes, which will constitute a
3829  * memory leak (see the comments in TransformState::finalize(), etc.).
3830  */
3831  manager->finalize_now((RenderEffects *)_effects.p());
3832 
3833 
3834 
3835  // Get the parent and child pointers.
3836  pi += complete_up_list(*modify_up(), "up", p_list + pi, manager);
3837  pi += complete_down_list(*modify_down(), "down", p_list + pi, manager);
3838  pi += complete_down_list(*modify_stashed(), "stashed", p_list + pi, manager);
3839 
3840  // Since the _effects and _states members have been finalized by now, this
3841  // should be safe.
3842  set_fancy_bit(FB_transform, !_transform->is_identity());
3843  set_fancy_bit(FB_state, !_state->is_empty());
3844  set_fancy_bit(FB_effects, !_effects->is_empty());
3845  set_fancy_bit(FB_tag, !_tag_data.is_empty());
3846 
3847  // Mark the bounds stale.
3848  ++_next_update;
3849 
3850  nassertr(!_transform->is_invalid(), pi);
3851  nassertr(!_prev_transform->is_invalid(), pi);
3852 
3853  return pi;
3854 }
3855 
3856 /**
3857  * This internal function is called by make_from_bam to read in all of the
3858  * relevant data from the BamFile for the new PandaNode.
3859  */
3860 void PandaNode::CData::
3861 fillin(DatagramIterator &scan, BamReader *manager) {
3862  // Read the state and transform pointers.
3863  manager->read_pointer(scan);
3864  manager->read_pointer(scan);
3865 
3866  // Read the effects pointer.
3867  manager->read_pointer(scan);
3868 
3869  if (manager->get_file_minor_ver() < 2) {
3870  DrawMask draw_mask;
3871  draw_mask.set_word(scan.get_uint32());
3872 
3873  if (draw_mask == DrawMask::all_off()) {
3874  // Hidden.
3875  _draw_control_mask = _overall_bit;
3876  _draw_show_mask = ~_overall_bit;
3877 
3878  } else if (draw_mask == DrawMask::all_on()) {
3879  // Normally visible.
3880  _draw_control_mask = DrawMask::all_off();
3881  _draw_show_mask = DrawMask::all_on();
3882 
3883  } else {
3884  // Some per-camera combination.
3885  draw_mask &= ~_overall_bit;
3886  _draw_control_mask = ~draw_mask;
3887  _draw_show_mask = draw_mask;
3888  }
3889 
3890  } else {
3891  _draw_control_mask.set_word(scan.get_uint32());
3892  _draw_show_mask.set_word(scan.get_uint32());
3893  }
3894 
3895  _into_collide_mask.set_word(scan.get_uint32());
3896 
3897  _bounds_type = BoundingVolume::BT_default;
3898  if (manager->get_file_minor_ver() >= 19) {
3899  _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8();
3900  }
3901 
3902  // Read in the tag list.
3903  int num_tags = scan.get_uint32();
3904  for (int i = 0; i < num_tags; i++) {
3905  string key = scan.get_string();
3906  string value = scan.get_string();
3907  _tag_data.store(key, value);
3908  }
3909 
3910 
3911  fillin_up_list(*modify_up(), "up", scan, manager);
3912  fillin_down_list(*modify_down(), "down", scan, manager);
3913  fillin_down_list(*modify_stashed(), "stashed", scan, manager);
3914 }
3915 
3916 /**
3917  * Writes the indicated list of parent node pointers to the datagram.
3918  */
3919 void PandaNode::CData::
3920 write_up_list(const PandaNode::Up &up_list,
3921  BamWriter *manager, Datagram &dg) const {
3922 /*
3923  * When we write a PandaNode, we write out its complete list of child node
3924  * pointers, but we only write out the parent node pointers that have already
3925  * been added to the bam file by a previous write operation. This is a bit of
3926  * trickery that allows us to write out just a subgraph (instead of the
3927  * complete graph) when we write out an arbitrary node in the graph, yet also
3928  * allows us to keep nodes completely in sync when we use the bam format for
3929  * streaming scene graph operations over the network.
3930  */
3931 
3932  int num_parents = 0;
3933  Up::const_iterator ui;
3934  for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3935  PandaNode *parent_node = (*ui).get_parent();
3936  if (manager->has_object(parent_node)) {
3937  num_parents++;
3938  }
3939  }
3940  nassertv(num_parents == (int)(uint16_t)num_parents);
3941  dg.add_uint16(num_parents);
3942  for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3943  PandaNode *parent_node = (*ui).get_parent();
3944  if (manager->has_object(parent_node)) {
3945  manager->write_pointer(dg, parent_node);
3946  }
3947  }
3948 }
3949 
3950 /**
3951  * Writes the indicated list of child node pointers to the datagram.
3952  */
3953 void PandaNode::CData::
3954 write_down_list(const PandaNode::Down &down_list,
3955  BamWriter *manager, Datagram &dg) const {
3956  int num_children = down_list.size();
3957  nassertv(num_children == (int)(uint16_t)num_children);
3958  dg.add_uint16(num_children);
3959 
3960  // Should we smarten up the writing of the sort number? Most of the time
3961  // these will all be zero.
3962  Down::const_iterator di;
3963  for (di = down_list.begin(); di != down_list.end(); ++di) {
3964  PandaNode *child_node = (*di).get_child();
3965  int sort = (*di).get_sort();
3966  manager->write_pointer(dg, child_node);
3967  dg.add_int32(sort);
3968  }
3969 }
3970 
3971 /**
3972  * Calls consider_update on each node of the indicated up list.
3973  */
3974 void PandaNode::CData::
3975 update_up_list(const PandaNode::Up &up_list, BamWriter *manager) const {
3976  Up::const_iterator ui;
3977  for (ui = up_list.begin(); ui != up_list.end(); ++ui) {
3978  PandaNode *parent_node = (*ui).get_parent();
3979  if (manager->has_object(parent_node)) {
3980  manager->consider_update(parent_node);
3981  }
3982  }
3983 }
3984 
3985 /**
3986  * Calls consider_update on each node of the indicated up list.
3987  */
3988 void PandaNode::CData::
3989 update_down_list(const PandaNode::Down &down_list, BamWriter *manager) const {
3990  Down::const_iterator di;
3991  for (di = down_list.begin(); di != down_list.end(); ++di) {
3992  PandaNode *child_node = (*di).get_child();
3993  manager->consider_update(child_node);
3994  }
3995 }
3996 
3997 /**
3998  * Calls complete_pointers() on the list of parent node pointers.
3999  */
4000 int PandaNode::CData::
4001 complete_up_list(PandaNode::Up &up_list, const string &tag,
4002  TypedWritable **p_list, BamReader *manager) {
4003  int pi = 0;
4004 
4005  int num_parents = manager->get_int_tag(tag);
4006  Up new_up_list(PandaNode::get_class_type());
4007  new_up_list.reserve(num_parents);
4008  for (int i = 0; i < num_parents; i++) {
4009  PandaNode *parent_node = DCAST(PandaNode, p_list[pi++]);
4010  UpConnection connection(parent_node);
4011  new_up_list.push_back(connection);
4012  }
4013 
4014  // Now we should sort the list, since the sorting is based on pointer order,
4015  // which might be different from one session to the next.
4016  new_up_list.sort();
4017 
4018  // Make it permanent.
4019  up_list.swap(new_up_list);
4020  new_up_list.clear();
4021 
4022  return pi;
4023 }
4024 
4025 /**
4026  * Calls complete_pointers() on the list of child node pointers.
4027  */
4028 int PandaNode::CData::
4029 complete_down_list(PandaNode::Down &down_list, const string &tag,
4030  TypedWritable **p_list, BamReader *manager) {
4031  int pi = 0;
4032 
4033  BamReaderAuxDataDown *aux;
4034  DCAST_INTO_R(aux, manager->get_aux_tag(tag), pi);
4035 
4036  Down &new_down_list = aux->_down_list;
4037  for (Down::iterator di = new_down_list.begin();
4038  di != new_down_list.end();
4039  ++di) {
4040  PandaNode *child_node = DCAST(PandaNode, p_list[pi++]);
4041  (*di).set_child(child_node);
4042  }
4043 
4044  // Unlike the up list, we should *not* sort the down list. The down list is
4045  // stored in a specific order, not related to pointer order; and this order
4046  // should be preserved from one session to the next.
4047 
4048  // Make it permanent.
4049  down_list.swap(new_down_list);
4050  new_down_list.clear();
4051 
4052  return pi;
4053 }
4054 
4055 /**
4056  * Reads the indicated list parent node pointers from the datagram (or at
4057  * least calls read_pointer() for each one).
4058  */
4059 void PandaNode::CData::
4060 fillin_up_list(PandaNode::Up &up_list, const string &tag,
4061  DatagramIterator &scan, BamReader *manager) {
4062  int num_parents = scan.get_uint16();
4063  manager->set_int_tag(tag, num_parents);
4064  manager->read_pointers(scan, num_parents);
4065 }
4066 
4067 /**
4068  * Reads the indicated list child node pointers from the datagram (or at least
4069  * calls read_pointer() for each one).
4070  */
4071 void PandaNode::CData::
4072 fillin_down_list(PandaNode::Down &down_list, const string &tag,
4073  DatagramIterator &scan, BamReader *manager) {
4074  int num_children = scan.get_uint16();
4075 
4076  // Create a temporary down_list, with the right number of elements, but a
4077  // NULL value for each pointer (we'll fill in the pointers later). We need
4078  // to do this to associate the sort values with their pointers.
4079  Down new_down_list(PandaNode::get_class_type());
4080  new_down_list.reserve(num_children);
4081  for (int i = 0; i < num_children; i++) {
4082  manager->read_pointer(scan);
4083  int sort = scan.get_int32();
4084  DownConnection connection(nullptr, sort);
4085  new_down_list.push_back(connection);
4086  }
4087 
4088  // Now store the temporary down_list in the BamReader, so we can get it
4089  // during the call to complete_down_list().
4090  PT(BamReaderAuxDataDown) aux = new BamReaderAuxDataDown;
4091  aux->_down_list.swap(new_down_list);
4092  manager->set_aux_tag(tag, aux);
4093 }
4094 
4095 /**
4096  * Ensures that the draw masks etc. are properly computed on this node. If
4097  * update_bounds is true, also checks the bounding volume.
4098  */
4100 check_cached(bool update_bounds) const {
4101  UpdateSeq last_update = update_bounds
4102  ? _cdata->_last_bounds_update
4103  : _cdata->_last_update;
4104 
4105  if (last_update != _cdata->_next_update) {
4106  // The cache is stale; it needs to be rebuilt.
4107 
4108  // We'll need to get a fresh read pointer, since another thread might
4109  // already have modified the pointer on the object since we queried it.
4110 #ifdef DO_PIPELINING
4111  node_unref_delete((CycleData *)_cdata);
4112 #endif // DO_PIPELINING
4113  ((PandaNodePipelineReader *)this)->_cdata = nullptr;
4114  int pipeline_stage = _current_thread->get_pipeline_stage();
4115  PandaNode::CDLockedStageReader fresh_cdata(_node->_cycler, pipeline_stage, _current_thread);
4116  if (fresh_cdata->_last_update == fresh_cdata->_next_update &&
4117  (!update_bounds || fresh_cdata->_last_bounds_update == fresh_cdata->_next_update)) {
4118  // What luck, some other thread has already freshened the cache for us.
4119  // Save the new pointer, and let the lock release itself.
4120  if (_cdata != (const PandaNode::CData *)fresh_cdata) {
4121  ((PandaNodePipelineReader *)this)->_cdata = fresh_cdata;
4122 #ifdef DO_PIPELINING
4123  _cdata->node_ref();
4124 #endif // DO_PIPELINING
4125  }
4126 
4127  } else {
4128  // No, the cache is still stale. We have to do the work of freshening
4129  // it.
4130  PStatTimer timer(PandaNode::_update_bounds_pcollector);
4131  PandaNode::CDStageWriter cdataw = ((PandaNode *)_node)->update_cached(update_bounds, pipeline_stage, fresh_cdata);
4132  nassertv(cdataw->_last_update == cdataw->_next_update);
4133  // As above, we save the new pointer, and then let the lock release
4134  // itself.
4135  if (_cdata != (const PandaNode::CData *)cdataw) {
4136  ((PandaNodePipelineReader *)this)->_cdata = cdataw;
4137 #ifdef DO_PIPELINING
4138  _cdata->node_ref();
4139 #endif // DO_PIPELINING
4140  }
4141  }
4142  }
4143 
4144  nassertv(_cdata->_last_update == _cdata->_next_update);
4145  nassertv(!update_bounds || _cdata->_last_bounds_update == _cdata->_next_update);
4146 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 ...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:653
int get_int_tag(const std::string &tag) const
Returns the value previously set via set_int_tag().
Definition: bamReader.cxx:744
BamReaderAuxData * get_aux_tag(const std::string &tag) const
Returns the value previously set via set_aux_tag().
Definition: bamReader.cxx:785
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
Definition: bamReader.cxx:897
void set_aux_tag(const std::string &tag, BamReaderAuxData *value)
Allows the creating object to store a temporary data value on the BamReader.
Definition: bamReader.cxx:772
void set_int_tag(const std::string &tag, int value)
Allows the creating object to store a temporary data value on the BamReader.
Definition: bamReader.cxx:731
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
bool has_object(const TypedWritable *obj) const
Returns true if the object has previously been written (or at least requested to be written) to the b...
Definition: bamWriter.cxx:258
void consider_update(const TypedWritable *obj)
Should be called from TypedWritable::update_bam_nested() to recursively check the entire hiererachy o...
Definition: bamWriter.cxx:279
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
static BitMask< uint32_t, nbits > bit(int index)
Returns a BitMask with only the indicated bit on.
Definition: bitMask.I:70
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition: bitMask.I:32
static BitMask< uint32_t, nbits > all_off()
Returns a BitMask whose bits are all off.
Definition: bitMask.I:43
void set_word(WordType value)
Sets the entire BitMask to the value indicated by the given word.
Definition: bitMask.I:255
bool is_zero() const
Returns true if the entire bitmask is zero, false otherwise.
Definition: bitMask.I:153
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
This defines a bounding sphere, consisting of a center and a radius.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
bool around(const BoundingVolume **first, const BoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
This functions similarly to a LightAttrib.
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
This class is similar to CycleDataLockedReader, except it allows reading from a particular stage of t...
Thread * get_current_thread() const
Returns the Thread pointer of the currently-executing thread, as passed to the constructor of this ob...
const CycleDataType * take_pointer()
This is intended to be called only from CycleDataStageWriter when it elevates the pointer from read t...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: cycleData.cxx:48
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
std::string get_string()
Extracts a variable-length string.
int32_t get_int32()
Extracts a signed 32-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:94
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:67
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
An object specifically designed to transform the vertices of a Geom without disturbing indexing or af...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Similar to MutexHolder, but for a light mutex.
Similar to MutexHolder, but for a light reentrant mutex.
The abstract interface to all kinds of lights.
Definition: light.h:38
This just stores the pointers to implement a doubly-linked list of some kind of object.
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
Definition: memoryUsage.I:55
A base class for all things which can have a name.
Definition: namable.h:26
This is one component of a NodePath.
PandaNode * get_node() const
Returns the node referenced by this component.
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
NodePathComponent * get_next(int pipeline_stage, Thread *current_thread) const
Returns the next component in the path.
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition: nodePath.I:62
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...
Definition: pStatTimer.h:30
This class maintains a linked list of PandaNodes.
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
Definition: pandaNode.h:840
void check_cached(bool update_bounds) const
Ensures that the draw masks etc.
Definition: pandaNode.cxx:4100
int get_child_sort(size_t n) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
Definition: pandaNode.I:973
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
PandaNode * get_parent(size_t n) const
Returns the nth parent of the node.
Definition: pandaNode.I:1122
size_t get_num_parents() const
Returns the number of parents of the node.
Definition: pandaNode.I:1113
PandaNode * get_stashed(size_t n) const
Returns the nth stashed child of the node.
Definition: pandaNode.I:1042
int get_stashed_sort(size_t n) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
Definition: pandaNode.I:1053
size_t get_num_stashed() const
Returns the number of stashed children of the node.
Definition: pandaNode.I:1033
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
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.
Definition: pandaNode.cxx:910
void write_recorder(BamWriter *manager, Datagram &dg)
This method is provided for the benefit of classes (like MouseRecorder) that inherit from PandaMode a...
Definition: pandaNode.cxx:3612
DrawMask get_net_draw_control_mask() const
Returns the set of bits in get_net_draw_show_mask() that have been explicitly set via adjust_draw_mas...
Definition: pandaNode.cxx:1623
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
Definition: pandaNode.cxx:256
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...
Definition: pandaNode.cxx:632
get_draw_control_mask
Returns the set of bits in draw_show_mask that are considered meaningful.
Definition: pandaNode.h:255
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2062
void get_tag_keys(vector_string &keys) const
Fills the given vector up with the list of tags on this PandaNode.
Definition: pandaNode.cxx:1298
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
Definition: pandaNode.cxx:319
virtual int get_next_visible_child(int n) const
Returns the index number of the next visible child of this node following the indicated child,...
Definition: pandaNode.cxx:426
bool unstash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Returns the indicated stashed node to normal child status.
Definition: pandaNode.I:128
virtual bool has_single_child_visibility() const
Should be overridden by derived classes to return true if this kind of node has the special property ...
Definition: pandaNode.cxx:442
virtual bool safe_to_combine() const
Returns true if it is generally safe to combine this particular kind of PandaNode with other kinds of...
Definition: pandaNode.cxx:228
virtual int get_unsafe_to_apply_attribs() const
Returns the union of all attributes from SceneGraphReducer::AttribTypes that may not safely be applie...
Definition: pandaNode.cxx:268
virtual int get_visible_child() const
Returns the index number of the currently visible child of this node.
Definition: pandaNode.cxx:451
set_tag
Associates a user-defined value with a user-defined key which is stored on the node.
Definition: pandaNode.h:207
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of PandaNode by calling the xf...
Definition: pandaNode.cxx:204
void clear_unexpected_change(unsigned int flags)
Sets one or more of the PandaNode::UnexpectedChange bits off, indicating that the corresponding prope...
Definition: pandaNode.cxx:1548
DrawMask get_net_draw_show_mask() const
Returns the union of all draw_show_mask values–of renderable nodes only– at this level and below.
Definition: pandaNode.cxx:1650
void reset_prev_transform(Thread *current_thread=Thread::get_current_thread())
Resets the transform that represents this node's "previous" position to the same as the current trans...
Definition: pandaNode.cxx:1147
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
Definition: pandaNode.cxx:1016
virtual void update_bam_nested(BamWriter *manager)
Called by the BamWriter when this object has not itself been modified recently, but it should check i...
Definition: pandaNode.cxx:3595
CollideMask get_net_collide_mask(Thread *current_thread=Thread::get_current_thread()) const
Returns the union of all into_collide_mask() values set at CollisionNodes at this level and below.
Definition: pandaNode.cxx:1715
void remove_all_children(Thread *current_thread=Thread::get_current_thread())
Removes all the children from the node at once, including stashed children.
Definition: pandaNode.cxx:830
int find_stashed(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated stashed node, if it is a stashed child, or -1 if it is not.
Definition: pandaNode.I:178
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
Definition: pandaNode.cxx:462
static void reset_all_prev_transform(Thread *current_thread=Thread::get_current_thread())
Visits all nodes in the world with the _dirty_prev_transform flag–that is, all nodes whose _prev_tran...
Definition: pandaNode.cxx:1170
virtual bool safe_to_combine_children() const
Returns true if it is generally safe to combine the children of this PandaNode with each other.
Definition: pandaNode.cxx:238
virtual bool safe_to_modify_transform() const
Returns true if it is safe to automatically adjust the transform on this kind of node.
Definition: pandaNode.cxx:217
void remove_stashed(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth stashed child from the node.
Definition: pandaNode.cxx:800
get_legal_collide_mask
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode.
Definition: pandaNode.h:265
virtual void r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer, Thread *current_thread)
The recursive implementation of prepare_scene().
Definition: pandaNode.cxx:2436
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
Definition: pandaNode.cxx:1907
void set_bounds_type(BoundingVolume::BoundsType bounds_type)
Specifies the desired type of bounding volume that will be created for this node.
Definition: pandaNode.cxx:1872
set_effects
Sets the complete RenderEffects that will be applied this node.
Definition: pandaNode.h:178
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
Definition: pandaNode.cxx:564
static void register_with_read_factory()
Tells the BamReader how to create objects of type PandaNode.
Definition: pandaNode.cxx:3574
get_parents
Returns an object that can be used to walk through the list of parents of the node,...
Definition: pandaNode.h:784
get_num_stashed
Returns the number of stashed nodes this node has.
Definition: pandaNode.h:148
void adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask)
Adjusts the hide/show bits of this particular node.
Definition: pandaNode.cxx:1585
get_draw_show_mask
Returns the hide/show bits of this particular node.
Definition: pandaNode.h:256
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so.
Definition: pandaNode.cxx:304
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...
Definition: pandaNode.cxx:1786
virtual int get_first_visible_child() const
Returns the index number of the first visible child of this node, or a number >= get_num_children() i...
Definition: pandaNode.cxx:415
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
void copy_all_properties(PandaNode *other)
Copies the TransformState, RenderState, RenderEffects, tags, Python tags, and the show/hide state fro...
Definition: pandaNode.cxx:1361
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 ...
Definition: pandaNode.cxx:247
virtual PandaNode * dupe_for_flatten() const
This is similar to make_copy(), but it makes a copy for the specific purpose of flatten.
Definition: pandaNode.cxx:184
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
Definition: pandaNode.h:173
virtual bool has_selective_visibility() const
Should be overridden by derived classes to return true if this kind of node has some restrictions on ...
Definition: pandaNode.cxx:403
set_transform
Sets the transform that will be applied to this node and below.
Definition: pandaNode.h:183
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: pandaNode.cxx:999
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...
Definition: pandaNode.cxx:282
bool is_scene_root() const
Returns true if this particular node is known to be the render root of some active DisplayRegion asso...
Definition: pandaNode.cxx:1769
virtual bool is_lod_node() const
A simple downcast check.
Definition: pandaNode.cxx:2074
bool stash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Stashes the indicated child node.
Definition: pandaNode.I:107
void add_stashed(PandaNode *child_node, int sort=0, Thread *current_thread=Thread::get_current_thread())
Adds a new child to the node, directly as a stashed child.
Definition: pandaNode.cxx:765
virtual bool is_collision_node() const
A simple downcast check.
Definition: pandaNode.cxx:2086
void list_tags(std::ostream &out, const std::string &separator="\n") const
Writes a list of all the tag keys assigned to the node to the indicated stream.
Definition: pandaNode.cxx:1277
unsigned int get_unexpected_change(unsigned int flags) const
Returns nonzero if any of the bits in the input parameter are set on this node, or zero if none of th...
Definition: pandaNode.cxx:1529
static void set_scene_root_func(SceneRootFunc *func)
This is used by the GraphicsEngine to hook in a pointer to the scene_root_func(), the function to det...
Definition: pandaNode.cxx:3566
clear_tag
Removes the value defined for this key on this particular node.
Definition: pandaNode.h:207
void copy_tags(PandaNode *other)
Copies all of the tags stored on the other node onto this node.
Definition: pandaNode.cxx:1240
void set_prev_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Sets the transform that represents this node's "previous" position, one frame ago,...
Definition: pandaNode.cxx:1118
void set_bound(const BoundingVolume *volume)
Deprecated.
Definition: pandaNode.cxx:1926
virtual bool is_ambient_light() const
Returns true if this is an AmbientLight, false if it is not a light, or it is some other kind of ligh...
Definition: pandaNode.cxx:2104
int find_parent(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated parent node, if it is a parent, or -1 if it is not.
Definition: pandaNode.I:44
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
Definition: pandaNode.cxx:481
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...
Definition: pandaNode.I:78
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
Definition: pandaNode.cxx:938
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data)
Adds the node's contents to the CullResult we are building up during the cull traversal,...
Definition: pandaNode.cxx:472
get_stashed
Returns the nth stashed child of this node.
Definition: pandaNode.h:148
set_into_collide_mask
Sets the "into" CollideMask.
Definition: pandaNode.h:264
void set_unexpected_change(unsigned int flags)
Sets one or more of the PandaNode::UnexpectedChange bits on, indicating that the corresponding proper...
Definition: pandaNode.cxx:1513
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:782
get_bounds_type
Returns the bounding volume type set with set_bounds_type().
Definition: pandaNode.h:293
void replace_node(PandaNode *other)
Inserts this node into the scene graph in place of the other one, and removes the other node.
Definition: pandaNode.cxx:1454
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: pandaNode.cxx:3583
void steal_children(PandaNode *other, Thread *current_thread=Thread::get_current_thread())
Moves all the children from the other node onto this node.
Definition: pandaNode.cxx:875
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...
Definition: pandaNode.cxx:1313
int get_stashed_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth stashed node of this node (that is, the number that was passed to a...
Definition: pandaNode.I:166
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes,...
Definition: pandaNode.cxx:2095
get_parent
Returns the nth parent node of this node.
Definition: pandaNode.h:118
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
Definition: pandaNode.cxx:195
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
A base class for all things that want to be reference-counted.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:41
bool is_empty() const
Returns true if the state is empty, false otherwise.
Definition: renderEffects.I:94
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
bool is_empty() const
Returns true if the state is empty, false otherwise.
Definition: renderState.I:27
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
constexpr size_t size() const
Returns the total number of entries in the table.
A thread; that is, a lightweight process.
Definition: thread.h:46
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
Definition: thread.h:105
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
Indicates a coordinate-system transform on vertices.
bool is_invalid() const
Returns true if the transform represents an invalid matrix, for instance the result of inverting a si...
get_mat
Returns the matrix that describes the transform.
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
static bool decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr, vector_uchar data, BamReader *reader=nullptr)
Reads the bytes created by a previous call to encode_to_bam_stream(), and extracts the single object ...
void mark_bam_modified()
Increments the bam_modified counter, so that this object will be invalidated and retransmitted on any...
Definition: typedWritable.I:43
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void node_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(TransformState) PandaNode
This is used to support NodePath::calc_tight_bounds().
Definition: pandaNode.cxx:351
PT(PandaNode) PandaNode
Allocates and returns a complete copy of this PandaNode and the entire scene graph rooted at this Pan...
Definition: pandaNode.cxx:491
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void release_read_stage(int pipeline_stage, const CycleData *pointer) const
Releases a pointer previously obtained via a call to read_stage().