Panda3D
nodePath.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 nodePath.cxx
10  * @author drose
11  * @date 2002-02-25
12 
13  */
14 
15 #include "nodePath.h"
16 #include "nodePathCollection.h"
17 #include "findApproxPath.h"
18 #include "findApproxLevelEntry.h"
19 #include "internalNameCollection.h"
20 #include "config_pgraph.h"
21 #include "colorAttrib.h"
22 #include "colorScaleAttrib.h"
23 #include "cullBinAttrib.h"
24 #include "textureAttrib.h"
25 #include "texMatrixAttrib.h"
26 #include "texGenAttrib.h"
27 #include "materialAttrib.h"
28 #include "materialCollection.h"
29 #include "lightAttrib.h"
30 #include "clipPlaneAttrib.h"
31 #include "occluderEffect.h"
32 #include "polylightEffect.h"
33 #include "fogAttrib.h"
34 #include "renderModeAttrib.h"
35 #include "cullFaceAttrib.h"
36 #include "alphaTestAttrib.h"
37 #include "depthTestAttrib.h"
38 #include "depthWriteAttrib.h"
39 #include "depthOffsetAttrib.h"
40 #include "shaderAttrib.h"
41 #include "billboardEffect.h"
42 #include "compassEffect.h"
43 #include "showBoundsEffect.h"
44 #include "transparencyAttrib.h"
45 #include "antialiasAttrib.h"
46 #include "audioVolumeAttrib.h"
47 #include "texProjectorEffect.h"
48 #include "scissorEffect.h"
49 #include "texturePool.h"
50 #include "planeNode.h"
51 #include "occluderNode.h"
52 #include "lensNode.h"
53 #include "materialPool.h"
54 #include "look_at.h"
55 #include "plist.h"
56 #include "boundingSphere.h"
57 #include "geomNode.h"
58 #include "sceneGraphReducer.h"
59 #include "textureCollection.h"
60 #include "textureStageCollection.h"
61 #include "globPattern.h"
62 #include "shader.h"
63 #include "shaderInput.h"
64 #include "config_gobj.h"
65 #include "bamFile.h"
67 #include "dcast.h"
68 #include "pStatCollector.h"
69 #include "pStatTimer.h"
70 #include "modelNode.h"
71 #include "bam.h"
72 #include "bamWriter.h"
73 #include "datagramBuffer.h"
74 #include "weakNodePath.h"
75 
76 using std::max;
77 using std::move;
78 using std::ostream;
79 using std::ostringstream;
80 using std::string;
81 
82 // stack seems to overflow on Intel C++ at 7000. If we need more than 7000,
83 // need to increase stack size.
84 int NodePath::_max_search_depth = 7000;
85 TypeHandle NodePath::_type_handle;
86 
87 PStatCollector NodePath::_get_transform_pcollector("*:NodePath:get_transform");
88 PStatCollector NodePath::_verify_complete_pcollector("*:NodePath:verify_complete");
89 
90 /**
91  * Constructs a NodePath with the indicated parent NodePath and child node;
92  * the child node must be a stashed or unstashed child of the parent.
93  */
95 NodePath(const NodePath &parent, PandaNode *child_node,
96  Thread *current_thread) :
97  _error_type(ET_fail)
98 {
99  nassertv(child_node != nullptr);
100  int pipeline_stage = current_thread->get_pipeline_stage();
101 
102  if (parent.is_empty()) {
103  // Special case: constructing a NodePath at the root.
104  _head = PandaNode::get_top_component(child_node, true,
105  pipeline_stage, current_thread);
106 
107  } else {
108  _head = PandaNode::get_component(parent._head, child_node, pipeline_stage,
109  current_thread);
110  }
111  nassertv(_head != nullptr);
112 
113  if (_head != nullptr) {
114  _error_type = ET_ok;
115  }
116  _backup_key = 0;
117 }
118 
119 /**
120  * Returns true if the NodePath is valid (not empty), or false if it contains
121  * no nodes.
122  */
123 NodePath::
124 operator bool () const {
125  return !is_empty();
126 }
127 
128 /**
129  * Returns the number of nodes in the path.
130  */
131 int NodePath::
132 get_num_nodes(Thread *current_thread) const {
133  if (is_empty()) {
134  return 0;
135  }
136  int pipeline_stage = current_thread->get_pipeline_stage();
137  return _head->get_length(pipeline_stage, current_thread);
138 }
139 
140 /**
141  * Returns the nth node of the path, where 0 is the referenced (bottom) node
142  * and get_num_nodes() - 1 is the top node. This requires iterating through
143  * the path.
144  *
145  * Also see node(), which is a convenience function to return the same thing
146  * as get_node(0) (since the bottom node is the most important node in the
147  * NodePath, and is the one most frequently referenced).
148  *
149  * Note that this function returns the same thing as
150  * get_ancestor(index).node().
151  */
153 get_node(int index, Thread *current_thread) const {
154  nassertr(index >= 0 && index < get_num_nodes(), nullptr);
155 
156  int pipeline_stage = current_thread->get_pipeline_stage();
157 
158  NodePathComponent *comp = _head;
159  while (index > 0) {
160  // If this assertion fails, the index was out of range; the component's
161  // length must have been invalid.
162  nassertr(comp != nullptr, nullptr);
163  comp = comp->get_next(pipeline_stage, current_thread);
164  index--;
165  }
166 
167  // If this assertion fails, the index was out of range; the component's
168  // length must have been invalid.
169  nassertr(comp != nullptr, nullptr);
170  return comp->get_node();
171 }
172 
173 /**
174  * Returns the nth ancestor of the path, where 0 is the NodePath itself and
175  * get_num_nodes() - 1 is get_top(). This requires iterating through the path.
176  *
177  * Also see get_node(), which returns the same thing as a PandaNode pointer,
178  * not a NodePath.
179  */
181 get_ancestor(int index, Thread *current_thread) const {
182  nassertr(index >= 0 && index < get_num_nodes(), NodePath::fail());
183 
184  int pipeline_stage = current_thread->get_pipeline_stage();
185 
186  NodePathComponent *comp = _head;
187  while (index > 0) {
188  // If this assertion fails, the index was out of range; the component's
189  // length must have been invalid.
190  nassertr(comp != nullptr, NodePath::fail());
191  comp = comp->get_next(pipeline_stage, current_thread);
192  index--;
193  }
194 
195  // If this assertion fails, the index was out of range; the component's
196  // length must have been invalid.
197  nassertr(comp != nullptr, NodePath::fail());
198 
199  NodePath result;
200  result._head = comp;
201  return result;
202 }
203 
204 /**
205  * Returns a singleton NodePath that represents the top of the path, or empty
206  * NodePath if this path is empty.
207  */
209 get_top(Thread *current_thread) const {
210  if (is_empty()) {
211  return *this;
212  }
213 
214  int pipeline_stage = current_thread->get_pipeline_stage();
215 
216  NodePathComponent *comp = _head;
217  while (!comp->is_top_node(pipeline_stage, current_thread)) {
218  comp = comp->get_next(pipeline_stage, current_thread);
219  nassertr(comp != nullptr, NodePath::fail());
220  }
221 
222  NodePath top;
223  top._head = comp;
224  return top;
225 }
226 
227 
228 /**
229  * Returns the set of all child nodes of the referenced node.
230  */
232 get_children(Thread *current_thread) const {
233  NodePathCollection result;
234  nassertr_always(!is_empty(), result);
235 
236  PandaNode *bottom_node = node();
237 
238  int pipeline_stage = current_thread->get_pipeline_stage();
239 
240  PandaNode::Children cr = bottom_node->get_children();
241  int num_children = cr.get_num_children();
242  for (int i = 0; i < num_children; i++) {
243  NodePath child;
244  child._head = PandaNode::get_component(_head, cr.get_child(i),
245  pipeline_stage, current_thread);
246  result.add_path(child);
247  }
248 
249  return result;
250 }
251 
252 /**
253  * Returns the set of all child nodes of the referenced node that have been
254  * stashed. These children are not normally visible on the node, and do not
255  * appear in the list returned by get_children().
256  */
258 get_stashed_children(Thread *current_thread) const {
259  NodePathCollection result;
260  nassertr_always(!is_empty(), result);
261 
262  PandaNode *bottom_node = node();
263 
264  int pipeline_stage = current_thread->get_pipeline_stage();
265 
266  int num_stashed = bottom_node->get_num_stashed();
267  for (int i = 0; i < num_stashed; i++) {
268  NodePath stashed;
269  stashed._head = PandaNode::get_component(_head, bottom_node->get_stashed(i),
270  pipeline_stage, current_thread);
271  result.add_path(stashed);
272  }
273 
274  return result;
275 }
276 
277 /**
278  * Returns the sort value of the referenced node within its parent; that is,
279  * the sort number passed on the last reparenting operation for this node.
280  * This will control the position of the node within its parent's list of
281  * children.
282  */
283 int NodePath::
284 get_sort(Thread *current_thread) const {
285  if (!has_parent()) {
286  return 0;
287  }
288 
289  int pipeline_stage = current_thread->get_pipeline_stage();
290 
291  PandaNode *parent = _head->get_next(pipeline_stage, current_thread)->get_node();
292  PandaNode *child = node();
293  nassertr(parent != nullptr && child != nullptr, 0);
294  int child_index = parent->find_child(child);
295  if (child_index != -1) {
296  return parent->get_child_sort(child_index);
297  }
298 
299  child_index = parent->find_stashed(child);
300  if (child_index != -1) {
301  return parent->get_stashed_sort(child_index);
302  }
303 
304  nassertr(false, 0);
305  return 0;
306 }
307 
308 /**
309  * Searches for a node below the referenced node that matches the indicated
310  * string. Returns the shortest match found, if any, or an empty NodePath if
311  * no match can be found.
312  */
314 find(const string &path) const {
315  nassertr_always(!is_empty(), fail());
316 
317  NodePathCollection col;
318  find_matches(col, path, 1);
319 
320  if (col.is_empty()) {
321  return NodePath::not_found();
322  }
323 
324  return col.get_path(0);
325 }
326 
327 /**
328  * Searches for the indicated node below this node and returns the shortest
329  * NodePath that connects them.
330  */
332 find_path_to(PandaNode *node) const {
333  nassertr_always(!is_empty(), fail());
334  nassertr(node != nullptr, fail());
335 
336  NodePathCollection col;
337  FindApproxPath approx_path;
338  approx_path.add_match_many(0);
339  approx_path.add_match_pointer(node, 0);
340  find_matches(col, approx_path, 1);
341 
342  if (col.is_empty()) {
343  return NodePath::not_found();
344  }
345 
346  return col.get_path(0);
347 }
348 
349 /**
350  * Returns the complete set of all NodePaths that begin with this NodePath and
351  * can be extended by path. The shortest paths will be listed first.
352  */
354 find_all_matches(const string &path) const {
355  NodePathCollection col;
356  nassertr_always(!is_empty(), col);
357  nassertr(verify_complete(), col);
358  find_matches(col, path, -1);
359  return col;
360 }
361 
362 /**
363  * Returns the set of all NodePaths that extend from this NodePath down to the
364  * indicated node. The shortest paths will be listed first.
365  */
367 find_all_paths_to(PandaNode *node) const {
368  NodePathCollection col;
369  nassertr_always(!is_empty(), col);
370  nassertr(verify_complete(), col);
371  nassertr(node != nullptr, col);
372  FindApproxPath approx_path;
373  approx_path.add_match_many(0);
374  approx_path.add_match_pointer(node, 0);
375  find_matches(col, approx_path, -1);
376  return col;
377 }
378 
379 /**
380  * Removes the referenced node of the NodePath from its current parent and
381  * attaches it to the referenced node of the indicated NodePath.
382  *
383  * If the destination NodePath is empty, this is the same thing as
384  * detach_node().
385  *
386  * If the referenced node is already a child of the indicated NodePath (via
387  * some other instance), this operation fails and leaves the NodePath
388  * detached.
389  */
391 reparent_to(const NodePath &other, int sort, Thread *current_thread) {
392  nassertv(verify_complete());
393  nassertv(other.verify_complete());
394  nassertv_always(!is_empty());
395  nassertv(other._error_type == ET_ok);
396 
397  // Reparenting implicitly resets the delta vector.
399 
400  int pipeline_stage = current_thread->get_pipeline_stage();
401  bool reparented = PandaNode::reparent(other._head, _head, sort, false,
402  pipeline_stage, current_thread);
403  nassertv(reparented);
404 }
405 
406 /**
407  * Similar to reparent_to(), but the node is added to its new parent's stashed
408  * list, so that the result is equivalent to calling reparent_to() immediately
409  * followed by stash().
410  */
412 stash_to(const NodePath &other, int sort, Thread *current_thread) {
413  nassertv(verify_complete());
414  nassertv(other.verify_complete());
415  nassertv_always(!is_empty());
416  nassertv(other._error_type == ET_ok);
417 
418  // Reparenting implicitly resets the delta vector.
420 
421  int pipeline_stage = current_thread->get_pipeline_stage();
422  bool reparented = PandaNode::reparent(other._head, _head, sort, true,
423  pipeline_stage, current_thread);
424  nassertv(reparented);
425 }
426 
427 /**
428  * This functions identically to reparent_to(), except the transform on this
429  * node is also adjusted so that the node remains in the same place in world
430  * coordinates, even if it is reparented into a different coordinate system.
431  */
433 wrt_reparent_to(const NodePath &other, int sort, Thread *current_thread) {
434  nassertv(verify_complete(current_thread));
435  nassertv(other.verify_complete(current_thread));
436  nassertv_always(!is_empty());
437  nassertv(other._error_type == ET_ok);
438 
439  if (get_transform(current_thread) == get_prev_transform(current_thread)) {
440  set_transform(get_transform(other, current_thread), current_thread);
441  node()->reset_prev_transform(current_thread);
442  } else {
443  set_transform(get_transform(other, current_thread), current_thread);
444  set_prev_transform(get_prev_transform(other, current_thread), current_thread);
445  }
446 
447  reparent_to(other, sort, current_thread);
448 }
449 
450 /**
451  * Adds the referenced node of the NodePath as a child of the referenced node
452  * of the indicated other NodePath. Any other parent-child relations of the
453  * node are unchanged; in particular, the node is not removed from its
454  * existing parent, if any.
455  *
456  * If the node already had an existing parent, this method will create a new
457  * instance of the node within the scene graph.
458  *
459  * This does not change the NodePath itself, but does return a new NodePath
460  * that reflects the new instance node.
461  *
462  * If the destination NodePath is empty, this creates a new instance which is
463  * not yet parented to any node. A new instance of this sort cannot easily be
464  * differentiated from other similar instances, but it is nevertheless a
465  * different instance and it will return a different get_id() value.
466  *
467  * If the referenced node is already a child of the indicated NodePath,
468  * returns that already-existing instance, unstashing it first if necessary.
469  */
471 instance_to(const NodePath &other, int sort, Thread *current_thread) const {
472  nassertr(verify_complete(), NodePath::fail());
473  nassertr(other.verify_complete(), NodePath::fail());
474  nassertr_always(!is_empty(), NodePath::fail());
475  nassertr(other._error_type == ET_ok, NodePath::fail());
476 
477  NodePath new_instance;
478 
479  // First, we'll attach to NULL, to guarantee we get a brand new instance.
480  int pipeline_stage = current_thread->get_pipeline_stage();
481  new_instance._head = PandaNode::attach(nullptr, node(), sort, pipeline_stage,
482  current_thread);
483 
484  // Now, we'll reparent the new instance to the target node.
485  bool reparented = PandaNode::reparent(other._head, new_instance._head,
486  sort, false, pipeline_stage,
487  current_thread);
488  if (!reparented) {
489  // Hmm, couldn't reparent. Either making this instance would create a
490  // cycle, or it was already a child of that node. If it was already a
491  // child, return that existing NodePath instead.
492  NodePath orig(other, node(), current_thread);
493  if (!orig.is_empty()) {
494  if (orig.is_stashed()) {
495  orig.unstash();
496  }
497  return orig;
498  }
499 
500  // Nope, it must be a cycle.
501  nassertr(reparented, new_instance);
502  }
503 
504  // instance_to() doesn't reset the velocity delta, unlike most of the other
505  // reparenting operations. The reasoning is that instance_to() is not
506  // necessarily a reparenting operation, since it doesn't change the original
507  // instance.
508 
509  return new_instance;
510 }
511 
512 /**
513  * Behaves like instance_to(), but implicitly creates a new node to instance
514  * the geometry under, and returns a NodePath to that new node. This allows
515  * the programmer to set a unique state and/or transform on this instance.
516  */
518 instance_under_node(const NodePath &other, const string &name, int sort,
519  Thread *current_thread) const {
520  NodePath new_node = other.attach_new_node(name, sort, current_thread);
521  NodePath instance = instance_to(new_node, 0, current_thread);
522  if (instance.is_empty()) {
523  new_node.remove_node(current_thread);
524  return instance;
525  }
526  return new_node;
527 }
528 
529 /**
530  * Functions like instance_to(), except a deep copy is made of the referenced
531  * node and all of its descendents, which is then parented to the indicated
532  * node. A NodePath to the newly created copy is returned.
533  */
535 copy_to(const NodePath &other, int sort, Thread *current_thread) const {
536  nassertr(verify_complete(current_thread), fail());
537  nassertr(other.verify_complete(current_thread), fail());
538  nassertr_always(!is_empty(), fail());
539  nassertr(other._error_type == ET_ok, fail());
540 
541  PandaNode *source_node = node();
542  PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread);
543  nassertr(copy_node != nullptr, fail());
544 
545  copy_node->reset_prev_transform(current_thread);
546 
547  return other.attach_new_node(copy_node, sort, current_thread);
548 }
549 
550 /**
551  * Attaches a new node, with or without existing parents, to the scene graph
552  * below the referenced node of this NodePath. This is the preferred way to
553  * add nodes to the graph.
554  *
555  * If the node was already a child of the parent, this returns a NodePath to
556  * the existing child.
557  *
558  * This does *not* automatically extend the current NodePath to reflect the
559  * attachment; however, a NodePath that does reflect this extension is
560  * returned.
561  */
563 attach_new_node(PandaNode *node, int sort, Thread *current_thread) const {
564  nassertr(verify_complete(current_thread), NodePath::fail());
565  nassertr(_error_type == ET_ok, NodePath::fail());
566  nassertr(node != nullptr, NodePath::fail());
567 
568  NodePath new_path(*this);
569  int pipeline_stage = current_thread->get_pipeline_stage();
570  new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage,
571  current_thread);
572  return new_path;
573 }
574 
575 /**
576  * Disconnects the referenced node from the scene graph. This will also
577  * delete the node if there are no other pointers to it.
578  *
579  * Normally, this should be called only when you are really done with the
580  * node. If you want to remove a node from the scene graph but keep it around
581  * for later, you should probably use detach_node() instead.
582  *
583  * In practice, the only difference between remove_node() and detach_node() is
584  * that remove_node() also resets the NodePath to empty, which will cause the
585  * node to be deleted immediately if there are no other references. On the
586  * other hand, detach_node() leaves the NodePath referencing the node, which
587  * will keep at least one reference to the node for as long as the NodePath
588  * exists.
589  */
591 remove_node(Thread *current_thread) {
592  nassertv(_error_type != ET_not_found);
593 
594  // If we have no parents, remove_node() is just a do-nothing operation; if
595  // we have no nodes, maybe we were already removed. In either case, quietly
596  // do nothing except to ensure the NodePath is clear.
597  if (!is_empty() && !is_singleton(current_thread)) {
598  node()->reset_prev_transform(current_thread);
599  int pipeline_stage = current_thread->get_pipeline_stage();
600  PandaNode::detach(_head, pipeline_stage, current_thread);
601  }
602 
603  if (is_empty() || _head->has_key()) {
604  // Preserve the key we had on the node before we removed it.
605  int key = get_key();
606  (*this) = NodePath::removed();
607  _backup_key = key;
608 
609  } else {
610  // We didn't have a key; just clear the NodePath.
611  (*this) = NodePath::removed();
612  }
613 }
614 
615 /**
616  * Disconnects the referenced node from its parent, but does not immediately
617  * delete it. The NodePath retains a pointer to the node, and becomes a
618  * singleton NodePath.
619  *
620  * This should be called to detach a node from the scene graph, with the
621  * option of reattaching it later to the same parent or to a different parent.
622  *
623  * In practice, the only difference between remove_node() and detach_node() is
624  * that remove_node() also resets the NodePath to empty, which will cause the
625  * node to be deleted immediately if there are no other references. On the
626  * other hand, detach_node() leaves the NodePath referencing the node, which
627  * will keep at least one reference to the node for as long as the NodePath
628  * exists.
629  */
631 detach_node(Thread *current_thread) {
632  nassertv(_error_type != ET_not_found);
633  if (!is_empty() && !is_singleton()) {
635  int pipeline_stage = current_thread->get_pipeline_stage();
636  PandaNode::detach(_head, pipeline_stage, current_thread);
637  }
638 }
639 
640 /**
641  * Lists the hierarchy at and above the referenced node.
642  */
644 reverse_ls(ostream &out, int indent_level) const {
645  if (is_empty()) {
646  out << "(empty)\n";
647  return 0;
648  } else if (has_parent()) {
649  indent_level = get_parent().reverse_ls(out, indent_level);
650  }
651  node()->write(out, indent_level);
652  return indent_level + 2;
653 }
654 
655 /**
656  * Writes a sensible description of the NodePath to the indicated output
657  * stream.
658  */
660 output(ostream &out) const {
661  switch (_error_type) {
662  case ET_not_found:
663  out << "**not found**";
664  return;
665  case ET_removed:
666  out << "**removed**";
667  return;
668  case ET_fail:
669  out << "**error**";
670  return;
671  default:
672  break;
673  }
674 
675  if (_head == nullptr) {
676  out << "(empty)";
677  } else {
678  _head->output(out);
679  }
680 }
681 
682 /**
683  * Returns the complete state object set on this node.
684  */
686 get_state(Thread *current_thread) const {
687  // This method is declared non-inline to avoid a compiler bug in gcc-3.4 and
688  // gcc-4.0.
689  nassertr_always(!is_empty(), RenderState::make_empty());
690  return node()->get_state(current_thread);
691 }
692 
693 /**
694  * Returns the state changes that must be made to transition to the render
695  * state of this node from the render state of the other node.
696  */
698 get_state(const NodePath &other, Thread *current_thread) const {
699  nassertr(_error_type == ET_ok && other._error_type == ET_ok, RenderState::make_empty());
700 
701  if (other.is_empty()) {
702  return get_net_state(current_thread);
703  }
704  if (is_empty()) {
705  return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty());
706  }
707 
708 #if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS))
709  nassertr(verify_complete(current_thread), RenderState::make_empty());
710  nassertr(other.verify_complete(current_thread), RenderState::make_empty());
711 #endif
712 
713  int a_count, b_count;
714  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == nullptr) {
715  if (allow_unrelated_wrt) {
716  pgraph_cat.debug()
717  << *this << " is not related to " << other << "\n";
718  } else {
719  pgraph_cat.error()
720  << *this << " is not related to " << other << "\n";
721  nassert_raise("unrelated nodes");
722  return RenderState::make_empty();
723  }
724  }
725 
726  CPT(RenderState) a_state = r_get_partial_state(_head, a_count, current_thread);
727  CPT(RenderState) b_state = r_get_partial_state(other._head, b_count, current_thread);
728  return b_state->invert_compose(a_state);
729 }
730 
731 /**
732  * Sets the state object on this node, relative to the other node. This
733  * computes a new state object that will have the indicated value when seen
734  * from the other node.
735  */
736 void NodePath::
737 set_state(const NodePath &other, const RenderState *state,
738  Thread *current_thread) {
739  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
740  nassertv_always(!is_empty());
741 
742  // First, we perform a wrt to the parent, to get the conversion.
743  CPT(RenderState) rel_state;
744  if (has_parent()) {
745  rel_state = other.get_state(get_parent(current_thread), current_thread);
746  } else {
747  rel_state = other.get_state(NodePath(), current_thread);
748  }
749 
750  CPT(RenderState) new_state = rel_state->compose(state);
751  set_state(new_state, current_thread);
752 }
753 
754 /**
755  * Returns the complete transform object set on this node.
756  */
758 get_transform(Thread *current_thread) const {
759  // This method is declared non-inline to avoid a compiler bug in gcc-3.4 and
760  // gcc-4.0.
761  nassertr_always(!is_empty(), TransformState::make_identity());
762  return node()->get_transform(current_thread);
763 }
764 
765 /**
766  * Returns the relative transform to this node from the other node; i.e. the
767  * transformation of this node as seen from the other node.
768  */
770 get_transform(const NodePath &other, Thread *current_thread) const {
771  nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
772  PStatTimer timer(_get_transform_pcollector);
773 
774  if (other.is_empty()) {
775  return get_net_transform(current_thread);
776  }
777  if (is_empty()) {
778  return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity());
779  }
780 
781 #if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS))
782  nassertr(verify_complete(current_thread), TransformState::make_identity());
783  nassertr(other.verify_complete(current_thread), TransformState::make_identity());
784 #endif
785 
786  int a_count, b_count;
787  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == nullptr) {
788  if (allow_unrelated_wrt) {
789  if (pgraph_cat.is_debug()) {
790  pgraph_cat.debug()
791  << *this << " is not related to " << other << "\n";
792  }
793  } else {
794  pgraph_cat.error()
795  << *this << " is not related to " << other << "\n";
796  nassert_raise("unrelated nodes");
797  return TransformState::make_identity();
798  }
799  }
800 
801  CPT(TransformState) a_transform, b_transform;
802 
803  a_transform = r_get_partial_transform(_head, a_count, current_thread);
804  if (a_transform != nullptr) {
805  b_transform = r_get_partial_transform(other._head, b_count, current_thread);
806  }
807  if (b_transform == nullptr) {
808  // If either path involved a node with a net_transform RenderEffect
809  // applied, we have to go all the way up to the root to get the right
810  // answer.
811  a_transform = r_get_net_transform(_head, current_thread);
812  b_transform = r_get_net_transform(other._head, current_thread);
813  }
814 
815  return b_transform->invert_compose(a_transform);
816 }
817 
818 /**
819  * Sets the transform object on this node, relative to the other node. This
820  * computes a new transform object that will have the indicated value when
821  * seen from the other node.
822  */
823 void NodePath::
824 set_transform(const NodePath &other, const TransformState *transform,
825  Thread *current_thread) {
826  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
827  nassertv_always(!is_empty());
828 
829  // First, we perform a wrt to the parent, to get the conversion.
830  CPT(TransformState) rel_trans;
831  if (has_parent()) {
832  rel_trans = other.get_transform(get_parent(current_thread), current_thread);
833  } else {
834  rel_trans = other.get_transform(NodePath(), current_thread);
835  }
836 
837  CPT(TransformState) new_trans = rel_trans->compose(transform);
838  set_transform(new_trans, current_thread);
839 }
840 
841 /**
842  * Returns the transform that has been set as this node's "previous" position.
843  * See set_prev_transform().
844  */
846 get_prev_transform(Thread *current_thread) const {
847  // This method is declared non-inline to avoid a compiler bug in gcc-3.4 and
848  // gcc-4.0.
849  nassertr_always(!is_empty(), TransformState::make_identity());
850  return node()->get_prev_transform(current_thread);
851 }
852 
853 /**
854  * Returns the relative "previous" transform to this node from the other node;
855  * i.e. the position of this node in the previous frame, as seen by the other
856  * node in the previous frame.
857  */
859 get_prev_transform(const NodePath &other, Thread *current_thread) const {
860  nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
861 
862  if (other.is_empty()) {
863  return get_net_prev_transform(current_thread);
864  }
865  if (is_empty()) {
866  return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity());
867  }
868 
869 #if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS))
870  nassertr(verify_complete(current_thread), TransformState::make_identity());
871  nassertr(other.verify_complete(current_thread), TransformState::make_identity());
872 #endif
873 
874  int a_count, b_count;
875  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == nullptr) {
876  if (allow_unrelated_wrt) {
877  pgraph_cat.debug()
878  << *this << " is not related to " << other << "\n";
879  } else {
880  pgraph_cat.error()
881  << *this << " is not related to " << other << "\n";
882  nassert_raise("unrelated nodes");
883  return TransformState::make_identity();
884  }
885  }
886 
887  CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count, current_thread);
888  CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count, current_thread);
889  return b_prev_transform->invert_compose(a_prev_transform);
890 }
891 
892 /**
893  * Sets the "previous" transform object on this node, relative to the other
894  * node. This computes a new transform object that will have the indicated
895  * value when seen from the other node.
896  */
897 void NodePath::
898 set_prev_transform(const NodePath &other, const TransformState *transform,
899  Thread *current_thread) {
900  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
901  nassertv_always(!is_empty());
902 
903  // First, we perform a wrt to the parent, to get the conversion.
904  CPT(TransformState) rel_trans;
905  if (has_parent(current_thread)) {
906  rel_trans = other.get_prev_transform(get_parent(current_thread), current_thread);
907  } else {
908  rel_trans = other.get_prev_transform(NodePath(), current_thread);
909  }
910 
911  CPT(TransformState) new_trans = rel_trans->compose(transform);
912  set_prev_transform(new_trans, current_thread);
913 }
914 
915 /**
916  * Sets the translation component of the transform, leaving rotation and scale
917  * untouched. This also resets the node's "previous" position, so that the
918  * collision system will see the node as having suddenly appeared in the new
919  * position, without passing any points in between. See Also:
920  * NodePath::set_fluid_pos
921  */
922 void NodePath::
923 set_pos(const LVecBase3 &pos) {
924  nassertv_always(!is_empty());
925  set_transform(get_transform()->set_pos(pos));
927 }
928 
929 void NodePath::
930 set_x(PN_stdfloat x) {
931  nassertv_always(!is_empty());
932  LPoint3 pos = get_pos();
933  pos[0] = x;
934  set_pos(pos);
935 }
936 
937 void NodePath::
938 set_y(PN_stdfloat y) {
939  nassertv_always(!is_empty());
940  LPoint3 pos = get_pos();
941  pos[1] = y;
942  set_pos(pos);
943 }
944 
945 void NodePath::
946 set_z(PN_stdfloat z) {
947  nassertv_always(!is_empty());
948  LPoint3 pos = get_pos();
949  pos[2] = z;
950  set_pos(pos);
951 }
952 
953 /**
954  * Sets the translation component, without changing the "previous" position,
955  * so that the collision system will see the node as moving fluidly from its
956  * previous position to its new position. See Also: NodePath::set_pos
957  */
959 set_fluid_pos(const LVecBase3 &pos) {
960  nassertv_always(!is_empty());
961  set_transform(get_transform()->set_pos(pos));
962 }
963 
964 void NodePath::
965 set_fluid_x(PN_stdfloat x) {
966  nassertv_always(!is_empty());
967  LPoint3 pos = get_pos();
968  pos[0] = x;
969  set_fluid_pos(pos);
970 }
971 
972 void NodePath::
973 set_fluid_y(PN_stdfloat y) {
974  nassertv_always(!is_empty());
975  LPoint3 pos = get_pos();
976  pos[1] = y;
977  set_fluid_pos(pos);
978 }
979 
980 void NodePath::
981 set_fluid_z(PN_stdfloat z) {
982  nassertv_always(!is_empty());
983  LPoint3 pos = get_pos();
984  pos[2] = z;
985  set_fluid_pos(pos);
986 }
987 
988 /**
989  * Retrieves the translation component of the transform.
990  */
991 LPoint3 NodePath::
992 get_pos() const {
993  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
994  return get_transform()->get_pos();
995 }
996 
997 /**
998  * Returns the delta vector from this node's position in the previous frame
999  * (according to set_prev_transform(), typically set via the use of
1000  * set_fluid_pos()) and its position in the current frame. This is the vector
1001  * used to determine collisions. Generally, if the node was last repositioned
1002  * via set_pos(), the delta will be zero; if it was adjusted via
1003  * set_fluid_pos(), the delta will represent the change from the previous
1004  * frame's position.
1005  */
1006 LVector3 NodePath::
1007 get_pos_delta() const {
1008  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
1009  return get_transform()->get_pos() - get_prev_transform()->get_pos();
1010 }
1011 
1012 /**
1013  * Sets the rotation component of the transform, leaving translation and scale
1014  * untouched.
1015  */
1017 set_hpr(const LVecBase3 &hpr) {
1018  nassertv_always(!is_empty());
1019  CPT(TransformState) transform = get_transform();
1020  nassertv(transform->has_hpr());
1021  set_transform(transform->set_hpr(hpr));
1022 }
1023 
1024 void NodePath::
1025 set_h(PN_stdfloat h) {
1026  nassertv_always(!is_empty());
1027  CPT(TransformState) transform = get_transform();
1028  nassertv(transform->has_hpr());
1029  LVecBase3 hpr = transform->get_hpr();
1030  hpr[0] = h;
1031  set_transform(transform->set_hpr(hpr));
1032 }
1033 
1034 void NodePath::
1035 set_p(PN_stdfloat p) {
1036  nassertv_always(!is_empty());
1037  CPT(TransformState) transform = get_transform();
1038  nassertv(transform->has_hpr());
1039  LVecBase3 hpr = transform->get_hpr();
1040  hpr[1] = p;
1041  set_transform(transform->set_hpr(hpr));
1042 }
1043 
1044 void NodePath::
1045 set_r(PN_stdfloat r) {
1046  nassertv_always(!is_empty());
1047  CPT(TransformState) transform = get_transform();
1048  nassertv(transform->has_hpr());
1049  LVecBase3 hpr = transform->get_hpr();
1050  hpr[2] = r;
1051  set_transform(transform->set_hpr(hpr));
1052 }
1053 
1054 /**
1055  * Retrieves the rotation component of the transform.
1056  */
1057 LVecBase3 NodePath::
1058 get_hpr() const {
1059  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1060  CPT(TransformState) transform = get_transform();
1061  nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f));
1062  return transform->get_hpr();
1063 }
1064 
1065 /**
1066  * Sets the rotation component of the transform, leaving translation and scale
1067  * untouched.
1068  */
1070 set_quat(const LQuaternion &quat) {
1071  nassertv_always(!is_empty());
1072  CPT(TransformState) transform = get_transform();
1073  set_transform(transform->set_quat(quat));
1074 }
1075 
1076 /**
1077  * Retrieves the rotation component of the transform.
1078  */
1079 LQuaternion NodePath::
1080 get_quat() const {
1081  nassertr_always(!is_empty(), LQuaternion::ident_quat());
1082  CPT(TransformState) transform = get_transform();
1083  return transform->get_quat();
1084 }
1085 
1086 /**
1087  * Sets the scale component of the transform, leaving translation and rotation
1088  * untouched.
1089  */
1091 set_scale(const LVecBase3 &scale) {
1092  nassertv_always(!is_empty());
1093  CPT(TransformState) transform = get_transform();
1094  set_transform(transform->set_scale(scale));
1095 }
1096 
1097 void NodePath::
1098 set_sx(PN_stdfloat sx) {
1099  nassertv_always(!is_empty());
1100  CPT(TransformState) transform = get_transform();
1101  LVecBase3 scale = transform->get_scale();
1102  scale[0] = sx;
1103  set_transform(transform->set_scale(scale));
1104 }
1105 
1106 void NodePath::
1107 set_sy(PN_stdfloat sy) {
1108  nassertv_always(!is_empty());
1109  CPT(TransformState) transform = get_transform();
1110  LVecBase3 scale = transform->get_scale();
1111  scale[1] = sy;
1112  set_transform(transform->set_scale(scale));
1113 }
1114 
1115 void NodePath::
1116 set_sz(PN_stdfloat sz) {
1117  nassertv_always(!is_empty());
1118  CPT(TransformState) transform = get_transform();
1119  LVecBase3 scale = transform->get_scale();
1120  scale[2] = sz;
1121  set_transform(transform->set_scale(scale));
1122 }
1123 
1124 /**
1125  * Retrieves the scale component of the transform.
1126  */
1127 LVecBase3 NodePath::
1128 get_scale() const {
1129  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1130  CPT(TransformState) transform = get_transform();
1131  return transform->get_scale();
1132 }
1133 
1134 /**
1135  * Sets the shear component of the transform, leaving translation and rotation
1136  * untouched.
1137  */
1139 set_shear(const LVecBase3 &shear) {
1140  nassertv_always(!is_empty());
1141  CPT(TransformState) transform = get_transform();
1142  set_transform(transform->set_shear(shear));
1143 }
1144 
1145 void NodePath::
1146 set_shxy(PN_stdfloat shxy) {
1147  nassertv_always(!is_empty());
1148  CPT(TransformState) transform = get_transform();
1149  LVecBase3 shear = transform->get_shear();
1150  shear[0] = shxy;
1151  set_transform(transform->set_shear(shear));
1152 }
1153 
1154 void NodePath::
1155 set_shxz(PN_stdfloat shxz) {
1156  nassertv_always(!is_empty());
1157  CPT(TransformState) transform = get_transform();
1158  LVecBase3 shear = transform->get_shear();
1159  shear[1] = shxz;
1160  set_transform(transform->set_shear(shear));
1161 }
1162 
1163 void NodePath::
1164 set_shyz(PN_stdfloat shyz) {
1165  nassertv_always(!is_empty());
1166  CPT(TransformState) transform = get_transform();
1167  LVecBase3 shear = transform->get_shear();
1168  shear[2] = shyz;
1169  set_transform(transform->set_shear(shear));
1170 }
1171 
1172 /**
1173  * Retrieves the shear component of the transform.
1174  */
1175 LVecBase3 NodePath::
1176 get_shear() const {
1177  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1178  CPT(TransformState) transform = get_transform();
1179  return transform->get_shear();
1180 }
1181 
1182 /**
1183  * Sets the translation and rotation component of the transform, leaving scale
1184  * untouched.
1185  */
1187 set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr) {
1188  nassertv_always(!is_empty());
1189  CPT(TransformState) transform = get_transform();
1190  transform = TransformState::make_pos_hpr_scale_shear
1191  (pos, hpr, transform->get_scale(), transform->get_shear());
1192  set_transform(transform);
1194 }
1195 
1196 /**
1197  * Sets the translation and rotation component of the transform, leaving scale
1198  * untouched.
1199  */
1201 set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat) {
1202  nassertv_always(!is_empty());
1203  CPT(TransformState) transform = get_transform();
1204  transform = TransformState::make_pos_quat_scale_shear
1205  (pos, quat, transform->get_scale(), transform->get_shear());
1206  set_transform(transform);
1208 }
1209 
1210 /**
1211  * Sets the rotation and scale components of the transform, leaving
1212  * translation untouched.
1213  */
1215 set_hpr_scale(const LVecBase3 &hpr, const LVecBase3 &scale) {
1216  nassertv_always(!is_empty());
1217  CPT(TransformState) transform = get_transform();
1218  transform = TransformState::make_pos_hpr_scale_shear
1219  (transform->get_pos(), hpr, scale, transform->get_shear());
1220  set_transform(transform);
1221 }
1222 
1223 /**
1224  * Sets the rotation and scale components of the transform, leaving
1225  * translation untouched.
1226  */
1228 set_quat_scale(const LQuaternion &quat, const LVecBase3 &scale) {
1229  nassertv_always(!is_empty());
1230  CPT(TransformState) transform = get_transform();
1231  transform = TransformState::make_pos_quat_scale_shear
1232  (transform->get_pos(), quat, scale, transform->get_shear());
1233  set_transform(transform);
1234 }
1235 
1236 /**
1237  * Replaces the translation, rotation, and scale components, implicitly
1238  * setting shear to 0.
1239  */
1241 set_pos_hpr_scale(const LVecBase3 &pos, const LVecBase3 &hpr,
1242  const LVecBase3 &scale) {
1243  nassertv_always(!is_empty());
1244  set_transform(TransformState::make_pos_hpr_scale
1245  (pos, hpr, scale));
1247 }
1248 
1249 /**
1250  * Replaces the translation, rotation, and scale components, implicitly
1251  * setting shear to 0.
1252  */
1254 set_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat,
1255  const LVecBase3 &scale) {
1256  nassertv_always(!is_empty());
1257  set_transform(TransformState::make_pos_quat_scale
1258  (pos, quat, scale));
1260 }
1261 
1262 /**
1263  * Completely replaces the transform with new translation, rotation, scale,
1264  * and shear components.
1265  */
1267 set_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr,
1268  const LVecBase3 &scale, const LVecBase3 &shear) {
1269  nassertv_always(!is_empty());
1270  set_transform(TransformState::make_pos_hpr_scale_shear
1271  (pos, hpr, scale, shear));
1273 }
1274 
1275 /**
1276  * Completely replaces the transform with new translation, rotation, scale,
1277  * and shear components.
1278  */
1280 set_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat,
1281  const LVecBase3 &scale, const LVecBase3 &shear) {
1282  nassertv_always(!is_empty());
1283  set_transform(TransformState::make_pos_quat_scale_shear
1284  (pos, quat, scale, shear));
1286 }
1287 
1288 /**
1289  * Directly sets an arbitrary 4x4 transform matrix.
1290  */
1292 set_mat(const LMatrix4 &mat) {
1293  nassertv_always(!is_empty());
1294  set_transform(TransformState::make_mat(mat));
1296 }
1297 
1298 /**
1299  * Sets the hpr on this NodePath so that it rotates to face the indicated
1300  * point in space.
1301  */
1303 look_at(const LPoint3 &point, const LVector3 &up) {
1304  nassertv_always(!is_empty());
1305 
1306  LPoint3 pos = get_pos();
1307 
1308  LQuaternion quat;
1309  ::look_at(quat, point - pos, up);
1310  set_quat(quat);
1311 }
1312 
1313 /**
1314  * Behaves like look_at(), but with a strong preference to keeping the up
1315  * vector oriented in the indicated "up" direction.
1316  */
1318 heads_up(const LPoint3 &point, const LVector3 &up) {
1319  nassertv_always(!is_empty());
1320 
1321  LPoint3 pos = get_pos();
1322 
1323  LQuaternion quat;
1324  ::heads_up(quat, point - pos, up);
1325  set_quat(quat);
1326 }
1327 
1328 /**
1329  * Sets the translation component of the transform, relative to the other
1330  * node.
1331  */
1332 void NodePath::
1333 set_pos(const NodePath &other, const LVecBase3 &pos) {
1334  nassertv_always(!is_empty());
1335  CPT(TransformState) rel_transform = get_transform(other);
1336 
1337  CPT(TransformState) orig_transform = get_transform();
1338  if (orig_transform->has_components()) {
1339  // If we had a componentwise transform before we started, we should be
1340  // careful to preserve the other three components. We wouldn't need to do
1341  // this, except for the possibility of numerical error or decompose
1342  // ambiguity.
1343  const LVecBase3 &orig_hpr = orig_transform->get_hpr();
1344  const LVecBase3 &orig_scale = orig_transform->get_scale();
1345  const LVecBase3 &orig_shear = orig_transform->get_shear();
1346 
1347  set_transform(other, rel_transform->set_pos(pos));
1348  set_pos_hpr_scale_shear(get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear);
1349 
1350  } else {
1351  // If we didn't have a componentwise transform already, never mind.
1352  set_transform(other, rel_transform->set_pos(pos));
1353  }
1355 }
1356 
1357 void NodePath::
1358 set_x(const NodePath &other, PN_stdfloat x) {
1359  nassertv_always(!is_empty());
1360  LPoint3 pos = get_pos(other);
1361  pos[0] = x;
1362  set_pos(other, pos);
1363 }
1364 
1365 void NodePath::
1366 set_y(const NodePath &other, PN_stdfloat y) {
1367  nassertv_always(!is_empty());
1368  LPoint3 pos = get_pos(other);
1369  pos[1] = y;
1370  set_pos(other, pos);
1371 }
1372 
1373 void NodePath::
1374 set_z(const NodePath &other, PN_stdfloat z) {
1375  nassertv_always(!is_empty());
1376  LPoint3 pos = get_pos(other);
1377  pos[2] = z;
1378  set_pos(other, pos);
1379 }
1380 
1381 /**
1382  * Sets the translation component of the transform, relative to the other
1383  * node.
1384  */
1386 set_fluid_pos(const NodePath &other, const LVecBase3 &pos) {
1387  nassertv_always(!is_empty());
1388  CPT(TransformState) rel_transform = get_transform(other);
1389 
1390  CPT(TransformState) orig_transform = get_transform();
1391  if (orig_transform->has_components()) {
1392  // If we had a componentwise transform before we started, we should be
1393  // careful to preserve the other three components. We wouldn't need to do
1394  // this, except for the possibility of numerical error or decompose
1395  // ambiguity.
1396  const LVecBase3 &orig_hpr = orig_transform->get_hpr();
1397  const LVecBase3 &orig_scale = orig_transform->get_scale();
1398  const LVecBase3 &orig_shear = orig_transform->get_shear();
1399 
1400  // Use the relative set_transform() to compute the relative pos, and then
1401  // reset all of the other components back to the way they were.
1402  set_transform(other, rel_transform->set_pos(pos));
1403  set_transform(TransformState::make_pos_hpr_scale_shear
1404  (get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear));
1405 
1406  } else {
1407  // If we didn't have a componentwise transform already, never mind.
1408  set_transform(other, rel_transform->set_pos(pos));
1409  }
1410 }
1411 
1412 void NodePath::
1413 set_fluid_x(const NodePath &other, PN_stdfloat x) {
1414  nassertv_always(!is_empty());
1415  LPoint3 pos = get_pos(other);
1416  pos[0] = x;
1417  set_fluid_pos(other, pos);
1418 }
1419 
1420 void NodePath::
1421 set_fluid_y(const NodePath &other, PN_stdfloat y) {
1422  nassertv_always(!is_empty());
1423  LPoint3 pos = get_pos(other);
1424  pos[1] = y;
1425  set_fluid_pos(other, pos);
1426 }
1427 
1428 void NodePath::
1429 set_fluid_z(const NodePath &other, PN_stdfloat z) {
1430  nassertv_always(!is_empty());
1431  LPoint3 pos = get_pos(other);
1432  pos[2] = z;
1433  set_fluid_pos(other, pos);
1434 }
1435 
1436 /**
1437  * Returns the relative position of the referenced node as seen from the other
1438  * node.
1439  */
1440 LPoint3 NodePath::
1441 get_pos(const NodePath &other) const {
1442  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
1443  return get_transform(other)->get_pos();
1444 }
1445 
1446 /**
1447  * Returns the delta vector from this node's position in the previous frame
1448  * (according to set_prev_transform(), typically set via the use of
1449  * set_fluid_pos()) and its position in the current frame, as seen in the
1450  * indicated node's coordinate space. This is the vector used to determine
1451  * collisions. Generally, if the node was last repositioned via set_pos(),
1452  * the delta will be zero; if it was adjusted via set_fluid_pos(), the delta
1453  * will represent the change from the previous frame's position.
1454  */
1455 LVector3 NodePath::
1456 get_pos_delta(const NodePath &other) const {
1457  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
1458  return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos();
1459 }
1460 
1461 /**
1462  * Sets the rotation component of the transform, relative to the other node.
1463  */
1465 set_hpr(const NodePath &other, const LVecBase3 &hpr) {
1466  nassertv_always(!is_empty());
1467  CPT(TransformState) rel_transform = get_transform(other);
1468  nassertv(rel_transform->has_hpr());
1469 
1470  CPT(TransformState) transform = get_transform();
1471  if (transform->has_components()) {
1472  // If we had a componentwise transform before we started, we should be
1473  // careful to preserve the other three components. We wouldn't need to do
1474  // this, except for the possibility of numerical error or decompose
1475  // ambiguity.
1476  const LVecBase3 &orig_pos = transform->get_pos();
1477  const LVecBase3 &orig_scale = transform->get_scale();
1478  const LVecBase3 &orig_shear = transform->get_shear();
1479 
1480  set_transform(other, rel_transform->set_hpr(hpr));
1481  transform = get_transform();
1482  if (transform->has_components()) {
1483  set_transform(TransformState::make_pos_hpr_scale_shear
1484  (orig_pos, transform->get_hpr(), orig_scale, orig_shear));
1485  }
1486 
1487  } else {
1488  // If we didn't have a componentwise transform already, never mind.
1489  set_transform(other, rel_transform->set_hpr(hpr));
1490  }
1491 }
1492 
1493 void NodePath::
1494 set_h(const NodePath &other, PN_stdfloat h) {
1495  nassertv_always(!is_empty());
1496  LVecBase3 hpr = get_hpr(other);
1497  hpr[0] = h;
1498  set_hpr(other, hpr);
1499 }
1500 
1501 void NodePath::
1502 set_p(const NodePath &other, PN_stdfloat p) {
1503  nassertv_always(!is_empty());
1504  LVecBase3 hpr = get_hpr(other);
1505  hpr[1] = p;
1506  set_hpr(other, hpr);
1507 }
1508 
1509 void NodePath::
1510 set_r(const NodePath &other, PN_stdfloat r) {
1511  nassertv_always(!is_empty());
1512  LVecBase3 hpr = get_hpr(other);
1513  hpr[2] = r;
1514  set_hpr(other, hpr);
1515 }
1516 
1517 /**
1518  * Returns the relative orientation of the bottom node as seen from the other
1519  * node.
1520  */
1521 LVecBase3 NodePath::
1522 get_hpr(const NodePath &other) const {
1523  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1524  CPT(TransformState) transform = get_transform(other);
1525  nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f));
1526  return transform->get_hpr();
1527 }
1528 
1529 /**
1530  * Sets the rotation component of the transform, relative to the other node.
1531  */
1533 set_quat(const NodePath &other, const LQuaternion &quat) {
1534  nassertv_always(!is_empty());
1535  CPT(TransformState) rel_transform = get_transform(other);
1536 
1537  CPT(TransformState) transform = get_transform();
1538  if (transform->has_components()) {
1539  // If we had a componentwise transform before we started, we should be
1540  // careful to preserve the other three components. We wouldn't need to do
1541  // this, except for the possibility of numerical error or decompose
1542  // ambiguity.
1543  const LVecBase3 &orig_pos = transform->get_pos();
1544  const LVecBase3 &orig_scale = transform->get_scale();
1545  const LVecBase3 &orig_shear = transform->get_shear();
1546 
1547  set_transform(other, rel_transform->set_quat(quat));
1548  transform = get_transform();
1549  if (transform->has_components()) {
1550  set_transform(TransformState::make_pos_quat_scale_shear
1551  (orig_pos, transform->get_quat(), orig_scale, orig_shear));
1552  }
1553 
1554  } else {
1555  // If we didn't have a componentwise transform already, never mind.
1556  set_transform(other, rel_transform->set_quat(quat));
1557  }
1558 }
1559 
1560 /**
1561  * Returns the relative orientation of the bottom node as seen from the other
1562  * node.
1563  */
1564 LQuaternion NodePath::
1565 get_quat(const NodePath &other) const {
1566  nassertr_always(!is_empty(), LQuaternion::ident_quat());
1567  CPT(TransformState) transform = get_transform(other);
1568  return transform->get_quat();
1569 }
1570 
1571 /**
1572  * Sets the scale component of the transform, relative to the other node.
1573  */
1575 set_scale(const NodePath &other, const LVecBase3 &scale) {
1576  nassertv_always(!is_empty());
1577  CPT(TransformState) rel_transform = get_transform(other);
1578 
1579  CPT(TransformState) transform = get_transform();
1580  if (transform->has_components()) {
1581  // If we had a componentwise transform before we started, we should be
1582  // careful to preserve the other three components. We wouldn't need to do
1583  // this, except for the possibility of numerical error or decompose
1584  // ambiguity.
1585  const LVecBase3 &orig_pos = transform->get_pos();
1586  const LVecBase3 &orig_hpr = transform->get_hpr();
1587  const LVecBase3 &orig_shear = transform->get_shear();
1588 
1589  set_transform(other, rel_transform->set_scale(scale));
1590  transform = get_transform();
1591  if (transform->has_components()) {
1592  set_transform(TransformState::make_pos_hpr_scale_shear
1593  (orig_pos, orig_hpr, transform->get_scale(), orig_shear));
1594  }
1595 
1596  } else {
1597  // If we didn't have a componentwise transform already, never mind.
1598  set_transform(other, rel_transform->set_scale(scale));
1599  }
1600 }
1601 
1602 void NodePath::
1603 set_sx(const NodePath &other, PN_stdfloat sx) {
1604  nassertv_always(!is_empty());
1605  LVecBase3 scale = get_scale(other);
1606  scale[0] = sx;
1607  set_scale(other, scale);
1608 }
1609 
1610 void NodePath::
1611 set_sy(const NodePath &other, PN_stdfloat sy) {
1612  nassertv_always(!is_empty());
1613  LVecBase3 scale = get_scale(other);
1614  scale[1] = sy;
1615  set_scale(other, scale);
1616 }
1617 
1618 void NodePath::
1619 set_sz(const NodePath &other, PN_stdfloat sz) {
1620  nassertv_always(!is_empty());
1621  LVecBase3 scale = get_scale(other);
1622  scale[2] = sz;
1623  set_scale(other, scale);
1624 }
1625 
1626 /**
1627  * Returns the relative scale of the bottom node as seen from the other node.
1628  */
1629 LVecBase3 NodePath::
1630 get_scale(const NodePath &other) const {
1631  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1632  CPT(TransformState) transform = get_transform(other);
1633  return transform->get_scale();
1634 }
1635 
1636 /**
1637  * Sets the shear component of the transform, relative to the other node.
1638  */
1640 set_shear(const NodePath &other, const LVecBase3 &shear) {
1641  nassertv_always(!is_empty());
1642  CPT(TransformState) rel_transform = get_transform(other);
1643 
1644  CPT(TransformState) transform = get_transform();
1645  if (transform->has_components()) {
1646  // If we had a componentwise transform before we started, we should be
1647  // careful to preserve the other three components. We wouldn't need to do
1648  // this, except for the possibility of numerical error or decompose
1649  // ambiguity.
1650  const LVecBase3 &orig_pos = transform->get_pos();
1651  const LVecBase3 &orig_hpr = transform->get_hpr();
1652  const LVecBase3 &orig_scale = transform->get_scale();
1653 
1654  set_transform(other, rel_transform->set_shear(shear));
1655  transform = get_transform();
1656  if (transform->has_components()) {
1657  set_transform(TransformState::make_pos_hpr_scale_shear
1658  (orig_pos, orig_hpr, orig_scale, transform->get_shear()));
1659  }
1660 
1661  } else {
1662  // If we didn't have a componentwise transform already, never mind.
1663  set_transform(other, rel_transform->set_shear(shear));
1664  }
1665 }
1666 
1667 void NodePath::
1668 set_shxy(const NodePath &other, PN_stdfloat shxy) {
1669  nassertv_always(!is_empty());
1670  LVecBase3 shear = get_shear(other);
1671  shear[0] = shxy;
1672  set_shear(other, shear);
1673 }
1674 
1675 void NodePath::
1676 set_shxz(const NodePath &other, PN_stdfloat shxz) {
1677  nassertv_always(!is_empty());
1678  LVecBase3 shear = get_shear(other);
1679  shear[1] = shxz;
1680  set_shear(other, shear);
1681 }
1682 
1683 void NodePath::
1684 set_shyz(const NodePath &other, PN_stdfloat shyz) {
1685  nassertv_always(!is_empty());
1686  LVecBase3 shear = get_shear(other);
1687  shear[2] = shyz;
1688  set_shear(other, shear);
1689 }
1690 
1691 /**
1692  * Returns the relative shear of the bottom node as seen from the other node.
1693  */
1694 LVecBase3 NodePath::
1695 get_shear(const NodePath &other) const {
1696  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1697  CPT(TransformState) transform = get_transform(other);
1698  return transform->get_shear();
1699 }
1700 
1701 /**
1702  * Sets the translation and rotation component of the transform, relative to
1703  * the other node.
1704  */
1706 set_pos_hpr(const NodePath &other, const LVecBase3 &pos,
1707  const LVecBase3 &hpr) {
1708  nassertv_always(!is_empty());
1709  CPT(TransformState) rel_transform = get_transform(other);
1710 
1711  CPT(TransformState) transform = get_transform();
1712  if (transform->has_components()) {
1713  // If we had a componentwise transform before we started, we should be
1714  // careful to preserve the other two components. We wouldn't need to do
1715  // this, except for the possibility of numerical error or decompose
1716  // ambiguity.
1717  const LVecBase3 &orig_scale = transform->get_scale();
1718  const LVecBase3 &orig_shear = transform->get_shear();
1719 
1720  set_transform(other, TransformState::make_pos_hpr_scale_shear
1721  (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
1722  transform = get_transform();
1723  if (transform->has_components()) {
1724  set_pos_hpr_scale_shear(transform->get_pos(), transform->get_hpr(),
1725  orig_scale, orig_shear);
1726  }
1727 
1728  } else {
1729  // If we didn't have a componentwise transform already, never mind.
1730  set_transform(other, TransformState::make_pos_hpr_scale_shear
1731  (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
1733  }
1734 }
1735 
1736 /**
1737  * Sets the translation and rotation component of the transform, relative to
1738  * the other node.
1739  */
1741 set_pos_quat(const NodePath &other, const LVecBase3 &pos,
1742  const LQuaternion &quat) {
1743  nassertv_always(!is_empty());
1744  CPT(TransformState) rel_transform = get_transform(other);
1745 
1746  CPT(TransformState) transform = get_transform();
1747  if (transform->has_components()) {
1748  // If we had a componentwise transform before we started, we should be
1749  // careful to preserve the other two components. We wouldn't need to do
1750  // this, except for the possibility of numerical error or decompose
1751  // ambiguity.
1752  const LVecBase3 &orig_scale = transform->get_scale();
1753  const LVecBase3 &orig_shear = transform->get_shear();
1754 
1755  set_transform(other, TransformState::make_pos_quat_scale_shear
1756  (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
1757  transform = get_transform();
1758  if (transform->has_components()) {
1759  set_pos_quat_scale_shear(transform->get_pos(), transform->get_quat(),
1760  orig_scale, orig_shear);
1761  }
1762 
1763  } else {
1764  // If we didn't have a componentwise transform already, never mind.
1765  set_transform(other, TransformState::make_pos_quat_scale_shear
1766  (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
1768  }
1769 }
1770 
1771 /**
1772  * Sets the rotation and scale components of the transform, leaving
1773  * translation untouched. This, or set_pos_hpr_scale, is the preferred way to
1774  * update a transform when both hpr and scale are to be changed.
1775  */
1777 set_hpr_scale(const NodePath &other, const LVecBase3 &hpr, const LVecBase3 &scale) {
1778  // We don't bother trying very hard to preserve pos across this operation,
1779  // unlike the work we do above to preserve hpr or scale, since it generally
1780  // doesn't matter that much if pos is off by a few thousandths.
1781  nassertv_always(!is_empty());
1782  CPT(TransformState) transform = get_transform(other);
1783  transform = TransformState::make_pos_hpr_scale_shear
1784  (transform->get_pos(), hpr, scale, transform->get_shear());
1785  set_transform(other, transform);
1786 }
1787 
1788 /**
1789  * Sets the rotation and scale components of the transform, leaving
1790  * translation untouched. This, or set_pos_quat_scale, is the preferred way
1791  * to update a transform when both quat and scale are to be changed.
1792  */
1794 set_quat_scale(const NodePath &other, const LQuaternion &quat,
1795  const LVecBase3 &scale) {
1796  // We don't bother trying very hard to preserve pos across this operation,
1797  // unlike the work we do above to preserve quat or scale, since it generally
1798  // doesn't matter that much if pos is off by a few thousandths.
1799  nassertv_always(!is_empty());
1800  CPT(TransformState) transform = get_transform(other);
1801  transform = TransformState::make_pos_quat_scale_shear
1802  (transform->get_pos(), quat, scale, transform->get_shear());
1803  set_transform(other, transform);
1804 }
1805 
1806 /**
1807  * Completely replaces the transform with new translation, rotation, and scale
1808  * components, relative to the other node, implicitly setting shear to 0.
1809  */
1811 set_pos_hpr_scale(const NodePath &other,
1812  const LVecBase3 &pos, const LVecBase3 &hpr,
1813  const LVecBase3 &scale) {
1814  nassertv_always(!is_empty());
1815  set_transform(other, TransformState::make_pos_hpr_scale
1816  (pos, hpr, scale));
1818 }
1819 
1820 /**
1821  * Completely replaces the transform with new translation, rotation, and scale
1822  * components, relative to the other node, implicitly setting shear to 0.
1823  */
1825 set_pos_quat_scale(const NodePath &other,
1826  const LVecBase3 &pos, const LQuaternion &quat,
1827  const LVecBase3 &scale) {
1828  nassertv_always(!is_empty());
1829  set_transform(other, TransformState::make_pos_quat_scale
1830  (pos, quat, scale));
1832 }
1833 
1834 /**
1835  * Completely replaces the transform with new translation, rotation, scale,
1836  * and shear components, relative to the other node.
1837  */
1839 set_pos_hpr_scale_shear(const NodePath &other,
1840  const LVecBase3 &pos, const LVecBase3 &hpr,
1841  const LVecBase3 &scale, const LVecBase3 &shear) {
1842  nassertv_always(!is_empty());
1843  set_transform(other, TransformState::make_pos_hpr_scale_shear
1844  (pos, hpr, scale, shear));
1846 }
1847 
1848 /**
1849  * Completely replaces the transform with new translation, rotation, scale,
1850  * and shear components, relative to the other node.
1851  */
1853 set_pos_quat_scale_shear(const NodePath &other,
1854  const LVecBase3 &pos, const LQuaternion &quat,
1855  const LVecBase3 &scale, const LVecBase3 &shear) {
1856  nassertv_always(!is_empty());
1857  set_transform(other, TransformState::make_pos_quat_scale_shear
1858  (pos, quat, scale, shear));
1860 }
1861 
1862 /**
1863  * Returns the matrix that describes the coordinate space of the bottom node,
1864  * relative to the other path's bottom node's coordinate space.
1865  */
1866 LMatrix4 NodePath::
1867 get_mat(const NodePath &other) const {
1868  CPT(TransformState) transform = get_transform(other);
1869  // We can't safely return a reference to the matrix, because we can't assume
1870  // the transform won't go away when the function returns. If the transform
1871  // was partially modified by, say, a CompassEffect, it won't be stored in
1872  // the cache, and thus we might have the only reference to it.
1873  return transform->get_mat();
1874 }
1875 
1876 /**
1877  * Converts the indicated matrix from the other's coordinate space to the
1878  * local coordinate space, and applies it to the node.
1879  */
1881 set_mat(const NodePath &other, const LMatrix4 &mat) {
1882  nassertv_always(!is_empty());
1883  set_transform(other, TransformState::make_mat(mat));
1885 }
1886 
1887 /**
1888  * Given that the indicated point is in the coordinate system of the other
1889  * node, returns the same point in this node's coordinate system.
1890  */
1891 LPoint3 NodePath::
1892 get_relative_point(const NodePath &other, const LVecBase3 &point) const {
1893  CPT(TransformState) transform = other.get_transform(*this);
1894  LPoint3 rel_point = LPoint3(point) * transform->get_mat();
1895  return rel_point;
1896 }
1897 
1898 /**
1899  * Given that the indicated vector is in the coordinate system of the other
1900  * node, returns the same vector in this node's coordinate system.
1901  */
1902 LVector3 NodePath::
1903 get_relative_vector(const NodePath &other, const LVecBase3 &vec) const {
1904  CPT(TransformState) transform = other.get_transform(*this);
1905  LVector3 rel_vector = LVector3(vec) * transform->get_mat();
1906  return rel_vector;
1907 }
1908 
1909 /**
1910  * Sets the transform on this NodePath so that it rotates to face the
1911  * indicated point in space, which is relative to the other NodePath.
1912  */
1914 look_at(const NodePath &other, const LPoint3 &point, const LVector3 &up) {
1915  nassertv_always(!is_empty());
1916 
1917  CPT(TransformState) transform = other.get_transform(get_parent());
1918  LPoint3 rel_point = point * transform->get_mat();
1919 
1920  LPoint3 pos = get_pos();
1921 
1922  LQuaternion quat;
1923  ::look_at(quat, rel_point - pos, up);
1924  set_quat(quat);
1925 }
1926 
1927 /**
1928  * Behaves like look_at(), but with a strong preference to keeping the up
1929  * vector oriented in the indicated "up" direction.
1930  */
1932 heads_up(const NodePath &other, const LPoint3 &point, const LVector3 &up) {
1933  nassertv_always(!is_empty());
1934 
1935  CPT(TransformState) transform = other.get_transform(get_parent());
1936  LPoint3 rel_point = point * transform->get_mat();
1937 
1938  LPoint3 pos = get_pos();
1939 
1940  LQuaternion quat;
1941  ::heads_up(quat, rel_point - pos, up);
1942  set_quat(quat);
1943 }
1944 
1945 
1946 /**
1947  * Applies a scene-graph color to the referenced node. This color will apply
1948  * to all geometry at this level and below (that does not specify a new color
1949  * or a set_color_off()).
1950  */
1952 set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a,
1953  int priority) {
1954  set_color(LColor(r, g, b, a), priority);
1955 }
1956 
1957 /**
1958  * Applies a scene-graph color to the referenced node. This color will apply
1959  * to all geometry at this level and below (that does not specify a new color
1960  * or a set_color_off()).
1961  */
1963 set_color(const LColor &color, int priority) {
1964  nassertv_always(!is_empty());
1965  node()->set_attrib(ColorAttrib::make_flat(color), priority);
1966 }
1967 
1968 /**
1969  * Sets the geometry at this level and below to render using the geometry
1970  * color. This is normally the default, but it may be useful to use this to
1971  * contradict set_color() at a higher node level (or, with a priority, to
1972  * override a set_color() at a lower level).
1973  */
1975 set_color_off(int priority) {
1976  nassertv_always(!is_empty());
1977  node()->set_attrib(ColorAttrib::make_vertex(), priority);
1978 }
1979 
1980 /**
1981  * Completely removes any color adjustment from the node. This allows the
1982  * natural color of the geometry, or whatever color transitions might be
1983  * otherwise affecting the geometry, to show instead.
1984  */
1986 clear_color() {
1987  nassertv_always(!is_empty());
1988  node()->clear_attrib(ColorAttrib::get_class_slot());
1989 }
1990 
1991 /**
1992  * Returns true if a color has been applied to the given node, false
1993  * otherwise.
1994  */
1996 has_color() const {
1997  nassertr_always(!is_empty(), false);
1998  return node()->has_attrib(ColorAttrib::get_class_slot());
1999 }
2000 
2001 /**
2002  * Returns the color that has been assigned to the node, or black if no color
2003  * has been assigned.
2004  */
2006 get_color() const {
2007  nassertr_always(!is_empty(), false);
2008  const RenderAttrib *attrib =
2009  node()->get_attrib(ColorAttrib::get_class_slot());
2010  if (attrib != nullptr) {
2011  const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
2012  if (ca->get_color_type() == ColorAttrib::T_flat) {
2013  return ca->get_color();
2014  }
2015  }
2016 
2017  pgraph_cat.warning()
2018  << "get_color() called on " << *this << " which has no color set.\n";
2019 
2020  return LColor(1.0f, 1.0f, 1.0f, 1.0f);
2021 }
2022 
2023 /**
2024  * Returns true if a color scale has been applied to the referenced node,
2025  * false otherwise. It is still possible that color at this node might have
2026  * been scaled by an ancestor node.
2027  */
2029 has_color_scale() const {
2030  nassertr_always(!is_empty(), false);
2031  return node()->has_attrib(ColorScaleAttrib::get_class_slot());
2032 }
2033 
2034 /**
2035  * Completely removes any color scale from the referenced node. This is
2036  * preferable to simply setting the color scale to identity, as it also
2037  * removes the overhead associated with having a color scale at all.
2038  */
2041  nassertv_always(!is_empty());
2042  node()->clear_attrib(ColorScaleAttrib::get_class_slot());
2043 }
2044 
2045 /**
2046  * multiplies the color scale component of the transform, with previous color
2047  * scale leaving translation and rotation untouched.
2048  */
2050 compose_color_scale(const LVecBase4 &scale, int priority) {
2051  nassertv_always(!is_empty());
2052 
2053  const RenderAttrib *attrib =
2054  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2055  if (attrib != nullptr) {
2056  priority = max(priority,
2057  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2058  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2059 
2060  // Modify the existing ColorScaleAttrib by multiplying with the indicated
2061  // colorScale.
2062  LVecBase4 prev_color_scale = csa->get_scale();
2063  LVecBase4 new_color_scale(prev_color_scale[0]*scale[0],
2064  prev_color_scale[1]*scale[1],
2065  prev_color_scale[2]*scale[2],
2066  prev_color_scale[3]*scale[3]);
2067  node()->set_attrib(csa->set_scale(new_color_scale), priority);
2068 
2069  } else {
2070  // Create a new ColorScaleAttrib for this node.
2071  node()->set_attrib(ColorScaleAttrib::make(scale), priority);
2072  }
2073 }
2074 
2075 /**
2076  * Sets the color scale component of the transform, leaving translation and
2077  * rotation untouched.
2078  */
2080 set_color_scale(const LVecBase4 &scale, int priority) {
2081  nassertv_always(!is_empty());
2082 
2083  const RenderAttrib *attrib =
2084  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2085  if (attrib != nullptr) {
2086  priority = max(priority,
2087  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2088  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2089 
2090  // Modify the existing ColorScaleAttrib to add the indicated colorScale.
2091  node()->set_attrib(csa->set_scale(scale), priority);
2092 
2093  } else {
2094  // Create a new ColorScaleAttrib for this node.
2095  node()->set_attrib(ColorScaleAttrib::make(scale), priority);
2096  }
2097 }
2098 
2099 /**
2100  * Disables any color scale attribute inherited from above. This is not the
2101  * same thing as clear_color_scale(), which undoes any previous
2102  * set_color_scale() operation on this node; rather, this actively disables
2103  * any set_color_scale() that might be inherited from a parent node. This
2104  * also disables set_alpha_scale() at the same time.
2105  *
2106  * It is legal to specify a new color scale on the same node with a subsequent
2107  * call to set_color_scale() or set_alpha_scale(); this new scale will apply
2108  * to lower geometry.
2109  */
2111 set_color_scale_off(int priority) {
2112  nassertv_always(!is_empty());
2113  node()->set_attrib(ColorScaleAttrib::make_off(), priority);
2114 }
2115 
2116 /**
2117  * Sets the alpha scale component of the transform without (much) affecting
2118  * the color scale. Note that any priority specified will also apply to the
2119  * color scale.
2120  */
2122 set_alpha_scale(PN_stdfloat scale, int priority) {
2123  nassertv_always(!is_empty());
2124 
2125  const RenderAttrib *attrib =
2126  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2127  if (attrib != nullptr) {
2128  priority = max(priority,
2129  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2130  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2131 
2132  // Modify the existing ColorScaleAttrib to add the indicated colorScale.
2133  const LVecBase4 &sc = csa->get_scale();
2134  node()->set_attrib(csa->set_scale(LVecBase4(sc[0], sc[1], sc[2], scale)), priority);
2135 
2136  } else {
2137  // Create a new ColorScaleAttrib for this node.
2138  node()->set_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, scale)), priority);
2139  }
2140 }
2141 
2142 /**
2143  * Scales all the color components of the object by the same amount, darkening
2144  * the object, without (much) affecting alpha. Note that any priority
2145  * specified will also apply to the alpha scale.
2146  */
2148 set_all_color_scale(PN_stdfloat scale, int priority) {
2149  nassertv_always(!is_empty());
2150 
2151  const RenderAttrib *attrib =
2152  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2153  if (attrib != nullptr) {
2154  priority = max(priority,
2155  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2156  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2157 
2158  // Modify the existing ColorScaleAttrib to add the indicated colorScale.
2159  const LVecBase4 &sc = csa->get_scale();
2160  node()->set_attrib(csa->set_scale(LVecBase4(scale, scale, scale, sc[3])), priority);
2161 
2162  } else {
2163  // Create a new ColorScaleAttrib for this node.
2164  node()->set_attrib(ColorScaleAttrib::make(LVecBase4(scale, scale, scale, 1.0f)), priority);
2165  }
2166 }
2167 
2168 /**
2169  * Returns the complete color scale vector that has been applied to this node
2170  * via a previous call to set_color_scale() and/or set_alpha_scale(), or all
2171  * 1's (identity) if no scale has been applied to this particular node.
2172  */
2173 const LVecBase4 &NodePath::
2174 get_color_scale() const {
2175  static const LVecBase4 ident_scale(1.0f, 1.0f, 1.0f, 1.0f);
2176  nassertr_always(!is_empty(), ident_scale);
2177  const RenderAttrib *attrib =
2178  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2179  if (attrib != nullptr) {
2180  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2181  return csa->get_scale();
2182  }
2183 
2184  return ident_scale;
2185 }
2186 
2187 /**
2188  * Adds the indicated Light or PolylightNode to the list of lights that
2189  * illuminate geometry at this node and below. The light itself should be
2190  * parented into the scene graph elsewhere, to represent the light's position
2191  * in space; but until set_light() is called it will illuminate no geometry.
2192  */
2194 set_light(const NodePath &light, int priority) {
2195  nassertv_always(!is_empty());
2196  if (!light.is_empty()) {
2197  Light *light_obj = light.node()->as_light();
2198  if (light_obj != nullptr) {
2199  // It's an actual Light object.
2200  const RenderAttrib *attrib =
2201  node()->get_attrib(LightAttrib::get_class_slot());
2202  if (attrib != nullptr) {
2203  priority = max(priority,
2204  node()->get_state()->get_override(LightAttrib::get_class_slot()));
2205  const LightAttrib *la = DCAST(LightAttrib, attrib);
2206 
2207  // Modify the existing LightAttrib to add the indicated light.
2208  node()->set_attrib(la->add_on_light(light), priority);
2209 
2210  } else {
2211  // Create a new LightAttrib for this node.
2212  CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
2213  node()->set_attrib(la->add_on_light(light), priority);
2214  }
2215  return;
2216 
2217  } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
2218  // It's a Polylight object.
2219  if (priority != 0) {
2220  // PolylightEffects can't have a priority, since they're just an
2221  // effect to be applied immediately.
2222  pgraph_cat.warning()
2223  << "Ignoring priority on set_light(" << light << ")\n";
2224  }
2225 
2226  const RenderEffect *effect =
2227  node()->get_effect(PolylightEffect::get_class_type());
2228  if (effect != nullptr) {
2229  const PolylightEffect *ple = DCAST(PolylightEffect, effect);
2230 
2231  // Modify the existing PolylightEffect to add the indicated light.
2232  node()->set_effect(ple->add_light(light));
2233 
2234  } else {
2235  // Create a new PolylightEffect for this node.
2236  CPT(PolylightEffect) ple = DCAST(PolylightEffect, PolylightEffect::make());
2237  node()->set_effect(ple->add_light(light));
2238  }
2239  return;
2240  }
2241  }
2242  nassert_raise("Not a Light object.");
2243 }
2244 
2245 /**
2246  * Sets the geometry at this level and below to render using no lights at all.
2247  * This is different from not specifying a light; rather, this specifically
2248  * contradicts set_light() at a higher node level (or, with a priority,
2249  * overrides a set_light() at a lower level).
2250  *
2251  * If no lights are in effect on a particular piece of geometry, that geometry
2252  * is rendered with lighting disabled.
2253  */
2255 set_light_off(int priority) {
2256  nassertv_always(!is_empty());
2257  node()->set_attrib(LightAttrib::make_all_off(), priority);
2258  node()->clear_effect(PolylightEffect::get_class_type());
2259 }
2260 
2261 /**
2262  * Sets the geometry at this level and below to render without using the
2263  * indicated Light. This is different from not specifying the Light; rather,
2264  * this specifically contradicts set_light() at a higher node level (or, with
2265  * a priority, overrides a set_light() at a lower level).
2266  *
2267  * This interface does not support PolylightNodes, which cannot be turned off
2268  * at a lower level.
2269  */
2271 set_light_off(const NodePath &light, int priority) {
2272  nassertv_always(!is_empty());
2273 
2274  if (!light.is_empty()) {
2275  Light *light_obj = light.node()->as_light();
2276  if (light_obj != nullptr) {
2277  const RenderAttrib *attrib =
2278  node()->get_attrib(LightAttrib::get_class_slot());
2279  if (attrib != nullptr) {
2280  priority = max(priority,
2281  node()->get_state()->get_override(LightAttrib::get_class_slot()));
2282  const LightAttrib *la = DCAST(LightAttrib, attrib);
2283 
2284  // Modify the existing LightAttrib to add the indicated light to the
2285  // "off" list. This also, incidentally, removes it from the "on" list
2286  // if it is there.
2287  node()->set_attrib(la->add_off_light(light), priority);
2288 
2289  } else {
2290  // Create a new LightAttrib for this node that turns off the indicated
2291  // light.
2292  CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
2293  node()->set_attrib(la->add_off_light(light), priority);
2294  }
2295  return;
2296  }
2297  }
2298  nassert_raise("Not a Light object.");
2299 }
2300 
2301 /**
2302  * Completely removes any lighting operations that may have been set via
2303  * set_light() or set_light_off() from this particular node.
2304  */
2306 clear_light() {
2307  nassertv_always(!is_empty());
2308  node()->clear_attrib(LightAttrib::get_class_slot());
2309  node()->clear_effect(PolylightEffect::get_class_type());
2310 }
2311 
2312 /**
2313  * Removes any reference to the indicated Light or PolylightNode from the
2314  * NodePath.
2315  */
2317 clear_light(const NodePath &light) {
2318  nassertv_always(!is_empty());
2319 
2320  if (!light.is_empty()) {
2321  Light *light_obj = light.node()->as_light();
2322  if (light_obj != nullptr) {
2323  const RenderAttrib *attrib =
2324  node()->get_attrib(LightAttrib::get_class_slot());
2325  if (attrib != nullptr) {
2326  CPT(LightAttrib) la = DCAST(LightAttrib, attrib);
2327  la = DCAST(LightAttrib, la->remove_on_light(light));
2328  la = DCAST(LightAttrib, la->remove_off_light(light));
2329 
2330  if (la->is_identity()) {
2331  node()->clear_attrib(LightAttrib::get_class_slot());
2332 
2333  } else {
2334  int priority = node()->get_state()->get_override(LightAttrib::get_class_slot());
2335  node()->set_attrib(la, priority);
2336  }
2337  }
2338  return;
2339 
2340  } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
2341  const RenderEffect *effect =
2342  node()->get_effect(PolylightEffect::get_class_type());
2343  if (effect != nullptr) {
2344  CPT(PolylightEffect) ple = DCAST(PolylightEffect, effect);
2345  ple = DCAST(PolylightEffect, ple->remove_light(light));
2346  node()->set_effect(ple);
2347  }
2348  return;
2349  }
2350  }
2351  nassert_raise("Not a Light object.");
2352 }
2353 
2354 /**
2355  * Returns true if the indicated Light or PolylightNode has been specifically
2356  * enabled on this particular node. This means that someone called
2357  * set_light() on this node with the indicated light.
2358  */
2360 has_light(const NodePath &light) const {
2361  nassertr_always(!is_empty(), false);
2362 
2363  if (!light.is_empty()) {
2364  Light *light_obj = light.node()->as_light();
2365  if (light_obj != nullptr) {
2366  const RenderAttrib *attrib =
2367  node()->get_attrib(LightAttrib::get_class_slot());
2368  if (attrib != nullptr) {
2369  const LightAttrib *la = DCAST(LightAttrib, attrib);
2370  return la->has_on_light(light);
2371  }
2372  return false;
2373 
2374  } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
2375  const RenderEffect *effect =
2376  node()->get_effect(PolylightEffect::get_class_type());
2377  if (effect != nullptr) {
2378  const PolylightEffect *ple = DCAST(PolylightEffect, effect);
2379  return ple->has_light(light);
2380  }
2381  return false;
2382  }
2383  }
2384  nassert_raise("Not a Light object.");
2385  return false;
2386 }
2387 
2388 /**
2389  * Returns true if all Lights have been specifically disabled on this
2390  * particular node. This means that someone called set_light_off() on this
2391  * node with no parameters.
2392  */
2394 has_light_off() const {
2395  nassertr_always(!is_empty(), false);
2396 
2397  const RenderAttrib *attrib =
2398  node()->get_attrib(LightAttrib::get_class_slot());
2399  if (attrib != nullptr) {
2400  const LightAttrib *la = DCAST(LightAttrib, attrib);
2401  return la->has_all_off();
2402  }
2403 
2404  return false;
2405 }
2406 
2407 /**
2408  * Returns true if the indicated Light has been specifically disabled on this
2409  * particular node. This means that someone called set_light_off() on this
2410  * node with the indicated light.
2411  *
2412  * This interface does not support PolylightNodes, which cannot be turned off
2413  * at a lower level.
2414  */
2416 has_light_off(const NodePath &light) const {
2417  nassertr_always(!is_empty(), false);
2418  if (!light.is_empty()) {
2419  Light *light_obj = light.node()->as_light();
2420  if (light_obj != nullptr) {
2421  const RenderAttrib *attrib =
2422  node()->get_attrib(LightAttrib::get_class_slot());
2423  if (attrib != nullptr) {
2424  const LightAttrib *la = DCAST(LightAttrib, attrib);
2425  return la->has_off_light(light);
2426  }
2427  }
2428  }
2429  nassert_raise("Not a Light object.");
2430  return false;
2431 }
2432 
2433 /**
2434  * Adds the indicated clipping plane to the list of planes that apply to
2435  * geometry at this node and below. The clipping plane itself, a PlaneNode,
2436  * should be parented into the scene graph elsewhere, to represent the plane's
2437  * position in space; but until set_clip_plane() is called it will clip no
2438  * geometry.
2439  */
2441 set_clip_plane(const NodePath &clip_plane, int priority) {
2442  nassertv_always(!is_empty());
2443  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2444  const RenderAttrib *attrib =
2445  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2446  if (attrib != nullptr) {
2447  priority = max(priority,
2448  node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()));
2449  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2450 
2451  // Modify the existing ClipPlaneAttrib to add the indicated clip_plane.
2452  node()->set_attrib(la->add_on_plane(clip_plane), priority);
2453 
2454  } else {
2455  // Create a new ClipPlaneAttrib for this node.
2456  CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
2457  node()->set_attrib(la->add_on_plane(clip_plane), priority);
2458  }
2459  return;
2460  }
2461  nassert_raise("Not a PlaneNode object.");
2462 }
2463 
2464 /**
2465  * Sets the geometry at this level and below to render using no clip_planes at
2466  * all. This is different from not specifying a clip_plane; rather, this
2467  * specifically contradicts set_clip_plane() at a higher node level (or, with
2468  * a priority, overrides a set_clip_plane() at a lower level).
2469  *
2470  * If no clip_planes are in effect on a particular piece of geometry, that
2471  * geometry is rendered without being clipped (other than by the viewing
2472  * frustum).
2473  */
2475 set_clip_plane_off(int priority) {
2476  nassertv_always(!is_empty());
2477  node()->set_attrib(ClipPlaneAttrib::make_all_off(), priority);
2478 }
2479 
2480 /**
2481  * Sets the geometry at this level and below to render without being clipped
2482  * by the indicated PlaneNode. This is different from not specifying the
2483  * PlaneNode; rather, this specifically contradicts set_clip_plane() at a
2484  * higher node level (or, with a priority, overrides a set_clip_plane() at a
2485  * lower level).
2486  */
2488 set_clip_plane_off(const NodePath &clip_plane, int priority) {
2489  nassertv_always(!is_empty());
2490 
2491  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2492  const RenderAttrib *attrib =
2493  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2494  if (attrib != nullptr) {
2495  priority = max(priority,
2496  node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()));
2497  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2498 
2499  // Modify the existing ClipPlaneAttrib to add the indicated clip_plane
2500  // to the "off" list. This also, incidentally, removes it from the "on"
2501  // list if it is there.
2502  node()->set_attrib(la->add_off_plane(clip_plane), priority);
2503 
2504  } else {
2505  // Create a new ClipPlaneAttrib for this node that turns off the
2506  // indicated clip_plane.
2507  CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
2508  node()->set_attrib(la->add_off_plane(clip_plane), priority);
2509  }
2510  return;
2511  }
2512  nassert_raise("Not a PlaneNode object.");
2513 }
2514 
2515 /**
2516  * Completely removes any clip planes that may have been set via
2517  * set_clip_plane() or set_clip_plane_off() from this particular node.
2518  */
2520 clear_clip_plane() {
2521  nassertv_always(!is_empty());
2522  node()->clear_attrib(ClipPlaneAttrib::get_class_slot());
2523 }
2524 
2525 /**
2526  * Removes any reference to the indicated clipping plane from the NodePath.
2527  */
2529 clear_clip_plane(const NodePath &clip_plane) {
2530  nassertv_always(!is_empty());
2531 
2532  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2533  const RenderAttrib *attrib =
2534  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2535  if (attrib != nullptr) {
2536  CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib);
2537  la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane));
2538  la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane));
2539 
2540  if (la->is_identity()) {
2541  node()->clear_attrib(ClipPlaneAttrib::get_class_slot());
2542 
2543  } else {
2544  int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot());
2545  node()->set_attrib(la, priority);
2546  }
2547  }
2548  return;
2549  }
2550  nassert_raise("Not a PlaneNode object.");
2551 }
2552 
2553 /**
2554  * Returns true if the indicated clipping plane has been specifically applied
2555  * to this particular node. This means that someone called set_clip_plane()
2556  * on this node with the indicated clip_plane.
2557  */
2559 has_clip_plane(const NodePath &clip_plane) const {
2560  nassertr_always(!is_empty(), false);
2561 
2562  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2563  const RenderAttrib *attrib =
2564  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2565  if (attrib != nullptr) {
2566  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2567  return la->has_on_plane(clip_plane);
2568  }
2569  return false;
2570  }
2571  nassert_raise("Not a PlaneNode object.");
2572  return false;
2573 }
2574 
2575 /**
2576  * Returns true if all clipping planes have been specifically disabled on this
2577  * particular node. This means that someone called set_clip_plane_off() on
2578  * this node with no parameters.
2579  */
2581 has_clip_plane_off() const {
2582  nassertr_always(!is_empty(), false);
2583 
2584  const RenderAttrib *attrib =
2585  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2586  if (attrib != nullptr) {
2587  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2588  return la->has_all_off();
2589  }
2590 
2591  return false;
2592 }
2593 
2594 /**
2595  * Returns true if the indicated clipping plane has been specifically disabled
2596  * on this particular node. This means that someone called
2597  * set_clip_plane_off() on this node with the indicated clip_plane.
2598  */
2600 has_clip_plane_off(const NodePath &clip_plane) const {
2601  nassertr_always(!is_empty(), false);
2602  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2603  const RenderAttrib *attrib =
2604  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2605  if (attrib != nullptr) {
2606  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2607  return la->has_off_plane(clip_plane);
2608  }
2609  }
2610  nassert_raise("Not a PlaneNode object.");
2611  return false;
2612 }
2613 
2614 /**
2615  * Adds the indicated occluder to the list of occluders that apply to geometry
2616  * at this node and below. The occluder itself, an OccluderNode, should be
2617  * parented into the scene graph elsewhere, to represent the occluder's
2618  * position in space; but until set_occluder() is called it will clip no
2619  * geometry.
2620  */
2622 set_occluder(const NodePath &occluder) {
2623  nassertv_always(!is_empty());
2624  if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
2625  const RenderEffect *effect =
2626  node()->get_effect(OccluderEffect::get_class_type());
2627  if (effect != nullptr) {
2628  const OccluderEffect *la = DCAST(OccluderEffect, effect);
2629 
2630  // Modify the existing OccluderEffect to add the indicated occluder.
2631  node()->set_effect(la->add_on_occluder(occluder));
2632 
2633  } else {
2634  // Create a new OccluderEffect for this node.
2635  CPT(OccluderEffect) la = DCAST(OccluderEffect, OccluderEffect::make());
2636  node()->set_effect(la->add_on_occluder(occluder));
2637  }
2638  return;
2639  }
2640  nassert_raise("Not an OccluderNode object.");
2641 }
2642 
2643 /**
2644  * Completely removes any occluders that may have been set via set_occluder()
2645  * from this particular node.
2646  */
2648 clear_occluder() {
2649  nassertv_always(!is_empty());
2650  node()->clear_effect(OccluderEffect::get_class_type());
2651 }
2652 
2653 /**
2654  * Removes any reference to the indicated occluder from the NodePath.
2655  */
2657 clear_occluder(const NodePath &occluder) {
2658  nassertv_always(!is_empty());
2659 
2660  if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
2661  const RenderEffect *effect =
2662  node()->get_effect(OccluderEffect::get_class_type());
2663  if (effect != nullptr) {
2664  CPT(OccluderEffect) la = DCAST(OccluderEffect, effect);
2665  la = DCAST(OccluderEffect, la->remove_on_occluder(occluder));
2666 
2667  if (la->is_identity()) {
2668  node()->clear_effect(OccluderEffect::get_class_type());
2669 
2670  } else {
2671  node()->set_effect(la);
2672  }
2673  }
2674  return;
2675  }
2676  nassert_raise("Not an OccluderNode object.");
2677 }
2678 
2679 /**
2680  * Returns true if the indicated occluder has been specifically applied to
2681  * this particular node. This means that someone called set_occluder() on
2682  * this node with the indicated occluder.
2683  */
2685 has_occluder(const NodePath &occluder) const {
2686  nassertr_always(!is_empty(), false);
2687 
2688  if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
2689  const RenderEffect *effect =
2690  node()->get_effect(OccluderEffect::get_class_type());
2691  if (effect != nullptr) {
2692  const OccluderEffect *la = DCAST(OccluderEffect, effect);
2693  return la->has_on_occluder(occluder);
2694  }
2695  return false;
2696  }
2697  nassert_raise("Not an OccluderNode object.");
2698  return false;
2699 }
2700 
2701 /**
2702  * Sets up a scissor region on the nodes rendered at this level and below.
2703  * The four coordinates are understood to define a rectangle in screen space.
2704  * These numbers are relative to the current DisplayRegion, where (0,0) is the
2705  * lower-left corner of the DisplayRegion, and (1,1) is the upper-right
2706  * corner.
2707  */
2709 set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
2710  set_effect(ScissorEffect::make_screen(LVecBase4(left, right, bottom, top)));
2711 }
2712 
2713 /**
2714  * Sets up a scissor region on the nodes rendered at this level and below.
2715  * The two points are understood to be relative to this node. When these
2716  * points are projected into screen space, they define the diagonally-opposite
2717  * points that determine the scissor region.
2718  */
2720 set_scissor(const LPoint3 &a, const LPoint3 &b) {
2721  set_effect(ScissorEffect::make_node(a, b));
2722 }
2723 
2724 /**
2725  * Sets up a scissor region on the nodes rendered at this level and below.
2726  * The four points are understood to be relative to this node. When these
2727  * points are projected into screen space, they define the bounding volume of
2728  * the scissor region (the scissor region is the smallest onscreen rectangle
2729  * that encloses all four points).
2730  */
2732 set_scissor(const LPoint3 &a, const LPoint3 &b,
2733  const LPoint3 &c, const LPoint3 &d) {
2734  set_effect(ScissorEffect::make_node(a, b, c, d));
2735 }
2736 
2737 /**
2738  * Sets up a scissor region on the nodes rendered at this level and below.
2739  * The two points are understood to be relative to the indicated other node.
2740  * When these points are projected into screen space, they define the
2741  * diagonally-opposite points that determine the scissor region.
2742  */
2744 set_scissor(const NodePath &other, const LPoint3 &a, const LPoint3 &b) {
2745  set_effect(ScissorEffect::make_node(a, b, other));
2746 }
2747 
2748 /**
2749  * Sets up a scissor region on the nodes rendered at this level and below.
2750  * The four points are understood to be relative to the indicated other node.
2751  * When these points are projected into screen space, they define the bounding
2752  * volume of the scissor region (the scissor region is the smallest onscreen
2753  * rectangle that encloses all four points).
2754  */
2756 set_scissor(const NodePath &other,
2757  const LPoint3 &a, const LPoint3 &b,
2758  const LPoint3 &c, const LPoint3 &d) {
2759  set_effect(ScissorEffect::make_node(a, b, c, d, other));
2760 }
2761 
2762 /**
2763  * Removes the scissor region that was defined at this node level by a
2764  * previous call to set_scissor().
2765  */
2767 clear_scissor() {
2768  clear_effect(ScissorEffect::get_class_type());
2769 }
2770 
2771 /**
2772  * Returns true if a scissor region was defined at this node by a previous
2773  * call to set_scissor(). This does not check for scissor regions inherited
2774  * from a parent class. It also does not check for the presence of a low-
2775  * level ScissorAttrib, which is different from the ScissorEffect added by
2776  * set_scissor.
2777  */
2779 has_scissor() const {
2780  return has_effect(ScissorEffect::get_class_type());
2781 }
2782 
2783 /**
2784  * Assigns the geometry at this level and below to the named rendering bin.
2785  * It is the user's responsibility to ensure that such a bin already exists,
2786  * either via the cull-bin Configrc variable, or by explicitly creating a
2787  * GeomBin of the appropriate type at runtime.
2788  *
2789  * There are two default bins created when Panda is started: "default" and
2790  * "fixed". Normally, all geometry is assigned to "default" unless specified
2791  * otherwise. This bin renders opaque geometry in state-sorted order,
2792  * followed by transparent geometry sorted back-to-front. If any geometry is
2793  * assigned to "fixed", this will be rendered following all the geometry in
2794  * "default", in the order specified by draw_order for each piece of geometry
2795  * so assigned.
2796  *
2797  * The draw_order parameter is meaningful only for GeomBinFixed type bins,
2798  * e.g. "fixed". Other kinds of bins ignore it.
2799  */
2801 set_bin(const string &bin_name, int draw_order, int priority) {
2802  nassertv_always(!is_empty());
2803  node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority);
2804 }
2805 
2806 /**
2807  * Completely removes any bin adjustment that may have been set via set_bin()
2808  * from this particular node.
2809  */
2811 clear_bin() {
2812  nassertv_always(!is_empty());
2813  node()->clear_attrib(CullBinAttrib::get_class_slot());
2814 }
2815 
2816 /**
2817  * Returns true if the node has been assigned to the a particular rendering
2818  * bin via set_bin(), false otherwise.
2819  */
2821 has_bin() const {
2822  nassertr_always(!is_empty(), false);
2823  return node()->has_attrib(CullBinAttrib::get_class_slot());
2824 }
2825 
2826 /**
2827  * Returns the name of the bin that this particular node was assigned to via
2828  * set_bin(), or the empty string if no bin was assigned. See set_bin() and
2829  * has_bin().
2830  */
2832 get_bin_name() const {
2833  nassertr_always(!is_empty(), string());
2834  const RenderAttrib *attrib =
2835  node()->get_attrib(CullBinAttrib::get_class_slot());
2836  if (attrib != nullptr) {
2837  const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
2838  return ba->get_bin_name();
2839  }
2840 
2841  return string();
2842 }
2843 
2844 /**
2845  * Returns the drawing order associated with the bin that this particular node
2846  * was assigned to via set_bin(), or 0 if no bin was assigned. See set_bin()
2847  * and has_bin().
2848  */
2850 get_bin_draw_order() const {
2851  nassertr_always(!is_empty(), false);
2852  const RenderAttrib *attrib =
2853  node()->get_attrib(CullBinAttrib::get_class_slot());
2854  if (attrib != nullptr) {
2855  const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
2856  return ba->get_draw_order();
2857  }
2858 
2859  return 0;
2860 }
2861 
2862 /**
2863  * Adds the indicated texture to the list of textures that will be rendered on
2864  * the default texture stage.
2865  *
2866  * This is the convenience single-texture variant of this method; it is now
2867  * superceded by set_texture() that accepts a stage and texture. You may use
2868  * this method if you just want to adjust the default stage.
2869  */
2871 set_texture(Texture *tex, int priority) {
2872  nassertv_always(!is_empty());
2874  set_texture(stage, tex, priority);
2875 }
2876 
2877 /**
2878  * Adds the indicated texture to the list of textures that will be rendered on
2879  * the indicated multitexture stage. If there are multiple texture stages
2880  * specified (possibly on multiple different nodes at different levels), they
2881  * will all be applied to geometry together, according to the stage
2882  * specification set up in the TextureStage object.
2883  */
2885 set_texture(TextureStage *stage, Texture *tex, int priority) {
2886  nassertv_always(!is_empty());
2887 
2888  const RenderAttrib *attrib =
2889  node()->get_attrib(TextureAttrib::get_class_slot());
2890  if (attrib != nullptr) {
2891  const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
2892  int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
2893 
2894  // Modify the existing TextureAttrib to add the indicated texture.
2895  node()->set_attrib(tsa->add_on_stage(stage, tex, priority), sg_priority);
2896 
2897  } else {
2898  // Create a new TextureAttrib for this node.
2899  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
2900  node()->set_attrib(tsa->add_on_stage(stage, tex, priority));
2901  }
2902 }
2903 
2904 /**
2905  * Adds the indicated texture to the list of textures that will be rendered on
2906  * the default texture stage.
2907  *
2908  * The given sampler state will override the sampling settings on the texture
2909  * itself. Note that this method makes a copy of the sampler settings that
2910  * you give; further changes to this object will not be reflected.
2911  *
2912  * This is the convenience single-texture variant of this method; it is now
2913  * superceded by set_texture() that accepts a stage and texture. You may use
2914  * this method if you just want to adjust the default stage.
2915  */
2917 set_texture(Texture *tex, const SamplerState &sampler, int priority) {
2918  nassertv_always(!is_empty());
2920  set_texture(stage, tex, sampler, priority);
2921 }
2922 
2923 /**
2924  * Adds the indicated texture to the list of textures that will be rendered on
2925  * the indicated multitexture stage. If there are multiple texture stages
2926  * specified (possibly on multiple different nodes at different levels), they
2927  * will all be applied to geometry together, according to the stage
2928  * specification set up in the TextureStage object.
2929  *
2930  * The given sampler state will override the sampling settings on the texture
2931  * itself. Note that this method makes a copy of the sampler settings that
2932  * you give; further changes to this object will not be reflected.
2933  */
2935 set_texture(TextureStage *stage, Texture *tex, const SamplerState &sampler, int priority) {
2936  nassertv_always(!is_empty());
2937 
2938  const RenderAttrib *attrib =
2939  node()->get_attrib(TextureAttrib::get_class_slot());
2940  if (attrib != nullptr) {
2941  const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
2942  int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
2943 
2944  // Modify the existing TextureAttrib to add the indicated texture.
2945  node()->set_attrib(tsa->add_on_stage(stage, tex, sampler, priority), sg_priority);
2946 
2947  } else {
2948  // Create a new TextureAttrib for this node.
2949  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
2950  node()->set_attrib(tsa->add_on_stage(stage, tex, sampler, priority));
2951  }
2952 }
2953 
2954 /**
2955  * Sets the geometry at this level and below to render using no texture, on
2956  * any stage. This is different from not specifying a texture; rather, this
2957  * specifically contradicts set_texture() at a higher node level (or, with a
2958  * priority, overrides a set_texture() at a lower level).
2959  */
2961 set_texture_off(int priority) {
2962  nassertv_always(!is_empty());
2963  node()->set_attrib(TextureAttrib::make_all_off(), priority);
2964 }
2965 
2966 /**
2967  * Sets the geometry at this level and below to render using no texture, on
2968  * the indicated stage. This is different from not specifying a texture;
2969  * rather, this specifically contradicts set_texture() at a higher node level
2970  * (or, with a priority, overrides a set_texture() at a lower level).
2971  */
2973 set_texture_off(TextureStage *stage, int priority) {
2974  nassertv_always(!is_empty());
2975 
2976  const RenderAttrib *attrib =
2977  node()->get_attrib(TextureAttrib::get_class_slot());
2978  if (attrib != nullptr) {
2979  const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
2980  int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
2981 
2982  // Modify the existing TextureAttrib to add the indicated texture to the
2983  // "off" list. This also, incidentally, removes it from the "on" list if
2984  // it is there.
2985  node()->set_attrib(tsa->add_off_stage(stage, priority), sg_priority);
2986 
2987  } else {
2988  // Create a new TextureAttrib for this node that turns off the indicated
2989  // stage.
2990  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
2991  node()->set_attrib(tsa->add_off_stage(stage, priority));
2992  }
2993 }
2994 
2995 /**
2996  * Completely removes any texture adjustment that may have been set via
2997  * set_texture() or set_texture_off() from this particular node. This allows
2998  * whatever textures might be otherwise affecting the geometry to show
2999  * instead.
3000  */
3002 clear_texture() {
3003  nassertv_always(!is_empty());
3004  node()->clear_attrib(TextureAttrib::get_class_slot());
3005 }
3006 
3007 /**
3008  * Removes any reference to the indicated texture stage from the NodePath.
3009  */
3011 clear_texture(TextureStage *stage) {
3012  nassertv_always(!is_empty());
3013 
3014  const RenderAttrib *attrib =
3015  node()->get_attrib(TextureAttrib::get_class_slot());
3016  if (attrib != nullptr) {
3017  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, attrib);
3018  tsa = DCAST(TextureAttrib, tsa->remove_on_stage(stage));
3019  tsa = DCAST(TextureAttrib, tsa->remove_off_stage(stage));
3020 
3021  if (tsa->is_identity()) {
3022  node()->clear_attrib(TextureAttrib::get_class_slot());
3023 
3024  } else {
3025  int priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
3026  node()->set_attrib(tsa, priority);
3027  }
3028  }
3029 }
3030 
3031 /**
3032  * Returns true if a texture has been applied to this particular node via
3033  * set_texture(), false otherwise. This is not the same thing as asking
3034  * whether the geometry at this node will be rendered with texturing, as there
3035  * may be a texture in effect from a higher or lower level.
3036  */
3038 has_texture() const {
3039  return get_texture() != nullptr;
3040 }
3041 
3042 /**
3043  * Returns true if texturing has been specifically enabled on this particular
3044  * node for the indicated stage. This means that someone called set_texture()
3045  * on this node with the indicated stage name, or the stage_name is the
3046  * default stage_name, and someone called set_texture() on this node.
3047  */
3049 has_texture(TextureStage *stage) const {
3050  nassertr_always(!is_empty(), false);
3051 
3052  const RenderAttrib *attrib =
3053  node()->get_attrib(TextureAttrib::get_class_slot());
3054  if (attrib != nullptr) {
3055  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3056  return ta->has_on_stage(stage);
3057  }
3058 
3059  return false;
3060 }
3061 
3062 /**
3063  * Returns true if texturing has been specifically disabled on this particular
3064  * node via set_texture_off(), false otherwise. This is not the same thing as
3065  * asking whether the geometry at this node will be rendered untextured, as
3066  * there may be a texture in effect from a higher or lower level.
3067  */
3069 has_texture_off() const {
3070  nassertr_always(!is_empty(), false);
3071  const RenderAttrib *attrib =
3072  node()->get_attrib(TextureAttrib::get_class_slot());
3073  if (attrib != nullptr) {
3074  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3075  return ta->has_all_off();
3076  }
3077 
3078  return false;
3079 }
3080 
3081 /**
3082  * Returns true if texturing has been specifically disabled on this particular
3083  * node for the indicated stage. This means that someone called
3084  * set_texture_off() on this node with the indicated stage name, or that
3085  * someone called set_texture_off() on this node to remove all stages.
3086  */
3088 has_texture_off(TextureStage *stage) const {
3089  nassertr_always(!is_empty(), false);
3090 
3091  const RenderAttrib *attrib =
3092  node()->get_attrib(TextureAttrib::get_class_slot());
3093  if (attrib != nullptr) {
3094  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3095  return ta->has_off_stage(stage);
3096  }
3097 
3098  return false;
3099 }
3100 
3101 /**
3102  * Returns the base-level texture that has been set on this particular node,
3103  * or NULL if no texture has been set. This is not necessarily the texture
3104  * that will be applied to the geometry at or below this level, as another
3105  * texture at a higher or lower level may override.
3106  *
3107  * See also find_texture().
3108  */
3110 get_texture() const {
3111  nassertr_always(!is_empty(), nullptr);
3112  const RenderAttrib *attrib =
3113  node()->get_attrib(TextureAttrib::get_class_slot());
3114  if (attrib != nullptr) {
3115  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3116  return ta->get_texture();
3117  }
3118 
3119  return nullptr;
3120 }
3121 
3122 /**
3123  * Returns the texture that has been set on the indicated stage for this
3124  * particular node, or NULL if no texture has been set for this stage.
3125  */
3127 get_texture(TextureStage *stage) const {
3128  nassertr_always(!is_empty(), nullptr);
3129  const RenderAttrib *attrib =
3130  node()->get_attrib(TextureAttrib::get_class_slot());
3131  if (attrib != nullptr) {
3132  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3133  return ta->get_on_texture(stage);
3134  }
3135 
3136  return nullptr;
3137 }
3138 
3139 /**
3140  * Recursively searches the scene graph for references to the given texture,
3141  * and replaces them with the new texture.
3142  *
3143  * @since 1.10.4
3144  */
3146 replace_texture(Texture *tex, Texture *new_tex) {
3147  nassertv_always(!is_empty());
3148  nassertv(tex != nullptr);
3149  nassertv(new_tex != nullptr);
3150 
3151  r_replace_texture(node(), tex, new_tex);
3152 }
3153 
3154 /**
3155  * Returns the sampler state that has been given for the base-level texture
3156  * that has been set on this particular node. If no sampler state was given,
3157  * this returns the texture's default sampler settings.
3158  *
3159  * It is an error to call this if there is no base-level texture applied to
3160  * this particular node.
3161  */
3163 get_texture_sampler() const {
3165 }
3166 
3167 /**
3168  * Returns the sampler state that has been given for the indicated texture
3169  * stage that has been set on this particular node. If no sampler state was
3170  * given, this returns the texture's default sampler settings.
3171  *
3172  * It is an error to call this if there is no texture set for this stage on
3173  * this particular node.
3174  */
3176 get_texture_sampler(TextureStage *stage) const {
3177  nassertr_always(!is_empty(), SamplerState::get_default());
3178  const RenderAttrib *attrib =
3179  node()->get_attrib(TextureAttrib::get_class_slot());
3180  nassertr_always(attrib != nullptr, SamplerState::get_default());
3181 
3182  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3183  return ta->get_on_sampler(stage);
3184 }
3185 
3186 /**
3187  *
3188  */
3189 void NodePath::
3190 set_shader(const Shader *sha, int priority) {
3191  nassertv_always(!is_empty());
3192 
3193  const RenderAttrib *attrib =
3194  node()->get_attrib(ShaderAttrib::get_class_slot());
3195  if (attrib != nullptr) {
3196  priority = max(priority,
3197  node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
3198  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3199  node()->set_attrib(sa->set_shader(sha, priority));
3200  } else {
3201  // Create a new ShaderAttrib for this node.
3202  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3203  node()->set_attrib(sa->set_shader(sha, priority));
3204  }
3205 }
3206 
3207 /**
3208  *
3209  */
3210 void NodePath::
3211 set_shader_off(int priority) {
3212  set_shader(nullptr, priority);
3213 }
3214 
3215 /**
3216  *
3217  */
3218 void NodePath::
3219 set_shader_auto(int priority) {
3220  nassertv_always(!is_empty());
3221 
3222  const RenderAttrib *attrib =
3223  node()->get_attrib(ShaderAttrib::get_class_slot());
3224  if (attrib != nullptr) {
3225  priority = max(priority,
3226  node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
3227  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3228  node()->set_attrib(sa->set_shader_auto(priority));
3229  } else {
3230  // Create a new ShaderAttrib for this node.
3231  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3232  node()->set_attrib(sa->set_shader_auto(priority));
3233  }
3234 }
3235 
3236 /**
3237  * overloaded for auto shader customization
3238  */
3239 void NodePath::
3240 set_shader_auto(BitMask32 shader_switch, int priority) {
3241  nassertv_always(!is_empty());
3242 
3243  const RenderAttrib *attrib =
3244  node()->get_attrib(ShaderAttrib::get_class_slot());
3245  if (attrib != nullptr) {
3246  priority = max(priority,
3247  node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
3248  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3249  node()->set_attrib(sa->set_shader_auto(shader_switch, priority));
3250  } else {
3251  // Create a new ShaderAttrib for this node.
3252  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3253  node()->set_attrib(sa->set_shader_auto(shader_switch, priority));
3254  }
3255 }
3256 /**
3257  *
3258  */
3259 void NodePath::
3260 clear_shader() {
3261  nassertv_always(!is_empty());
3262 
3263  const RenderAttrib *attrib =
3264  node()->get_attrib(ShaderAttrib::get_class_slot());
3265  if (attrib != nullptr) {
3266  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3267  node()->set_attrib(sa->clear_shader());
3268  }
3269 }
3270 
3271 /**
3272  *
3273  */
3274 const Shader *NodePath::
3275 get_shader() const {
3276  nassertr_always(!is_empty(), nullptr);
3277  const RenderAttrib *attrib =
3278  node()->get_attrib(ShaderAttrib::get_class_slot());
3279  if (attrib != nullptr) {
3280  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3281  return sa->get_shader();
3282  }
3283  return nullptr;
3284 }
3285 
3286 /**
3287  *
3288  */
3289 void NodePath::
3290 set_shader_input(const ShaderInput &inp) {
3291  nassertv_always(!is_empty());
3292 
3293  PandaNode *pnode = node();
3294  const RenderAttrib *attrib =
3295  pnode->get_attrib(ShaderAttrib::get_class_slot());
3296  if (attrib != nullptr) {
3297  const ShaderAttrib *sa = (const ShaderAttrib *)attrib;
3298  pnode->set_attrib(sa->set_shader_input(inp));
3299  } else {
3300  // Create a new ShaderAttrib for this node.
3301  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3302  pnode->set_attrib(sa->set_shader_input(inp));
3303  }
3304 }
3305 
3306 /**
3307  *
3308  */
3309 void NodePath::
3310 set_shader_input(ShaderInput &&inp) {
3311  nassertv_always(!is_empty());
3312 
3313  PandaNode *pnode = node();
3314  const RenderAttrib *attrib =
3315  pnode->get_attrib(ShaderAttrib::get_class_slot());
3316  if (attrib != nullptr) {
3317  const ShaderAttrib *sa = (const ShaderAttrib *)attrib;
3318  pnode->set_attrib(sa->set_shader_input(move(inp)));
3319  } else {
3320  // Create a new ShaderAttrib for this node.
3321  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3322  pnode->set_attrib(sa->set_shader_input(move(inp)));
3323  }
3324 }
3325 
3326 /**
3327  *
3328  */
3329 ShaderInput NodePath::
3330 get_shader_input(CPT_InternalName id) const {
3331  nassertr_always(!is_empty(), ShaderInput::get_blank());
3332 
3333  const RenderAttrib *attrib =
3334  node()->get_attrib(ShaderAttrib::get_class_slot());
3335  if (attrib != nullptr) {
3336  const ShaderAttrib *sa = (const ShaderAttrib *)attrib;
3337  return sa->get_shader_input(id);
3338  }
3339  return ShaderInput::get_blank();
3340 }
3341 
3342 /**
3343  * Returns the geometry instance count, or 0 if disabled. See
3344  * set_instance_count.
3345  */
3347 get_instance_count() const {
3348  nassertr_always(!is_empty(), 0);
3349 
3350  const RenderAttrib *attrib =
3351  node()->get_attrib(ShaderAttrib::get_class_slot());
3352 
3353  if (attrib != nullptr) {
3354  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3355  return sa->get_instance_count();
3356  }
3357 
3358  return 0;
3359 }
3360 
3361 /**
3362  *
3363  */
3364 void NodePath::
3365 clear_shader_input(CPT_InternalName id) {
3366  nassertv_always(!is_empty());
3367 
3368  const RenderAttrib *attrib =
3369  node()->get_attrib(ShaderAttrib::get_class_slot());
3370  if (attrib != nullptr) {
3371  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3372  node()->set_attrib(sa->clear_shader_input(id));
3373  }
3374 }
3375 
3376 /**
3377  * Sets the geometry instance count, or 0 if geometry instancing should be
3378  * disabled. Do not confuse with instanceTo which only applies to animation
3379  * instancing.
3380  */
3382 set_instance_count(int instance_count) {
3383  nassertv_always(!is_empty());
3384 
3385  const RenderAttrib *attrib =
3386  node()->get_attrib(ShaderAttrib::get_class_slot());
3387  if (attrib != nullptr) {
3388  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3389  node()->set_attrib(sa->set_instance_count(instance_count));
3390  } else {
3391  // Create a new ShaderAttrib for this node.
3392  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3393  node()->set_attrib(sa->set_instance_count(instance_count));
3394  }
3395 }
3396 
3397 /**
3398  * Sets the texture matrix on the current node to the indicated transform for
3399  * the given stage.
3400  */
3402 set_tex_transform(TextureStage *stage, const TransformState *transform) {
3403  nassertv_always(!is_empty());
3404 
3405  const RenderAttrib *attrib =
3406  node()->get_attrib(TexMatrixAttrib::get_class_slot());
3407  if (attrib != nullptr) {
3408  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
3409 
3410  // Modify the existing TexMatrixAttrib to add the indicated stage.
3411  node()->set_attrib(tma->add_stage(stage, transform));
3412 
3413  } else {
3414  // Create a new TexMatrixAttrib for this node.
3415  node()->set_attrib(TexMatrixAttrib::make(stage, transform));
3416  }
3417 }
3418 
3419 /**
3420  * Removes all texture matrices from the current node.
3421  */
3424  nassertv_always(!is_empty());
3425  node()->clear_attrib(TexMatrixAttrib::get_class_slot());
3426 }
3427 
3428 /**
3429  * Removes the texture matrix on the current node for the given stage.
3430  */
3433  nassertv_always(!is_empty());
3434 
3435  const RenderAttrib *attrib =
3436  node()->get_attrib(TexMatrixAttrib::get_class_slot());
3437  if (attrib != nullptr) {
3438  CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, attrib);
3439  tma = DCAST(TexMatrixAttrib, tma->remove_stage(stage));
3440 
3441  if (tma->is_empty()) {
3442  node()->clear_attrib(TexMatrixAttrib::get_class_slot());
3443 
3444  } else {
3445  node()->set_attrib(tma);
3446  }
3447  }
3448 }
3449 
3450 /**
3451  * Returns true if there is an explicit texture matrix on the current node for
3452  * the given stage.
3453  */
3455 has_tex_transform(TextureStage *stage) const {
3456  nassertr_always(!is_empty(), false);
3457 
3458  const RenderAttrib *attrib =
3459  node()->get_attrib(TexMatrixAttrib::get_class_slot());
3460  if (attrib != nullptr) {
3461  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
3462  return tma->has_stage(stage);
3463  }
3464 
3465  return false;
3466 }
3467 
3468 /**
3469  * Returns the texture matrix on the current node for the given stage, or
3470  * identity transform if there is no explicit transform set for the given
3471  * stage.
3472  */
3473 CPT(TransformState) NodePath::
3474 get_tex_transform(TextureStage *stage) const {
3475  nassertr_always(!is_empty(), nullptr);
3476 
3477  const RenderAttrib *attrib =
3478  node()->get_attrib(TexMatrixAttrib::get_class_slot());
3479  if (attrib != nullptr) {
3480  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
3481  return tma->get_transform(stage);
3482  }
3483 
3484  return TransformState::make_identity();
3485 }
3486 
3487 /**
3488  * Sets the texture matrix on the current node to the indicated transform for
3489  * the given stage.
3490  */
3491 void NodePath::
3492 set_tex_transform(const NodePath &other, TextureStage *stage, const TransformState *transform) {
3493  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
3494  nassertv_always(!is_empty());
3495 
3496  CPT(RenderState) state = get_state(other);
3497  const RenderAttrib *attrib =
3498  state->get_attrib(TexMatrixAttrib::get_class_slot());
3499  if (attrib != nullptr) {
3500  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
3501 
3502  // Modify the existing TexMatrixAttrib to add the indicated stage.
3503  state = state->add_attrib(tma->add_stage(stage, transform));
3504 
3505  } else {
3506  // Create a new TexMatrixAttrib for this node.
3507  state = state->add_attrib(TexMatrixAttrib::make(stage, transform));
3508  }
3509 
3510  // Now compose that with our parent's state.
3511  CPT(RenderState) rel_state;
3512  if (has_parent()) {
3513  rel_state = other.get_state(get_parent());
3514  } else {
3515  rel_state = other.get_state(NodePath());
3516  }
3517  CPT(RenderState) new_state = rel_state->compose(state);
3518 
3519  // And apply only the TexMatrixAttrib to the current node, leaving the
3520  // others unchanged.
3521  node()->set_attrib(new_state->get_attrib(TexMatrixAttrib::get_class_slot()));
3522 }
3523 
3524 /**
3525  * Returns the texture matrix on the current node for the given stage,
3526  * relative to the other node.
3527  */
3528 CPT(TransformState) NodePath::
3529 get_tex_transform(const NodePath &other, TextureStage *stage) const {
3530  nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
3531 
3532  CPT(RenderState) state = get_state(other);
3533  const RenderAttrib *attrib =
3534  state->get_attrib(TexMatrixAttrib::get_class_slot());
3535  if (attrib != nullptr) {
3536  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
3537  return tma->get_transform(stage);
3538  }
3539 
3540  return TransformState::make_identity();
3541 }
3542 
3543 /**
3544  * Enables automatic texture coordinate generation for the indicated texture
3545  * stage.
3546  */
3547 void NodePath::
3548 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) {
3549  nassertv_always(!is_empty());
3550 
3551  const RenderAttrib *attrib =
3552  node()->get_attrib(TexGenAttrib::get_class_slot());
3553 
3554  CPT(TexGenAttrib) tga;
3555 
3556  if (attrib != nullptr) {
3557  priority = max(priority,
3558  node()->get_state()->get_override(TextureAttrib::get_class_slot()));
3559  tga = DCAST(TexGenAttrib, attrib);
3560 
3561  } else {
3562  tga = DCAST(TexGenAttrib, TexGenAttrib::make());
3563  }
3564 
3565  node()->set_attrib(tga->add_stage(stage, mode), priority);
3566 }
3567 
3568 /**
3569  * Enables automatic texture coordinate generation for the indicated texture
3570  * stage. This version of this method is useful when setting M_constant,
3571  * which requires a constant texture coordinate value.
3572  */
3573 void NodePath::
3574 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode,
3575  const LTexCoord3 &constant_value, int priority) {
3576  nassertv_always(!is_empty());
3577 
3578  const RenderAttrib *attrib =
3579  node()->get_attrib(TexGenAttrib::get_class_slot());
3580 
3581  CPT(TexGenAttrib) tga;
3582 
3583  if (attrib != nullptr) {
3584  priority = max(priority,
3585  node()->get_state()->get_override(TextureAttrib::get_class_slot()));
3586  tga = DCAST(TexGenAttrib, attrib);
3587 
3588  } else {
3589  tga = DCAST(TexGenAttrib, TexGenAttrib::make());
3590  }
3591 
3592  node()->set_attrib(tga->add_stage(stage, mode, constant_value), priority);
3593 }
3594 
3595 /**
3596  * Removes the texture coordinate generation mode from all texture stages on
3597  * this node.
3598  */
3600 clear_tex_gen() {
3601  nassertv_always(!is_empty());
3602  node()->clear_attrib(TexGenAttrib::get_class_slot());
3603 }
3604 
3605 /**
3606  * Disables automatic texture coordinate generation for the indicated texture
3607  * stage.
3608  */
3610 clear_tex_gen(TextureStage *stage) {
3611  nassertv_always(!is_empty());
3612 
3613  const RenderAttrib *attrib =
3614  node()->get_attrib(TexGenAttrib::get_class_slot());
3615  if (attrib != nullptr) {
3616  CPT(TexGenAttrib) tga = DCAST(TexGenAttrib, attrib);
3617  tga = DCAST(TexGenAttrib, tga->remove_stage(stage));
3618 
3619  if (tga->is_empty()) {
3620  node()->clear_attrib(TexGenAttrib::get_class_slot());
3621 
3622  } else {
3623  node()->set_attrib(tga);
3624  }
3625  }
3626 }
3627 
3628 /**
3629  * Returns true if there is a mode for automatic texture coordinate generation
3630  * on the current node for the given stage.
3631  */
3633 has_tex_gen(TextureStage *stage) const {
3634  nassertr_always(!is_empty(), false);
3635 
3636  const RenderAttrib *attrib =
3637  node()->get_attrib(TexGenAttrib::get_class_slot());
3638  if (attrib != nullptr) {
3639  const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
3640  return tga->has_stage(stage);
3641  }
3642 
3643  return false;
3644 }
3645 
3646 /**
3647  * Returns the texture coordinate generation mode for the given stage, or
3648  * M_off if there is no explicit mode set for the given stage.
3649  */
3650 RenderAttrib::TexGenMode NodePath::
3651 get_tex_gen(TextureStage *stage) const {
3652  nassertr_always(!is_empty(), TexGenAttrib::M_off);
3653 
3654  const RenderAttrib *attrib =
3655  node()->get_attrib(TexGenAttrib::get_class_slot());
3656  if (attrib != nullptr) {
3657  const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
3658  return tga->get_mode(stage);
3659  }
3660 
3661  return TexGenAttrib::M_off;
3662 }
3663 
3664 /**
3665  * Establishes a TexProjectorEffect on this node, which can be used to
3666  * establish projective texturing (but see also the
3667  * NodePath::project_texture() convenience function), or it can be used to
3668  * bind this node's texture transform to particular node's position in space,
3669  * allowing a LerpInterval (for instance) to adjust this node's texture
3670  * coordinates.
3671  *
3672  * If to is a LensNode, then the fourth parameter, lens_index, can be provided
3673  * to select a particular lens to apply. Otherwise lens_index is not used.
3674  */
3676 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to,
3677  int lens_index) {
3678  nassertv_always(!is_empty());
3679 
3680  const RenderEffect *effect =
3681  node()->get_effect(TexProjectorEffect::get_class_type());
3682 
3683  CPT(TexProjectorEffect) tpe;
3684 
3685  if (effect != nullptr) {
3686  tpe = DCAST(TexProjectorEffect, effect);
3687 
3688  } else {
3689  tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make());
3690  }
3691 
3692  node()->set_effect(tpe->add_stage(stage, from, to, lens_index));
3693 }
3694 
3695 /**
3696  * Removes the TexProjectorEffect for the indicated stage from this node.
3697  */
3700  nassertv_always(!is_empty());
3701 
3702  const RenderEffect *effect =
3703  node()->get_effect(TexProjectorEffect::get_class_type());
3704  if (effect != nullptr) {
3705  CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect);
3706  tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage));
3707 
3708  if (tpe->is_empty()) {
3709  node()->clear_effect(TexProjectorEffect::get_class_type());
3710 
3711  } else {
3712  node()->set_effect(tpe);
3713  }
3714  }
3715 }
3716 
3717 /**
3718  * Removes the TexProjectorEffect for all stages from this node.
3719  */
3722  nassertv_always(!is_empty());
3723  node()->clear_effect(TexProjectorEffect::get_class_type());
3724 }
3725 
3726 /**
3727  * Returns true if this node has a TexProjectorEffect for the indicated stage,
3728  * false otherwise.
3729  */
3731 has_tex_projector(TextureStage *stage) const {
3732  nassertr_always(!is_empty(), false);
3733 
3734  const RenderEffect *effect =
3735  node()->get_effect(TexProjectorEffect::get_class_type());
3736  if (effect != nullptr) {
3737  const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
3738  return tpe->has_stage(stage);
3739  }
3740 
3741  return false;
3742 }
3743 
3744 /**
3745  * Returns the "from" node associated with the TexProjectorEffect on the
3746  * indicated stage. The relative transform between the "from" and the "to"
3747  * nodes is automatically applied to the texture transform each frame.
3748  */
3750 get_tex_projector_from(TextureStage *stage) const {
3751  nassertr_always(!is_empty(), NodePath::fail());
3752 
3753  const RenderEffect *effect =
3754  node()->get_effect(TexProjectorEffect::get_class_type());
3755  if (effect != nullptr) {
3756  const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
3757  return tpe->get_from(stage);
3758  }
3759 
3760  return NodePath::not_found();
3761 }
3762 
3763 /**
3764  * Returns the "to" node associated with the TexProjectorEffect on the
3765  * indicated stage. The relative transform between the "from" and the "to"
3766  * nodes is automatically applied to the texture transform each frame.
3767  */
3769 get_tex_projector_to(TextureStage *stage) const {
3770  nassertr_always(!is_empty(), NodePath::fail());
3771 
3772  const RenderEffect *effect =
3773  node()->get_effect(TexProjectorEffect::get_class_type());
3774  if (effect != nullptr) {
3775  const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
3776  return tpe->get_to(stage);
3777  }
3778 
3779  return NodePath::not_found();
3780 }
3781 
3782 /**
3783  * A convenience function to enable projective texturing at this node level
3784  * and below, using the indicated NodePath (which should contain a LensNode)
3785  * as the projector.
3786  */
3788 project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) {
3789  nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type()));
3790  set_texture(stage, tex);
3791  set_tex_gen(stage, TexGenAttrib::M_world_position);
3792  set_tex_projector(stage, NodePath(), projector);
3793 }
3794 
3795 /**
3796  * Returns true if there are at least some vertices at this node and below
3797  * that contain a reference to the indicated vertex data column name, false
3798  * otherwise.
3799  *
3800  * This is particularly useful for testing whether a particular model has a
3801  * given texture coordinate set (but see has_texcoord()).
3802  */
3804 has_vertex_column(const InternalName *name) const {
3805  nassertr_always(!is_empty(), false);
3806  return r_has_vertex_column(node(), name);
3807 }
3808 
3809 /**
3810  * Returns a list of all vertex array columns stored on some geometry found at
3811  * this node level and below.
3812  */
3814 find_all_vertex_columns() const {
3815  nassertr_always(!is_empty(), InternalNameCollection());
3816  InternalNames vertex_columns;
3817  r_find_all_vertex_columns(node(), vertex_columns);
3818 
3820  InternalNames::iterator ti;
3821  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
3822  tc.add_name(*ti);
3823  }
3824  return tc;
3825 }
3826 
3827 /**
3828  * Returns a list of all vertex array columns stored on some geometry found at
3829  * this node level and below that match the indicated name (which may contain
3830  * wildcard characters).
3831  */
3833 find_all_vertex_columns(const string &name) const {
3834  nassertr_always(!is_empty(), InternalNameCollection());
3835  InternalNames vertex_columns;
3836  r_find_all_vertex_columns(node(), vertex_columns);
3837 
3838  GlobPattern glob(name);
3839 
3841  InternalNames::iterator ti;
3842  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
3843  const InternalName *name = (*ti);
3844  if (glob.matches(name->get_name())) {
3845  tc.add_name(name);
3846  }
3847  }
3848  return tc;
3849 }
3850 
3851 /**
3852  * Returns a list of all texture coordinate sets used by any geometry at this
3853  * node level and below.
3854  */
3856 find_all_texcoords() const {
3857  nassertr_always(!is_empty(), InternalNameCollection());
3858  InternalNames vertex_columns;
3859  r_find_all_vertex_columns(node(), vertex_columns);
3860 
3861  CPT(InternalName) texcoord_name = InternalName::get_texcoord();
3862 
3864  InternalNames::iterator ti;
3865  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
3866  if ((*ti)->get_top() == texcoord_name) {
3867  tc.add_name(*ti);
3868  }
3869  }
3870  return tc;
3871 }
3872 
3873 /**
3874  * Returns a list of all texture coordinate sets used by any geometry at this
3875  * node level and below that match the indicated name (which may contain
3876  * wildcard characters).
3877  */
3879 find_all_texcoords(const string &name) const {
3880  nassertr_always(!is_empty(), InternalNameCollection());
3881  InternalNames vertex_columns;
3882  r_find_all_vertex_columns(node(), vertex_columns);
3883 
3884  GlobPattern glob(name);
3885  CPT_InternalName texcoord_name = InternalName::get_texcoord();
3886 
3888  InternalNames::iterator ti;
3889  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
3890  const InternalName *name = (*ti);
3891  if (name->get_top() == texcoord_name) {
3892  // This is a texture coordinate name. Figure out the basename of the
3893  // texture coordinates.
3894  int index = name->find_ancestor("texcoord");
3895  nassertr(index != -1, InternalNameCollection());
3896  string net_basename = name->get_net_basename(index - 1);
3897 
3898  if (glob.matches(net_basename)) {
3899  tc.add_name(name);
3900  }
3901  }
3902  }
3903  return tc;
3904 }
3905 
3906 /**
3907  * Returns the first texture found applied to geometry at this node or below
3908  * that matches the indicated name (which may contain wildcards). Returns the
3909  * texture if it is found, or NULL if it is not.
3910  */
3912 find_texture(const string &name) const {
3913  nassertr_always(!is_empty(), nullptr);
3914  GlobPattern glob(name);
3915  return r_find_texture(node(), get_net_state(), glob);
3916 }
3917 
3918 /**
3919  * Returns the first texture found applied to geometry at this node or below
3920  * that is assigned to the indicated texture stage. Returns the texture if it
3921  * is found, or NULL if it is not.
3922  */
3924 find_texture(TextureStage *stage) const {
3925  nassertr_always(!is_empty(), nullptr);
3926  return r_find_texture(node(), stage);
3927 }
3928 
3929 /**
3930  * Returns a list of a textures applied to geometry at this node and below.
3931  */
3933 find_all_textures() const {
3934  nassertr_always(!is_empty(), TextureCollection());
3935  Textures textures;
3936  r_find_all_textures(node(), get_net_state(), textures);
3937 
3938  TextureCollection tc;
3939  Textures::iterator ti;
3940  for (ti = textures.begin(); ti != textures.end(); ++ti) {
3941  tc.add_texture(*ti);
3942  }
3943  return tc;
3944 }
3945 
3946 /**
3947  * Returns a list of a textures applied to geometry at this node and below
3948  * that match the indicated name (which may contain wildcard characters).
3949  */
3951 find_all_textures(const string &name) const {
3952  nassertr_always(!is_empty(), TextureCollection());
3953  Textures textures;
3954  r_find_all_textures(node(), get_net_state(), textures);
3955 
3956  GlobPattern glob(name);
3957 
3958  TextureCollection tc;
3959  Textures::iterator ti;
3960  for (ti = textures.begin(); ti != textures.end(); ++ti) {
3961  Texture *texture = (*ti);
3962  if (glob.matches(texture->get_name())) {
3963  tc.add_texture(texture);
3964  }
3965  }
3966  return tc;
3967 }
3968 
3969 /**
3970  * Returns a list of a textures on geometry at this node and below that are
3971  * assigned to the indicated texture stage.
3972  */
3974 find_all_textures(TextureStage *stage) const {
3975  nassertr_always(!is_empty(), TextureCollection());
3976  Textures textures;
3977  r_find_all_textures(node(), stage, textures);
3978 
3979  TextureCollection tc;
3980  Textures::iterator ti;
3981  for (ti = textures.begin(); ti != textures.end(); ++ti) {
3982  Texture *texture = (*ti);
3983  tc.add_texture(texture);
3984  }
3985  return tc;
3986 }
3987 
3988 /**
3989  * Returns the first TextureStage found applied to geometry at this node or
3990  * below that matches the indicated name (which may contain wildcards).
3991  * Returns the TextureStage if it is found, or NULL if it is not.
3992  */
3994 find_texture_stage(const string &name) const {
3995  nassertr_always(!is_empty(), nullptr);
3996  GlobPattern glob(name);
3997  return r_find_texture_stage(node(), get_net_state(), glob);
3998 }
3999 
4000 /**
4001  * Returns a list of a TextureStages applied to geometry at this node and
4002  * below.
4003  */
4005 find_all_texture_stages() const {
4006  nassertr_always(!is_empty(), TextureStageCollection());
4007  TextureStages texture_stages;
4008  r_find_all_texture_stages(node(), get_net_state(), texture_stages);
4009 
4011  TextureStages::iterator ti;
4012  for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
4013  tc.add_texture_stage(*ti);
4014  }
4015  return tc;
4016 }
4017 
4018 /**
4019  * Searches through all TextureStages at this node and below. Any
4020  * TextureStages that share the same name as the indicated TextureStage object
4021  * are replaced with this object, thus ensuring that all geometry at this node
4022  * and below with a particular TextureStage name is using the same
4023  * TextureStage object.
4024  */
4027  nassertv_always(!is_empty());
4028  r_unify_texture_stages(node(), stage);
4029 }
4030 
4031 /**
4032  * Returns a list of a TextureStages applied to geometry at this node and
4033  * below that match the indicated name (which may contain wildcard
4034  * characters).
4035  */
4037 find_all_texture_stages(const string &name) const {
4038  nassertr_always(!is_empty(), TextureStageCollection());
4039  TextureStages texture_stages;
4040  r_find_all_texture_stages(node(), get_net_state(), texture_stages);
4041 
4042  GlobPattern glob(name);
4043 
4045  TextureStages::iterator ti;
4046  for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
4047  TextureStage *texture_stage = (*ti);
4048  if (glob.matches(texture_stage->get_name())) {
4049  tc.add_texture_stage(texture_stage);
4050  }
4051  }
4052  return tc;
4053 }
4054 
4055 /**
4056  * Returns the first material found applied to geometry at this node or below
4057  * that matches the indicated name (which may contain wildcards). Returns the
4058  * material if it is found, or NULL if it is not.
4059  */
4061 find_material(const string &name) const {
4062  nassertr_always(!is_empty(), nullptr);
4063  GlobPattern glob(name);
4064  return r_find_material(node(), get_net_state(), glob);
4065 }
4066 
4067 /**
4068  * Returns a list of a materials applied to geometry at this node and below.
4069  */
4071 find_all_materials() const {
4072  nassertr_always(!is_empty(), MaterialCollection());
4073  Materials materials;
4074  r_find_all_materials(node(), get_net_state(), materials);
4075 
4076  MaterialCollection tc;
4077  Materials::iterator ti;
4078  for (ti = materials.begin(); ti != materials.end(); ++ti) {
4079  tc.add_material(*ti);
4080  }
4081  return tc;
4082 }
4083 
4084 /**
4085  * Returns a list of a materials applied to geometry at this node and below
4086  * that match the indicated name (which may contain wildcard characters).
4087  */
4089 find_all_materials(const string &name) const {
4090  nassertr_always(!is_empty(), MaterialCollection());
4091  Materials materials;
4092  r_find_all_materials(node(), get_net_state(), materials);
4093 
4094  GlobPattern glob(name);
4095 
4096  MaterialCollection tc;
4097  Materials::iterator ti;
4098  for (ti = materials.begin(); ti != materials.end(); ++ti) {
4099  Material *material = (*ti);
4100  if (glob.matches(material->get_name())) {
4101  tc.add_material(material);
4102  }
4103  }
4104  return tc;
4105 }
4106 
4107 /**
4108  * Sets the geometry at this level and below to render using the indicated
4109  * material.
4110  *
4111  * Previously, this operation made a copy of the material structure, but
4112  * nowadays it assigns the pointer directly.
4113  */
4115 set_material(Material *mat, int priority) {
4116  nassertv_always(!is_empty());
4117  nassertv(mat != nullptr);
4118  node()->set_attrib(MaterialAttrib::make(mat), priority);
4119 }
4120 
4121 /**
4122  * Sets the geometry at this level and below to render using no material.
4123  * This is normally the default, but it may be useful to use this to
4124  * contradict set_material() at a higher node level (or, with a priority, to
4125  * override a set_material() at a lower level).
4126  */
4128 set_material_off(int priority) {
4129  nassertv_always(!is_empty());
4130  node()->set_attrib(MaterialAttrib::make_off(), priority);
4131 }
4132 
4133 /**
4134  * Completely removes any material adjustment that may have been set via
4135  * set_material() from this particular node.
4136  */
4138 clear_material() {
4139  nassertv_always(!is_empty());
4140  node()->clear_attrib(MaterialAttrib::get_class_slot());
4141 }
4142 
4143 /**
4144  * Returns true if a material has been applied to this particular node via
4145  * set_material(), false otherwise.
4146  */
4148 has_material() const {
4149  nassertr_always(!is_empty(), false);
4150  const RenderAttrib *attrib =
4151  node()->get_attrib(MaterialAttrib::get_class_slot());
4152  if (attrib != nullptr) {
4153  const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
4154  return !ma->is_off();
4155  }
4156 
4157  return false;
4158 }
4159 
4160 /**
4161  * Returns the material that has been set on this particular node, or NULL if
4162  * no material has been set. This is not necessarily the material that will
4163  * be applied to the geometry at or below this level, as another material at a
4164  * higher or lower level may override.
4165  *
4166  * See also find_material().
4167  */
4168 PT(Material) NodePath::
4169 get_material() const {
4170  nassertr_always(!is_empty(), nullptr);
4171  const RenderAttrib *attrib =
4172  node()->get_attrib(MaterialAttrib::get_class_slot());
4173  if (attrib != nullptr) {
4174  const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
4175  return ma->get_material();
4176  }
4177 
4178  return nullptr;
4179 }
4180 
4181 /**
4182  * Recursively searches the scene graph for references to the given material,
4183  * and replaces them with the new material.
4184  */
4185 void NodePath::
4186 replace_material(Material *mat, Material *new_mat) {
4187  nassertv_always(!is_empty());
4188  nassertv(mat != nullptr);
4189  nassertv(new_mat != nullptr);
4190 
4191  CPT(RenderAttrib) new_attrib = MaterialAttrib::make(new_mat);
4192  r_replace_material(node(), mat, (const MaterialAttrib *)new_attrib.p());
4193 }
4194 
4195 /**
4196  * Sets the geometry at this level and below to render using the indicated
4197  * fog.
4198  */
4200 set_fog(Fog *fog, int priority) {
4201  nassertv_always(!is_empty());
4202  node()->set_attrib(FogAttrib::make(fog), priority);
4203 }
4204 
4205 /**
4206  * Sets the geometry at this level and below to render using no fog. This is
4207  * normally the default, but it may be useful to use this to contradict
4208  * set_fog() at a higher node level (or, with a priority, to override a
4209  * set_fog() at a lower level).
4210  */
4212 set_fog_off(int priority) {
4213  nassertv_always(!is_empty());
4214  node()->set_attrib(FogAttrib::make_off(), priority);
4215 }
4216 
4217 /**
4218  * Completely removes any fog adjustment that may have been set via set_fog()
4219  * or set_fog_off() from this particular node. This allows whatever fogs
4220  * might be otherwise affecting the geometry to show instead.
4221  */
4223 clear_fog() {
4224  nassertv_always(!is_empty());
4225  node()->clear_attrib(FogAttrib::get_class_slot());
4226 }
4227 
4228 /**
4229  * Returns true if a fog has been applied to this particular node via
4230  * set_fog(), false otherwise. This is not the same thing as asking whether
4231  * the geometry at this node will be rendered with fog, as there may be a fog
4232  * in effect from a higher or lower level.
4233  */
4235 has_fog() const {
4236  nassertr_always(!is_empty(), false);
4237  const RenderAttrib *attrib =
4238  node()->get_attrib(FogAttrib::get_class_slot());
4239  if (attrib != nullptr) {
4240  const FogAttrib *fa = DCAST(FogAttrib, attrib);
4241  return !fa->is_off();
4242  }
4243 
4244  return false;
4245 }
4246 
4247 /**
4248  * Returns true if a fog has been specifically disabled on this particular
4249  * node via set_fog_off(), false otherwise. This is not the same thing as
4250  * asking whether the geometry at this node will be rendered unfogged, as
4251  * there may be a fog in effect from a higher or lower level.
4252  */
4254 has_fog_off() const {
4255  nassertr_always(!is_empty(), false);
4256  const RenderAttrib *attrib =
4257  node()->get_attrib(FogAttrib::get_class_slot());
4258  if (attrib != nullptr) {
4259  const FogAttrib *fa = DCAST(FogAttrib, attrib);
4260  return fa->is_off();
4261  }
4262 
4263  return false;
4264 }
4265 
4266 /**
4267  * Returns the fog that has been set on this particular node, or NULL if no
4268  * fog has been set. This is not necessarily the fog that will be applied to
4269  * the geometry at or below this level, as another fog at a higher or lower
4270  * level may override.
4271  */
4273 get_fog() const {
4274  nassertr_always(!is_empty(), nullptr);
4275  const RenderAttrib *attrib =
4276  node()->get_attrib(FogAttrib::get_class_slot());
4277  if (attrib != nullptr) {
4278  const FogAttrib *fa = DCAST(FogAttrib, attrib);
4279  return fa->get_fog();
4280  }
4281 
4282  return nullptr;
4283 }
4284 
4285 /**
4286  * Sets up the geometry at this level and below (unless overridden) to render
4287  * in wireframe mode.
4288  */
4290 set_render_mode_wireframe(int priority) {
4291  nassertv_always(!is_empty());
4292  const RenderModeAttrib *rma;
4293  node()->get_state()->get_attrib_def(rma);
4294  node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, rma->get_thickness(), rma->get_perspective()), priority);
4295 }
4296 
4297 /**
4298  * Sets up the geometry at this level and below (unless overridden) to render
4299  * in filled (i.e. not wireframe) mode.
4300  */
4302 set_render_mode_filled(int priority) {
4303  nassertv_always(!is_empty());
4304  const RenderModeAttrib *rma;
4305  node()->get_state()->get_attrib_def(rma);
4306  node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, rma->get_thickness(), rma->get_perspective()), priority);
4307 }
4308 
4309 /**
4310  * Sets up the geometry at this level and below (unless overridden) to render
4311  * in filled, but overlay the wireframe on top with a fixed color. This is
4312  * useful for debug visualizations.
4313  */
4315 set_render_mode_filled_wireframe(const LColor &wireframe_color, int priority) {
4316  nassertv_always(!is_empty());
4317  const RenderModeAttrib *rma;
4318  node()->get_state()->get_attrib_def(rma);
4319  node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled_wireframe, rma->get_thickness(), rma->get_perspective(), wireframe_color), priority);
4320 }
4321 
4322 /**
4323  * Sets up the point geometry at this level and below to render as perspective
4324  * sprites (that is, billboarded quads). The thickness, as specified with
4325  * set_render_mode_thickness(), is the width of each point in 3-D units,
4326  * unless it is overridden on a per-vertex basis. This does not affect
4327  * geometry other than points.
4328  *
4329  * If you want the quads to be individually textured, you should also set a
4330  * TexGenAttrib::M_point_sprite on the node.
4331  */
4333 set_render_mode_perspective(bool perspective, int priority) {
4334  nassertv_always(!is_empty());
4335  const RenderModeAttrib *rma;
4336  node()->get_state()->get_attrib_def(rma);
4337  node()->set_attrib(RenderModeAttrib::make(rma->get_mode(), rma->get_thickness(), perspective, rma->get_wireframe_color()), priority);
4338 }
4339 
4340 /**
4341  * Sets up the point geometry at this level and below to render as thick
4342  * points (that is, billboarded quads). The thickness is in pixels, unless
4343  * set_render_mode_perspective is also true, in which case it is in 3-D units.
4344  *
4345  * If you want the quads to be individually textured, you should also set a
4346  * TexGenAttrib::M_point_sprite on the node.
4347  */
4349 set_render_mode_thickness(PN_stdfloat thickness, int priority) {
4350  nassertv_always(!is_empty());
4351  const RenderModeAttrib *rma;
4352  node()->get_state()->get_attrib_def(rma);
4353  node()->set_attrib(RenderModeAttrib::make(rma->get_mode(), thickness, rma->get_perspective(), rma->get_wireframe_color()), priority);
4354 }
4355 
4356 /**
4357  * Sets up the geometry at this level and below (unless overridden) to render
4358  * in the specified mode and with the indicated line and/or point thickness.
4359  */
4361 set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority) {
4362  nassertv_always(!is_empty());
4363 
4364  node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority);
4365 }
4366 
4367 /**
4368  * Completely removes any render mode adjustment that may have been set on
4369  * this node via set_render_mode_wireframe() or set_render_mode_filled().
4370  */
4373  nassertv_always(!is_empty());
4374  node()->clear_attrib(RenderModeAttrib::get_class_slot());
4375 }
4376 
4377 /**
4378  * Returns true if a render mode has been explicitly set on this particular
4379  * node via set_render_mode() (or set_render_mode_wireframe() or
4380  * set_render_mode_filled()), false otherwise.
4381  */
4383 has_render_mode() const {
4384  nassertr_always(!is_empty(), false);
4385  return node()->has_attrib(RenderModeAttrib::get_class_slot());
4386 }
4387 
4388 /**
4389  * Returns the render mode that has been specifically set on this node via
4390  * set_render_mode(), or M_unchanged if nothing has been set.
4391  */
4392 RenderModeAttrib::Mode NodePath::
4393 get_render_mode() const {
4394  nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged);
4395  const RenderAttrib *attrib =
4396  node()->get_attrib(RenderModeAttrib::get_class_slot());
4397  if (attrib != nullptr) {
4398  const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
4399  return ta->get_mode();
4400  }
4401 
4402  return RenderModeAttrib::M_unchanged;
4403 }
4404 
4405 /**
4406  * Returns the render mode thickness that has been specifically set on this
4407  * node via set_render_mode(), or 1.0 if nothing has been set.
4408  */
4409 PN_stdfloat NodePath::
4410 get_render_mode_thickness() const {
4411  nassertr_always(!is_empty(), 0.0f);
4412  const RenderAttrib *attrib =
4413  node()->get_attrib(RenderModeAttrib::get_class_slot());
4414  if (attrib != nullptr) {
4415  const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
4416  return ta->get_thickness();
4417  }
4418 
4419  return 1.0f;
4420 }
4421 
4422 /**
4423  * Returns the flag that has been set on this node via
4424  * set_render_mode_perspective(), or false if no flag has been set.
4425  */
4428  nassertr_always(!is_empty(), 0.0f);
4429  const RenderAttrib *attrib =
4430  node()->get_attrib(RenderModeAttrib::get_class_slot());
4431  if (attrib != nullptr) {
4432  const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
4433  return ta->get_perspective();
4434  }
4435 
4436  return false;
4437 }
4438 
4439 /**
4440  * Specifically sets or disables two-sided rendering mode on this particular
4441  * node. If no other nodes override, this will cause backfacing polygons to
4442  * be drawn (in two-sided mode, true) or culled (in one-sided mode, false).
4443  */
4445 set_two_sided(bool two_sided, int priority) {
4446  nassertv_always(!is_empty());
4447 
4448  CullFaceAttrib::Mode mode =
4449  two_sided ?
4450  CullFaceAttrib::M_cull_none :
4451  CullFaceAttrib::M_cull_clockwise;
4452 
4453  node()->set_attrib(CullFaceAttrib::make(mode), priority);
4454 }
4455 
4456 /**
4457  * Completely removes any two-sided adjustment that may have been set on this
4458  * node via set_two_sided(). The geometry at this level and below will
4459  * subsequently be rendered either two-sided or one-sided, according to
4460  * whatever other nodes may have had set_two_sided() on it, or according to
4461  * the initial state otherwise.
4462  */
4464 clear_two_sided() {
4465  nassertv_always(!is_empty());
4466  node()->clear_attrib(CullFaceAttrib::get_class_slot());
4467 }
4468 
4469 /**
4470  * Returns true if a two-sided adjustment has been explicitly set on this
4471  * particular node via set_two_sided(). If this returns true, then
4472  * get_two_sided() may be called to determine which has been set.
4473  */
4475 has_two_sided() const {
4476  nassertr_always(!is_empty(), false);
4477  return node()->has_attrib(CullFaceAttrib::get_class_slot());
4478 }
4479 
4480 /**
4481  * Returns true if two-sided rendering has been specifically set on this node
4482  * via set_two_sided(), or false if one-sided rendering has been specifically
4483  * set, or if nothing has been specifically set. See also has_two_sided().
4484  * This does not necessarily imply that the geometry will or will not be
4485  * rendered two-sided, as there may be other nodes that override.
4486  */
4488 get_two_sided() const {
4489  nassertr_always(!is_empty(), false);
4490  const RenderAttrib *attrib =
4491  node()->get_attrib(CullFaceAttrib::get_class_slot());
4492  if (attrib != nullptr) {
4493  const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
4494  return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
4495  }
4496 
4497  return false;
4498 }
4499 
4500 /**
4501  * Specifically sets or disables the testing of the depth buffer on this
4502  * particular node. This is normally on in the 3-d scene graph and off in the
4503  * 2-d scene graph; it should be on for rendering most 3-d objects properly.
4504  */
4506 set_depth_test(bool depth_test, int priority) {
4507  nassertv_always(!is_empty());
4508 
4509  DepthTestAttrib::PandaCompareFunc mode =
4510  depth_test ?
4511  DepthTestAttrib::M_less :
4512  DepthTestAttrib::M_none;
4513 
4514  node()->set_attrib(DepthTestAttrib::make(mode), priority);
4515 }
4516 
4517 /**
4518  * Completely removes any depth-test adjustment that may have been set on this
4519  * node via set_depth_test().
4520  */
4522 clear_depth_test() {
4523  nassertv_always(!is_empty());
4524  node()->clear_attrib(DepthTestAttrib::get_class_slot());
4525 }
4526 
4527 /**
4528  * Returns true if a depth-test adjustment has been explicitly set on this
4529  * particular node via set_depth_test(). If this returns true, then
4530  * get_depth_test() may be called to determine which has been set.
4531  */
4533 has_depth_test() const {
4534  nassertr_always(!is_empty(), false);
4535  return node()->has_attrib(DepthTestAttrib::get_class_slot());
4536 }
4537 
4538 /**
4539  * Returns true if depth-test rendering has been specifically set on this node
4540  * via set_depth_test(), or false if depth-test rendering has been
4541  * specifically disabled. If nothing has been specifically set, returns true.
4542  * See also has_depth_test().
4543  */
4545 get_depth_test() const {
4546  nassertr_always(!is_empty(), false);
4547  const RenderAttrib *attrib =
4548  node()->get_attrib(DepthTestAttrib::get_class_slot());
4549  if (attrib != nullptr) {
4550  const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
4551  return (dta->get_mode() != DepthTestAttrib::M_none);
4552  }
4553 
4554  return true;
4555 }
4556 
4557 /**
4558  * Specifically sets or disables the writing to the depth buffer on this
4559  * particular node. This is normally on in the 3-d scene graph and off in the
4560  * 2-d scene graph; it should be on for rendering most 3-d objects properly.
4561  */
4563 set_depth_write(bool depth_write, int priority) {
4564  nassertv_always(!is_empty());
4565 
4566  DepthWriteAttrib::Mode mode =
4567  depth_write ?
4568  DepthWriteAttrib::M_on :
4569  DepthWriteAttrib::M_off;
4570 
4571  node()->set_attrib(DepthWriteAttrib::make(mode), priority);
4572 }
4573 
4574 /**
4575  * Completely removes any depth-write adjustment that may have been set on
4576  * this node via set_depth_write().
4577  */
4580  nassertv_always(!is_empty());
4581  node()->clear_attrib(DepthWriteAttrib::get_class_slot());
4582 }
4583 
4584 /**
4585  * Returns true if a depth-write adjustment has been explicitly set on this
4586  * particular node via set_depth_write(). If this returns true, then
4587  * get_depth_write() may be called to determine which has been set.
4588  */
4590 has_depth_write() const {
4591  nassertr_always(!is_empty(), false);
4592  return node()->has_attrib(DepthWriteAttrib::get_class_slot());
4593 }
4594 
4595 /**
4596  * Returns true if depth-write rendering has been specifically set on this
4597  * node via set_depth_write(), or false if depth-write rendering has been
4598  * specifically disabled. If nothing has been specifically set, returns true.
4599  * See also has_depth_write().
4600  */
4602 get_depth_write() const {
4603  nassertr_always(!is_empty(), false);
4604  const RenderAttrib *attrib =
4605  node()->get_attrib(DepthWriteAttrib::get_class_slot());
4606  if (attrib != nullptr) {
4607  const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
4608  return (dta->get_mode() != DepthWriteAttrib::M_off);
4609  }
4610 
4611  return true;
4612 }
4613 
4614 /**
4615  * This instructs the graphics driver to apply an offset or bias to the
4616  * generated depth values for rendered polygons, before they are written to
4617  * the depth buffer. This can be used to shift polygons forward slightly, to
4618  * resolve depth conflicts, or self-shadowing artifacts on thin objects. The
4619  * bias is always an integer number, and each integer increment represents the
4620  * smallest possible increment in Z that is sufficient to completely resolve
4621  * two coplanar polygons. Positive numbers are closer towards the camera.
4622  */
4624 set_depth_offset(int bias, int priority) {
4625  nassertv_always(!is_empty());
4626 
4627  node()->set_attrib(DepthOffsetAttrib::make(bias), priority);
4628 }
4629 
4630 /**
4631  * Completely removes any depth-offset adjustment that may have been set on
4632  * this node via set_depth_offset().
4633  */
4636  nassertv_always(!is_empty());
4637  node()->clear_attrib(DepthOffsetAttrib::get_class_slot());
4638 }
4639 
4640 /**
4641  * Returns true if a depth-offset adjustment has been explicitly set on this
4642  * particular node via set_depth_offset(). If this returns true, then
4643  * get_depth_offset() may be called to determine which has been set.
4644  */
4646 has_depth_offset() const {
4647  nassertr_always(!is_empty(), false);
4648  return node()->has_attrib(DepthOffsetAttrib::get_class_slot());
4649 }
4650 
4651 /**
4652  * Returns the depth offset value if it has been specified using
4653  * set_depth_offset, or 0 if not.
4654  */
4656 get_depth_offset() const {
4657  nassertr_always(!is_empty(), 0);
4658  const RenderAttrib *attrib =
4659  node()->get_attrib(DepthOffsetAttrib::get_class_slot());
4660  if (attrib != nullptr) {
4661  const DepthOffsetAttrib *doa = DCAST(DepthOffsetAttrib, attrib);
4662  return doa->get_offset();
4663  }
4664 
4665  return 0;
4666 }
4667 
4668 /**
4669  * Performs a billboard-type rotate to the indicated camera node, one time
4670  * only, and leaves the object rotated. This is similar in principle to
4671  * heads_up().
4672  */
4674 do_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
4675  nassertv_always(!is_empty());
4676 
4677  CPT(TransformState) transform = camera.get_transform(get_parent());
4678  const LMatrix4 &rel_mat = transform->get_mat();
4679 
4680  LVector3 up = LVector3::up();
4681  LVector3 rel_pos = -rel_mat.get_row3(3);
4682 
4683  LQuaternion quat;
4684  ::heads_up(quat, rel_pos, up);
4685  set_quat(quat);
4686 
4687  // Also slide the geometry towards the camera according to the offset
4688  // factor.
4689  if (offset != 0.0f) {
4690  LVector3 translate = rel_mat.get_row3(3);
4691  translate.normalize();
4692  translate *= offset;
4693  set_pos(translate);
4694  }
4695 }
4696 
4697 /**
4698  * Performs a billboard-type rotate to the indicated camera node, one time
4699  * only, and leaves the object rotated. This is similar in principle to
4700  * look_at(), although the point_eye billboard effect cannot be achieved using
4701  * the ordinary look_at() call.
4702  */
4704 do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
4705  nassertv_always(!is_empty());
4706 
4707  CPT(TransformState) transform = camera.get_transform(get_parent());
4708  const LMatrix4 &rel_mat = transform->get_mat();
4709 
4710  LVector3 up = LVector3::up() * rel_mat;
4711  LVector3 rel_pos = LVector3::forward() * rel_mat;
4712 
4713  LQuaternion quat;
4714  ::look_at(quat, rel_pos, up);
4715  set_quat(quat);
4716 
4717  // Also slide the geometry towards the camera according to the offset
4718  // factor.
4719  if (offset != 0.0f) {
4720  LVector3 translate = rel_mat.get_row3(3);
4721  translate.normalize();
4722  translate *= offset;
4723  set_pos(translate);
4724  }
4725 }
4726 
4727 /**
4728  * Performs a billboard-type rotate to the indicated camera node, one time
4729  * only, and leaves the object rotated. This is similar in principle to
4730  * look_at().
4731  */
4733 do_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
4734  nassertv_always(!is_empty());
4735 
4736  CPT(TransformState) transform = camera.get_transform(get_parent());
4737  const LMatrix4 &rel_mat = transform->get_mat();
4738 
4739  LVector3 up = LVector3::up();
4740  LVector3 rel_pos = -rel_mat.get_row3(3);
4741 
4742  LQuaternion quat;
4743  ::look_at(quat, rel_pos, up);
4744  set_quat(quat);
4745 
4746  // Also slide the geometry towards the camera according to the offset
4747  // factor.
4748  if (offset != 0.0f) {
4749  LVector3 translate = rel_mat.get_row3(3);
4750  translate.normalize();
4751  translate *= offset;
4752  set_pos(translate);
4753  }
4754 }
4755 
4756 /**
4757  * Puts a billboard transition on the node such that it will rotate in two
4758  * dimensions around the up axis, towards a specified "camera" instead of to
4759  * the viewing camera.
4760  */
4762 set_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
4763  nassertv_always(!is_empty());
4764  CPT(RenderEffect) billboard = BillboardEffect::make
4765  (LVector3::up(), false, true,
4766  offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
4767  node()->set_effect(billboard);
4768 }
4769 
4770 /**
4771  * Puts a billboard transition on the node such that it will rotate in three
4772  * dimensions about the origin, keeping its up vector oriented to the top of
4773  * the camera, towards a specified "camera" instead of to the viewing camera.
4774  */
4776 set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset, bool fixed_depth) {
4777  nassertv_always(!is_empty());
4778  CPT(RenderEffect) billboard = BillboardEffect::make
4779  (LVector3::up(), true, false,
4780  offset, camera, LPoint3(0.0f, 0.0f, 0.0f), fixed_depth);
4781  node()->set_effect(billboard);
4782 }
4783 
4784 /**
4785  * Puts a billboard transition on the node such that it will rotate in three
4786  * dimensions about the origin, keeping its up vector oriented to the sky,
4787  * towards a specified "camera" instead of to the viewing camera.
4788  */
4790 set_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
4791  nassertv_always(!is_empty());
4792  CPT(RenderEffect) billboard = BillboardEffect::make
4793  (LVector3::up(), false, false,
4794  offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
4795  node()->set_effect(billboard);
4796 }
4797 
4798 /**
4799  * Removes any billboard effect from the node.
4800  */
4802 clear_billboard() {
4803  nassertv_always(!is_empty());
4804  node()->clear_effect(BillboardEffect::get_class_type());
4805 }
4806 
4807 /**
4808  * Returns true if there is any billboard effect on the node.
4809  */
4811 has_billboard() const {
4812  nassertr_always(!is_empty(), false);
4813  return node()->has_effect(BillboardEffect::get_class_type());
4814 }
4815 
4816 /**
4817  * Puts a compass effect on the node, so that it will retain a fixed rotation
4818  * relative to the reference node (or render if the reference node is empty)
4819  * regardless of the transforms above it.
4820  */
4822 set_compass(const NodePath &reference) {
4823  nassertv_always(!is_empty());
4824  node()->set_effect(CompassEffect::make(reference));
4825 }
4826 
4827 /**
4828  * Removes any compass effect from the node.
4829  */
4831 clear_compass() {
4832  nassertv_always(!is_empty());
4833  node()->clear_effect(CompassEffect::get_class_type());
4834 }
4835 
4836 /**
4837  * Returns true if there is any compass effect on the node.
4838  */
4840 has_compass() const {
4841  nassertr_always(!is_empty(), false);
4842  return node()->has_effect(CompassEffect::get_class_type());
4843 }
4844 
4845 /**
4846  * Specifically sets or disables transparent rendering mode on this particular
4847  * node. If no other nodes override, this will cause items with a non-1 value
4848  * for alpha color to be rendered partially transparent.
4849  */
4851 set_transparency(TransparencyAttrib::Mode mode, int priority) {
4852  nassertv_always(!is_empty());
4853 
4854  node()->set_attrib(TransparencyAttrib::make(mode), priority);
4855 }
4856 
4857 /**
4858  * Completely removes any transparency adjustment that may have been set on
4859  * this node via set_transparency(). The geometry at this level and below will
4860  * subsequently be rendered either transparent or not, to whatever other nodes
4861  * may have had set_transparency() on them.
4862  */
4865  nassertv_always(!is_empty());
4866  node()->clear_attrib(TransparencyAttrib::get_class_slot());
4867 }
4868 
4869 /**
4870  * Returns true if a transparent-rendering adjustment has been explicitly set
4871  * on this particular node via set_transparency(). If this returns true, then
4872  * get_transparency() may be called to determine whether transparency has been
4873  * explicitly enabled or explicitly disabled for this node.
4874  */
4876 has_transparency() const {
4877  nassertr_always(!is_empty(), false);
4878  return node()->has_attrib(TransparencyAttrib::get_class_slot());
4879 }
4880 
4881 /**
4882  * Returns the transparent rendering that has been specifically set on this
4883  * node via set_transparency(), or M_none if nontransparent rendering has been
4884  * specifically set, or if nothing has been specifically set. See also
4885  * has_transparency(). This does not necessarily imply that the geometry will
4886  * or will not be rendered transparent, as there may be other nodes that
4887  * override.
4888  */
4889 TransparencyAttrib::Mode NodePath::
4890 get_transparency() const {
4891  nassertr_always(!is_empty(), TransparencyAttrib::M_none);
4892  const RenderAttrib *attrib =
4893  node()->get_attrib(TransparencyAttrib::get_class_slot());
4894  if (attrib != nullptr) {
4895  const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
4896  return ta->get_mode();
4897  }
4898 
4899  return TransparencyAttrib::M_none;
4900 }
4901 
4902 /**
4903  * Specifically sets or disables a logical operation on this particular node.
4904  * If no other nodes override, this will cause geometry to be rendered without
4905  * color blending but instead using the given logical operator.
4906  */
4908 set_logic_op(LogicOpAttrib::Operation op, int priority) {
4909  nassertv_always(!is_empty());
4910 
4911  node()->set_attrib(LogicOpAttrib::make(op), priority);
4912 }
4913 
4914 /**
4915  * Completely removes any logical operation that may have been set on this
4916  * node via set_logic_op(). The geometry at this level and below will
4917  * subsequently be rendered using standard color blending.
4918  */
4920 clear_logic_op() {
4921  nassertv_always(!is_empty());
4922  node()->clear_attrib(LogicOpAttrib::get_class_slot());
4923 }
4924 
4925 /**
4926  * Returns true if a logical operation has been explicitly set on this
4927  * particular node via set_logic_op(). If this returns true, then
4928  * get_logic_op() may be called to determine whether a logical operation has
4929  * been explicitly disabled for this node or set to particular operation.
4930  */
4932 has_logic_op() const {
4933  nassertr_always(!is_empty(), false);
4934  return node()->has_attrib(LogicOpAttrib::get_class_slot());
4935 }
4936 
4937 /**
4938  * Returns the logical operation that has been specifically set on this node
4939  * via set_logic_op(), or O_none if standard color blending has been
4940  * specifically set, or if nothing has been specifically set. See also
4941  * has_logic_op(). This does not necessarily imply that the geometry will
4942  * or will not be rendered with the given logical operation, as there may be
4943  * other nodes that override.
4944  */
4945 LogicOpAttrib::Operation NodePath::
4946 get_logic_op() const {
4947  nassertr_always(!is_empty(), LogicOpAttrib::O_none);
4948  const RenderAttrib *attrib =
4949  node()->get_attrib(LogicOpAttrib::get_class_slot());
4950  if (attrib != nullptr) {
4951  const LogicOpAttrib *ta = DCAST(LogicOpAttrib, attrib);
4952  return ta->get_operation();
4953  }
4954 
4955  return LogicOpAttrib::O_none;
4956 }
4957 
4958 /**
4959  * Specifies the antialiasing type that should be applied at this node and
4960  * below. See AntialiasAttrib.
4961  */
4963 set_antialias(unsigned short mode, int priority) {
4964  nassertv_always(!is_empty());
4965 
4966  node()->set_attrib(AntialiasAttrib::make(mode), priority);
4967 }
4968 
4969 /**
4970  * Completely removes any antialias setting that may have been set on this
4971  * node via set_antialias().
4972  */
4974 clear_antialias() {
4975  nassertv_always(!is_empty());
4976  node()->clear_attrib(AntialiasAttrib::get_class_slot());
4977 }
4978 
4979 /**
4980  * Returns true if an antialias setting has been explicitly mode on this
4981  * particular node via set_antialias(). If this returns true, then
4982  * get_antialias() may be called to determine what the setting was.
4983  */
4985 has_antialias() const {
4986  nassertr_always(!is_empty(), false);
4987  return node()->has_attrib(AntialiasAttrib::get_class_slot());
4988 }
4989 
4990 /**
4991  * Returns the antialias setting that has been specifically set on this node
4992  * via set_antialias(), or M_none if no setting has been made.
4993  */
4994 unsigned short NodePath::
4995 get_antialias() const {
4996  nassertr_always(!is_empty(), AntialiasAttrib::M_none);
4997  const RenderAttrib *attrib =
4998  node()->get_attrib(AntialiasAttrib::get_class_slot());
4999  if (attrib != nullptr) {
5000  const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib);
5001  return ta->get_mode();
5002  }
5003 
5004  return AntialiasAttrib::M_none;
5005 }
5006 
5007 /**
5008  * Returns true if an audio volume has been applied to the referenced node,
5009  * false otherwise. It is still possible that volume at this node might have
5010  * been scaled by an ancestor node.
5011  */
5013 has_audio_volume() const {
5014  nassertr_always(!is_empty(), false);
5015  return node()->has_attrib(AudioVolumeAttrib::get_class_slot());
5016 }
5017 
5018 /**
5019  * Completely removes any audio volume from the referenced node. This is
5020  * preferable to simply setting the audio volume to identity, as it also
5021  * removes the overhead associated with having an audio volume at all.
5022  */
5025  nassertv_always(!is_empty());
5026  node()->clear_attrib(AudioVolumeAttrib::get_class_slot());
5027 }
5028 
5029 /**
5030  * Sets the audio volume component of the transform
5031  */
5033 set_audio_volume(PN_stdfloat volume, int priority) {
5034  nassertv_always(!is_empty());
5035 
5036  const RenderAttrib *attrib =
5037  node()->get_attrib(AudioVolumeAttrib::get_class_slot());
5038  if (attrib != nullptr) {
5039  priority = max(priority,
5040  node()->get_state()->get_override(AudioVolumeAttrib::get_class_slot()));
5041  CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib);
5042 
5043  // Modify the existing AudioVolumeAttrib to add the indicated volume.
5044  node()->set_attrib(ava->set_volume(volume), priority);
5045 
5046  } else {
5047  // Create a new AudioVolumeAttrib for this node.
5048  node()->set_attrib(AudioVolumeAttrib::make(volume), priority);
5049  }
5050 }
5051 
5052 /**
5053  * Disables any audio volume attribute inherited from above. This is not the
5054  * same thing as clear_audio_volume(), which undoes any previous
5055  * set_audio_volume() operation on this node; rather, this actively disables
5056  * any set_audio_volume() that might be inherited from a parent node.
5057  *
5058  * It is legal to specify a new volume on the same node with a subsequent call
5059  * to set_audio_volume(); this new scale will apply to lower nodes.
5060  */
5062 set_audio_volume_off(int priority) {
5063  nassertv_always(!is_empty());
5064  node()->set_attrib(AudioVolumeAttrib::make_off(), priority);
5065 }
5066 
5067 /**
5068  * Returns the complete audio volume that has been applied to this node via a
5069  * previous call to set_audio_volume(), or 1. (identity) if no volume has been
5070  * applied to this particular node.
5071  */
5072 PN_stdfloat NodePath::
5073 get_audio_volume() const {
5074  const RenderAttrib *attrib =
5075  node()->get_attrib(AudioVolumeAttrib::get_class_slot());
5076  if (attrib != nullptr) {
5077  const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
5078  return ava->get_volume();
5079  }
5080 
5081  return 1.0f;
5082 }
5083 
5084 /**
5085  * Returns the complete audio volume for this node taking highers nodes in the
5086  * graph into account.
5087  */
5088 PN_stdfloat NodePath::
5089 get_net_audio_volume() const {
5090  CPT(RenderState) net_state = get_net_state();
5091  const RenderAttrib *attrib = net_state->get_attrib(AudioVolumeAttrib::get_class_slot());
5092  if (attrib != nullptr) {
5093  const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
5094  if (ava != nullptr) {
5095  return ava->get_volume();
5096  }
5097  }
5098 
5099  return 1.0f;
5100 }
5101 
5102 /**
5103  * Returns the NodePath at or above the referenced node that is hidden to the
5104  * indicated camera(s), or an empty NodePath if no ancestor of the referenced
5105  * node is hidden (and the node should be visible).
5106  */
5108 get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const {
5109  int pipeline_stage = current_thread->get_pipeline_stage();
5110 
5111  NodePathComponent *comp;
5112  for (comp = _head;
5113  comp != nullptr;
5114  comp = comp->get_next(pipeline_stage, current_thread)) {
5115  PandaNode *node = comp->get_node();
5116  if (node->is_overall_hidden() ||
5117  ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
5118  NodePath result;
5119  result._head = comp;
5120  return result;
5121  }
5122  }
5123 
5124  return not_found();
5125 }
5126 
5127 /**
5128  * Removes the referenced node (and the entire subgraph below this node) from
5129  * the scene graph in any normal sense. The node will no longer be visible
5130  * and is not tested for collisions; furthermore, no normal scene graph
5131  * traversal will visit the node. The node's bounding volume no longer
5132  * contributes to its parent's bounding volume.
5133  *
5134  * A stashed node cannot be located by a normal find() operation (although a
5135  * special find string can still retrieve it).
5136  */
5138 stash(int sort, Thread *current_thread) {
5139  nassertv_always(!is_singleton() && !is_empty());
5140  nassertv(verify_complete());
5141 
5142  int pipeline_stage = current_thread->get_pipeline_stage();
5143  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
5144  _head, sort, true, pipeline_stage,
5145  current_thread);
5146  nassertv(reparented);
5147 }
5148 
5149 /**
5150  * Undoes the effect of a previous stash() on this node: makes the referenced
5151  * node (and the entire subgraph below this node) once again part of the scene
5152  * graph.
5153  */
5155 unstash(int sort, Thread *current_thread) {
5156  nassertv_always(!is_singleton() && !is_empty());
5157  nassertv(verify_complete());
5158 
5159  int pipeline_stage = current_thread->get_pipeline_stage();
5160  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
5161  _head, sort, false, pipeline_stage,
5162  current_thread);
5163  nassertv(reparented);
5164 }
5165 
5166 /**
5167  * Unstashes this node and all stashed child nodes.
5168  */
5170 unstash_all(Thread *current_thread) {
5171  NodePathCollection stashed_descendents = find_all_matches("**/@@*");
5172  stashed_descendents.unstash();
5173  unstash(0, current_thread);
5174 }
5175 
5176 /**
5177  * Returns the NodePath at or above the referenced node that is stashed, or an
5178  * empty NodePath if no ancestor of the referenced node is stashed (and the
5179  * node should be visible).
5180  */
5182 get_stashed_ancestor(Thread *current_thread) const {
5183  NodePathComponent *comp = _head;
5184  if (comp != nullptr) {
5185  int pipeline_stage = current_thread->get_pipeline_stage();
5186  NodePathComponent *next = comp->get_next(pipeline_stage, current_thread);
5187 
5188  while (next != nullptr) {
5189  PandaNode *node = comp->get_node();
5190  PandaNode *parent_node = next->get_node();
5191 
5192  if (parent_node->find_stashed(node) >= 0) {
5193  NodePath result;
5194  result._head = comp;
5195  return result;
5196  }
5197 
5198  comp = next;
5199  next = next->get_next(pipeline_stage, current_thread);
5200  }
5201  }
5202 
5203  return not_found();
5204 }
5205 
5206 /**
5207  * Returns true if the two paths are equivalent; that is, if they contain the
5208  * same list of nodes in the same order.
5209  */
5211 operator == (const WeakNodePath &other) const {
5212  return (other == *this);
5213 }
5214 
5215 /**
5216  * Returns true if the two paths are not equivalent.
5217  */
5219 operator != (const WeakNodePath &other) const {
5220  return (other != *this);
5221 }
5222 
5223 /**
5224  * Returns true if this NodePath sorts before the other one, false otherwise.
5225  * The sorting order of two nonequivalent NodePaths is consistent but
5226  * undefined, and is useful only for storing NodePaths in a sorted container
5227  * like an STL set.
5228  */
5230 operator < (const WeakNodePath &other) const {
5231  return other.compare_to(*this) > 0;
5232 }
5233 
5234 /**
5235  * Returns a number less than zero if this NodePath sorts before the other
5236  * one, greater than zero if it sorts after, or zero if they are equivalent.
5237  *
5238  * Two NodePaths are considered equivalent if they consist of exactly the same
5239  * list of nodes in the same order. Otherwise, they are different; different
5240  * NodePaths will be ranked in a consistent but undefined ordering; the
5241  * ordering is useful only for placing the NodePaths in a sorted container
5242  * like an STL set.
5243  */
5245 compare_to(const WeakNodePath &other) const {
5246  return -other.compare_to(*this);
5247 }
5248 
5249 /**
5250  * Returns true if all of the nodes described in the NodePath are connected,
5251  * or false otherwise.
5252  */
5254 verify_complete(Thread *current_thread) const {
5255  if (is_empty()) {
5256  return true;
5257  }
5258 
5259 #ifdef HAVE_THREADS
5260  if (Thread::is_true_threads()) {
5261  // In a threaded environment, we can't reliably test this, since a sub-
5262  // thread may be mucking with the NodePath's ancestry as we try to
5263  // validate it. NodePaths are inherently not thread-safe, but generally
5264  // that's not an issue.
5265  return true;
5266  }
5267 #endif // HAVE_THREADS
5268 
5269  PStatTimer timer(_verify_complete_pcollector);
5270 
5271  const NodePathComponent *comp = _head;
5272  nassertr(comp != nullptr, false);
5273 
5274  int pipeline_stage = current_thread->get_pipeline_stage();
5275 
5276  PandaNode *node = comp->get_node();
5277  nassertr(node != nullptr, false);
5278  int length = comp->get_length(pipeline_stage, current_thread);
5279 
5280  comp = comp->get_next(pipeline_stage, current_thread);
5281  length--;
5282  while (comp != nullptr) {
5283  PandaNode *next_node = comp->get_node();
5284  nassertr(next_node != nullptr, false);
5285 
5286  if (node->find_parent(next_node) < 0) {
5287  pgraph_cat.warning()
5288  << *this << " is incomplete; " << *node << " is not a child of "
5289  << *next_node << "\n";
5290  return false;
5291  }
5292 
5293  if (comp->get_length(pipeline_stage, current_thread) != length) {
5294  pgraph_cat.warning()
5295  << *this << " is incomplete; length at " << *next_node
5296  << " indicates " << comp->get_length(pipeline_stage, current_thread)
5297  << " while length at " << *node << " indicates " << length << "\n";
5298  return false;
5299  }
5300 
5301  node = next_node;
5302  comp = comp->get_next(pipeline_stage, current_thread);
5303  length--;
5304  }
5305 
5306  return true;
5307 }
5308 
5309 /**
5310  * Walks through the scene graph beginning at the bottom node, and internally
5311  * adjusts any GeomVertexFormats for optimal rendering on the indicated GSG.
5312  * If this step is not done prior to rendering, the formats will be optimized
5313  * at render time instead, for a small cost.
5314  *
5315  * It is not normally necessary to do this on a model loaded directly from
5316  * disk, since the loader will do this by default.
5317  */
5320  nassertv_always(!is_empty());
5321 
5322  CPT(RenderState) state = RenderState::make_empty();
5323  if (has_parent()) {
5324  state = get_parent().get_net_state();
5325  }
5326 
5327  SceneGraphReducer gr(gsg);
5328  gr.premunge(node(), state);
5329 }
5330 
5331 /**
5332  * Walks through the scene graph beginning at the bottom node, and does
5333  * whatever initialization is required to render the scene properly with the
5334  * indicated GSG. It is not strictly necessary to call this, since the GSG
5335  * will initialize itself when the scene is rendered, but this may take some
5336  * of the overhead away from that process.
5337  *
5338  * In particular, this will ensure that textures and vertex buffers within the
5339  * scene are loaded into graphics memory.
5340  */
5343  nassertv_always(!is_empty());
5344 
5345  node()->prepare_scene(gsg, get_net_state());
5346 }
5347 
5348 /**
5349  * Causes the bounding volume of the bottom node and all of its descendants
5350  * (that is, the bounding volume associated with the the bottom arc) to be
5351  * rendered, if possible. The rendering method is less than optimal; this is
5352  * intended primarily for debugging.
5353  */
5355 show_bounds() {
5356  nassertv_always(!is_empty());
5357  node()->set_effect(ShowBoundsEffect::make(false));
5358 }
5359 
5360 /**
5361  * Similar to show_bounds(), this draws a bounding box representing the
5362  * "tight" bounds of this node and all of its descendants. The bounding box
5363  * is recomputed every frame by reexamining all of the vertices; this is far
5364  * from efficient, but this is intended for debugging.
5365  */
5368  nassertv_always(!is_empty());
5369  node()->set_effect(ShowBoundsEffect::make(true));
5370 }
5371 
5372 /**
5373  * Stops the rendering of the bounding volume begun with show_bounds().
5374  */
5376 hide_bounds() {
5377  nassertv_always(!is_empty());
5378  node()->clear_effect(ShowBoundsEffect::get_class_type());
5379 }
5380 
5381 /**
5382  * Returns a newly-allocated bounding volume containing the bottom node and
5383  * all of its descendants. This is the bounding volume on the bottom arc,
5384  * converted to the local coordinate space of the node.
5385  */
5386 PT(BoundingVolume) NodePath::
5387 get_bounds(Thread *current_thread) const {
5388  nassertr_always(!is_empty(), new BoundingSphere);
5389  return node()->get_bounds(current_thread)->make_copy();
5390 }
5391 
5392 /**
5393  * Forces the recomputing of all the bounding volumes at every node in the
5394  * subgraph beginning at this node and below.
5395  *
5396  * This should not normally need to be called, since the bounding volumes are
5397  * supposed to be recomputed automatically when necessary. It may be useful
5398  * when debugging, to verify that the bounding volumes have not become
5399  * inadvertently stale; it may also be useful to force animated characters to
5400  * update their bounding volumes (which does not presently happen
5401  * automatically).
5402  */
5403 void NodePath::
5404 force_recompute_bounds() {
5405  nassertv_always(!is_empty());
5406  r_force_recompute_bounds(node());
5407 }
5408 
5409 /**
5410  * Writes a description of the bounding volume containing the bottom node and
5411  * all of its descendants to the indicated output stream.
5412  */
5414 write_bounds(ostream &out) const {
5415  get_bounds()->write(out);
5416 }
5417 
5418 /**
5419  * Calculates the minimum and maximum vertices of all Geoms at this NodePath's
5420  * bottom node and below. This is a tight bounding box; it will generally be
5421  * tighter than the bounding volume returned by get_bounds() (but it is more
5422  * expensive to compute).
5423  *
5424  * The bounding box is computed relative to the parent node's coordinate
5425  * system by default. You can optionally specify a different NodePath to
5426  * compute the bounds relative to. Note that the box is always axis-aligned
5427  * against the given NodePath's coordinate system, so you might get a
5428  * differently sized box depending on which node you pass.
5429  *
5430  * The return value is true if any points are within the bounding volume, or
5431  * false if none are.
5432  */
5434 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
5435  const NodePath &other, Thread *current_thread) const {
5436  min_point.set(0.0f, 0.0f, 0.0f);
5437  max_point.set(0.0f, 0.0f, 0.0f);
5438  nassertr_always(!is_empty(), false);
5439 
5440  CPT(TransformState) transform = TransformState::make_identity();
5441  if (!other.is_empty()) {
5442  transform = get_transform(other)->compose(get_transform()->get_inverse());
5443  }
5444 
5445  bool found_any = false;
5446  node()->calc_tight_bounds(min_point, max_point, found_any,
5447  move(transform), current_thread);
5448 
5449  return found_any;
5450 }
5451 
5452 /**
5453  * Analyzes the geometry below this node and reports the number of vertices,
5454  * triangles, etc. This is the same information reported by the bam-info
5455  * program.
5456  */
5457 /*
5458 NB: Had to remove this function to avoid circular dependency when
5459 moving SceneGraphAnalyzer into pgraphnodes, attempting to reduce size
5460 of pgraph. This function is now defined as a Python extension
5461 function instead.
5462 
5463 void NodePath::
5464 analyze() const {
5465  nassertv_always(!is_empty());
5466  SceneGraphAnalyzer sga;
5467  sga.add_node(node());
5468 
5469  if (sga.get_num_lod_nodes() == 0) {
5470  sga.write(nout);
5471 
5472  } else {
5473  nout << "At highest LOD:\n";
5474  SceneGraphAnalyzer sga2;
5475  sga2.set_lod_mode(SceneGraphAnalyzer::LM_highest);
5476  sga2.add_node(node());
5477  sga2.write(nout);
5478 
5479  nout << "\nAt lowest LOD:\n";
5480  sga2.clear();
5481  sga2.set_lod_mode(SceneGraphAnalyzer::LM_lowest);
5482  sga2.add_node(node());
5483  sga2.write(nout);
5484 
5485  nout << "\nAll nodes:\n";
5486  sga.write(nout);
5487  }
5488 }
5489 */
5490 
5491 /**
5492  * Lightly flattens out the hierarchy below this node by applying transforms,
5493  * colors, and texture matrices from the nodes onto the vertices, but does not
5494  * remove any nodes.
5495  *
5496  * This can result in improved rendering performance because there will be
5497  * fewer transforms in the resulting scene graph, but the number of nodes will
5498  * remain the same.
5499  *
5500  * In particular, any NodePaths that reference nodes within this hierarchy
5501  * will not be damaged. However, since this operation will remove transforms
5502  * from the scene graph, it may be dangerous to apply to nodes where you
5503  * expect to dynamically modify the transform, or where you expect the
5504  * geometry to remain in a particular local coordinate system.
5505  *
5506  * The return value is always 0, since flatten_light does not remove any
5507  * nodes.
5508  */
5510 flatten_light() {
5511  nassertr_always(!is_empty(), 0);
5512  SceneGraphReducer gr;
5513  gr.apply_attribs(node());
5514 
5515  return 0;
5516 }
5517 
5518 /**
5519  * A more thorough flattening than flatten_light(), this first applies all the
5520  * transforms, colors, and texture matrices from the nodes onto the vertices,
5521  * and then removes unneeded grouping nodes--nodes that have exactly one
5522  * child, for instance, but have no special properties in themselves.
5523  *
5524  * This results in improved performance over flatten_light() because the
5525  * number of nodes in the scene graph is reduced.
5526  *
5527  * The return value is the number of nodes removed.
5528  */
5530 flatten_medium() {
5531  nassertr_always(!is_empty(), 0);
5532  SceneGraphReducer gr;
5533  gr.apply_attribs(node());
5534  int num_removed = gr.flatten(node(), 0);
5535 
5536  if (flatten_geoms) {
5538  gr.collect_vertex_data(node());
5539  gr.unify(node(), true);
5540  }
5541 
5542  return num_removed;
5543 }
5544 
5545 /**
5546  * The strongest possible flattening. This first applies all of the
5547  * transforms to the vertices, as in flatten_medium(), but then it will
5548  * combine sibling nodes together when possible, in addition to removing
5549  * unnecessary parent-child nodes. This can result in substantially fewer
5550  * nodes, but any nicely-grouped hierachical bounding volumes may be lost.
5551  *
5552  * It is generally a good idea to apply this kind of flattening only to nodes
5553  * that will be culled largely as a single unit, like a car. Applying this to
5554  * an entire scene may result in overall poorer performance because of less-
5555  * effective culling.
5556  */
5558 flatten_strong() {
5559  nassertr_always(!is_empty(), 0);
5560  SceneGraphReducer gr;
5561  gr.apply_attribs(node());
5562  int num_removed = gr.flatten(node(), ~0);
5563 
5564  if (flatten_geoms) {
5566  gr.collect_vertex_data(node(), ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type));
5567  gr.unify(node(), false);
5568  }
5569 
5570  return num_removed;
5571 }
5572 
5573 /**
5574  * Removes textures from Geoms at this node and below by applying the texture
5575  * colors to the vertices. This is primarily useful to simplify a low-LOD
5576  * model. The texture colors are replaced by flat colors that approximate the
5577  * original textures.
5578  *
5579  * Only the bottommost texture on each Geom is used (if there is more than
5580  * one), and it is applied as if it were M_modulate, and WM_repeat, regardless
5581  * of its actual settings. If the texture has a simple_ram_image, this may be
5582  * used if the main image isn't resident.
5583  *
5584  * After this call, there will be no texturing specified at this level and
5585  * below. Of course, there might still be texturing inherited from above.
5586  */
5589  nassertv_always(!is_empty());
5590  SceneGraphReducer gr;
5591  gr.apply_attribs(node(), SceneGraphReducer::TT_apply_texture_color | SceneGraphReducer::TT_tex_matrix | SceneGraphReducer::TT_other);
5592 }
5593 
5594 /**
5595  * Returns the lowest ancestor of this node that contains a tag definition
5596  * with the indicated key, if any, or an empty NodePath if no ancestor of this
5597  * node contains this tag definition. See set_tag().
5598  */
5600 find_net_tag(const string &key) const {
5601  if (is_empty()) {
5602  return NodePath::not_found();
5603  }
5604  if (has_tag(key)) {
5605  return *this;
5606  }
5607  return get_parent().find_net_tag(key);
5608 }
5609 
5610 /**
5611  * Writes the contents of this node and below out to a bam file with the
5612  * indicated filename. This file may then be read in again, as is, at some
5613  * later point. Returns true if successful, false on some kind of error.
5614  */
5616 write_bam_file(const Filename &filename) const {
5617  nassertr_always(!is_empty(), false);
5618 
5619  BamFile bam_file;
5620 
5621  bool okflag = false;
5622 
5623  if (bam_file.open_write(filename)) {
5624  // Tell the BamWriter which node is the root node, for making NodePaths
5625  // relative to when writing them out to the file.
5626  bam_file.get_writer()->set_root_node(node());
5627 
5628  if (bam_file.write_object(node())) {
5629  okflag = true;
5630  }
5631  bam_file.close();
5632  }
5633  return okflag;
5634 }
5635 
5636 /**
5637  * Writes the contents of this node and below out to the indicated stream.
5638  */
5640 write_bam_stream(ostream &out) const {
5641  nassertr_always(!is_empty(), false);
5642 
5643  BamFile bam_file;
5644 
5645  bool okflag = false;
5646 
5647  if (bam_file.open_write(out)) {
5648  // Tell the BamWriter which node is the root node, for making NodePaths
5649  // relative to when writing them out to the file.
5650  bam_file.get_writer()->set_root_node(node());
5651 
5652  if (bam_file.write_object(node())) {
5653  okflag = true;
5654  }
5655  bam_file.close();
5656  }
5657  return okflag;
5658 }
5659 
5660 /**
5661  * Converts the NodePath object into a single stream of data using a
5662  * BamWriter, and stores that data in the indicated string. Returns true on
5663  * success, false on failure.
5664  *
5665  * If the BamWriter is NULL, this behaves the same way as
5666  * NodePath::write_bam_stream() and PandaNode::encode_to_bam_stream(), in the
5667  * sense that it only writes this node and all nodes below it.
5668  *
5669  * However, if the BamWriter is not NULL, it behaves very differently. In
5670  * this case, it encodes the *entire graph* of all nodes connected to the
5671  * NodePath, including all parent nodes and siblings. This is necessary for
5672  * correct streaming of related NodePaths and restoration of instances, etc.,
5673  * but it does mean you must detach() a node before writing it if you want to
5674  * limit the nodes that get written.
5675  *
5676  * This method is used by __reduce__ to handle streaming of NodePaths to a
5677  * pickle file. The BamWriter case is used by the direct.stdpy.pickle module,
5678  * while the saner, non-BamWriter case is used when the standard pickle module
5679  * calls this function.
5680  */
5682 encode_to_bam_stream(vector_uchar &data, BamWriter *writer) const {
5683  data.clear();
5684  ostringstream stream;
5685 
5686  DatagramBuffer buffer;
5687  BamWriter local_writer;
5688  bool used_local_writer = false;
5689  if (writer == nullptr) {
5690  // Create our own writer.
5691 
5692  if (!buffer.write_header(_bam_header)) {
5693  return false;
5694  }
5695  writer = &local_writer;
5696  used_local_writer = true;
5697  }
5698 
5699  writer->set_target(&buffer);
5700 
5701  int num_nodes = get_num_nodes();
5702  if (used_local_writer && num_nodes > 1) {
5703  // In this case--no BamWriter--we only write the bottom node.
5704  num_nodes = 1;
5705  }
5706 
5707  // Tell the BamWriter which node is the root node, for making NodePaths
5708  // relative to when writing them out to the file.
5709  if (!is_empty()) {
5710  writer->set_root_node(node());
5711  }
5712 
5713  // Write an initial Datagram to represent the error type and number of
5714  // nodes.
5715  Datagram dg;
5716  dg.add_uint8(_error_type);
5717  dg.add_int32(num_nodes);
5718 
5719  if (!buffer.put_datagram(dg)) {
5720  writer->set_target(nullptr);
5721  return false;
5722  }
5723 
5724  // Now write the nodes, one at a time.
5725  for (int i = 0; i < num_nodes; ++i) {
5726  PandaNode *node = get_node(num_nodes - i - 1);
5727  nassertr(node != nullptr, false);
5728  if (!writer->write_object(node)) {
5729  writer->set_target(nullptr);
5730  return false;
5731  }
5732  }
5733  writer->set_target(nullptr);
5734 
5735  buffer.swap_data(data);
5736  return true;
5737 }
5738 
5739 /**
5740  * Reads the string created by a previous call to encode_to_bam_stream(), and
5741  * extracts and returns the NodePath on that string. Returns NULL on error.
5742  */
5744 decode_from_bam_stream(vector_uchar data, BamReader *reader) {
5745  NodePath result;
5746 
5747  DatagramBuffer buffer(move(data));
5748 
5749  BamReader local_reader;
5750  if (reader == nullptr) {
5751  // Create a local reader.
5752 
5753  string head;
5754  if (!buffer.read_header(head, _bam_header.size())) {
5755  return NodePath::fail();
5756  }
5757 
5758  if (head != _bam_header) {
5759  return NodePath::fail();
5760  }
5761 
5762  reader = &local_reader;
5763  }
5764 
5765  reader->set_source(&buffer);
5766 
5767  // One initial datagram to encode the error type, and the number of nodes.
5768  Datagram dg;
5769  if (!buffer.get_datagram(dg)) {
5770  return NodePath::fail();
5771  }
5772 
5773  DatagramIterator dgi(dg);
5774  ErrorType error_type = (ErrorType)dgi.get_uint8();
5775  int num_nodes = dgi.get_int32();
5776  if (num_nodes == 0) {
5777  // An empty NodePath.
5778  result._error_type = error_type;
5779 
5780  } else {
5781  // A real NodePath. Ignore error_type.
5782  for (int i = 0; i < num_nodes; ++i) {
5783  TypedWritable *object = reader->read_object();
5784 
5785  if (object == nullptr ||
5786  !object->is_of_type(PandaNode::get_class_type())) {
5787  reader->set_source(nullptr);
5788  return NodePath::fail();
5789  }
5790 
5791  if (!reader->resolve()) {
5792  reader->set_source(nullptr);
5793  return NodePath::fail();
5794  }
5795 
5796  PandaNode *node = DCAST(PandaNode, object);
5797  result = NodePath(result, node);
5798  }
5799  }
5800 
5801  reader->set_source(nullptr);
5802 
5803  return result;
5804 }
5805 
5806 /**
5807  * Walks up from both NodePaths to find the first node that both have in
5808  * common, if any. Fills a_count and b_count with the number of nodes below
5809  * the common node in each path.
5810  *
5811  * The return value is the NodePathComponent of the node they have in common,
5812  * or NULL if they have nothing in common.
5813  */
5814 NodePathComponent *NodePath::
5815 find_common_ancestor(const NodePath &a, const NodePath &b,
5816  int &a_count, int &b_count, Thread *current_thread) {
5817  nassertr(!a.is_empty() && !b.is_empty(), nullptr);
5818  NodePathComponent *ac = a._head;
5819  NodePathComponent *bc = b._head;
5820  a_count = 0;
5821  b_count = 0;
5822 
5823  int pipeline_stage = current_thread->get_pipeline_stage();
5824 
5825  // Shorten up the longer one until they are the same length.
5826  while (ac->get_length(pipeline_stage, current_thread) > bc->get_length(pipeline_stage, current_thread)) {
5827  nassertr(ac != nullptr, nullptr);
5828  ac = ac->get_next(pipeline_stage, current_thread);
5829  a_count++;
5830  }
5831  while (bc->get_length(pipeline_stage, current_thread) > ac->get_length(pipeline_stage, current_thread)) {
5832  nassertr(bc != nullptr, nullptr);
5833  bc = bc->get_next(pipeline_stage, current_thread);
5834  b_count++;
5835  }
5836 
5837  // Now shorten them both up until we reach the same component.
5838  while (ac != bc) {
5839  // These shouldn't go to NULL unless they both go there together.
5840  nassertr(ac != nullptr, nullptr);
5841  nassertr(bc != nullptr, nullptr);
5842  ac = ac->get_next(pipeline_stage, current_thread);
5843  a_count++;
5844  bc = bc->get_next(pipeline_stage, current_thread);
5845  b_count++;
5846  }
5847 
5848  return ac;
5849 }
5850 
5851 /**
5852  * Recursively determines the net state changes to the indicated component
5853  * node from the root of the graph.
5854  */
5855 CPT(RenderState) NodePath::
5856 r_get_net_state(NodePathComponent *comp, Thread *current_thread) const {
5857  if (comp == nullptr) {
5858  return RenderState::make_empty();
5859  } else {
5860  CPT(RenderState) state = comp->get_node()->get_state(current_thread);
5861  int pipeline_stage = current_thread->get_pipeline_stage();
5862  return r_get_net_state(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(state);
5863  }
5864 }
5865 
5866 /**
5867  * Recursively determines the net state changes to the indicated component
5868  * node from the nth node above it. If n exceeds the length of the path, this
5869  * returns the net transform from the root of the graph.
5870  */
5871 CPT(RenderState) NodePath::
5872 r_get_partial_state(NodePathComponent *comp, int n,
5873  Thread *current_thread) const {
5874  if (n == 0 || comp == nullptr) {
5875  return RenderState::make_empty();
5876  } else {
5877  CPT(RenderState) state = comp->get_node()->get_state(current_thread);
5878  int pipeline_stage = current_thread->get_pipeline_stage();
5879  return r_get_partial_state(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(state);
5880  }
5881 }
5882 
5883 /**
5884  * Recursively determines the net transform to the indicated component node
5885  * from the root of the graph.
5886  */
5887 CPT(TransformState) NodePath::
5888 r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const {
5889  if (comp == nullptr) {
5890  return TransformState::make_identity();
5891  } else {
5892  PandaNode *node = comp->get_node();
5893  int pipeline_stage = current_thread->get_pipeline_stage();
5894  CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread);
5895 
5896  PandaNode::CDReader node_cdata(node->_cycler, current_thread);
5897  if (!node_cdata->_effects->has_adjust_transform()) {
5898  if (node_cdata->_transform->is_identity()) {
5899  return net_transform;
5900  } else {
5901  return net_transform->compose(node_cdata->_transform);
5902  }
5903  } else {
5904  CPT(TransformState) transform = node_cdata->_transform.p();
5905  node_cdata->_effects->adjust_transform(net_transform, transform, node);
5906  return net_transform->compose(transform);
5907  }
5908  }
5909 }
5910 
5911 /**
5912  * Recursively determines the net transform to the indicated component node
5913  * from the nth node above it. If n exceeds the length of the path, this
5914  * returns the net transform from the root of the graph.
5915  *
5916  * If any node in the path had a net_transform effect applied, returns NULL--
5917  * in this case the partial transform cannot be easily determined.
5918  */
5919 CPT(TransformState) NodePath::
5920 r_get_partial_transform(NodePathComponent *comp, int n,
5921  Thread *current_thread) const {
5922  if (n == 0 || comp == nullptr) {
5923  return TransformState::make_identity();
5924  } else {
5925  PandaNode *node = comp->get_node();
5926  PandaNode::CDReader node_cdata(node->_cycler, current_thread);
5927  if (node_cdata->_effects->has_adjust_transform()) {
5928  return nullptr;
5929  }
5930  int pipeline_stage = current_thread->get_pipeline_stage();
5931  CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread);
5932  if (partial == nullptr) {
5933  return nullptr;
5934  }
5935  if (node_cdata->_transform->is_identity()) {
5936  return partial;
5937  } else {
5938  return partial->compose(node_cdata->_transform);
5939  }
5940  }
5941 }
5942 
5943 /**
5944  * Recursively determines the net "previous" transform to the indicated
5945  * component node from the root of the graph.
5946  */
5947 CPT(TransformState) NodePath::
5948 r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const {
5949  if (comp == nullptr) {
5950  return TransformState::make_identity();
5951  } else {
5952  CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
5953  int pipeline_stage = current_thread->get_pipeline_stage();
5954  return r_get_net_prev_transform(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(transform);
5955  }
5956 }
5957 
5958 /**
5959  * Recursively determines the net "previous" transform to the indicated
5960  * component node from the nth node above it. If n exceeds the length of the
5961  * path, this returns the net previous transform from the root of the graph.
5962  */
5963 CPT(TransformState) NodePath::
5964 r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const {
5965  if (n == 0 || comp == nullptr) {
5966  return TransformState::make_identity();
5967  } else {
5968  CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
5969  int pipeline_stage = current_thread->get_pipeline_stage();
5970  return r_get_partial_prev_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(transform);
5971  }
5972 }
5973 
5974 /**
5975  * Finds up to max_matches matches against the given path string from this
5976  * node and deeper. The max_matches count indicates the maximum number of
5977  * matches to return, or -1 not to limit the number returned.
5978  */
5979 void NodePath::
5980 find_matches(NodePathCollection &result, const string &path,
5981  int max_matches) const {
5982  if (is_empty()) {
5983  pgraph_cat.warning()
5984  << "Attempt to extend an empty NodePath by '" << path
5985  << "'.\n";
5986  return;
5987  }
5988  FindApproxPath approx_path;
5989  if (approx_path.add_string(path)) {
5990  find_matches(result, approx_path, max_matches);
5991  }
5992 }
5993 
5994 /**
5995  * Finds up to max_matches matches against the given approx_path from this
5996  * node and deeper. The max_matches count indicates the maximum number of
5997  * matches to return, or -1 not to limit the number returned.
5998  */
5999 void NodePath::
6000 find_matches(NodePathCollection &result, FindApproxPath &approx_path,
6001  int max_matches) const {
6002  if (is_empty()) {
6003  pgraph_cat.warning()
6004  << "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
6005  return;
6006  }
6007 
6008  // We start with just one entry on the level.
6009  FindApproxLevelEntry *level =
6010  new FindApproxLevelEntry(WorkingNodePath(*this), approx_path);
6011  nassertv(level->_node_path.is_valid());
6012 
6013  find_matches(result, level, max_matches);
6014 }
6015 
6016 /**
6017  * The fundamental implementation of find_matches(), given a starting level (a
6018  * linked list of FindApproxLevelEntry objects).
6019  */
6020 void NodePath::
6021 find_matches(NodePathCollection &result, FindApproxLevelEntry *level,
6022  int max_matches) const {
6023 
6024  int num_levels_remaining = _max_search_depth;
6025 
6026  FindApproxLevelEntry *deleted_entries = nullptr;
6027 
6028  while (num_levels_remaining > 0 && level != nullptr) {
6029  if (pgraph_cat.is_spam()) {
6030  pgraph_cat.spam()
6031  << "find_matches pass: " << result << ", "
6032  << max_matches << ", " << num_levels_remaining << "\n";
6033  level->write_level(pgraph_cat.spam(false), 4);
6034  }
6035 
6036  num_levels_remaining--;
6037 
6038  FindApproxLevelEntry *next_level = nullptr;
6039 
6040  // For each node in the current level, build up the set of possible
6041  // matches in the next level.
6042  FindApproxLevelEntry *entry = level;
6043  while (entry != nullptr) {
6044  if (entry->consider_node(result, next_level, max_matches, 0)) {
6045  // If we found the requisite number of matches, we can stop. Delete
6046  // all remaining entries and return immediately.
6047 
6048  while (entry != nullptr) {
6049  FindApproxLevelEntry *next = entry->_next;
6050  delete entry;
6051  entry = next;
6052  }
6053  while (next_level != nullptr) {
6054  FindApproxLevelEntry *next = next_level->_next;
6055  delete next_level;
6056  next_level = next;
6057  }
6058  while (deleted_entries != nullptr) {
6059  FindApproxLevelEntry *next = deleted_entries->_next;
6060  delete deleted_entries;
6061  deleted_entries = next;
6062  }
6063  return;
6064  }
6065 
6066  // Move the entry to the delete chain so we can delete it before we
6067  // return from this method. (We can't delete it immediately, because
6068  // there might be WorkingNodePaths in the next_level that reference the
6069  // WorkingNodePath object within the entry.)
6070  FindApproxLevelEntry *next = entry->_next;
6071  entry->_next = deleted_entries;
6072  deleted_entries = entry;
6073 
6074  entry = next;
6075  }
6076 
6077  // Make sure the remaining entries from this level are added to the delete
6078  // chain.
6079  while (entry != nullptr) {
6080  FindApproxLevelEntry *next = entry->_next;
6081  entry->_next = deleted_entries;
6082  deleted_entries = entry;
6083 
6084  entry = next;
6085  }
6086 
6087  level = next_level;
6088  }
6089 
6090  // Now it's safe to delete all entries on the delete chain.
6091  while (deleted_entries != nullptr) {
6092  FindApproxLevelEntry *next = deleted_entries->_next;
6093  delete deleted_entries;
6094  deleted_entries = next;
6095  }
6096 }
6097 
6098 /**
6099  * The recursive implementation of clear_model_nodes(). This walks through
6100  * the subgraph defined by the indicated node and below.
6101  */
6102 int NodePath::
6103 r_clear_model_nodes(PandaNode *node) {
6104  int count = 0;
6105 
6106  if (node->is_of_type(ModelNode::get_class_type())) {
6107  ModelNode *mnode;
6108  DCAST_INTO_R(mnode, node, count);
6109  mnode->set_preserve_transform(ModelNode::PT_drop_node);
6110  ++count;
6111  }
6112 
6114  int num_children = cr.get_num_children();
6115  for (int i = 0; i < num_children; i++) {
6116  count += r_clear_model_nodes(cr.get_child(i));
6117  }
6118 
6119  return count;
6120 }
6121 
6122 /**
6123  * The recursive implementation of adjust_all_priorities(). This walks
6124  * through the subgraph defined by the indicated node and below.
6125  */
6126 void NodePath::
6127 r_adjust_all_priorities(PandaNode *node, int adjustment) {
6128  node->set_state(node->get_state()->adjust_all_priorities(adjustment));
6129  if (node->is_geom_node()) {
6130  GeomNode *gnode;
6131  DCAST_INTO_V(gnode, node);
6132 
6133  int num_geoms = gnode->get_num_geoms();
6134  for (int i = 0; i < num_geoms; i++) {
6135  gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment));
6136  }
6137  }
6138 
6140  int num_children = cr.get_num_children();
6141  for (int i = 0; i < num_children; i++) {
6142  r_adjust_all_priorities(cr.get_child(i), adjustment);
6143  }
6144 }
6145 
6146 /**
6147  *
6148  */
6149 void NodePath::
6150 r_force_recompute_bounds(PandaNode *node) {
6151  if (node->is_geom_node()) {
6152  GeomNode *gnode;
6153  DCAST_INTO_V(gnode, node);
6154 
6155  int num_geoms = gnode->get_num_geoms();
6156  for (int i = 0; i < num_geoms; i++) {
6157  const Geom *geom = gnode->get_geom(i);
6158  geom->mark_bounds_stale();
6159  }
6160  }
6161 
6162  node->mark_bounds_stale();
6163 
6164  // Now consider children.
6166  int num_children = cr.get_num_children();
6167  for (int i = 0; i < num_children; i++) {
6168  r_force_recompute_bounds(cr.get_child(i));
6169  }
6170 }
6171 
6172 /**
6173  * Recursively applies the indicated collide mask to the nodes at and below
6174  * this node.
6175  */
6176 void NodePath::
6177 r_set_collide_mask(PandaNode *node,
6178  CollideMask and_mask, CollideMask or_mask,
6179  TypeHandle node_type) {
6180  if (node->is_of_type(node_type)) {
6181  CollideMask into_collide_mask = node->get_into_collide_mask();
6182  into_collide_mask = (into_collide_mask & and_mask) | or_mask;
6183  node->set_into_collide_mask(into_collide_mask);
6184  }
6185 
6187  int num_children = cr.get_num_children();
6188  for (int i = 0; i < num_children; i++) {
6189  r_set_collide_mask(cr.get_child(i), and_mask, or_mask, node_type);
6190  }
6191 }
6192 
6193 /**
6194  *
6195  */
6196 bool NodePath::
6197 r_has_vertex_column(PandaNode *node, const InternalName *name) const {
6198  if (node->is_geom_node()) {
6199  GeomNode *gnode;
6200  DCAST_INTO_R(gnode, node, false);
6201 
6202  int num_geoms = gnode->get_num_geoms();
6203  for (int i = 0; i < num_geoms; i++) {
6204  const Geom *geom = gnode->get_geom(i);
6205  CPT(GeomVertexData) vdata = geom->get_vertex_data();
6206  if (vdata->has_column(name)) {
6207  return true;
6208  }
6209  }
6210  }
6211 
6212  // Now consider children.
6214  int num_children = cr.get_num_children();
6215  for (int i = 0; i < num_children; i++) {
6216  PandaNode *child = cr.get_child(i);
6217  if (r_has_vertex_column(child, name)) {
6218  return true;
6219  }
6220  }
6221 
6222  return false;
6223 }
6224 
6225 /**
6226  *
6227  */
6228 void NodePath::
6229 r_find_all_vertex_columns(PandaNode *node,
6230  NodePath::InternalNames &vertex_columns) const {
6231  if (node->is_geom_node()) {
6232  GeomNode *gnode;
6233  DCAST_INTO_V(gnode, node);
6234 
6235  int num_geoms = gnode->get_num_geoms();
6236  for (int i = 0; i < num_geoms; ++i) {
6237  const Geom *geom = gnode->get_geom(i);
6238  const GeomVertexFormat *format = geom->get_vertex_data()->get_format();
6239  int num_arrays = format->get_num_arrays();
6240  for (int j = 0; j < num_arrays; ++j) {
6241  const GeomVertexArrayFormat *array = format->get_array(j);
6242  int num_columns = array->get_num_columns();
6243  for (int k = 0; k < num_columns; ++k) {
6244  const GeomVertexColumn *column = array->get_column(k);
6245  vertex_columns.insert(column->get_name());
6246  }
6247  }
6248  }
6249  }
6250 
6251  // Now consider children.
6253  int num_children = cr.get_num_children();
6254  for (int i = 0; i < num_children; i++) {
6255  PandaNode *child = cr.get_child(i);
6256  r_find_all_vertex_columns(child, vertex_columns);
6257  }
6258 }
6259 
6260 /**
6261  *
6262  */
6263 Texture *NodePath::
6264 r_find_texture(PandaNode *node, const RenderState *state,
6265  const GlobPattern &glob) const {
6266  if (node->is_geom_node()) {
6267  GeomNode *gnode;
6268  DCAST_INTO_R(gnode, node, nullptr);
6269 
6270  int num_geoms = gnode->get_num_geoms();
6271  for (int i = 0; i < num_geoms; i++) {
6272  CPT(RenderState) geom_state =
6273  state->compose(gnode->get_geom_state(i));
6274 
6275  // Look for a TextureAttrib on the state.
6276  const RenderAttrib *attrib =
6277  geom_state->get_attrib(TextureAttrib::get_class_slot());
6278  if (attrib != nullptr) {
6279  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6280  for (int i = 0; i < ta->get_num_on_stages(); i++) {
6281  Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
6282  if (texture != nullptr) {
6283  if (glob.matches(texture->get_name())) {
6284  return texture;
6285  }
6286  }
6287  }
6288  }
6289  }
6290  }
6291 
6292  // Now consider children.
6294  int num_children = cr.get_num_children();
6295  for (int i = 0; i < num_children; i++) {
6296  PandaNode *child = cr.get_child(i);
6297  CPT(RenderState) next_state = state->compose(child->get_state());
6298 
6299  Texture *result = r_find_texture(child, next_state, glob);
6300  if (result != nullptr) {
6301  return result;
6302  }
6303  }
6304 
6305  return nullptr;
6306 }
6307 
6308 /**
6309  *
6310  */
6311 void NodePath::
6312 r_find_all_textures(PandaNode *node, const RenderState *state,
6313  NodePath::Textures &textures) const {
6314  if (node->is_geom_node()) {
6315  GeomNode *gnode;
6316  DCAST_INTO_V(gnode, node);
6317 
6318  int num_geoms = gnode->get_num_geoms();
6319  for (int i = 0; i < num_geoms; i++) {
6320  CPT(RenderState) geom_state =
6321  state->compose(gnode->get_geom_state(i));
6322 
6323  // Look for a TextureAttrib on the state.
6324  const RenderAttrib *attrib =
6325  geom_state->get_attrib(TextureAttrib::get_class_slot());
6326  if (attrib != nullptr) {
6327  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6328  for (int i = 0; i < ta->get_num_on_stages(); i++) {
6329  Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
6330  if (texture != nullptr) {
6331  textures.insert(texture);
6332  }
6333  }
6334  }
6335  }
6336  }
6337 
6338  // Now consider children.
6340  int num_children = cr.get_num_children();
6341  for (int i = 0; i < num_children; i++) {
6342  PandaNode *child = cr.get_child(i);
6343  CPT(RenderState) next_state = state->compose(child->get_state());
6344  r_find_all_textures(child, next_state, textures);
6345  }
6346 }
6347 
6348 /**
6349  *
6350  */
6351 Texture * NodePath::
6352 r_find_texture(PandaNode *node, TextureStage *stage) const {
6353  // Look for a TextureAttrib on the node.
6354  const RenderAttrib *attrib =
6355  node->get_attrib(TextureAttrib::get_class_slot());
6356  if (attrib != nullptr) {
6357  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6358  if (ta->has_on_stage(stage)) {
6359  return ta->get_on_texture(stage);
6360  }
6361  }
6362 
6363  if (node->is_geom_node()) {
6364  GeomNode *gnode;
6365  DCAST_INTO_R(gnode, node, nullptr);
6366 
6367  int num_geoms = gnode->get_num_geoms();
6368  for (int i = 0; i < num_geoms; i++) {
6369  CPT(RenderState) geom_state = gnode->get_geom_state(i);
6370 
6371  // Look for a TextureAttrib on the state.
6372  const RenderAttrib *attrib =
6373  geom_state->get_attrib(TextureAttrib::get_class_slot());
6374  if (attrib != nullptr) {
6375  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6376  if (ta->has_on_stage(stage)) {
6377  return ta->get_on_texture(stage);
6378  }
6379  }
6380  }
6381  }
6382 
6383  // Now consider children.
6385  int num_children = cr.get_num_children();
6386  for (int i = 0; i < num_children; i++) {
6387  PandaNode *child = cr.get_child(i);
6388 
6389  Texture *result = r_find_texture(child, stage);
6390  if (result != nullptr) {
6391  return result;
6392  }
6393  }
6394 
6395  return nullptr;
6396 }
6397 
6398 /**
6399  *
6400  */
6401 void NodePath::
6402 r_find_all_textures(PandaNode *node, TextureStage *stage,
6403  NodePath::Textures &textures) const {
6404  // Look for a TextureAttrib on the node.
6405  const RenderAttrib *attrib =
6406  node->get_attrib(TextureAttrib::get_class_slot());
6407  if (attrib != nullptr) {
6408  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6409  if (ta->has_on_stage(stage)) {
6410  textures.insert(ta->get_on_texture(stage));
6411  }
6412  }
6413 
6414  if (node->is_geom_node()) {
6415  GeomNode *gnode;
6416  DCAST_INTO_V(gnode, node);
6417 
6418  int num_geoms = gnode->get_num_geoms();
6419  for (int i = 0; i < num_geoms; i++) {
6420  CPT(RenderState) geom_state = gnode->get_geom_state(i);
6421 
6422  // Look for a TextureAttrib on the state.
6423  const RenderAttrib *attrib =
6424  geom_state->get_attrib(TextureAttrib::get_class_slot());
6425  if (attrib != nullptr) {
6426  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6427  if (ta->has_on_stage(stage)) {
6428  textures.insert(ta->get_on_texture(stage));
6429  }
6430  }
6431  }
6432  }
6433 
6434  // Now consider children.
6436  int num_children = cr.get_num_children();
6437  for (int i = 0; i < num_children; i++) {
6438  PandaNode *child = cr.get_child(i);
6439  r_find_all_textures(child, stage, textures);
6440  }
6441 }
6442 
6443 /**
6444  * Recursively replaces references to the given texture on this section of the
6445  * scene graph with the given other texture.
6446  */
6447 void NodePath::
6448 r_replace_texture(PandaNode *node, Texture *tex, Texture *new_tex) {
6449  // Consider the state of the node itself.
6450  {
6451  CPT(RenderState) node_state = node->get_state();
6452  const TextureAttrib *ta;
6453  if (node_state->get_attrib(ta)) {
6454  CPT(RenderAttrib) new_ta = ta->replace_texture(tex, new_tex);
6455  if (new_ta != ta) {
6456  node->set_state(node_state->set_attrib(new_ta));
6457  }
6458  }
6459  }
6460 
6461  // If this is a GeomNode, consider the state of any of its Geoms.
6462  if (node->is_geom_node()) {
6463  GeomNode *gnode;
6464  DCAST_INTO_V(gnode, node);
6465 
6466  int num_geoms = gnode->get_num_geoms();
6467  for (int i = 0; i < num_geoms; i++) {
6468  CPT(RenderState) geom_state = gnode->get_geom_state(i);
6469 
6470  // Look for a TextureAttrib on the state.
6471  const TextureAttrib *ta;
6472  if (geom_state->get_attrib(ta)) {
6473  CPT(RenderAttrib) new_ta = ta->replace_texture(tex, new_tex);
6474  if (new_ta != ta) {
6475  gnode->set_geom_state(i, geom_state->set_attrib(new_ta));
6476  }
6477  }
6478  }
6479  }
6480 
6481  // Now consider children.
6483  size_t num_children = cr.get_num_children();
6484  for (size_t i = 0; i < num_children; ++i) {
6485  PandaNode *child = cr.get_child(i);
6486  r_replace_texture(child, tex, new_tex);
6487  }
6488 }
6489 
6490 /**
6491  *
6492  */
6493 TextureStage * NodePath::
6494 r_find_texture_stage(PandaNode *node, const RenderState *state,
6495  const GlobPattern &glob) const {
6496  if (node->is_geom_node()) {
6497  GeomNode *gnode;
6498  DCAST_INTO_R(gnode, node, nullptr);
6499 
6500  int num_geoms = gnode->get_num_geoms();
6501  for (int i = 0; i < num_geoms; i++) {
6502  CPT(RenderState) geom_state =
6503  state->compose(gnode->get_geom_state(i));
6504 
6505  // Look for a TextureAttrib on the state.
6506  const RenderAttrib *attrib =
6507  geom_state->get_attrib(TextureAttrib::get_class_slot());
6508  if (attrib != nullptr) {
6509  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6510  for (int i = 0; i < ta->get_num_on_stages(); i++) {
6511  TextureStage *texture_stage = ta->get_on_stage(i);
6512  if (texture_stage != nullptr) {
6513  if (glob.matches(texture_stage->get_name())) {
6514  return texture_stage;
6515  }
6516  }
6517  }
6518  }
6519  }
6520  }
6521 
6522  // Now consider children.
6524  int num_children = cr.get_num_children();
6525  for (int i = 0; i < num_children; i++) {
6526  PandaNode *child = cr.get_child(i);
6527  CPT(RenderState) next_state = state->compose(child->get_state());
6528 
6529  TextureStage *result = r_find_texture_stage(child, next_state, glob);
6530  if (result != nullptr) {
6531  return result;
6532  }
6533  }
6534 
6535  return nullptr;
6536 }
6537 
6538 /**
6539  *
6540  */
6541 void NodePath::
6542 r_find_all_texture_stages(PandaNode *node, const RenderState *state,
6543  NodePath::TextureStages &texture_stages) const {
6544  if (node->is_geom_node()) {
6545  GeomNode *gnode;
6546  DCAST_INTO_V(gnode, node);
6547 
6548  int num_geoms = gnode->get_num_geoms();
6549  for (int i = 0; i < num_geoms; i++) {
6550  CPT(RenderState) geom_state =
6551  state->compose(gnode->get_geom_state(i));
6552 
6553  // Look for a TextureAttrib on the state.
6554  const RenderAttrib *attrib =
6555  geom_state->get_attrib(TextureAttrib::get_class_slot());
6556  if (attrib != nullptr) {
6557  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6558  for (int i = 0; i < ta->get_num_on_stages(); i++) {
6559  TextureStage *texture_stage = ta->get_on_stage(i);
6560  if (texture_stage != nullptr) {
6561  texture_stages.insert(texture_stage);
6562  }
6563  }
6564  }
6565  }
6566  }
6567 
6568  // Now consider children.
6570  int num_children = cr.get_num_children();
6571  for (int i = 0; i < num_children; i++) {
6572  PandaNode *child = cr.get_child(i);
6573  CPT(RenderState) next_state = state->compose(child->get_state());
6574  r_find_all_texture_stages(child, next_state, texture_stages);
6575  }
6576 }
6577 
6578 /**
6579  *
6580  */
6581 void NodePath::
6582 r_unify_texture_stages(PandaNode *node, TextureStage *stage) {
6583  // Look for a TextureAttrib on the state.
6584  const RenderAttrib *attrib =
6585  node->get_attrib(TextureAttrib::get_class_slot());
6586  if (attrib != nullptr) {
6587  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6588  CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
6589  if (new_attrib != ta) {
6590  node->set_attrib(new_attrib);
6591  }
6592  }
6593 
6594  if (node->is_geom_node()) {
6595  GeomNode *gnode;
6596  DCAST_INTO_V(gnode, node);
6597 
6598  int num_geoms = gnode->get_num_geoms();
6599  for (int i = 0; i < num_geoms; i++) {
6600  CPT(RenderState) state = gnode->get_geom_state(i);
6601 
6602  // Look for a TextureAttrib on the state.
6603  const RenderAttrib *attrib =
6604  state->get_attrib(TextureAttrib::get_class_slot());
6605  if (attrib != nullptr) {
6606  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
6607  CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
6608  if (new_attrib != ta) {
6609  CPT(RenderState) new_state = state->add_attrib(new_attrib);
6610  gnode->set_geom_state(i, new_state);
6611  }
6612  }
6613  }
6614  }
6615 
6616  // Now consider children.
6618  int num_children = cr.get_num_children();
6619  for (int i = 0; i < num_children; i++) {
6620  PandaNode *child = cr.get_child(i);
6621  r_unify_texture_stages(child, stage);
6622  }
6623 }
6624 
6625 /**
6626  *
6627  */
6628 Material *NodePath::
6629 r_find_material(PandaNode *node, const RenderState *state,
6630  const GlobPattern &glob) const {
6631  if (node->is_geom_node()) {
6632  GeomNode *gnode;
6633  DCAST_INTO_R(gnode, node, nullptr);
6634 
6635  int num_geoms = gnode->get_num_geoms();
6636  for (int i = 0; i < num_geoms; i++) {
6637  CPT(RenderState) geom_state =
6638  state->compose(gnode->get_geom_state(i));
6639 
6640  // Look for a MaterialAttrib on the state.
6641  const RenderAttrib *attrib =
6642  geom_state->get_attrib(MaterialAttrib::get_class_slot());
6643  if (attrib != nullptr) {
6644  const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
6645  if (!ta->is_off()) {
6646  Material *material = ta->get_material();
6647  if (material != nullptr) {
6648  if (glob.matches(material->get_name())) {
6649  return material;
6650  }
6651  }
6652  }
6653  }
6654  }
6655  }
6656 
6657  // Now consider children.
6659  int num_children = cr.get_num_children();
6660  for (int i = 0; i < num_children; i++) {
6661  PandaNode *child = cr.get_child(i);
6662  CPT(RenderState) next_state = state->compose(child->get_state());
6663 
6664  Material *result = r_find_material(child, next_state, glob);
6665  if (result != nullptr) {
6666  return result;
6667  }
6668  }
6669 
6670  return nullptr;
6671 }
6672 
6673 /**
6674  *
6675  */
6676 void NodePath::
6677 r_find_all_materials(PandaNode *node, const RenderState *state,
6678  NodePath::Materials &materials) const {
6679  if (node->is_geom_node()) {
6680  GeomNode *gnode;
6681  DCAST_INTO_V(gnode, node);
6682 
6683  int num_geoms = gnode->get_num_geoms();
6684  for (int i = 0; i < num_geoms; i++) {
6685  CPT(RenderState) geom_state =
6686  state->compose(gnode->get_geom_state(i));
6687 
6688  // Look for a MaterialAttrib on the state.
6689  const RenderAttrib *attrib =
6690  geom_state->get_attrib(MaterialAttrib::get_class_slot());
6691  if (attrib != nullptr) {
6692  const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
6693  if (!ta->is_off()) {
6694  Material *material = ta->get_material();
6695  if (material != nullptr) {
6696  materials.insert(material);
6697  }
6698  }
6699  }
6700  }
6701  }
6702 
6703  // Now consider children.
6705  int num_children = cr.get_num_children();
6706  for (int i = 0; i < num_children; i++) {
6707  PandaNode *child = cr.get_child(i);
6708  CPT(RenderState) next_state = state->compose(child->get_state());
6709  r_find_all_materials(child, next_state, materials);
6710  }
6711 }
6712 
6713 /**
6714  *
6715  */
6716 void NodePath::
6717 r_replace_material(PandaNode *node, Material *mat,
6718  const MaterialAttrib *new_attrib) {
6719  // Consider the state of the node itself.
6720  {
6721  CPT(RenderState) node_state = node->get_state();
6722  const MaterialAttrib *ma;
6723  if (node_state->get_attrib(ma)) {
6724  if (mat == ma->get_material()) {
6725  node->set_state(node_state->set_attrib(new_attrib));
6726  }
6727  }
6728  }
6729 
6730  // If this is a GeomNode, consider the state of any of its Geoms.
6731  if (node->is_geom_node()) {
6732  GeomNode *gnode;
6733  DCAST_INTO_V(gnode, node);
6734 
6735  int num_geoms = gnode->get_num_geoms();
6736  for (int i = 0; i < num_geoms; i++) {
6737  CPT(RenderState) geom_state = gnode->get_geom_state(i);
6738 
6739  // Look for a MaterialAttrib on the state.
6740  const MaterialAttrib *ma;
6741  if (geom_state->get_attrib(ma)) {
6742  if (mat == ma->get_material()) {
6743  // Replace it
6744  gnode->set_geom_state(i, geom_state->set_attrib(new_attrib));
6745  }
6746  }
6747  }
6748  }
6749 
6750  // Now consider children.
6752  size_t num_children = cr.get_num_children();
6753  for (size_t i = 0; i < num_children; ++i) {
6754  PandaNode *child = cr.get_child(i);
6755  r_replace_material(child, mat, new_attrib);
6756  }
6757 }
6758 
6759 /**
6760  * Writes the contents of this object to the datagram for shipping out to a
6761  * Bam file.
6762  */
6764 write_datagram(BamWriter *manager, Datagram &dg) const {
6765  if (is_empty()) {
6766  manager->write_pointer(dg, nullptr);
6767  return;
6768  }
6769 
6770  PandaNode *root = DCAST(PandaNode, manager->get_root_node());
6771 
6772  // We have no root node to measure from.
6773  if (root == nullptr || root == node()) {
6774  manager->write_pointer(dg, node());
6775  manager->write_pointer(dg, nullptr);
6776  return;
6777  }
6778 
6779  Thread *current_thread = Thread::get_current_thread();
6780  int pipeline_stage = current_thread->get_pipeline_stage();
6781 
6782  // Record the chain of nodes from the root to this node.
6783  pvector<PandaNode *> path;
6784  NodePathComponent *comp = _head;
6785  while (comp != nullptr) {
6786  PandaNode *node = comp->get_node();
6787  path.push_back(node);
6788 
6789  if (node == root) {
6790  break;
6791  }
6792 
6793  comp = comp->get_next(pipeline_stage, current_thread);
6794  }
6795 
6796  if (comp == nullptr) {
6797  // We did not encounter the root node. Not much we can do.
6798  manager->write_pointer(dg, node());
6799  manager->write_pointer(dg, nullptr);
6800  return;
6801  }
6802 
6803  // Write out the nodes in reverse order, for fast reconstructing.
6804  for (int i = path.size() - 1; i >= 0; --i) {
6805  manager->write_pointer(dg, path[i]);
6806  }
6807  manager->write_pointer(dg, nullptr);
6808 }
6809 
6810 /**
6811  * Receives an array of pointers, one for each time manager->read_pointer()
6812  * was called in fillin(). Returns the number of pointers processed.
6813  */
6815 complete_pointers(TypedWritable **p_list, BamReader *manager) {
6816  int pi = 0;
6817  PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]);
6818  if (node.is_null()) {
6819  // An empty NodePath.
6820  _head = nullptr;
6821  return pi;
6822  }
6823 
6824  Thread *current_thread = Thread::get_current_thread();
6825  int pipeline_stage = current_thread->get_pipeline_stage();
6826 
6827  // Take an arbitrary path to the root of the NodePath. This probably won't
6828  // be ambiguous, as this is usually the root of the model or scene we are
6829  // currently loading.
6830  PT(NodePathComponent) comp = node->get_generic_component(false, pipeline_stage, current_thread);
6831  nassertd(!comp.is_null()) {
6832  while (p_list[pi++]) {}
6833  return pi;
6834  }
6835 
6836  // Build up the chain of NodePathComponents leading up to this node.
6837  while (p_list[pi] != nullptr) {
6838  PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]);
6839 
6840  LightReMutexHolder holder(node->_paths_lock);
6841 
6842  // First, walk through the list of NodePathComponents we already have on
6843  // the child, looking for one that already exists, referencing the
6844  // indicated parent component.
6845  PandaNode::Paths::const_iterator it;
6846  for (it = node->_paths.begin(); it != node->_paths.end(); ++it) {
6847  if ((*it)->get_next(pipeline_stage, current_thread) == comp) {
6848  // If we already have such a component, use that.
6849  comp = (*it);
6850  break;
6851  }
6852  }
6853 
6854  if (it == node->_paths.end()) {
6855  // We don't already have a NodePathComponent referring to this parent-
6856  // child relationship. Create a new one. Note that we can't verify
6857  // that they are actually related because we may not have completed the
6858  // node's pointers yet, so we trust that the .bam is right.
6859  comp = new NodePathComponent(node, comp, pipeline_stage, current_thread);
6860  node->_paths.insert(comp);
6861  }
6862  }
6863  // One more for the final NULL node.
6864  ++pi;
6865 
6866  _head = comp;
6867  return pi;
6868 }
6869 
6870 /**
6871  * This internal function is called by make_from_bam to read in all of the
6872  * relevant data from the BamFile for the new NodePath.
6873  */
6875 fillin(DatagramIterator &scan, BamReader *manager) {
6876  while(manager->read_pointer(scan)) {};
6877 }
NodePath::set_pos_quat_scale
void set_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat, const LVecBase3 &scale)
Replaces the translation, rotation, and scale components, implicitly setting shear to 0.
Definition: nodePath.cxx:1254
Geom
A container for geometry primitives.
Definition: geom.h:54
NodePath::clear_texture
void clear_texture()
Completely removes any texture adjustment that may have been set via set_texture() or set_texture_off...
Definition: nodePath.cxx:3002
NodePath::has_audio_volume
bool has_audio_volume() const
Returns true if an audio volume has been applied to the referenced node, false otherwise.
Definition: nodePath.cxx:5013
PandaNode::find_parent
int find_parent(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated parent node, if it is a parent, or -1 if it is not.
Definition: pandaNode.I:44
NodePath::set_transform
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Changes the complete transform object on this node.
Definition: nodePath.I:565
RenderModeAttrib::get_mode
get_mode
Returns the render mode.
Definition: renderModeAttrib.h:69
NodePath::write_bam_file
bool write_bam_file(const Filename &filename) const
Writes the contents of this node and below out to a bam file with the indicated filename.
Definition: nodePath.cxx:5616
clipPlaneAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::set_alpha_scale
void set_alpha_scale(PN_stdfloat scale, int priority=0)
Sets the alpha scale component of the transform without (much) affecting the color scale.
Definition: nodePath.cxx:2122
DepthTestAttrib::get_mode
get_mode
Returns the depth write mode.
Definition: depthTestAttrib.h:37
texturePool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::wrt_reparent_to
void wrt_reparent_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread())
This functions identically to reparent_to(), except the transform on this node is also adjusted so th...
Definition: nodePath.cxx:433
DepthTestAttrib
Enables or disables writing to the depth buffer.
Definition: depthTestAttrib.h:26
nodePath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::is_geom_node
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2062
NodePath::has_antialias
bool has_antialias() const
Returns true if an antialias setting has been explicitly mode on this particular node via set_antiali...
Definition: nodePath.cxx:4985
NodePath::clear_material
void clear_material()
Completely removes any material adjustment that may have been set via set_material() from this partic...
Definition: nodePath.cxx:4138
PandaNode::clear_effect
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
Definition: pandaNode.cxx:1016
PandaNode::set_effect
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: pandaNode.cxx:999
TransformState::get_quat
get_quat
Returns the rotation component of the transform as a quaternion.
Definition: transformState.h:152
RenderModeAttrib::get_thickness
get_thickness
Returns the line width or point thickness.
Definition: renderModeAttrib.h:70
ClipPlaneAttrib
This functions similarly to a LightAttrib.
Definition: clipPlaneAttrib.h:31
DatagramIterator::get_int32
int32_t get_int32()
Extracts a signed 32-bit integer.
Definition: datagramIterator.I:107
BamReader::set_source
set_source
Changes the source of future datagrams for this BamReader.
Definition: bamReader.h:154
occluderNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::clear_depth_write
void clear_depth_write()
Completely removes any depth-write adjustment that may have been set on this node via set_depth_write...
Definition: nodePath.cxx:4579
NodePath::look_at
void look_at(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the transform on this NodePath so that it rotates to face the indicated point in space.
Definition: nodePath.I:789
NodePath::has_transparency
bool has_transparency() const
Returns true if a transparent-rendering adjustment has been explicitly set on this particular node vi...
Definition: nodePath.cxx:4876
NodePath::has_tag
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: nodePath.I:2027
TextureCollection
Manages a list of Texture objects, as returned by TexturePool::find_all_textures().
Definition: textureCollection.h:25
Shader
Definition: shader.h:49
billboardEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
NodePath::set_texture
void set_texture(Texture *tex, int priority=0)
Adds the indicated texture to the list of textures that will be rendered on the default texture stage...
Definition: nodePath.cxx:2871
NodePath::find_all_textures
TextureCollection find_all_textures() const
Returns a list of a textures applied to geometry at this node and below.
Definition: nodePath.cxx:3933
NodePath::clear_color_scale
void clear_color_scale()
Completely removes any color scale from the referenced node.
Definition: nodePath.cxx:2040
NodePath::set_render_mode_filled_wireframe
void set_render_mode_filled_wireframe(const LColor &wireframe_color, int priority=0)
Sets up the geometry at this level and below (unless overridden) to render in filled,...
Definition: nodePath.cxx:4315
NodePath::premunge_scene
void premunge_scene(GraphicsStateGuardianBase *gsg=nullptr)
Walks through the scene graph beginning at the bottom node, and internally adjusts any GeomVertexForm...
Definition: nodePath.cxx:5319
AntialiasAttrib
Specifies whether or how to enable antialiasing, if supported by the backend renderer.
Definition: antialiasAttrib.h:27
ClipPlaneAttrib::has_on_plane
bool has_on_plane(const NodePath &plane) const
Returns true if the indicated plane is enabled by the attrib, false otherwise.
Definition: clipPlaneAttrib.I:56
SceneGraphReducer
An interface for simplifying ("flattening") scene graphs by eliminating unneeded nodes and collapsing...
Definition: sceneGraphReducer.h:39
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
SceneGraphReducer::make_compatible_state
int make_compatible_state(PandaNode *root)
Searches for GeomNodes that contain multiple Geoms that differ only in their ColorAttribs.
Definition: sceneGraphReducer.cxx:143
NodePath::encode_to_bam_stream
vector_uchar encode_to_bam_stream() const
Converts the NodePath object into a single stream of data using a BamWriter, and returns that data as...
Definition: nodePath.I:2105
NodePath::get_logic_op
LogicOpAttrib::Operation get_logic_op() const
Returns the logical operation that has been specifically set on this node via set_logic_op(),...
Definition: nodePath.cxx:4946
config_gobj.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BoundingSphere
This defines a bounding sphere, consisting of a center and a radius.
Definition: boundingSphere.h:25
NodePath::set_state
void set_state(const RenderState *state, Thread *current_thread=Thread::get_current_thread())
Changes the complete state object on this node.
Definition: nodePath.I:427
NodePath::get_num_nodes
get_num_nodes
Returns the number of nodes in the path.
Definition: nodePath.h:204
NodePath::has_color
bool has_color() const
Returns true if a color has been applied to the given node, false otherwise.
Definition: nodePath.cxx:1996
NodePath::get_depth_test
bool get_depth_test() const
Returns true if depth-test rendering has been specifically set on this node via set_depth_test(),...
Definition: nodePath.cxx:4545
NodePath::find_texture_stage
TextureStage * find_texture_stage(const std::string &name) const
Returns the first TextureStage found applied to geometry at this node or below that matches the indic...
Definition: nodePath.cxx:3994
NodePath::set_clip_plane
void set_clip_plane(const NodePath &clip_plane, int priority=0)
Adds the indicated clipping plane to the list of planes that apply to geometry at this node and below...
Definition: nodePath.cxx:2441
PandaNode::get_stashed_sort
int get_stashed_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth stashed node of this node (that is, the number that was passed to a...
Definition: pandaNode.I:166
NodePath::set_fog_off
void set_fog_off(int priority=0)
Sets the geometry at this level and below to render using no fog.
Definition: nodePath.cxx:4212
NodePath::get_color
LColor get_color() const
Returns the color that has been assigned to the node, or black if no color has been assigned.
Definition: nodePath.cxx:2006
NodePath::clear_transparency
void clear_transparency()
Completely removes any transparency adjustment that may have been set on this node via set_transparen...
Definition: nodePath.cxx:4864
BamWriter::set_target
set_target
Changes the destination of future datagrams written by the BamWriter.
Definition: bamWriter.h:91
NodePath::has_fog
bool has_fog() const
Returns true if a fog has been applied to this particular node via set_fog(), false otherwise.
Definition: nodePath.cxx:4235
RenderEffect
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
GeomVertexArrayFormat::get_column
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
Definition: geomVertexArrayFormat.h:106
TextureStageCollection
Definition: textureStageCollection.h:24
NodePathCollection::add_path
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
Definition: nodePathCollection.cxx:29
NodePath::set_hpr
void set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r)
Sets the rotation component of the transform, leaving translation and scale untouched.
Definition: nodePath.I:651
NodePath::set_render_mode
void set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority=0)
Sets up the geometry at this level and below (unless overridden) to render in the specified mode and ...
Definition: nodePath.cxx:4361
NodePathComponent::get_node
PandaNode * get_node() const
Returns the node referenced by this component.
Definition: nodePathComponent.I:45
NodePath::has_parent
has_parent
Returns true if the referenced node has a parent; i.e.
Definition: nodePath.h:242
NodePath::get_two_sided
bool get_two_sided() const
Returns true if two-sided rendering has been specifically set on this node via set_two_sided(),...
Definition: nodePath.cxx:4488
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
Thread::is_true_threads
is_true_threads
Returns true if a real threading library is available that supports actual OS-implemented threads,...
Definition: thread.h:113
NodePath::set_tex_projector
void set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to, int lens_index=0)
Establishes a TexProjectorEffect on this node, which can be used to establish projective texturing (b...
Definition: nodePath.cxx:3676
NodePath::get_scale
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
Definition: nodePath.cxx:1128
BamFile::open_write
bool open_write(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated file for writing.
Definition: bamFile.cxx:190
TransparencyAttrib
This controls the enabling of transparency.
Definition: transparencyAttrib.h:31
NodePath::calc_tight_bounds
bool calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, const NodePath &other=NodePath(), Thread *current_thread=Thread::get_current_thread()) const
Calculates the minimum and maximum vertices of all Geoms at this NodePath's bottom node and below.
Definition: nodePath.cxx:5434
dcast.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamWriter::set_root_node
set_root_node
Sets the root node of the part of the scene graph we are currently writing out.
Definition: bamWriter.h:96
sceneGraphReducer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::has_fog_off
bool has_fog_off() const
Returns true if a fog has been specifically disabled on this particular node via set_fog_off(),...
Definition: nodePath.cxx:4254
NodePath::clear_bin
void clear_bin()
Completely removes any bin adjustment that may have been set via set_bin() from this particular node.
Definition: nodePath.cxx:2811
CPT
CPT(RenderState) NodePath
Returns the state changes that must be made to transition to the render state of this node from the r...
Definition: nodePath.cxx:697
NodePath::set_texture_off
void set_texture_off(int priority=0)
Sets the geometry at this level and below to render using no texture, on any stage.
Definition: nodePath.cxx:2961
NodePath::set_billboard_point_world
void set_billboard_point_world(PN_stdfloat offset=0.0)
Puts a billboard transition on the node such that it will rotate in three dimensions about the origin...
Definition: nodePath.I:1764
InternalName::get_top
const InternalName * get_top() const
Returns the oldest ancestor in the InternalName's chain, not counting the root.
Definition: internalName.cxx:219
GeomVertexArrayFormat::get_num_columns
get_num_columns
Returns the number of different columns in the array.
Definition: geomVertexArrayFormat.h:106
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
NodePath::clear_tex_transform
void clear_tex_transform()
Removes all texture matrices from the current node.
Definition: nodePath.cxx:3423
NodePath::set_bin
void set_bin(const std::string &bin_name, int draw_order, int priority=0)
Assigns the geometry at this level and below to the named rendering bin.
Definition: nodePath.cxx:2801
preparedGraphicsObjects.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::reparent_to
void reparent_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread())
Removes the referenced node of the NodePath from its current parent and attaches it to the referenced...
Definition: nodePath.cxx:391
materialCollection.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::set_light
void set_light(const NodePath &light, int priority=0)
Adds the indicated Light or PolylightNode to the list of lights that illuminate geometry at this node...
Definition: nodePath.cxx:2194
DepthWriteAttrib::get_mode
get_mode
Returns the depth write mode.
Definition: depthWriteAttrib.h:43
NodePath::get_state
const RenderState * get_state(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete state object set on this node.
Definition: nodePath.cxx:686
SceneGraphReducer::collect_vertex_data
int collect_vertex_data(PandaNode *root, int collect_bits=~0)
Collects all different GeomVertexData blocks that have compatible formats at this node and below into...
Definition: sceneGraphReducer.I:139
TextureAttrib::get_on_texture
get_on_texture
Returns the texture associated with the indicated stage, or NULL if no texture is associated.
Definition: textureAttrib.h:69
NodePath::get_key
int get_key() const
Returns an integer that is guaranteed to be the same for all NodePaths that represent the same node i...
Definition: nodePath.I:245
Material
Defines the way an object appears in the presence of lighting.
Definition: material.h:43
NodePath::reverse_ls
void reverse_ls() const
Lists the hierarchy at and above the referenced node.
Definition: nodePath.I:419
PandaNode::find_child
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
ModelNode::set_preserve_transform
void set_preserve_transform(PreserveTransform preserve_transform)
Sets the preserve_transform flag.
Definition: modelNode.I:52
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
polylightEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::has_material
bool has_material() const
Returns true if a material has been applied to this particular node via set_material(),...
Definition: nodePath.cxx:4148
NodePath::clear_fog
void clear_fog()
Completely removes any fog adjustment that may have been set via set_fog() or set_fog_off() from this...
Definition: nodePath.cxx:4223
modelNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::get_relative_vector
LVector3 get_relative_vector(const NodePath &other, const LVecBase3 &vec) const
Given that the indicated vector is in the coordinate system of the other node, returns the same vecto...
Definition: nodePath.cxx:1903
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
colorAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
SamplerState::get_default
static const SamplerState & get_default()
Returns a reference to the global default immutable SamplerState object.
Definition: samplerState.I:36
BamWriter::write_pointer
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
InternalName::get_net_basename
std::string get_net_basename(int n) const
Returns the basename of this name prefixed by the indicated number of ancestors.
Definition: internalName.cxx:234
RenderAttrib
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
shaderInput.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::clear_antialias
void clear_antialias()
Completely removes any antialias setting that may have been set on this node via set_antialias().
Definition: nodePath.cxx:4974
NodePathCollection::get_path
get_path
Returns the nth NodePath in the collection.
Definition: nodePathCollection.h:47
compassEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
weakNodePath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::Children::get_child
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition: pandaNode.I:962
ShaderAttrib
Definition: shaderAttrib.h:39
scissorEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
bam.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::do_billboard_axis
void do_billboard_axis(const NodePath &camera, PN_stdfloat offset)
Performs a billboard-type rotate to the indicated camera node, one time only, and leaves the object r...
Definition: nodePath.cxx:4674
NodePath::find_material
Material * find_material(const std::string &name) const
Returns the first material found applied to geometry at this node or below that matches the indicated...
Definition: nodePath.cxx:4061
FogAttrib
Applies a Fog to the geometry at and below this node.
Definition: fogAttrib.h:25
MaterialAttrib::is_off
bool is_off() const
Returns true if the MaterialAttrib is an 'off' MaterialAttrib, indicating that it should disable the ...
Definition: materialAttrib.I:26
FogAttrib::is_off
bool is_off() const
Returns true if the FogAttrib is an 'off' FogAttrib, indicating that it should disable fog.
Definition: fogAttrib.I:26
NodePath::set_pos_hpr_scale_shear
void set_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale, const LVecBase3 &shear)
Completely replaces the transform with new translation, rotation, scale, and shear components.
Definition: nodePath.cxx:1267
NodePath::compare_to
int compare_to(const NodePath &other) const
Returns a number less than zero if this NodePath sorts before the other one, greater than zero if it ...
Definition: nodePath.I:1955
PandaNode::set_state
set_state
Sets the complete RenderState that will be applied to all nodes at this level and below.
Definition: pandaNode.h:173
NodePath::operator!=
bool operator!=(const NodePath &other) const
Returns true if the two paths are not equivalent.
Definition: nodePath.I:1929
PandaNode::get_child_sort
int get_child_sort(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the sort index of the nth child node of this node (that is, the number that was passed to add...
Definition: pandaNode.I:78
TransformState::get_mat
get_mat
Returns the matrix that describes the transform.
Definition: transformState.h:156
NodePath::get_transform
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:758
NodePathCollection::is_empty
bool is_empty() const
Returns true if there are no NodePaths in the collection, false otherwise.
Definition: nodePathCollection.cxx:167
BitMask< uint32_t, 32 >
TextureStage::get_name
get_name
Returns the name of this texture stage.
Definition: textureStage.h:188
showBoundsEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::project_texture
void project_texture(TextureStage *stage, Texture *tex, const NodePath &projector)
A convenience function to enable projective texturing at this node level and below,...
Definition: nodePath.cxx:3788
Texture
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
NodePath::clear_clip_plane
void clear_clip_plane()
Completely removes any clip planes that may have been set via set_clip_plane() or set_clip_plane_off(...
Definition: nodePath.cxx:2520
NodePath::clear_scissor
void clear_scissor()
Removes the scissor region that was defined at this node level by a previous call to set_scissor().
Definition: nodePath.cxx:2767
NodePath::get_parent
get_parent
Returns the NodePath to the parent of the referenced node: that is, this NodePath,...
Definition: nodePath.h:242
NodePath::write_bounds
void write_bounds(std::ostream &out) const
Writes a description of the bounding volume containing the bottom node and all of its descendants to ...
Definition: nodePath.cxx:5414
TransformState::get_shear
get_shear
Returns the shear component of the transform.
Definition: transformState.h:155
NodePath::flatten_light
int flatten_light()
Analyzes the geometry below this node and reports the number of vertices, triangles,...
Definition: nodePath.cxx:5510
GlobPattern::matches
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:122
NodePath::prepare_scene
void prepare_scene(GraphicsStateGuardianBase *gsg)
Walks through the scene graph beginning at the bottom node, and does whatever initialization is requi...
Definition: nodePath.cxx:5342
AntialiasAttrib::get_mode
get_mode
Returns the specified antialias mode.
Definition: antialiasAttrib.h:56
NodePath::set_billboard_point_eye
void set_billboard_point_eye(PN_stdfloat offset=0.0, bool fixed_depth=false)
Puts a billboard transition on the node such that it will rotate in three dimensions about the origin...
Definition: nodePath.I:1755
NodePath::find_all_matches
NodePathCollection find_all_matches(const std::string &path) const
Returns the complete set of all NodePaths that begin with this NodePath and can be extended by path.
Definition: nodePath.cxx:354
NodePath::not_found
static NodePath not_found()
Creates a NodePath with the ET_not_found error type set.
Definition: nodePath.I:129
Light
The abstract interface to all kinds of lights.
Definition: light.h:38
NodePath::get_shear
LVecBase3 get_shear() const
Retrieves the shear component of the transform.
Definition: nodePath.cxx:1176
NodePath::show_tight_bounds
void show_tight_bounds()
Similar to show_bounds(), this draws a bounding box representing the "tight" bounds of this node and ...
Definition: nodePath.cxx:5367
NodePath::set_billboard_axis
void set_billboard_axis(PN_stdfloat offset=0.0)
Puts a billboard transition on the node such that it will rotate in two dimensions around the up axis...
Definition: nodePath.I:1745
GeomNode::set_geom_state
void set_geom_state(int n, const RenderState *state)
Changes the RenderState associated with the nth geom of the node.
Definition: geomNode.I:102
NodePath::set_all_color_scale
void set_all_color_scale(PN_stdfloat scale, int priority=0)
Scales all the color components of the object by the same amount, darkening the object,...
Definition: nodePath.cxx:2148
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PandaNode::get_children
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.h:782
NodePath::get_render_mode_thickness
PN_stdfloat get_render_mode_thickness() const
Returns the render mode thickness that has been specifically set on this node via set_render_mode(),...
Definition: nodePath.cxx:4410
InternalNameCollection::add_name
void add_name(const InternalName *name)
Adds a new InternalName to the collection.
Definition: internalNameCollection.cxx:46
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
NodePath::get_pos_delta
LVector3 get_pos_delta() const
Returns the delta vector from this node's position in the previous frame (according to set_prev_trans...
Definition: nodePath.cxx:1007
NodePath::set_material
void set_material(Material *tex, int priority=0)
Sets the geometry at this level and below to render using the indicated material.
Definition: nodePath.cxx:4115
FindApproxPath::add_match_pointer
void add_match_pointer(PandaNode *pointer, int flags)
Adds a component that must match a particular node exactly, by pointer.
Definition: findApproxPath.cxx:397
PandaNode::get_draw_show_mask
get_draw_show_mask
Returns the hide/show bits of this particular node.
Definition: pandaNode.h:256
GeomNode::get_num_geoms
get_num_geoms
Returns the number of geoms in the node.
Definition: geomNode.h:71
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
NodePath::get_depth_offset
int get_depth_offset() const
Returns the depth offset value if it has been specified using set_depth_offset, or 0 if not.
Definition: nodePath.cxx:4656
NodePath::is_stashed
bool is_stashed() const
Returns true if the referenced node is stashed either directly, or because some ancestor is stashed.
Definition: nodePath.I:1877
NodePath::instance_to
NodePath instance_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Adds the referenced node of the NodePath as a child of the referenced node of the indicated other Nod...
Definition: nodePath.cxx:471
NodePath::fillin
void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is called by make_from_bam to read in all of the relevant data from the BamFil...
Definition: nodePath.cxx:6875
SceneGraphReducer::unify
void unify(PandaNode *root, bool preserve_order)
Calls unify() on every GeomNode at this level and below.
Definition: sceneGraphReducer.cxx:178
NodePath::set_pos_quat
void set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat)
Sets the translation and rotation component of the transform, leaving scale untouched.
Definition: nodePath.cxx:1201
texProjectorEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::set_pos_quat_scale_shear
void set_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat, const LVecBase3 &scale, const LVecBase3 &shear)
Completely replaces the transform with new translation, rotation, scale, and shear components.
Definition: nodePath.cxx:1280
plist.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::apply_texture_colors
void apply_texture_colors()
Removes textures from Geoms at this node and below by applying the texture colors to the vertices.
Definition: nodePath.cxx:5588
NodePath::set_color_off
void set_color_off(int priority=0)
Sets the geometry at this level and below to render using the geometry color.
Definition: nodePath.cxx:1975
FindApproxLevelEntry::consider_node
bool consider_node(NodePathCollection &result, FindApproxLevelEntry *&next_level, int max_matches, int increment) const
Considers the node represented by the entry for matching the find path.
Definition: findApproxLevelEntry.cxx:59
PandaNode::find_stashed
int find_stashed(PandaNode *node, Thread *current_thread=Thread::get_current_thread()) const
Returns the index of the indicated stashed node, if it is a stashed child, or -1 if it is not.
Definition: pandaNode.I:178
NodePath::set_hpr_scale
void set_hpr_scale(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz)
Sets the rotation and scale components of the transform, leaving translation untouched.
Definition: nodePath.I:737
textureCollection.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
bamFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MaterialCollection
Definition: materialCollection.h:24
NodePath::removed
static NodePath removed()
Creates a NodePath with the ET_removed error type set.
Definition: nodePath.I:139
NodePath::has_texture
bool has_texture() const
Returns true if a texture has been applied to this particular node via set_texture(),...
Definition: nodePath.cxx:3038
PStatTimer
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
materialAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomNode
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
MaterialCollection::add_material
void add_material(Material *node_material)
Adds a new Material to the collection.
Definition: materialCollection.cxx:46
NodePath::set_quat_scale
void set_quat_scale(const LQuaternion &quat, const LVecBase3 &scale)
Sets the rotation and scale components of the transform, leaving translation untouched.
Definition: nodePath.cxx:1228
DepthWriteAttrib
Enables or disables writing to the depth buffer.
Definition: depthWriteAttrib.h:26
NodePath::unstash
void unstash(int sort=0, Thread *current_thread=Thread::get_current_thread())
Undoes the effect of a previous stash() on this node: makes the referenced node (and the entire subgr...
Definition: nodePath.cxx:5155
NodePath::has_light
bool has_light(const NodePath &light) const
Returns true if the indicated Light or PolylightNode has been specifically enabled on this particular...
Definition: nodePath.cxx:2360
NodePath::set_audio_volume
void set_audio_volume(PN_stdfloat volume, int priority=0)
Sets the audio volume component of the transform.
Definition: nodePath.cxx:5033
texGenAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::set_scissor
void set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top)
Sets up a scissor region on the nodes rendered at this level and below.
Definition: nodePath.cxx:2709
findApproxPath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DepthOffsetAttrib::get_offset
get_offset
Returns the depth offset represented by this attrib.
Definition: depthOffsetAttrib.h:64
planeNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::find_path_to
NodePath find_path_to(PandaNode *node) const
Searches for the indicated node below this node and returns the shortest NodePath that connects them.
Definition: nodePath.cxx:332
SamplerState
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:36
NodePath::get_relative_point
LPoint3 get_relative_point(const NodePath &other, const LVecBase3 &point) const
Given that the indicated point is in the coordinate system of the other node, returns the same point ...
Definition: nodePath.cxx:1892
NodePath::set_scale
void set_scale(PN_stdfloat scale)
Sets the scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.I:675
NodePath::set_depth_write
void set_depth_write(bool depth_write, int priority=0)
Specifically sets or disables the writing to the depth buffer on this particular node.
Definition: nodePath.cxx:4563
NodePath::clear_render_mode
void clear_render_mode()
Completely removes any render mode adjustment that may have been set on this node via set_render_mode...
Definition: nodePath.cxx:4372
CullFaceAttrib::get_actual_mode
get_actual_mode
Returns the actual culling mode, without considering the effects of the reverse flag.
Definition: cullFaceAttrib.h:48
NodePath::verify_complete
bool verify_complete(Thread *current_thread=Thread::get_current_thread()) const
Returns true if all of the nodes described in the NodePath are connected, or false otherwise.
Definition: nodePath.cxx:5254
renderModeAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
depthOffsetAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
materialPool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::clear_color
void clear_color()
Completely removes any color adjustment from the node.
Definition: nodePath.cxx:1986
PandaNode::Children
Definition: pandaNode.h:706
InternalName::get_name
get_name
Returns the complete name represented by the InternalName and all of its parents.
Definition: internalName.h:61
PandaNode::set_attrib
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
Definition: pandaNode.cxx:938
TextureAttrib::get_texture
Texture * get_texture() const
If the TextureAttrib is not an 'off' TextureAttrib, returns the base-level texture that is associated...
Definition: textureAttrib.I:61
TransformState::get_scale
get_scale
Returns the scale component of the transform.
Definition: transformState.h:154
TextureCollection::add_texture
void add_texture(Texture *texture)
Adds a new Texture to the collection.
Definition: textureCollection.cxx:45
NodePath::set_effect
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: nodePath.I:490
fogAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::write_bam_stream
bool write_bam_stream(std::ostream &out) const
Writes the contents of this node and below out to the indicated stream.
Definition: nodePath.cxx:5640
NodePath::set_color_scale_off
void set_color_scale_off(int priority=0)
Disables any color scale attribute inherited from above.
Definition: nodePath.cxx:2111
NodePath::output
void output(std::ostream &out) const
Writes a sensible description of the NodePath to the indicated output stream.
Definition: nodePath.cxx:660
NodePath::has_logic_op
bool has_logic_op() const
Returns true if a logical operation has been explicitly set on this particular node via set_logic_op(...
Definition: nodePath.cxx:4932
NodePath::get_sort
get_sort
Returns the sort value of the referenced node within its parent; that is, the sort number passed on t...
Definition: nodePath.h:243
colorScaleAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::set_pos_hpr
void set_pos_hpr(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r)
Sets the translation and rotation component of the transform, leaving scale untouched.
Definition: nodePath.I:728
WorkingNodePath
This is a class designed to support low-overhead traversals of the complete scene graph,...
Definition: workingNodePath.h:39
NodePath::operator<
bool operator<(const NodePath &other) const
Returns true if this NodePath sorts before the other one, false otherwise.
Definition: nodePath.I:1940
Fog
Specifies how atmospheric fog effects are applied to geometry.
Definition: fog.h:41
CullBinAttrib::get_bin_name
get_bin_name
Returns the name of the bin this attribute specifies.
Definition: cullBinAttrib.h:39
NodePath::set_color_scale
void set_color_scale(const LVecBase4 &scale, int priority=0)
Sets the color scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.cxx:2080
BamReader::read_object
TypedWritable * read_object()
Reads a single object from the Bam file.
Definition: bamReader.cxx:224
BamWriter::write_object
bool write_object(const TypedWritable *obj)
Writes a single object to the Bam file, so that the BamReader::read_object() can later correctly rest...
Definition: bamWriter.cxx:204
NodePath::has_bin
bool has_bin() const
Returns true if the node has been assigned to the a particular rendering bin via set_bin(),...
Definition: nodePath.cxx:2821
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
NodePath::clear_tex_projector
void clear_tex_projector()
Removes the TexProjectorEffect for all stages from this node.
Definition: nodePath.cxx:3721
NodePath::get_depth_write
bool get_depth_write() const
Returns true if depth-write rendering has been specifically set on this node via set_depth_write(),...
Definition: nodePath.cxx:4602
NodePath::has_effect
bool has_effect(TypeHandle type) const
Returns true if there is a render effect of the indicated type defined on this node,...
Definition: nodePath.I:510
TextureAttrib::has_all_off
bool has_all_off() const
Returns true if this attrib turns off all stages (although it may also turn some on).
Definition: textureAttrib.I:205
LogicOpAttrib
If enabled, specifies that a custom logical operation be performed instead of any color blending.
Definition: logicOpAttrib.h:30
NodePath::find_all_vertex_columns
InternalNameCollection find_all_vertex_columns() const
Returns a list of all vertex array columns stored on some geometry found at this node level and below...
Definition: nodePath.cxx:3814
NodePath::find_net_tag
NodePath find_net_tag(const std::string &key) const
Returns the lowest ancestor of this node that contains a tag definition with the indicated key,...
Definition: nodePath.cxx:5600
NodePath::set_depth_test
void set_depth_test(bool depth_test, int priority=0)
Specifically sets or disables the testing of the depth buffer on this particular node.
Definition: nodePath.cxx:4506
NodePath::get_audio_volume
PN_stdfloat get_audio_volume() const
Returns the complete audio volume that has been applied to this node via a previous call to set_audio...
Definition: nodePath.cxx:5073
NodePath::clear_tex_gen
void clear_tex_gen()
Removes the texture coordinate generation mode from all texture stages on this node.
Definition: nodePath.cxx:3600
OccluderEffect::has_on_occluder
bool has_on_occluder(const NodePath &occluder) const
Returns true if the indicated occluder is enabled by the effect, false otherwise.
Definition: occluderEffect.I:54
CycleDataReader
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
Definition: cycleDataReader.h:35
DatagramBuffer::swap_data
void swap_data(vector_uchar &other)
Swaps the data in the internal buffer with that of the other buffer.
Definition: datagramBuffer.I:66
SceneGraphReducer::premunge
void premunge(PandaNode *root, const RenderState *initial_state)
Walks the scene graph rooted at this node and below, and uses the indicated GSG to premunge every Geo...
Definition: sceneGraphReducer.I:173
PolylightEffect
A PolylightEffect can be used on a node to define a LightGroup for that node.
Definition: polylightEffect.h:35
boundingSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::clear_billboard
void clear_billboard()
Removes any billboard effect from the node.
Definition: nodePath.cxx:4802
BamFile::write_object
bool write_object(const TypedWritable *object)
Writes the indicated object to the Bam file.
Definition: bamFile.cxx:226
DatagramBuffer
This class can be used to write a series of datagrams into a memory buffer.
Definition: datagramBuffer.h:30
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition: pStatCollector.h:43
NodePath::get_node
get_node
Returns the nth node of the path, where 0 is the referenced (bottom) node and get_num_nodes() - 1 is ...
Definition: nodePath.h:204
NodePath::has_clip_plane
bool has_clip_plane(const NodePath &clip_plane) const
Returns true if the indicated clipping plane has been specifically applied to this particular node.
Definition: nodePath.cxx:2559
PandaNode::Children::get_num_children
size_t get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:953
NodePath::get_stashed_children
get_stashed_children
Returns the set of all child nodes of the referenced node that have been stashed.
Definition: nodePath.h:234
RenderModeAttrib
Specifies how polygons are to be drawn.
Definition: renderModeAttrib.h:27
NodePath::has_depth_offset
bool has_depth_offset() const
Returns true if a depth-offset adjustment has been explicitly set on this particular node via set_dep...
Definition: nodePath.cxx:4646
shaderAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
transparencyAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::operator==
bool operator==(const NodePath &other) const
Returns true if the two paths are equivalent; that is, if they contain the same list of nodes in the ...
Definition: nodePath.I:1921
NodePath::set_mat
void set_mat(const LMatrix4 &mat)
Directly sets an arbitrary 4x4 transform matrix.
Definition: nodePath.cxx:1292
CPT_InternalName
This is a const pointer to an InternalName, and should be used in lieu of a CPT(InternalName) in func...
Definition: internalName.h:193
depthWriteAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::get_tex_projector_to
NodePath get_tex_projector_to(TextureStage *stage) const
Returns the "to" node associated with the TexProjectorEffect on the indicated stage.
Definition: nodePath.cxx:3769
GeomVertexColumn::get_name
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
Definition: geomVertexColumn.I:77
cullFaceAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LightAttrib::has_off_light
bool has_off_light(const NodePath &light) const
Returns true if the indicated light is turned off by the attrib, false otherwise.
Definition: lightAttrib.I:89
NodePath::get_texture
Texture * get_texture() const
Returns the base-level texture that has been set on this particular node, or NULL if no texture has b...
Definition: nodePath.cxx:3110
NodePath::flatten_strong
int flatten_strong()
The strongest possible flattening.
Definition: nodePath.cxx:5558
MaterialAttrib
Indicates which, if any, material should be applied to geometry.
Definition: materialAttrib.h:27
TextureStageCollection::add_texture_stage
void add_texture_stage(TextureStage *node_texture_stage)
Adds a new TextureStage to the collection.
Definition: textureStageCollection.cxx:48
TransparencyAttrib::get_mode
get_mode
Returns the transparency mode.
Definition: transparencyAttrib.h:54
ClipPlaneAttrib::has_off_plane
bool has_off_plane(const NodePath &plane) const
Returns true if the indicated plane is disabled by the attrib, false otherwise.
Definition: clipPlaneAttrib.I:83
NodePath::set_light_off
void set_light_off(int priority=0)
Sets the geometry at this level and below to render using no lights at all.
Definition: nodePath.cxx:2255
NodePath::find_all_paths_to
NodePathCollection find_all_paths_to(PandaNode *node) const
Returns the set of all NodePaths that extend from this NodePath down to the indicated node.
Definition: nodePath.cxx:367
NodePath::heads_up
void heads_up(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Behaves like look_at(), but with a strong preference to keeping the up vector oriented in the indicat...
Definition: nodePath.I:798
occluderEffect.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
textureStageCollection.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::set_render_mode_perspective
void set_render_mode_perspective(bool perspective, int priority=0)
Sets up the point geometry at this level and below to render as perspective sprites (that is,...
Definition: nodePath.cxx:4333
FindApproxPath
This class is local to this package only; it doesn't get exported.
Definition: findApproxPath.h:31
NodePath::find
NodePath find(const std::string &path) const
Searches for a node below the referenced node that matches the indicated string.
Definition: nodePath.cxx:314
CullBinAttrib
Assigns geometry to a particular bin by name.
Definition: cullBinAttrib.h:27
NodePath::find_all_materials
MaterialCollection find_all_materials() const
Returns a list of a materials applied to geometry at this node and below.
Definition: nodePath.cxx:4071
LightAttrib::has_all_off
bool has_all_off() const
Returns true if this attrib turns off all lights (although it may also turn some on).
Definition: lightAttrib.I:99
NodePath::has_scissor
bool has_scissor() const
Returns true if a scissor region was defined at this node by a previous call to set_scissor().
Definition: nodePath.cxx:2779
NodePathComponent::is_top_node
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
Definition: nodePathComponent.cxx:81
NodePath::get_texture_sampler
const SamplerState & get_texture_sampler() const
Returns the sampler state that has been given for the base-level texture that has been set on this pa...
Definition: nodePath.cxx:3163
NodePath::find_all_texcoords
InternalNameCollection find_all_texcoords() const
Returns a list of all texture coordinate sets used by any geometry at this node level and below.
Definition: nodePath.cxx:3856
NodePath::clear_depth_offset
void clear_depth_offset()
Completely removes any depth-offset adjustment that may have been set on this node via set_depth_offs...
Definition: nodePath.cxx:4635
NodePath::get_tex_gen
RenderAttrib::TexGenMode get_tex_gen(TextureStage *stage) const
Returns the texture coordinate generation mode for the given stage, or M_off if there is no explicit ...
Definition: nodePath.cxx:3651
GeomVertexFormat
This class defines the physical layout of the vertex data stored within a Geom.
Definition: geomVertexFormat.h:55
NodePath::clear_logic_op
void clear_logic_op()
Completely removes any logical operation that may have been set on this node via set_logic_op().
Definition: nodePath.cxx:4920
ModelNode
This node is placed at key points within the scene graph to indicate the roots of "models": subtrees ...
Definition: modelNode.h:31
NodePath::clear_effect
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
Definition: nodePath.I:519
TextureAttrib::get_num_on_stages
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.h:55
DatagramBuffer::write_header
bool write_header(const std::string &header)
Writes a sequence of bytes to the beginning of the datagram file.
Definition: datagramBuffer.cxx:23
NodePath::set_render_mode_thickness
void set_render_mode_thickness(PN_stdfloat thickness, int priority=0)
Sets up the point geometry at this level and below to render as thick points (that is,...
Definition: nodePath.cxx:4349
ColorAttrib::get_color_type
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
NodePath::stash_to
void stash_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread())
Similar to reparent_to(), but the node is added to its new parent's stashed list, so that the result ...
Definition: nodePath.cxx:412
TransformState::get_hpr
get_hpr
Returns the rotation component of the transform as a trio of Euler angles.
Definition: transformState.h:151
NodePath::instance_under_node
NodePath instance_under_node(const NodePath &other, const std::string &name, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Behaves like instance_to(), but implicitly creates a new node to instance the geometry under,...
Definition: nodePath.cxx:518
NodePath::hide_bounds
void hide_bounds()
Stops the rendering of the bounding volume begun with show_bounds().
Definition: nodePath.cxx:5376
PandaNode::get_stashed
get_stashed
Returns the nth stashed child of this node.
Definition: pandaNode.h:148
SceneGraphReducer::apply_attribs
void apply_attribs(PandaNode *node, int attrib_types=~(TT_clip_plane|TT_cull_face|TT_apply_texture_color))
Walks the scene graph, accumulating attribs of the indicated types, applying them to the vertices,...
Definition: sceneGraphReducer.I:78
GeomVertexFormat::get_array
get_array
Returns the description of the nth array used by the format.
Definition: geomVertexFormat.h:79
NodePath::do_billboard_point_eye
void do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset)
Performs a billboard-type rotate to the indicated camera node, one time only, and leaves the object r...
Definition: nodePath.cxx:4704
NodePath::show_bounds
void show_bounds()
Causes the bounding volume of the bottom node and all of its descendants (that is,...
Definition: nodePath.cxx:5355
MaterialAttrib::get_material
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated.
Definition: materialAttrib.h:40
Datagram::add_int32
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:67
lensNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader::resolve
bool resolve()
This may be called at any time during processing of the Bam file to resolve all the known pointers so...
Definition: bamReader.cxx:325
NodePath::get_hidden_ancestor
NodePath get_hidden_ancestor(DrawMask camera_mask=PandaNode::get_overall_bit(), Thread *current_thread=Thread::get_current_thread()) const
Returns the NodePath at or above the referenced node that is hidden to the indicated camera(s),...
Definition: nodePath.cxx:5108
NodePath::clear_audio_volume
void clear_audio_volume()
Completely removes any audio volume from the referenced node.
Definition: nodePath.cxx:5024
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
NodePath::decode_from_bam_stream
static NodePath decode_from_bam_stream(vector_uchar data, BamReader *reader=nullptr)
Reads the string created by a previous call to encode_to_bam_stream(), and extracts and returns the N...
Definition: nodePath.cxx:5744
NodePathComponent
This is one component of a NodePath.
Definition: nodePathComponent.h:42
depthTestAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::has_depth_test
bool has_depth_test() const
Returns true if a depth-test adjustment has been explicitly set on this particular node via set_depth...
Definition: nodePath.cxx:4533
BamFile
The principle public interface to reading and writing Bam disk files.
Definition: bamFile.h:41
NodePath::has_occluder
bool has_occluder(const NodePath &occluder) const
Returns true if the indicated occluder has been specifically applied to this particular node.
Definition: nodePath.cxx:2685
SceneGraphReducer::flatten
int flatten(PandaNode *root, int combine_siblings_bits)
Simplifies the graph by removing unnecessary nodes and nodes.
Definition: sceneGraphReducer.cxx:85
NodePath::has_light_off
bool has_light_off() const
Returns true if all Lights have been specifically disabled on this particular node.
Definition: nodePath.cxx:2394
NodePath::get_top
NodePath get_top(Thread *current_thread=Thread::get_current_thread()) const
Returns a singleton NodePath that represents the top of the path, or empty NodePath if this path is e...
Definition: nodePath.cxx:209
NodePath::get_quat
LQuaternion get_quat() const
Retrieves the rotation component of the transform.
Definition: nodePath.cxx:1080
NodePath::detach_node
void detach_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from its parent, but does not immediately delete it.
Definition: nodePath.cxx:631
findApproxLevelEntry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::get_render_mode
RenderModeAttrib::Mode get_render_mode() const
Returns the render mode that has been specifically set on this node via set_render_mode(),...
Definition: nodePath.cxx:4393
texMatrixAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::get_stashed_ancestor
NodePath get_stashed_ancestor(Thread *current_thread=Thread::get_current_thread()) const
Returns the NodePath at or above the referenced node that is stashed, or an empty NodePath if no ance...
Definition: nodePath.cxx:5182
BamFile::get_writer
get_writer
Returns the BamWriter in charge of performing the write operations.
Definition: bamFile.h:82
NodePath::set_fog
void set_fog(Fog *fog, int priority=0)
Sets the geometry at this level and below to render using the indicated fog.
Definition: nodePath.cxx:4200
datagramBuffer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePathComponent::get_next
NodePathComponent * get_next(int pipeline_stage, Thread *current_thread) const
Returns the next component in the path.
Definition: nodePathComponent.I:65
BamWriter::get_root_node
get_root_node
Returns the root node of the part of the scene graph we are currently writing out.
Definition: bamWriter.h:96
nodePathCollection.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
textureAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureAttrib::get_on_sampler
get_on_sampler
Returns the sampler associated with the indicated stage, or the one associated with its texture if no...
Definition: textureAttrib.h:72
globPattern.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TransformState::has_components
bool has_components() const
Returns true if the transform can be described by separate pos, hpr, and scale components.
Definition: transformState.I:246
NodePath::has_vertex_column
bool has_vertex_column(const InternalName *name) const
Returns true if there are at least some vertices at this node and below that contain a reference to t...
Definition: nodePath.cxx:3804
RenderModeAttrib::get_wireframe_color
get_wireframe_color
Returns the color that is used in M_filled_wireframe mode to distinguish the wireframe from the rest ...
Definition: renderModeAttrib.h:72
ColorScaleAttrib
Applies a scale to colors in the scene graph and on vertices.
Definition: colorScaleAttrib.h:27
NodePathCollection::unstash
void unstash()
Unstashes all NodePaths in the collection.
Definition: nodePathCollection.cxx:304
NodePath::set_shear
void set_shear(PN_stdfloat shxy, PN_stdfloat shxz, PN_stdfloat shyz)
Sets the shear component of the transform, leaving translation, rotation, and scale untouched.
Definition: nodePath.I:704
NodePath::set_quat
void set_quat(const LQuaternion &quat)
Sets the rotation component of the transform, leaving translation and scale untouched.
Definition: nodePath.cxx:1070
PandaNode::make_copy
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
Definition: pandaNode.cxx:481
NodePath::set_clip_plane_off
void set_clip_plane_off(int priority=0)
Sets the geometry at this level and below to render using no clip_planes at all.
Definition: nodePath.cxx:2475
NodePath::set_instance_count
void set_instance_count(int instance_count)
Sets the geometry instance count, or 0 if geometry instancing should be disabled.
Definition: nodePath.cxx:3382
NodePath::get_mat
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
Definition: nodePath.I:776
NodePath::complete_pointers
int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: nodePath.cxx:6815
NodePath::set_material_off
void set_material_off(int priority=0)
Sets the geometry at this level and below to render using no material.
Definition: nodePath.cxx:4128
PandaNode::as_light
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes,...
Definition: pandaNode.cxx:2095
TextureAttrib::get_on_stage
get_on_stage
Returns the nth stage turned on by the attribute, sorted in render order.
Definition: textureAttrib.h:55
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
TexMatrixAttrib
Applies a transform matrix to UV's before they are rendered.
Definition: texMatrixAttrib.h:30
NodePath::get_hpr
LVecBase3 get_hpr() const
Retrieves the rotation component of the transform.
Definition: nodePath.cxx:1058
NodePath::find_texture
Texture * find_texture(const std::string &name) const
Returns the first texture found applied to geometry at this node or below that matches the indicated ...
Definition: nodePath.cxx:3912
NodePath::is_singleton
bool is_singleton(Thread *current_thread=Thread::get_current_thread()) const
Returns true if the NodePath contains exactly one node.
Definition: nodePath.I:196
NodePath::has_render_mode
bool has_render_mode() const
Returns true if a render mode has been explicitly set on this particular node via set_render_mode() (...
Definition: nodePath.cxx:4383
PandaNode::reset_prev_transform
void reset_prev_transform(Thread *current_thread=Thread::get_current_thread())
Resets the transform that represents this node's "previous" position to the same as the current trans...
Definition: pandaNode.cxx:1147
NodePath::set_compass
void set_compass(const NodePath &reference=NodePath())
Puts a compass effect on the node, so that it will retain a fixed rotation relative to the reference ...
Definition: nodePath.cxx:4822
NodePath::copy_to
NodePath copy_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Functions like instance_to(), except a deep copy is made of the referenced node and all of its descen...
Definition: nodePath.cxx:535
FindApproxLevelEntry
This class is local to this package only; it doesn't get exported.
Definition: findApproxLevelEntry.h:29
NodePath::replace_texture
void replace_texture(Texture *tex, Texture *new_tex)
Recursively searches the scene graph for references to the given texture, and replaces them with the ...
Definition: nodePath.cxx:3146
NodePath::flatten_medium
int flatten_medium()
A more thorough flattening than flatten_light(), this first applies all the transforms,...
Definition: nodePath.cxx:5530
NodePath::set_two_sided
void set_two_sided(bool two_sided, int priority=0)
Specifically sets or disables two-sided rendering mode on this particular node.
Definition: nodePath.cxx:4445
TransformState::get_pos
get_pos
Returns the pos component of the transform.
Definition: transformState.h:150
InternalName::find_ancestor
int find_ancestor(const std::string &basename) const
Returns the index of the ancestor with the indicated basename, or -1 if no ancestor has that basename...
Definition: internalName.cxx:177
DatagramBuffer::get_datagram
virtual bool get_datagram(Datagram &data) override
Reads the next datagram from the file.
Definition: datagramBuffer.cxx:97
NodePath::get_color_scale
const LVecBase4 & get_color_scale() const
Returns the complete color scale vector that has been applied to this node via a previous call to set...
Definition: nodePath.cxx:2174
TexGenAttrib
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
NodePath::has_tex_transform
bool has_tex_transform(TextureStage *stage) const
Returns true if there is an explicit texture matrix on the current node for the given stage.
Definition: nodePath.cxx:3455
NodePath::fail
static NodePath fail()
Creates a NodePath with the ET_fail error type set.
Definition: nodePath.I:149
internalNameCollection.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::attach_new_node
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition: nodePath.cxx:563
shader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramBuffer::put_datagram
virtual bool put_datagram(const Datagram &data) override
Writes the given datagram to the file.
Definition: datagramBuffer.cxx:35
FogAttrib::get_fog
get_fog
If the FogAttrib is not an 'off' FogAttrib, returns the fog that is associated.
Definition: fogAttrib.h:38
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition: graphicsStateGuardianBase.h:110
GeomVertexColumn
This defines how a single column is interleaved within a vertex array stored within a Geom.
Definition: geomVertexColumn.h:37
NodePath::set_occluder
void set_occluder(const NodePath &occluder)
Adds the indicated occluder to the list of occluders that apply to geometry at this node and below.
Definition: nodePath.cxx:2622
LightAttrib::has_on_light
bool has_on_light(const NodePath &light) const
Returns true if the indicated light is turned on by the attrib, false otherwise.
Definition: lightAttrib.I:54
NodePath::get_net_audio_volume
PN_stdfloat get_net_audio_volume() const
Returns the complete audio volume for this node taking highers nodes in the graph into account.
Definition: nodePath.cxx:5089
InternalNameCollection
Definition: internalNameCollection.h:24
NodePath::unify_texture_stages
void unify_texture_stages(TextureStage *stage)
Searches through all TextureStages at this node and below.
Definition: nodePath.cxx:4026
alphaTestAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomNode::get_geom_state
get_geom_state
Returns the RenderState associated with the nth geom of the node.
Definition: geomNode.h:75
WorkingNodePath::is_valid
is_valid
Returns true if the WorkingNodePath object appears to be a valid NodePath reference,...
Definition: workingNodePath.h:59
ClipPlaneAttrib::has_all_off
bool has_all_off() const
Returns true if this attrib disables all planes (although it may also enable some).
Definition: clipPlaneAttrib.I:93
audioVolumeAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode::get_into_collide_mask
get_into_collide_mask
Returns the "into" collide mask for this node.
Definition: pandaNode.h:264
geomNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureStage::get_default
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Definition: textureStage.h:205
NodePath::do_billboard_point_world
void do_billboard_point_world(const NodePath &camera, PN_stdfloat offset)
Performs a billboard-type rotate to the indicated camera node, one time only, and leaves the object r...
Definition: nodePath.cxx:4733
NodePath::has_two_sided
bool has_two_sided() const
Returns true if a two-sided adjustment has been explicitly set on this particular node via set_two_si...
Definition: nodePath.cxx:4475
PT
PT(Material) NodePath
Returns the material that has been set on this particular node, or NULL if no material has been set.
Definition: nodePath.cxx:4168
CullBinAttrib::get_draw_order
get_draw_order
Returns the draw order this attribute specifies.
Definition: cullBinAttrib.h:40
TransformState::has_hpr
bool has_hpr() const
Returns true if the transform's rotation component can be extracted out separately and described as a...
Definition: transformState.I:300
NodePath::has_billboard
bool has_billboard() const
Returns true if there is any billboard effect on the node.
Definition: nodePath.cxx:4811
antialiasAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lightAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::set_tex_transform
void set_tex_transform(TextureStage *stage, const TransformState *transform)
Sets the texture matrix on the current node to the indicated transform for the given stage.
Definition: nodePath.cxx:3402
NodePath::set_color
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a=1.0, int priority=0)
Applies a scene-graph color to the referenced node.
Definition: nodePath.cxx:1952
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
Thread::get_pipeline_stage
get_pipeline_stage
Returns the Pipeline stage number associated with this thread.
Definition: thread.h:105
LogicOpAttrib::get_operation
get_operation
Returns the logic operation specified by this attribute.
Definition: logicOpAttrib.h:61
TexProjectorEffect
This effect automatically applies a computed texture matrix to the specified texture stage,...
Definition: texProjectorEffect.h:49
NodePath::clear_light
void clear_light()
Completely removes any lighting operations that may have been set via set_light() or set_light_off() ...
Definition: nodePath.cxx:2306
NodePath::has_texture_off
bool has_texture_off() const
Returns true if texturing has been specifically disabled on this particular node via set_texture_off(...
Definition: nodePath.cxx:3069
LightAttrib
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:30
NodePath::clear_two_sided
void clear_two_sided()
Completely removes any two-sided adjustment that may have been set on this node via set_two_sided().
Definition: nodePath.cxx:4464
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition: boundingVolume.h:41
NodePath::has_color_scale
bool has_color_scale() const
Returns true if a color scale has been applied to the referenced node, false otherwise.
Definition: nodePath.cxx:2029
WeakNodePath
This class is a wrapper around a NodePath that, unlike the actual NodePath class, doesn't hold a refe...
Definition: weakNodePath.h:32
ShaderAttrib::get_instance_count
get_instance_count
Returns the number of geometry instances.
Definition: shaderAttrib.h:127
NodePath::set_logic_op
void set_logic_op(LogicOpAttrib::Operation op, int priority=0)
Specifically sets or disables a logical operation on this particular node.
Definition: nodePath.cxx:4908
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamFile::close
void close()
Closes the input or output stream.
Definition: bamFile.cxx:243
TextureAttrib::has_off_stage
bool has_off_stage(TextureStage *stage) const
Returns true if the indicated stage is turned off by the attrib, false otherwise.
Definition: textureAttrib.I:195
NodePath::get_antialias
unsigned short get_antialias() const
Returns the antialias setting that has been specifically set on this node via set_antialias(),...
Definition: nodePath.cxx:4995
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
DepthOffsetAttrib
This is a special kind of attribute that instructs the graphics driver to apply an offset or bias to ...
Definition: depthOffsetAttrib.h:50
ShaderInput::get_blank
static const ShaderInput & get_blank()
Returns a static ShaderInput object with name NULL, priority zero, type INVALID, and all value-fields...
Definition: shaderInput.cxx:23
NodePath::write_datagram
void write_datagram(BamWriter *manager, Datagram &dg) const
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: nodePath.cxx:6764
AudioVolumeAttrib
Applies a scale to audio volume for positional sounds in the scene graph.
Definition: audioVolumeAttrib.h:27
TextureAttrib
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
NodePath::node
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
FindApproxLevelEntry::write_level
void write_level(std::ostream &out, int indent_level) const
Writes the entire level (a linked list of entries beginning at this entry).
Definition: findApproxLevelEntry.cxx:41
NodePath::get_tex_projector_from
NodePath get_tex_projector_from(TextureStage *stage) const
Returns the "from" node associated with the TexProjectorEffect on the indicated stage.
Definition: nodePath.cxx:3750
PandaNode::get_num_stashed
get_num_stashed
Returns the number of stashed nodes this node has.
Definition: pandaNode.h:148
NodePath::unstash_all
void unstash_all(Thread *current_thread=Thread::get_current_thread())
Unstashes this node and all stashed child nodes.
Definition: nodePath.cxx:5170
look_at.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::get_render_mode_perspective
bool get_render_mode_perspective() const
Returns the flag that has been set on this node via set_render_mode_perspective(),...
Definition: nodePath.cxx:4427
ColorAttrib
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
NodePath::has_compass
bool has_compass() const
Returns true if there is any compass effect on the node.
Definition: nodePath.cxx:4840
NodePath::set_antialias
void set_antialias(unsigned short mode, int priority=0)
Specifies the antialiasing type that should be applied at this node and below.
Definition: nodePath.cxx:4963
NodePath::get_pos
LPoint3 get_pos() const
Retrieves the translation component of the transform.
Definition: nodePath.cxx:992
PandaNode::is_overall_hidden
is_overall_hidden
Returns true if the node has been hidden to all cameras by clearing its overall bit.
Definition: pandaNode.h:248
NodePath::find_all_texture_stages
TextureStageCollection find_all_texture_stages() const
Returns a list of a TextureStages applied to geometry at this node and below.
Definition: nodePath.cxx:4005
AudioVolumeAttrib::get_volume
get_volume
Returns the volume to be applied to sounds.
Definition: audioVolumeAttrib.h:44
NodePath::get_bin_name
std::string get_bin_name() const
Returns the name of the bin that this particular node was assigned to via set_bin(),...
Definition: nodePath.cxx:2832
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath::stash
void stash(int sort=0, Thread *current_thread=Thread::get_current_thread())
Removes the referenced node (and the entire subgraph below this node) from the scene graph in any nor...
Definition: nodePath.cxx:5138
NodePath::has_tex_projector
bool has_tex_projector(TextureStage *stage) const
Returns true if this node has a TexProjectorEffect for the indicated stage, false otherwise.
Definition: nodePath.cxx:3731
NodePathComponent::get_length
int get_length(int pipeline_stage, Thread *current_thread) const
Returns the length of the path to this node.
Definition: nodePathComponent.cxx:90
TextureStage
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
NodePath::compose_color_scale
void compose_color_scale(const LVecBase4 &scale, int priority=0)
multiplies the color scale component of the transform, with previous color scale leaving translation ...
Definition: nodePath.cxx:2050
PandaNode::get_draw_control_mask
get_draw_control_mask
Returns the set of bits in draw_show_mask that are considered meaningful.
Definition: pandaNode.h:255
GeomVertexFormat::get_num_arrays
get_num_arrays
Returns the number of individual arrays required by the format.
Definition: geomVertexFormat.h:79
NodePath::get_instance_count
int get_instance_count() const
Returns the geometry instance count, or 0 if disabled.
Definition: nodePath.cxx:3347
NodePath::clear_occluder
void clear_occluder()
Completely removes any occluders that may have been set via set_occluder() from this particular node.
Definition: nodePath.cxx:2648
GlobPattern
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition: globPattern.h:32
RenderModeAttrib::get_perspective
get_perspective
Returns the perspective flag.
Definition: renderModeAttrib.h:71
NodePath::get_fog
Fog * get_fog() const
Returns the fog that has been set on this particular node, or NULL if no fog has been set.
Definition: nodePath.cxx:4273
DatagramBuffer::read_header
bool read_header(std::string &header, size_t num_bytes)
Reads a sequence of bytes from the beginning of the datagram file.
Definition: datagramBuffer.cxx:81
NodePath::NodePath
NodePath()
This constructs an empty NodePath with no nodes.
Definition: nodePath.I:18
GeomVertexArrayFormat
This describes the structure of a single array within a Geom data.
Definition: geomVertexArrayFormat.h:47
NodePath::has_depth_write
bool has_depth_write() const
Returns true if a depth-write adjustment has been explicitly set on this particular node via set_dept...
Definition: nodePath.cxx:4590
NodePath::set_audio_volume_off
void set_audio_volume_off(int priority=0)
Disables any audio volume attribute inherited from above.
Definition: nodePath.cxx:5062
CullFaceAttrib
Indicates which faces should be culled based on their vertex ordering.
Definition: cullFaceAttrib.h:26
FindApproxPath::add_string
bool add_string(const std::string &str_path)
Adds a sequence of components separated by slashes, followed optionally by a semicolon and a sequence...
Definition: findApproxPath.cxx:117
NodePath::remove_node
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:591
NodePath::get_prev_transform
const TransformState * get_prev_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the transform that has been set as this node's "previous" position.
Definition: nodePath.cxx:846
NodePath::get_ancestor
get_ancestor
Returns the nth ancestor of the path, where 0 is the NodePath itself and get_num_nodes() - 1 is get_t...
Definition: nodePath.h:207
NodePath::get_transparency
TransparencyAttrib::Mode get_transparency() const
Returns the transparent rendering that has been specifically set on this node via set_transparency(),...
Definition: nodePath.cxx:4890
ColorScaleAttrib::get_scale
get_scale
Returns the scale to be applied to colors.
Definition: colorScaleAttrib.h:47
NodePath::set_fluid_pos
void set_fluid_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the translation component, without changing the "previous" position, so that the collision syste...
Definition: nodePath.I:627
NodePath::has_tex_gen
bool has_tex_gen(TextureStage *stage) const
Returns true if there is a mode for automatic texture coordinate generation on the current node for t...
Definition: nodePath.cxx:3633
NodePath::set_render_mode_filled
void set_render_mode_filled(int priority=0)
Sets up the geometry at this level and below (unless overridden) to render in filled (i....
Definition: nodePath.cxx:4302
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
OccluderEffect
This functions similarly to a LightAttrib or ClipPlaneAttrib.
Definition: occluderEffect.h:32
NodePath::set_pos_hpr_scale
void set_pos_hpr_scale(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz)
Completely replaces the transform with new translation, rotation, and scale components.
Definition: nodePath.I:746
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
NodePath::has_clip_plane_off
bool has_clip_plane_off() const
Returns true if all clipping planes have been specifically disabled on this particular node.
Definition: nodePath.cxx:2581
ColorAttrib::get_color
get_color
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
Definition: colorAttrib.h:47
NodePath::set_transparency
void set_transparency(TransparencyAttrib::Mode mode, int priority=0)
Specifically sets or disables transparent rendering mode on this particular node.
Definition: nodePath.cxx:4851
NodePath::set_depth_offset
void set_depth_offset(int bias, int priority=0)
This instructs the graphics driver to apply an offset or bias to the generated depth values for rende...
Definition: nodePath.cxx:4624
NodePath::get_children
get_children
Returns the set of all child nodes of the referenced node.
Definition: nodePath.h:233
NodePath::get_bin_draw_order
int get_bin_draw_order() const
Returns the drawing order associated with the bin that this particular node was assigned to via set_b...
Definition: nodePath.cxx:2850
PandaNode::set_into_collide_mask
set_into_collide_mask
Sets the "into" CollideMask.
Definition: pandaNode.h:264
NodePath::clear_compass
void clear_compass()
Removes any compass effect from the node.
Definition: nodePath.cxx:4831
ShaderInput
This is a small container class that can hold any one of the value types that can be passed as input ...
Definition: shaderInput.h:40
cullBinAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TextureAttrib::has_on_stage
has_on_stage
Returns true if the indicated stage is turned on by the attrib, false otherwise.
Definition: textureAttrib.h:69
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
NodePath::set_render_mode_wireframe
void set_render_mode_wireframe(int priority=0)
Sets up the geometry at this level and below (unless overridden) to render in wireframe mode.
Definition: nodePath.cxx:4290
NodePathCollection
This is a set of zero or more NodePaths.
Definition: nodePathCollection.h:26
NodePath::clear_depth_test
void clear_depth_test()
Completely removes any depth-test adjustment that may have been set on this node via set_depth_test()...
Definition: nodePath.cxx:4522
FindApproxPath::add_match_many
void add_match_many(int flags)
Adds a component that will match a chain of zero or more consecutive nodes.
Definition: findApproxPath.cxx:386
pStatCollector.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.