Panda3D
pandaNode.I
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.I
10  * @author drose
11  * @date 2002-02-20
12  */
13 
14 /**
15  * Returns the number of parent nodes this node has. If this number is
16  * greater than 1, the node has been multiply instanced. The order of the
17  * parent nodes is not meaningful and is not related to the order in which the
18  * node was instanced to them.
19  */
20 INLINE int PandaNode::
21 get_num_parents(Thread *current_thread) const {
22  CDReader cdata(_cycler, current_thread);
23  return cdata->get_up()->size();
24 }
25 
26 /**
27  * Returns the nth parent node of this node. See get_num_parents(). Also see
28  * get_parents(), if your intention is to iterate through the complete list of
29  * parents; get_parents() is preferable in this case.
30  */
31 INLINE PandaNode *PandaNode::
32 get_parent(int n, Thread *current_thread) const {
33  CDReader cdata(_cycler, current_thread);
34  CPT(Up) up = cdata->get_up();
35  nassertr(n >= 0 && n < (int)up->size(), nullptr);
36  return (*up)[n].get_parent();
37 }
38 
39 /**
40  * Returns the index of the indicated parent node, if it is a parent, or -1 if
41  * it is not.
42  */
43 INLINE int PandaNode::
44 find_parent(PandaNode *node, Thread *current_thread) const {
45  CDReader cdata(_cycler, current_thread);
46  return do_find_parent(node, cdata);
47 }
48 
49 /**
50  * Returns the number of child nodes this node has. The order of the child
51  * nodes *is* meaningful and is based on the sort number that was passed to
52  * add_child(), and also on the order in which the nodes were added.
53  */
54 INLINE int PandaNode::
55 get_num_children(Thread *current_thread) const {
56  CDReader cdata(_cycler, current_thread);
57  return cdata->get_down()->size();
58 }
59 
60 /**
61  * Returns the nth child node of this node. See get_num_children(). Also see
62  * get_children(), if your intention is to iterate through the complete list
63  * of children; get_children() is preferable in this case.
64  */
65 INLINE PandaNode *PandaNode::
66 get_child(int n, Thread *current_thread) const {
67  CDReader cdata(_cycler, current_thread);
68  CPT(Down) down = cdata->get_down();
69  nassertr(n >= 0 && n < (int)down->size(), nullptr);
70  return (*down)[n].get_child();
71 }
72 
73 /**
74  * Returns the sort index of the nth child node of this node (that is, the
75  * number that was passed to add_child()). See get_num_children().
76  */
77 INLINE int PandaNode::
78 get_child_sort(int n, Thread *current_thread) const {
79  CDReader cdata(_cycler, current_thread);
80  CPT(Down) down = cdata->get_down();
81  nassertr(n >= 0 && n < (int)down->size(), -1);
82  return (*down)[n].get_sort();
83 }
84 
85 /**
86  * Returns the index of the indicated child node, if it is a child, or -1 if
87  * it is not.
88  */
89 INLINE int PandaNode::
90 find_child(PandaNode *node, Thread *current_thread) const {
91  CDReader cdata(_cycler, current_thread);
92  return do_find_child(node, cdata->get_down());
93 }
94 
95 /**
96  * Stashes the indicated child node. This removes the child from the list of
97  * active children and puts it on a special list of stashed children. This
98  * child node no longer contributes to the bounding volume of the PandaNode,
99  * and is not visited in normal traversals. It is invisible and uncollidable.
100  * The child may later be restored by calling unstash_child().
101  *
102  * This function returns true if the child node was successfully stashed, or
103  * false if it was not a child of the node in the first place (e.g. it was
104  * previously stashed).
105  */
106 INLINE bool PandaNode::
107 stash_child(PandaNode *child_node, Thread *current_thread) {
108  int child_index = find_child(child_node, current_thread);
109  if (child_index < 0) {
110  return false;
111  }
112  stash_child(child_index, current_thread);
113  return true;
114 }
115 
116 /**
117  * Returns the indicated stashed node to normal child status. This removes
118  * the child from the list of stashed children and puts it on the normal list
119  * of active children. This child node once again contributes to the bounding
120  * volume of the PandaNode, and will be visited in normal traversals. It is
121  * visible and collidable.
122  *
123  * This function returns true if the child node was successfully stashed, or
124  * false if it was not a child of the node in the first place (e.g. it was
125  * previously stashed).
126  */
127 INLINE bool PandaNode::
128 unstash_child(PandaNode *child_node, Thread *current_thread) {
129  int stashed_index = find_stashed(child_node, current_thread);
130  if (stashed_index < 0) {
131  return false;
132  }
133  unstash_child(stashed_index, current_thread);
134  return true;
135 }
136 
137 /**
138  * Returns the number of stashed nodes this node has. These are former
139  * children of the node that have been moved to the special stashed list via
140  * stash_child().
141  */
142 INLINE int PandaNode::
143 get_num_stashed(Thread *current_thread) const {
144  CDReader cdata(_cycler, current_thread);
145  return cdata->get_stashed()->size();
146 }
147 
148 /**
149  * Returns the nth stashed child of this node. See get_num_stashed(). Also
150  * see get_stashed(), if your intention is to iterate through the complete
151  * list of stashed children; get_stashed() is preferable in this case.
152  */
153 INLINE PandaNode *PandaNode::
154 get_stashed(int n, Thread *current_thread) const {
155  CDReader cdata(_cycler, current_thread);
156  CPT(Down) stashed = cdata->get_stashed();
157  nassertr(n >= 0 && n < (int)stashed->size(), nullptr);
158  return (*stashed)[n].get_child();
159 }
160 
161 /**
162  * Returns the sort index of the nth stashed node of this node (that is, the
163  * number that was passed to add_child()). See get_num_stashed().
164  */
165 INLINE int PandaNode::
166 get_stashed_sort(int n, Thread *current_thread) const {
167  CDReader cdata(_cycler, current_thread);
168  CPT(Down) stashed = cdata->get_stashed();
169  nassertr(n >= 0 && n < (int)stashed->size(), -1);
170  return (*stashed)[n].get_sort();
171 }
172 
173 /**
174  * Returns the index of the indicated stashed node, if it is a stashed child,
175  * or -1 if it is not.
176  */
177 INLINE int PandaNode::
178 find_stashed(PandaNode *node, Thread *current_thread) const {
179  CDReader cdata(_cycler, current_thread);
180  return do_find_child(node, cdata->get_stashed());
181 }
182 
183 /**
184  * Returns the render attribute of the indicated type, if it is defined on the
185  * node, or NULL if it is not. This checks only what is set on this
186  * particular node level, and has nothing to do with what render attributes
187  * may be inherited from parent nodes.
188  */
189 INLINE CPT(RenderAttrib) PandaNode::
190 get_attrib(TypeHandle type) const {
191  CDReader cdata(_cycler);
192  return cdata->_state->get_attrib(type);
193 }
194 
195 /**
196  * Returns the render attribute of the indicated type, if it is defined on the
197  * node, or NULL if it is not. This checks only what is set on this
198  * particular node level, and has nothing to do with what render attributes
199  * may be inherited from parent nodes.
200  */
201 INLINE CPT(RenderAttrib) PandaNode::
202 get_attrib(int slot) const {
203  CDReader cdata(_cycler);
204  return cdata->_state->get_attrib(slot);
205 }
206 
207 /**
208  * Returns true if there is a render attribute of the indicated type defined
209  * on this node, or false if there is not.
210  */
211 INLINE bool PandaNode::
212 has_attrib(TypeHandle type) const {
213  CDReader cdata(_cycler);
214  return cdata->_state->has_attrib(type);
215 }
216 
217 /**
218  * Returns true if there is a render attribute of the indicated type defined
219  * on this node, or false if there is not.
220  */
221 INLINE bool PandaNode::
222 has_attrib(int slot) const {
223  CDReader cdata(_cycler);
224  return cdata->_state->has_attrib(slot);
225 }
226 
227 /**
228  * Removes the render attribute of the given type from this node. This node,
229  * and the subgraph below, will now inherit the indicated render attribute
230  * from the nodes above this one.
231  */
232 INLINE void PandaNode::
233 clear_attrib(TypeHandle type) {
235  int slot = reg->get_slot(type);
236  clear_attrib(slot);
237 }
238 
239 /**
240  * Returns the render effect of the indicated type, if it is defined on the
241  * node, or NULL if it is not.
242  */
243 INLINE CPT(RenderEffect) PandaNode::
244 get_effect(TypeHandle type) const {
245  CDReader cdata(_cycler);
246  int index = cdata->_effects->find_effect(type);
247  if (index >= 0) {
248  return cdata->_effects->get_effect(index);
249  }
250  return nullptr;
251 }
252 
253 /**
254  * Returns true if there is a render effect of the indicated type defined on
255  * this node, or false if there is not.
256  */
257 INLINE bool PandaNode::
258 has_effect(TypeHandle type) const {
259  CDReader cdata(_cycler);
260  int index = cdata->_effects->find_effect(type);
261  return (index >= 0);
262 }
263 
264 /**
265  * Returns the complete RenderState that will be applied to all nodes at this
266  * level and below, as set on this node. This returns only the RenderState
267  * set on this particular node, and has nothing to do with state that might be
268  * inherited from above.
269  */
270 INLINE CPT(RenderState) PandaNode::
271 get_state(Thread *current_thread) const {
272  CDReader cdata(_cycler, current_thread);
273  return cdata->_state.p();
274 }
275 
276 /**
277  * Resets this node to leave the render state alone. Nodes at this level and
278  * below will once again inherit their render state unchanged from the nodes
279  * above this level.
280  */
281 INLINE void PandaNode::
282 clear_state(Thread *current_thread) {
283  set_state(RenderState::make_empty(), current_thread);
284 }
285 
286 /**
287  * Returns the complete RenderEffects that will be applied to this node.
288  */
289 INLINE CPT(RenderEffects) PandaNode::
290 get_effects(Thread *current_thread) const {
291  CDReader cdata(_cycler, current_thread);
292  return cdata->_effects;
293 }
294 
295 /**
296  * Resets this node to have no render effects.
297  */
298 INLINE void PandaNode::
299 clear_effects(Thread *current_thread) {
300  set_effects(RenderEffects::make_empty(), current_thread);
301 }
302 
303 /**
304  * Returns the transform that has been set on this particular node. This is
305  * not the net transform from the root, but simply the transform on this
306  * particular node.
307  */
308 INLINE CPT(TransformState) PandaNode::
309 get_transform(Thread *current_thread) const {
310  CDReader cdata(_cycler, current_thread);
311  return cdata->_transform.p();
312 }
313 
314 /**
315  * Resets the transform on this node to the identity transform.
316  */
317 INLINE void PandaNode::
318 clear_transform(Thread *current_thread) {
319  set_transform(TransformState::make_identity(), current_thread);
320 }
321 
322 /**
323  * Returns the transform that has been set as this node's "previous" position.
324  * See set_prev_transform().
325  */
326 INLINE CPT(TransformState) PandaNode::
327 get_prev_transform(Thread *current_thread) const {
328  CDReader cdata(_cycler, current_thread);
329  return cdata->_prev_transform.p();
330 }
331 
332 /**
333  * Returns true if this node has the _dirty_prev_transform flag set, which
334  * indicates its _prev_transform is different from its _transform value (in
335  * pipeline stage 0). In this case, the node will be visited by
336  * reset_prev_transform().
337  */
338 INLINE bool PandaNode::
339 has_dirty_prev_transform() const {
340  return _dirty_prev_transform;
341 }
342 
343 /**
344  * Retrieves the user-defined value that was previously set on this node for
345  * the particular key, if any. If no value has been previously set, returns
346  * the empty string.
347  */
348 INLINE std::string PandaNode::
349 get_tag(const std::string &key, Thread *current_thread) const {
350  CDReader cdata(_cycler, current_thread);
351  int index = cdata->_tag_data.find(key);
352  if (index >= 0) {
353  return cdata->_tag_data.get_data((size_t)index);
354  } else {
355  return std::string();
356  }
357 }
358 
359 /**
360  * Returns true if a value has been defined on this node for the particular
361  * key (even if that value is the empty string), or false if no value has been
362  * set.
363  */
364 INLINE bool PandaNode::
365 has_tag(const std::string &key, Thread *current_thread) const {
366  CDReader cdata(_cycler, current_thread);
367  return cdata->_tag_data.find(key) >= 0;
368 }
369 
370 /**
371  * Returns the number of tags applied to this node.
372  */
373 INLINE size_t PandaNode::
374 get_num_tags() const {
375  CDReader cdata(_cycler);
376  return cdata->_tag_data.size();
377 }
378 
379 /**
380  * Returns the key of the nth tag applied to this node.
381  */
382 INLINE std::string PandaNode::
383 get_tag_key(size_t i) const {
384  CDReader cdata(_cycler);
385  return cdata->_tag_data.get_key(i);
386 }
387 
388 /**
389  * Returns true if the node has any tags (or any Python tags) at all, false if
390  * it has none.
391  */
392 INLINE bool PandaNode::
393 has_tags() const {
394  CDReader cdata(_cycler);
395  if (!cdata->_tag_data.is_empty()) {
396  return true;
397  }
398 #ifdef HAVE_PYTHON
399  // This is a bit awkward, since it doesn't catch cases where the Python tags
400  // are cleared. Maybe we should make this behavior deprecated, so that
401  // has_tags will not consider the Python tags.
402  if (!_python_tag_data.is_null()) {
403  return true;
404  }
405 #endif // HAVE_PYTHON
406  return false;
407 }
408 
409 /**
410  * Lists all the nodes at and below the current path hierarchically.
411  */
412 INLINE void PandaNode::
413 ls(std::ostream &out, int indent_level) const {
414  r_list_descendants(out, indent_level);
415 }
416 
417 /**
418  * Returns the special bit that, when specifically cleared in the node's
419  * DrawMask, indicates that the node is hidden to all cameras, regardless of
420  * the remaining DrawMask bits.
421  */
422 INLINE DrawMask PandaNode::
423 get_overall_bit() {
424  return _overall_bit;
425 }
426 
427 /**
428  * Returns a DrawMask that is appropriate for rendering to all cameras.
429  */
430 INLINE DrawMask PandaNode::
431 get_all_camera_mask() {
432  return ~_overall_bit;
433 }
434 
435 /**
436  * Returns true if the node has been hidden to all cameras by clearing its
437  * overall bit.
438  */
439 INLINE bool PandaNode::
440 is_overall_hidden() const {
441  CDReader cdata(_cycler);
442  return ((cdata->_draw_show_mask | ~cdata->_draw_control_mask) & _overall_bit).is_zero();
443 }
444 
445 /**
446  * Sets or clears the hidden flag. When the hidden flag is true, the node and
447  * all of its children are invisible to all cameras, regardless of the setting
448  * of any draw masks. Setting the hidden flag to false restores the previous
449  * visibility as established by the draw masks.
450  *
451  * This actually works by twiddling the reserved _overall_bit in the node's
452  * draw mask, which has special meaning.
453  */
454 INLINE void PandaNode::
455 set_overall_hidden(bool hidden) {
456  if (hidden) {
458  } else {
460  }
461 }
462 
463 /**
464  * Returns the set of bits in draw_show_mask that are considered meaningful.
465  * See adjust_draw_mask().
466  */
467 INLINE DrawMask PandaNode::
468 get_draw_control_mask() const {
469  CDReader cdata(_cycler);
470  return cdata->_draw_control_mask;
471 }
472 
473 /**
474  * Returns the hide/show bits of this particular node. See
475  * adjust_draw_mask().
476  */
477 INLINE DrawMask PandaNode::
478 get_draw_show_mask() const {
479  CDReader cdata(_cycler);
480  return cdata->_draw_show_mask;
481 }
482 
483 /**
484  * Returns the "into" collide mask for this node.
485  */
486 INLINE CollideMask PandaNode::
487 get_into_collide_mask() const {
488  CDReader cdata(_cycler);
489  return cdata->_into_collide_mask;
490 }
491 
492 /**
493  * Reverses the effect of a previous call to set_bounds(), and allows the
494  * node's bounding volume to be automatically computed once more based on the
495  * contents of the node.
496  */
497 INLINE void PandaNode::
499  set_bounds(nullptr);
500 }
501 
502 /**
503  * Returns the node's internal bounding volume. This is the bounding volume
504  * around the node alone, without including children. If the user has called
505  * set_bounds(), it will be the specified bounding volume.
506  */
507 INLINE CPT(BoundingVolume) PandaNode::
508 get_internal_bounds(Thread *current_thread) const {
509  return get_internal_bounds(current_thread->get_pipeline_stage(),
510  current_thread);
511 }
512 
513 /**
514  * Returns the total number of vertices that will be rendered by this
515  * particular node alone, not accounting for its children.
516  *
517  * This may not include all vertices for certain dynamic effects.
518  */
519 INLINE int PandaNode::
520 get_internal_vertices(Thread *current_thread) const {
521  return get_internal_vertices(current_thread->get_pipeline_stage(),
522  current_thread);
523 }
524 
525 /**
526  * Returns true if the bounding volume of this node is stale and will be
527  * implicitly recomputed at the next call to get_bounds(), or false if it is
528  * fresh and need not be recomputed.
529  */
530 bool PandaNode::
531 is_bounds_stale() const {
532  CDReader cdata(_cycler);
533  return (cdata->_last_bounds_update != cdata->_next_update);
534 }
535 
536 /**
537  * Sets the "final" flag on this PandaNode. If this is true, than no bounding
538  * volume need be tested below it; a positive intersection with this node's
539  * bounding volume is deemed to be a positive intersection with all geometry
540  * inside.
541  *
542  * This is useful to quickly force a larger bounding volume around a node when
543  * the GeomNodes themselves are inaccurate for some reason, without forcing a
544  * recompute of every nested bounding volume. It's also helpful when the
545  * bounding volume is tricked by some special properties, like billboards,
546  * that may move geometry out of its bounding volume otherwise.
547  */
548 INLINE void PandaNode::
549 set_final(bool flag) {
550  CDWriter cdata(_cycler);
551  cdata->_final_bounds = flag;
553 }
554 
555 /**
556  * Returns the current state of the "final" flag. Initially, this flag is off
557  * (false), but it may be changed by an explicit call to set_final(). See
558  * set_final().
559  */
560 INLINE bool PandaNode::
561 is_final(Thread *current_thread) const {
562  CDReader cdata(_cycler, current_thread);
563  return cdata->_final_bounds;
564 }
565 
566 /**
567  * Returns the union of all of the enum FancyBits values corresponding to the
568  * various "fancy" attributes that are set on the node. If this returns 0,
569  * the node has nothing interesting about it. This is intended to speed
570  * traversal by quickly skipping past nodes that don't particularly affect the
571  * render state.
572  */
573 INLINE int PandaNode::
574 get_fancy_bits(Thread *current_thread) const {
575  CDReader cdata(_cycler, current_thread);
576  return cdata->_fancy_bits;
577 }
578 
579 /**
580  * Returns the node's user bounding volume. This is the bounding volume
581  * specified with get_bounds(). This will return NULL if the user bounding
582  * volume has never been set.
583  */
584 INLINE CPT(BoundingVolume) PandaNode::
585 get_user_bounds(int pipeline_stage, Thread *current_thread) const {
586  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
587  return cdata->_user_bounds;
588 }
589 
590 /**
591  * Indicates that the bounding volume, or something that influences the
592  * bounding volume (or any of the other things stored in CData, like
593  * net_collide_mask), may have changed for this node, and that it must be
594  * recomputed.
595  */
596 INLINE void PandaNode::
597 mark_bounds_stale(int pipeline_stage, Thread *current_thread) const {
598  // We check whether it is already marked stale. If so, we don't have to
599  // make the call to force_bounds_stale().
600  bool is_stale_bounds;
601  {
602  CDStageReader cdata(_cycler, pipeline_stage, current_thread);
603  is_stale_bounds = (cdata->_last_update != cdata->_next_update);
604  }
605  // It's important that we don't hold the lock during the call to
606  // force_bounds_stale().
607  if (!is_stale_bounds) {
608  ((PandaNode *)this)->force_bounds_stale(pipeline_stage, current_thread);
609  }
610 }
611 
612 /**
613  * Should be called by a derived class to mark the internal bounding volume
614  * stale, so that recompute_internal_bounds() will be called when the bounding
615  * volume is next requested.
616  */
617 INLINE void PandaNode::
618 mark_internal_bounds_stale(int pipeline_stage, Thread *current_thread) {
619  {
620  CDStageWriter cdata(_cycler, pipeline_stage, current_thread);
621  ++cdata->_internal_bounds_mark;
622  }
623  mark_bounds_stale(pipeline_stage, current_thread);
624 }
625 
626 /**
627  * Returns an object that can be used to walk through the list of children of
628  * the node. When you intend to visit multiple children, using this is
629  * slightly faster than calling get_child() directly on the PandaNode, since
630  * this object avoids reopening the PipelineCycler each time.
631  *
632  * This object also protects you from self-modifying loops (e.g. adding or
633  * removing children during traversal), since a virtual copy of the children
634  * is made ahead of time. The virtual copy is fast--it is a form of copy-on-
635  * write, so the list is not actually copied unless it is modified during the
636  * traversal.
637  */
639 get_children(Thread *current_thread) const {
640  CDReader cdata(_cycler, current_thread);
641  return Children(cdata);
642 }
643 
644 /**
645  * Returns an object that can be used to walk through the list of children of
646  * the node. When you intend to visit multiple children, using this is
647  * slightly faster than calling get_stashed() directly on the PandaNode, since
648  * this object avoids reopening the PipelineCycler each time.
649  *
650  * This object also protects you from self-modifying loops (e.g. adding or
651  * removing children during traversal), since a virtual copy of the children
652  * is made ahead of time. The virtual copy is fast--it is a form of copy-on-
653  * write, so the list is not actually copied unless it is modified during the
654  * traversal.
655  */
657 get_stashed(Thread *current_thread) const {
658  CDReader cdata(_cycler, current_thread);
659  return Stashed(cdata);
660 }
661 
662 /**
663  * Returns an object that can be used to walk through the list of parents of
664  * the node, similar to get_children() and get_stashed().
665  */
667 get_parents(Thread *current_thread) const {
668  CDReader cdata(_cycler, current_thread);
669  return Parents(cdata);
670 }
671 
672 /**
673  * The private implementation of find_parent().
674  */
675 INLINE int PandaNode::
676 do_find_parent(PandaNode *node, const CData *cdata) const {
677  CPT(Up) up = cdata->get_up();
678  Up::const_iterator ui = up->find(UpConnection(node));
679  if (ui == up->end()) {
680  return -1;
681  }
682  return ui - up->begin();
683 }
684 
685 /**
686  * Ensures that attaching the indicated child node to this node would not
687  * introduce a cycle in the graph. Returns true if the attachment is valid,
688  * false otherwise.
689  */
690 INLINE bool PandaNode::
691 verify_child_no_cycles(PandaNode *child_node) {
692 #ifndef NDEBUG
693  if (detect_graph_cycles) {
694  if (!find_node_above(child_node)) {
695  return true;
696  }
697  report_cycle(child_node);
698  return false;
699  }
700 #endif // NDEBUG
701  return true;
702 }
703 
704 /**
705  * Sets the dirty_prev_transform flag, and adds the node to the
706  * _dirty_prev_transforms chain. Assumes _dirty_prev_transforms._lock is
707  * already held.
708  */
709 INLINE void PandaNode::
710 do_set_dirty_prev_transform() {
711  nassertv(_dirty_prev_transforms._lock.debug_is_locked());
712  if (!_dirty_prev_transform) {
713  LinkedListNode::insert_before(&_dirty_prev_transforms);
714  _dirty_prev_transform = true;
715  }
716 }
717 
718 /**
719  * Clears the dirty_prev_transform flag, and removes the node from the
720  * _dirty_prev_transforms chain. Assumes _dirty_prev_transforms._lock is
721  * already held.
722  */
723 INLINE void PandaNode::
724 do_clear_dirty_prev_transform() {
725  nassertv(_dirty_prev_transforms._lock.debug_is_locked());
726  if (_dirty_prev_transform) {
727  LinkedListNode::remove_from_list();
728  _dirty_prev_transform = false;
729  }
730 }
731 
732 /**
733  *
734  */
735 INLINE PandaNode::DownConnection::
736 DownConnection(PandaNode *child, int sort) :
737  _child(child),
738  _sort(sort)
739 {
740 }
741 
742 /**
743  * Provides a partial ordering on the children of a node so that they are
744  * ranked first in sort order, and then (by virtue of the ordered_vector) in
745  * the order they were added.
746  */
747 INLINE bool PandaNode::DownConnection::
748 operator < (const DownConnection &other) const {
749  return _sort < other._sort;
750 }
751 
752 /**
753  *
754  */
755 INLINE PandaNode *PandaNode::DownConnection::
756 get_child() const {
757  return _child;
758 }
759 
760 /**
761  * This is only called by PandaNode::replace_child().
762  */
763 INLINE void PandaNode::DownConnection::
765  _child = child;
766 }
767 
768 /**
769  *
770  */
771 INLINE int PandaNode::DownConnection::
772 get_sort() const {
773  return _sort;
774 }
775 
776 /**
777  *
778  */
779 INLINE PandaNode::UpConnection::
780 UpConnection(PandaNode *parent) :
781  _parent(parent)
782 {
783 }
784 
785 /**
786  * Sorts the up connections of a node by pointer. This is different from the
787  * down connections of a node, which are sorted by the specified _sort number.
788  * This makes it easy to locate a particular parent of a node by pointer, or
789  * to test for a parent-child relationship given two node pointers.
790  */
791 INLINE bool PandaNode::UpConnection::
792 operator < (const UpConnection &other) const {
793  return _parent < other._parent;
794 }
795 
796 /**
797  *
798  */
799 INLINE PandaNode *PandaNode::UpConnection::
800 get_parent() const {
801  return _parent;
802 }
803 
804 /**
805  *
806  */
807 INLINE PandaNode::BoundsData::
808 BoundsData() :
809  _internal_bounds(nullptr),
810  _internal_vertices(0)
811 {
812  ++_internal_bounds_mark;
813 }
814 
815 /**
816  *
817  */
818 INLINE PandaNode::BoundsData::
819 BoundsData(const PandaNode::BoundsData &copy) :
820  _internal_bounds(copy._internal_bounds),
821  _internal_vertices(copy._internal_vertices),
822  _internal_bounds_mark(copy._internal_bounds_mark),
823  _internal_bounds_computed(copy._internal_bounds_computed)
824 {
825 }
826 
827 /**
828  * Copies just the BoundsData part of the structure.
829  */
830 INLINE void PandaNode::BoundsData::
831 copy_bounds(const PandaNode::BoundsData &copy) {
832  _internal_bounds = copy._internal_bounds;
833  _internal_vertices = copy._internal_vertices;
834  _internal_bounds_mark = copy._internal_bounds_mark;
835  _internal_bounds_computed = copy._internal_bounds_computed;
836 }
837 
838 /**
839  * Internal function to set (if value is true) or clear (if value is false)
840  * the indicated bit(s) in the _fancy_bits member.
841  */
842 INLINE void PandaNode::CData::
843 set_fancy_bit(int bits, bool value) {
844  if (value) {
845  _fancy_bits |= bits;
846  } else {
847  _fancy_bits &= ~bits;
848  }
849 }
850 
851 /**
852  * Returns a read-only pointer to the _down list.
853  */
854 INLINE CPT(PandaNode::Down) PandaNode::CData::
855 get_down() const {
856  return _down.get_read_pointer();
857 }
858 
859 /**
860  * Returns a modifiable, unique pointer to the _down list.
861  */
862 INLINE PT(PandaNode::Down) PandaNode::CData::
863 modify_down() {
864  return _down.get_write_pointer();
865 }
866 
867 /**
868  * Returns a read-only pointer to the _stashed list.
869  */
870 INLINE CPT(PandaNode::Down) PandaNode::CData::
871 get_stashed() const {
872  return _stashed.get_read_pointer();
873 }
874 
875 /**
876  * Returns a modifiable, unique pointer to the _stashed list.
877  */
878 INLINE PT(PandaNode::Down) PandaNode::CData::
879 modify_stashed() {
880  return _stashed.get_write_pointer();
881 }
882 
883 /**
884  * Returns a read-only pointer to the _up list.
885  */
886 INLINE CPT(PandaNode::Up) PandaNode::CData::
887 get_up() const {
888  return _up.get_read_pointer();
889 }
890 
891 /**
892  * Returns a modifiable, unique pointer to the _up list.
893  */
894 INLINE PT(PandaNode::Up) PandaNode::CData::
895 modify_up() {
896  return _up.get_write_pointer();
897 }
898 
899 /**
900  *
901  */
902 INLINE PandaNode::Children::
903 Children() {
904 }
905 
906 /**
907  *
908  */
909 INLINE PandaNode::Children::
910 Children(const PandaNode::CData *cdata) :
911  _down(cdata->get_down())
912 {
913 }
914 
915 /**
916  *
917  */
918 INLINE PandaNode::Children::
919 Children(const PandaNode::Children &copy) :
920  _down(copy._down)
921 {
922 }
923 
924 /**
925  *
926  */
927 INLINE void PandaNode::Children::
928 operator = (const PandaNode::Children &copy) {
929  _down = copy._down;
930 }
931 
932 /**
933  *
934  */
935 INLINE PandaNode::Children::
936 Children(PandaNode::Children &&from) noexcept :
937  _down(std::move(from._down))
938 {
939 }
940 
941 /**
942  *
943  */
944 INLINE void PandaNode::Children::
945 operator = (PandaNode::Children &&from) noexcept {
946  _down = std::move(from._down);
947 }
948 
949 /**
950  * Returns the number of children of the node.
951  */
952 INLINE size_t PandaNode::Children::
954  nassertr(_down != nullptr, 0);
955  return _down->size();
956 }
957 
958 /**
959  * Returns the nth child of the node.
960  */
962 get_child(size_t n) const {
963  nassertr(_down != nullptr, nullptr);
964  nassertr(n < (size_t)_down->size(), nullptr);
965  return (*_down)[n].get_child();
966 }
967 
968 /**
969  * Returns the sort index of the nth child node of this node (that is, the
970  * number that was passed to add_child()). See get_num_children().
971  */
972 INLINE int PandaNode::Children::
973 get_child_sort(size_t n) const {
974  nassertr(_down != nullptr, -1);
975  nassertr(n < _down->size(), -1);
976  return (*_down)[n].get_sort();
977 }
978 
979 /**
980  *
981  */
982 INLINE PandaNode::Stashed::
983 Stashed() {
984 }
985 
986 /**
987  *
988  */
989 INLINE PandaNode::Stashed::
990 Stashed(const PandaNode::CData *cdata) :
991  _stashed(cdata->get_stashed())
992 {
993 }
994 
995 /**
996  *
997  */
998 INLINE PandaNode::Stashed::
999 Stashed(const PandaNode::Stashed &copy) :
1000  _stashed(copy._stashed)
1001 {
1002 }
1003 
1004 /**
1005  *
1006  */
1007 INLINE void PandaNode::Stashed::
1008 operator = (const PandaNode::Stashed &copy) {
1009  _stashed = copy._stashed;
1010 }
1011 
1012 /**
1013  *
1014  */
1015 INLINE PandaNode::Stashed::
1016 Stashed(PandaNode::Stashed &&from) noexcept :
1017  _stashed(std::move(from._stashed))
1018 {
1019 }
1020 
1021 /**
1022  *
1023  */
1024 INLINE void PandaNode::Stashed::
1025 operator = (PandaNode::Stashed &&from) noexcept {
1026  _stashed = std::move(from._stashed);
1027 }
1028 
1029 /**
1030  * Returns the number of stashed children of the node.
1031  */
1032 INLINE size_t PandaNode::Stashed::
1034  nassertr(_stashed != nullptr, 0);
1035  return _stashed->size();
1036 }
1037 
1038 /**
1039  * Returns the nth stashed child of the node.
1040  */
1042 get_stashed(size_t n) const {
1043  nassertr(_stashed != nullptr, nullptr);
1044  nassertr(n < _stashed->size(), nullptr);
1045  return (*_stashed)[n].get_child();
1046 }
1047 
1048 /**
1049  * Returns the sort index of the nth child node of this node (that is, the
1050  * number that was passed to add_child()). See get_num_stashed().
1051  */
1052 INLINE int PandaNode::Stashed::
1053 get_stashed_sort(size_t n) const {
1054  nassertr(_stashed != nullptr, -1);
1055  nassertr(n < _stashed->size(), -1);
1056  return (*_stashed)[n].get_sort();
1057 }
1058 
1059 /**
1060  *
1061  */
1062 INLINE PandaNode::Parents::
1063 Parents() {
1064 }
1065 
1066 /**
1067  *
1068  */
1069 INLINE PandaNode::Parents::
1070 Parents(const PandaNode::CData *cdata) :
1071  _up(cdata->get_up())
1072 {
1073 }
1074 
1075 /**
1076  *
1077  */
1078 INLINE PandaNode::Parents::
1079 Parents(const PandaNode::Parents &copy) :
1080  _up(copy._up)
1081 {
1082 }
1083 
1084 /**
1085  *
1086  */
1087 INLINE void PandaNode::Parents::
1088 operator = (const PandaNode::Parents &copy) {
1089  _up = copy._up;
1090 }
1091 
1092 /**
1093  *
1094  */
1095 INLINE PandaNode::Parents::
1096 Parents(PandaNode::Parents &&from) noexcept :
1097  _up(std::move(from._up))
1098 {
1099 }
1100 
1101 /**
1102  *
1103  */
1104 INLINE void PandaNode::Parents::
1105 operator = (PandaNode::Parents &&from) noexcept {
1106  _up = std::move(from._up);
1107 }
1108 
1109 /**
1110  * Returns the number of parents of the node.
1111  */
1112 INLINE size_t PandaNode::Parents::
1114  nassertr(_up != nullptr, 0);
1115  return _up->size();
1116 }
1117 
1118 /**
1119  * Returns the nth parent of the node.
1120  */
1122 get_parent(size_t n) const {
1123  nassertr(_up != nullptr, nullptr);
1124  nassertr(n < _up->size(), nullptr);
1125  return (*_up)[n].get_parent();
1126 }
1127 
1128 /**
1129  *
1130  */
1131 INLINE PandaNodePipelineReader::
1132 PandaNodePipelineReader(const PandaNode *node, Thread *current_thread) :
1133  _node(node),
1134  _current_thread(current_thread),
1135  _cdata(node->_cycler.read_unlocked(current_thread))
1136 {
1137 #ifdef _DEBUG
1138  nassertv(_node->test_ref_count_nonzero());
1139 #endif // _DEBUG
1140 
1141 #ifdef DO_PIPELINING
1142  // We node_ref the CData pointer, so that if anyone makes changes to the
1143  // PandaNode while we hold this pointer, it will force a copy--so that this
1144  // object will remain unchanged (if out-of-date).
1145  _cdata->node_ref();
1146 #endif // DO_PIPELINING
1147 }
1148 
1149 /**
1150  *
1151  */
1152 INLINE PandaNodePipelineReader::
1153 PandaNodePipelineReader(const PandaNodePipelineReader &copy) :
1154  _node(copy._node),
1155  _current_thread(copy._current_thread),
1156  _cdata(copy._cdata)
1157 {
1158 #ifdef DO_PIPELINING
1159  _cdata->node_ref();
1160 #endif // DO_PIPELINING
1161 
1162  /*
1163  if (_cdata != (PandaNode::CData *)NULL) {
1164  _node->_cycler.increment_read(_cdata);
1165  }
1166  */
1167 }
1168 
1169 /**
1170  *
1171  */
1172 INLINE void PandaNodePipelineReader::
1173 operator = (const PandaNodePipelineReader &copy) {
1174  nassertv(_current_thread == copy._current_thread);
1175 
1176  /*
1177  if (_cdata != (PandaNode::CData *)NULL) {
1178  _node->_cycler.release_read(_cdata);
1179  }
1180  */
1181 
1182 #ifdef DO_PIPELINING
1183  node_unref_delete((CycleData *)_cdata);
1184 #endif // DO_PIPELINING
1185 
1186  _node = copy._node;
1187  _cdata = copy._cdata;
1188 
1189 #ifdef DO_PIPELINING
1190  _cdata->node_ref();
1191 #endif // DO_PIPELINING
1192 
1193  /*
1194  if (_cdata != (PandaNode::CData *)NULL) {
1195  _node->_cycler.increment_read(_cdata);
1196  }
1197  */
1198 }
1199 
1200 /**
1201  *
1202  */
1203 INLINE PandaNodePipelineReader::
1204 ~PandaNodePipelineReader() {
1205  /*
1206  if (_cdata != (PandaNode::CData *)NULL) {
1207  _node->_cycler.release_read(_cdata);
1208  }
1209  */
1210 
1211 #ifdef DO_PIPELINING
1212  node_unref_delete((CycleData *)_cdata);
1213 #endif // DO_PIPELINING
1214 
1215 #ifdef _DEBUG
1216  _node = nullptr;
1217  _cdata = nullptr;
1218 #endif // _DEBUG
1219 }
1220 
1221 /**
1222  *
1223  */
1224 INLINE const PandaNode *PandaNodePipelineReader::
1225 get_node() const {
1226  return _node;
1227 }
1228 
1229 /**
1230  *
1231  */
1232 INLINE Thread *PandaNodePipelineReader::
1233 get_current_thread() const {
1234  return _current_thread;
1235 }
1236 
1237 /**
1238  * Releases the lock on this object. No future calls will be valid on this
1239  * object.
1240  */
1241 INLINE void PandaNodePipelineReader::
1243  /*
1244  if (_cdata != (PandaNode::CData *)NULL) {
1245  _node->_cycler.release_read(_cdata);
1246  _cdata = NULL;
1247  }
1248  */
1249 }
1250 
1251 /**
1252  * Computes the result of applying this node's draw masks to a running draw
1253  * mask, as during a traversal.
1254  */
1255 INLINE void PandaNodePipelineReader::
1256 compose_draw_mask(DrawMask &running_draw_mask) const {
1257  nassertv(_cdata != nullptr);
1258  running_draw_mask = (running_draw_mask & ~_cdata->_draw_control_mask) |
1259  (_cdata->_draw_show_mask & _cdata->_draw_control_mask);
1260 }
1261 
1262 /**
1263  * Compares the running draw mask computed during a traversal with this node's
1264  * net draw masks. Returns true if the node should be traversed into, or
1265  * false if there is nothing at this level or below that will be visible to
1266  * the indicated camera_mask.
1267  */
1268 INLINE bool PandaNodePipelineReader::
1269 compare_draw_mask(DrawMask running_draw_mask, DrawMask camera_mask) const {
1270  nassertr(_cdata != nullptr, false);
1271  nassertr(_cdata->_last_update == _cdata->_next_update, false);
1272 
1273  // As a special case, if net_draw_show_mask is all 0, it means either that
1274  // all nodes under this node are hidden to all cameras, or that none of them
1275  // are renderable nodes (or some combination). In either case, we might as
1276  // well short-circuit.
1277  if (_cdata->_net_draw_show_mask.is_zero()) {
1278  return false;
1279  }
1280 
1281  DrawMask net_draw_control_mask, net_draw_show_mask;
1282  net_draw_control_mask = _cdata->_net_draw_control_mask;
1283  net_draw_show_mask = _cdata->_net_draw_show_mask;
1284 
1285  // Now the bits that are not in net_draw_control_mask--that is, those bits
1286  // that are not changed by any of the nodes at this level and below--are
1287  // taken from running_draw_mask, which is inherited from above. On the
1288  // other hand, the bits that *are* in net_draw_control_mask--those bits that
1289  // are changed by any of the nodes at this level and below--are taken from
1290  // net_draw_show_mask, which is propagated upwards from below.
1291 
1292  // This way, we will traverse into this node if it has any children which
1293  // want to be visited by the traversal, but we will avoid traversing into it
1294  // if all of its children are hidden to this camera.
1295  DrawMask compare_mask = (running_draw_mask & ~net_draw_control_mask) | (net_draw_show_mask & net_draw_control_mask);
1296 
1297  return !((compare_mask & PandaNode::_overall_bit).is_zero()) && !((compare_mask & camera_mask).is_zero());
1298 }
1299 
1300 /**
1301  * Returns the number of parent nodes this node has. If this number is
1302  * greater than 1, the node has been multiply instanced. The order of the
1303  * parent nodes is not meaningful and is not related to the order in which the
1304  * node was instanced to them.
1305  */
1306 INLINE int PandaNodePipelineReader::
1308  return _cdata->get_up()->size();
1309 }
1310 
1311 /**
1312  * Returns the nth parent node of this node. See get_num_parents(). Also see
1313  * get_parents(), if your intention is to iterate through the complete list of
1314  * parents; get_parents() is preferable in this case.
1315  */
1317 get_parent(int n) const {
1318  CPT(PandaNode::Up) up = _cdata->get_up();
1319  nassertr(n >= 0 && n < (int)up->size(), nullptr);
1320  return (*up)[n].get_parent();
1321 }
1322 
1323 /**
1324  * Returns the index of the indicated parent node, if it is a parent, or -1 if
1325  * it is not.
1326  */
1327 INLINE int PandaNodePipelineReader::
1328 find_parent(PandaNode *node) const {
1329  return _node->do_find_parent(node, _cdata);
1330 }
1331 
1332 /**
1333  * Returns the number of child nodes this node has. The order of the child
1334  * nodes *is* meaningful and is based on the sort number that was passed to
1335  * add_child(), and also on the order in which the nodes were added.
1336  */
1337 INLINE int PandaNodePipelineReader::
1339  return _cdata->get_down()->size();
1340 }
1341 
1342 /**
1343  * Returns the nth child node of this node. See get_num_children(). Also see
1344  * get_children(), if your intention is to iterate through the complete list
1345  * of children; get_children() is preferable in this case.
1346  */
1348 get_child(int n) const {
1349  CPT(PandaNode::Down) down = _cdata->get_down();
1350  nassertr(n >= 0 && n < (int)down->size(), nullptr);
1351  return (*down)[n].get_child();
1352 }
1353 
1354 /**
1355  * Returns the sort index of the nth child node of this node (that is, the
1356  * number that was passed to add_child()). See get_num_children().
1357  */
1358 INLINE int PandaNodePipelineReader::
1359 get_child_sort(int n) const {
1360  CPT(PandaNode::Down) down = _cdata->get_down();
1361  nassertr(n >= 0 && n < (int)down->size(), -1);
1362  return (*down)[n].get_sort();
1363 }
1364 
1365 /**
1366  * Returns the index of the indicated child node, if it is a child, or -1 if
1367  * it is not.
1368  */
1369 INLINE int PandaNodePipelineReader::
1370 find_child(PandaNode *node) const {
1371  return _node->do_find_child(node, _cdata->get_down());
1372 }
1373 
1374 /**
1375  * Returns the number of stashed nodes this node has. These are former
1376  * children of the node that have been moved to the special stashed list via
1377  * stash_child().
1378  */
1379 INLINE int PandaNodePipelineReader::
1381  return _cdata->get_stashed()->size();
1382 }
1383 
1384 /**
1385  * Returns the nth stashed child of this node. See get_num_stashed(). Also
1386  * see get_stashed(), if your intention is to iterate through the complete
1387  * list of stashed children; get_stashed() is preferable in this case.
1388  */
1390 get_stashed(int n) const {
1391  CPT(PandaNode::Down) stashed = _cdata->get_stashed();
1392  nassertr(n >= 0 && n < (int)stashed->size(), nullptr);
1393  return (*stashed)[n].get_child();
1394 }
1395 
1396 /**
1397  * Returns the sort index of the nth stashed node of this node (that is, the
1398  * number that was passed to add_child()). See get_num_stashed().
1399  */
1400 INLINE int PandaNodePipelineReader::
1401 get_stashed_sort(int n) const {
1402  CPT(PandaNode::Down) stashed = _cdata->get_stashed();
1403  nassertr(n >= 0 && n < (int)stashed->size(), -1);
1404  return (*stashed)[n].get_sort();
1405 }
1406 
1407 /**
1408  * Returns the index of the indicated stashed node, if it is a stashed child,
1409  * or -1 if it is not.
1410  */
1411 INLINE int PandaNodePipelineReader::
1412 find_stashed(PandaNode *node) const {
1413  return _node->do_find_child(node, _cdata->get_stashed());
1414 }
1415 
1416 /**
1417  * Returns the complete RenderState that will be applied to all nodes at this
1418  * level and below, as set on this node. This returns only the RenderState
1419  * set on this particular node, and has nothing to do with state that might be
1420  * inherited from above.
1421  */
1423 get_state() const {
1424  return _cdata->_state;
1425 }
1426 
1427 /**
1428  * Returns the complete RenderEffects that will be applied to this node.
1429  */
1431 get_effects() const {
1432  return _cdata->_effects;
1433 }
1434 
1435 /**
1436  * Returns the transform that has been set on this particular node. This is
1437  * not the net transform from the root, but simply the transform on this
1438  * particular node.
1439  */
1441 get_transform() const {
1442  return _cdata->_transform;
1443 }
1444 
1445 /**
1446  * Returns the transform that has been set as this node's "previous" position.
1447  * See set_prev_transform().
1448  */
1451  return _cdata->_prev_transform;
1452 }
1453 
1454 /**
1455  * Retrieves the user-defined value that was previously set on this node for
1456  * the particular key, if any. If no value has been previously set, returns
1457  * the empty string.
1458  */
1459 INLINE std::string PandaNodePipelineReader::
1460 get_tag(const std::string &key) const {
1461  int index = _cdata->_tag_data.find(key);
1462  if (index >= 0) {
1463  return _cdata->_tag_data.get_data((size_t)index);
1464  } else {
1465  return std::string();
1466  }
1467 }
1468 
1469 /**
1470  * Returns true if a value has been defined on this node for the particular
1471  * key (even if that value is the empty string), or false if no value has been
1472  * set.
1473  */
1474 INLINE bool PandaNodePipelineReader::
1475 has_tag(const std::string &key) const {
1476  return _cdata->_tag_data.find(key) >= 0;
1477 }
1478 
1479 /**
1480  * Returns the union of all into_collide_mask() values set at CollisionNodes
1481  * at this level and below.
1482  */
1485  nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_net_collide_mask);
1486  return _cdata->_net_collide_mask;
1487 }
1488 
1489 /**
1490  * Returns a ClipPlaneAttrib which represents the union of all of the clip
1491  * planes that have been turned *off* at this level and below.
1492  */
1495  nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_off_clip_planes);
1496  return _cdata->_off_clip_planes;
1497 }
1498 
1499 /**
1500  * Returns the external bounding volume of this node: a bounding volume that
1501  * contains the user bounding volume, the internal bounding volume, and all of
1502  * the children's bounding volumes.
1503  */
1505 get_bounds() const {
1506  nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_external_bounds);
1507  return _cdata->_external_bounds;
1508 }
1509 
1510 /**
1511  * Returns the total number of vertices that will be rendered by this node and
1512  * all of its descendents.
1513  *
1514  * This is not necessarily an accurate count of vertices that will actually be
1515  * rendered, since this will include all vertices of all LOD's, and it will
1516  * also include hidden nodes. It may also omit or only approximate certain
1517  * kinds of dynamic geometry. However, it will not include stashed nodes.
1518  */
1519 INLINE int PandaNodePipelineReader::
1521  nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_nested_vertices);
1522  return _cdata->_nested_vertices;
1523 }
1524 
1525 /**
1526  * Returns the current state of the "final" flag. Initially, this flag is off
1527  * (false), but it may be changed by an explicit call to set_final(). See
1528  * set_final().
1529  */
1530 INLINE bool PandaNodePipelineReader::
1531 is_final() const {
1532  return _cdata->_final_bounds;
1533 }
1534 
1535 
1536 /**
1537  * Returns the union of all of the enum FancyBits values corresponding to the
1538  * various "fancy" attributes that are set on the node. If this returns 0,
1539  * the node has nothing interesting about it. This is intended to speed
1540  * traversal by quickly skipping past nodes that don't particularly affect the
1541  * render state.
1542  */
1543 INLINE int PandaNodePipelineReader::
1545  return _cdata->_fancy_bits;
1546 }
1547 
1548 /**
1549  * Returns an object that can be used to walk through the list of children of
1550  * the node. When you intend to visit multiple children, using this is
1551  * slightly faster than calling get_child() directly on the PandaNode, since
1552  * this object avoids reopening the PipelineCycler each time.
1553  *
1554  * This object also protects you from self-modifying loops (e.g. adding or
1555  * removing children during traversal), since a virtual copy of the children
1556  * is made ahead of time. The virtual copy is fast--it is a form of copy-on-
1557  * write, so the list is not actually copied unless it is modified during the
1558  * traversal.
1559  */
1561 get_children() const {
1562  return PandaNode::Children(_cdata);
1563 }
1564 
1565 /**
1566  * Returns an object that can be used to walk through the list of children of
1567  * the node. When you intend to visit multiple children, using this is
1568  * slightly faster than calling get_stashed() directly on the PandaNode, since
1569  * this object avoids reopening the PipelineCycler each time.
1570  *
1571  * This object also protects you from self-modifying loops (e.g. adding or
1572  * removing children during traversal), since a virtual copy of the children
1573  * is made ahead of time. The virtual copy is fast--it is a form of copy-on-
1574  * write, so the list is not actually copied unless it is modified during the
1575  * traversal.
1576  */
1578 get_stashed() const {
1579  return PandaNode::Stashed(_cdata);
1580 }
1581 
1582 /**
1583  * Returns an object that can be used to walk through the list of parents of
1584  * the node, similar to get_children() and get_stashed().
1585  */
1587 get_parents() const {
1588  return PandaNode::Parents(_cdata);
1589 }
1590 
1591 /**
1592  *
1593  */
1594 INLINE PandaNode::BamReaderAuxDataDown::
1595 BamReaderAuxDataDown() :
1596  _down_list(PandaNode::get_class_type())
1597 {
1598 }
PandaNode::Stashed get_stashed() const
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.I:1578
bool is_final() const
Returns the current state of the "final" flag.
Definition: pandaNode.I:1531
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
PandaNode * get_stashed(size_t n) const
Returns the nth stashed child of the node.
Definition: pandaNode.I:1042
Indicates a coordinate-system transform on vertices.
bool debug_is_locked() const
Returns true if the current thread has locked the LightMutex, false otherwise.
const RenderEffects * get_effects() const
Returns the complete RenderEffects that will be applied to this node.
Definition: pandaNode.I:1431
const TransformState * get_transform() const
Returns the transform that has been set on this particular node.
Definition: pandaNode.I:1441
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
int find_child(PandaNode *node) const
Returns the index of the indicated child node, if it is a child, or -1 if it is not.
Definition: pandaNode.I:1370
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
Definition: pandaNode.h:173
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
int get_child_sort(int 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:1359
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
Definition: pandaNode.cxx:1913
get_num_parents
Returns the number of parent nodes this node has.
Definition: pandaNode.h:118
bool stash_child(PandaNode *child_node, Thread *current_thread=Thread::get_current_thread())
Stashes the indicated child node.
Definition: pandaNode.I:107
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
const RenderState * get_state() const
Returns the complete RenderState that will be applied to all nodes at this level and below,...
Definition: pandaNode.I:1423
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
void compose_draw_mask(DrawMask &running_draw_mask) const
Computes the result of applying this node's draw masks to a running draw mask, as during a traversal.
Definition: pandaNode.I:1256
int get_nested_vertices() const
Returns the total number of vertices that will be rendered by this node and all of its descendents.
Definition: pandaNode.I:1520
bool has_tag(const std::string &key) const
Returns true if a value has been defined on this node for the particular key (even if that value is t...
Definition: pandaNode.I:1475
bool compare_draw_mask(DrawMask running_draw_mask, DrawMask camera_mask) const
Compares the running draw mask computed during a traversal with this node's net draw masks.
Definition: pandaNode.I:1269
const TransformState * get_prev_transform() const
Returns the transform that has been set as this node's "previous" position.
Definition: pandaNode.I:1450
PandaNode * get_parent(int n) const
Returns the nth parent node of this node.
Definition: pandaNode.I:1317
PandaNode::Children get_children() const
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.I:1561
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
static BitMask< uint32_t, nbits > all_off()
Returns a BitMask whose bits are all off.
Definition: bitMask.I:43
PandaNode::Parents get_parents() const
Returns an object that can be used to walk through the list of parents of the node,...
Definition: pandaNode.I:1587
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
int get_stashed_sort(int n) 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:1401
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
Definition: thread.h:105
is_final
Returns the current state of the "final" flag.
Definition: pandaNode.h:314
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
set_overall_hidden
Sets or clears the hidden flag.
Definition: pandaNode.h:248
set_transform
Sets the transform that will be applied to this node and below.
Definition: pandaNode.h:183
bool operator<(const DownConnection &other) const
Provides a partial ordering on the children of a node so that they are ranked first in sort order,...
Definition: pandaNode.I:748
get_parents
Returns an object that can be used to walk through the list of parents of the node,...
Definition: pandaNode.h:786
int find_parent(PandaNode *node) const
Returns the index of the indicated parent node, if it is a parent, or -1 if it is not.
Definition: pandaNode.I:1328
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
CPT(RenderAttrib) PandaNode
Returns the render attribute of the indicated type, if it is defined on the node, or NULL if it is no...
Definition: pandaNode.I:189
int find_stashed(PandaNode *node) const
Returns the index of the indicated stashed node, if it is a stashed child, or -1 if it is not.
Definition: pandaNode.I:1412
get_num_children
Returns the number of child nodes this node has.
Definition: pandaNode.h:124
void release()
Releases the lock on this object.
Definition: pandaNode.I:1242
set_effects
Sets the complete RenderEffects that will be applied this node.
Definition: pandaNode.h:178
int get_slot(TypeHandle type_handle) const
Returns the slot number assigned to the indicated TypeHandle, or 0 if no slot number has been assigne...
int get_fancy_bits(Thread *current_thread=Thread::get_current_thread()) const
Returns the union of all of the enum FancyBits values corresponding to the various "fancy" attributes...
Definition: pandaNode.I:574
const RenderAttrib * get_off_clip_planes() const
Returns a ClipPlaneAttrib which represents the union of all of the clip planes that have been turned ...
Definition: pandaNode.I:1494
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
This class is used to associate each RenderAttrib with a different slot index at runtime,...
void clear_bounds()
Reverses the effect of a previous call to set_bounds(), and allows the node's bounding volume to be a...
Definition: pandaNode.I:498
void set_child(PandaNode *child)
This is only called by PandaNode::replace_child().
Definition: pandaNode.I:764
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
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
int find_child(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated child node, if it is a child, or -1 if it is not.
Definition: pandaNode.I:90
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:784
std::string get_tag(const std::string &key) const
Retrieves the user-defined value that was previously set on this node for the particular key,...
Definition: pandaNode.I:1460
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
const BoundingVolume * get_bounds() const
Returns the external bounding volume of this node: a bounding volume that contains the user bounding ...
Definition: pandaNode.I:1505
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
get_parent
Returns the nth parent node of this node.
Definition: pandaNode.h:118
get_stashed
Returns the nth stashed child of this node.
Definition: pandaNode.h:148
int get_num_children() const
Returns the number of child nodes this node has.
Definition: pandaNode.I:1338
A thread; that is, a lightweight process.
Definition: thread.h:46
int get_num_stashed() const
Returns the number of stashed nodes this node has.
Definition: pandaNode.I:1380
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
size_t get_num_stashed() const
Returns the number of stashed children of the node.
Definition: pandaNode.I:1033
int get_fancy_bits() const
Returns the union of all of the enum FancyBits values corresponding to the various "fancy" attributes...
Definition: pandaNode.I:1544
PandaNode * get_child(int n) const
Returns the nth child node of this node.
Definition: pandaNode.I:1348
get_child
Returns the nth child node of this node.
Definition: pandaNode.h:124
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
CollideMask get_net_collide_mask() const
Returns the union of all into_collide_mask() values set at CollisionNodes at this level and below.
Definition: pandaNode.I:1484
int get_num_parents() const
Returns the number of parent nodes this node has.
Definition: pandaNode.I:1307
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
size_t get_num_parents() const
Returns the number of parents of the node.
Definition: pandaNode.I:1113
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:41
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
static RenderAttribRegistry * quick_get_global_ptr()
Returns the global_ptr without first ensuring it has been initialized.
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...
get_num_stashed
Returns the number of stashed nodes this node has.
Definition: pandaNode.h:148