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 }
PandaNode::is_lod_node
virtual bool is_lod_node() const
A simple downcast check.
Definition: pandaNode.cxx:2074
PandaNode::remove_all_children
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
PandaNode::set_effects
set_effects
Sets the complete RenderEffects that will be applied this node.
Definition: pandaNode.h:178
PandaNode::get_parent
get_parent
Returns the nth parent node of this node.
Definition: pandaNode.h:118
PandaNode::find_parent
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
PandaNode::combine_with
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
clipPlaneAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TransformState::is_identity
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
Definition: transformState.I:197
DatagramIterator::get_string
std::string get_string()
Extracts a variable-length string.
Definition: datagramIterator.cxx:26
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PandaNode::adjust_draw_mask
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
UpdateSeq
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
PandaNode::is_geom_node
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2062
PandaNode::clear_effect
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
Definition: pandaNode.cxx:1016
pandaNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
RenderEffects
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:41
PandaNode::set_effect
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: pandaNode.cxx:999
CycleData
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
ClipPlaneAttrib
This functions similarly to a LightAttrib.
Definition: clipPlaneAttrib.h:31
DatagramIterator::get_int32
int32_t get_int32()
Extracts a signed 32-bit integer.
Definition: datagramIterator.I:107
RenderEffects::is_empty
bool is_empty() const
Returns true if the state is empty, false otherwise.
Definition: renderEffects.I:94
PandaNode::is_scene_root
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
PipelineCyclerTrivialImpl::release_read_stage
void release_read_stage(int pipeline_stage, const CycleData *pointer) const
Releases a pointer previously obtained via a call to read_stage().
Definition: pipelineCyclerTrivialImpl.I:227
PandaNode::set_bounds
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
Definition: pandaNode.cxx:1907
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
PandaNode::get_visible_child
virtual int get_visible_child() const
Returns the index number of the currently visible child of this node.
Definition: pandaNode.cxx:451
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
accumulatedAttribs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::set_bounds_type
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
BoundingSphere
This defines a bounding sphere, consisting of a center and a radius.
Definition: boundingSphere.h:25
PandaNode::is_ambient_light
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
BamReader::get_int_tag
int get_int_tag(const std::string &tag) const
Returns the value previously set via set_int_tag().
Definition: bamReader.cxx:744
PandaNode::Stashed::get_stashed
PandaNode * get_stashed(size_t n) const
Returns the nth stashed child of the node.
Definition: pandaNode.I:1042
PandaNode::get_net_draw_control_mask
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
PandaNode::add_stashed
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
PandaNode::get_stashed_sort
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
GeomTransformer
An object specifically designed to transform the vertices of a Geom without disturbing indexing or af...
Definition: geomTransformer.h:42
RenderEffect
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
ReferenceCount
A base class for all things that want to be reference-counted.
Definition: referenceCount.h:38
CycleDataStageReader
This class is similar to CycleDataReader, except it allows reading from a particular stage of the pip...
Definition: cycleDataStageReader.h:27
NodePathComponent::get_node
PandaNode * get_node() const
Returns the node referenced by this component.
Definition: nodePathComponent.I:45
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
PandaNode::write_recorder
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
PandaNode::get_first_visible_child
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
sceneGraphReducer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::copy_children
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
PandaNode::update_bam_nested
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
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
CycleDataLockedStageReader
This class is similar to CycleDataLockedReader, except it allows reading from a particular stage of t...
Definition: cycleDataLockedStageReader.h:27
PandaNode::apply_attribs_to_vertices
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
BoundingVolume::around
bool around(const BoundingVolume **first, const BoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
Definition: boundingVolume.cxx:40
PandaNode::replace_node
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
BamReader::get_aux_tag
BamReaderAuxData * get_aux_tag(const std::string &tag) const
Returns the value previously set via set_aux_tag().
Definition: bamReader.cxx:785
PandaNode::set_unexpected_change
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
PandaNode::replace_child
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
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::get_unsafe_to_apply_attribs
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
PandaNode::Parents
Definition: pandaNode.h:752
nodePathComponent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
BamWriter::write_pointer
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
RenderAttrib
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
SimpleHashMap::get_key
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
Definition: simpleHashMap.I:396
PandaNode::Parents::get_parent
PandaNode * get_parent(size_t n) const
Returns the nth parent of the node.
Definition: pandaNode.I:1122
PandaNodePipelineReader
Encapsulates the data from a PandaNode, pre-fetched for one stage of the pipeline.
Definition: pandaNode.h:840
PandaNode::Children::get_child
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
PandaNode::get_bounds_type
get_bounds_type
Returns the bounding volume type set with set_bounds_type().
Definition: pandaNode.h:293
PandaNode::set_state
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
Definition: pandaNode.h:173
PandaNode::get_child_sort
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
TransformState::get_mat
get_mat
Returns the matrix that describes the transform.
Definition: transformState.h:156
BitMask< uint32_t, 32 >
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
PandaNode::is_under_scene_root
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
PandaNode::unstash_child
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
PandaNode::add_for_draw
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
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CopyOnWriteObj1< DownList, TypeHandle >
PandaNode::get_next_visible_child
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
BamWriter::consider_update
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
PandaNode::dupe_for_flatten
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
Light
The abstract interface to all kinds of lights.
Definition: light.h:38
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PandaNode::get_children
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:782
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PandaNode::is_renderable
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
PandaNode::has_selective_visibility
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
PandaNode::get_draw_show_mask
get_draw_show_mask
Returns the hide/show bits of this particular node.
Definition: pandaNode.h:256
CycleDataLockedStageReader::take_pointer
const CycleDataType * take_pointer()
This is intended to be called only from CycleDataStageWriter when it elevates the pointer from read t...
Definition: cycleDataLockedStageReader.I:244
LinkedListNode
This just stores the pointers to implement a doubly-linked list of some kind of object.
Definition: linkedListNode.h:31
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
BoundingBox
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
PandaNode::steal_children
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
SimpleHashMap< std::string, std::string, string_hash >
BitMask::is_zero
bool is_zero() const
Returns true if the entire bitmask is zero, false otherwise.
Definition: bitMask.I:153
PandaNode::clear_unexpected_change
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
PandaNode::set_prev_transform
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
PandaNode::list_tags
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
PandaNode::find_stashed
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
PandaNode::DownConnection
Definition: pandaNode.h:448
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
AccumulatedAttribs
This class is used by the SceneGraphReducer to maintain and accumulate the set of attributes we have ...
Definition: accumulatedAttribs.h:30
PStatTimer
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
Datagram::add_string
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PandaNode::safe_to_transform
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
BamWriter::has_object
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
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
BitMask< uint32_t, 32 >::bit
static BitMask< uint32_t, nbits > bit(int index)
Returns a BitMask with only the indicated bit on.
Definition: bitMask.I:70
MemoryUsage::update_type
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
Definition: memoryUsage.I:55
PandaNode::write_datagram
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
BamReader::read_pointers
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:653
PandaNode::Children
Definition: pandaNode.h:706
BamReader::read_cdata
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PandaNode::set_attrib
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
TypedWritable::mark_bam_modified
void mark_bam_modified()
Increments the bam_modified counter, so that this object will be invalidated and retransmitted on any...
Definition: typedWritable.I:43
PandaNode::has_single_child_visibility
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
PandaNode::reset_all_prev_transform
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
CycleDataWriter
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
Definition: cycleDataWriter.h:34
PandaNode::preserve_name
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
TypedWritable::write_datagram
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: typedWritable.cxx:54
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
BamReader::set_int_tag
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
GeometricBoundingVolume
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
Definition: geometricBoundingVolume.h:29
CycleDataReader
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
Definition: cycleDataReader.h:35
PandaNode::remove_child
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
Definition: pandaNode.cxx:564
boundingSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNodeChain
This class maintains a linked list of PandaNodes.
Definition: pandaNodeChain.h:28
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition: pStatCollector.h:43
PandaNode::Children::get_num_children
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
BitMask::set_word
void set_word(WordType value)
Sets the entire BitMask to the value indicated by the given word.
Definition: bitMask.I:255
PandaNode::get_child
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
TransformState::is_invalid
bool is_invalid() const
Returns true if the transform represents an invalid matrix, for instance the result of inverting a si...
Definition: transformState.I:207
PandaNode::r_prepare_scene
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
PandaNodePipelineReader::check_cached
void check_cached(bool update_bounds) const
Ensures that the draw masks etc.
Definition: pandaNode.cxx:4100
CPT
CPT(TransformState) PandaNode
This is used to support NodePath::calc_tight_bounds().
Definition: pandaNode.cxx:351
NodePathComponent::is_top_node
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
Definition: nodePathComponent.cxx:81
PandaNode::safe_to_flatten_below
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
PandaNode::get_parents
get_parents
Returns an object that can be used to walk through the list of parents of the node,...
Definition: pandaNode.h:784
Factory::register_factory
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
BamWriter::write_cdata
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
CycleDataStageWriter
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
Definition: cycleDataStageWriter.h:31
PandaNode::clear_tag
clear_tag
Removes the value defined for this key on this particular node.
Definition: pandaNode.h:207
PandaNode::get_stashed
get_stashed
Returns the nth stashed child of this node.
Definition: pandaNode.h:148
Datagram::add_int32
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:67
PandaNode::stash_child
bool stash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Stashes the indicated child node.
Definition: pandaNode.I:107
NodePathComponent
This is one component of a NodePath.
Definition: nodePathComponent.h:42
NodePathComponent::get_next
NodePathComponent * get_next(int pipeline_stage, Thread *current_thread) const
Returns the next component in the path.
Definition: nodePathComponent.I:65
config_mathutil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BitMask::all_off
static BitMask< WType, nbits > all_off()
Returns a BitMask whose bits are all off.
Definition: bitMask.I:43
PandaNode::set_transform
set_transform
Sets the transform that will be applied to this node and below.
Definition: pandaNode.h:183
PandaNode::make_copy
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
Definition: pandaNode.cxx:481
Datagram::add_uint32
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:94
BamReader::finalize_now
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
Definition: bamReader.cxx:897
PandaNode::as_light
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
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
PandaNode::safe_to_flatten
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
Namable
A base class for all things which can have a name.
Definition: namable.h:26
PandaNode::get_net_draw_show_mask
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
PandaNode::copy_tags
void copy_tags(PandaNode *other)
Copies all of the tags stored on the other node onto this node.
Definition: pandaNode.cxx:1240
PandaNode::reset_prev_transform
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
PandaNode::safe_to_modify_transform
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
TypedWritableReferenceCount
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Definition: typedWritableReferenceCount.h:31
PandaNode::set_tag
set_tag
Associates a user-defined value with a user-defined key which is stored on the node.
Definition: pandaNode.h:207
PandaNode::set_bound
void set_bound(const BoundingVolume *volume)
Deprecated.
Definition: pandaNode.cxx:1926
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition: graphicsStateGuardianBase.h:110
node_unref_delete
void node_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
Definition: nodeReferenceCount.I:185
CycleDataLockedStageReader::get_current_thread
Thread * get_current_thread() const
Returns the Thread pointer of the currently-executing thread, as passed to the constructor of this ob...
Definition: cycleDataLockedStageReader.I:254
PandaNode::Parents::get_num_parents
size_t get_num_parents() const
Returns the number of parents of the node.
Definition: pandaNode.I:1113
PandaNode::safe_to_combine_children
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
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
PandaNode::Stashed::get_stashed_sort
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
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
RenderState::is_empty
bool is_empty() const
Returns true if the state is empty, false otherwise.
Definition: renderState.I:27
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
DatagramIterator::get_uint32
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
Definition: datagramIterator.I:164
Thread::get_pipeline_stage
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
Definition: thread.h:105
BamReader::set_aux_tag
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
TypedWritable::fillin
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...
Definition: typedWritable.cxx:103
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition: boundingVolume.h:41
PandaNode::get_legal_collide_mask
get_legal_collide_mask
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode.
Definition: pandaNode.h:265
PandaNode::get_num_children
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
SimpleHashMap::size
constexpr size_t size() const
Returns the total number of entries in the table.
Definition: simpleHashMap.I:385
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PandaNode::Stashed
Definition: pandaNode.h:729
PandaNode::get_num_stashed
get_num_stashed
Returns the number of stashed nodes this node has.
Definition: pandaNode.h:148
PandaNode::copy_all_properties
void copy_all_properties(PandaNode *other)
Copies the TransformState, RenderState, RenderEffects, tags, Python tags, and the show/hide state fro...
Definition: pandaNode.cxx:1361
graphicsStateGuardianBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BitMask< uint32_t, 32 >::all_on
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition: bitMask.I:32
TypedObject::is_exact_type
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
PandaNode::compare_tags
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
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::remove_stashed
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
CycleData::complete_pointers
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
PandaNode::get_draw_control_mask
get_draw_control_mask
Returns the set of bits in draw_show_mask that are considered meaningful.
Definition: pandaNode.h:255
PT
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
PandaNode::register_with_read_factory
static void register_with_read_factory()
Tells the BamReader how to create objects of type PandaNode.
Definition: pandaNode.cxx:3574
PandaNode::xform
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
PandaNode::Stashed::get_num_stashed
size_t get_num_stashed() const
Returns the number of stashed children of the node.
Definition: pandaNode.I:1033
PandaNode::get_net_collide_mask
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
parse_params
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
PandaNode::get_tag_keys
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
PandaNode::get_unexpected_change
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
PandaNode::is_collision_node
virtual bool is_collision_node() const
A simple downcast check.
Definition: pandaNode.cxx:2086
PandaNode::set_scene_root_func
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
NodePath::any_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
PandaNode::Children::get_child_sort
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::safe_to_combine
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
TypedWritable::decode_raw_from_bam_stream
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 ...
Definition: typedWritable.cxx:190
lightReMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::set_into_collide_mask
set_into_collide_mask
Sets the "into" CollideMask.
Definition: pandaNode.h:264
boundingBox.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geometricBoundingVolume.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.