Panda3D
nodePath.cxx
1 // Filename: nodePath.cxx
2 // Created by: drose (25Feb02)
3 // Updated by: fperazzi, PandaSE (06Apr10) (added more overloads
4 // for set_shader_input)
5 // Updated by: weifengh, PandaSE(30Apr10) (added set_shader_auto)
6 //
7 ////////////////////////////////////////////////////////////////////
8 //
9 // PANDA 3D SOFTWARE
10 // Copyright (c) Carnegie Mellon University. All rights reserved.
11 //
12 // All use of this software is subject to the terms of the revised BSD
13 // license. You should have received a copy of this license along
14 // with this source code in a file named "LICENSE."
15 //
16 ////////////////////////////////////////////////////////////////////
17 
18 #include "nodePath.h"
19 #include "nodePathCollection.h"
20 #include "findApproxPath.h"
21 #include "findApproxLevelEntry.h"
22 #include "internalNameCollection.h"
23 #include "config_pgraph.h"
24 #include "colorAttrib.h"
25 #include "colorScaleAttrib.h"
26 #include "cullBinAttrib.h"
27 #include "textureAttrib.h"
28 #include "texMatrixAttrib.h"
29 #include "texGenAttrib.h"
30 #include "materialAttrib.h"
31 #include "materialCollection.h"
32 #include "lightAttrib.h"
33 #include "clipPlaneAttrib.h"
34 #include "occluderEffect.h"
35 #include "polylightEffect.h"
36 #include "fogAttrib.h"
37 #include "renderModeAttrib.h"
38 #include "cullFaceAttrib.h"
39 #include "alphaTestAttrib.h"
40 #include "depthTestAttrib.h"
41 #include "depthWriteAttrib.h"
42 #include "depthOffsetAttrib.h"
43 #include "shaderAttrib.h"
44 #include "billboardEffect.h"
45 #include "compassEffect.h"
46 #include "showBoundsEffect.h"
47 #include "transparencyAttrib.h"
48 #include "antialiasAttrib.h"
49 #include "audioVolumeAttrib.h"
50 #include "texProjectorEffect.h"
51 #include "scissorEffect.h"
52 #include "texturePool.h"
53 #include "planeNode.h"
54 #include "occluderNode.h"
55 #include "lensNode.h"
56 #include "materialPool.h"
57 #include "look_at.h"
58 #include "plist.h"
59 #include "boundingSphere.h"
60 #include "geomNode.h"
61 #include "sceneGraphReducer.h"
62 #include "textureCollection.h"
63 #include "textureStageCollection.h"
64 #include "globPattern.h"
65 #include "shader.h"
66 #include "shaderInput.h"
67 #include "config_gobj.h"
68 #include "bamFile.h"
69 #include "preparedGraphicsObjects.h"
70 #include "dcast.h"
71 #include "pStatCollector.h"
72 #include "pStatTimer.h"
73 #include "modelNode.h"
74 #include "py_panda.h"
75 #include "bam.h"
76 #include "bamWriter.h"
77 
78 // stack seems to overflow on Intel C++ at 7000. If we need more than
79 // 7000, need to increase stack size.
80 int NodePath::_max_search_depth = 7000;
81 TypeHandle NodePath::_type_handle;
82 
83 PStatCollector NodePath::_get_transform_pcollector("*:NodePath:get_transform");
84 PStatCollector NodePath::_verify_complete_pcollector("*:NodePath:verify_complete");
85 
86 #ifdef HAVE_PYTHON
87 #include "py_panda.h"
88 #ifndef CPPPARSER
89 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamWriter;
90 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamReader;
91 #endif // CPPPARSER
92 #endif // HAVE_PYTHON
93 
94 // ***Begin temporary transition code for operator bool
95 enum EmptyNodePathType {
96  ENP_future,
97  ENP_transition,
98  ENP_deprecated,
99  ENP_notify,
100 };
101 
102 ostream &operator << (ostream &out, EmptyNodePathType enp) {
103  switch (enp) {
104  case ENP_future:
105  return out << "future";
106  case ENP_transition:
107  return out << "transition";
108  case ENP_deprecated:
109  return out << "deprecated";
110  case ENP_notify:
111  return out << "notify";
112  }
113  return out << "**invalid EmptyNodePathType value (" << (int)enp << ")**";
114 }
115 
116 istream &operator >> (istream &in, EmptyNodePathType &enp) {
117  string word;
118  in >> word;
119  if (word == "future") {
120  enp = ENP_future;
121  } else if (word == "transition") {
122  enp = ENP_transition;
123  } else if (word == "deprecated") {
124  enp = ENP_deprecated;
125  } else if (word == "notify") {
126  enp = ENP_notify;
127  } else {
128  pgraph_cat.warning()
129  << "Invalid EmptyNodePathType value (\"" << word << "\")\n";
130  enp = ENP_transition;
131  }
132  return in;
133 }
134 
135 static ConfigVariableEnum<EmptyNodePathType> empty_node_path
136 ("empty-node-path", ENP_future,
137  PRC_DESC("This is a temporary transition variable to control the behavior "
138  "of a NodePath when it is used as a boolean false. Set this to "
139  "'deprecated' to preserve the original behavior: every NodePath "
140  "evaluates true, even an empty NodePath. Set it to 'future' to "
141  "support the new behavior: non-empty NodePaths evaluate true, "
142  "and empty NodePaths evaluate false. Set it to 'transition' to "
143  "raise an exception if an empty NodePath is used as a boolean."));
144 
145 // ***End temporary transition code for operator bool
146 
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: NodePath::Constructor
150 // Access: Published
151 // Description: Constructs a NodePath with the indicated parent
152 // NodePath and child node; the child node must be a
153 // stashed or unstashed child of the parent.
154 ////////////////////////////////////////////////////////////////////
156 NodePath(const NodePath &parent, PandaNode *child_node,
157  Thread *current_thread) :
158  _error_type(ET_fail)
159 {
160  nassertv(child_node != (PandaNode *)NULL);
161  int pipeline_stage = current_thread->get_pipeline_stage();
162 
163  if (parent.is_empty()) {
164  // Special case: constructing a NodePath at the root.
165  _head = PandaNode::get_top_component(child_node, true,
166  pipeline_stage, current_thread);
167 
168  } else {
169  _head = PandaNode::get_component(parent._head, child_node, pipeline_stage,
170  current_thread);
171  }
172  nassertv(_head != (NodePathComponent *)NULL);
173 
174  if (_head != (NodePathComponent *)NULL) {
175  _error_type = ET_ok;
176  }
177  _backup_key = 0;
178 }
179 
180 ////////////////////////////////////////////////////////////////////
181 // Function: NodePath::operator bool
182 // Access: Published
183 // Description: Returns true if the NodePath is valid (not empty),
184 // or false if it contains no nodes.
185 ////////////////////////////////////////////////////////////////////
186 NodePath::
187 operator bool () const {
188  switch (empty_node_path) {
189  case ENP_future:
190  return !is_empty();
191 
192  case ENP_deprecated:
193  return true;
194 
195  case ENP_notify:
196  {
197  const char *msg = "NodePath being used as a Boolean (talk to Zac)";
198 #ifdef HAVE_PYTHON
199  PyErr_Warn(PyExc_FutureWarning, (char *)msg);
200 #endif
201  return !is_empty();
202  }
203 
204 
205  case ENP_transition:
206  if (!is_empty()) {
207  return true;
208  }
209 
210  {
211  const char *message = "Using an empty NodePath as a boolean value. Because the meaning of this operation is changing, you should avoid doing this to avoid ambiguity, or set the config variable empty-node-path to 'future' or 'deprecated' to specify the desired behavior.";
212  pgraph_cat.warning()
213  << message << "\n";
214 #ifdef HAVE_PYTHON
215  PyErr_Warn(PyExc_FutureWarning, (char *)message);
216 #endif
217  }
218  return true;
219  }
220 
221  nassertr(false, true);
222  return true;
223 }
224 
225 ////////////////////////////////////////////////////////////////////
226 // Function: NodePath::get_num_nodes
227 // Access: Published
228 // Description: Returns the number of nodes in the path.
229 ////////////////////////////////////////////////////////////////////
230 int NodePath::
231 get_num_nodes(Thread *current_thread) const {
232  if (is_empty()) {
233  return 0;
234  }
235  int pipeline_stage = current_thread->get_pipeline_stage();
236  return _head->get_length(pipeline_stage, current_thread);
237 }
238 
239 ////////////////////////////////////////////////////////////////////
240 // Function: NodePath::get_node
241 // Access: Published
242 // Description: Returns the nth node of the path, where 0 is the
243 // referenced (bottom) node and get_num_nodes() - 1 is
244 // the top node. This requires iterating through the
245 // path.
246 //
247 // Also see node(), which is a convenience function to
248 // return the same thing as get_node(0) (since the
249 // bottom node is the most important node in the
250 // NodePath, and is the one most frequently referenced).
251 //
252 // Note that this function returns the same thing as
253 // get_ancestor(index).node().
254 ////////////////////////////////////////////////////////////////////
256 get_node(int index, Thread *current_thread) const {
257  nassertr(index >= 0 && index < get_num_nodes(), NULL);
258 
259  int pipeline_stage = current_thread->get_pipeline_stage();
260 
261  NodePathComponent *comp = _head;
262  while (index > 0) {
263  // If this assertion fails, the index was out of range; the
264  // component's length must have been invalid.
265  nassertr(comp != (NodePathComponent *)NULL, NULL);
266  comp = comp->get_next(pipeline_stage, current_thread);
267  index--;
268  }
269 
270  // If this assertion fails, the index was out of range; the
271  // component's length must have been invalid.
272  nassertr(comp != (NodePathComponent *)NULL, NULL);
273  return comp->get_node();
274 }
275 
276 ////////////////////////////////////////////////////////////////////
277 // Function: NodePath::get_ancestor
278 // Access: Published
279 // Description: Returns the nth ancestor of the path, where 0 is the
280 // NodePath itself and get_num_nodes() - 1 is get_top().
281 // This requires iterating through the path.
282 //
283 // Also see get_node(), which returns the same thing as
284 // a PandaNode pointer, not a NodePath.
285 ////////////////////////////////////////////////////////////////////
287 get_ancestor(int index, Thread *current_thread) const {
288  nassertr(index >= 0 && index < get_num_nodes(), NodePath::fail());
289 
290  int pipeline_stage = current_thread->get_pipeline_stage();
291 
292  NodePathComponent *comp = _head;
293  while (index > 0) {
294  // If this assertion fails, the index was out of range; the
295  // component's length must have been invalid.
296  nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
297  comp = comp->get_next(pipeline_stage, current_thread);
298  index--;
299  }
300 
301  // If this assertion fails, the index was out of range; the
302  // component's length must have been invalid.
303  nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
304 
305  NodePath result;
306  result._head = comp;
307  return result;
308 }
309 
310 ////////////////////////////////////////////////////////////////////
311 // Function: NodePath::get_top
312 // Access: Published
313 // Description: Returns a singleton NodePath that represents the top
314 // of the path, or empty NodePath if this path is empty.
315 ////////////////////////////////////////////////////////////////////
317 get_top(Thread *current_thread) const {
318  if (is_empty()) {
319  return *this;
320  }
321 
322  int pipeline_stage = current_thread->get_pipeline_stage();
323 
324  NodePathComponent *comp = _head;
325  while (!comp->is_top_node(pipeline_stage, current_thread)) {
326  comp = comp->get_next(pipeline_stage, current_thread);
327  nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
328  }
329 
330  NodePath top;
331  top._head = comp;
332  return top;
333 }
334 
335 
336 ////////////////////////////////////////////////////////////////////
337 // Function: NodePath::get_children
338 // Access: Published
339 // Description: Returns the set of all child nodes of the referenced
340 // node.
341 ////////////////////////////////////////////////////////////////////
343 get_children(Thread *current_thread) const {
344  NodePathCollection result;
345  nassertr_always(!is_empty(), result);
346 
347  PandaNode *bottom_node = node();
348 
349  int pipeline_stage = current_thread->get_pipeline_stage();
350 
351  PandaNode::Children cr = bottom_node->get_children();
352  int num_children = cr.get_num_children();
353  for (int i = 0; i < num_children; i++) {
354  NodePath child;
355  child._head = PandaNode::get_component(_head, cr.get_child(i),
356  pipeline_stage, current_thread);
357  result.add_path(child);
358  }
359 
360  return result;
361 }
362 
363 ////////////////////////////////////////////////////////////////////
364 // Function: NodePath::get_stashed_children
365 // Access: Published
366 // Description: Returns the set of all child nodes of the referenced
367 // node that have been stashed. These children are not
368 // normally visible on the node, and do not appear in
369 // the list returned by get_children().
370 ////////////////////////////////////////////////////////////////////
372 get_stashed_children(Thread *current_thread) const {
373  NodePathCollection result;
374  nassertr_always(!is_empty(), result);
375 
376  PandaNode *bottom_node = node();
377 
378  int pipeline_stage = current_thread->get_pipeline_stage();
379 
380  int num_stashed = bottom_node->get_num_stashed();
381  for (int i = 0; i < num_stashed; i++) {
382  NodePath stashed;
383  stashed._head = PandaNode::get_component(_head, bottom_node->get_stashed(i),
384  pipeline_stage, current_thread);
385  result.add_path(stashed);
386  }
387 
388  return result;
389 }
390 
391 ////////////////////////////////////////////////////////////////////
392 // Function: NodePath::get_sort
393 // Access: Published
394 // Description: Returns the sort value of the referenced node within
395 // its parent; that is, the sort number passed on the
396 // last reparenting operation for this node. This will
397 // control the position of the node within its parent's
398 // list of children.
399 ////////////////////////////////////////////////////////////////////
400 int NodePath::
401 get_sort(Thread *current_thread) const {
402  if (!has_parent()) {
403  return 0;
404  }
405 
406  int pipeline_stage = current_thread->get_pipeline_stage();
407 
408  PandaNode *parent = _head->get_next(pipeline_stage, current_thread)->get_node();
409  PandaNode *child = node();
410  nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0);
411  int child_index = parent->find_child(child);
412  if (child_index != -1) {
413  return parent->get_child_sort(child_index);
414  }
415 
416  child_index = parent->find_stashed(child);
417  if (child_index != -1) {
418  return parent->get_stashed_sort(child_index);
419  }
420 
421  nassertr(false, 0);
422  return 0;
423 }
424 
425 ////////////////////////////////////////////////////////////////////
426 // Function: NodePath::find
427 // Access: Published
428 // Description: Searches for a node below the referenced node that
429 // matches the indicated string. Returns the shortest
430 // match found, if any, or an empty NodePath if no match
431 // can be found.
432 ////////////////////////////////////////////////////////////////////
434 find(const string &path) const {
435  nassertr_always(!is_empty(), fail());
436 
437  NodePathCollection col;
438  find_matches(col, path, 1);
439 
440  if (col.is_empty()) {
441  return NodePath::not_found();
442  }
443 
444  return col.get_path(0);
445 }
446 
447 ////////////////////////////////////////////////////////////////////
448 // Function: NodePath::find_path_to
449 // Access: Published
450 // Description: Searches for the indicated node below this node and
451 // returns the shortest NodePath that connects them.
452 ////////////////////////////////////////////////////////////////////
455  nassertr_always(!is_empty(), fail());
456  nassertr(node != (PandaNode *)NULL, fail());
457 
458  NodePathCollection col;
459  FindApproxPath approx_path;
460  approx_path.add_match_many(0);
461  approx_path.add_match_pointer(node, 0);
462  find_matches(col, approx_path, 1);
463 
464  if (col.is_empty()) {
465  return NodePath::not_found();
466  }
467 
468  return col.get_path(0);
469 }
470 
471 ////////////////////////////////////////////////////////////////////
472 // Function: NodePath::find_all_matches
473 // Access: Published
474 // Description: Returns the complete set of all NodePaths that begin
475 // with this NodePath and can be extended by
476 // path. The shortest paths will be listed
477 // first.
478 ////////////////////////////////////////////////////////////////////
480 find_all_matches(const string &path) const {
481  NodePathCollection col;
482  nassertr_always(!is_empty(), col);
483  nassertr(verify_complete(), col);
484  find_matches(col, path, -1);
485  return col;
486 }
487 
488 ////////////////////////////////////////////////////////////////////
489 // Function: NodePath::find_all_paths_to
490 // Access: Published
491 // Description: Returns the set of all NodePaths that extend from
492 // this NodePath down to the indicated node. The
493 // shortest paths will be listed first.
494 ////////////////////////////////////////////////////////////////////
497  NodePathCollection col;
498  nassertr_always(!is_empty(), col);
499  nassertr(verify_complete(), col);
500  nassertr(node != (PandaNode *)NULL, col);
501  FindApproxPath approx_path;
502  approx_path.add_match_many(0);
503  approx_path.add_match_pointer(node, 0);
504  find_matches(col, approx_path, -1);
505  return col;
506 }
507 
508 ////////////////////////////////////////////////////////////////////
509 // Function: NodePath::reparent_to
510 // Access: Published
511 // Description: Removes the referenced node of the NodePath from its
512 // current parent and attaches it to the referenced node
513 // of the indicated NodePath.
514 //
515 // If the destination NodePath is empty, this is the
516 // same thing as detach_node().
517 //
518 // If the referenced node is already a child of the
519 // indicated NodePath (via some other instance), this
520 // operation fails and leaves the NodePath detached.
521 ////////////////////////////////////////////////////////////////////
522 void NodePath::
523 reparent_to(const NodePath &other, int sort, Thread *current_thread) {
524  nassertv(verify_complete());
525  nassertv(other.verify_complete());
526  nassertv_always(!is_empty());
527  nassertv(other._error_type == ET_ok);
528 
529  // Reparenting implicitly resets the delta vector.
531 
532  int pipeline_stage = current_thread->get_pipeline_stage();
533  bool reparented = PandaNode::reparent(other._head, _head, sort, false,
534  pipeline_stage, current_thread);
535  nassertv(reparented);
536 }
537 
538 ////////////////////////////////////////////////////////////////////
539 // Function: NodePath::stash_to
540 // Access: Published
541 // Description: Similar to reparent_to(), but the node is added to
542 // its new parent's stashed list, so that the result is
543 // equivalent to calling reparent_to() immediately
544 // followed by stash().
545 ////////////////////////////////////////////////////////////////////
546 void NodePath::
547 stash_to(const NodePath &other, int sort, Thread *current_thread) {
548  nassertv(verify_complete());
549  nassertv(other.verify_complete());
550  nassertv_always(!is_empty());
551  nassertv(other._error_type == ET_ok);
552 
553  // Reparenting implicitly resets the delta vector.
555 
556  int pipeline_stage = current_thread->get_pipeline_stage();
557  bool reparented = PandaNode::reparent(other._head, _head, sort, true,
558  pipeline_stage, current_thread);
559  nassertv(reparented);
560 }
561 
562 ////////////////////////////////////////////////////////////////////
563 // Function: NodePath::wrt_reparent_to
564 // Access: Published
565 // Description: This functions identically to reparent_to(), except
566 // the transform on this node is also adjusted so that
567 // the node remains in the same place in world
568 // coordinates, even if it is reparented into a
569 // different coordinate system.
570 ////////////////////////////////////////////////////////////////////
571 void NodePath::
572 wrt_reparent_to(const NodePath &other, int sort, Thread *current_thread) {
573  nassertv(verify_complete(current_thread));
574  nassertv(other.verify_complete(current_thread));
575  nassertv_always(!is_empty());
576  nassertv(other._error_type == ET_ok);
577 
578  if (get_transform(current_thread) == get_prev_transform(current_thread)) {
579  set_transform(get_transform(other, current_thread), current_thread);
580  node()->reset_prev_transform(current_thread);
581  } else {
582  set_transform(get_transform(other, current_thread), current_thread);
583  set_prev_transform(get_prev_transform(other, current_thread), current_thread);
584  }
585 
586  reparent_to(other, sort, current_thread);
587 }
588 
589 ////////////////////////////////////////////////////////////////////
590 // Function: NodePath::instance_to
591 // Access: Published
592 // Description: Adds the referenced node of the NodePath as a child
593 // of the referenced node of the indicated other
594 // NodePath. Any other parent-child relations of the
595 // node are unchanged; in particular, the node is not
596 // removed from its existing parent, if any.
597 //
598 // If the node already had an existing parent, this
599 // method will create a new instance of the node within
600 // the scene graph.
601 //
602 // This does not change the NodePath itself, but does
603 // return a new NodePath that reflects the new instance
604 // node.
605 //
606 // If the destination NodePath is empty, this creates a
607 // new instance which is not yet parented to any node.
608 // A new instance of this sort cannot easily be
609 // differentiated from other similar instances, but it
610 // is nevertheless a different instance and it will
611 // return a different get_id() value.
612 //
613 // If the referenced node is already a child of the
614 // indicated NodePath, returns that already-existing
615 // instance, unstashing it first if necessary.
616 ////////////////////////////////////////////////////////////////////
618 instance_to(const NodePath &other, int sort, Thread *current_thread) const {
619  nassertr(verify_complete(), NodePath::fail());
620  nassertr(other.verify_complete(), NodePath::fail());
621  nassertr_always(!is_empty(), NodePath::fail());
622  nassertr(other._error_type == ET_ok, NodePath::fail());
623 
624  NodePath new_instance;
625 
626  // First, we'll attach to NULL, to guarantee we get a brand new
627  // instance.
628  int pipeline_stage = current_thread->get_pipeline_stage();
629  new_instance._head = PandaNode::attach(NULL, node(), sort, pipeline_stage,
630  current_thread);
631 
632  // Now, we'll reparent the new instance to the target node.
633  bool reparented = PandaNode::reparent(other._head, new_instance._head,
634  sort, false, pipeline_stage,
635  current_thread);
636  if (!reparented) {
637  // Hmm, couldn't reparent. Either making this instance would
638  // create a cycle, or it was already a child of that node. If it
639  // was already a child, return that existing NodePath instead.
640  NodePath orig(other, node(), current_thread);
641  if (!orig.is_empty()) {
642  if (orig.is_stashed()) {
643  orig.unstash();
644  }
645  return orig;
646  }
647 
648  // Nope, it must be a cycle.
649  nassertr(reparented, new_instance);
650  }
651 
652  // instance_to() doesn't reset the velocity delta, unlike most of
653  // the other reparenting operations. The reasoning is that
654  // instance_to() is not necessarily a reparenting operation, since
655  // it doesn't change the original instance.
656 
657  return new_instance;
658 }
659 
660 ////////////////////////////////////////////////////////////////////
661 // Function: NodePath::instance_under_node
662 // Access: Published
663 // Description: Behaves like instance_to(), but implicitly creates a
664 // new node to instance the geometry under, and returns a
665 // NodePath to that new node. This allows the
666 // programmer to set a unique state and/or transform on
667 // this instance.
668 ////////////////////////////////////////////////////////////////////
670 instance_under_node(const NodePath &other, const string &name, int sort,
671  Thread *current_thread) const {
672  NodePath new_node = other.attach_new_node(name, sort, current_thread);
673  NodePath instance = instance_to(new_node, 0, current_thread);
674  if (instance.is_empty()) {
675  new_node.remove_node(current_thread);
676  return instance;
677  }
678  return new_node;
679 }
680 
681 ////////////////////////////////////////////////////////////////////
682 // Function: NodePath::copy_to
683 // Access: Published
684 // Description: Functions like instance_to(), except a deep
685 // copy is made of the referenced node and all of its
686 // descendents, which is then parented to the indicated
687 // node. A NodePath to the newly created copy is
688 // returned.
689 ////////////////////////////////////////////////////////////////////
691 copy_to(const NodePath &other, int sort, Thread *current_thread) const {
692  nassertr(verify_complete(current_thread), fail());
693  nassertr(other.verify_complete(current_thread), fail());
694  nassertr_always(!is_empty(), fail());
695  nassertr(other._error_type == ET_ok, fail());
696 
697  PandaNode *source_node = node();
698  PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread);
699  nassertr(copy_node != (PandaNode *)NULL, fail());
700 
701  copy_node->reset_prev_transform(current_thread);
702 
703  return other.attach_new_node(copy_node, sort, current_thread);
704 }
705 
706 ////////////////////////////////////////////////////////////////////
707 // Function: NodePath::attach_new_node
708 // Access: Published
709 // Description: Attaches a new node, with or without existing
710 // parents, to the scene graph below the referenced node
711 // of this NodePath. This is the preferred way to add
712 // nodes to the graph.
713 //
714 // If the node was already a child of the parent, this
715 // returns a NodePath to the existing child.
716 //
717 // This does *not* automatically extend the current
718 // NodePath to reflect the attachment; however, a
719 // NodePath that does reflect this extension is
720 // returned.
721 ////////////////////////////////////////////////////////////////////
723 attach_new_node(PandaNode *node, int sort, Thread *current_thread) const {
724  nassertr(verify_complete(current_thread), NodePath::fail());
725  nassertr(_error_type == ET_ok, NodePath::fail());
726  nassertr(node != (PandaNode *)NULL, NodePath::fail());
727 
728  NodePath new_path(*this);
729  int pipeline_stage = current_thread->get_pipeline_stage();
730  new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage,
731  current_thread);
732  return new_path;
733 }
734 
735 ////////////////////////////////////////////////////////////////////
736 // Function: NodePath::remove_node
737 // Access: Published
738 // Description: Disconnects the referenced node from the scene graph.
739 // This will also delete the node if there are no other
740 // pointers to it.
741 //
742 // Normally, this should be called only when you are
743 // really done with the node. If you want to remove a
744 // node from the scene graph but keep it around for
745 // later, you should probably use detach_node() instead.
746 //
747 // In practice, the only difference between
748 // remove_node() and detach_node() is that remove_node()
749 // also resets the NodePath to empty, which will cause
750 // the node to be deleted immediately if there are no
751 // other references. On the other hand, detach_node()
752 // leaves the NodePath referencing the node, which will
753 // keep at least one reference to the node for as long
754 // as the NodePath exists.
755 ////////////////////////////////////////////////////////////////////
756 void NodePath::
757 remove_node(Thread *current_thread) {
758  nassertv(_error_type != ET_not_found);
759 
760  // If we have no parents, remove_node() is just a do-nothing
761  // operation; if we have no nodes, maybe we were already removed.
762  // In either case, quietly do nothing except to ensure the
763  // NodePath is clear.
764  if (!is_empty() && !is_singleton(current_thread)) {
765  node()->reset_prev_transform(current_thread);
766  int pipeline_stage = current_thread->get_pipeline_stage();
767  PandaNode::detach(_head, pipeline_stage, current_thread);
768  }
769 
770  if (is_empty() || _head->has_key()) {
771  // Preserve the key we had on the node before we removed it.
772  int key = get_key();
773  (*this) = NodePath::removed();
774  _backup_key = key;
775 
776  } else {
777  // We didn't have a key; just clear the NodePath.
778  (*this) = NodePath::removed();
779  }
780 }
781 
782 ////////////////////////////////////////////////////////////////////
783 // Function: NodePath::detach_node
784 // Access: Published
785 // Description: Disconnects the referenced node from its parent, but
786 // does not immediately delete it. The NodePath retains
787 // a pointer to the node, and becomes a singleton
788 // NodePath.
789 //
790 // This should be called to detach a node from the scene
791 // graph, with the option of reattaching it later to the
792 // same parent or to a different parent.
793 //
794 // In practice, the only difference between
795 // remove_node() and detach_node() is that remove_node()
796 // also resets the NodePath to empty, which will cause
797 // the node to be deleted immediately if there are no
798 // other references. On the other hand, detach_node()
799 // leaves the NodePath referencing the node, which will
800 // keep at least one reference to the node for as long
801 // as the NodePath exists.
802 ////////////////////////////////////////////////////////////////////
803 void NodePath::
804 detach_node(Thread *current_thread) {
805  nassertv(_error_type != ET_not_found);
806  if (!is_empty() && !is_singleton()) {
808  int pipeline_stage = current_thread->get_pipeline_stage();
809  PandaNode::detach(_head, pipeline_stage, current_thread);
810  }
811 }
812 
813 ////////////////////////////////////////////////////////////////////
814 // Function: NodePath::output
815 // Access: Published
816 // Description: Writes a sensible description of the NodePath to the
817 // indicated output stream.
818 ////////////////////////////////////////////////////////////////////
819 void NodePath::
820 output(ostream &out) const {
821  switch (_error_type) {
822  case ET_not_found:
823  out << "**not found**";
824  return;
825  case ET_removed:
826  out << "**removed**";
827  return;
828  case ET_fail:
829  out << "**error**";
830  return;
831  default:
832  break;
833  }
834 
835  if (_head == (NodePathComponent *)NULL) {
836  out << "(empty)";
837  } else {
838  _head->output(out);
839  }
840 }
841 
842 ////////////////////////////////////////////////////////////////////
843 // Function: NodePath::get_state
844 // Access: Published
845 // Description: Returns the complete state object set on this node.
846 ////////////////////////////////////////////////////////////////////
847 const RenderState *NodePath::
848 get_state(Thread *current_thread) const {
849  // This method is declared non-inline to avoid a compiler bug in
850  // gcc-3.4 and gcc-4.0.
851  nassertr_always(!is_empty(), RenderState::make_empty());
852  return node()->get_state(current_thread);
853 }
854 
855 ////////////////////////////////////////////////////////////////////
856 // Function: NodePath::get_state
857 // Access: Published
858 // Description: Returns the state changes that must be made to
859 // transition to the render state of this node from the
860 // render state of the other node.
861 ////////////////////////////////////////////////////////////////////
863 get_state(const NodePath &other, Thread *current_thread) const {
864  nassertr(_error_type == ET_ok && other._error_type == ET_ok, RenderState::make_empty());
865 
866  if (other.is_empty()) {
867  return get_net_state(current_thread);
868  }
869  if (is_empty()) {
870  return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty());
871  }
872 
873  nassertr(verify_complete(current_thread), RenderState::make_empty());
874  nassertr(other.verify_complete(current_thread), RenderState::make_empty());
875 
876  int a_count, b_count;
877  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
878  if (allow_unrelated_wrt) {
879  pgraph_cat.debug()
880  << *this << " is not related to " << other << "\n";
881  } else {
882  pgraph_cat.error()
883  << *this << " is not related to " << other << "\n";
884  nassertr(false, RenderState::make_empty());
885  }
886  }
887 
888  CPT(RenderState) a_state = r_get_partial_state(_head, a_count, current_thread);
889  CPT(RenderState) b_state = r_get_partial_state(other._head, b_count, current_thread);
890  return b_state->invert_compose(a_state);
891 }
892 
893 ////////////////////////////////////////////////////////////////////
894 // Function: NodePath::set_state
895 // Access: Published
896 // Description: Sets the state object on this node, relative to
897 // the other node. This computes a new state object
898 // that will have the indicated value when seen from the
899 // other node.
900 ////////////////////////////////////////////////////////////////////
901 void NodePath::
902 set_state(const NodePath &other, const RenderState *state,
903  Thread *current_thread) {
904  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
905  nassertv_always(!is_empty());
906 
907  // First, we perform a wrt to the parent, to get the conversion.
908  CPT(RenderState) rel_state;
909  if (has_parent()) {
910  rel_state = other.get_state(get_parent(current_thread), current_thread);
911  } else {
912  rel_state = other.get_state(NodePath(), current_thread);
913  }
914 
915  CPT(RenderState) new_state = rel_state->compose(state);
916  set_state(new_state, current_thread);
917 }
918 
919 ////////////////////////////////////////////////////////////////////
920 // Function: NodePath::get_transform
921 // Access: Published
922 // Description: Returns the complete transform object set on this node.
923 ////////////////////////////////////////////////////////////////////
924 const TransformState *NodePath::
925 get_transform(Thread *current_thread) const {
926  // This method is declared non-inline to avoid a compiler bug in
927  // gcc-3.4 and gcc-4.0.
928  nassertr_always(!is_empty(), TransformState::make_identity());
929  return node()->get_transform(current_thread);
930 }
931 
932 ////////////////////////////////////////////////////////////////////
933 // Function: NodePath::get_transform
934 // Access: Published
935 // Description: Returns the relative transform to this node from the
936 // other node; i.e. the transformation of this node
937 // as seen from the other node.
938 ////////////////////////////////////////////////////////////////////
939 CPT(TransformState) NodePath::
940 get_transform(const NodePath &other, Thread *current_thread) const {
941  nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
942  PStatTimer timer(_get_transform_pcollector);
943 
944  if (other.is_empty()) {
945  return get_net_transform(current_thread);
946  }
947  if (is_empty()) {
948  return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity());
949  }
950 
951  nassertr(verify_complete(current_thread), TransformState::make_identity());
952  nassertr(other.verify_complete(current_thread), TransformState::make_identity());
953 
954  int a_count, b_count;
955  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
956  if (allow_unrelated_wrt) {
957  if (pgraph_cat.is_debug()) {
958  pgraph_cat.debug()
959  << *this << " is not related to " << other << "\n";
960  }
961  } else {
962  pgraph_cat.error()
963  << *this << " is not related to " << other << "\n";
964  nassertr(false, TransformState::make_identity());
965  }
966  }
967 
968  CPT(TransformState) a_transform, b_transform;
969 
970  a_transform = r_get_partial_transform(_head, a_count, current_thread);
971  if (a_transform != (TransformState *)NULL) {
972  b_transform = r_get_partial_transform(other._head, b_count, current_thread);
973  }
974  if (b_transform == (TransformState *)NULL) {
975  // If either path involved a node with a net_transform
976  // RenderEffect applied, we have to go all the way up to the root
977  // to get the right answer.
978  a_transform = r_get_net_transform(_head, current_thread);
979  b_transform = r_get_net_transform(other._head, current_thread);
980  }
981 
982  return b_transform->invert_compose(a_transform);
983 }
984 
985 ////////////////////////////////////////////////////////////////////
986 // Function: NodePath::set_transform
987 // Access: Published
988 // Description: Sets the transform object on this node, relative to
989 // the other node. This computes a new transform object
990 // that will have the indicated value when seen from the
991 // other node.
992 ////////////////////////////////////////////////////////////////////
993 void NodePath::
994 set_transform(const NodePath &other, const TransformState *transform,
995  Thread *current_thread) {
996  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
997  nassertv_always(!is_empty());
998 
999  // First, we perform a wrt to the parent, to get the conversion.
1000  CPT(TransformState) rel_trans;
1001  if (has_parent()) {
1002  rel_trans = other.get_transform(get_parent(current_thread), current_thread);
1003  } else {
1004  rel_trans = other.get_transform(NodePath(), current_thread);
1005  }
1006 
1007  CPT(TransformState) new_trans = rel_trans->compose(transform);
1008  set_transform(new_trans, current_thread);
1009 }
1010 
1011 ////////////////////////////////////////////////////////////////////
1012 // Function: NodePath::get_prev_transform
1013 // Access: Published
1014 // Description: Returns the transform that has been set as this
1015 // node's "previous" position. See
1016 // set_prev_transform().
1017 ////////////////////////////////////////////////////////////////////
1018 const TransformState *NodePath::
1019 get_prev_transform(Thread *current_thread) const {
1020  // This method is declared non-inline to avoid a compiler bug in
1021  // gcc-3.4 and gcc-4.0.
1022  nassertr_always(!is_empty(), TransformState::make_identity());
1023  return node()->get_prev_transform(current_thread);
1024 }
1025 
1026 ////////////////////////////////////////////////////////////////////
1027 // Function: NodePath::get_prev_transform
1028 // Access: Published
1029 // Description: Returns the relative "previous" transform to this
1030 // node from the other node; i.e. the position of this
1031 // node in the previous frame, as seen by the other node
1032 // in the previous frame.
1033 ////////////////////////////////////////////////////////////////////
1034 CPT(TransformState) NodePath::
1035 get_prev_transform(const NodePath &other, Thread *current_thread) const {
1036  nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
1037 
1038  if (other.is_empty()) {
1039  return get_net_prev_transform(current_thread);
1040  }
1041  if (is_empty()) {
1042  return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity());
1043  }
1044 
1045  nassertr(verify_complete(current_thread), TransformState::make_identity());
1046  nassertr(other.verify_complete(current_thread), TransformState::make_identity());
1047 
1048  int a_count, b_count;
1049  if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
1050  if (allow_unrelated_wrt) {
1051  pgraph_cat.debug()
1052  << *this << " is not related to " << other << "\n";
1053  } else {
1054  pgraph_cat.error()
1055  << *this << " is not related to " << other << "\n";
1056  nassertr(false, TransformState::make_identity());
1057  }
1058  }
1059 
1060  CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count, current_thread);
1061  CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count, current_thread);
1062  return b_prev_transform->invert_compose(a_prev_transform);
1063 }
1064 
1065 ////////////////////////////////////////////////////////////////////
1066 // Function: NodePath::set_prev_transform
1067 // Access: Published
1068 // Description: Sets the "previous" transform object on this node,
1069 // relative to the other node. This computes a new
1070 // transform object that will have the indicated value
1071 // when seen from the other node.
1072 ////////////////////////////////////////////////////////////////////
1073 void NodePath::
1074 set_prev_transform(const NodePath &other, const TransformState *transform,
1075  Thread *current_thread) {
1076  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
1077  nassertv_always(!is_empty());
1078 
1079  // First, we perform a wrt to the parent, to get the conversion.
1080  CPT(TransformState) rel_trans;
1081  if (has_parent(current_thread)) {
1082  rel_trans = other.get_prev_transform(get_parent(current_thread), current_thread);
1083  } else {
1084  rel_trans = other.get_prev_transform(NodePath(), current_thread);
1085  }
1086 
1087  CPT(TransformState) new_trans = rel_trans->compose(transform);
1088  set_prev_transform(new_trans, current_thread);
1089 }
1090 
1091 ////////////////////////////////////////////////////////////////////
1092 // Function: NodePath::set_pos
1093 // Access: Published
1094 // Description: Sets the translation component of the transform,
1095 // leaving rotation and scale untouched. This also
1096 // resets the node's "previous" position, so that the
1097 // collision system will see the node as having suddenly
1098 // appeared in the new position, without passing any
1099 // points in between.
1100 // See Also: NodePath::set_fluid_pos
1101 ////////////////////////////////////////////////////////////////////
1102 void NodePath::
1103 set_pos(const LVecBase3 &pos) {
1104  nassertv_always(!is_empty());
1105  set_transform(get_transform()->set_pos(pos));
1107 }
1108 
1109 void NodePath::
1110 set_x(PN_stdfloat x) {
1111  nassertv_always(!is_empty());
1112  LPoint3 pos = get_pos();
1113  pos[0] = x;
1114  set_pos(pos);
1115 }
1116 
1117 void NodePath::
1118 set_y(PN_stdfloat y) {
1119  nassertv_always(!is_empty());
1120  LPoint3 pos = get_pos();
1121  pos[1] = y;
1122  set_pos(pos);
1123 }
1124 
1125 void NodePath::
1126 set_z(PN_stdfloat z) {
1127  nassertv_always(!is_empty());
1128  LPoint3 pos = get_pos();
1129  pos[2] = z;
1130  set_pos(pos);
1131 }
1132 
1133 ////////////////////////////////////////////////////////////////////
1134 // Function: NodePath::set_fluid_pos
1135 // Access: Published
1136 // Description: Sets the translation component, without changing the
1137 // "previous" position, so that the collision system
1138 // will see the node as moving fluidly from its previous
1139 // position to its new position.
1140 // See Also: NodePath::set_pos
1141 ////////////////////////////////////////////////////////////////////
1142 void NodePath::
1144  nassertv_always(!is_empty());
1145  set_transform(get_transform()->set_pos(pos));
1146 }
1147 
1148 void NodePath::
1149 set_fluid_x(PN_stdfloat x) {
1150  nassertv_always(!is_empty());
1151  LPoint3 pos = get_pos();
1152  pos[0] = x;
1153  set_fluid_pos(pos);
1154 }
1155 
1156 void NodePath::
1157 set_fluid_y(PN_stdfloat y) {
1158  nassertv_always(!is_empty());
1159  LPoint3 pos = get_pos();
1160  pos[1] = y;
1161  set_fluid_pos(pos);
1162 }
1163 
1164 void NodePath::
1165 set_fluid_z(PN_stdfloat z) {
1166  nassertv_always(!is_empty());
1167  LPoint3 pos = get_pos();
1168  pos[2] = z;
1169  set_fluid_pos(pos);
1170 }
1171 
1172 ////////////////////////////////////////////////////////////////////
1173 // Function: NodePath::get_pos
1174 // Access: Published
1175 // Description: Retrieves the translation component of the transform.
1176 ////////////////////////////////////////////////////////////////////
1178 get_pos() const {
1179  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
1180  return get_transform()->get_pos();
1181 }
1182 
1183 ////////////////////////////////////////////////////////////////////
1184 // Function: NodePath::get_pos_delta
1185 // Access: Published
1186 // Description: Returns the delta vector from this node's position in
1187 // the previous frame (according to
1188 // set_prev_transform(), typically set via the use of
1189 // set_fluid_pos()) and its position in the current
1190 // frame. This is the vector used to determine
1191 // collisions. Generally, if the node was last
1192 // repositioned via set_pos(), the delta will be zero;
1193 // if it was adjusted via set_fluid_pos(), the delta
1194 // will represent the change from the previous frame's
1195 // position.
1196 ////////////////////////////////////////////////////////////////////
1198 get_pos_delta() const {
1199  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
1200  return get_transform()->get_pos() - get_prev_transform()->get_pos();
1201 }
1202 
1203 ////////////////////////////////////////////////////////////////////
1204 // Function: NodePath::set_hpr
1205 // Access: Published
1206 // Description: Sets the rotation component of the transform,
1207 // leaving translation and scale untouched.
1208 ////////////////////////////////////////////////////////////////////
1209 void NodePath::
1210 set_hpr(const LVecBase3 &hpr) {
1211  nassertv_always(!is_empty());
1212  CPT(TransformState) transform = get_transform();
1213  nassertv(transform->has_hpr());
1214  set_transform(transform->set_hpr(hpr));
1215 }
1216 
1217 void NodePath::
1218 set_h(PN_stdfloat h) {
1219  nassertv_always(!is_empty());
1220  CPT(TransformState) transform = get_transform();
1221  nassertv(transform->has_hpr());
1222  LVecBase3 hpr = transform->get_hpr();
1223  hpr[0] = h;
1224  set_transform(transform->set_hpr(hpr));
1225 }
1226 
1227 void NodePath::
1228 set_p(PN_stdfloat p) {
1229  nassertv_always(!is_empty());
1230  CPT(TransformState) transform = get_transform();
1231  nassertv(transform->has_hpr());
1232  LVecBase3 hpr = transform->get_hpr();
1233  hpr[1] = p;
1234  set_transform(transform->set_hpr(hpr));
1235 }
1236 
1237 void NodePath::
1238 set_r(PN_stdfloat r) {
1239  nassertv_always(!is_empty());
1240  CPT(TransformState) transform = get_transform();
1241  nassertv(transform->has_hpr());
1242  LVecBase3 hpr = transform->get_hpr();
1243  hpr[2] = r;
1244  set_transform(transform->set_hpr(hpr));
1245 }
1246 
1247 ////////////////////////////////////////////////////////////////////
1248 // Function: NodePath::get_hpr
1249 // Access: Published
1250 // Description: Retrieves the rotation component of the transform.
1251 ////////////////////////////////////////////////////////////////////
1253 get_hpr() const {
1254  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1255  CPT(TransformState) transform = get_transform();
1256  nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f));
1257  return transform->get_hpr();
1258 }
1259 
1260 ////////////////////////////////////////////////////////////////////
1261 // Function: NodePath::set_quat
1262 // Access: Published
1263 // Description: Sets the rotation component of the transform,
1264 // leaving translation and scale untouched.
1265 ////////////////////////////////////////////////////////////////////
1266 void NodePath::
1267 set_quat(const LQuaternion &quat) {
1268  nassertv_always(!is_empty());
1269  CPT(TransformState) transform = get_transform();
1270  set_transform(transform->set_quat(quat));
1271 }
1272 
1273 ////////////////////////////////////////////////////////////////////
1274 // Function: NodePath::get_quat
1275 // Access: Published
1276 // Description: Retrieves the rotation component of the transform.
1277 ////////////////////////////////////////////////////////////////////
1279 get_quat() const {
1280  nassertr_always(!is_empty(), LQuaternion::ident_quat());
1281  CPT(TransformState) transform = get_transform();
1282  return transform->get_quat();
1283 }
1284 
1285 ////////////////////////////////////////////////////////////////////
1286 // Function: NodePath::set_scale
1287 // Access: Published
1288 // Description: Sets the scale component of the transform,
1289 // leaving translation and rotation untouched.
1290 ////////////////////////////////////////////////////////////////////
1291 void NodePath::
1292 set_scale(const LVecBase3 &scale) {
1293  nassertv_always(!is_empty());
1294  CPT(TransformState) transform = get_transform();
1295  set_transform(transform->set_scale(scale));
1296 }
1297 
1298 void NodePath::
1299 set_sx(PN_stdfloat sx) {
1300  nassertv_always(!is_empty());
1301  CPT(TransformState) transform = get_transform();
1302  LVecBase3 scale = transform->get_scale();
1303  scale[0] = sx;
1304  set_transform(transform->set_scale(scale));
1305 }
1306 
1307 void NodePath::
1308 set_sy(PN_stdfloat sy) {
1309  nassertv_always(!is_empty());
1310  CPT(TransformState) transform = get_transform();
1311  LVecBase3 scale = transform->get_scale();
1312  scale[1] = sy;
1313  set_transform(transform->set_scale(scale));
1314 }
1315 
1316 void NodePath::
1317 set_sz(PN_stdfloat sz) {
1318  nassertv_always(!is_empty());
1319  CPT(TransformState) transform = get_transform();
1320  LVecBase3 scale = transform->get_scale();
1321  scale[2] = sz;
1322  set_transform(transform->set_scale(scale));
1323 }
1324 
1325 ////////////////////////////////////////////////////////////////////
1326 // Function: NodePath::get_scale
1327 // Access: Published
1328 // Description: Retrieves the scale component of the transform.
1329 ////////////////////////////////////////////////////////////////////
1331 get_scale() const {
1332  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1333  CPT(TransformState) transform = get_transform();
1334  return transform->get_scale();
1335 }
1336 
1337 ////////////////////////////////////////////////////////////////////
1338 // Function: NodePath::set_shear
1339 // Access: Published
1340 // Description: Sets the shear component of the transform,
1341 // leaving translation and rotation untouched.
1342 ////////////////////////////////////////////////////////////////////
1343 void NodePath::
1344 set_shear(const LVecBase3 &shear) {
1345  nassertv_always(!is_empty());
1346  CPT(TransformState) transform = get_transform();
1347  set_transform(transform->set_shear(shear));
1348 }
1349 
1350 void NodePath::
1351 set_shxy(PN_stdfloat shxy) {
1352  nassertv_always(!is_empty());
1353  CPT(TransformState) transform = get_transform();
1354  LVecBase3 shear = transform->get_shear();
1355  shear[0] = shxy;
1356  set_transform(transform->set_shear(shear));
1357 }
1358 
1359 void NodePath::
1360 set_shxz(PN_stdfloat shxz) {
1361  nassertv_always(!is_empty());
1362  CPT(TransformState) transform = get_transform();
1363  LVecBase3 shear = transform->get_shear();
1364  shear[1] = shxz;
1365  set_transform(transform->set_shear(shear));
1366 }
1367 
1368 void NodePath::
1369 set_shyz(PN_stdfloat shyz) {
1370  nassertv_always(!is_empty());
1371  CPT(TransformState) transform = get_transform();
1372  LVecBase3 shear = transform->get_shear();
1373  shear[2] = shyz;
1374  set_transform(transform->set_shear(shear));
1375 }
1376 
1377 ////////////////////////////////////////////////////////////////////
1378 // Function: NodePath::get_shear
1379 // Access: Published
1380 // Description: Retrieves the shear component of the transform.
1381 ////////////////////////////////////////////////////////////////////
1383 get_shear() const {
1384  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1385  CPT(TransformState) transform = get_transform();
1386  return transform->get_shear();
1387 }
1388 
1389 ////////////////////////////////////////////////////////////////////
1390 // Function: NodePath::set_pos_hpr
1391 // Access: Published
1392 // Description: Sets the translation and rotation component of the
1393 // transform, leaving scale untouched.
1394 ////////////////////////////////////////////////////////////////////
1395 void NodePath::
1396 set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr) {
1397  nassertv_always(!is_empty());
1398  CPT(TransformState) transform = get_transform();
1399  transform = TransformState::make_pos_hpr_scale_shear
1400  (pos, hpr, transform->get_scale(), transform->get_shear());
1401  set_transform(transform);
1403 }
1404 
1405 ////////////////////////////////////////////////////////////////////
1406 // Function: NodePath::set_pos_quat
1407 // Access: Published
1408 // Description: Sets the translation and rotation component of the
1409 // transform, leaving scale untouched.
1410 ////////////////////////////////////////////////////////////////////
1411 void NodePath::
1412 set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat) {
1413  nassertv_always(!is_empty());
1414  CPT(TransformState) transform = get_transform();
1415  transform = TransformState::make_pos_quat_scale_shear
1416  (pos, quat, transform->get_scale(), transform->get_shear());
1417  set_transform(transform);
1419 }
1420 
1421 ////////////////////////////////////////////////////////////////////
1422 // Function: NodePath::set_hpr_scale
1423 // Access: Published
1424 // Description: Sets the rotation and scale components of the
1425 // transform, leaving translation untouched.
1426 ////////////////////////////////////////////////////////////////////
1427 void NodePath::
1428 set_hpr_scale(const LVecBase3 &hpr, const LVecBase3 &scale) {
1429  nassertv_always(!is_empty());
1430  CPT(TransformState) transform = get_transform();
1431  transform = TransformState::make_pos_hpr_scale_shear
1432  (transform->get_pos(), hpr, scale, transform->get_shear());
1433  set_transform(transform);
1434 }
1435 
1436 ////////////////////////////////////////////////////////////////////
1437 // Function: NodePath::set_quat_scale
1438 // Access: Published
1439 // Description: Sets the rotation and scale components of the
1440 // transform, leaving translation untouched.
1441 ////////////////////////////////////////////////////////////////////
1442 void NodePath::
1443 set_quat_scale(const LQuaternion &quat, const LVecBase3 &scale) {
1444  nassertv_always(!is_empty());
1445  CPT(TransformState) transform = get_transform();
1446  transform = TransformState::make_pos_quat_scale_shear
1447  (transform->get_pos(), quat, scale, transform->get_shear());
1448  set_transform(transform);
1449 }
1450 
1451 ////////////////////////////////////////////////////////////////////
1452 // Function: NodePath::set_pos_hpr_scale
1453 // Access: Published
1454 // Description: Replaces the translation, rotation, and scale
1455 // components, implicitly setting shear to 0.
1456 ////////////////////////////////////////////////////////////////////
1457 void NodePath::
1458 set_pos_hpr_scale(const LVecBase3 &pos, const LVecBase3 &hpr,
1459  const LVecBase3 &scale) {
1460  nassertv_always(!is_empty());
1461  set_transform(TransformState::make_pos_hpr_scale
1462  (pos, hpr, scale));
1464 }
1465 
1466 ////////////////////////////////////////////////////////////////////
1467 // Function: NodePath::set_pos_quat_scale
1468 // Access: Published
1469 // Description: Replaces the translation, rotation, and scale
1470 // components, implicitly setting shear to 0.
1471 ////////////////////////////////////////////////////////////////////
1472 void NodePath::
1473 set_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat,
1474  const LVecBase3 &scale) {
1475  nassertv_always(!is_empty());
1476  set_transform(TransformState::make_pos_quat_scale
1477  (pos, quat, scale));
1479 }
1480 
1481 ////////////////////////////////////////////////////////////////////
1482 // Function: NodePath::set_pos_hpr_scale_shear
1483 // Access: Published
1484 // Description: Completely replaces the transform with new
1485 // translation, rotation, scale, and shear components.
1486 ////////////////////////////////////////////////////////////////////
1487 void NodePath::
1489  const LVecBase3 &scale, const LVecBase3 &shear) {
1490  nassertv_always(!is_empty());
1491  set_transform(TransformState::make_pos_hpr_scale_shear
1492  (pos, hpr, scale, shear));
1494 }
1495 
1496 ////////////////////////////////////////////////////////////////////
1497 // Function: NodePath::set_pos_quat_scale_shear
1498 // Access: Published
1499 // Description: Completely replaces the transform with new
1500 // translation, rotation, scale, and shear components.
1501 ////////////////////////////////////////////////////////////////////
1502 void NodePath::
1504  const LVecBase3 &scale, const LVecBase3 &shear) {
1505  nassertv_always(!is_empty());
1506  set_transform(TransformState::make_pos_quat_scale_shear
1507  (pos, quat, scale, shear));
1509 }
1510 
1511 ////////////////////////////////////////////////////////////////////
1512 // Function: NodePath::set_mat
1513 // Access: Published
1514 // Description: Directly sets an arbitrary 4x4 transform matrix.
1515 ////////////////////////////////////////////////////////////////////
1516 void NodePath::
1517 set_mat(const LMatrix4 &mat) {
1518  nassertv_always(!is_empty());
1519  set_transform(TransformState::make_mat(mat));
1521 }
1522 
1523 ////////////////////////////////////////////////////////////////////
1524 // Function: NodePath::look_at
1525 // Access: Published
1526 // Description: Sets the hpr on this NodePath so that it
1527 // rotates to face the indicated point in space.
1528 ////////////////////////////////////////////////////////////////////
1529 void NodePath::
1530 look_at(const LPoint3 &point, const LVector3 &up) {
1531  nassertv_always(!is_empty());
1532 
1533  LPoint3 pos = get_pos();
1534 
1535  LQuaternion quat;
1536  ::look_at(quat, point - pos, up);
1537  set_quat(quat);
1538 }
1539 
1540 ////////////////////////////////////////////////////////////////////
1541 // Function: NodePath::heads_up
1542 // Access: Published
1543 // Description: Behaves like look_at(), but with a strong preference
1544 // to keeping the up vector oriented in the indicated
1545 // "up" direction.
1546 ////////////////////////////////////////////////////////////////////
1547 void NodePath::
1548 heads_up(const LPoint3 &point, const LVector3 &up) {
1549  nassertv_always(!is_empty());
1550 
1551  LPoint3 pos = get_pos();
1552 
1553  LQuaternion quat;
1554  ::heads_up(quat, point - pos, up);
1555  set_quat(quat);
1556 }
1557 
1558 ////////////////////////////////////////////////////////////////////
1559 // Function: NodePath::set_pos
1560 // Access: Published
1561 // Description: Sets the translation component of the transform,
1562 // relative to the other node.
1563 ////////////////////////////////////////////////////////////////////
1564 void NodePath::
1565 set_pos(const NodePath &other, const LVecBase3 &pos) {
1566  nassertv_always(!is_empty());
1567  CPT(TransformState) rel_transform = get_transform(other);
1568 
1569  CPT(TransformState) orig_transform = get_transform();
1570  if (orig_transform->has_components()) {
1571  // If we had a componentwise transform before we started, we
1572  // should be careful to preserve the other three components. We
1573  // wouldn't need to do this, except for the possibility of
1574  // numerical error or decompose ambiguity.
1575  const LVecBase3 &orig_hpr = orig_transform->get_hpr();
1576  const LVecBase3 &orig_scale = orig_transform->get_scale();
1577  const LVecBase3 &orig_shear = orig_transform->get_shear();
1578 
1579  set_transform(other, rel_transform->set_pos(pos));
1580  set_pos_hpr_scale_shear(get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear);
1581 
1582  } else {
1583  // If we didn't have a componentwise transform already, never
1584  // mind.
1585  set_transform(other, rel_transform->set_pos(pos));
1586  }
1588 }
1589 
1590 void NodePath::
1591 set_x(const NodePath &other, PN_stdfloat x) {
1592  nassertv_always(!is_empty());
1593  LPoint3 pos = get_pos(other);
1594  pos[0] = x;
1595  set_pos(other, pos);
1596 }
1597 
1598 void NodePath::
1599 set_y(const NodePath &other, PN_stdfloat y) {
1600  nassertv_always(!is_empty());
1601  LPoint3 pos = get_pos(other);
1602  pos[1] = y;
1603  set_pos(other, pos);
1604 }
1605 
1606 void NodePath::
1607 set_z(const NodePath &other, PN_stdfloat z) {
1608  nassertv_always(!is_empty());
1609  LPoint3 pos = get_pos(other);
1610  pos[2] = z;
1611  set_pos(other, pos);
1612 }
1613 
1614 ////////////////////////////////////////////////////////////////////
1615 // Function: NodePath::set_fluid_pos
1616 // Access: Published
1617 // Description: Sets the translation component of the transform,
1618 // relative to the other node.
1619 ////////////////////////////////////////////////////////////////////
1620 void NodePath::
1621 set_fluid_pos(const NodePath &other, const LVecBase3 &pos) {
1622  nassertv_always(!is_empty());
1623  CPT(TransformState) rel_transform = get_transform(other);
1624 
1625  CPT(TransformState) orig_transform = get_transform();
1626  if (orig_transform->has_components()) {
1627  // If we had a componentwise transform before we started, we
1628  // should be careful to preserve the other three components. We
1629  // wouldn't need to do this, except for the possibility of
1630  // numerical error or decompose ambiguity.
1631  const LVecBase3 &orig_hpr = orig_transform->get_hpr();
1632  const LVecBase3 &orig_scale = orig_transform->get_scale();
1633  const LVecBase3 &orig_shear = orig_transform->get_shear();
1634 
1635  // Use the relative set_transform() to compute the relative pos, and
1636  // then reset all of the other components back to the way they were.
1637  set_transform(other, rel_transform->set_pos(pos));
1638  set_transform(TransformState::make_pos_hpr_scale_shear
1639  (get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear));
1640 
1641  } else {
1642  // If we didn't have a componentwise transform already, never
1643  // mind.
1644  set_transform(other, rel_transform->set_pos(pos));
1645  }
1646 }
1647 
1648 void NodePath::
1649 set_fluid_x(const NodePath &other, PN_stdfloat x) {
1650  nassertv_always(!is_empty());
1651  LPoint3 pos = get_pos(other);
1652  pos[0] = x;
1653  set_fluid_pos(other, pos);
1654 }
1655 
1656 void NodePath::
1657 set_fluid_y(const NodePath &other, PN_stdfloat y) {
1658  nassertv_always(!is_empty());
1659  LPoint3 pos = get_pos(other);
1660  pos[1] = y;
1661  set_fluid_pos(other, pos);
1662 }
1663 
1664 void NodePath::
1665 set_fluid_z(const NodePath &other, PN_stdfloat z) {
1666  nassertv_always(!is_empty());
1667  LPoint3 pos = get_pos(other);
1668  pos[2] = z;
1669  set_fluid_pos(other, pos);
1670 }
1671 
1672 ////////////////////////////////////////////////////////////////////
1673 // Function: NodePath::get_pos
1674 // Access: Published
1675 // Description: Returns the relative position of the referenced node
1676 // as seen from the other node.
1677 ////////////////////////////////////////////////////////////////////
1679 get_pos(const NodePath &other) const {
1680  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
1681  return get_transform(other)->get_pos();
1682 }
1683 
1684 ////////////////////////////////////////////////////////////////////
1685 // Function: NodePath::get_pos_delta
1686 // Access: Published
1687 // Description: Returns the delta vector from this node's position in
1688 // the previous frame (according to
1689 // set_prev_transform(), typically set via the use of
1690 // set_fluid_pos()) and its position in the current
1691 // frame, as seen in the indicated node's coordinate
1692 // space. This is the vector used to determine
1693 // collisions. Generally, if the node was last
1694 // repositioned via set_pos(), the delta will be zero;
1695 // if it was adjusted via set_fluid_pos(), the delta
1696 // will represent the change from the previous frame's
1697 // position.
1698 ////////////////////////////////////////////////////////////////////
1700 get_pos_delta(const NodePath &other) const {
1701  nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
1702  return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos();
1703 }
1704 
1705 ////////////////////////////////////////////////////////////////////
1706 // Function: NodePath::set_hpr
1707 // Access: Published
1708 // Description: Sets the rotation component of the transform,
1709 // relative to the other node.
1710 ////////////////////////////////////////////////////////////////////
1711 void NodePath::
1712 set_hpr(const NodePath &other, const LVecBase3 &hpr) {
1713  nassertv_always(!is_empty());
1714  CPT(TransformState) rel_transform = get_transform(other);
1715  nassertv(rel_transform->has_hpr());
1716 
1717  CPT(TransformState) transform = get_transform();
1718  if (transform->has_components()) {
1719  // If we had a componentwise transform before we started, we
1720  // should be careful to preserve the other three components. We
1721  // wouldn't need to do this, except for the possibility of
1722  // numerical error or decompose ambiguity.
1723  const LVecBase3 &orig_pos = transform->get_pos();
1724  const LVecBase3 &orig_scale = transform->get_scale();
1725  const LVecBase3 &orig_shear = transform->get_shear();
1726 
1727  set_transform(other, rel_transform->set_hpr(hpr));
1728  transform = get_transform();
1729  if (transform->has_components()) {
1730  set_transform(TransformState::make_pos_hpr_scale_shear
1731  (orig_pos, transform->get_hpr(), orig_scale, orig_shear));
1732  }
1733 
1734  } else {
1735  // If we didn't have a componentwise transform already, never
1736  // mind.
1737  set_transform(other, rel_transform->set_hpr(hpr));
1738  }
1739 }
1740 
1741 void NodePath::
1742 set_h(const NodePath &other, PN_stdfloat h) {
1743  nassertv_always(!is_empty());
1744  LVecBase3 hpr = get_hpr(other);
1745  hpr[0] = h;
1746  set_hpr(other, hpr);
1747 }
1748 
1749 void NodePath::
1750 set_p(const NodePath &other, PN_stdfloat p) {
1751  nassertv_always(!is_empty());
1752  LVecBase3 hpr = get_hpr(other);
1753  hpr[1] = p;
1754  set_hpr(other, hpr);
1755 }
1756 
1757 void NodePath::
1758 set_r(const NodePath &other, PN_stdfloat r) {
1759  nassertv_always(!is_empty());
1760  LVecBase3 hpr = get_hpr(other);
1761  hpr[2] = r;
1762  set_hpr(other, hpr);
1763 }
1764 
1765 ////////////////////////////////////////////////////////////////////
1766 // Function: NodePath::get_hpr
1767 // Access: Published
1768 // Description: Returns the relative orientation of the bottom node
1769 // as seen from the other node.
1770 ////////////////////////////////////////////////////////////////////
1772 get_hpr(const NodePath &other) const {
1773  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1774  CPT(TransformState) transform = get_transform(other);
1775  nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f));
1776  return transform->get_hpr();
1777 }
1778 
1779 ////////////////////////////////////////////////////////////////////
1780 // Function: NodePath::set_quat
1781 // Access: Published
1782 // Description: Sets the rotation component of the transform,
1783 // relative to the other node.
1784 ////////////////////////////////////////////////////////////////////
1785 void NodePath::
1786 set_quat(const NodePath &other, const LQuaternion &quat) {
1787  nassertv_always(!is_empty());
1788  CPT(TransformState) rel_transform = get_transform(other);
1789 
1790  CPT(TransformState) transform = get_transform();
1791  if (transform->has_components()) {
1792  // If we had a componentwise transform before we started, we
1793  // should be careful to preserve the other three components. We
1794  // wouldn't need to do this, except for the possibility of
1795  // numerical error or decompose ambiguity.
1796  const LVecBase3 &orig_pos = transform->get_pos();
1797  const LVecBase3 &orig_scale = transform->get_scale();
1798  const LVecBase3 &orig_shear = transform->get_shear();
1799 
1800  set_transform(other, rel_transform->set_quat(quat));
1801  transform = get_transform();
1802  if (transform->has_components()) {
1803  set_transform(TransformState::make_pos_quat_scale_shear
1804  (orig_pos, transform->get_quat(), orig_scale, orig_shear));
1805  }
1806 
1807  } else {
1808  // If we didn't have a componentwise transform already, never
1809  // mind.
1810  set_transform(other, rel_transform->set_quat(quat));
1811  }
1812 }
1813 
1814 ////////////////////////////////////////////////////////////////////
1815 // Function: NodePath::get_quat
1816 // Access: Published
1817 // Description: Returns the relative orientation of the bottom node
1818 // as seen from the other node.
1819 ////////////////////////////////////////////////////////////////////
1821 get_quat(const NodePath &other) const {
1822  nassertr_always(!is_empty(), LQuaternion::ident_quat());
1823  CPT(TransformState) transform = get_transform(other);
1824  return transform->get_quat();
1825 }
1826 
1827 ////////////////////////////////////////////////////////////////////
1828 // Function: NodePath::set_scale
1829 // Access: Published
1830 // Description: Sets the scale component of the transform,
1831 // relative to the other node.
1832 ////////////////////////////////////////////////////////////////////
1833 void NodePath::
1834 set_scale(const NodePath &other, const LVecBase3 &scale) {
1835  nassertv_always(!is_empty());
1836  CPT(TransformState) rel_transform = get_transform(other);
1837 
1838  CPT(TransformState) transform = get_transform();
1839  if (transform->has_components()) {
1840  // If we had a componentwise transform before we started, we
1841  // should be careful to preserve the other three components. We
1842  // wouldn't need to do this, except for the possibility of
1843  // numerical error or decompose ambiguity.
1844  const LVecBase3 &orig_pos = transform->get_pos();
1845  const LVecBase3 &orig_hpr = transform->get_hpr();
1846  const LVecBase3 &orig_shear = transform->get_shear();
1847 
1848  set_transform(other, rel_transform->set_scale(scale));
1849  transform = get_transform();
1850  if (transform->has_components()) {
1851  set_transform(TransformState::make_pos_hpr_scale_shear
1852  (orig_pos, orig_hpr, transform->get_scale(), orig_shear));
1853  }
1854 
1855  } else {
1856  // If we didn't have a componentwise transform already, never
1857  // mind.
1858  set_transform(other, rel_transform->set_scale(scale));
1859  }
1860 }
1861 
1862 void NodePath::
1863 set_sx(const NodePath &other, PN_stdfloat sx) {
1864  nassertv_always(!is_empty());
1865  LVecBase3 scale = get_scale(other);
1866  scale[0] = sx;
1867  set_scale(other, scale);
1868 }
1869 
1870 void NodePath::
1871 set_sy(const NodePath &other, PN_stdfloat sy) {
1872  nassertv_always(!is_empty());
1873  LVecBase3 scale = get_scale(other);
1874  scale[1] = sy;
1875  set_scale(other, scale);
1876 }
1877 
1878 void NodePath::
1879 set_sz(const NodePath &other, PN_stdfloat sz) {
1880  nassertv_always(!is_empty());
1881  LVecBase3 scale = get_scale(other);
1882  scale[2] = sz;
1883  set_scale(other, scale);
1884 }
1885 
1886 ////////////////////////////////////////////////////////////////////
1887 // Function: NodePath::get_scale
1888 // Access: Published
1889 // Description: Returns the relative scale of the bottom node
1890 // as seen from the other node.
1891 ////////////////////////////////////////////////////////////////////
1893 get_scale(const NodePath &other) const {
1894  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1895  CPT(TransformState) transform = get_transform(other);
1896  return transform->get_scale();
1897 }
1898 
1899 ////////////////////////////////////////////////////////////////////
1900 // Function: NodePath::set_shear
1901 // Access: Published
1902 // Description: Sets the shear component of the transform,
1903 // relative to the other node.
1904 ////////////////////////////////////////////////////////////////////
1905 void NodePath::
1906 set_shear(const NodePath &other, const LVecBase3 &shear) {
1907  nassertv_always(!is_empty());
1908  CPT(TransformState) rel_transform = get_transform(other);
1909 
1910  CPT(TransformState) transform = get_transform();
1911  if (transform->has_components()) {
1912  // If we had a componentwise transform before we started, we
1913  // should be careful to preserve the other three components. We
1914  // wouldn't need to do this, except for the possibility of
1915  // numerical error or decompose ambiguity.
1916  const LVecBase3 &orig_pos = transform->get_pos();
1917  const LVecBase3 &orig_hpr = transform->get_hpr();
1918  const LVecBase3 &orig_scale = transform->get_scale();
1919 
1920  set_transform(other, rel_transform->set_shear(shear));
1921  transform = get_transform();
1922  if (transform->has_components()) {
1923  set_transform(TransformState::make_pos_hpr_scale_shear
1924  (orig_pos, orig_hpr, orig_scale, transform->get_shear()));
1925  }
1926 
1927  } else {
1928  // If we didn't have a componentwise transform already, never
1929  // mind.
1930  set_transform(other, rel_transform->set_shear(shear));
1931  }
1932 }
1933 
1934 void NodePath::
1935 set_shxy(const NodePath &other, PN_stdfloat shxy) {
1936  nassertv_always(!is_empty());
1937  LVecBase3 shear = get_shear(other);
1938  shear[0] = shxy;
1939  set_shear(other, shear);
1940 }
1941 
1942 void NodePath::
1943 set_shxz(const NodePath &other, PN_stdfloat shxz) {
1944  nassertv_always(!is_empty());
1945  LVecBase3 shear = get_shear(other);
1946  shear[1] = shxz;
1947  set_shear(other, shear);
1948 }
1949 
1950 void NodePath::
1951 set_shyz(const NodePath &other, PN_stdfloat shyz) {
1952  nassertv_always(!is_empty());
1953  LVecBase3 shear = get_shear(other);
1954  shear[2] = shyz;
1955  set_shear(other, shear);
1956 }
1957 
1958 ////////////////////////////////////////////////////////////////////
1959 // Function: NodePath::get_shear
1960 // Access: Published
1961 // Description: Returns the relative shear of the bottom node
1962 // as seen from the other node.
1963 ////////////////////////////////////////////////////////////////////
1965 get_shear(const NodePath &other) const {
1966  nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
1967  CPT(TransformState) transform = get_transform(other);
1968  return transform->get_shear();
1969 }
1970 
1971 ////////////////////////////////////////////////////////////////////
1972 // Function: NodePath::set_pos_hpr
1973 // Access: Published
1974 // Description: Sets the translation and rotation component of the
1975 // transform, relative to the other node.
1976 ////////////////////////////////////////////////////////////////////
1977 void NodePath::
1978 set_pos_hpr(const NodePath &other, const LVecBase3 &pos,
1979  const LVecBase3 &hpr) {
1980  nassertv_always(!is_empty());
1981  CPT(TransformState) rel_transform = get_transform(other);
1982 
1983  CPT(TransformState) transform = get_transform();
1984  if (transform->has_components()) {
1985  // If we had a componentwise transform before we started, we
1986  // should be careful to preserve the other two components. We
1987  // wouldn't need to do this, except for the possibility of
1988  // numerical error or decompose ambiguity.
1989  const LVecBase3 &orig_scale = transform->get_scale();
1990  const LVecBase3 &orig_shear = transform->get_shear();
1991 
1992  set_transform(other, TransformState::make_pos_hpr_scale_shear
1993  (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
1994  transform = get_transform();
1995  if (transform->has_components()) {
1996  set_pos_hpr_scale_shear(transform->get_pos(), transform->get_hpr(),
1997  orig_scale, orig_shear);
1998  }
1999 
2000  } else {
2001  // If we didn't have a componentwise transform already, never
2002  // mind.
2003  set_transform(other, TransformState::make_pos_hpr_scale_shear
2004  (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
2006  }
2007 }
2008 
2009 ////////////////////////////////////////////////////////////////////
2010 // Function: NodePath::set_pos_quat
2011 // Access: Published
2012 // Description: Sets the translation and rotation component of the
2013 // transform, relative to the other node.
2014 ////////////////////////////////////////////////////////////////////
2015 void NodePath::
2016 set_pos_quat(const NodePath &other, const LVecBase3 &pos,
2017  const LQuaternion &quat) {
2018  nassertv_always(!is_empty());
2019  CPT(TransformState) rel_transform = get_transform(other);
2020 
2021  CPT(TransformState) transform = get_transform();
2022  if (transform->has_components()) {
2023  // If we had a componentwise transform before we started, we
2024  // should be careful to preserve the other two components. We
2025  // wouldn't need to do this, except for the possibility of
2026  // numerical error or decompose ambiguity.
2027  const LVecBase3 &orig_scale = transform->get_scale();
2028  const LVecBase3 &orig_shear = transform->get_shear();
2029 
2030  set_transform(other, TransformState::make_pos_quat_scale_shear
2031  (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
2032  transform = get_transform();
2033  if (transform->has_components()) {
2034  set_pos_quat_scale_shear(transform->get_pos(), transform->get_quat(),
2035  orig_scale, orig_shear);
2036  }
2037 
2038  } else {
2039  // If we didn't have a componentwise transform already, never
2040  // mind.
2041  set_transform(other, TransformState::make_pos_quat_scale_shear
2042  (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
2044  }
2045 }
2046 
2047 ////////////////////////////////////////////////////////////////////
2048 // Function: NodePath::set_hpr_scale
2049 // Access: Published
2050 // Description: Sets the rotation and scale components of the
2051 // transform, leaving translation untouched. This, or
2052 // set_pos_hpr_scale, is the preferred way to update a
2053 // transform when both hpr and scale are to be changed.
2054 ////////////////////////////////////////////////////////////////////
2055 void NodePath::
2056 set_hpr_scale(const NodePath &other, const LVecBase3 &hpr, const LVecBase3 &scale) {
2057  // We don't bother trying very hard to preserve pos across this
2058  // operation, unlike the work we do above to preserve hpr or scale,
2059  // since it generally doesn't matter that much if pos is off by a
2060  // few thousandths.
2061  nassertv_always(!is_empty());
2062  CPT(TransformState) transform = get_transform(other);
2063  transform = TransformState::make_pos_hpr_scale_shear
2064  (transform->get_pos(), hpr, scale, transform->get_shear());
2065  set_transform(other, transform);
2066 }
2067 
2068 ////////////////////////////////////////////////////////////////////
2069 // Function: NodePath::set_quat_scale
2070 // Access: Published
2071 // Description: Sets the rotation and scale components of the
2072 // transform, leaving translation untouched. This, or
2073 // set_pos_quat_scale, is the preferred way to update a
2074 // transform when both quat and scale are to be changed.
2075 ////////////////////////////////////////////////////////////////////
2076 void NodePath::
2077 set_quat_scale(const NodePath &other, const LQuaternion &quat,
2078  const LVecBase3 &scale) {
2079  // We don't bother trying very hard to preserve pos across this
2080  // operation, unlike the work we do above to preserve quat or scale,
2081  // since it generally doesn't matter that much if pos is off by a
2082  // few thousandths.
2083  nassertv_always(!is_empty());
2084  CPT(TransformState) transform = get_transform(other);
2085  transform = TransformState::make_pos_quat_scale_shear
2086  (transform->get_pos(), quat, scale, transform->get_shear());
2087  set_transform(other, transform);
2088 }
2089 
2090 ////////////////////////////////////////////////////////////////////
2091 // Function: NodePath::set_pos_hpr_scale
2092 // Access: Published
2093 // Description: Completely replaces the transform with new
2094 // translation, rotation, and scale components, relative
2095 // to the other node, implicitly setting shear to 0.
2096 ////////////////////////////////////////////////////////////////////
2097 void NodePath::
2099  const LVecBase3 &pos, const LVecBase3 &hpr,
2100  const LVecBase3 &scale) {
2101  nassertv_always(!is_empty());
2102  set_transform(other, TransformState::make_pos_hpr_scale
2103  (pos, hpr, scale));
2105 }
2106 
2107 ////////////////////////////////////////////////////////////////////
2108 // Function: NodePath::set_pos_quat_scale
2109 // Access: Published
2110 // Description: Completely replaces the transform with new
2111 // translation, rotation, and scale components, relative
2112 // to the other node, implicitly setting shear to 0.
2113 ////////////////////////////////////////////////////////////////////
2114 void NodePath::
2116  const LVecBase3 &pos, const LQuaternion &quat,
2117  const LVecBase3 &scale) {
2118  nassertv_always(!is_empty());
2119  set_transform(other, TransformState::make_pos_quat_scale
2120  (pos, quat, scale));
2122 }
2123 
2124 ////////////////////////////////////////////////////////////////////
2125 // Function: NodePath::set_pos_hpr_scale_shear
2126 // Access: Published
2127 // Description: Completely replaces the transform with new
2128 // translation, rotation, scale, and shear components,
2129 // relative to the other node.
2130 ////////////////////////////////////////////////////////////////////
2131 void NodePath::
2133  const LVecBase3 &pos, const LVecBase3 &hpr,
2134  const LVecBase3 &scale, const LVecBase3 &shear) {
2135  nassertv_always(!is_empty());
2136  set_transform(other, TransformState::make_pos_hpr_scale_shear
2137  (pos, hpr, scale, shear));
2139 }
2140 
2141 ////////////////////////////////////////////////////////////////////
2142 // Function: NodePath::set_pos_quat_scale_shear
2143 // Access: Published
2144 // Description: Completely replaces the transform with new
2145 // translation, rotation, scale, and shear components,
2146 // relative to the other node.
2147 ////////////////////////////////////////////////////////////////////
2148 void NodePath::
2150  const LVecBase3 &pos, const LQuaternion &quat,
2151  const LVecBase3 &scale, const LVecBase3 &shear) {
2152  nassertv_always(!is_empty());
2153  set_transform(other, TransformState::make_pos_quat_scale_shear
2154  (pos, quat, scale, shear));
2156 }
2157 
2158 ////////////////////////////////////////////////////////////////////
2159 // Function: NodePath::get_mat
2160 // Access: Published
2161 // Description: Returns the matrix that describes the coordinate
2162 // space of the bottom node, relative to the other
2163 // path's bottom node's coordinate space.
2164 ////////////////////////////////////////////////////////////////////
2166 get_mat(const NodePath &other) const {
2167  CPT(TransformState) transform = get_transform(other);
2168  // We can't safely return a reference to the matrix, because we
2169  // can't assume the transform won't go away when the function
2170  // returns. If the transform was partially modified by, say, a
2171  // CompassEffect, it won't be stored in the cache, and thus we might
2172  // have the only reference to it.
2173  return transform->get_mat();
2174 }
2175 
2176 ////////////////////////////////////////////////////////////////////
2177 // Function: NodePath::set_mat
2178 // Access: Published
2179 // Description: Converts the indicated matrix from the other's
2180 // coordinate space to the local coordinate space, and
2181 // applies it to the node.
2182 ////////////////////////////////////////////////////////////////////
2183 void NodePath::
2184 set_mat(const NodePath &other, const LMatrix4 &mat) {
2185  nassertv_always(!is_empty());
2186  set_transform(other, TransformState::make_mat(mat));
2188 }
2189 
2190 ////////////////////////////////////////////////////////////////////
2191 // Function: NodePath::get_relative_point
2192 // Access: Published
2193 // Description: Given that the indicated point is in the coordinate
2194 // system of the other node, returns the same point in
2195 // this node's coordinate system.
2196 ////////////////////////////////////////////////////////////////////
2198 get_relative_point(const NodePath &other, const LVecBase3 &point) const {
2199  CPT(TransformState) transform = other.get_transform(*this);
2200  LPoint3 rel_point = LPoint3(point) * transform->get_mat();
2201  return rel_point;
2202 }
2203 
2204 ////////////////////////////////////////////////////////////////////
2205 // Function: NodePath::get_relative_vector
2206 // Access: Published
2207 // Description: Given that the indicated vector is in the coordinate
2208 // system of the other node, returns the same vector in
2209 // this node's coordinate system.
2210 ////////////////////////////////////////////////////////////////////
2212 get_relative_vector(const NodePath &other, const LVecBase3 &vec) const {
2213  CPT(TransformState) transform = other.get_transform(*this);
2214  LVector3 rel_vector = LVector3(vec) * transform->get_mat();
2215  return rel_vector;
2216 }
2217 
2218 ////////////////////////////////////////////////////////////////////
2219 // Function: NodePath::look_at
2220 // Access: Published
2221 // Description: Sets the transform on this NodePath so that it
2222 // rotates to face the indicated point in space, which
2223 // is relative to the other NodePath.
2224 ////////////////////////////////////////////////////////////////////
2225 void NodePath::
2226 look_at(const NodePath &other, const LPoint3 &point, const LVector3 &up) {
2227  nassertv_always(!is_empty());
2228 
2229  CPT(TransformState) transform = other.get_transform(get_parent());
2230  LPoint3 rel_point = point * transform->get_mat();
2231 
2232  LPoint3 pos = get_pos();
2233 
2234  LQuaternion quat;
2235  ::look_at(quat, rel_point - pos, up);
2236  set_quat(quat);
2237 }
2238 
2239 ////////////////////////////////////////////////////////////////////
2240 // Function: NodePath::heads_up
2241 // Access: Published
2242 // Description: Behaves like look_at(), but with a strong preference
2243 // to keeping the up vector oriented in the indicated
2244 // "up" direction.
2245 ////////////////////////////////////////////////////////////////////
2246 void NodePath::
2247 heads_up(const NodePath &other, const LPoint3 &point, const LVector3 &up) {
2248  nassertv_always(!is_empty());
2249 
2250  CPT(TransformState) transform = other.get_transform(get_parent());
2251  LPoint3 rel_point = point * transform->get_mat();
2252 
2253  LPoint3 pos = get_pos();
2254 
2255  LQuaternion quat;
2256  ::heads_up(quat, rel_point - pos, up);
2257  set_quat(quat);
2258 }
2259 
2260 
2261 ////////////////////////////////////////////////////////////////////
2262 // Function: NodePath::set_color
2263 // Access: Published
2264 // Description: Applies a scene-graph color to the referenced node.
2265 // This color will apply to all geometry at this level
2266 // and below (that does not specify a new color or a
2267 // set_color_off()).
2268 ////////////////////////////////////////////////////////////////////
2269 void NodePath::
2270 set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a,
2271  int priority) {
2272  set_color(LColor(r, g, b, a), priority);
2273 }
2274 
2275 ////////////////////////////////////////////////////////////////////
2276 // Function: NodePath::set_color
2277 // Access: Published
2278 // Description: Applies a scene-graph color to the referenced node.
2279 // This color will apply to all geometry at this level
2280 // and below (that does not specify a new color or a
2281 // set_color_off()).
2282 ////////////////////////////////////////////////////////////////////
2283 void NodePath::
2284 set_color(const LColor &color, int priority) {
2285  nassertv_always(!is_empty());
2286  node()->set_attrib(ColorAttrib::make_flat(color), priority);
2287 }
2288 
2289 ////////////////////////////////////////////////////////////////////
2290 // Function: NodePath::set_color_off
2291 // Access: Published
2292 // Description: Sets the geometry at this level and below to render
2293 // using the geometry color. This is normally the
2294 // default, but it may be useful to use this to
2295 // contradict set_color() at a higher node level (or,
2296 // with a priority, to override a set_color() at a lower
2297 // level).
2298 ////////////////////////////////////////////////////////////////////
2299 void NodePath::
2300 set_color_off(int priority) {
2301  nassertv_always(!is_empty());
2302  node()->set_attrib(ColorAttrib::make_vertex(), priority);
2303 }
2304 
2305 ////////////////////////////////////////////////////////////////////
2306 // Function: NodePath::clear_color
2307 // Access: Published
2308 // Description: Completely removes any color adjustment from the node.
2309 // This allows the natural color of the geometry, or
2310 // whatever color transitions might be otherwise
2311 // affecting the geometry, to show instead.
2312 ////////////////////////////////////////////////////////////////////
2313 void NodePath::
2315  nassertv_always(!is_empty());
2316  node()->clear_attrib(ColorAttrib::get_class_slot());
2317 }
2318 
2319 ////////////////////////////////////////////////////////////////////
2320 // Function: NodePath::has_color
2321 // Access: Published
2322 // Description: Returns true if a color has been applied to the given
2323 // node, false otherwise.
2324 ////////////////////////////////////////////////////////////////////
2325 bool NodePath::
2326 has_color() const {
2327  nassertr_always(!is_empty(), false);
2328  return node()->has_attrib(ColorAttrib::get_class_slot());
2329 }
2330 
2331 ////////////////////////////////////////////////////////////////////
2332 // Function: NodePath::get_color
2333 // Access: Published
2334 // Description: Returns the color that has been assigned to the node,
2335 // or black if no color has been assigned.
2336 ////////////////////////////////////////////////////////////////////
2338 get_color() const {
2339  nassertr_always(!is_empty(), false);
2340  const RenderAttrib *attrib =
2341  node()->get_attrib(ColorAttrib::get_class_slot());
2342  if (attrib != (const RenderAttrib *)NULL) {
2343  const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
2344  if (ca->get_color_type() == ColorAttrib::T_flat) {
2345  return ca->get_color();
2346  }
2347  }
2348 
2349  pgraph_cat.warning()
2350  << "get_color() called on " << *this << " which has no color set.\n";
2351 
2352  return LColor(1.0f, 1.0f, 1.0f, 1.0f);
2353 }
2354 
2355 ////////////////////////////////////////////////////////////////////
2356 // Function: NodePath::has_color_scale
2357 // Access: Published
2358 // Description: Returns true if a color scale has been applied
2359 // to the referenced node, false otherwise. It is still
2360 // possible that color at this node might have been
2361 // scaled by an ancestor node.
2362 ////////////////////////////////////////////////////////////////////
2363 bool NodePath::
2365  nassertr_always(!is_empty(), false);
2366  return node()->has_attrib(ColorScaleAttrib::get_class_slot());
2367 }
2368 
2369 ////////////////////////////////////////////////////////////////////
2370 // Function: NodePath::clear_color_scale
2371 // Access: Published
2372 // Description: Completely removes any color scale from the
2373 // referenced node. This is preferable to simply
2374 // setting the color scale to identity, as it also
2375 // removes the overhead associated with having a color
2376 // scale at all.
2377 ////////////////////////////////////////////////////////////////////
2378 void NodePath::
2380  nassertv_always(!is_empty());
2381  node()->clear_attrib(ColorScaleAttrib::get_class_slot());
2382 }
2383 
2384 ////////////////////////////////////////////////////////////////////
2385 // Function: NodePath::compose_color_scale
2386 // Access: Published
2387 // Description: multiplies the color scale component of the transform,
2388 // with previous color scale leaving translation and
2389 // rotation untouched.
2390 ////////////////////////////////////////////////////////////////////
2391 void NodePath::
2392 compose_color_scale(const LVecBase4 &scale, int priority) {
2393  nassertv_always(!is_empty());
2394 
2395  const RenderAttrib *attrib =
2396  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2397  if (attrib != (const RenderAttrib *)NULL) {
2398  priority = max(priority,
2399  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2400  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2401 
2402  // Modify the existing ColorScaleAttrib by multiplying with the
2403  // indicated colorScale.
2404  LVecBase4 prev_color_scale = csa->get_scale();
2405  LVecBase4 new_color_scale(prev_color_scale[0]*scale[0],
2406  prev_color_scale[1]*scale[1],
2407  prev_color_scale[2]*scale[2],
2408  prev_color_scale[3]*scale[3]);
2409  node()->set_attrib(csa->set_scale(new_color_scale), priority);
2410 
2411  } else {
2412  // Create a new ColorScaleAttrib for this node.
2413  node()->set_attrib(ColorScaleAttrib::make(scale), priority);
2414  }
2415 }
2416 
2417 ////////////////////////////////////////////////////////////////////
2418 // Function: NodePath::set_color_scale
2419 // Access: Published
2420 // Description: Sets the color scale component of the transform,
2421 // leaving translation and rotation untouched.
2422 ////////////////////////////////////////////////////////////////////
2423 void NodePath::
2424 set_color_scale(const LVecBase4 &scale, int priority) {
2425  nassertv_always(!is_empty());
2426 
2427  const RenderAttrib *attrib =
2428  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2429  if (attrib != (const RenderAttrib *)NULL) {
2430  priority = max(priority,
2431  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2432  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2433 
2434  // Modify the existing ColorScaleAttrib to add the indicated
2435  // colorScale.
2436  node()->set_attrib(csa->set_scale(scale), priority);
2437 
2438  } else {
2439  // Create a new ColorScaleAttrib for this node.
2440  node()->set_attrib(ColorScaleAttrib::make(scale), priority);
2441  }
2442 }
2443 
2444 ////////////////////////////////////////////////////////////////////
2445 // Function: NodePath::set_color_scale_off
2446 // Access: Published
2447 // Description: Disables any color scale attribute inherited from
2448 // above. This is not the same thing as
2449 // clear_color_scale(), which undoes any previous
2450 // set_color_scale() operation on this node; rather,
2451 // this actively disables any set_color_scale() that
2452 // might be inherited from a parent node. This also
2453 // disables set_alpha_scale() at the same time.
2454 //
2455 // It is legal to specify a new color scale on the same
2456 // node with a subsequent call to set_color_scale() or
2457 // set_alpha_scale(); this new scale will apply to lower
2458 // geometry.
2459 ////////////////////////////////////////////////////////////////////
2460 void NodePath::
2461 set_color_scale_off(int priority) {
2462  nassertv_always(!is_empty());
2463  node()->set_attrib(ColorScaleAttrib::make_off(), priority);
2464 }
2465 
2466 ////////////////////////////////////////////////////////////////////
2467 // Function: NodePath::set_alpha_scale
2468 // Access: Published
2469 // Description: Sets the alpha scale component of the transform
2470 // without (much) affecting the color scale. Note that
2471 // any priority specified will also apply to the color
2472 // scale.
2473 ////////////////////////////////////////////////////////////////////
2474 void NodePath::
2475 set_alpha_scale(PN_stdfloat scale, int priority) {
2476  nassertv_always(!is_empty());
2477 
2478  const RenderAttrib *attrib =
2479  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2480  if (attrib != (const RenderAttrib *)NULL) {
2481  priority = max(priority,
2482  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2483  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2484 
2485  // Modify the existing ColorScaleAttrib to add the indicated
2486  // colorScale.
2487  const LVecBase4 &sc = csa->get_scale();
2488  node()->set_attrib(csa->set_scale(LVecBase4(sc[0], sc[1], sc[2], scale)), priority);
2489 
2490  } else {
2491  // Create a new ColorScaleAttrib for this node.
2492  node()->set_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, scale)), priority);
2493  }
2494 }
2495 
2496 ////////////////////////////////////////////////////////////////////
2497 // Function: NodePath::set_all_color_scale
2498 // Access: Published
2499 // Description: Scales all the color components of the object by the
2500 // same amount, darkening the object, without (much)
2501 // affecting alpha. Note that any priority specified
2502 // will also apply to the alpha scale.
2503 ////////////////////////////////////////////////////////////////////
2504 void NodePath::
2505 set_all_color_scale(PN_stdfloat scale, int priority) {
2506  nassertv_always(!is_empty());
2507 
2508  const RenderAttrib *attrib =
2509  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2510  if (attrib != (const RenderAttrib *)NULL) {
2511  priority = max(priority,
2512  node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
2513  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2514 
2515  // Modify the existing ColorScaleAttrib to add the indicated
2516  // colorScale.
2517  const LVecBase4 &sc = csa->get_scale();
2518  node()->set_attrib(csa->set_scale(LVecBase4(scale, scale, scale, sc[3])), priority);
2519 
2520  } else {
2521  // Create a new ColorScaleAttrib for this node.
2522  node()->set_attrib(ColorScaleAttrib::make(LVecBase4(scale, scale, scale, 1.0f)), priority);
2523  }
2524 }
2525 
2526 ////////////////////////////////////////////////////////////////////
2527 // Function: NodePath::get_color_scale
2528 // Access: Published
2529 // Description: Returns the complete color scale vector that has been
2530 // applied to this node via a previous call to
2531 // set_color_scale() and/or set_alpha_scale(), or all
2532 // 1's (identity) if no scale has been applied to this
2533 // particular node.
2534 ////////////////////////////////////////////////////////////////////
2535 const LVecBase4 &NodePath::
2537  static const LVecBase4 ident_scale(1.0f, 1.0f, 1.0f, 1.0f);
2538  nassertr_always(!is_empty(), ident_scale);
2539  const RenderAttrib *attrib =
2540  node()->get_attrib(ColorScaleAttrib::get_class_slot());
2541  if (attrib != (const RenderAttrib *)NULL) {
2542  const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
2543  return csa->get_scale();
2544  }
2545 
2546  return ident_scale;
2547 }
2548 
2549 ////////////////////////////////////////////////////////////////////
2550 // Function: NodePath::set_light
2551 // Access: Published
2552 // Description: Adds the indicated Light or PolylightNode to the list
2553 // of lights that illuminate geometry at this node and
2554 // below. The light itself should be parented into the
2555 // scene graph elsewhere, to represent the light's
2556 // position in space; but until set_light() is called it
2557 // will illuminate no geometry.
2558 ////////////////////////////////////////////////////////////////////
2559 void NodePath::
2560 set_light(const NodePath &light, int priority) {
2561  nassertv_always(!is_empty());
2562  if (!light.is_empty()) {
2563  Light *light_obj = light.node()->as_light();
2564  if (light_obj != (Light *)NULL) {
2565  // It's an actual Light object.
2566  const RenderAttrib *attrib =
2567  node()->get_attrib(LightAttrib::get_class_slot());
2568  if (attrib != (const RenderAttrib *)NULL) {
2569  priority = max(priority,
2570  node()->get_state()->get_override(LightAttrib::get_class_slot()));
2571  const LightAttrib *la = DCAST(LightAttrib, attrib);
2572 
2573  // Modify the existing LightAttrib to add the indicated
2574  // light.
2575  node()->set_attrib(la->add_on_light(light), priority);
2576 
2577  } else {
2578  // Create a new LightAttrib for this node.
2579  CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
2580  node()->set_attrib(la->add_on_light(light), priority);
2581  }
2582  return;
2583 
2584  } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
2585  // It's a Polylight object.
2586  if (priority != 0) {
2587  // PolylightEffects can't have a priority, since they're just
2588  // an effect to be applied immediately.
2589  pgraph_cat.warning()
2590  << "Ignoring priority on set_light(" << light << ")\n";
2591  }
2592 
2593  const RenderEffect *effect =
2594  node()->get_effect(PolylightEffect::get_class_type());
2595  if (effect != (const RenderEffect *)NULL) {
2596  const PolylightEffect *ple = DCAST(PolylightEffect, effect);
2597 
2598  // Modify the existing PolylightEffect to add the indicated
2599  // light.
2600  node()->set_effect(ple->add_light(light));
2601 
2602  } else {
2603  // Create a new PolylightEffect for this node.
2604  CPT(PolylightEffect) ple = DCAST(PolylightEffect, PolylightEffect::make());
2605  node()->set_effect(ple->add_light(light));
2606  }
2607  return;
2608  }
2609  }
2610  nassert_raise("Not a Light object.");
2611 }
2612 
2613 ////////////////////////////////////////////////////////////////////
2614 // Function: NodePath::set_light_off
2615 // Access: Published
2616 // Description: Sets the geometry at this level and below to render
2617 // using no lights at all. This is different
2618 // from not specifying a light; rather, this
2619 // specifically contradicts set_light() at a higher
2620 // node level (or, with a priority, overrides a
2621 // set_light() at a lower level).
2622 //
2623 // If no lights are in effect on a particular piece of
2624 // geometry, that geometry is rendered with lighting
2625 // disabled.
2626 ////////////////////////////////////////////////////////////////////
2627 void NodePath::
2628 set_light_off(int priority) {
2629  nassertv_always(!is_empty());
2630  node()->set_attrib(LightAttrib::make_all_off(), priority);
2631  node()->clear_effect(PolylightEffect::get_class_type());
2632 }
2633 
2634 ////////////////////////////////////////////////////////////////////
2635 // Function: NodePath::set_light_off
2636 // Access: Published
2637 // Description: Sets the geometry at this level and below to render
2638 // without using the indicated Light. This is different
2639 // from not specifying the Light; rather, this
2640 // specifically contradicts set_light() at a higher node
2641 // level (or, with a priority, overrides a set_light()
2642 // at a lower level).
2643 //
2644 // This interface does not support PolylightNodes, which
2645 // cannot be turned off at a lower level.
2646 ////////////////////////////////////////////////////////////////////
2647 void NodePath::
2648 set_light_off(const NodePath &light, int priority) {
2649  nassertv_always(!is_empty());
2650 
2651  if (!light.is_empty()) {
2652  Light *light_obj = light.node()->as_light();
2653  if (light_obj != (Light *)NULL) {
2654  const RenderAttrib *attrib =
2655  node()->get_attrib(LightAttrib::get_class_slot());
2656  if (attrib != (const RenderAttrib *)NULL) {
2657  priority = max(priority,
2658  node()->get_state()->get_override(LightAttrib::get_class_slot()));
2659  const LightAttrib *la = DCAST(LightAttrib, attrib);
2660 
2661  // Modify the existing LightAttrib to add the indicated light
2662  // to the "off" list. This also, incidentally, removes it from
2663  // the "on" list if it is there.
2664  node()->set_attrib(la->add_off_light(light), priority);
2665 
2666  } else {
2667  // Create a new LightAttrib for this node that turns off the
2668  // indicated light.
2669  CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
2670  node()->set_attrib(la->add_off_light(light), priority);
2671  }
2672  return;
2673  }
2674  }
2675  nassert_raise("Not a Light object.");
2676 }
2677 
2678 ////////////////////////////////////////////////////////////////////
2679 // Function: NodePath::clear_light
2680 // Access: Published
2681 // Description: Completely removes any lighting operations that may
2682 // have been set via set_light() or set_light_off()
2683 // from this particular node.
2684 ////////////////////////////////////////////////////////////////////
2685 void NodePath::
2687  nassertv_always(!is_empty());
2688  node()->clear_attrib(LightAttrib::get_class_slot());
2689  node()->clear_effect(PolylightEffect::get_class_type());
2690 }
2691 
2692 ////////////////////////////////////////////////////////////////////
2693 // Function: NodePath::clear_light
2694 // Access: Published
2695 // Description: Removes any reference to the indicated Light or
2696 // PolylightNode from the NodePath.
2697 ////////////////////////////////////////////////////////////////////
2698 void NodePath::
2699 clear_light(const NodePath &light) {
2700  nassertv_always(!is_empty());
2701 
2702  if (!light.is_empty()) {
2703  Light *light_obj = light.node()->as_light();
2704  if (light_obj != (Light *)NULL) {
2705  const RenderAttrib *attrib =
2706  node()->get_attrib(LightAttrib::get_class_slot());
2707  if (attrib != (const RenderAttrib *)NULL) {
2708  CPT(LightAttrib) la = DCAST(LightAttrib, attrib);
2709  la = DCAST(LightAttrib, la->remove_on_light(light));
2710  la = DCAST(LightAttrib, la->remove_off_light(light));
2711 
2712  if (la->is_identity()) {
2713  node()->clear_attrib(LightAttrib::get_class_slot());
2714 
2715  } else {
2716  int priority = node()->get_state()->get_override(LightAttrib::get_class_slot());
2717  node()->set_attrib(la, priority);
2718  }
2719  }
2720  return;
2721 
2722  } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
2723  const RenderEffect *effect =
2724  node()->get_effect(PolylightEffect::get_class_type());
2725  if (effect != (const RenderEffect *)NULL) {
2726  CPT(PolylightEffect) ple = DCAST(PolylightEffect, effect);
2727  ple = DCAST(PolylightEffect, ple->remove_light(light));
2728  node()->set_effect(ple);
2729  }
2730  return;
2731  }
2732  }
2733  nassert_raise("Not a Light object.");
2734 }
2735 
2736 ////////////////////////////////////////////////////////////////////
2737 // Function: NodePath::has_light
2738 // Access: Published
2739 // Description: Returns true if the indicated Light or PolylightNode
2740 // has been specifically enabled on this particular
2741 // node. This means that someone called set_light() on
2742 // this node with the indicated light.
2743 ////////////////////////////////////////////////////////////////////
2744 bool NodePath::
2745 has_light(const NodePath &light) const {
2746  nassertr_always(!is_empty(), false);
2747 
2748  if (!light.is_empty()) {
2749  Light *light_obj = light.node()->as_light();
2750  if (light_obj != (Light *)NULL) {
2751  const RenderAttrib *attrib =
2752  node()->get_attrib(LightAttrib::get_class_slot());
2753  if (attrib != (const RenderAttrib *)NULL) {
2754  const LightAttrib *la = DCAST(LightAttrib, attrib);
2755  return la->has_on_light(light);
2756  }
2757  return false;
2758 
2759  } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
2760  const RenderEffect *effect =
2761  node()->get_effect(PolylightEffect::get_class_type());
2762  if (effect != (const RenderEffect *)NULL) {
2763  const PolylightEffect *ple = DCAST(PolylightEffect, effect);
2764  return ple->has_light(light);
2765  }
2766  return false;
2767  }
2768  }
2769  nassert_raise("Not a Light object.");
2770  return false;
2771 }
2772 
2773 ////////////////////////////////////////////////////////////////////
2774 // Function: NodePath::has_light_off
2775 // Access: Published
2776 // Description: Returns true if all Lights have been specifically
2777 // disabled on this particular node. This means that
2778 // someone called set_light_off() on this node with no
2779 // parameters.
2780 ////////////////////////////////////////////////////////////////////
2781 bool NodePath::
2782 has_light_off() const {
2783  nassertr_always(!is_empty(), false);
2784 
2785  const RenderAttrib *attrib =
2786  node()->get_attrib(LightAttrib::get_class_slot());
2787  if (attrib != (const RenderAttrib *)NULL) {
2788  const LightAttrib *la = DCAST(LightAttrib, attrib);
2789  return la->has_all_off();
2790  }
2791 
2792  return false;
2793 }
2794 
2795 ////////////////////////////////////////////////////////////////////
2796 // Function: NodePath::has_light_off
2797 // Access: Published
2798 // Description: Returns true if the indicated Light has been
2799 // specifically disabled on this particular node. This
2800 // means that someone called set_light_off() on this
2801 // node with the indicated light.
2802 //
2803 // This interface does not support PolylightNodes, which
2804 // cannot be turned off at a lower level.
2805 ////////////////////////////////////////////////////////////////////
2806 bool NodePath::
2807 has_light_off(const NodePath &light) const {
2808  nassertr_always(!is_empty(), false);
2809  if (!light.is_empty()) {
2810  Light *light_obj = light.node()->as_light();
2811  if (light_obj != (Light *)NULL) {
2812  const RenderAttrib *attrib =
2813  node()->get_attrib(LightAttrib::get_class_slot());
2814  if (attrib != (const RenderAttrib *)NULL) {
2815  const LightAttrib *la = DCAST(LightAttrib, attrib);
2816  return la->has_off_light(light);
2817  }
2818  }
2819  }
2820  nassert_raise("Not a Light object.");
2821  return false;
2822 }
2823 
2824 ////////////////////////////////////////////////////////////////////
2825 // Function: NodePath::set_clip_plane
2826 // Access: Published
2827 // Description: Adds the indicated clipping plane to the list of
2828 // planes that apply to geometry at this node and below.
2829 // The clipping plane itself, a PlaneNode, should be
2830 // parented into the scene graph elsewhere, to represent
2831 // the plane's position in space; but until
2832 // set_clip_plane() is called it will clip no geometry.
2833 ////////////////////////////////////////////////////////////////////
2834 void NodePath::
2835 set_clip_plane(const NodePath &clip_plane, int priority) {
2836  nassertv_always(!is_empty());
2837  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2838  const RenderAttrib *attrib =
2839  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2840  if (attrib != (const RenderAttrib *)NULL) {
2841  priority = max(priority,
2842  node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()));
2843  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2844 
2845  // Modify the existing ClipPlaneAttrib to add the indicated
2846  // clip_plane.
2847  node()->set_attrib(la->add_on_plane(clip_plane), priority);
2848 
2849  } else {
2850  // Create a new ClipPlaneAttrib for this node.
2851  CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
2852  node()->set_attrib(la->add_on_plane(clip_plane), priority);
2853  }
2854  return;
2855  }
2856  nassert_raise("Not a PlaneNode object.");
2857 }
2858 
2859 ////////////////////////////////////////////////////////////////////
2860 // Function: NodePath::set_clip_plane_off
2861 // Access: Published
2862 // Description: Sets the geometry at this level and below to render
2863 // using no clip_planes at all. This is different
2864 // from not specifying a clip_plane; rather, this
2865 // specifically contradicts set_clip_plane() at a higher
2866 // node level (or, with a priority, overrides a
2867 // set_clip_plane() at a lower level).
2868 //
2869 // If no clip_planes are in effect on a particular piece
2870 // of geometry, that geometry is rendered without being
2871 // clipped (other than by the viewing frustum).
2872 ////////////////////////////////////////////////////////////////////
2873 void NodePath::
2874 set_clip_plane_off(int priority) {
2875  nassertv_always(!is_empty());
2876  node()->set_attrib(ClipPlaneAttrib::make_all_off(), priority);
2877 }
2878 
2879 ////////////////////////////////////////////////////////////////////
2880 // Function: NodePath::set_clip_plane_off
2881 // Access: Published
2882 // Description: Sets the geometry at this level and below to render
2883 // without being clipped by the indicated PlaneNode.
2884 // This is different from not specifying the PlaneNode;
2885 // rather, this specifically contradicts
2886 // set_clip_plane() at a higher node level (or, with a
2887 // priority, overrides a set_clip_plane() at a lower
2888 // level).
2889 ////////////////////////////////////////////////////////////////////
2890 void NodePath::
2891 set_clip_plane_off(const NodePath &clip_plane, int priority) {
2892  nassertv_always(!is_empty());
2893 
2894  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2895  const RenderAttrib *attrib =
2896  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2897  if (attrib != (const RenderAttrib *)NULL) {
2898  priority = max(priority,
2899  node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()));
2900  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2901 
2902  // Modify the existing ClipPlaneAttrib to add the indicated clip_plane
2903  // to the "off" list. This also, incidentally, removes it from
2904  // the "on" list if it is there.
2905  node()->set_attrib(la->add_off_plane(clip_plane), priority);
2906 
2907  } else {
2908  // Create a new ClipPlaneAttrib for this node that turns off the
2909  // indicated clip_plane.
2910  CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
2911  node()->set_attrib(la->add_off_plane(clip_plane), priority);
2912  }
2913  return;
2914  }
2915  nassert_raise("Not a PlaneNode object.");
2916 }
2917 
2918 ////////////////////////////////////////////////////////////////////
2919 // Function: NodePath::clear_clip_plane
2920 // Access: Published
2921 // Description: Completely removes any clip planes that may have been
2922 // set via set_clip_plane() or set_clip_plane_off() from
2923 // this particular node.
2924 ////////////////////////////////////////////////////////////////////
2925 void NodePath::
2927  nassertv_always(!is_empty());
2928  node()->clear_attrib(ClipPlaneAttrib::get_class_slot());
2929 }
2930 
2931 ////////////////////////////////////////////////////////////////////
2932 // Function: NodePath::clear_clip_plane
2933 // Access: Published
2934 // Description: Removes any reference to the indicated clipping plane
2935 // from the NodePath.
2936 ////////////////////////////////////////////////////////////////////
2937 void NodePath::
2938 clear_clip_plane(const NodePath &clip_plane) {
2939  nassertv_always(!is_empty());
2940 
2941  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2942  const RenderAttrib *attrib =
2943  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2944  if (attrib != (const RenderAttrib *)NULL) {
2945  CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib);
2946  la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane));
2947  la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane));
2948 
2949  if (la->is_identity()) {
2950  node()->clear_attrib(ClipPlaneAttrib::get_class_slot());
2951 
2952  } else {
2953  int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot());
2954  node()->set_attrib(la, priority);
2955  }
2956  }
2957  return;
2958  }
2959  nassert_raise("Not a PlaneNode object.");
2960 }
2961 
2962 ////////////////////////////////////////////////////////////////////
2963 // Function: NodePath::has_clip_plane
2964 // Access: Published
2965 // Description: Returns true if the indicated clipping plane has been
2966 // specifically applied to this particular node. This
2967 // means that someone called set_clip_plane() on this
2968 // node with the indicated clip_plane.
2969 ////////////////////////////////////////////////////////////////////
2970 bool NodePath::
2971 has_clip_plane(const NodePath &clip_plane) const {
2972  nassertr_always(!is_empty(), false);
2973 
2974  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
2975  const RenderAttrib *attrib =
2976  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
2977  if (attrib != (const RenderAttrib *)NULL) {
2978  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
2979  return la->has_on_plane(clip_plane);
2980  }
2981  return false;
2982  }
2983  nassert_raise("Not a PlaneNode object.");
2984  return false;
2985 }
2986 
2987 ////////////////////////////////////////////////////////////////////
2988 // Function: NodePath::has_clip_plane_off
2989 // Access: Published
2990 // Description: Returns true if all clipping planes have been
2991 // specifically disabled on this particular node. This
2992 // means that someone called set_clip_plane_off() on
2993 // this node with no parameters.
2994 ////////////////////////////////////////////////////////////////////
2995 bool NodePath::
2997  nassertr_always(!is_empty(), false);
2998 
2999  const RenderAttrib *attrib =
3000  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
3001  if (attrib != (const RenderAttrib *)NULL) {
3002  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
3003  return la->has_all_off();
3004  }
3005 
3006  return false;
3007 }
3008 
3009 ////////////////////////////////////////////////////////////////////
3010 // Function: NodePath::has_clip_plane_off
3011 // Access: Published
3012 // Description: Returns true if the indicated clipping plane has been
3013 // specifically disabled on this particular node. This
3014 // means that someone called set_clip_plane_off() on
3015 // this node with the indicated clip_plane.
3016 ////////////////////////////////////////////////////////////////////
3017 bool NodePath::
3018 has_clip_plane_off(const NodePath &clip_plane) const {
3019  nassertr_always(!is_empty(), false);
3020  if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
3021  const RenderAttrib *attrib =
3022  node()->get_attrib(ClipPlaneAttrib::get_class_slot());
3023  if (attrib != (const RenderAttrib *)NULL) {
3024  const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
3025  return la->has_off_plane(clip_plane);
3026  }
3027  }
3028  nassert_raise("Not a PlaneNode object.");
3029  return false;
3030 }
3031 
3032 ////////////////////////////////////////////////////////////////////
3033 // Function: NodePath::set_occluder
3034 // Access: Published
3035 // Description: Adds the indicated occluder to the list of
3036 // occluders that apply to geometry at this node and below.
3037 // The occluder itself, an OccluderNode, should be
3038 // parented into the scene graph elsewhere, to represent
3039 // the occluder's position in space; but until
3040 // set_occluder() is called it will clip no geometry.
3041 ////////////////////////////////////////////////////////////////////
3042 void NodePath::
3043 set_occluder(const NodePath &occluder) {
3044  nassertv_always(!is_empty());
3045  if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
3046  const RenderEffect *effect =
3047  node()->get_effect(OccluderEffect::get_class_type());
3048  if (effect != (const RenderEffect *)NULL) {
3049  const OccluderEffect *la = DCAST(OccluderEffect, effect);
3050 
3051  // Modify the existing OccluderEffect to add the indicated
3052  // occluder.
3053  node()->set_effect(la->add_on_occluder(occluder));
3054 
3055  } else {
3056  // Create a new OccluderEffect for this node.
3057  CPT(OccluderEffect) la = DCAST(OccluderEffect, OccluderEffect::make());
3058  node()->set_effect(la->add_on_occluder(occluder));
3059  }
3060  return;
3061  }
3062  nassert_raise("Not an OccluderNode object.");
3063 }
3064 
3065 ////////////////////////////////////////////////////////////////////
3066 // Function: NodePath::clear_occluder
3067 // Access: Published
3068 // Description: Completely removes any occluders that may have been
3069 // set via set_occluder() from this particular node.
3070 ////////////////////////////////////////////////////////////////////
3071 void NodePath::
3073  nassertv_always(!is_empty());
3074  node()->clear_effect(OccluderEffect::get_class_type());
3075 }
3076 
3077 ////////////////////////////////////////////////////////////////////
3078 // Function: NodePath::clear_occluder
3079 // Access: Published
3080 // Description: Removes any reference to the indicated occluder
3081 // from the NodePath.
3082 ////////////////////////////////////////////////////////////////////
3083 void NodePath::
3084 clear_occluder(const NodePath &occluder) {
3085  nassertv_always(!is_empty());
3086 
3087  if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
3088  const RenderEffect *effect =
3089  node()->get_effect(OccluderEffect::get_class_type());
3090  if (effect != (const RenderEffect *)NULL) {
3091  CPT(OccluderEffect) la = DCAST(OccluderEffect, effect);
3092  la = DCAST(OccluderEffect, la->remove_on_occluder(occluder));
3093 
3094  if (la->is_identity()) {
3095  node()->clear_effect(OccluderEffect::get_class_type());
3096 
3097  } else {
3098  node()->set_effect(la);
3099  }
3100  }
3101  return;
3102  }
3103  nassert_raise("Not an OccluderNode object.");
3104 }
3105 
3106 ////////////////////////////////////////////////////////////////////
3107 // Function: NodePath::has_occluder
3108 // Access: Published
3109 // Description: Returns true if the indicated occluder has been
3110 // specifically applied to this particular node. This
3111 // means that someone called set_occluder() on this
3112 // node with the indicated occluder.
3113 ////////////////////////////////////////////////////////////////////
3114 bool NodePath::
3115 has_occluder(const NodePath &occluder) const {
3116  nassertr_always(!is_empty(), false);
3117 
3118  if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
3119  const RenderEffect *effect =
3120  node()->get_effect(OccluderEffect::get_class_type());
3121  if (effect != (const RenderEffect *)NULL) {
3122  const OccluderEffect *la = DCAST(OccluderEffect, effect);
3123  return la->has_on_occluder(occluder);
3124  }
3125  return false;
3126  }
3127  nassert_raise("Not an OccluderNode object.");
3128  return false;
3129 }
3130 
3131 ////////////////////////////////////////////////////////////////////
3132 // Function: NodePath::set_scissor
3133 // Access: Published
3134 // Description: Sets up a scissor region on the nodes rendered at
3135 // this level and below. The four coordinates are
3136 // understood to define a rectangle in screen space.
3137 // These numbers are relative to the current
3138 // DisplayRegion, where (0,0) is the lower-left corner
3139 // of the DisplayRegion, and (1,1) is the upper-right
3140 // corner.
3141 ////////////////////////////////////////////////////////////////////
3142 void NodePath::
3143 set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
3144  set_effect(ScissorEffect::make_screen(LVecBase4(left, right, bottom, top)));
3145 }
3146 
3147 ////////////////////////////////////////////////////////////////////
3148 // Function: NodePath::set_scissor
3149 // Access: Published
3150 // Description: Sets up a scissor region on the nodes rendered at
3151 // this level and below. The two points are understood
3152 // to be relative to this node. When these points are
3153 // projected into screen space, they define the
3154 // diagonally-opposite points that determine the scissor
3155 // region.
3156 ////////////////////////////////////////////////////////////////////
3157 void NodePath::
3158 set_scissor(const LPoint3 &a, const LPoint3 &b) {
3159  set_effect(ScissorEffect::make_node(a, b));
3160 }
3161 
3162 ////////////////////////////////////////////////////////////////////
3163 // Function: NodePath::set_scissor
3164 // Access: Published
3165 // Description: Sets up a scissor region on the nodes rendered at
3166 // this level and below. The four points are understood
3167 // to be relative to this node. When these points are
3168 // projected into screen space, they define the
3169 // bounding volume of the scissor region (the scissor
3170 // region is the smallest onscreen rectangle that
3171 // encloses all four points).
3172 ////////////////////////////////////////////////////////////////////
3173 void NodePath::
3174 set_scissor(const LPoint3 &a, const LPoint3 &b,
3175  const LPoint3 &c, const LPoint3 &d) {
3176  set_effect(ScissorEffect::make_node(a, b, c, d));
3177 }
3178 
3179 ////////////////////////////////////////////////////////////////////
3180 // Function: NodePath::set_scissor
3181 // Access: Published
3182 // Description: Sets up a scissor region on the nodes rendered at
3183 // this level and below. The two points are understood
3184 // to be relative to the indicated other node. When
3185 // these points are projected into screen space, they
3186 // define the diagonally-opposite points that determine
3187 // the scissor region.
3188 ////////////////////////////////////////////////////////////////////
3189 void NodePath::
3190 set_scissor(const NodePath &other, const LPoint3 &a, const LPoint3 &b) {
3191  set_effect(ScissorEffect::make_node(a, b, other));
3192 }
3193 
3194 ////////////////////////////////////////////////////////////////////
3195 // Function: NodePath::set_scissor
3196 // Access: Published
3197 // Description: Sets up a scissor region on the nodes rendered at
3198 // this level and below. The four points are understood
3199 // to be relative to the indicated other node. When
3200 // these points are projected into screen space, they
3201 // define the bounding volume of the scissor region (the
3202 // scissor region is the smallest onscreen rectangle
3203 // that encloses all four points).
3204 ////////////////////////////////////////////////////////////////////
3205 void NodePath::
3206 set_scissor(const NodePath &other,
3207  const LPoint3 &a, const LPoint3 &b,
3208  const LPoint3 &c, const LPoint3 &d) {
3209  set_effect(ScissorEffect::make_node(a, b, c, d, other));
3210 }
3211 
3212 ////////////////////////////////////////////////////////////////////
3213 // Function: NodePath::clear_scissor
3214 // Access: Published
3215 // Description: Removes the scissor region that was defined at this
3216 // node level by a previous call to set_scissor().
3217 ////////////////////////////////////////////////////////////////////
3218 void NodePath::
3220  clear_effect(ScissorEffect::get_class_type());
3221 }
3222 
3223 ////////////////////////////////////////////////////////////////////
3224 // Function: NodePath::has_scissor
3225 // Access: Published
3226 // Description: Returns true if a scissor region was defined at this
3227 // node by a previous call to set_scissor(). This does
3228 // not check for scissor regions inherited from a parent
3229 // class. It also does not check for the presence of a
3230 // low-level ScissorAttrib, which is different from the
3231 // ScissorEffect added by set_scissor.
3232 ////////////////////////////////////////////////////////////////////
3233 bool NodePath::
3234 has_scissor() const {
3235  return has_effect(ScissorEffect::get_class_type());
3236 }
3237 
3238 ////////////////////////////////////////////////////////////////////
3239 // Function: NodePath::set_bin
3240 // Access: Published
3241 // Description: Assigns the geometry at this level and below to the
3242 // named rendering bin. It is the user's responsibility
3243 // to ensure that such a bin already exists, either via
3244 // the cull-bin Configrc variable, or by explicitly
3245 // creating a GeomBin of the appropriate type at
3246 // runtime.
3247 //
3248 // There are two default bins created when Panda is
3249 // started: "default" and "fixed". Normally, all
3250 // geometry is assigned to "default" unless specified
3251 // otherwise. This bin renders opaque geometry in
3252 // state-sorted order, followed by transparent geometry
3253 // sorted back-to-front. If any geometry is assigned to
3254 // "fixed", this will be rendered following all the
3255 // geometry in "default", in the order specified by
3256 // draw_order for each piece of geometry so assigned.
3257 //
3258 // The draw_order parameter is meaningful only for
3259 // GeomBinFixed type bins, e.g. "fixed". Other kinds of
3260 // bins ignore it.
3261 ////////////////////////////////////////////////////////////////////
3262 void NodePath::
3263 set_bin(const string &bin_name, int draw_order, int priority) {
3264  nassertv_always(!is_empty());
3265  node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority);
3266 }
3267 
3268 ////////////////////////////////////////////////////////////////////
3269 // Function: NodePath::clear_bin
3270 // Access: Published
3271 // Description: Completely removes any bin adjustment that may have
3272 // been set via set_bin() from this particular node.
3273 ////////////////////////////////////////////////////////////////////
3274 void NodePath::
3276  nassertv_always(!is_empty());
3277  node()->clear_attrib(CullBinAttrib::get_class_slot());
3278 }
3279 
3280 ////////////////////////////////////////////////////////////////////
3281 // Function: NodePath::has_bin
3282 // Access: Published
3283 // Description: Returns true if the node has been assigned to the a
3284 // particular rendering bin via set_bin(), false
3285 // otherwise.
3286 ////////////////////////////////////////////////////////////////////
3287 bool NodePath::
3288 has_bin() const {
3289  nassertr_always(!is_empty(), false);
3290  return node()->has_attrib(CullBinAttrib::get_class_slot());
3291 }
3292 
3293 ////////////////////////////////////////////////////////////////////
3294 // Function: NodePath::get_bin_name
3295 // Access: Published
3296 // Description: Returns the name of the bin that this particular node
3297 // was assigned to via set_bin(), or the empty string if
3298 // no bin was assigned. See set_bin() and has_bin().
3299 ////////////////////////////////////////////////////////////////////
3300 string NodePath::
3301 get_bin_name() const {
3302  nassertr_always(!is_empty(), string());
3303  const RenderAttrib *attrib =
3304  node()->get_attrib(CullBinAttrib::get_class_slot());
3305  if (attrib != (const RenderAttrib *)NULL) {
3306  const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
3307  return ba->get_bin_name();
3308  }
3309 
3310  return string();
3311 }
3312 
3313 ////////////////////////////////////////////////////////////////////
3314 // Function: NodePath::get_bin_draw_order
3315 // Access: Published
3316 // Description: Returns the drawing order associated with the bin
3317 // that this particular node was assigned to via
3318 // set_bin(), or 0 if no bin was assigned. See
3319 // set_bin() and has_bin().
3320 ////////////////////////////////////////////////////////////////////
3321 int NodePath::
3323  nassertr_always(!is_empty(), false);
3324  const RenderAttrib *attrib =
3325  node()->get_attrib(CullBinAttrib::get_class_slot());
3326  if (attrib != (const RenderAttrib *)NULL) {
3327  const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
3328  return ba->get_draw_order();
3329  }
3330 
3331  return 0;
3332 }
3333 
3334 ////////////////////////////////////////////////////////////////////
3335 // Function: NodePath::set_texture
3336 // Access: Published
3337 // Description: Adds the indicated texture to the list of textures
3338 // that will be rendered on the default texture stage.
3339 //
3340 // This is the convenience single-texture variant of
3341 // this method; it is now superceded by set_texture()
3342 // that accepts a stage and texture. You may use this
3343 // method if you just want to adjust the default stage.
3344 ////////////////////////////////////////////////////////////////////
3345 void NodePath::
3346 set_texture(Texture *tex, int priority) {
3347  nassertv_always(!is_empty());
3349  set_texture(stage, tex, priority);
3350 }
3351 
3352 ////////////////////////////////////////////////////////////////////
3353 // Function: NodePath::set_texture
3354 // Access: Published
3355 // Description: Adds the indicated texture to the list of textures
3356 // that will be rendered on the indicated multitexture
3357 // stage. If there are multiple texture stages
3358 // specified (possibly on multiple different nodes at
3359 // different levels), they will all be applied to
3360 // geometry together, according to the stage
3361 // specification set up in the TextureStage object.
3362 ////////////////////////////////////////////////////////////////////
3363 void NodePath::
3364 set_texture(TextureStage *stage, Texture *tex, int priority) {
3365  nassertv_always(!is_empty());
3366 
3367  const RenderAttrib *attrib =
3368  node()->get_attrib(TextureAttrib::get_class_slot());
3369  if (attrib != (const RenderAttrib *)NULL) {
3370  const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
3371  int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
3372 
3373  // Modify the existing TextureAttrib to add the indicated
3374  // texture.
3375  node()->set_attrib(tsa->add_on_stage(stage, tex, priority), sg_priority);
3376 
3377  } else {
3378  // Create a new TextureAttrib for this node.
3379  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
3380  node()->set_attrib(tsa->add_on_stage(stage, tex, priority));
3381  }
3382 }
3383 
3384 ////////////////////////////////////////////////////////////////////
3385 // Function: NodePath::set_texture
3386 // Access: Published
3387 // Description: Adds the indicated texture to the list of textures
3388 // that will be rendered on the default texture stage.
3389 //
3390 // The given sampler state will override the sampling
3391 // settings on the texture itself. Note that this
3392 // method makes a copy of the sampler settings that
3393 // you give; further changes to this object will not
3394 // be reflected.
3395 //
3396 // This is the convenience single-texture variant of
3397 // this method; it is now superceded by set_texture()
3398 // that accepts a stage and texture. You may use this
3399 // method if you just want to adjust the default stage.
3400 ////////////////////////////////////////////////////////////////////
3401 void NodePath::
3402 set_texture(Texture *tex, const SamplerState &sampler, int priority) {
3403  nassertv_always(!is_empty());
3405  set_texture(stage, tex, sampler, priority);
3406 }
3407 
3408 ////////////////////////////////////////////////////////////////////
3409 // Function: NodePath::set_texture
3410 // Access: Published
3411 // Description: Adds the indicated texture to the list of textures
3412 // that will be rendered on the indicated multitexture
3413 // stage. If there are multiple texture stages
3414 // specified (possibly on multiple different nodes at
3415 // different levels), they will all be applied to
3416 // geometry together, according to the stage
3417 // specification set up in the TextureStage object.
3418 //
3419 // The given sampler state will override the sampling
3420 // settings on the texture itself. Note that this
3421 // method makes a copy of the sampler settings that
3422 // you give; further changes to this object will not
3423 // be reflected.
3424 ////////////////////////////////////////////////////////////////////
3425 void NodePath::
3426 set_texture(TextureStage *stage, Texture *tex, const SamplerState &sampler, int priority) {
3427  nassertv_always(!is_empty());
3428 
3429  const RenderAttrib *attrib =
3430  node()->get_attrib(TextureAttrib::get_class_slot());
3431  if (attrib != (const RenderAttrib *)NULL) {
3432  const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
3433  int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
3434 
3435  // Modify the existing TextureAttrib to add the indicated
3436  // texture.
3437  node()->set_attrib(tsa->add_on_stage(stage, tex, sampler, priority), sg_priority);
3438 
3439  } else {
3440  // Create a new TextureAttrib for this node.
3441  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
3442  node()->set_attrib(tsa->add_on_stage(stage, tex, sampler, priority));
3443  }
3444 }
3445 
3446 ////////////////////////////////////////////////////////////////////
3447 // Function: NodePath::set_texture_off
3448 // Access: Published
3449 // Description: Sets the geometry at this level and below to render
3450 // using no texture, on any stage. This is different
3451 // from not specifying a texture; rather, this
3452 // specifically contradicts set_texture() at a higher
3453 // node level (or, with a priority, overrides a
3454 // set_texture() at a lower level).
3455 ////////////////////////////////////////////////////////////////////
3456 void NodePath::
3457 set_texture_off(int priority) {
3458  nassertv_always(!is_empty());
3459  node()->set_attrib(TextureAttrib::make_all_off(), priority);
3460 }
3461 
3462 ////////////////////////////////////////////////////////////////////
3463 // Function: NodePath::set_texture_off
3464 // Access: Published
3465 // Description: Sets the geometry at this level and below to render
3466 // using no texture, on the indicated stage. This is
3467 // different from not specifying a texture; rather, this
3468 // specifically contradicts set_texture() at a higher
3469 // node level (or, with a priority, overrides a
3470 // set_texture() at a lower level).
3471 ////////////////////////////////////////////////////////////////////
3472 void NodePath::
3473 set_texture_off(TextureStage *stage, int priority) {
3474  nassertv_always(!is_empty());
3475 
3476  const RenderAttrib *attrib =
3477  node()->get_attrib(TextureAttrib::get_class_slot());
3478  if (attrib != (const RenderAttrib *)NULL) {
3479  const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
3480  int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
3481 
3482  // Modify the existing TextureAttrib to add the indicated texture
3483  // to the "off" list. This also, incidentally, removes it from
3484  // the "on" list if it is there.
3485  node()->set_attrib(tsa->add_off_stage(stage, priority), sg_priority);
3486 
3487  } else {
3488  // Create a new TextureAttrib for this node that turns off the
3489  // indicated stage.
3490  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
3491  node()->set_attrib(tsa->add_off_stage(stage, priority));
3492  }
3493 }
3494 
3495 ////////////////////////////////////////////////////////////////////
3496 // Function: NodePath::clear_texture
3497 // Access: Published
3498 // Description: Completely removes any texture adjustment that may
3499 // have been set via set_texture() or set_texture_off()
3500 // from this particular node. This allows whatever
3501 // textures might be otherwise affecting the geometry to
3502 // show instead.
3503 ////////////////////////////////////////////////////////////////////
3504 void NodePath::
3506  nassertv_always(!is_empty());
3507  node()->clear_attrib(TextureAttrib::get_class_slot());
3508 }
3509 
3510 ////////////////////////////////////////////////////////////////////
3511 // Function: NodePath::clear_texture
3512 // Access: Published
3513 // Description: Removes any reference to the indicated texture stage
3514 // from the NodePath.
3515 ////////////////////////////////////////////////////////////////////
3516 void NodePath::
3518  nassertv_always(!is_empty());
3519 
3520  const RenderAttrib *attrib =
3521  node()->get_attrib(TextureAttrib::get_class_slot());
3522  if (attrib != (const RenderAttrib *)NULL) {
3523  CPT(TextureAttrib) tsa = DCAST(TextureAttrib, attrib);
3524  tsa = DCAST(TextureAttrib, tsa->remove_on_stage(stage));
3525  tsa = DCAST(TextureAttrib, tsa->remove_off_stage(stage));
3526 
3527  if (tsa->is_identity()) {
3528  node()->clear_attrib(TextureAttrib::get_class_slot());
3529 
3530  } else {
3531  int priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
3532  node()->set_attrib(tsa, priority);
3533  }
3534  }
3535 }
3536 
3537 ////////////////////////////////////////////////////////////////////
3538 // Function: NodePath::has_texture
3539 // Access: Published
3540 // Description: Returns true if a texture has been applied to this
3541 // particular node via set_texture(), false otherwise.
3542 // This is not the same thing as asking whether the
3543 // geometry at this node will be rendered with
3544 // texturing, as there may be a texture in effect from a
3545 // higher or lower level.
3546 ////////////////////////////////////////////////////////////////////
3547 bool NodePath::
3548 has_texture() const {
3549  return get_texture() != (Texture *)NULL;
3550 }
3551 
3552 ////////////////////////////////////////////////////////////////////
3553 // Function: NodePath::has_texture
3554 // Access: Published
3555 // Description: Returns true if texturing has been specifically
3556 // enabled on this particular node for the indicated
3557 // stage. This means that someone called
3558 // set_texture() on this node with the indicated stage
3559 // name, or the stage_name is the default stage_name,
3560 // and someone called set_texture() on this node.
3561 ////////////////////////////////////////////////////////////////////
3562 bool NodePath::
3563 has_texture(TextureStage *stage) const {
3564  nassertr_always(!is_empty(), false);
3565 
3566  const RenderAttrib *attrib =
3567  node()->get_attrib(TextureAttrib::get_class_slot());
3568  if (attrib != (const RenderAttrib *)NULL) {
3569  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3570  return ta->has_on_stage(stage);
3571  }
3572 
3573  return false;
3574 }
3575 
3576 ////////////////////////////////////////////////////////////////////
3577 // Function: NodePath::has_texture_off
3578 // Access: Published
3579 // Description: Returns true if texturing has been specifically
3580 // disabled on this particular node via
3581 // set_texture_off(), false otherwise. This is not the
3582 // same thing as asking whether the geometry at this
3583 // node will be rendered untextured, as there may be a
3584 // texture in effect from a higher or lower level.
3585 ////////////////////////////////////////////////////////////////////
3586 bool NodePath::
3588  nassertr_always(!is_empty(), false);
3589  const RenderAttrib *attrib =
3590  node()->get_attrib(TextureAttrib::get_class_slot());
3591  if (attrib != (const RenderAttrib *)NULL) {
3592  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3593  return ta->has_all_off();
3594  }
3595 
3596  return false;
3597 }
3598 
3599 ////////////////////////////////////////////////////////////////////
3600 // Function: NodePath::has_texture_off
3601 // Access: Published
3602 // Description: Returns true if texturing has been specifically
3603 // disabled on this particular node for the indicated
3604 // stage. This means that someone called
3605 // set_texture_off() on this node with the indicated
3606 // stage name, or that someone called set_texture_off()
3607 // on this node to remove all stages.
3608 ////////////////////////////////////////////////////////////////////
3609 bool NodePath::
3611  nassertr_always(!is_empty(), false);
3612 
3613  const RenderAttrib *attrib =
3614  node()->get_attrib(TextureAttrib::get_class_slot());
3615  if (attrib != (const RenderAttrib *)NULL) {
3616  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3617  return ta->has_off_stage(stage);
3618  }
3619 
3620  return false;
3621 }
3622 
3623 ////////////////////////////////////////////////////////////////////
3624 // Function: NodePath::get_texture
3625 // Access: Published
3626 // Description: Returns the base-level texture that has been set on
3627 // this particular node, or NULL if no texture has been
3628 // set. This is not necessarily the texture that will
3629 // be applied to the geometry at or below this level, as
3630 // another texture at a higher or lower level may
3631 // override.
3632 //
3633 // See also find_texture().
3634 ////////////////////////////////////////////////////////////////////
3636 get_texture() const {
3637  nassertr_always(!is_empty(), NULL);
3638  const RenderAttrib *attrib =
3639  node()->get_attrib(TextureAttrib::get_class_slot());
3640  if (attrib != (const RenderAttrib *)NULL) {
3641  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3642  return ta->get_texture();
3643  }
3644 
3645  return NULL;
3646 }
3647 
3648 ////////////////////////////////////////////////////////////////////
3649 // Function: NodePath::get_texture
3650 // Access: Published
3651 // Description: Returns the texture that has been set on the
3652 // indicated stage for this particular node, or NULL if
3653 // no texture has been set for this stage.
3654 ////////////////////////////////////////////////////////////////////
3656 get_texture(TextureStage *stage) const {
3657  nassertr_always(!is_empty(), NULL);
3658  const RenderAttrib *attrib =
3659  node()->get_attrib(TextureAttrib::get_class_slot());
3660  if (attrib != (const RenderAttrib *)NULL) {
3661  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3662  return ta->get_on_texture(stage);
3663  }
3664 
3665  return NULL;
3666 }
3667 
3668 ////////////////////////////////////////////////////////////////////
3669 // Function: NodePath::get_texture_sampler
3670 // Access: Published
3671 // Description: Returns the sampler state that has been given for
3672 // the base-level texture that has been set on this
3673 // particular node. If no sampler state was given,
3674 // this returns the texture's default sampler settings.
3675 //
3676 // It is an error to call this if there is no base-level
3677 // texture applied to this particular node.
3678 ////////////////////////////////////////////////////////////////////
3679 const SamplerState &NodePath::
3682 }
3683 
3684 ////////////////////////////////////////////////////////////////////
3685 // Function: NodePath::get_texture_sampler
3686 // Access: Published
3687 // Description: Returns the sampler state that has been given for
3688 // the indicated texture stage that has been set on this
3689 // particular node. If no sampler state was given,
3690 // this returns the texture's default sampler settings.
3691 //
3692 // It is an error to call this if there is no texture
3693 // set for this stage on this particular node.
3694 ////////////////////////////////////////////////////////////////////
3695 const SamplerState &NodePath::
3697  nassertr_always(!is_empty(), SamplerState::get_default());
3698  const RenderAttrib *attrib =
3699  node()->get_attrib(TextureAttrib::get_class_slot());
3700  nassertr_always(attrib != NULL, SamplerState::get_default());
3701 
3702  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
3703  return ta->get_on_sampler(stage);
3704 }
3705 
3706 ////////////////////////////////////////////////////////////////////
3707 // Function: NodePath::set_shader
3708 // Access: Published
3709 // Description:
3710 ////////////////////////////////////////////////////////////////////
3711 void NodePath::
3712 set_shader(const Shader *sha, int priority) {
3713  nassertv_always(!is_empty());
3714 
3715  const RenderAttrib *attrib =
3716  node()->get_attrib(ShaderAttrib::get_class_slot());
3717  if (attrib != (const RenderAttrib *)NULL) {
3718  priority = max(priority,
3719  node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
3720  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3721  node()->set_attrib(sa->set_shader(sha, priority));
3722  } else {
3723  // Create a new ShaderAttrib for this node.
3724  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3725  node()->set_attrib(sa->set_shader(sha, priority));
3726  }
3727 }
3728 
3729 ////////////////////////////////////////////////////////////////////
3730 // Function: NodePath::set_shader_off
3731 // Access: Published
3732 // Description:
3733 ////////////////////////////////////////////////////////////////////
3734 void NodePath::
3735 set_shader_off(int priority) {
3736  set_shader(NULL, priority);
3737 }
3738 
3739 ////////////////////////////////////////////////////////////////////
3740 // Function: NodePath::set_shader_auto
3741 // Access: Published
3742 // Description:
3743 ////////////////////////////////////////////////////////////////////
3744 void NodePath::
3745 set_shader_auto(int priority) {
3746  nassertv_always(!is_empty());
3747 
3748  const RenderAttrib *attrib =
3749  node()->get_attrib(ShaderAttrib::get_class_slot());
3750  if (attrib != (const RenderAttrib *)NULL) {
3751  priority = max(priority,
3752  node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
3753  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3754  node()->set_attrib(sa->set_shader_auto(priority));
3755  } else {
3756  // Create a new ShaderAttrib for this node.
3757  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3758  node()->set_attrib(sa->set_shader_auto(priority));
3759  }
3760 }
3761 
3762 ////////////////////////////////////////////////////////////////////
3763 // Function: NodePath::set_shader_auto
3764 // Access: Published
3765 // Description: overloaded for auto shader customization
3766 ////////////////////////////////////////////////////////////////////
3767 void NodePath::
3768 set_shader_auto(BitMask32 shader_switch, int priority) {
3769  nassertv_always(!is_empty());
3770 
3771  const RenderAttrib *attrib =
3772  node()->get_attrib(ShaderAttrib::get_class_slot());
3773  if (attrib != (const RenderAttrib *)NULL) {
3774  priority = max(priority,
3775  node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
3776  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3777  node()->set_attrib(sa->set_shader_auto(shader_switch, priority));
3778  } else {
3779  // Create a new ShaderAttrib for this node.
3780  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3781  node()->set_attrib(sa->set_shader_auto(shader_switch, priority));
3782  }
3783 }
3784 ////////////////////////////////////////////////////////////////////
3785 // Function: NodePath::clear_shader
3786 // Access: Published
3787 // Description:
3788 ////////////////////////////////////////////////////////////////////
3789 void NodePath::
3790 clear_shader() {
3791  nassertv_always(!is_empty());
3792 
3793  const RenderAttrib *attrib =
3794  node()->get_attrib(ShaderAttrib::get_class_slot());
3795  if (attrib != (const RenderAttrib *)NULL) {
3796  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3797  node()->set_attrib(sa->clear_shader());
3798  }
3799 }
3800 
3801 ////////////////////////////////////////////////////////////////////
3802 // Function: NodePath::get_shader
3803 // Access: Published
3804 // Description:
3805 ////////////////////////////////////////////////////////////////////
3806 const Shader *NodePath::
3807 get_shader() const {
3808  nassertr_always(!is_empty(), NULL);
3809  const RenderAttrib *attrib =
3810  node()->get_attrib(ShaderAttrib::get_class_slot());
3811  if (attrib != (const RenderAttrib *)NULL) {
3812  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3813  return sa->get_shader();
3814  }
3815  return NULL;
3816 }
3817 
3818 ////////////////////////////////////////////////////////////////////
3819 // Function: NodePath::set_shader_input
3820 // Access: Published
3821 // Description:
3822 ////////////////////////////////////////////////////////////////////
3823 void NodePath::
3824 set_shader_input(const ShaderInput *inp) {
3825  nassertv_always(!is_empty());
3826 
3827  const RenderAttrib *attrib =
3828  node()->get_attrib(ShaderAttrib::get_class_slot());
3829  if (attrib != (const RenderAttrib *)NULL) {
3830  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3831  node()->set_attrib(sa->set_shader_input(inp));
3832  } else {
3833  // Create a new ShaderAttrib for this node.
3834  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3835  node()->set_attrib(sa->set_shader_input(inp));
3836  }
3837 }
3838 
3839 ////////////////////////////////////////////////////////////////////
3840 // Function: NodePath::get_shader_input
3841 // Access: Published
3842 // Description:
3843 ////////////////////////////////////////////////////////////////////
3844 const ShaderInput *NodePath::
3845 get_shader_input(CPT_InternalName id) const {
3846  nassertr_always(!is_empty(), NULL);
3847 
3848  const RenderAttrib *attrib =
3849  node()->get_attrib(ShaderAttrib::get_class_slot());
3850  if (attrib != (const RenderAttrib *)NULL) {
3851  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3852  return sa->get_shader_input(id);
3853  }
3854  return NULL;
3855 }
3856 
3857 ////////////////////////////////////////////////////////////////////
3858 // Function: NodePath::get_instance_count
3859 // Access: Published
3860 // Description: Returns the geometry instance count, or 0 if
3861 // disabled. See set_instance_count.
3862 ////////////////////////////////////////////////////////////////////
3863 int NodePath::
3865  nassertr_always(!is_empty(), 0);
3866 
3867  const RenderAttrib *attrib =
3868  node()->get_attrib(ShaderAttrib::get_class_slot());
3869 
3870  if (attrib != (const RenderAttrib *)NULL) {
3871  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3872  return sa->get_instance_count();
3873  }
3874 
3875  return 0;
3876 }
3877 
3878 ////////////////////////////////////////////////////////////////////
3879 // Function: NodePath::clear_shader_input
3880 // Access: Published
3881 // Description:
3882 ////////////////////////////////////////////////////////////////////
3883 void NodePath::
3884 clear_shader_input(CPT_InternalName id) {
3885  nassertv_always(!is_empty());
3886 
3887  const RenderAttrib *attrib =
3888  node()->get_attrib(ShaderAttrib::get_class_slot());
3889  if (attrib != (const RenderAttrib *)NULL) {
3890  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3891  node()->set_attrib(sa->clear_shader_input(id));
3892  }
3893 }
3894 
3895 ////////////////////////////////////////////////////////////////////
3896 // Function: NodePath::set_instance_count
3897 // Access: Published
3898 // Description: Sets the geometry instance count, or 0 if
3899 // geometry instancing should be disabled. Do not
3900 // confuse with instanceTo which only applies to
3901 // animation instancing.
3902 ////////////////////////////////////////////////////////////////////
3903 void NodePath::
3904 set_instance_count(int instance_count) {
3905  nassertv_always(!is_empty());
3906 
3907  const RenderAttrib *attrib =
3908  node()->get_attrib(ShaderAttrib::get_class_slot());
3909  if (attrib != (const RenderAttrib *)NULL) {
3910  const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
3911  node()->set_attrib(sa->set_instance_count(instance_count));
3912  } else {
3913  // Create a new ShaderAttrib for this node.
3914  CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
3915  node()->set_attrib(sa->set_instance_count(instance_count));
3916  }
3917 }
3918 
3919 ////////////////////////////////////////////////////////////////////
3920 // Function: NodePath::set_tex_transform
3921 // Access: Published
3922 // Description: Sets the texture matrix on the current node to the
3923 // indicated transform for the given stage.
3924 ////////////////////////////////////////////////////////////////////
3925 void NodePath::
3926 set_tex_transform(TextureStage *stage, const TransformState *transform) {
3927  nassertv_always(!is_empty());
3928 
3929  const RenderAttrib *attrib =
3930  node()->get_attrib(TexMatrixAttrib::get_class_slot());
3931  if (attrib != (const RenderAttrib *)NULL) {
3932  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
3933 
3934  // Modify the existing TexMatrixAttrib to add the indicated
3935  // stage.
3936  node()->set_attrib(tma->add_stage(stage, transform));
3937 
3938  } else {
3939  // Create a new TexMatrixAttrib for this node.
3940  node()->set_attrib(TexMatrixAttrib::make(stage, transform));
3941  }
3942 }
3943 
3944 ////////////////////////////////////////////////////////////////////
3945 // Function: NodePath::clear_tex_transform
3946 // Access: Published
3947 // Description: Removes all texture matrices from the current node.
3948 ////////////////////////////////////////////////////////////////////
3949 void NodePath::
3951  nassertv_always(!is_empty());
3952  node()->clear_attrib(TexMatrixAttrib::get_class_slot());
3953 }
3954 
3955 ////////////////////////////////////////////////////////////////////
3956 // Function: NodePath::clear_tex_transform
3957 // Access: Published
3958 // Description: Removes the texture matrix on the current node for
3959 // the given stage.
3960 ////////////////////////////////////////////////////////////////////
3961 void NodePath::
3963  nassertv_always(!is_empty());
3964 
3965  const RenderAttrib *attrib =
3966  node()->get_attrib(TexMatrixAttrib::get_class_slot());
3967  if (attrib != (const RenderAttrib *)NULL) {
3968  CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, attrib);
3969  tma = DCAST(TexMatrixAttrib, tma->remove_stage(stage));
3970 
3971  if (tma->is_empty()) {
3972  node()->clear_attrib(TexMatrixAttrib::get_class_slot());
3973 
3974  } else {
3975  node()->set_attrib(tma);
3976  }
3977  }
3978 }
3979 
3980 ////////////////////////////////////////////////////////////////////
3981 // Function: NodePath::has_tex_transform
3982 // Access: Published
3983 // Description: Returns true if there is an explicit texture matrix
3984 // on the current node for the given stage.
3985 ////////////////////////////////////////////////////////////////////
3986 bool NodePath::
3988  nassertr_always(!is_empty(), false);
3989 
3990  const RenderAttrib *attrib =
3991  node()->get_attrib(TexMatrixAttrib::get_class_slot());
3992  if (attrib != (const RenderAttrib *)NULL) {
3993  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
3994  return tma->has_stage(stage);
3995  }
3996 
3997  return false;
3998 }
3999 
4000 ////////////////////////////////////////////////////////////////////
4001 // Function: NodePath::get_tex_transform
4002 // Access: Published
4003 // Description: Returns the texture matrix on the current node for the
4004 // given stage, or identity transform if there is no
4005 // explicit transform set for the given stage.
4006 ////////////////////////////////////////////////////////////////////
4007 CPT(TransformState) NodePath::
4008 get_tex_transform(TextureStage *stage) const {
4009  nassertr_always(!is_empty(), NULL);
4010 
4011  const RenderAttrib *attrib =
4012  node()->get_attrib(TexMatrixAttrib::get_class_slot());
4013  if (attrib != (const RenderAttrib *)NULL) {
4014  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
4015  return tma->get_transform(stage);
4016  }
4017 
4018  return TransformState::make_identity();
4019 }
4020 
4021 ////////////////////////////////////////////////////////////////////
4022 // Function: NodePath::set_tex_transform
4023 // Access: Published
4024 // Description: Sets the texture matrix on the current node to the
4025 // indicated transform for the given stage.
4026 ////////////////////////////////////////////////////////////////////
4027 void NodePath::
4028 set_tex_transform(const NodePath &other, TextureStage *stage, const TransformState *transform) {
4029  nassertv(_error_type == ET_ok && other._error_type == ET_ok);
4030  nassertv_always(!is_empty());
4031 
4032  CPT(RenderState) state = get_state(other);
4033  const RenderAttrib *attrib =
4034  state->get_attrib(TexMatrixAttrib::get_class_slot());
4035  if (attrib != (const RenderAttrib *)NULL) {
4036  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
4037 
4038  // Modify the existing TexMatrixAttrib to add the indicated
4039  // stage.
4040  state = state->add_attrib(tma->add_stage(stage, transform));
4041 
4042  } else {
4043  // Create a new TexMatrixAttrib for this node.
4044  state = state->add_attrib(TexMatrixAttrib::make(stage, transform));
4045  }
4046 
4047  // Now compose that with our parent's state.
4048  CPT(RenderState) rel_state;
4049  if (has_parent()) {
4050  rel_state = other.get_state(get_parent());
4051  } else {
4052  rel_state = other.get_state(NodePath());
4053  }
4054  CPT(RenderState) new_state = rel_state->compose(state);
4055 
4056  // And apply only the TexMatrixAttrib to the current node, leaving
4057  // the others unchanged.
4058  node()->set_attrib(new_state->get_attrib(TexMatrixAttrib::get_class_slot()));
4059 }
4060 
4061 ////////////////////////////////////////////////////////////////////
4062 // Function: NodePath::get_tex_transform
4063 // Access: Published
4064 // Description: Returns the texture matrix on the current node for the
4065 // given stage, relative to the other node.
4066 ////////////////////////////////////////////////////////////////////
4067 CPT(TransformState) NodePath::
4068 get_tex_transform(const NodePath &other, TextureStage *stage) const {
4069  nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
4070 
4071  CPT(RenderState) state = get_state(other);
4072  const RenderAttrib *attrib =
4073  state->get_attrib(TexMatrixAttrib::get_class_slot());
4074  if (attrib != (const RenderAttrib *)NULL) {
4075  const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
4076  return tma->get_transform(stage);
4077  }
4078 
4079  return TransformState::make_identity();
4080 }
4081 
4082 ////////////////////////////////////////////////////////////////////
4083 // Function: NodePath::set_tex_gen
4084 // Access: Published
4085 // Description: Enables automatic texture coordinate generation for
4086 // the indicated texture stage.
4087 ////////////////////////////////////////////////////////////////////
4088 void NodePath::
4089 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) {
4090  nassertv_always(!is_empty());
4091 
4092  const RenderAttrib *attrib =
4093  node()->get_attrib(TexGenAttrib::get_class_slot());
4094 
4095  CPT(TexGenAttrib) tga;
4096 
4097  if (attrib != (const RenderAttrib *)NULL) {
4098  priority = max(priority,
4099  node()->get_state()->get_override(TextureAttrib::get_class_slot()));
4100  tga = DCAST(TexGenAttrib, attrib);
4101 
4102  } else {
4103  tga = DCAST(TexGenAttrib, TexGenAttrib::make());
4104  }
4105 
4106  node()->set_attrib(tga->add_stage(stage, mode), priority);
4107 }
4108 
4109 ////////////////////////////////////////////////////////////////////
4110 // Function: NodePath::set_tex_gen
4111 // Access: Published
4112 // Description: Enables automatic texture coordinate generation for
4113 // the indicated texture stage. This version of this
4114 // method is useful when setting M_constant, which
4115 // requires a constant texture coordinate value.
4116 ////////////////////////////////////////////////////////////////////
4117 void NodePath::
4118 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode,
4119  const LTexCoord3 &constant_value, int priority) {
4120  nassertv_always(!is_empty());
4121 
4122  const RenderAttrib *attrib =
4123  node()->get_attrib(TexGenAttrib::get_class_slot());
4124 
4125  CPT(TexGenAttrib) tga;
4126 
4127  if (attrib != (const RenderAttrib *)NULL) {
4128  priority = max(priority,
4129  node()->get_state()->get_override(TextureAttrib::get_class_slot()));
4130  tga = DCAST(TexGenAttrib, attrib);
4131 
4132  } else {
4133  tga = DCAST(TexGenAttrib, TexGenAttrib::make());
4134  }
4135 
4136  node()->set_attrib(tga->add_stage(stage, mode, constant_value), priority);
4137 }
4138 
4139 ////////////////////////////////////////////////////////////////////
4140 // Function: NodePath::clear_tex_gen
4141 // Access: Published
4142 // Description: Removes the texture coordinate generation mode from
4143 // all texture stages on this node.
4144 ////////////////////////////////////////////////////////////////////
4145 void NodePath::
4147  nassertv_always(!is_empty());
4148  node()->clear_attrib(TexGenAttrib::get_class_slot());
4149 }
4150 
4151 ////////////////////////////////////////////////////////////////////
4152 // Function: NodePath::clear_tex_gen
4153 // Access: Published
4154 // Description: Disables automatic texture coordinate generation for
4155 // the indicated texture stage.
4156 ////////////////////////////////////////////////////////////////////
4157 void NodePath::
4159  nassertv_always(!is_empty());
4160 
4161  const RenderAttrib *attrib =
4162  node()->get_attrib(TexGenAttrib::get_class_slot());
4163  if (attrib != (const RenderAttrib *)NULL) {
4164  CPT(TexGenAttrib) tga = DCAST(TexGenAttrib, attrib);
4165  tga = DCAST(TexGenAttrib, tga->remove_stage(stage));
4166 
4167  if (tga->is_empty()) {
4168  node()->clear_attrib(TexGenAttrib::get_class_slot());
4169 
4170  } else {
4171  node()->set_attrib(tga);
4172  }
4173  }
4174 }
4175 
4176 ////////////////////////////////////////////////////////////////////
4177 // Function: NodePath::has_tex_gen
4178 // Access: Published
4179 // Description: Returns true if there is a mode for automatic texture
4180 // coordinate generation on the current node for the
4181 // given stage.
4182 ////////////////////////////////////////////////////////////////////
4183 bool NodePath::
4184 has_tex_gen(TextureStage *stage) const {
4185  nassertr_always(!is_empty(), false);
4186 
4187  const RenderAttrib *attrib =
4188  node()->get_attrib(TexGenAttrib::get_class_slot());
4189  if (attrib != (const RenderAttrib *)NULL) {
4190  const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
4191  return tga->has_stage(stage);
4192  }
4193 
4194  return false;
4195 }
4196 
4197 ////////////////////////////////////////////////////////////////////
4198 // Function: NodePath::get_tex_gen
4199 // Access: Published
4200 // Description: Returns the texture coordinate generation mode for
4201 // the given stage, or M_off if there is no explicit
4202 // mode set for the given stage.
4203 ////////////////////////////////////////////////////////////////////
4204 RenderAttrib::TexGenMode NodePath::
4205 get_tex_gen(TextureStage *stage) const {
4206  nassertr_always(!is_empty(), TexGenAttrib::M_off);
4207 
4208  const RenderAttrib *attrib =
4209  node()->get_attrib(TexGenAttrib::get_class_slot());
4210  if (attrib != (const RenderAttrib *)NULL) {
4211  const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
4212  return tga->get_mode(stage);
4213  }
4214 
4215  return TexGenAttrib::M_off;
4216 }
4217 
4218 ////////////////////////////////////////////////////////////////////
4219 // Function: NodePath::set_tex_projector
4220 // Access: Published
4221 // Description: Establishes a TexProjectorEffect on this node, which
4222 // can be used to establish projective texturing (but
4223 // see also the NodePath::project_texture() convenience
4224 // function), or it can be used to bind this node's
4225 // texture transform to particular node's position in
4226 // space, allowing a LerpInterval (for instance) to
4227 // adjust this node's texture coordinates.
4228 //
4229 // If to is a LensNode, then the fourth parameter,
4230 // lens_index, can be provided to select a particular
4231 // lens to apply. Otherwise lens_index is not used.
4232 ////////////////////////////////////////////////////////////////////
4233 void NodePath::
4234 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to,
4235  int lens_index) {
4236  nassertv_always(!is_empty());
4237 
4238  const RenderEffect *effect =
4239  node()->get_effect(TexProjectorEffect::get_class_type());
4240 
4241  CPT(TexProjectorEffect) tpe;
4242 
4243  if (effect != (const RenderEffect *)NULL) {
4244  tpe = DCAST(TexProjectorEffect, effect);
4245 
4246  } else {
4247  tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make());
4248  }
4249 
4250  node()->set_effect(tpe->add_stage(stage, from, to, lens_index));
4251 }
4252 
4253 ////////////////////////////////////////////////////////////////////
4254 // Function: NodePath::clear_tex_projector
4255 // Access: Published
4256 // Description: Removes the TexProjectorEffect for the indicated
4257 // stage from this node.
4258 ////////////////////////////////////////////////////////////////////
4259 void NodePath::
4261  nassertv_always(!is_empty());
4262 
4263  const RenderEffect *effect =
4264  node()->get_effect(TexProjectorEffect::get_class_type());
4265  if (effect != (const RenderEffect *)NULL) {
4266  CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect);
4267  tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage));
4268 
4269  if (tpe->is_empty()) {
4270  node()->clear_effect(TexProjectorEffect::get_class_type());
4271 
4272  } else {
4273  node()->set_effect(tpe);
4274  }
4275  }
4276 }
4277 
4278 ////////////////////////////////////////////////////////////////////
4279 // Function: NodePath::clear_tex_projector
4280 // Access: Published
4281 // Description: Removes the TexProjectorEffect for all stages from
4282 // this node.
4283 ////////////////////////////////////////////////////////////////////
4284 void NodePath::
4286  nassertv_always(!is_empty());
4287  node()->clear_effect(TexProjectorEffect::get_class_type());
4288 }
4289 
4290 ////////////////////////////////////////////////////////////////////
4291 // Function: NodePath::has_tex_projector
4292 // Access: Published
4293 // Description: Returns true if this node has a TexProjectorEffect
4294 // for the indicated stage, false otherwise.
4295 ////////////////////////////////////////////////////////////////////
4296 bool NodePath::
4298  nassertr_always(!is_empty(), false);
4299 
4300  const RenderEffect *effect =
4301  node()->get_effect(TexProjectorEffect::get_class_type());
4302  if (effect != (const RenderEffect *)NULL) {
4303  const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
4304  return tpe->has_stage(stage);
4305  }
4306 
4307  return false;
4308 }
4309 
4310 ////////////////////////////////////////////////////////////////////
4311 // Function: NodePath::get_tex_projector_from
4312 // Access: Published
4313 // Description: Returns the "from" node associated with the
4314 // TexProjectorEffect on the indicated stage. The
4315 // relative transform between the "from" and the "to"
4316 // nodes is automatically applied to the texture
4317 // transform each frame.
4318 ////////////////////////////////////////////////////////////////////
4321  nassertr_always(!is_empty(), NodePath::fail());
4322 
4323  const RenderEffect *effect =
4324  node()->get_effect(TexProjectorEffect::get_class_type());
4325  if (effect != (const RenderEffect *)NULL) {
4326  const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
4327  return tpe->get_from(stage);
4328  }
4329 
4330  return NodePath::not_found();
4331 }
4332 
4333 ////////////////////////////////////////////////////////////////////
4334 // Function: NodePath::get_tex_projector_to
4335 // Access: Published
4336 // Description: Returns the "to" node associated with the
4337 // TexProjectorEffect on the indicated stage. The
4338 // relative transform between the "from" and the "to"
4339 // nodes is automatically applied to the texture
4340 // transform each frame.
4341 ////////////////////////////////////////////////////////////////////
4344  nassertr_always(!is_empty(), NodePath::fail());
4345 
4346  const RenderEffect *effect =
4347  node()->get_effect(TexProjectorEffect::get_class_type());
4348  if (effect != (const RenderEffect *)NULL) {
4349  const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
4350  return tpe->get_to(stage);
4351  }
4352 
4353  return NodePath::not_found();
4354 }
4355 
4356 ////////////////////////////////////////////////////////////////////
4357 // Function: NodePath::project_texture
4358 // Access: Published
4359 // Description: A convenience function to enable projective texturing
4360 // at this node level and below, using the indicated
4361 // NodePath (which should contain a LensNode) as the
4362 // projector.
4363 ////////////////////////////////////////////////////////////////////
4364 void NodePath::
4365 project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) {
4366  nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type()));
4367  set_texture(stage, tex);
4368  set_tex_gen(stage, TexGenAttrib::M_world_position);
4369  set_tex_projector(stage, NodePath(), projector);
4370 }
4371 
4372 ////////////////////////////////////////////////////////////////////
4373 // Function: NodePath::has_vertex_column
4374 // Access: Published
4375 // Description: Returns true if there are at least some vertices at
4376 // this node and below that contain a reference to the
4377 // indicated vertex data column name, false otherwise.
4378 //
4379 // This is particularly useful for testing whether a
4380 // particular model has a given texture coordinate set
4381 // (but see has_texcoord()).
4382 ////////////////////////////////////////////////////////////////////
4383 bool NodePath::
4384 has_vertex_column(const InternalName *name) const {
4385  nassertr_always(!is_empty(), false);
4386  return r_has_vertex_column(node(), name);
4387 }
4388 
4389 ////////////////////////////////////////////////////////////////////
4390 // Function: NodePath::find_all_vertex_columns
4391 // Access: Published
4392 // Description: Returns a list of all vertex array columns stored on
4393 // some geometry found at this node level and below.
4394 ////////////////////////////////////////////////////////////////////
4397  nassertr_always(!is_empty(), InternalNameCollection());
4398  InternalNames vertex_columns;
4399  r_find_all_vertex_columns(node(), vertex_columns);
4400 
4402  InternalNames::iterator ti;
4403  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
4404  tc.add_name(*ti);
4405  }
4406  return tc;
4407 }
4408 
4409 ////////////////////////////////////////////////////////////////////
4410 // Function: NodePath::find_all_vertex_columns
4411 // Access: Published
4412 // Description: Returns a list of all vertex array columns stored on
4413 // some geometry found at this node level and below that
4414 // match the indicated name (which may contain wildcard
4415 // characters).
4416 ////////////////////////////////////////////////////////////////////
4418 find_all_vertex_columns(const string &name) const {
4419  nassertr_always(!is_empty(), InternalNameCollection());
4420  InternalNames vertex_columns;
4421  r_find_all_vertex_columns(node(), vertex_columns);
4422 
4423  GlobPattern glob(name);
4424 
4426  InternalNames::iterator ti;
4427  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
4428  const InternalName *name = (*ti);
4429  if (glob.matches(name->get_name())) {
4430  tc.add_name(name);
4431  }
4432  }
4433  return tc;
4434 }
4435 
4436 ////////////////////////////////////////////////////////////////////
4437 // Function: NodePath::find_all_texcoords
4438 // Access: Published
4439 // Description: Returns a list of all texture coordinate sets used by
4440 // any geometry at this node level and below.
4441 ////////////////////////////////////////////////////////////////////
4444  nassertr_always(!is_empty(), InternalNameCollection());
4445  InternalNames vertex_columns;
4446  r_find_all_vertex_columns(node(), vertex_columns);
4447 
4448  CPT(InternalName) texcoord_name = InternalName::get_texcoord();
4449 
4451  InternalNames::iterator ti;
4452  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
4453  if ((*ti)->get_top() == texcoord_name) {
4454  tc.add_name(*ti);
4455  }
4456  }
4457  return tc;
4458 }
4459 
4460 ////////////////////////////////////////////////////////////////////
4461 // Function: NodePath::find_all_texcoords
4462 // Access: Published
4463 // Description: Returns a list of all texture coordinate sets used by
4464 // any geometry at this node level and below that match
4465 // the indicated name (which may contain wildcard
4466 // characters).
4467 ////////////////////////////////////////////////////////////////////
4469 find_all_texcoords(const string &name) const {
4470  nassertr_always(!is_empty(), InternalNameCollection());
4471  InternalNames vertex_columns;
4472  r_find_all_vertex_columns(node(), vertex_columns);
4473 
4474  GlobPattern glob(name);
4475  CPT_InternalName texcoord_name = InternalName::get_texcoord();
4476 
4478  InternalNames::iterator ti;
4479  for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
4480  const InternalName *name = (*ti);
4481  if (name->get_top() == texcoord_name) {
4482  // This is a texture coordinate name. Figure out the basename
4483  // of the texture coordinates.
4484  int index = name->find_ancestor("texcoord");
4485  nassertr(index != -1, InternalNameCollection());
4486  string net_basename = name->get_net_basename(index - 1);
4487 
4488  if (glob.matches(net_basename)) {
4489  tc.add_name(name);
4490  }
4491  }
4492  }
4493  return tc;
4494 }
4495 
4496 ////////////////////////////////////////////////////////////////////
4497 // Function: NodePath::find_texture
4498 // Access: Published
4499 // Description: Returns the first texture found applied to geometry
4500 // at this node or below that matches the indicated name
4501 // (which may contain wildcards). Returns the texture
4502 // if it is found, or NULL if it is not.
4503 ////////////////////////////////////////////////////////////////////
4505 find_texture(const string &name) const {
4506  nassertr_always(!is_empty(), NULL);
4507  GlobPattern glob(name);
4508  return r_find_texture(node(), get_net_state(), glob);
4509 }
4510 
4511 ////////////////////////////////////////////////////////////////////
4512 // Function: NodePath::find_texture
4513 // Access: Published
4514 // Description: Returns the first texture found applied to geometry
4515 // at this node or below that is assigned to the
4516 // indicated texture stage. Returns the texture if it
4517 // is found, or NULL if it is not.
4518 ////////////////////////////////////////////////////////////////////
4521  nassertr_always(!is_empty(), NULL);
4522  return r_find_texture(node(), stage);
4523 }
4524 
4525 ////////////////////////////////////////////////////////////////////
4526 // Function: NodePath::find_all_textures
4527 // Access: Published
4528 // Description: Returns a list of a textures applied to geometry at
4529 // this node and below.
4530 ////////////////////////////////////////////////////////////////////
4533  nassertr_always(!is_empty(), TextureCollection());
4534  Textures textures;
4535  r_find_all_textures(node(), get_net_state(), textures);
4536 
4537  TextureCollection tc;
4538  Textures::iterator ti;
4539  for (ti = textures.begin(); ti != textures.end(); ++ti) {
4540  tc.add_texture(*ti);
4541  }
4542  return tc;
4543 }
4544 
4545 ////////////////////////////////////////////////////////////////////
4546 // Function: NodePath::find_all_textures
4547 // Access: Published
4548 // Description: Returns a list of a textures applied to geometry at
4549 // this node and below that match the indicated name
4550 // (which may contain wildcard characters).
4551 ////////////////////////////////////////////////////////////////////
4553 find_all_textures(const string &name) const {
4554  nassertr_always(!is_empty(), TextureCollection());
4555  Textures textures;
4556  r_find_all_textures(node(), get_net_state(), textures);
4557 
4558  GlobPattern glob(name);
4559 
4560  TextureCollection tc;
4561  Textures::iterator ti;
4562  for (ti = textures.begin(); ti != textures.end(); ++ti) {
4563  Texture *texture = (*ti);
4564  if (glob.matches(texture->get_name())) {
4565  tc.add_texture(texture);
4566  }
4567  }
4568  return tc;
4569 }
4570 
4571 ////////////////////////////////////////////////////////////////////
4572 // Function: NodePath::find_all_textures
4573 // Access: Published
4574 // Description: Returns a list of a textures on geometry at
4575 // this node and below that are assigned to the
4576 // indicated texture stage.
4577 ////////////////////////////////////////////////////////////////////
4580  nassertr_always(!is_empty(), TextureCollection());
4581  Textures textures;
4582  r_find_all_textures(node(), stage, textures);
4583 
4584  TextureCollection tc;
4585  Textures::iterator ti;
4586  for (ti = textures.begin(); ti != textures.end(); ++ti) {
4587  Texture *texture = (*ti);
4588  tc.add_texture(texture);
4589  }
4590  return tc;
4591 }
4592 
4593 ////////////////////////////////////////////////////////////////////
4594 // Function: NodePath::find_texture_stage
4595 // Access: Published
4596 // Description: Returns the first TextureStage found applied to
4597 // geometry at this node or below that matches the
4598 // indicated name (which may contain wildcards).
4599 // Returns the TextureStage if it is found, or NULL if
4600 // it is not.
4601 ////////////////////////////////////////////////////////////////////
4603 find_texture_stage(const string &name) const {
4604  nassertr_always(!is_empty(), NULL);
4605  GlobPattern glob(name);
4606  return r_find_texture_stage(node(), get_net_state(), glob);
4607 }
4608 
4609 ////////////////////////////////////////////////////////////////////
4610 // Function: NodePath::find_all_texture_stages
4611 // Access: Published
4612 // Description: Returns a list of a TextureStages applied to geometry
4613 // at this node and below.
4614 ////////////////////////////////////////////////////////////////////
4617  nassertr_always(!is_empty(), TextureStageCollection());
4618  TextureStages texture_stages;
4619  r_find_all_texture_stages(node(), get_net_state(), texture_stages);
4620 
4622  TextureStages::iterator ti;
4623  for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
4624  tc.add_texture_stage(*ti);
4625  }
4626  return tc;
4627 }
4628 
4629 ////////////////////////////////////////////////////////////////////
4630 // Function: NodePath::unify_texture_stages
4631 // Access: Published
4632 // Description: Searches through all TextureStages at this node and
4633 // below. Any TextureStages that share the same name as
4634 // the indicated TextureStage object are replaced with
4635 // this object, thus ensuring that all geometry at this
4636 // node and below with a particular TextureStage name is
4637 // using the same TextureStage object.
4638 ////////////////////////////////////////////////////////////////////
4639 void NodePath::
4641  nassertv_always(!is_empty());
4642  r_unify_texture_stages(node(), stage);
4643 }
4644 
4645 ////////////////////////////////////////////////////////////////////
4646 // Function: NodePath::find_all_texture_stages
4647 // Access: Published
4648 // Description: Returns a list of a TextureStages applied to geometry
4649 // at this node and below that match the indicated name
4650 // (which may contain wildcard characters).
4651 ////////////////////////////////////////////////////////////////////
4653 find_all_texture_stages(const string &name) const {
4654  nassertr_always(!is_empty(), TextureStageCollection());
4655  TextureStages texture_stages;
4656  r_find_all_texture_stages(node(), get_net_state(), texture_stages);
4657 
4658  GlobPattern glob(name);
4659 
4661  TextureStages::iterator ti;
4662  for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
4663  TextureStage *texture_stage = (*ti);
4664  if (glob.matches(texture_stage->get_name())) {
4665  tc.add_texture_stage(texture_stage);
4666  }
4667  }
4668  return tc;
4669 }
4670 
4671 ////////////////////////////////////////////////////////////////////
4672 // Function: NodePath::find_material
4673 // Access: Published
4674 // Description: Returns the first material found applied to geometry
4675 // at this node or below that matches the indicated name
4676 // (which may contain wildcards). Returns the material
4677 // if it is found, or NULL if it is not.
4678 ////////////////////////////////////////////////////////////////////
4680 find_material(const string &name) const {
4681  nassertr_always(!is_empty(), NULL);
4682  GlobPattern glob(name);
4683  return r_find_material(node(), get_net_state(), glob);
4684 }
4685 
4686 ////////////////////////////////////////////////////////////////////
4687 // Function: NodePath::find_all_materials
4688 // Access: Published
4689 // Description: Returns a list of a materials applied to geometry at
4690 // this node and below.
4691 ////////////////////////////////////////////////////////////////////
4694  nassertr_always(!is_empty(), MaterialCollection());
4695  Materials materials;
4696  r_find_all_materials(node(), get_net_state(), materials);
4697 
4698  MaterialCollection tc;
4699  Materials::iterator ti;
4700  for (ti = materials.begin(); ti != materials.end(); ++ti) {
4701  tc.add_material(*ti);
4702  }
4703  return tc;
4704 }
4705 
4706 ////////////////////////////////////////////////////////////////////
4707 // Function: NodePath::find_all_materials
4708 // Access: Published
4709 // Description: Returns a list of a materials applied to geometry at
4710 // this node and below that match the indicated name
4711 // (which may contain wildcard characters).
4712 ////////////////////////////////////////////////////////////////////
4714 find_all_materials(const string &name) const {
4715  nassertr_always(!is_empty(), MaterialCollection());
4716  Materials materials;
4717  r_find_all_materials(node(), get_net_state(), materials);
4718 
4719  GlobPattern glob(name);
4720 
4721  MaterialCollection tc;
4722  Materials::iterator ti;
4723  for (ti = materials.begin(); ti != materials.end(); ++ti) {
4724  Material *material = (*ti);
4725  if (glob.matches(material->get_name())) {
4726  tc.add_material(material);
4727  }
4728  }
4729  return tc;
4730 }
4731 
4732 ////////////////////////////////////////////////////////////////////
4733 // Function: NodePath::set_material
4734 // Access: Published
4735 // Description: Sets the geometry at this level and below to render
4736 // using the indicated material.
4737 //
4738 // Previously, this operation made a copy of the
4739 // material structure, but nowadays it assigns the
4740 // pointer directly.
4741 ////////////////////////////////////////////////////////////////////
4742 void NodePath::
4743 set_material(Material *mat, int priority) {
4744  nassertv_always(!is_empty());
4745  nassertv(mat != NULL);
4746  node()->set_attrib(MaterialAttrib::make(mat), priority);
4747 }
4748 
4749 ////////////////////////////////////////////////////////////////////
4750 // Function: NodePath::set_material_off
4751 // Access: Published
4752 // Description: Sets the geometry at this level and below to render
4753 // using no material. This is normally the default, but
4754 // it may be useful to use this to contradict
4755 // set_material() at a higher node level (or, with a
4756 // priority, to override a set_material() at a lower
4757 // level).
4758 ////////////////////////////////////////////////////////////////////
4759 void NodePath::
4760 set_material_off(int priority) {
4761  nassertv_always(!is_empty());
4762  node()->set_attrib(MaterialAttrib::make_off(), priority);
4763 }
4764 
4765 ////////////////////////////////////////////////////////////////////
4766 // Function: NodePath::clear_material
4767 // Access: Published
4768 // Description: Completely removes any material adjustment that may
4769 // have been set via set_material() from this particular
4770 // node.
4771 ////////////////////////////////////////////////////////////////////
4772 void NodePath::
4774  nassertv_always(!is_empty());
4775  node()->clear_attrib(MaterialAttrib::get_class_slot());
4776 }
4777 
4778 ////////////////////////////////////////////////////////////////////
4779 // Function: NodePath::has_material
4780 // Access: Published
4781 // Description: Returns true if a material has been applied to this
4782 // particular node via set_material(), false otherwise.
4783 ////////////////////////////////////////////////////////////////////
4784 bool NodePath::
4785 has_material() const {
4786  nassertr_always(!is_empty(), false);
4787  const RenderAttrib *attrib =
4788  node()->get_attrib(MaterialAttrib::get_class_slot());
4789  if (attrib != (const RenderAttrib *)NULL) {
4790  const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
4791  return !ma->is_off();
4792  }
4793 
4794  return false;
4795 }
4796 
4797 ////////////////////////////////////////////////////////////////////
4798 // Function: NodePath::get_material
4799 // Access: Published
4800 // Description: Returns the material that has been set on this
4801 // particular node, or NULL if no material has been set.
4802 // This is not necessarily the material that will be
4803 // applied to the geometry at or below this level, as
4804 // another material at a higher or lower level may
4805 // override.
4806 
4807 // See also find_material().
4808 ////////////////////////////////////////////////////////////////////
4809 PT(Material) NodePath::
4810 get_material() const {
4811  nassertr_always(!is_empty(), NULL);
4812  const RenderAttrib *attrib =
4813  node()->get_attrib(MaterialAttrib::get_class_slot());
4814  if (attrib != (const RenderAttrib *)NULL) {
4815  const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
4816  return ma->get_material();
4817  }
4818 
4819  return NULL;
4820 }
4821 
4822 ////////////////////////////////////////////////////////////////////
4823 // Function: NodePath::set_fog
4824 // Access: Published
4825 // Description: Sets the geometry at this level and below to render
4826 // using the indicated fog.
4827 ////////////////////////////////////////////////////////////////////
4828 void NodePath::
4829 set_fog(Fog *fog, int priority) {
4830  nassertv_always(!is_empty());
4831  node()->set_attrib(FogAttrib::make(fog), priority);
4832 }
4833 
4834 ////////////////////////////////////////////////////////////////////
4835 // Function: NodePath::set_fog_off
4836 // Access: Published
4837 // Description: Sets the geometry at this level and below to render
4838 // using no fog. This is normally the default, but
4839 // it may be useful to use this to contradict
4840 // set_fog() at a higher node level (or, with a
4841 // priority, to override a set_fog() at a lower
4842 // level).
4843 ////////////////////////////////////////////////////////////////////
4844 void NodePath::
4845 set_fog_off(int priority) {
4846  nassertv_always(!is_empty());
4847  node()->set_attrib(FogAttrib::make_off(), priority);
4848 }
4849 
4850 ////////////////////////////////////////////////////////////////////
4851 // Function: NodePath::clear_fog
4852 // Access: Published
4853 // Description: Completely removes any fog adjustment that may
4854 // have been set via set_fog() or set_fog_off()
4855 // from this particular node. This allows whatever
4856 // fogs might be otherwise affecting the geometry to
4857 // show instead.
4858 ////////////////////////////////////////////////////////////////////
4859 void NodePath::
4861  nassertv_always(!is_empty());
4862  node()->clear_attrib(FogAttrib::get_class_slot());
4863 }
4864 
4865 ////////////////////////////////////////////////////////////////////
4866 // Function: NodePath::has_fog
4867 // Access: Published
4868 // Description: Returns true if a fog has been applied to this
4869 // particular node via set_fog(), false otherwise.
4870 // This is not the same thing as asking whether the
4871 // geometry at this node will be rendered with
4872 // fog, as there may be a fog in effect from a higher or
4873 // lower level.
4874 ////////////////////////////////////////////////////////////////////
4875 bool NodePath::
4876 has_fog() const {
4877  nassertr_always(!is_empty(), false);
4878  const RenderAttrib *attrib =
4879  node()->get_attrib(FogAttrib::get_class_slot());
4880  if (attrib != (const RenderAttrib *)NULL) {
4881  const FogAttrib *fa = DCAST(FogAttrib, attrib);
4882  return !fa->is_off();
4883  }
4884 
4885  return false;
4886 }
4887 
4888 ////////////////////////////////////////////////////////////////////
4889 // Function: NodePath::has_fog_off
4890 // Access: Published
4891 // Description: Returns true if a fog has been specifically
4892 // disabled on this particular node via
4893 // set_fog_off(), false otherwise. This is not the
4894 // same thing as asking whether the geometry at this
4895 // node will be rendered unfogged, as there may be a
4896 // fog in effect from a higher or lower level.
4897 ////////////////////////////////////////////////////////////////////
4898 bool NodePath::
4899 has_fog_off() const {
4900  nassertr_always(!is_empty(), false);
4901  const RenderAttrib *attrib =
4902  node()->get_attrib(FogAttrib::get_class_slot());
4903  if (attrib != (const RenderAttrib *)NULL) {
4904  const FogAttrib *fa = DCAST(FogAttrib, attrib);
4905  return fa->is_off();
4906  }
4907 
4908  return false;
4909 }
4910 
4911 ////////////////////////////////////////////////////////////////////
4912 // Function: NodePath::get_fog
4913 // Access: Published
4914 // Description: Returns the fog that has been set on this
4915 // particular node, or NULL if no fog has been set.
4916 // This is not necessarily the fog that will be
4917 // applied to the geometry at or below this level, as
4918 // another fog at a higher or lower level may
4919 // override.
4920 ////////////////////////////////////////////////////////////////////
4921 Fog *NodePath::
4922 get_fog() const {
4923  nassertr_always(!is_empty(), NULL);
4924  const RenderAttrib *attrib =
4925  node()->get_attrib(FogAttrib::get_class_slot());
4926  if (attrib != (const RenderAttrib *)NULL) {
4927  const FogAttrib *fa = DCAST(FogAttrib, attrib);
4928  return fa->get_fog();
4929  }
4930 
4931  return NULL;
4932 }
4933 
4934 ////////////////////////////////////////////////////////////////////
4935 // Function: NodePath::set_render_mode_wireframe
4936 // Access: Published
4937 // Description: Sets up the geometry at this level and below (unless
4938 // overridden) to render in wireframe mode.
4939 ////////////////////////////////////////////////////////////////////
4940 void NodePath::
4942  nassertv_always(!is_empty());
4943  const RenderModeAttrib *rma;
4944  node()->get_state()->get_attrib_def(rma);
4945  node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, rma->get_thickness(), rma->get_perspective()), priority);
4946 }
4947 
4948 ////////////////////////////////////////////////////////////////////
4949 // Function: NodePath::set_render_mode_filled
4950 // Access: Published
4951 // Description: Sets up the geometry at this level and below (unless
4952 // overridden) to render in filled (i.e. not wireframe)
4953 // mode.
4954 ////////////////////////////////////////////////////////////////////
4955 void NodePath::
4956 set_render_mode_filled(int priority) {
4957  nassertv_always(!is_empty());
4958  const RenderModeAttrib *rma;
4959  node()->get_state()->get_attrib_def(rma);
4960  node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, rma->get_thickness(), rma->get_perspective()), priority);
4961 }
4962 
4963 ////////////////////////////////////////////////////////////////////
4964 // Function: NodePath::set_render_mode_filled_wireframe
4965 // Access: Published
4966 // Description: Sets up the geometry at this level and below (unless
4967 // overridden) to render in filled, but overlay the
4968 // wireframe on top with a fixed color. This is useful
4969 // for debug visualizations.
4970 ////////////////////////////////////////////////////////////////////
4971 void NodePath::
4972 set_render_mode_filled_wireframe(const LColor &wireframe_color, int priority) {
4973  nassertv_always(!is_empty());
4974  const RenderModeAttrib *rma;
4975  node()->get_state()->get_attrib_def(rma);
4976  node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled_wireframe, rma->get_thickness(), rma->get_perspective(), wireframe_color), priority);
4977 }
4978 
4979 ////////////////////////////////////////////////////////////////////
4980 // Function: NodePath::set_render_mode_perspective
4981 // Access: Published
4982 // Description: Sets up the point geometry at this level and below to
4983 // render as perspective sprites (that is, billboarded
4984 // quads). The thickness, as specified with
4985 // set_render_mode_thickness(), is the width of each
4986 // point in 3-D units, unless it is overridden on a
4987 // per-vertex basis. This does not affect geometry
4988 // other than points.
4989 //
4990 // If you want the quads to be individually textured,
4991 // you should also set a TexGenAttrib::M_point_sprite on
4992 // the node.
4993 ////////////////////////////////////////////////////////////////////
4994 void NodePath::
4995 set_render_mode_perspective(bool perspective, int priority) {
4996  nassertv_always(!is_empty());
4997  const RenderModeAttrib *rma;
4998  node()->get_state()->get_attrib_def(rma);
4999  node()->set_attrib(RenderModeAttrib::make(rma->get_mode(), rma->get_thickness(), perspective, rma->get_wireframe_color()), priority);
5000 }
5001 
5002 ////////////////////////////////////////////////////////////////////
5003 // Function: NodePath::set_render_mode_thickness
5004 // Access: Published
5005 // Description: Sets up the point geometry at this level and below to
5006 // render as thick points (that is, billboarded
5007 // quads). The thickness is in pixels, unless
5008 // set_render_mode_perspective is also true, in which
5009 // case it is in 3-D units.
5010 //
5011 // If you want the quads to be individually textured,
5012 // you should also set a TexGenAttrib::M_point_sprite on
5013 // the node.
5014 ////////////////////////////////////////////////////////////////////
5015 void NodePath::
5016 set_render_mode_thickness(PN_stdfloat thickness, int priority) {
5017  nassertv_always(!is_empty());
5018  const RenderModeAttrib *rma;
5019  node()->get_state()->get_attrib_def(rma);
5020  node()->set_attrib(RenderModeAttrib::make(rma->get_mode(), thickness, rma->get_perspective(), rma->get_wireframe_color()), priority);
5021 }
5022 
5023 ////////////////////////////////////////////////////////////////////
5024 // Function: NodePath::set_render_mode
5025 // Access: Published
5026 // Description: Sets up the geometry at this level and below (unless
5027 // overridden) to render in the specified mode and with
5028 // the indicated line and/or point thickness.
5029 ////////////////////////////////////////////////////////////////////
5030 void NodePath::
5031 set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority) {
5032  nassertv_always(!is_empty());
5033 
5034  node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority);
5035 }
5036 
5037 ////////////////////////////////////////////////////////////////////
5038 // Function: NodePath::clear_render_mode
5039 // Access: Published
5040 // Description: Completely removes any render mode adjustment that
5041 // may have been set on this node via
5042 // set_render_mode_wireframe() or
5043 // set_render_mode_filled().
5044 ////////////////////////////////////////////////////////////////////
5045 void NodePath::
5047  nassertv_always(!is_empty());
5048  node()->clear_attrib(RenderModeAttrib::get_class_slot());
5049 }
5050 
5051 ////////////////////////////////////////////////////////////////////
5052 // Function: NodePath::has_render_mode
5053 // Access: Published
5054 // Description: Returns true if a render mode has been explicitly set
5055 // on this particular node via set_render_mode() (or
5056 // set_render_mode_wireframe() or
5057 // set_render_mode_filled()), false otherwise.
5058 ////////////////////////////////////////////////////////////////////
5059 bool NodePath::
5061  nassertr_always(!is_empty(), false);
5062  return node()->has_attrib(RenderModeAttrib::get_class_slot());
5063 }
5064 
5065 ////////////////////////////////////////////////////////////////////
5066 // Function: NodePath::get_render_mode
5067 // Access: Published
5068 // Description: Returns the render mode that has been specifically
5069 // set on this node via set_render_mode(), or
5070 // M_unchanged if nothing has been set.
5071 ////////////////////////////////////////////////////////////////////
5072 RenderModeAttrib::Mode NodePath::
5074  nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged);
5075  const RenderAttrib *attrib =
5076  node()->get_attrib(RenderModeAttrib::get_class_slot());
5077  if (attrib != (const RenderAttrib *)NULL) {
5078  const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
5079  return ta->get_mode();
5080  }
5081 
5082  return RenderModeAttrib::M_unchanged;
5083 }
5084 
5085 ////////////////////////////////////////////////////////////////////
5086 // Function: NodePath::get_render_mode_thickness
5087 // Access: Published
5088 // Description: Returns the render mode thickness that has been
5089 // specifically set on this node via set_render_mode(),
5090 // or 1.0 if nothing has been set.
5091 ////////////////////////////////////////////////////////////////////
5092 PN_stdfloat NodePath::
5094  nassertr_always(!is_empty(), 0.0f);
5095  const RenderAttrib *attrib =
5096  node()->get_attrib(RenderModeAttrib::get_class_slot());
5097  if (attrib != (const RenderAttrib *)NULL) {
5098  const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
5099  return ta->get_thickness();
5100  }
5101 
5102  return 1.0f;
5103 }
5104 
5105 ////////////////////////////////////////////////////////////////////
5106 // Function: NodePath::get_render_mode_perspective
5107 // Access: Published
5108 // Description: Returns the flag that has been set on this node via
5109 // set_render_mode_perspective(), or false if no flag
5110 // has been set.
5111 ////////////////////////////////////////////////////////////////////
5112 bool NodePath::
5114  nassertr_always(!is_empty(), 0.0f);
5115  const RenderAttrib *attrib =
5116  node()->get_attrib(RenderModeAttrib::get_class_slot());
5117  if (attrib != (const RenderAttrib *)NULL) {
5118  const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
5119  return ta->get_perspective();
5120  }
5121 
5122  return false;
5123 }
5124 
5125 ////////////////////////////////////////////////////////////////////
5126 // Function: NodePath::set_two_sided
5127 // Access: Published
5128 // Description: Specifically sets or disables two-sided rendering
5129 // mode on this particular node. If no other nodes
5130 // override, this will cause backfacing polygons to be
5131 // drawn (in two-sided mode, true) or culled (in
5132 // one-sided mode, false).
5133 ////////////////////////////////////////////////////////////////////
5134 void NodePath::
5135 set_two_sided(bool two_sided, int priority) {
5136  nassertv_always(!is_empty());
5137 
5138  CullFaceAttrib::Mode mode =
5139  two_sided ?
5140  CullFaceAttrib::M_cull_none :
5141  CullFaceAttrib::M_cull_clockwise;
5142 
5143  node()->set_attrib(CullFaceAttrib::make(mode), priority);
5144 }
5145 
5146 ////////////////////////////////////////////////////////////////////
5147 // Function: NodePath::clear_two_sided
5148 // Access: Published
5149 // Description: Completely removes any two-sided adjustment that
5150 // may have been set on this node via set_two_sided().
5151 // The geometry at this level and below will
5152 // subsequently be rendered either two-sided or
5153 // one-sided, according to whatever other nodes may have
5154 // had set_two_sided() on it, or according to the
5155 // initial state otherwise.
5156 ////////////////////////////////////////////////////////////////////
5157 void NodePath::
5159  nassertv_always(!is_empty());
5160  node()->clear_attrib(CullFaceAttrib::get_class_slot());
5161 }
5162 
5163 ////////////////////////////////////////////////////////////////////
5164 // Function: NodePath::has_two_sided
5165 // Access: Published
5166 // Description: Returns true if a two-sided adjustment has been
5167 // explicitly set on this particular node via
5168 // set_two_sided(). If this returns true, then
5169 // get_two_sided() may be called to determine which has
5170 // been set.
5171 ////////////////////////////////////////////////////////////////////
5172 bool NodePath::
5173 has_two_sided() const {
5174  nassertr_always(!is_empty(), false);
5175  return node()->has_attrib(CullFaceAttrib::get_class_slot());
5176 }
5177 
5178 ////////////////////////////////////////////////////////////////////
5179 // Function: NodePath::get_two_sided
5180 // Access: Published
5181 // Description: Returns true if two-sided rendering has been
5182 // specifically set on this node via set_two_sided(), or
5183 // false if one-sided rendering has been specifically
5184 // set, or if nothing has been specifically set. See
5185 // also has_two_sided(). This does not necessarily
5186 // imply that the geometry will or will not be rendered
5187 // two-sided, as there may be other nodes that override.
5188 ////////////////////////////////////////////////////////////////////
5189 bool NodePath::
5190 get_two_sided() const {
5191  nassertr_always(!is_empty(), false);
5192  const RenderAttrib *attrib =
5193  node()->get_attrib(CullFaceAttrib::get_class_slot());
5194  if (attrib != (const RenderAttrib *)NULL) {
5195  const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
5196  return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
5197  }
5198 
5199  return false;
5200 }
5201 
5202 ////////////////////////////////////////////////////////////////////
5203 // Function: NodePath::set_depth_test
5204 // Access: Published
5205 // Description: Specifically sets or disables the testing of the
5206 // depth buffer on this particular node. This is
5207 // normally on in the 3-d scene graph and off in the 2-d
5208 // scene graph; it should be on for rendering most 3-d
5209 // objects properly.
5210 ////////////////////////////////////////////////////////////////////
5211 void NodePath::
5212 set_depth_test(bool depth_test, int priority) {
5213  nassertv_always(!is_empty());
5214 
5215  DepthTestAttrib::PandaCompareFunc mode =
5216  depth_test ?
5217  DepthTestAttrib::M_less :
5218  DepthTestAttrib::M_none;
5219 
5220  node()->set_attrib(DepthTestAttrib::make(mode), priority);
5221 }
5222 
5223 ////////////////////////////////////////////////////////////////////
5224 // Function: NodePath::clear_depth_test
5225 // Access: Published
5226 // Description: Completely removes any depth-test adjustment that
5227 // may have been set on this node via set_depth_test().
5228 ////////////////////////////////////////////////////////////////////
5229 void NodePath::
5231  nassertv_always(!is_empty());
5232  node()->clear_attrib(DepthTestAttrib::get_class_slot());
5233 }
5234 
5235 ////////////////////////////////////////////////////////////////////
5236 // Function: NodePath::has_depth_test
5237 // Access: Published
5238 // Description: Returns true if a depth-test adjustment has been
5239 // explicitly set on this particular node via
5240 // set_depth_test(). If this returns true, then
5241 // get_depth_test() may be called to determine which has
5242 // been set.
5243 ////////////////////////////////////////////////////////////////////
5244 bool NodePath::
5246  nassertr_always(!is_empty(), false);
5247  return node()->has_attrib(DepthTestAttrib::get_class_slot());
5248 }
5249 
5250 ////////////////////////////////////////////////////////////////////
5251 // Function: NodePath::get_depth_test
5252 // Access: Published
5253 // Description: Returns true if depth-test rendering has been
5254 // specifically set on this node via set_depth_test(), or
5255 // false if depth-test rendering has been specifically
5256 // disabled. If nothing has been specifically set,
5257 // returns true. See also has_depth_test().
5258 ////////////////////////////////////////////////////////////////////
5259 bool NodePath::
5261  nassertr_always(!is_empty(), false);
5262  const RenderAttrib *attrib =
5263  node()->get_attrib(DepthTestAttrib::get_class_slot());
5264  if (attrib != (const RenderAttrib *)NULL) {
5265  const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
5266  return (dta->get_mode() != DepthTestAttrib::M_none);
5267  }
5268 
5269  return true;
5270 }
5271 
5272 ////////////////////////////////////////////////////////////////////
5273 // Function: NodePath::set_depth_write
5274 // Access: Published
5275 // Description: Specifically sets or disables the writing to the
5276 // depth buffer on this particular node. This is
5277 // normally on in the 3-d scene graph and off in the 2-d
5278 // scene graph; it should be on for rendering most 3-d
5279 // objects properly.
5280 ////////////////////////////////////////////////////////////////////
5281 void NodePath::
5282 set_depth_write(bool depth_write, int priority) {
5283  nassertv_always(!is_empty());
5284 
5285  DepthWriteAttrib::Mode mode =
5286  depth_write ?
5287  DepthWriteAttrib::M_on :
5288  DepthWriteAttrib::M_off;
5289 
5290  node()->set_attrib(DepthWriteAttrib::make(mode), priority);
5291 }
5292 
5293 ////////////////////////////////////////////////////////////////////
5294 // Function: NodePath::clear_depth_write
5295 // Access: Published
5296 // Description: Completely removes any depth-write adjustment that
5297 // may have been set on this node via set_depth_write().
5298 ////////////////////////////////////////////////////////////////////
5299 void NodePath::
5301  nassertv_always(!is_empty());
5302  node()->clear_attrib(DepthWriteAttrib::get_class_slot());
5303 }
5304 
5305 ////////////////////////////////////////////////////////////////////
5306 // Function: NodePath::has_depth_write
5307 // Access: Published
5308 // Description: Returns true if a depth-write adjustment has been
5309 // explicitly set on this particular node via
5310 // set_depth_write(). If this returns true, then
5311 // get_depth_write() may be called to determine which has
5312 // been set.
5313 ////////////////////////////////////////////////////////////////////
5314 bool NodePath::
5316  nassertr_always(!is_empty(), false);
5317  return node()->has_attrib(DepthWriteAttrib::get_class_slot());
5318 }
5319 
5320 ////////////////////////////////////////////////////////////////////
5321 // Function: NodePath::get_depth_write
5322 // Access: Published
5323 // Description: Returns true if depth-write rendering has been
5324 // specifically set on this node via set_depth_write(), or
5325 // false if depth-write rendering has been specifically
5326 // disabled. If nothing has been specifically set,
5327 // returns true. See also has_depth_write().
5328 ////////////////////////////////////////////////////////////////////
5329 bool NodePath::
5331  nassertr_always(!is_empty(), false);
5332  const RenderAttrib *attrib =
5333  node()->get_attrib(DepthWriteAttrib::get_class_slot());
5334  if (attrib != (const RenderAttrib *)NULL) {
5335  const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
5336  return (dta->get_mode() != DepthWriteAttrib::M_off);
5337  }
5338 
5339  return true;
5340 }
5341 
5342 ////////////////////////////////////////////////////////////////////
5343 // Function: NodePath::set_depth_offset
5344 // Access: Published
5345 // Description: This instructs the graphics driver to apply an
5346 // offset or bias to the generated depth values for
5347 // rendered polygons, before they are written to the
5348 // depth buffer. This can be used to shift polygons
5349 // forward slightly, to resolve depth conflicts, or
5350 // self-shadowing artifacts on thin objects.
5351 // The bias is always an integer number, and each
5352 // integer increment represents the smallest possible
5353 // increment in Z that is sufficient to completely
5354 // resolve two coplanar polygons. Positive numbers
5355 // are closer towards the camera.
5356 ////////////////////////////////////////////////////////////////////
5357 void NodePath::
5358 set_depth_offset(int bias, int priority) {
5359  nassertv_always(!is_empty());
5360 
5361  node()->set_attrib(DepthOffsetAttrib::make(bias), priority);
5362 }
5363 
5364 ////////////////////////////////////////////////////////////////////
5365 // Function: NodePath::clear_depth_offset
5366 // Access: Published
5367 // Description: Completely removes any depth-offset adjustment that
5368 // may have been set on this node via set_depth_offset().
5369 ////////////////////////////////////////////////////////////////////
5370 void NodePath::
5372  nassertv_always(!is_empty());
5373  node()->clear_attrib(DepthOffsetAttrib::get_class_slot());
5374 }
5375 
5376 ////////////////////////////////////////////////////////////////////
5377 // Function: NodePath::has_depth_offset
5378 // Access: Published
5379 // Description: Returns true if a depth-offset adjustment has been
5380 // explicitly set on this particular node via
5381 // set_depth_offset(). If this returns true, then
5382 // get_depth_offset() may be called to determine which has
5383 // been set.
5384 ////////////////////////////////////////////////////////////////////
5385 bool NodePath::
5387  nassertr_always(!is_empty(), false);
5388  return node()->has_attrib(DepthOffsetAttrib::get_class_slot());
5389 }
5390 
5391 ////////////////////////////////////////////////////////////////////
5392 // Function: NodePath::get_depth_offset
5393 // Access: Published
5394 // Description: Returns the depth offset value if it has been
5395 // specified using set_depth_offset, or 0 if not.
5396 ////////////////////////////////////////////////////////////////////
5397 int NodePath::
5399  nassertr_always(!is_empty(), 0);
5400  const RenderAttrib *attrib =
5401  node()->get_attrib(DepthOffsetAttrib::get_class_slot());
5402  if (attrib != (const RenderAttrib *)NULL) {
5403  const DepthOffsetAttrib *doa = DCAST(DepthOffsetAttrib, attrib);
5404  return doa->get_offset();
5405  }
5406 
5407  return 0;
5408 }
5409 
5410 ////////////////////////////////////////////////////////////////////
5411 // Function: NodePath::do_billboard_axis
5412 // Access: Published
5413 // Description: Performs a billboard-type rotate to the indicated
5414 // camera node, one time only, and leaves the object
5415 // rotated. This is similar in principle to heads_up().
5416 ////////////////////////////////////////////////////////////////////
5417 void NodePath::
5418 do_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
5419  nassertv_always(!is_empty());
5420 
5421  CPT(TransformState) transform = camera.get_transform(get_parent());
5422  const LMatrix4 &rel_mat = transform->get_mat();
5423 
5424  LVector3 up = LVector3::up();
5425  LVector3 rel_pos = -rel_mat.get_row3(3);
5426 
5427  LQuaternion quat;
5428  ::heads_up(quat, rel_pos, up);
5429  set_quat(quat);
5430 
5431  // Also slide the geometry towards the camera according to the
5432  // offset factor.
5433  if (offset != 0.0f) {
5434  LVector3 translate = rel_mat.get_row3(3);
5435  translate.normalize();
5436  translate *= offset;
5437  set_pos(translate);
5438  }
5439 }
5440 
5441 ////////////////////////////////////////////////////////////////////
5442 // Function: NodePath::do_billboard_point_eye
5443 // Access: Published
5444 // Description: Performs a billboard-type rotate to the indicated
5445 // camera node, one time only, and leaves the object
5446 // rotated. This is similar in principle to look_at(),
5447 // although the point_eye billboard effect cannot be
5448 // achieved using the ordinary look_at() call.
5449 ////////////////////////////////////////////////////////////////////
5450 void NodePath::
5451 do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
5452  nassertv_always(!is_empty());
5453 
5454  CPT(TransformState) transform = camera.get_transform(get_parent());
5455  const LMatrix4 &rel_mat = transform->get_mat();
5456 
5457  LVector3 up = LVector3::up() * rel_mat;
5458  LVector3 rel_pos = LVector3::forward() * rel_mat;
5459 
5460  LQuaternion quat;
5461  ::look_at(quat, rel_pos, up);
5462  set_quat(quat);
5463 
5464  // Also slide the geometry towards the camera according to the
5465  // offset factor.
5466  if (offset != 0.0f) {
5467  LVector3 translate = rel_mat.get_row3(3);
5468  translate.normalize();
5469  translate *= offset;
5470  set_pos(translate);
5471  }
5472 }
5473 
5474 ////////////////////////////////////////////////////////////////////
5475 // Function: NodePath::do_billboard_point_world
5476 // Access: Published
5477 // Description: Performs a billboard-type rotate to the indicated
5478 // camera node, one time only, and leaves the object
5479 // rotated. This is similar in principle to look_at().
5480 ////////////////////////////////////////////////////////////////////
5481 void NodePath::
5482 do_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
5483  nassertv_always(!is_empty());
5484 
5485  CPT(TransformState) transform = camera.get_transform(get_parent());
5486  const LMatrix4 &rel_mat = transform->get_mat();
5487 
5488  LVector3 up = LVector3::up();
5489  LVector3 rel_pos = -rel_mat.get_row3(3);
5490 
5491  LQuaternion quat;
5492  ::look_at(quat, rel_pos, up);
5493  set_quat(quat);
5494 
5495  // Also slide the geometry towards the camera according to the
5496  // offset factor.
5497  if (offset != 0.0f) {
5498  LVector3 translate = rel_mat.get_row3(3);
5499  translate.normalize();
5500  translate *= offset;
5501  set_pos(translate);
5502  }
5503 }
5504 
5505 ////////////////////////////////////////////////////////////////////
5506 // Function: NodePath::set_billboard_axis
5507 // Access: Published
5508 // Description: Puts a billboard transition on the node such that it
5509 // will rotate in two dimensions around the up axis,
5510 // towards a specified "camera" instead of to the
5511 // viewing camera.
5512 ////////////////////////////////////////////////////////////////////
5513 void NodePath::
5514 set_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
5515  nassertv_always(!is_empty());
5516  CPT(RenderEffect) billboard = BillboardEffect::make
5517  (LVector3::up(), false, true,
5518  offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
5519  node()->set_effect(billboard);
5520 }
5521 
5522 ////////////////////////////////////////////////////////////////////
5523 // Function: NodePath::set_billboard_point_eye
5524 // Access: Published
5525 // Description: Puts a billboard transition on the node such that it
5526 // will rotate in three dimensions about the origin,
5527 // keeping its up vector oriented to the top of the
5528 // camera, towards a specified "camera" instead of to
5529 // the viewing camera.
5530 ////////////////////////////////////////////////////////////////////
5531 void NodePath::
5532 set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
5533  nassertv_always(!is_empty());
5534  CPT(RenderEffect) billboard = BillboardEffect::make
5535  (LVector3::up(), true, false,
5536  offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
5537  node()->set_effect(billboard);
5538 }
5539 
5540 ////////////////////////////////////////////////////////////////////
5541 // Function: NodePath::set_billboard_point_world
5542 // Access: Published
5543 // Description: Puts a billboard transition on the node such that it
5544 // will rotate in three dimensions about the origin,
5545 // keeping its up vector oriented to the sky, towards a
5546 // specified "camera" instead of to the viewing camera.
5547 ////////////////////////////////////////////////////////////////////
5548 void NodePath::
5549 set_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
5550  nassertv_always(!is_empty());
5551  CPT(RenderEffect) billboard = BillboardEffect::make
5552  (LVector3::up(), false, false,
5553  offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
5554  node()->set_effect(billboard);
5555 }
5556 
5557 ////////////////////////////////////////////////////////////////////
5558 // Function: NodePath::clear_billboard
5559 // Access: Published
5560 // Description: Removes any billboard effect from the node.
5561 ////////////////////////////////////////////////////////////////////
5562 void NodePath::
5564  nassertv_always(!is_empty());
5565  node()->clear_effect(BillboardEffect::get_class_type());
5566 }
5567 
5568 ////////////////////////////////////////////////////////////////////
5569 // Function: NodePath::has_billboard
5570 // Access: Published
5571 // Description: Returns true if there is any billboard effect on
5572 // the node.
5573 ////////////////////////////////////////////////////////////////////
5574 bool NodePath::
5575 has_billboard() const {
5576  nassertr_always(!is_empty(), false);
5577  return node()->has_effect(BillboardEffect::get_class_type());
5578 }
5579 
5580 ////////////////////////////////////////////////////////////////////
5581 // Function: NodePath::set_compass
5582 // Access: Published
5583 // Description: Puts a compass effect on the node, so that it will
5584 // retain a fixed rotation relative to the reference
5585 // node (or render if the reference node is empty)
5586 // regardless of the transforms above it.
5587 ////////////////////////////////////////////////////////////////////
5588 void NodePath::
5589 set_compass(const NodePath &reference) {
5590  nassertv_always(!is_empty());
5591  node()->set_effect(CompassEffect::make(reference));
5592 }
5593 
5594 ////////////////////////////////////////////////////////////////////
5595 // Function: NodePath::clear_compass
5596 // Access: Published
5597 // Description: Removes any compass effect from the node.
5598 ////////////////////////////////////////////////////////////////////
5599 void NodePath::
5601  nassertv_always(!is_empty());
5602  node()->clear_effect(CompassEffect::get_class_type());
5603 }
5604 
5605 ////////////////////////////////////////////////////////////////////
5606 // Function: NodePath::has_compass
5607 // Access: Published
5608 // Description: Returns true if there is any compass effect on
5609 // the node.
5610 ////////////////////////////////////////////////////////////////////
5611 bool NodePath::
5612 has_compass() const {
5613  nassertr_always(!is_empty(), false);
5614  return node()->has_effect(CompassEffect::get_class_type());
5615 }
5616 
5617 ////////////////////////////////////////////////////////////////////
5618 // Function: NodePath::set_transparency
5619 // Access: Published
5620 // Description: Specifically sets or disables transparent rendering
5621 // mode on this particular node. If no other nodes
5622 // override, this will cause items with a non-1 value
5623 // for alpha color to be rendered partially transparent.
5624 ////////////////////////////////////////////////////////////////////
5625 void NodePath::
5626 set_transparency(TransparencyAttrib::Mode mode, int priority) {
5627  nassertv_always(!is_empty());
5628 
5629  node()->set_attrib(TransparencyAttrib::make(mode), priority);
5630 }
5631 
5632 ////////////////////////////////////////////////////////////////////
5633 // Function: NodePath::clear_transparency
5634 // Access: Published
5635 // Description: Completely removes any transparency adjustment that
5636 // may have been set on this node via set_transparency().
5637 // The geometry at this level and below will
5638 // subsequently be rendered either transparent or not,
5639 // to whatever other nodes may have had
5640 // set_transparency() on them.
5641 ////////////////////////////////////////////////////////////////////
5642 void NodePath::
5644  nassertv_always(!is_empty());
5645  node()->clear_attrib(TransparencyAttrib::get_class_slot());
5646 }
5647 
5648 ////////////////////////////////////////////////////////////////////
5649 // Function: NodePath::has_transparency
5650 // Access: Published
5651 // Description: Returns true if a transparent-rendering adjustment
5652 // has been explicitly set on this particular node via
5653 // set_transparency(). If this returns true, then
5654 // get_transparency() may be called to determine whether
5655 // transparency has been explicitly enabled or
5656 // explicitly disabled for this node.
5657 ////////////////////////////////////////////////////////////////////
5658 bool NodePath::
5660  nassertr_always(!is_empty(), false);
5661  return node()->has_attrib(TransparencyAttrib::get_class_slot());
5662 }
5663 
5664 ////////////////////////////////////////////////////////////////////
5665 // Function: NodePath::get_transparency
5666 // Access: Published
5667 // Description: Returns the transparent rendering that has been
5668 // specifically set on this node via set_transparency(), or
5669 // M_none if nontransparent rendering has been specifically
5670 // set, or if nothing has been specifically set. See
5671 // also has_transparency(). This does not necessarily
5672 // imply that the geometry will or will not be rendered
5673 // transparent, as there may be other nodes that override.
5674 ////////////////////////////////////////////////////////////////////
5675 TransparencyAttrib::Mode NodePath::
5677  nassertr_always(!is_empty(), TransparencyAttrib::M_none);
5678  const RenderAttrib *attrib =
5679  node()->get_attrib(TransparencyAttrib::get_class_slot());
5680  if (attrib != (const RenderAttrib *)NULL) {
5681  const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
5682  return ta->get_mode();
5683  }
5684 
5685  return TransparencyAttrib::M_none;
5686 }
5687 
5688 ////////////////////////////////////////////////////////////////////
5689 // Function: NodePath::set_antialias
5690 // Access: Published
5691 // Description: Specifies the antialiasing type that should be
5692 // applied at this node and below. See AntialiasAttrib.
5693 ////////////////////////////////////////////////////////////////////
5694 void NodePath::
5695 set_antialias(unsigned short mode, int priority) {
5696  nassertv_always(!is_empty());
5697 
5698  node()->set_attrib(AntialiasAttrib::make(mode), priority);
5699 }
5700 
5701 ////////////////////////////////////////////////////////////////////
5702 // Function: NodePath::clear_antialias
5703 // Access: Published
5704 // Description: Completely removes any antialias setting that
5705 // may have been set on this node via set_antialias().
5706 ////////////////////////////////////////////////////////////////////
5707 void NodePath::
5709  nassertv_always(!is_empty());
5710  node()->clear_attrib(AntialiasAttrib::get_class_slot());
5711 }
5712 
5713 ////////////////////////////////////////////////////////////////////
5714 // Function: NodePath::has_antialias
5715 // Access: Published
5716 // Description: Returns true if an antialias setting has been
5717 // explicitly mode on this particular node via
5718 // set_antialias(). If this returns true, then
5719 // get_antialias() may be called to determine what the
5720 // setting was.
5721 ////////////////////////////////////////////////////////////////////
5722 bool NodePath::
5723 has_antialias() const {
5724  nassertr_always(!is_empty(), false);
5725  return node()->has_attrib(AntialiasAttrib::get_class_slot());
5726 }
5727 
5728 ////////////////////////////////////////////////////////////////////
5729 // Function: NodePath::get_antialias
5730 // Access: Published
5731 // Description: Returns the antialias setting that has been
5732 // specifically set on this node via set_antialias(), or
5733 // M_none if no setting has been made.
5734 ////////////////////////////////////////////////////////////////////
5735 unsigned short NodePath::
5736 get_antialias() const {
5737  nassertr_always(!is_empty(), AntialiasAttrib::M_none);
5738  const RenderAttrib *attrib =
5739  node()->get_attrib(AntialiasAttrib::get_class_slot());
5740  if (attrib != (const RenderAttrib *)NULL) {
5741  const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib);
5742  return ta->get_mode();
5743  }
5744 
5745  return AntialiasAttrib::M_none;
5746 }
5747 
5748 ////////////////////////////////////////////////////////////////////
5749 // Function: NodePath::has_audio_volume
5750 // Access: Published
5751 // Description: Returns true if an audio volume has been applied
5752 // to the referenced node, false otherwise. It is still
5753 // possible that volume at this node might have been
5754 // scaled by an ancestor node.
5755 ////////////////////////////////////////////////////////////////////
5756 bool NodePath::
5758  nassertr_always(!is_empty(), false);
5759  return node()->has_attrib(AudioVolumeAttrib::get_class_slot());
5760 }
5761 
5762 ////////////////////////////////////////////////////////////////////
5763 // Function: NodePath::clear_audio_volume
5764 // Access: Published
5765 // Description: Completely removes any audio volume from the
5766 // referenced node. This is preferable to simply
5767 // setting the audio volume to identity, as it also
5768 // removes the overhead associated with having an audio
5769 // volume at all.
5770 ////////////////////////////////////////////////////////////////////
5771 void NodePath::
5773  nassertv_always(!is_empty());
5774  node()->clear_attrib(AudioVolumeAttrib::get_class_slot());
5775 }
5776 
5777 ////////////////////////////////////////////////////////////////////
5778 // Function: NodePath::set_audio_volume
5779 // Access: Published
5780 // Description: Sets the audio volume component of the transform
5781 ////////////////////////////////////////////////////////////////////
5782 void NodePath::
5783 set_audio_volume(PN_stdfloat volume, int priority) {
5784  nassertv_always(!is_empty());
5785 
5786  const RenderAttrib *attrib =
5787  node()->get_attrib(AudioVolumeAttrib::get_class_slot());
5788  if (attrib != (const RenderAttrib *)NULL) {
5789  priority = max(priority,
5790  node()->get_state()->get_override(AudioVolumeAttrib::get_class_slot()));
5791  CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib);
5792 
5793  // Modify the existing AudioVolumeAttrib to add the indicated
5794  // volume.
5795  node()->set_attrib(ava->set_volume(volume), priority);
5796 
5797  } else {
5798  // Create a new AudioVolumeAttrib for this node.
5799  node()->set_attrib(AudioVolumeAttrib::make(volume), priority);
5800  }
5801 }
5802 
5803 ////////////////////////////////////////////////////////////////////
5804 // Function: NodePath::set_audio_volume_off
5805 // Access: Published
5806 // Description: Disables any audio volume attribute inherited from
5807 // above. This is not the same thing as
5808 // clear_audio_volume(), which undoes any previous
5809 // set_audio_volume() operation on this node; rather,
5810 // this actively disables any set_audio_volume() that
5811 // might be inherited from a parent node.
5812 //
5813 // It is legal to specify a new volume on the same
5814 // node with a subsequent call to set_audio_volume();
5815 // this new scale will apply to lower nodes.
5816 ////////////////////////////////////////////////////////////////////
5817 void NodePath::
5818 set_audio_volume_off(int priority) {
5819  nassertv_always(!is_empty());
5820  node()->set_attrib(AudioVolumeAttrib::make_off(), priority);
5821 }
5822 
5823 ////////////////////////////////////////////////////////////////////
5824 // Function: NodePath::get_audio_volume
5825 // Access: Published
5826 // Description: Returns the complete audio volume that has been
5827 // applied to this node via a previous call to
5828 // set_audio_volume(), or 1. (identity) if no volume has
5829 // been applied to this particular node.
5830 ////////////////////////////////////////////////////////////////////
5831 PN_stdfloat NodePath::
5833  const RenderAttrib *attrib =
5834  node()->get_attrib(AudioVolumeAttrib::get_class_slot());
5835  if (attrib != (const RenderAttrib *)NULL) {
5836  const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
5837  return ava->get_volume();
5838  }
5839 
5840  return 1.0f;
5841 }
5842 
5843 ////////////////////////////////////////////////////////////////////
5844 // Function: NodePath::get_net_audio_volume
5845 // Access: Published
5846 // Description: Returns the complete audio volume for this node
5847 // taking highers nodes in the graph into account.
5848 ////////////////////////////////////////////////////////////////////
5849 PN_stdfloat NodePath::
5851  CPT(RenderState) net_state = get_net_state();
5852  const RenderAttrib *attrib = net_state->get_attrib(AudioVolumeAttrib::get_class_slot());
5853  if (attrib != (const RenderAttrib *)NULL) {
5854  const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
5855  if (ava != (const AudioVolumeAttrib *)NULL) {
5856  return ava->get_volume();
5857  }
5858  }
5859 
5860  return 1.0f;
5861 }
5862 
5863 ////////////////////////////////////////////////////////////////////
5864 // Function: NodePath::get_hidden_ancestor
5865 // Access: Published
5866 // Description: Returns the NodePath at or above the referenced node
5867 // that is hidden to the indicated camera(s), or an
5868 // empty NodePath if no ancestor of the referenced node
5869 // is hidden (and the node should be visible).
5870 ////////////////////////////////////////////////////////////////////
5872 get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const {
5873  int pipeline_stage = current_thread->get_pipeline_stage();
5874 
5875  NodePathComponent *comp;
5876  for (comp = _head;
5877  comp != (NodePathComponent *)NULL;
5878  comp = comp->get_next(pipeline_stage, current_thread)) {
5879  PandaNode *node = comp->get_node();
5880  if (node->is_overall_hidden() ||
5881  ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
5882  NodePath result;
5883  result._head = comp;
5884  return result;
5885  }
5886  }
5887 
5888  return not_found();
5889 }
5890 
5891 ////////////////////////////////////////////////////////////////////
5892 // Function: NodePath::stash
5893 // Access: Published
5894 // Description: Removes the referenced node (and the entire subgraph
5895 // below this node) from the scene graph in any normal
5896 // sense. The node will no longer be visible and is not
5897 // tested for collisions; furthermore, no normal scene
5898 // graph traversal will visit the node. The node's
5899 // bounding volume no longer contributes to its parent's
5900 // bounding volume.
5901 //
5902 // A stashed node cannot be located by a normal find()
5903 // operation (although a special find string can still
5904 // retrieve it).
5905 ////////////////////////////////////////////////////////////////////
5906 void NodePath::
5907 stash(int sort, Thread *current_thread) {
5908  nassertv_always(!is_singleton() && !is_empty());
5909  nassertv(verify_complete());
5910 
5911  int pipeline_stage = current_thread->get_pipeline_stage();
5912  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
5913  _head, sort, true, pipeline_stage,
5914  current_thread);
5915  nassertv(reparented);
5916 }
5917 
5918 ////////////////////////////////////////////////////////////////////
5919 // Function: NodePath::unstash
5920 // Access: Published
5921 // Description: Undoes the effect of a previous stash() on this
5922 // node: makes the referenced node (and the entire
5923 // subgraph below this node) once again part of the
5924 // scene graph.
5925 ////////////////////////////////////////////////////////////////////
5926 void NodePath::
5927 unstash(int sort, Thread *current_thread) {
5928  nassertv_always(!is_singleton() && !is_empty());
5929  nassertv(verify_complete());
5930 
5931  int pipeline_stage = current_thread->get_pipeline_stage();
5932  bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
5933  _head, sort, false, pipeline_stage,
5934  current_thread);
5935  nassertv(reparented);
5936 }
5937 
5938 ////////////////////////////////////////////////////////////////////
5939 // Function: NodePath::unstash_all
5940 // Access: Published
5941 // Description: Unstashes this node and all stashed child nodes.
5942 ////////////////////////////////////////////////////////////////////
5943 void NodePath::
5944 unstash_all(Thread *current_thread) {
5945  NodePathCollection stashed_descendents = find_all_matches("**/@@*");
5946  stashed_descendents.unstash();
5947  unstash(0, current_thread);
5948 }
5949 
5950 ////////////////////////////////////////////////////////////////////
5951 // Function: NodePath::get_stashed_ancestor
5952 // Access: Published
5953 // Description: Returns the NodePath at or above the referenced node
5954 // that is stashed, or an empty NodePath if no ancestor
5955 // of the referenced node is stashed (and the node should
5956 // be visible).
5957 ////////////////////////////////////////////////////////////////////
5959 get_stashed_ancestor(Thread *current_thread) const {
5960  NodePathComponent *comp = _head;
5961  if (comp != (NodePathComponent *)NULL) {
5962  int pipeline_stage = current_thread->get_pipeline_stage();
5963  NodePathComponent *next = comp->get_next(pipeline_stage, current_thread);
5964 
5965  while (next != (NodePathComponent *)NULL) {
5966  PandaNode *node = comp->get_node();
5967  PandaNode *parent_node = next->get_node();
5968 
5969  if (parent_node->find_stashed(node) >= 0) {
5970  NodePath result;
5971  result._head = comp;
5972  return result;
5973  }
5974 
5975  comp = next;
5976  next = next->get_next(pipeline_stage, current_thread);
5977  }
5978  }
5979 
5980  return not_found();
5981 }
5982 
5983 ////////////////////////////////////////////////////////////////////
5984 // Function: NodePath::verify_complete
5985 // Access: Published
5986 // Description: Returns true if all of the nodes described in the
5987 // NodePath are connected, or false otherwise.
5988 ////////////////////////////////////////////////////////////////////
5989 bool NodePath::
5990 verify_complete(Thread *current_thread) const {
5991  if (is_empty()) {
5992  return true;
5993  }
5994 
5995 #ifdef HAVE_THREADS
5996  if (Thread::is_true_threads()) {
5997  // In a threaded environment, we can't reliably test this, since a
5998  // sub-thread may be mucking with the NodePath's ancestry as we
5999  // try to validate it. NodePaths are inherently not thread-safe,
6000  // but generally that's not an issue.
6001  return true;
6002  }
6003 #endif // HAVE_THREADS
6004 
6005  PStatTimer timer(_verify_complete_pcollector);
6006 
6007  const NodePathComponent *comp = _head;
6008  nassertr(comp != (const NodePathComponent *)NULL, false);
6009 
6010  int pipeline_stage = current_thread->get_pipeline_stage();
6011 
6012  PandaNode *node = comp->get_node();
6013  nassertr(node != (const PandaNode *)NULL, false);
6014  int length = comp->get_length(pipeline_stage, current_thread);
6015 
6016  comp = comp->get_next(pipeline_stage, current_thread);
6017  length--;
6018  while (comp != (const NodePathComponent *)NULL) {
6019  PandaNode *next_node = comp->get_node();
6020  nassertr(next_node != (const PandaNode *)NULL, false);
6021 
6022  if (node->find_parent(next_node) < 0) {
6023  pgraph_cat.warning()
6024  << *this << " is incomplete; " << *node << " is not a child of "
6025  << *next_node << "\n";
6026  return false;
6027  }
6028 
6029  if (comp->get_length(pipeline_stage, current_thread) != length) {
6030  pgraph_cat.warning()
6031  << *this << " is incomplete; length at " << *next_node
6032  << " indicates " << comp->get_length(pipeline_stage, current_thread)
6033  << " while length at " << *node << " indicates " << length << "\n";
6034  return false;
6035  }
6036 
6037  node = next_node;
6038  comp = comp->get_next(pipeline_stage, current_thread);
6039  length--;
6040  }
6041 
6042  return true;
6043 }
6044 
6045 ////////////////////////////////////////////////////////////////////
6046 // Function: NodePath::premunge_scene
6047 // Access: Published
6048 // Description: Walks through the scene graph beginning at the bottom
6049 // node, and internally adjusts any GeomVertexFormats
6050 // for optimal rendering on the indicated GSG. If this
6051 // step is not done prior to rendering, the formats will
6052 // be optimized at render time instead, for a small
6053 // cost.
6054 //
6055 // It is not normally necessary to do this on a model
6056 // loaded directly from disk, since the loader will do
6057 // this by default.
6058 ////////////////////////////////////////////////////////////////////
6059 void NodePath::
6061  nassertv_always(!is_empty());
6062 
6063  CPT(RenderState) state = RenderState::make_empty();
6064  if (has_parent()) {
6065  state = get_parent().get_net_state();
6066  }
6067 
6068  SceneGraphReducer gr(gsg);
6069  gr.premunge(node(), state);
6070 }
6071 
6072 ////////////////////////////////////////////////////////////////////
6073 // Function: NodePath::prepare_scene
6074 // Access: Published
6075 // Description: Walks through the scene graph beginning at the bottom
6076 // node, and does whatever initialization is required to
6077 // render the scene properly with the indicated GSG. It
6078 // is not strictly necessary to call this, since the GSG
6079 // will initialize itself when the scene is rendered,
6080 // but this may take some of the overhead away from that
6081 // process.
6082 //
6083 // In particular, this will ensure that textures and
6084 // vertex buffers within the scene are loaded into
6085 // graphics memory.
6086 ////////////////////////////////////////////////////////////////////
6087 void NodePath::
6089  nassertv_always(!is_empty());
6090 
6091  node()->prepare_scene(gsg, get_net_state());
6092 }
6093 
6094 ////////////////////////////////////////////////////////////////////
6095 // Function: NodePath::show_bounds
6096 // Access: Published
6097 // Description: Causes the bounding volume of the bottom node and all
6098 // of its descendants (that is, the bounding volume
6099 // associated with the the bottom arc) to be rendered,
6100 // if possible. The rendering method is less than
6101 // optimal; this is intended primarily for debugging.
6102 ////////////////////////////////////////////////////////////////////
6103 void NodePath::
6105  nassertv_always(!is_empty());
6106  node()->set_effect(ShowBoundsEffect::make(false));
6107 }
6108 
6109 ////////////////////////////////////////////////////////////////////
6110 // Function: NodePath::show_tight_bounds
6111 // Access: Published
6112 // Description: Similar to show_bounds(), this draws a bounding box
6113 // representing the "tight" bounds of this node and all
6114 // of its descendants. The bounding box is recomputed
6115 // every frame by reexamining all of the vertices; this
6116 // is far from efficient, but this is intended for
6117 // debugging.
6118 ////////////////////////////////////////////////////////////////////
6119 void NodePath::
6121  nassertv_always(!is_empty());
6122  node()->set_effect(ShowBoundsEffect::make(true));
6123 }
6124 
6125 ////////////////////////////////////////////////////////////////////
6126 // Function: NodePath::hide_bounds
6127 // Access: Published
6128 // Description: Stops the rendering of the bounding volume begun with
6129 // show_bounds().
6130 ////////////////////////////////////////////////////////////////////
6131 void NodePath::
6133  nassertv_always(!is_empty());
6134  node()->clear_effect(ShowBoundsEffect::get_class_type());
6135 }
6136 
6137 ////////////////////////////////////////////////////////////////////
6138 // Function: NodePath::get_bounds
6139 // Access: Published
6140 // Description: Returns a newly-allocated bounding volume containing
6141 // the bottom node and all of its descendants. This is
6142 // the bounding volume on the bottom arc, converted to
6143 // the local coordinate space of the node.
6144 ////////////////////////////////////////////////////////////////////
6145 PT(BoundingVolume) NodePath::
6146 get_bounds(Thread *current_thread) const {
6147  nassertr_always(!is_empty(), new BoundingSphere);
6148  return node()->get_bounds(current_thread)->make_copy();
6149 }
6150 
6151 ////////////////////////////////////////////////////////////////////
6152 // Function: NodePath::force_recompute_bounds
6153 // Access: Published
6154 // Description: Forces the recomputing of all the bounding volumes at
6155 // every node in the subgraph beginning at this node and
6156 // below.
6157 //
6158 // This should not normally need to be called, since the
6159 // bounding volumes are supposed to be recomputed
6160 // automatically when necessary. It may be useful when
6161 // debugging, to verify that the bounding volumes have
6162 // not become inadvertently stale; it may also be useful
6163 // to force animated characters to update their bounding
6164 // volumes (which does not presently happen
6165 // automatically).
6166 ////////////////////////////////////////////////////////////////////
6167 void NodePath::
6168 force_recompute_bounds() {
6169  nassertv_always(!is_empty());
6170  r_force_recompute_bounds(node());
6171 }
6172 
6173 ////////////////////////////////////////////////////////////////////
6174 // Function: NodePath::write_bounds
6175 // Access: Published
6176 // Description: Writes a description of the bounding volume
6177 // containing the bottom node and all of its descendants
6178 // to the indicated output stream.
6179 ////////////////////////////////////////////////////////////////////
6180 void NodePath::
6181 write_bounds(ostream &out) const {
6182  get_bounds()->write(out);
6183 }
6184 
6185 ////////////////////////////////////////////////////////////////////
6186 // Function: NodePath::calc_tight_bounds
6187 // Access: Published
6188 // Description: Calculates the minimum and maximum vertices of all
6189 // Geoms at this NodePath's bottom node and below. This
6190 // is a tight bounding box; it will generally be tighter
6191 // than the bounding volume returned by get_bounds()
6192 // (but it is more expensive to compute).
6193 //
6194 // The return value is true if any points are within the
6195 // bounding volume, or false if none are.
6196 ////////////////////////////////////////////////////////////////////
6197 bool NodePath::
6198 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
6199  Thread *current_thread) const {
6200  min_point.set(0.0f, 0.0f, 0.0f);
6201  max_point.set(0.0f, 0.0f, 0.0f);
6202  nassertr_always(!is_empty(), false);
6203 
6204  bool found_any = false;
6205  node()->calc_tight_bounds(min_point, max_point, found_any,
6206  TransformState::make_identity(),
6207  current_thread);
6208 
6209  return found_any;
6210 }
6211 
6212 /*
6213 
6214 NB: Had to remove this function to avoid circular dependency when
6215 moving SceneGraphAnalyzer into pgraphnodes, attempting to reduce size
6216 of pgraph. This function is now defined as a Python extension
6217 function instead.
6218 
6219 ////////////////////////////////////////////////////////////////////
6220 // Function: NodePath::analyze
6221 // Access: Published
6222 // Description: Analyzes the geometry below this node and reports the
6223 // number of vertices, triangles, etc. This is the same
6224 // information reported by the bam-info program.
6225 ////////////////////////////////////////////////////////////////////
6226 void NodePath::
6227 analyze() const {
6228  nassertv_always(!is_empty());
6229  SceneGraphAnalyzer sga;
6230  sga.add_node(node());
6231 
6232  if (sga.get_num_lod_nodes() == 0) {
6233  sga.write(nout);
6234 
6235  } else {
6236  nout << "At highest LOD:\n";
6237  SceneGraphAnalyzer sga2;
6238  sga2.set_lod_mode(SceneGraphAnalyzer::LM_highest);
6239  sga2.add_node(node());
6240  sga2.write(nout);
6241 
6242  nout << "\nAt lowest LOD:\n";
6243  sga2.clear();
6244  sga2.set_lod_mode(SceneGraphAnalyzer::LM_lowest);
6245  sga2.add_node(node());
6246  sga2.write(nout);
6247 
6248  nout << "\nAll nodes:\n";
6249  sga.write(nout);
6250  }
6251 }
6252 */
6253 
6254 ////////////////////////////////////////////////////////////////////
6255 // Function: NodePath::flatten_light
6256 // Access: Published
6257 // Description: Lightly flattens out the hierarchy below this node by
6258 // applying transforms, colors, and texture matrices
6259 // from the nodes onto the vertices, but does not remove
6260 // any nodes.
6261 //
6262 // This can result in improved rendering performance
6263 // because there will be fewer transforms in the
6264 // resulting scene graph, but the number of nodes will
6265 // remain the same.
6266 //
6267 // In particular, any NodePaths that reference nodes
6268 // within this hierarchy will not be damaged. However,
6269 // since this operation will remove transforms from the
6270 // scene graph, it may be dangerous to apply to nodes
6271 // where you expect to dynamically modify the transform,
6272 // or where you expect the geometry to remain in a
6273 // particular local coordinate system.
6274 //
6275 // The return value is always 0, since flatten_light
6276 // does not remove any nodes.
6277 ////////////////////////////////////////////////////////////////////
6278 int NodePath::
6280  nassertr_always(!is_empty(), 0);
6281  SceneGraphReducer gr;
6282  gr.apply_attribs(node());
6283 
6284  return 0;
6285 }
6286 
6287 ////////////////////////////////////////////////////////////////////
6288 // Function: NodePath::flatten_medium
6289 // Access: Published
6290 // Description: A more thorough flattening than flatten_light(), this
6291 // first applies all the transforms, colors, and texture
6292 // matrices from the nodes onto the vertices, and then
6293 // removes unneeded grouping nodes--nodes that have
6294 // exactly one child, for instance, but have no special
6295 // properties in themselves.
6296 //
6297 // This results in improved performance over
6298 // flatten_light() because the number of nodes in the
6299 // scene graph is reduced.
6300 //
6301 // The return value is the number of nodes removed.
6302 ////////////////////////////////////////////////////////////////////
6303 int NodePath::
6305  nassertr_always(!is_empty(), 0);
6306  SceneGraphReducer gr;
6307  gr.apply_attribs(node());
6308  int num_removed = gr.flatten(node(), 0);
6309 
6310  if (flatten_geoms) {
6312  gr.collect_vertex_data(node());
6313  gr.unify(node(), true);
6314  }
6315 
6316  return num_removed;
6317 }
6318 
6319 ////////////////////////////////////////////////////////////////////
6320 // Function: NodePath::flatten_strong
6321 // Access: Published
6322 // Description: The strongest possible flattening. This first
6323 // applies all of the transforms to the vertices, as in
6324 // flatten_medium(), but then it will combine sibling
6325 // nodes together when possible, in addition to removing
6326 // unnecessary parent-child nodes. This can result in
6327 // substantially fewer nodes, but any nicely-grouped
6328 // hierachical bounding volumes may be lost.
6329 //
6330 // It is generally a good idea to apply this kind of
6331 // flattening only to nodes that will be culled largely
6332 // as a single unit, like a car. Applying this to an
6333 // entire scene may result in overall poorer performance
6334 // because of less-effective culling.
6335 ////////////////////////////////////////////////////////////////////
6336 int NodePath::
6338  nassertr_always(!is_empty(), 0);
6339  SceneGraphReducer gr;
6340  gr.apply_attribs(node());
6341  int num_removed = gr.flatten(node(), ~0);
6342 
6343  if (flatten_geoms) {
6345  gr.collect_vertex_data(node(), ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type));
6346  gr.unify(node(), false);
6347  }
6348 
6349  return num_removed;
6350 }
6351 
6352 ////////////////////////////////////////////////////////////////////
6353 // Function: NodePath::apply_texture_colors
6354 // Access: Published
6355 // Description: Removes textures from Geoms at this node and below by
6356 // applying the texture colors to the vertices. This is
6357 // primarily useful to simplify a low-LOD model. The
6358 // texture colors are replaced by flat colors that
6359 // approximate the original textures.
6360 //
6361 // Only the bottommost texture on each Geom is used (if
6362 // there is more than one), and it is applied as if it
6363 // were M_modulate, and WM_repeat, regardless of its
6364 // actual settings. If the texture has a
6365 // simple_ram_image, this may be used if the main image
6366 // isn't resident.
6367 //
6368 // After this call, there will be no texturing specified
6369 // at this level and below. Of course, there might
6370 // still be texturing inherited from above.
6371 ////////////////////////////////////////////////////////////////////
6372 void NodePath::
6374  nassertv_always(!is_empty());
6375  SceneGraphReducer gr;
6376  gr.apply_attribs(node(), SceneGraphReducer::TT_apply_texture_color | SceneGraphReducer::TT_tex_matrix | SceneGraphReducer::TT_other);
6377 }
6378 
6379 ////////////////////////////////////////////////////////////////////
6380 // Function: NodePath::find_net_tag
6381 // Access: Published
6382 // Description: Returns the lowest ancestor of this node that
6383 // contains a tag definition with the indicated key, if
6384 // any, or an empty NodePath if no ancestor of this node
6385 // contains this tag definition. See set_tag().
6386 ////////////////////////////////////////////////////////////////////
6388 find_net_tag(const string &key) const {
6389  if (is_empty()) {
6390  return NodePath::not_found();
6391  }
6392  if (has_tag(key)) {
6393  return *this;
6394  }
6395  return get_parent().find_net_tag(key);
6396 }
6397 
6398 ////////////////////////////////////////////////////////////////////
6399 // Function: NodePath::write_bam_file
6400 // Access: Published
6401 // Description: Writes the contents of this node and below out to a
6402 // bam file with the indicated filename. This file may
6403 // then be read in again, as is, at some later point.
6404 // Returns true if successful, false on some kind of
6405 // error.
6406 ////////////////////////////////////////////////////////////////////
6407 bool NodePath::
6408 write_bam_file(const Filename &filename) const {
6409  nassertr_always(!is_empty(), false);
6410 
6411  BamFile bam_file;
6412 
6413  bool okflag = false;
6414 
6415  if (bam_file.open_write(filename)) {
6416  if (bam_file.write_object(node())) {
6417  okflag = true;
6418  }
6419  bam_file.close();
6420  }
6421  return okflag;
6422 }
6423 
6424 ////////////////////////////////////////////////////////////////////
6425 // Function: NodePath::write_bam_stream
6426 // Access: Published
6427 // Description: Writes the contents of this node and below out to the
6428 // indicated stream.
6429 ////////////////////////////////////////////////////////////////////
6430 bool NodePath::
6431 write_bam_stream(ostream &out) const {
6432  nassertr_always(!is_empty(), false);
6433 
6434  BamFile bam_file;
6435 
6436  bool okflag = false;
6437 
6438  if (bam_file.open_write(out)) {
6439  if (bam_file.write_object(node())) {
6440  okflag = true;
6441  }
6442  bam_file.close();
6443  }
6444  return okflag;
6445 }
6446 
6447 ////////////////////////////////////////////////////////////////////
6448 // Function: NodePath::encode_to_bam_stream
6449 // Access: Published
6450 // Description: Converts the NodePath object into a single
6451 // stream of data using a BamWriter, and stores that
6452 // data in the indicated string. Returns true on
6453 // success, false on failure.
6454 //
6455 // If the BamWriter is NULL, this behaves the same way
6456 // as NodePath::write_bam_stream() and
6457 // PandaNode::encode_to_bam_stream(), in the sense that
6458 // it only writes this node and all nodes below it.
6459 //
6460 // However, if the BamWriter is not NULL, it behaves
6461 // very differently. In this case, it encodes the
6462 // *entire graph* of all nodes connected to the
6463 // NodePath, including all parent nodes and siblings.
6464 // This is necessary for correct streaming of related
6465 // NodePaths and restoration of instances, etc., but it
6466 // does mean you must detach() a node before writing it
6467 // if you want to limit the nodes that get written.
6468 //
6469 // This method is used by __reduce__ to handle streaming
6470 // of NodePaths to a pickle file. The BamWriter case is
6471 // used by the direct.stdpy.pickle module, while the
6472 // saner, non-BamWriter case is used when the standard
6473 // pickle module calls this function.
6474 ////////////////////////////////////////////////////////////////////
6475 bool NodePath::
6476 encode_to_bam_stream(string &data, BamWriter *writer) const {
6477  data.clear();
6478  ostringstream stream;
6479 
6480  DatagramOutputFile dout;
6481  if (!dout.open(stream)) {
6482  return false;
6483  }
6484 
6485  BamWriter local_writer;
6486  bool used_local_writer = false;
6487  if (writer == NULL) {
6488  // Create our own writer.
6489 
6490  if (!dout.write_header(_bam_header)) {
6491  return false;
6492  }
6493  writer = &local_writer;
6494  used_local_writer = true;
6495  }
6496 
6497  writer->set_target(&dout);
6498 
6499  int num_nodes = get_num_nodes();
6500  if (used_local_writer && num_nodes > 1) {
6501  // In this case--no BamWriter--we only write the bottom node.
6502  num_nodes = 1;
6503  }
6504 
6505  // Write an initial Datagram to represent the error type and
6506  // number of nodes.
6507  Datagram dg;
6508  dg.add_uint8(_error_type);
6509  dg.add_int32(num_nodes);
6510 
6511  if (!dout.put_datagram(dg)) {
6512  writer->set_target(NULL);
6513  return false;
6514  }
6515 
6516  // Now write the nodes, one at a time.
6517  for (int i = 0; i < num_nodes; ++i) {
6518  PandaNode *node = get_node(num_nodes - i - 1);
6519  nassertr(node != NULL, false);
6520  if (!writer->write_object(node)) {
6521  writer->set_target(NULL);
6522  return false;
6523  }
6524  }
6525  writer->set_target(NULL);
6526 
6527  data = stream.str();
6528  return true;
6529 }
6530 
6531 ////////////////////////////////////////////////////////////////////
6532 // Function: NodePath::decode_from_bam_stream
6533 // Access: Published, Static
6534 // Description: Reads the string created by a previous call to
6535 // encode_to_bam_stream(), and extracts and
6536 // returns the NodePath on that string. Returns NULL on
6537 // error.
6538 ////////////////////////////////////////////////////////////////////
6540 decode_from_bam_stream(const string &data, BamReader *reader) {
6541  NodePath result;
6542 
6543  istringstream stream(data);
6544 
6545  DatagramInputFile din;
6546  if (!din.open(stream)) {
6547  return NodePath::fail();
6548  }
6549 
6550  BamReader local_reader;
6551  if (reader == NULL) {
6552  // Create a local reader.
6553 
6554  string head;
6555  if (!din.read_header(head, _bam_header.size())) {
6556  return NodePath::fail();
6557  }
6558 
6559  if (head != _bam_header) {
6560  return NodePath::fail();
6561  }
6562 
6563  reader = &local_reader;
6564  }
6565 
6566  reader->set_source(&din);
6567 
6568  // One initial datagram to encode the error type, and the number of nodes.
6569  Datagram dg;
6570  if (!din.get_datagram(dg)) {
6571  return NodePath::fail();
6572  }
6573 
6574  DatagramIterator dgi(dg);
6575  ErrorType error_type = (ErrorType)dgi.get_uint8();
6576  int num_nodes = dgi.get_int32();
6577  if (num_nodes == 0) {
6578  // An empty NodePath.
6579  result._error_type = error_type;
6580 
6581  } else {
6582  // A real NodePath. Ignore error_type.
6583  for (int i = 0; i < num_nodes; ++i) {
6584  TypedWritable *object = reader->read_object();
6585 
6586  if (object == (TypedWritable *)NULL ||
6587  !object->is_of_type(PandaNode::get_class_type())) {
6588  reader->set_source(NULL);
6589  return NodePath::fail();
6590  }
6591 
6592  if (!reader->resolve()) {
6593  reader->set_source(NULL);
6594  return NodePath::fail();
6595  }
6596 
6597  PandaNode *node = DCAST(PandaNode, object);
6598  result = NodePath(result, node);
6599  }
6600  }
6601 
6602  reader->set_source(NULL);
6603 
6604  return result;
6605 }
6606 
6607 ////////////////////////////////////////////////////////////////////
6608 // Function: NodePath::find_common_ancestor
6609 // Access: Private, Static
6610 // Description: Walks up from both NodePaths to find the first node
6611 // that both have in common, if any. Fills a_count and
6612 // b_count with the number of nodes below the common
6613 // node in each path.
6614 //
6615 // The return value is the NodePathComponent of the node
6616 // they have in common, or NULL if they have nothing in
6617 // common.
6618 ////////////////////////////////////////////////////////////////////
6619 NodePathComponent *NodePath::
6620 find_common_ancestor(const NodePath &a, const NodePath &b,
6621  int &a_count, int &b_count, Thread *current_thread) {
6622  nassertr(!a.is_empty() && !b.is_empty(), NULL);
6623  NodePathComponent *ac = a._head;
6624  NodePathComponent *bc = b._head;
6625  a_count = 0;
6626  b_count = 0;
6627 
6628  int pipeline_stage = current_thread->get_pipeline_stage();
6629 
6630  // Shorten up the longer one until they are the same length.
6631  while (ac->get_length(pipeline_stage, current_thread) > bc->get_length(pipeline_stage, current_thread)) {
6632  nassertr(ac != (NodePathComponent *)NULL, NULL);
6633  ac = ac->get_next(pipeline_stage, current_thread);
6634  a_count++;
6635  }
6636  while (bc->get_length(pipeline_stage, current_thread) > ac->get_length(pipeline_stage, current_thread)) {
6637  nassertr(bc != (NodePathComponent *)NULL, NULL);
6638  bc = bc->get_next(pipeline_stage, current_thread);
6639  b_count++;
6640  }
6641 
6642  // Now shorten them both up until we reach the same component.
6643  while (ac != bc) {
6644  // These shouldn't go to NULL unless they both go there together.
6645  nassertr(ac != (NodePathComponent *)NULL, NULL);
6646  nassertr(bc != (NodePathComponent *)NULL, NULL);
6647  ac = ac->get_next(pipeline_stage, current_thread);
6648  a_count++;
6649  bc = bc->get_next(pipeline_stage, current_thread);
6650  b_count++;
6651  }
6652 
6653  return ac;
6654 }
6655 
6656 ////////////////////////////////////////////////////////////////////
6657 // Function: NodePath::r_get_net_state
6658 // Access: Private
6659 // Description: Recursively determines the net state changes to the
6660 // indicated component node from the root of the graph.
6661 ////////////////////////////////////////////////////////////////////
6662 CPT(RenderState) NodePath::
6663 r_get_net_state(NodePathComponent *comp, Thread *current_thread) const {
6664  if (comp == (NodePathComponent *)NULL) {
6665  return RenderState::make_empty();
6666  } else {
6667  CPT(RenderState) state = comp->get_node()->get_state(current_thread);
6668  int pipeline_stage = current_thread->get_pipeline_stage();
6669  return r_get_net_state(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(state);
6670  }
6671 }
6672 
6673 ////////////////////////////////////////////////////////////////////
6674 // Function: NodePath::r_get_partial_state
6675 // Access: Private
6676 // Description: Recursively determines the net state changes to the
6677 // indicated component node from the nth node above it.
6678 // If n exceeds the length of the path, this returns the
6679 // net transform from the root of the graph.
6680 ////////////////////////////////////////////////////////////////////
6681 CPT(RenderState) NodePath::
6682 r_get_partial_state(NodePathComponent *comp, int n,
6683  Thread *current_thread) const {
6684  if (n == 0 || comp == (NodePathComponent *)NULL) {
6685  return RenderState::make_empty();
6686  } else {
6687  CPT(RenderState) state = comp->get_node()->get_state(current_thread);
6688  int pipeline_stage = current_thread->get_pipeline_stage();
6689  return r_get_partial_state(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(state);
6690  }
6691 }
6692 
6693 ////////////////////////////////////////////////////////////////////
6694 // Function: NodePath::r_get_net_transform
6695 // Access: Private
6696 // Description: Recursively determines the net transform to the
6697 // indicated component node from the root of the graph.
6698 ////////////////////////////////////////////////////////////////////
6699 CPT(TransformState) NodePath::
6700 r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const {
6701  if (comp == (NodePathComponent *)NULL) {
6702  return TransformState::make_identity();
6703  } else {
6704  int pipeline_stage = current_thread->get_pipeline_stage();
6705  CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread);
6706  PandaNode *node = comp->get_node();
6707  CPT(TransformState) transform = node->get_transform(current_thread);
6708 
6709  CPT(RenderEffects) effects = node->get_effects(current_thread);
6710  if (effects->has_adjust_transform()) {
6711  effects->adjust_transform(net_transform, transform, node);
6712  }
6713 
6714  return net_transform->compose(transform);
6715  }
6716 }
6717 
6718 ////////////////////////////////////////////////////////////////////
6719 // Function: NodePath::r_get_partial_transform
6720 // Access: Private
6721 // Description: Recursively determines the net transform to the
6722 // indicated component node from the nth node above it.
6723 // If n exceeds the length of the path, this returns the
6724 // net transform from the root of the graph.
6725 //
6726 // If any node in the path had a net_transform effect
6727 // applied, returns NULL--in this case the partial
6728 // transform cannot be easily determined.
6729 ////////////////////////////////////////////////////////////////////
6730 CPT(TransformState) NodePath::
6731 r_get_partial_transform(NodePathComponent *comp, int n,
6732  Thread *current_thread) const {
6733  if (n == 0 || comp == (NodePathComponent *)NULL) {
6734  return TransformState::make_identity();
6735  } else {
6736  if (comp->get_node()->get_effects(current_thread)->has_adjust_transform()) {
6737  return NULL;
6738  }
6739  CPT(TransformState) transform = comp->get_node()->get_transform(current_thread);
6740  int pipeline_stage = current_thread->get_pipeline_stage();
6741  CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread);
6742  if (partial == (const TransformState *)NULL) {
6743  return NULL;
6744  }
6745  return partial->compose(transform);
6746  }
6747 }
6748 
6749 ////////////////////////////////////////////////////////////////////
6750 // Function: NodePath::r_get_net_prev_transform
6751 // Access: Private
6752 // Description: Recursively determines the net "previous" transform
6753 // to the indicated component node from the root of the
6754 // graph.
6755 ////////////////////////////////////////////////////////////////////
6756 CPT(TransformState) NodePath::
6757 r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const {
6758  if (comp == (NodePathComponent *)NULL) {
6759  return TransformState::make_identity();
6760  } else {
6761  CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
6762  int pipeline_stage = current_thread->get_pipeline_stage();
6763  return r_get_net_prev_transform(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(transform);
6764  }
6765 }
6766 
6767 ////////////////////////////////////////////////////////////////////
6768 // Function: NodePath::r_get_partial_prev_transform
6769 // Access: Private
6770 // Description: Recursively determines the net "previous" transform
6771 // to the indicated component node from the nth node
6772 // above it. If n exceeds the length of the path, this
6773 // returns the net previous transform from the root of
6774 // the graph.
6775 ////////////////////////////////////////////////////////////////////
6776 CPT(TransformState) NodePath::
6777 r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const {
6778  if (n == 0 || comp == (NodePathComponent *)NULL) {
6779  return TransformState::make_identity();
6780  } else {
6781  CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
6782  int pipeline_stage = current_thread->get_pipeline_stage();
6783  return r_get_partial_prev_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(transform);
6784  }
6785 }
6786 
6787 ////////////////////////////////////////////////////////////////////
6788 // Function: NodePath::find_matches
6789 // Access: Private
6790 // Description: Finds up to max_matches matches against the given
6791 // path string from this node and deeper. The
6792 // max_matches count indicates the maximum number of
6793 // matches to return, or -1 not to limit the number
6794 // returned.
6795 ////////////////////////////////////////////////////////////////////
6796 void NodePath::
6797 find_matches(NodePathCollection &result, const string &path,
6798  int max_matches) const {
6799  if (is_empty()) {
6800  pgraph_cat.warning()
6801  << "Attempt to extend an empty NodePath by '" << path
6802  << "'.\n";
6803  return;
6804  }
6805  FindApproxPath approx_path;
6806  if (approx_path.add_string(path)) {
6807  find_matches(result, approx_path, max_matches);
6808  }
6809 }
6810 
6811 ////////////////////////////////////////////////////////////////////
6812 // Function: NodePath::find_matches
6813 // Access: Private
6814 // Description: Finds up to max_matches matches against the given
6815 // approx_path from this node and deeper. The
6816 // max_matches count indicates the maximum number of
6817 // matches to return, or -1 not to limit the number
6818 // returned.
6819 ////////////////////////////////////////////////////////////////////
6820 void NodePath::
6821 find_matches(NodePathCollection &result, FindApproxPath &approx_path,
6822  int max_matches) const {
6823  if (is_empty()) {
6824  pgraph_cat.warning()
6825  << "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
6826  return;
6827  }
6828 
6829  // We start with just one entry on the level.
6830  FindApproxLevelEntry *level =
6831  new FindApproxLevelEntry(WorkingNodePath(*this), approx_path);
6832  nassertv(level->_node_path.is_valid());
6833 
6834  find_matches(result, level, max_matches);
6835 }
6836 
6837 ////////////////////////////////////////////////////////////////////
6838 // Function: NodePath::find_matches
6839 // Access: Private
6840 // Description: The fundamental implementation of find_matches(),
6841 // given a starting level (a linked list of
6842 // FindApproxLevelEntry objects).
6843 ////////////////////////////////////////////////////////////////////
6844 void NodePath::
6845 find_matches(NodePathCollection &result, FindApproxLevelEntry *level,
6846  int max_matches) const {
6847 
6848  int num_levels_remaining = _max_search_depth;
6849 
6850  FindApproxLevelEntry *deleted_entries = NULL;
6851 
6852  while (num_levels_remaining > 0 && level != NULL) {
6853  if (pgraph_cat.is_spam()) {
6854  pgraph_cat.spam()
6855  << "find_matches pass: " << result << ", "
6856  << max_matches << ", " << num_levels_remaining << "\n";
6857  level->write_level(pgraph_cat.spam(false), 4);
6858  }
6859 
6860  num_levels_remaining--;
6861 
6862  FindApproxLevelEntry *next_level = NULL;
6863 
6864  // For each node in the current level, build up the set of possible
6865  // matches in the next level.
6866  FindApproxLevelEntry *entry = level;
6867  while (entry != (FindApproxLevelEntry *)NULL) {
6868  if (entry->consider_node(result, next_level, max_matches, 0)) {
6869  // If we found the requisite number of matches, we can stop.
6870  // Delete all remaining entries and return immediately.
6871 
6872  while (entry != (FindApproxLevelEntry *)NULL) {
6873  FindApproxLevelEntry *next = entry->_next;
6874  delete entry;
6875  entry = next;
6876  }
6877  while (next_level != (FindApproxLevelEntry *)NULL) {
6878  FindApproxLevelEntry *next = next_level->_next;
6879  delete next_level;
6880  next_level = next;
6881  }
6882  while (deleted_entries != (FindApproxLevelEntry *)NULL) {
6883  FindApproxLevelEntry *next = deleted_entries->_next;
6884  delete deleted_entries;
6885  deleted_entries = next;
6886  }
6887  return;
6888  }
6889 
6890  // Move the entry to the delete chain so we can delete it before
6891  // we return from this method. (We can't delete it immediately,
6892  // because there might be WorkingNodePaths in the next_level
6893  // that reference the WorkingNodePath object within the entry.)
6894  FindApproxLevelEntry *next = entry->_next;
6895  entry->_next = deleted_entries;
6896  deleted_entries = entry;
6897 
6898  entry = next;
6899  }
6900 
6901  // Make sure the remaining entries from this level are added to
6902  // the delete chain.
6903  while (entry != (FindApproxLevelEntry *)NULL) {
6904  FindApproxLevelEntry *next = entry->_next;
6905  entry->_next = deleted_entries;
6906  deleted_entries = entry;
6907 
6908  entry = next;
6909  }
6910 
6911  level = next_level;
6912  }
6913 
6914  // Now it's safe to delete all entries on the delete chain.
6915  while (deleted_entries != (FindApproxLevelEntry *)NULL) {
6916  FindApproxLevelEntry *next = deleted_entries->_next;
6917  delete deleted_entries;
6918  deleted_entries = next;
6919  }
6920 }
6921 
6922 ////////////////////////////////////////////////////////////////////
6923 // Function: NodePath::r_clear_model_nodes
6924 // Access: Private
6925 // Description: The recursive implementation of
6926 // clear_model_nodes(). This walks through the
6927 // subgraph defined by the indicated node and below.
6928 ////////////////////////////////////////////////////////////////////
6929 int NodePath::
6930 r_clear_model_nodes(PandaNode *node) {
6931  int count = 0;
6932 
6933  if (node->is_of_type(ModelNode::get_class_type())) {
6934  ModelNode *mnode;
6935  DCAST_INTO_R(mnode, node, count);
6936  mnode->set_preserve_transform(ModelNode::PT_drop_node);
6937  ++count;
6938  }
6939 
6940  PandaNode::Children cr = node->get_children();
6941  int num_children = cr.get_num_children();
6942  for (int i = 0; i < num_children; i++) {
6943  count += r_clear_model_nodes(cr.get_child(i));
6944  }
6945 
6946  return count;
6947 }
6948 
6949 ////////////////////////////////////////////////////////////////////
6950 // Function: NodePath::r_adjust_all_priorities
6951 // Access: Private
6952 // Description: The recursive implementation of
6953 // adjust_all_priorities(). This walks through the
6954 // subgraph defined by the indicated node and below.
6955 ////////////////////////////////////////////////////////////////////
6956 void NodePath::
6957 r_adjust_all_priorities(PandaNode *node, int adjustment) {
6958  node->set_state(node->get_state()->adjust_all_priorities(adjustment));
6959  if (node->is_geom_node()) {
6960  GeomNode *gnode;
6961  DCAST_INTO_V(gnode, node);
6962 
6963  int num_geoms = gnode->get_num_geoms();
6964  for (int i = 0; i < num_geoms; i++) {
6965  gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment));
6966  }
6967  }
6968 
6969  PandaNode::Children cr = node->get_children();
6970  int num_children = cr.get_num_children();
6971  for (int i = 0; i < num_children; i++) {
6972  r_adjust_all_priorities(cr.get_child(i), adjustment);
6973  }
6974 }
6975 
6976 ////////////////////////////////////////////////////////////////////
6977 // Function: NodePath::r_force_recompute_bounds
6978 // Access: Private
6979 // Description:
6980 ////////////////////////////////////////////////////////////////////
6981 void NodePath::
6982 r_force_recompute_bounds(PandaNode *node) {
6983  if (node->is_geom_node()) {
6984  GeomNode *gnode;
6985  DCAST_INTO_V(gnode, node);
6986 
6987  int num_geoms = gnode->get_num_geoms();
6988  for (int i = 0; i < num_geoms; i++) {
6989  const Geom *geom = gnode->get_geom(i);
6990  geom->mark_bounds_stale();
6991  }
6992  }
6993 
6994  node->mark_bounds_stale();
6995 
6996  // Now consider children.
6997  PandaNode::Children cr = node->get_children();
6998  int num_children = cr.get_num_children();
6999  for (int i = 0; i < num_children; i++) {
7000  r_force_recompute_bounds(cr.get_child(i));
7001  }
7002 }
7003 
7004 ////////////////////////////////////////////////////////////////////
7005 // Function: NodePath::r_set_collide_mask
7006 // Access: Private
7007 // Description: Recursively applies the indicated collide mask to the
7008 // nodes at and below this node.
7009 ////////////////////////////////////////////////////////////////////
7010 void NodePath::
7011 r_set_collide_mask(PandaNode *node,
7012  CollideMask and_mask, CollideMask or_mask,
7013  TypeHandle node_type) {
7014  if (node->is_of_type(node_type)) {
7015  CollideMask into_collide_mask = node->get_into_collide_mask();
7016  into_collide_mask = (into_collide_mask & and_mask) | or_mask;
7017  node->set_into_collide_mask(into_collide_mask);
7018  }
7019 
7020  PandaNode::Children cr = node->get_children();
7021  int num_children = cr.get_num_children();
7022  for (int i = 0; i < num_children; i++) {
7023  r_set_collide_mask(cr.get_child(i), and_mask, or_mask, node_type);
7024  }
7025 }
7026 
7027 ////////////////////////////////////////////////////////////////////
7028 // Function: NodePath::r_has_vertex_column
7029 // Access: Private
7030 // Description:
7031 ////////////////////////////////////////////////////////////////////
7032 bool NodePath::
7033 r_has_vertex_column(PandaNode *node, const InternalName *name) const {
7034  if (node->is_geom_node()) {
7035  GeomNode *gnode;
7036  DCAST_INTO_R(gnode, node, false);
7037 
7038  int num_geoms = gnode->get_num_geoms();
7039  for (int i = 0; i < num_geoms; i++) {
7040  const Geom *geom = gnode->get_geom(i);
7041  CPT(GeomVertexData) vdata = geom->get_vertex_data();
7042  if (vdata->has_column(name)) {
7043  return true;
7044  }
7045  }
7046  }
7047 
7048  // Now consider children.
7049  PandaNode::Children cr = node->get_children();
7050  int num_children = cr.get_num_children();
7051  for (int i = 0; i < num_children; i++) {
7052  PandaNode *child = cr.get_child(i);
7053  if (r_has_vertex_column(child, name)) {
7054  return true;
7055  }
7056  }
7057 
7058  return false;
7059 }
7060 
7061 ////////////////////////////////////////////////////////////////////
7062 // Function: NodePath::r_find_all_vertex_columns
7063 // Access: Private
7064 // Description:
7065 ////////////////////////////////////////////////////////////////////
7066 void NodePath::
7067 r_find_all_vertex_columns(PandaNode *node,
7068  NodePath::InternalNames &vertex_columns) const {
7069  if (node->is_geom_node()) {
7070  GeomNode *gnode;
7071  DCAST_INTO_V(gnode, node);
7072 
7073  int num_geoms = gnode->get_num_geoms();
7074  for (int i = 0; i < num_geoms; ++i) {
7075  const Geom *geom = gnode->get_geom(i);
7076  const GeomVertexFormat *format = geom->get_vertex_data()->get_format();
7077  int num_arrays = format->get_num_arrays();
7078  for (int j = 0; j < num_arrays; ++j) {
7079  const GeomVertexArrayFormat *array = format->get_array(j);
7080  int num_columns = array->get_num_columns();
7081  for (int k = 0; k < num_columns; ++k) {
7082  const GeomVertexColumn *column = array->get_column(k);
7083  vertex_columns.insert(column->get_name());
7084  }
7085  }
7086  }
7087  }
7088 
7089  // Now consider children.
7090  PandaNode::Children cr = node->get_children();
7091  int num_children = cr.get_num_children();
7092  for (int i = 0; i < num_children; i++) {
7093  PandaNode *child = cr.get_child(i);
7094  r_find_all_vertex_columns(child, vertex_columns);
7095  }
7096 }
7097 
7098 ////////////////////////////////////////////////////////////////////
7099 // Function: NodePath::r_find_texture
7100 // Access: Private
7101 // Description:
7102 ////////////////////////////////////////////////////////////////////
7103 Texture *NodePath::
7104 r_find_texture(PandaNode *node, const RenderState *state,
7105  const GlobPattern &glob) const {
7106  if (node->is_geom_node()) {
7107  GeomNode *gnode;
7108  DCAST_INTO_R(gnode, node, NULL);
7109 
7110  int num_geoms = gnode->get_num_geoms();
7111  for (int i = 0; i < num_geoms; i++) {
7112  CPT(RenderState) geom_state =
7113  state->compose(gnode->get_geom_state(i));
7114 
7115  // Look for a TextureAttrib on the state.
7116  const RenderAttrib *attrib =
7117  geom_state->get_attrib(TextureAttrib::get_class_slot());
7118  if (attrib != (const RenderAttrib *)NULL) {
7119  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7120  for (int i = 0; i < ta->get_num_on_stages(); i++) {
7121  Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
7122  if (texture != (Texture *)NULL) {
7123  if (glob.matches(texture->get_name())) {
7124  return texture;
7125  }
7126  }
7127  }
7128  }
7129  }
7130  }
7131 
7132  // Now consider children.
7133  PandaNode::Children cr = node->get_children();
7134  int num_children = cr.get_num_children();
7135  for (int i = 0; i < num_children; i++) {
7136  PandaNode *child = cr.get_child(i);
7137  CPT(RenderState) next_state = state->compose(child->get_state());
7138 
7139  Texture *result = r_find_texture(child, next_state, glob);
7140  if (result != (Texture *)NULL) {
7141  return result;
7142  }
7143  }
7144 
7145  return NULL;
7146 }
7147 
7148 ////////////////////////////////////////////////////////////////////
7149 // Function: NodePath::r_find_all_textures
7150 // Access: Private
7151 // Description:
7152 ////////////////////////////////////////////////////////////////////
7153 void NodePath::
7154 r_find_all_textures(PandaNode *node, const RenderState *state,
7155  NodePath::Textures &textures) const {
7156  if (node->is_geom_node()) {
7157  GeomNode *gnode;
7158  DCAST_INTO_V(gnode, node);
7159 
7160  int num_geoms = gnode->get_num_geoms();
7161  for (int i = 0; i < num_geoms; i++) {
7162  CPT(RenderState) geom_state =
7163  state->compose(gnode->get_geom_state(i));
7164 
7165  // Look for a TextureAttrib on the state.
7166  const RenderAttrib *attrib =
7167  geom_state->get_attrib(TextureAttrib::get_class_slot());
7168  if (attrib != (const RenderAttrib *)NULL) {
7169  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7170  for (int i = 0; i < ta->get_num_on_stages(); i++) {
7171  Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
7172  if (texture != (Texture *)NULL) {
7173  textures.insert(texture);
7174  }
7175  }
7176  }
7177  }
7178  }
7179 
7180  // Now consider children.
7181  PandaNode::Children cr = node->get_children();
7182  int num_children = cr.get_num_children();
7183  for (int i = 0; i < num_children; i++) {
7184  PandaNode *child = cr.get_child(i);
7185  CPT(RenderState) next_state = state->compose(child->get_state());
7186  r_find_all_textures(child, next_state, textures);
7187  }
7188 }
7189 
7190 ////////////////////////////////////////////////////////////////////
7191 // Function: NodePath::r_find_texture
7192 // Access: Private
7193 // Description:
7194 ////////////////////////////////////////////////////////////////////
7195 Texture * NodePath::
7196 r_find_texture(PandaNode *node, TextureStage *stage) const {
7197  // Look for a TextureAttrib on the node.
7198  const RenderAttrib *attrib =
7199  node->get_attrib(TextureAttrib::get_class_slot());
7200  if (attrib != (const RenderAttrib *)NULL) {
7201  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7202  if (ta->has_on_stage(stage)) {
7203  return ta->get_on_texture(stage);
7204  }
7205  }
7206 
7207  if (node->is_geom_node()) {
7208  GeomNode *gnode;
7209  DCAST_INTO_R(gnode, node, NULL);
7210 
7211  int num_geoms = gnode->get_num_geoms();
7212  for (int i = 0; i < num_geoms; i++) {
7213  CPT(RenderState) geom_state = gnode->get_geom_state(i);
7214 
7215  // Look for a TextureAttrib on the state.
7216  const RenderAttrib *attrib =
7217  geom_state->get_attrib(TextureAttrib::get_class_slot());
7218  if (attrib != (const RenderAttrib *)NULL) {
7219  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7220  if (ta->has_on_stage(stage)) {
7221  return ta->get_on_texture(stage);
7222  }
7223  }
7224  }
7225  }
7226 
7227  // Now consider children.
7228  PandaNode::Children cr = node->get_children();
7229  int num_children = cr.get_num_children();
7230  for (int i = 0; i < num_children; i++) {
7231  PandaNode *child = cr.get_child(i);
7232 
7233  Texture *result = r_find_texture(child, stage);
7234  if (result != (Texture *)NULL) {
7235  return result;
7236  }
7237  }
7238 
7239  return NULL;
7240 }
7241 
7242 ////////////////////////////////////////////////////////////////////
7243 // Function: NodePath::r_find_all_textures
7244 // Access: Private
7245 // Description:
7246 ////////////////////////////////////////////////////////////////////
7247 void NodePath::
7248 r_find_all_textures(PandaNode *node, TextureStage *stage,
7249  NodePath::Textures &textures) const {
7250  // Look for a TextureAttrib on the node.
7251  const RenderAttrib *attrib =
7252  node->get_attrib(TextureAttrib::get_class_slot());
7253  if (attrib != (const RenderAttrib *)NULL) {
7254  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7255  if (ta->has_on_stage(stage)) {
7256  textures.insert(ta->get_on_texture(stage));
7257  }
7258  }
7259 
7260  if (node->is_geom_node()) {
7261  GeomNode *gnode;
7262  DCAST_INTO_V(gnode, node);
7263 
7264  int num_geoms = gnode->get_num_geoms();
7265  for (int i = 0; i < num_geoms; i++) {
7266  CPT(RenderState) geom_state = gnode->get_geom_state(i);
7267 
7268  // Look for a TextureAttrib on the state.
7269  const RenderAttrib *attrib =
7270  geom_state->get_attrib(TextureAttrib::get_class_slot());
7271  if (attrib != (const RenderAttrib *)NULL) {
7272  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7273  if (ta->has_on_stage(stage)) {
7274  textures.insert(ta->get_on_texture(stage));
7275  }
7276  }
7277  }
7278  }
7279 
7280  // Now consider children.
7281  PandaNode::Children cr = node->get_children();
7282  int num_children = cr.get_num_children();
7283  for (int i = 0; i < num_children; i++) {
7284  PandaNode *child = cr.get_child(i);
7285  r_find_all_textures(child, stage, textures);
7286  }
7287 }
7288 
7289 ////////////////////////////////////////////////////////////////////
7290 // Function: NodePath::r_find_texture_stage
7291 // Access: Private
7292 // Description:
7293 ////////////////////////////////////////////////////////////////////
7294 TextureStage * NodePath::
7295 r_find_texture_stage(PandaNode *node, const RenderState *state,
7296  const GlobPattern &glob) const {
7297  if (node->is_geom_node()) {
7298  GeomNode *gnode;
7299  DCAST_INTO_R(gnode, node, NULL);
7300 
7301  int num_geoms = gnode->get_num_geoms();
7302  for (int i = 0; i < num_geoms; i++) {
7303  CPT(RenderState) geom_state =
7304  state->compose(gnode->get_geom_state(i));
7305 
7306  // Look for a TextureAttrib on the state.
7307  const RenderAttrib *attrib =
7308  geom_state->get_attrib(TextureAttrib::get_class_slot());
7309  if (attrib != (const RenderAttrib *)NULL) {
7310  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7311  for (int i = 0; i < ta->get_num_on_stages(); i++) {
7312  TextureStage *texture_stage = ta->get_on_stage(i);
7313  if (texture_stage != (TextureStage *)NULL) {
7314  if (glob.matches(texture_stage->get_name())) {
7315  return texture_stage;
7316  }
7317  }
7318  }
7319  }
7320  }
7321  }
7322 
7323  // Now consider children.
7324  PandaNode::Children cr = node->get_children();
7325  int num_children = cr.get_num_children();
7326  for (int i = 0; i < num_children; i++) {
7327  PandaNode *child = cr.get_child(i);
7328  CPT(RenderState) next_state = state->compose(child->get_state());
7329 
7330  TextureStage *result = r_find_texture_stage(child, next_state, glob);
7331  if (result != (TextureStage *)NULL) {
7332  return result;
7333  }
7334  }
7335 
7336  return NULL;
7337 }
7338 
7339 ////////////////////////////////////////////////////////////////////
7340 // Function: NodePath::r_find_all_texture_stages
7341 // Access: Private
7342 // Description:
7343 ////////////////////////////////////////////////////////////////////
7344 void NodePath::
7345 r_find_all_texture_stages(PandaNode *node, const RenderState *state,
7346  NodePath::TextureStages &texture_stages) const {
7347  if (node->is_geom_node()) {
7348  GeomNode *gnode;
7349  DCAST_INTO_V(gnode, node);
7350 
7351  int num_geoms = gnode->get_num_geoms();
7352  for (int i = 0; i < num_geoms; i++) {
7353  CPT(RenderState) geom_state =
7354  state->compose(gnode->get_geom_state(i));
7355 
7356  // Look for a TextureAttrib on the state.
7357  const RenderAttrib *attrib =
7358  geom_state->get_attrib(TextureAttrib::get_class_slot());
7359  if (attrib != (const RenderAttrib *)NULL) {
7360  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7361  for (int i = 0; i < ta->get_num_on_stages(); i++) {
7362  TextureStage *texture_stage = ta->get_on_stage(i);
7363  if (texture_stage != (TextureStage *)NULL) {
7364  texture_stages.insert(texture_stage);
7365  }
7366  }
7367  }
7368  }
7369  }
7370 
7371  // Now consider children.
7372  PandaNode::Children cr = node->get_children();
7373  int num_children = cr.get_num_children();
7374  for (int i = 0; i < num_children; i++) {
7375  PandaNode *child = cr.get_child(i);
7376  CPT(RenderState) next_state = state->compose(child->get_state());
7377  r_find_all_texture_stages(child, next_state, texture_stages);
7378  }
7379 }
7380 
7381 ////////////////////////////////////////////////////////////////////
7382 // Function: NodePath::r_unify_texture_stages
7383 // Access: Private
7384 // Description:
7385 ////////////////////////////////////////////////////////////////////
7386 void NodePath::
7387 r_unify_texture_stages(PandaNode *node, TextureStage *stage) {
7388  // Look for a TextureAttrib on the state.
7389  const RenderAttrib *attrib =
7390  node->get_attrib(TextureAttrib::get_class_slot());
7391  if (attrib != (const RenderAttrib *)NULL) {
7392  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7393  CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
7394  if (new_attrib != ta) {
7395  node->set_attrib(new_attrib);
7396  }
7397  }
7398 
7399  if (node->is_geom_node()) {
7400  GeomNode *gnode;
7401  DCAST_INTO_V(gnode, node);
7402 
7403  int num_geoms = gnode->get_num_geoms();
7404  for (int i = 0; i < num_geoms; i++) {
7405  CPT(RenderState) state = gnode->get_geom_state(i);
7406 
7407  // Look for a TextureAttrib on the state.
7408  const RenderAttrib *attrib =
7409  state->get_attrib(TextureAttrib::get_class_slot());
7410  if (attrib != (const RenderAttrib *)NULL) {
7411  const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
7412  CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
7413  if (new_attrib != ta) {
7414  CPT(RenderState) new_state = state->add_attrib(new_attrib);
7415  gnode->set_geom_state(i, new_state);
7416  }
7417  }
7418  }
7419  }
7420 
7421  // Now consider children.
7422  PandaNode::Children cr = node->get_children();
7423  int num_children = cr.get_num_children();
7424  for (int i = 0; i < num_children; i++) {
7425  PandaNode *child = cr.get_child(i);
7426  r_unify_texture_stages(child, stage);
7427  }
7428 }
7429 
7430 ////////////////////////////////////////////////////////////////////
7431 // Function: NodePath::r_find_material
7432 // Access: Private
7433 // Description:
7434 ////////////////////////////////////////////////////////////////////
7435 Material *NodePath::
7436 r_find_material(PandaNode *node, const RenderState *state,
7437  const GlobPattern &glob) const {
7438  if (node->is_geom_node()) {
7439  GeomNode *gnode;
7440  DCAST_INTO_R(gnode, node, NULL);
7441 
7442  int num_geoms = gnode->get_num_geoms();
7443  for (int i = 0; i < num_geoms; i++) {
7444  CPT(RenderState) geom_state =
7445  state->compose(gnode->get_geom_state(i));
7446 
7447  // Look for a MaterialAttrib on the state.
7448  const RenderAttrib *attrib =
7449  geom_state->get_attrib(MaterialAttrib::get_class_slot());
7450  if (attrib != (const RenderAttrib *)NULL) {
7451  const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
7452  if (!ta->is_off()) {
7453  Material *material = ta->get_material();
7454  if (material != (Material *)NULL) {
7455  if (glob.matches(material->get_name())) {
7456  return material;
7457  }
7458  }
7459  }
7460  }
7461  }
7462  }
7463 
7464  // Now consider children.
7465  PandaNode::Children cr = node->get_children();
7466  int num_children = cr.get_num_children();
7467  for (int i = 0; i < num_children; i++) {
7468  PandaNode *child = cr.get_child(i);
7469  CPT(RenderState) next_state = state->compose(child->get_state());
7470 
7471  Material *result = r_find_material(child, next_state, glob);
7472  if (result != (Material *)NULL) {
7473  return result;
7474  }
7475  }
7476 
7477  return NULL;
7478 }
7479 
7480 ////////////////////////////////////////////////////////////////////
7481 // Function: NodePath::r_find_all_materials
7482 // Access: Private
7483 // Description:
7484 ////////////////////////////////////////////////////////////////////
7485 void NodePath::
7486 r_find_all_materials(PandaNode *node, const RenderState *state,
7487  NodePath::Materials &materials) const {
7488  if (node->is_geom_node()) {
7489  GeomNode *gnode;
7490  DCAST_INTO_V(gnode, node);
7491 
7492  int num_geoms = gnode->get_num_geoms();
7493  for (int i = 0; i < num_geoms; i++) {
7494  CPT(RenderState) geom_state =
7495  state->compose(gnode->get_geom_state(i));
7496 
7497  // Look for a MaterialAttrib on the state.
7498  const RenderAttrib *attrib =
7499  geom_state->get_attrib(MaterialAttrib::get_class_slot());
7500  if (attrib != (const RenderAttrib *)NULL) {
7501  const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
7502  if (!ta->is_off()) {
7503  Material *material = ta->get_material();
7504  if (material != (Material *)NULL) {
7505  materials.insert(material);
7506  }
7507  }
7508  }
7509  }
7510  }
7511 
7512  // Now consider children.
7513  PandaNode::Children cr = node->get_children();
7514  int num_children = cr.get_num_children();
7515  for (int i = 0; i < num_children; i++) {
7516  PandaNode *child = cr.get_child(i);
7517  CPT(RenderState) next_state = state->compose(child->get_state());
7518  r_find_all_materials(child, next_state, materials);
7519  }
7520 }
7521 
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:5927
The principle public interface to reading and writing Bam disk files.
Definition: bamFile.h:45
static const LQuaternionf & ident_quat()
Returns an identity quaternion.
Definition: lquaternion.h:851
const RenderState * get_geom_state(int n) const
Returns the RenderState associated with the nth geom of the node.
Definition: geomNode.I:106
string get_bin_name() const
Returns the name of the bin that this particular node was assigned to via set_bin(), or the empty string if no bin was assigned.
Definition: nodePath.cxx:3301
void clear_audio_volume()
Completely removes any audio volume from the referenced node.
Definition: nodePath.cxx:5772
CollideMask get_into_collide_mask() const
Returns the "into" collide mask for this node.
Definition: pandaNode.I:582
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:3636
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:5300
TransparencyAttrib::Mode get_transparency() const
Returns the transparent rendering that has been specifically set on this node via set_transparency()...
Definition: nodePath.cxx:5676
Fog * get_fog() const
If the FogAttrib is not an &#39;off&#39; FogAttrib, returns the fog that is associated.
Definition: fogAttrib.I:45
int get_num_children() const
Returns the number of children of the node.
Definition: pandaNode.I:1163
void add_match_pointer(PandaNode *pointer, int flags)
Adds a component that must match a particular node exactly, by pointer.
bool calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, Thread *current_thread=Thread::get_current_thread()) const
Calculates the minimum and maximum vertices of all Geoms at this NodePath&#39;s bottom node and below...
Definition: nodePath.cxx:6198
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:5158
bool matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:157
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:4205
int get_offset() const
Returns the depth offset represented by this attrib.
void set_audio_volume(PN_stdfloat volume, int priority=0)
Sets the audio volume component of the transform.
Definition: nodePath.cxx:5783
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes, or returns NULL if it is not.
Definition: pandaNode.cxx:2528
bool write_object(const TypedWritable *object)
Writes the indicated object to the Bam file.
Definition: bamFile.cxx:258
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:5212
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
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:5418
void add_texture_stage(TextureStage *node_texture_stage)
Adds a new TextureStage to the collection.
The abstract interface to all kinds of lights.
Definition: light.h:42
unsigned short get_mode() const
Returns the specified antialias mode.
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:4384
void clear_material()
Completely removes any material adjustment that may have been set via set_material() from this partic...
Definition: nodePath.cxx:4773
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:138
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
bool get_render_mode_perspective() const
Returns the flag that has been set on this node via set_render_mode_perspective(), or false if no flag has been set.
Definition: nodePath.cxx:5113
void set_color_scale_off(int priority=0)
Disables any color scale attribute inherited from above.
Definition: nodePath.cxx:2461
This is a const pointer to an InternalName, and should be used in lieu of a CPT(InternalName) in func...
Definition: internalName.h:197
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...
Mode get_mode() const
Returns the render mode.
void write_bounds(ostream &out) const
Writes a description of the bounding volume containing the bottom node and all of its descendants to ...
Definition: nodePath.cxx:6181
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
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:916
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:2926
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:5451
bool has_off_plane(const NodePath &plane) const
Returns true if the indicated plane is disabled by the attrib, false otherwise.
Enables or disables writing to the depth buffer.
Material * get_material() const
If the MaterialAttrib is not an &#39;off&#39; MaterialAttrib, returns the material that is associated...
void set_source(DatagramGenerator *source)
Changes the source of future datagrams for this BamReader.
Definition: bamReader.cxx:75
int get_num_stashed(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of stashed nodes this node has.
Definition: pandaNode.I:176
bool has_occluder(const NodePath &occluder) const
Returns true if the indicated occluder has been specifically applied to this particular node...
Definition: nodePath.cxx:3115
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
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:4956
const LColor & get_color() const
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
Definition: colorAttrib.I:58
bool has_fog_off() const
Returns true if a fog has been specifically disabled on this particular node via set_fog_off(), false otherwise.
Definition: nodePath.cxx:4899
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:905
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:2212
int get_instance_count() const
Returns the geometry instance count, or 0 if disabled.
Definition: nodePath.cxx:3864
Material * find_material(const string &name) const
Returns the first material found applied to geometry at this node or below that matches the indicated...
Definition: nodePath.cxx:4680
NodePath()
This constructs an empty NodePath with no nodes.
Definition: nodePath.I:22
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:5282
int get_instance_count() const
Returns the number of geometry instances.
Definition: shaderAttrib.I:102
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:5386
bool has_color() const
Returns true if a color has been applied to the given node, false otherwise.
Definition: nodePath.cxx:2326
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
int get_pipeline_stage() const
Returns the Pipeline stage number associated with this thread.
Definition: thread.I:84
void clear_bin()
Completely removes any bin adjustment that may have been set via set_bin() from this particular node...
Definition: nodePath.cxx:3275
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:359
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:5398
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
Indicates which, if any, material should be applied to geometry.
DrawMask get_draw_control_mask() const
Returns the set of bits in draw_show_mask that are considered meaningful.
Definition: pandaNode.I:559
const LVecBase4 & get_scale() const
Returns the scale to be applied to colors.
This class is local to this package only; it doesn&#39;t get exported.
Enables or disables writing to the depth buffer.
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:2475
Texture * find_texture(const string &name) const
Returns the first texture found applied to geometry at this node or below that matches the indicated ...
Definition: nodePath.cxx:4505
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:2338
Specifies whether or how to enable antialiasing, if supported by the backend renderer.
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:2536
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:2835
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:5959
bool has_audio_volume() const
Returns true if an audio volume has been applied to the referenced node, false otherwise.
Definition: nodePath.cxx:5757
void unstash()
Unstashes all NodePaths in the collection.
bool is_empty() const
Returns true if there are no NodePaths in the collection, false otherwise.
TypedWritable * read_object()
Reads a single object from the Bam file.
Definition: bamReader.cxx:249
This class can be used to read a binary file that consists of an arbitrary header followed by a numbe...
This controls the enabling of transparency.
bool has_all_off() const
Returns true if this attrib disables all planes (although it may also enable some).
MaterialCollection find_all_materials() const
Returns a list of a materials applied to geometry at this node and below.
Definition: nodePath.cxx:4693
This defines a bounding sphere, consisting of a center and a radius.
void set_audio_volume_off(int priority=0)
Disables any audio volume attribute inherited from above.
Definition: nodePath.cxx:5818
static bool is_true_threads()
Returns true if a real threading library is available that supports actual OS-implemented threads...
Definition: thread.I:201
void clear_billboard()
Removes any billboard effect from the node.
Definition: nodePath.cxx:5563
bool has_tag(const 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:2501
Mode get_mode() const
Returns the transparency mode.
void set_instance_count(int instance_count)
Sets the geometry instance count, or 0 if geometry instancing should be disabled. ...
Definition: nodePath.cxx:3904
void set_scale(PN_stdfloat scale)
Sets the scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.I:848
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
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:5872
bool write_header(const string &header)
Writes a sequence of bytes to the beginning of the datagram file.
This class is local to this package only; it doesn&#39;t get exported.
An interface for simplifying ("flattening") scene graphs by eliminating unneeded nodes and collapsing...
void clear_tex_gen()
Removes the texture coordinate generation mode from all texture stages on this node.
Definition: nodePath.cxx:4146
bool has_on_occluder(const NodePath &occluder) const
Returns true if the indicated occluder is enabled by the effect, false otherwise. ...
NodePath instance_under_node(const NodePath &other, const 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:670
Definition: shader.h:50
void apply_texture_colors()
Removes textures from Geoms at this node and below by applying the texture colors to the vertices...
Definition: nodePath.cxx:6373
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:496
void hide_bounds()
Stops the rendering of the bounding volume begun with show_bounds().
Definition: nodePath.cxx:6132
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:5031
void show_bounds()
Causes the bounding volume of the bottom node and all of its descendants (that is, the bounding volume associated with the the bottom arc) to be rendered, if possible.
Definition: nodePath.cxx:6104
void set_target(DatagramSink *target)
Changes the destination of future datagrams written by the BamWriter.
Definition: bamWriter.cxx:76
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:1443
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
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:2392
bool has_fog() const
Returns true if a fog has been applied to this particular node via set_fog(), false otherwise...
Definition: nodePath.cxx:4876
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
This functions similarly to a LightAttrib.
int get_draw_order() const
Returns the draw order this attribute specifies.
Definition: cullBinAttrib.I:48
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:1412
void add_material(Material *node_material)
Adds a new Material to the collection.
bool has_billboard() const
Returns true if there is any billboard effect on the node.
Definition: nodePath.cxx:5575
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
This is a small container class that can hold any one of the value types that can be passed as input ...
Definition: shaderInput.h:41
NodePath get_ancestor(int index, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth ancestor of the path, where 0 is the NodePath itself and get_num_nodes() - 1 is get_t...
Definition: nodePath.cxx:287
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:56
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:618
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:5230
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:2270
void add_texture(Texture *texture)
Adds a new Texture to the collection.
int get_num_geoms() const
Returns the number of geoms in the node.
Definition: geomNode.I:46
void write_level(ostream &out, int indent_level) const
Writes the entire level (a linked list of entries beginning at this entry).
PN_int32 get_int32()
Extracts a signed 32-bit integer.
bool has_material() const
Returns true if a material has been applied to this particular node via set_material(), false otherwise.
Definition: nodePath.cxx:4785
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
PandaNode * get_node() const
Returns the node referenced by this component.
void unify_texture_stages(TextureStage *stage)
Searches through all TextureStages at this node and below.
Definition: nodePath.cxx:4640
void clear_transparency()
Completely removes any transparency adjustment that may have been set on this node via set_transparen...
Definition: nodePath.cxx:5643
bool get_perspective() const
Returns the perspective flag.
bool open(const FileReference *file)
Opens the indicated filename for reading.
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:5093
This is a class designed to support low-overhead traversals of the complete scene graph...
virtual bool get_datagram(Datagram &data)
Reads the next datagram from the file.
Type get_color_type() const
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.I:46
bool is_overall_hidden() const
Returns true if the node has been hidden to all cameras by clearing its overall bit.
Definition: pandaNode.I:524
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:5589
bool read_header(string &header, size_t num_bytes)
Reads a sequence of bytes from the beginning of the datagram file.
bool has_tex_projector(TextureStage *stage) const
Returns true if this node has a TexProjectorEffect for the indicated stage, false otherwise...
Definition: nodePath.cxx:4297
RenderModeAttrib::Mode get_render_mode() const
Returns the render mode that has been specifically set on this node via set_render_mode(), or M_unchanged if nothing has been set.
Definition: nodePath.cxx:5073
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:4743
bool has_antialias() const
Returns true if an antialias setting has been explicitly mode on this particular node via set_antiali...
Definition: nodePath.cxx:5723
void clear_scissor()
Removes the scissor region that was defined at this node level by a previous call to set_scissor()...
Definition: nodePath.cxx:3219
void close()
Closes the input or output stream.
Definition: bamFile.cxx:277
Mode get_mode() const
Returns the depth write mode.
This defines how a single column is interleaved within a vertex array stored within a Geom...
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:1503
TextureCollection find_all_textures() const
Returns a list of a textures applied to geometry at this node and below.
Definition: nodePath.cxx:4532
NodePath find_net_tag(const string &key) const
Returns the lowest ancestor of this node that contains a tag definition with the indicated key...
Definition: nodePath.cxx:6388
bool open(const FileReference *file)
Opens the indicated filename for writing.
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Changes the complete transform object on this node.
Definition: nodePath.I:718
A PolylightEffect can be used on a node to define a LightGroup for that node.
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:3346
static LVector3f forward(CoordinateSystem cs=CS_default)
Returns the forward vector for the given coordinate system.
Definition: lvector3.h:579
NodePathCollection get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the set of all child nodes of the referenced node.
Definition: nodePath.cxx:343
LVector3 get_pos_delta() const
Returns the delta vector from this node&#39;s position in the previous frame (according to set_prev_trans...
Definition: nodePath.cxx:1198
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:34
Indicates which faces should be culled based on their vertex ordering.
PandaNode * get_stashed(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth stashed child of this node.
Definition: pandaNode.I:191
bool is_stashed() const
Returns true if the referenced node is stashed either directly, or because some ancestor is stashed...
Definition: nodePath.I:2312
bool has_light_off() const
Returns true if all Lights have been specifically disabled on this particular node.
Definition: nodePath.cxx:2782
const SamplerState & get_on_sampler(TextureStage *stage) const
Returns the sampler associated with the indicated stage, or the one associated with its texture if no...
void prepare_scene(GraphicsStateGuardianBase *gsg)
Walks through the scene graph beginning at the bottom node, and does whatever initialization is requi...
Definition: nodePath.cxx:6088
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void output(ostream &out) const
Writes a sensible description of the NodePath to the indicated output stream.
Definition: nodePath.cxx:820
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:5016
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:2745
void clear_light()
Completely removes any lighting operations that may have been set via set_light() or set_light_off() ...
Definition: nodePath.cxx:2686
Applies a Fog to the geometry at and below this node.
Definition: fogAttrib.h:27
void reset_prev_transform(Thread *current_thread=Thread::get_current_thread())
Resets the transform that represents this node&#39;s "previous" position to the same as the current trans...
Definition: pandaNode.cxx:1336
bool has_texture() const
Returns true if a texture has been applied to this particular node via set_texture(), false otherwise.
Definition: nodePath.cxx:3548
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:5371
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:307
A lightweight class that represents a single element that may be timed and/or counted via stats...
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:3987
DrawMask get_draw_show_mask() const
Returns the hide/show bits of this particular node.
Definition: pandaNode.I:571
void premunge_scene(GraphicsStateGuardianBase *gsg=NULL)
Walks through the scene graph beginning at the bottom node, and internally adjusts any GeomVertexForm...
Definition: nodePath.cxx:6060
Texture * get_on_texture(TextureStage *stage) const
Returns the texture associated with the indicated stage, or NULL if no texture is associated...
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.
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:4396
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:2628
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:3043
NodePath find(const string &path) const
Searches for a node below the referenced node that matches the indicated string.
Definition: nodePath.cxx:434
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:523
virtual bool put_datagram(const Datagram &data)
Writes the given datagram to the file.
void set_fog_off(int priority=0)
Sets the geometry at this level and below to render using no fog.
Definition: nodePath.cxx:4845
NodePathCollection get_stashed_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the set of all child nodes of the referenced node that have been stashed. ...
Definition: nodePath.cxx:372
PN_stdfloat get_thickness() const
Returns the line width or point thickness.
bool is_top_node(int pipeline_stage, Thread *current_thread) const
Returns true if this component represents the top node in the path.
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:5990
This node is placed at key points within the scene graph to indicate the roots of "models": subtrees ...
Definition: modelNode.h:34
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:993
void add_match_many(int flags)
Adds a component that will match a chain of zero or more consecutive nodes.
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:3322
static NodePath fail()
Creates a NodePath with the ET_fail error type set.
Definition: nodePath.I:185
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:4922
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:3143
void unstash_all(Thread *current_thread=Thread::get_current_thread())
Unstashes this node and all stashed child nodes.
Definition: nodePath.cxx:5944
void set_bin(const 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:3263
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
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:1473
bool has_effect(TypeHandle type) const
Returns true if there is a render effect of the indicated type defined on this node, or false if there is not.
Definition: nodePath.I:648
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:723
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
void unify(PandaNode *root, bool preserve_order)
Calls unify() on every GeomNode at this level and below.
void set_quat(const LQuaternion &quat)
Sets the rotation component of the transform, leaving translation and scale untouched.
Definition: nodePath.cxx:1267
static NodePath decode_from_bam_stream(const string &data, BamReader *reader=NULL)
Reads the string created by a previous call to encode_to_bam_stream(), and extracts and returns the N...
Definition: nodePath.cxx:6540
This functions similarly to a LightAttrib or ClipPlaneAttrib.
Specifies how atmospheric fog effects are applied to geometry.
Definition: fog.h:46
bool has_color_scale() const
Returns true if a color scale has been applied to the referenced node, false otherwise.
Definition: nodePath.cxx:2364
unsigned short get_antialias() const
Returns the antialias setting that has been specifically set on this node via set_antialias(), or M_none if no setting has been made.
Definition: nodePath.cxx:5736
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:72
void show_tight_bounds()
Similar to show_bounds(), this draws a bounding box representing the "tight" bounds of this node and ...
Definition: nodePath.cxx:6120
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:5046
NodePathComponent * get_next(int pipeline_stage, Thread *current_thread) const
Returns the next component in the path.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
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:5695
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:54
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:111
bool is_singleton(Thread *current_thread=Thread::get_current_thread()) const
Returns true if the NodePath contains exactly one node.
Definition: nodePath.I:247
bool has_on_stage(TextureStage *stage) const
Returns true if the indicated stage is turned on by the attrib, false otherwise.
A container for geometry primitives.
Definition: geom.h:58
void set_state(const RenderState *state, Thread *current_thread=Thread::get_current_thread())
Sets the complete RenderState that will be applied to all nodes at this level and below...
Definition: pandaNode.cxx:1216
bool has_on_plane(const NodePath &plane) const
Returns true if the indicated plane is enabled by the attrib, false otherwise.
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, without (much) affecting alpha.
Definition: nodePath.cxx:2505
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:6408
PN_stdfloat get_volume() const
Returns the volume to be applied to sounds.
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...
Texture * get_texture() const
If the TextureAttrib is not an &#39;off&#39; TextureAttrib, returns the base-level texture that is associated...
Definition: textureAttrib.I:76
This class specializes ConfigVariable as an enumerated type.
Manages a list of Texture objects, as returned by TexturePool::find_all_textures().
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:152
void clear_color_scale()
Completely removes any color scale from the referenced node.
Definition: nodePath.cxx:2379
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: pandaNode.cxx:1174
void set_into_collide_mask(CollideMask mask)
Sets the "into" CollideMask.
Definition: pandaNode.cxx:2037
TextureStage * get_on_stage(int n) const
Returns the nth stage turned on by the attribute, sorted in render order.
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:691
LVecBase3 get_hpr() const
Retrieves the rotation component of the transform.
Definition: nodePath.cxx:1253
NodePath get_path(int index) const
Returns the nth NodePath in the collection.
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:3680
bool write_bam_stream(ostream &out) const
Writes the contents of this node and below out to the indicated stream.
Definition: nodePath.cxx:6431
void clear_color()
Completely removes any color adjustment from the node.
Definition: nodePath.cxx:2314
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:796
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: nodePath.I:623
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:97
bool has_all_off() const
Returns true if this attrib turns off all stages (although it may also turn some on).
int flatten_light()
Lightly flattens out the hierarchy below this node by applying transforms, colors, and texture matrices from the nodes onto the vertices, but does not remove any nodes.
Definition: nodePath.cxx:6279
bool has_clip_plane_off() const
Returns true if all clipping planes have been specifically disabled on this particular node...
Definition: nodePath.cxx:2996
int flatten(PandaNode *root, int combine_siblings_bits)
Simplifies the graph by removing unnecessary nodes and nodes.
bool get_depth_write() const
Returns true if depth-write rendering has been specifically set on this node via set_depth_write(), or false if depth-write rendering has been specifically disabled.
Definition: nodePath.cxx:5330
void clear_texture()
Completely removes any texture adjustment that may have been set via set_texture() or set_texture_off...
Definition: nodePath.cxx:3505
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:3926
virtual PandaNode * make_copy() const
Returns a newly-allocated PandaNode that is a shallow copy of this one.
Definition: pandaNode.cxx:604
void set_billboard_point_eye(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:2158
Defines the way an object appears in the presence of lighting.
Definition: material.h:34
LQuaternion get_quat() const
Retrieves the rotation component of the transform.
Definition: nodePath.cxx:1279
TextureStage * find_texture_stage(const string &name) const
Returns the first TextureStage found applied to geometry at this node or below that matches the indic...
Definition: nodePath.cxx:4603
LPoint3 get_pos() const
Retrieves the translation component of the transform.
Definition: nodePath.cxx:1178
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
Definition: pandaNode.cxx:1107
Applies a scale to colors in the scene graph and on vertices.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
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:2560
void set_color_off(int priority=0)
Sets the geometry at this level and below to render using the geometry color.
Definition: nodePath.cxx:2300
Assigns geometry to a particular bin by name.
Definition: cullBinAttrib.h:30
static NodePath removed()
Creates a NodePath with the ET_removed error type set.
Definition: nodePath.I:172
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:39
const string & get_name() const
Returns the name of this texture stage.
Definition: textureStage.I:32
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, but overlay the wireframe on top with a fixed color.
Definition: nodePath.cxx:4972
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:3234
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
void project_texture(TextureStage *stage, Texture *tex, const NodePath &projector)
A convenience function to enable projective texturing at this node level and below, using the indicated NodePath (which should contain a LensNode) as the projector.
Definition: nodePath.cxx:4365
Applies a transform matrix to UV&#39;s before they are rendered.
This class can be used to write a binary file that consists of an arbitrary header followed by a numb...
void clear_antialias()
Completely removes any antialias setting that may have been set on this node via set_antialias().
Definition: nodePath.cxx:5708
void add_name(const InternalName *name)
Adds a new InternalName to the collection.
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:2145
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:3457
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:879
static NodePath not_found()
Creates a NodePath with the ET_not_found error type set.
Definition: nodePath.I:159
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...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
int flatten_strong()
The strongest possible flattening.
Definition: nodePath.cxx:6337
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:822
bool has_texture_off() const
Returns true if texturing has been specifically disabled on this particular node via set_texture_off(...
Definition: nodePath.cxx:3587
static const SamplerState & get_default()
Returns a reference to the global default immutable SamplerState object.
Definition: samplerState.I:44
bool is_valid() const
Returns true if the WorkingNodePath object appears to be a valid NodePath reference, false otherwise.
bool has_off_stage(TextureStage *stage) const
Returns true if the indicated stage is turned off by the attrib, false otherwise. ...
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:4941
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
This effect automatically applies a computed texture matrix to the specified texture stage...
Children get_children(Thread *current_thread=Thread::get_current_thread()) const
Returns an object that can be used to walk through the list of children of the node.
Definition: pandaNode.I:773
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:4184
PandaCompareFunc get_mode() const
Returns the depth write mode.
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:1488
This is the base quaternion class.
Definition: lquaternion.h:96
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&#39;s stashed list, so that the result ...
Definition: nodePath.cxx:547
A thread; that is, a lightweight process.
Definition: thread.h:51
bool has_parent(Thread *current_thread=Thread::get_current_thread()) const
Returns true if the referenced node has a parent; i.e.
Definition: nodePath.I:447
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:757
int get_length(int pipeline_stage, Thread *current_thread) const
Returns the length of the path to this node.
bool has_all_off() const
Returns true if this attrib turns off all lights (although it may also turn some on).
Definition: lightAttrib.I:118
void set_material_off(int priority=0)
Sets the geometry at this level and below to render using no material.
Definition: nodePath.cxx:4760
int get_num_nodes(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of nodes in the path.
Definition: nodePath.cxx:231
This is a special kind of attribute that instructs the graphics driver to apply an offset or bias to ...
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:206
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:572
Mode get_actual_mode() const
Returns the actual culling mode, without considering the effects of the reverse flag.
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
Definition: nodePath.I:660
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
Definition: nodePath.cxx:1331
const LColor & get_wireframe_color() const
Returns the color that is used in M_filled_wireframe mode to distinguish the wireframe from the rest ...
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:5358
NodePath get_parent(Thread *current_thread=Thread::get_current_thread()) const
Returns the NodePath to the parent of the referenced node: that is, this NodePath, shortened by one node.
Definition: nodePath.I:460
const string & get_bin_name() const
Returns the name of the bin this attribute specifies.
Definition: cullBinAttrib.I:35
bool is_off() const
Returns true if the MaterialAttrib is an &#39;off&#39; MaterialAttrib, indicating that it should disable the ...
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:317
void set_mat(const LMatrix4 &mat)
Directly sets an arbitrary 4x4 transform matrix.
Definition: nodePath.cxx:1517
TextureStageCollection find_all_texture_stages() const
Returns a list of a TextureStages applied to geometry at this node and below.
Definition: nodePath.cxx:4616
bool add_string(const string &str_path)
Adds a sequence of components separated by slashes, followed optionally by a semicolon and a sequence...
Specifies how polygons are to be drawn.
void clear_occluder()
Completely removes any occluders that may have been set via set_occluder() from this particular node...
Definition: nodePath.cxx:3072
int get_num_on_stages() const
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.I:91
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:30
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
string 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:2597
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:4995
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:454
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:5832
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:965
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:5245
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:106
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:5907
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:927
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:159
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:5173
void set_transparency(TransparencyAttrib::Mode mode, int priority=0)
Specifically sets or disables transparent rendering mode on this particular node. ...
Definition: nodePath.cxx:5626
A class to retrieve the individual data elements previously stored in a Datagram. ...
const InternalName * get_name() const
Returns the name of this particular data field, e.g.
bool get_depth_test() const
Returns true if depth-test rendering has been specifically set on this node via set_depth_test(), or false if depth-test rendering has been specifically disabled.
Definition: nodePath.cxx:5260
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:2198
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
Definition: pandaNode.cxx:1194
void set_geom_state(int n, const RenderState *state)
Changes the RenderState associated with the nth geom of the node.
Definition: geomNode.I:131
PandaNode * get_child(int n) const
Returns the nth child of the node.
Definition: pandaNode.I:1174
bool open_write(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated file for writing.
Definition: bamFile.cxx:217
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
void set_preserve_transform(PreserveTransform preserve_transform)
Sets the preserve_transform flag.
Definition: modelNode.I:65
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:925
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:4234
void clear_tex_transform()
Removes all texture matrices from the current node.
Definition: nodePath.cxx:3950
bool is_off() const
Returns true if the FogAttrib is an &#39;off&#39; FogAttrib, indicating that it should disable fog...
Definition: fogAttrib.I:33
static TextureStage * get_default()
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Definition: textureStage.I:766
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:220
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2486
NodePath get_tex_projector_from(TextureStage *stage) const
Returns the "from" node associated with the TexProjectorEffect on the indicated stage.
Definition: nodePath.cxx:4320
NodePathCollection find_all_matches(const string &path) const
Returns the complete set of all NodePaths that begin with this NodePath and can be extended by path...
Definition: nodePath.cxx:480
bool normalize()
Normalizes the vector in place.
Definition: lvecBase3.h:783
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
Computes texture coordinates for geometry automatically based on vertex position and/or normal...
Definition: texGenAttrib.h:36
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:4860
LVecBase3 get_shear() const
Retrieves the shear component of the transform.
Definition: nodePath.cxx:1383
int flatten_medium()
A more thorough flattening than flatten_light(), this first applies all the transforms, colors, and texture matrices from the nodes onto the vertices, and then removes unneeded grouping nodes–nodes that have exactly one child, for instance, but have no special properties in themselves.
Definition: nodePath.cxx:6304
bool get_two_sided() const
Returns true if two-sided rendering has been specifically set on this node via set_two_sided(), or false if one-sided rendering has been specifically set, or if nothing has been specifically set.
Definition: nodePath.cxx:5190
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:5135
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:804
PandaNode * get_node(int index, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth node of the path, where 0 is the referenced (bottom) node and get_num_nodes() - 1 is ...
Definition: nodePath.cxx:256
LVecBase3f get_row3(int row) const
Retrieves the row column of the matrix as a 3-component vector, ignoring the last column...
Definition: lmatrix.h:1312
NodePath get_tex_projector_to(TextureStage *stage) const
Returns the "to" node associated with the TexProjectorEffect on the indicated stage.
Definition: nodePath.cxx:4343
bool has_compass() const
Returns true if there is any compass effect on the node.
Definition: nodePath.cxx:5612
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:5315
Applies a scale to audio volume for positional sounds in the scene graph.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
void set_state(const RenderState *state, Thread *current_thread=Thread::get_current_thread())
Changes the complete state object on this node.
Definition: nodePath.I:543
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:5482
static LVector3f up(CoordinateSystem cs=CS_default)
Returns the up vector for the given coordinate system.
Definition: lvector3.h:541
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:46
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:4443
bool has_transparency() const
Returns true if a transparent-rendering adjustment has been explicitly set on this particular node vi...
Definition: nodePath.cxx:5659
void clear_tex_projector()
Removes the TexProjectorEffect for all stages from this node.
Definition: nodePath.cxx:4285
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:37
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:2424
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:2874
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:2971
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:5060
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
void clear_compass()
Removes any compass effect from the node.
Definition: nodePath.cxx:5600
int make_compatible_state(PandaNode *root)
Searches for GeomNodes that contain multiple Geoms that differ only in their ColorAttribs.
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:33
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:2170
const TransformState * get_prev_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the transform that has been set as this node&#39;s "previous" position.
Definition: nodePath.cxx:1019
const RenderState * get_state(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete state object set on this node.
Definition: nodePath.cxx:848
bool has_bin() const
Returns true if the node has been assigned to the a particular rendering bin via set_bin(), false otherwise.
Definition: nodePath.cxx:3288
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:5850
This is one component of a NodePath.
int get_sort(Thread *current_thread=Thread::get_current_thread()) const
Returns the sort value of the referenced node within its parent; that is, the sort number passed on t...
Definition: nodePath.cxx:401
This is a set of zero or more NodePaths.
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:981