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