nodePath.cxx
00001 // Filename: nodePath.cxx
00002 // Created by:  drose (25Feb02)
00003 // Updated by:  fperazzi, PandaSE (06Apr10) (added more overloads
00004 //   for set_shader_input)
00005 // Updated by: weifengh, PandaSE(30Apr10) (added set_shader_auto)
00006 //
00007 ////////////////////////////////////////////////////////////////////
00008 //
00009 // PANDA 3D SOFTWARE
00010 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00011 //
00012 // All use of this software is subject to the terms of the revised BSD
00013 // license.  You should have received a copy of this license along
00014 // with this source code in a file named "LICENSE."
00015 //
00016 ////////////////////////////////////////////////////////////////////
00017 
00018 #include "nodePath.h"
00019 #include "nodePathCollection.h"
00020 #include "findApproxPath.h"
00021 #include "findApproxLevelEntry.h"
00022 #include "internalNameCollection.h"
00023 #include "config_pgraph.h"
00024 #include "colorAttrib.h"
00025 #include "colorScaleAttrib.h"
00026 #include "cullBinAttrib.h"
00027 #include "textureAttrib.h"
00028 #include "texMatrixAttrib.h"
00029 #include "texGenAttrib.h"
00030 #include "materialAttrib.h"
00031 #include "materialCollection.h"
00032 #include "lightAttrib.h"
00033 #include "clipPlaneAttrib.h"
00034 #include "occluderEffect.h"
00035 #include "polylightEffect.h"
00036 #include "fogAttrib.h"
00037 #include "renderModeAttrib.h"
00038 #include "cullFaceAttrib.h"
00039 #include "alphaTestAttrib.h"
00040 #include "depthTestAttrib.h"
00041 #include "depthWriteAttrib.h"
00042 #include "depthOffsetAttrib.h"
00043 #include "shaderAttrib.h"
00044 #include "billboardEffect.h"
00045 #include "compassEffect.h"
00046 #include "showBoundsEffect.h"
00047 #include "transparencyAttrib.h"
00048 #include "antialiasAttrib.h"
00049 #include "audioVolumeAttrib.h"
00050 #include "texProjectorEffect.h"
00051 #include "scissorEffect.h"
00052 #include "texturePool.h"
00053 #include "planeNode.h"
00054 #include "occluderNode.h"
00055 #include "lensNode.h"
00056 #include "materialPool.h"
00057 #include "look_at.h"
00058 #include "plist.h"
00059 #include "boundingSphere.h"
00060 #include "geomNode.h"
00061 #include "sceneGraphReducer.h"
00062 #include "textureCollection.h"
00063 #include "textureStageCollection.h"
00064 #include "globPattern.h"
00065 #include "shader.h"
00066 #include "shaderInput.h"
00067 #include "config_gobj.h"
00068 #include "bamFile.h"
00069 #include "preparedGraphicsObjects.h"
00070 #include "dcast.h"
00071 #include "pStatCollector.h"
00072 #include "pStatTimer.h"
00073 #include "modelNode.h"
00074 #include "py_panda.h"
00075 #include "bam.h"
00076 #include "bamWriter.h"
00077 
00078 // stack seems to overflow on Intel C++ at 7000.  If we need more than 
00079 // 7000, need to increase stack size.
00080 int NodePath::_max_search_depth = 7000; 
00081 TypeHandle NodePath::_type_handle;
00082 
00083 PStatCollector NodePath::_get_transform_pcollector("*:NodePath:get_transform");
00084 PStatCollector NodePath::_verify_complete_pcollector("*:NodePath:verify_complete");
00085 
00086 #ifdef HAVE_PYTHON
00087 #include "py_panda.h"  
00088 #ifndef CPPPARSER
00089 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamWriter;
00090 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamReader;
00091 #endif  // CPPPARSER
00092 #endif  // HAVE_PYTHON
00093 
00094 // ***Begin temporary transition code for operator bool
00095 enum EmptyNodePathType {
00096   ENP_future,
00097   ENP_transition,
00098   ENP_deprecated,
00099   ENP_notify,
00100 };
00101 
00102 ostream &operator << (ostream &out, EmptyNodePathType enp) {
00103   switch (enp) {
00104   case ENP_future:
00105     return out << "future";
00106   case ENP_transition:
00107     return out << "transition";
00108   case ENP_deprecated:
00109     return out << "deprecated";
00110   case ENP_notify:
00111     return out << "notify";
00112   }
00113   return out << "**invalid EmptyNodePathType value (" << (int)enp << ")**";
00114 }
00115 
00116 istream &operator >> (istream &in, EmptyNodePathType &enp) {
00117   string word;
00118   in >> word;
00119   if (word == "future") {
00120     enp = ENP_future;
00121   } else if (word == "transition") {
00122     enp = ENP_transition;
00123   } else if (word == "deprecated") {
00124     enp = ENP_deprecated;
00125   } else if (word == "notify") {
00126     enp = ENP_notify;
00127   } else {
00128     pgraph_cat.warning()
00129       << "Invalid EmptyNodePathType value (\"" << word << "\")\n";
00130     enp = ENP_transition;
00131   }
00132   return in;
00133 }
00134 
00135 static ConfigVariableEnum<EmptyNodePathType> empty_node_path
00136 ("empty-node-path", ENP_future,
00137  PRC_DESC("This is a temporary transition variable to control the behavior "
00138           "of a NodePath when it is used as a boolean false.  Set this to "
00139           "'deprecated' to preserve the original behavior: every NodePath "
00140           "evaluates true, even an empty NodePath.  Set it to 'future' to "
00141           "support the new behavior: non-empty NodePaths evaluate true, "
00142           "and empty NodePaths evaluate false.  Set it to 'transition' to "
00143           "raise an exception if an empty NodePath is used as a boolean."));
00144 
00145 // ***End temporary transition code for operator bool
00146 
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: NodePath::Constructor
00150 //       Access: Published
00151 //  Description: Constructs a NodePath with the indicated parent
00152 //               NodePath and child node; the child node must be a
00153 //               stashed or unstashed child of the parent.
00154 ////////////////////////////////////////////////////////////////////
00155 NodePath::
00156 NodePath(const NodePath &parent, PandaNode *child_node, 
00157          Thread *current_thread) :
00158   _error_type(ET_fail)
00159 {
00160   nassertv(child_node != (PandaNode *)NULL);
00161   int pipeline_stage = current_thread->get_pipeline_stage();
00162 
00163   if (parent.is_empty()) {
00164     // Special case: constructing a NodePath at the root.
00165     _head = PandaNode::get_top_component(child_node, true, 
00166                                          pipeline_stage, current_thread);
00167 
00168   } else {
00169     _head = PandaNode::get_component(parent._head, child_node, pipeline_stage,
00170                                      current_thread);
00171   }
00172   nassertv(_head != (NodePathComponent *)NULL);
00173 
00174   if (_head != (NodePathComponent *)NULL) {
00175     _error_type = ET_ok;
00176   }
00177   _backup_key = 0;
00178 }
00179 
00180 #ifdef HAVE_PYTHON
00181 ////////////////////////////////////////////////////////////////////
00182 //     Function: NodePath::__copy__
00183 //       Access: Published
00184 //  Description: A special Python method that is invoked by
00185 //               copy.copy(node).  Unlike the NodePath copy
00186 //               constructor, this makes a duplicate copy of the
00187 //               underlying PandaNode (but shares children, instead of
00188 //               copying them or omitting them).
00189 ////////////////////////////////////////////////////////////////////
00190 NodePath NodePath::
00191 __copy__() const {
00192   if (is_empty()) {
00193     // Invoke the copy constructor if we have no node.
00194     return *this;
00195   }
00196 
00197   // If we do have a node, duplicate it, and wrap it in a new
00198   // NodePath.
00199   return NodePath(node()->__copy__());
00200 }
00201 #endif  // HAVE_PYTHON
00202 
00203 #ifdef HAVE_PYTHON
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: NodePath::__deepcopy__
00206 //       Access: Published
00207 //  Description: A special Python method that is invoked by
00208 //               copy.deepcopy(np).  This calls copy_to() unless the
00209 //               NodePath is already present in the provided
00210 //               dictionary.
00211 ////////////////////////////////////////////////////////////////////
00212 PyObject *NodePath::
00213 __deepcopy__(PyObject *self, PyObject *memo) const {
00214   IMPORT_THIS struct Dtool_PyTypedObject Dtool_NodePath;
00215 
00216   // Borrowed reference.
00217   PyObject *dupe = PyDict_GetItem(memo, self);
00218   if (dupe != NULL) {
00219     // Already in the memo dictionary.
00220     Py_INCREF(dupe);
00221     return dupe;
00222   }
00223 
00224   NodePath *np_dupe;
00225   if (is_empty()) {
00226     np_dupe = new NodePath(*this);
00227   } else {
00228     np_dupe = new NodePath(copy_to(NodePath()));
00229   }
00230 
00231   dupe = DTool_CreatePyInstance((void *)np_dupe, Dtool_NodePath,
00232                                 true, false);
00233   if (PyDict_SetItem(memo, self, dupe) != 0) {
00234     Py_DECREF(dupe);
00235     return NULL;
00236   }
00237 
00238   return dupe;
00239 }
00240 #endif  // HAVE_PYTHON
00241 
00242 #ifdef HAVE_PYTHON
00243 ////////////////////////////////////////////////////////////////////
00244 //     Function: NodePath::__reduce__
00245 //       Access: Published
00246 //  Description: This special Python method is implement to provide
00247 //               support for the pickle module.
00248 //
00249 //               This hooks into the native pickle and cPickle
00250 //               modules, but it cannot properly handle
00251 //               self-referential BAM objects.
00252 ////////////////////////////////////////////////////////////////////
00253 PyObject *NodePath::
00254 __reduce__(PyObject *self) const {
00255   return __reduce_persist__(self, NULL);
00256 }
00257 #endif  // HAVE_PYTHON
00258 
00259 #ifdef HAVE_PYTHON
00260 ////////////////////////////////////////////////////////////////////
00261 //     Function: NodePath::__reduce_persist__
00262 //       Access: Published
00263 //  Description: This special Python method is implement to provide
00264 //               support for the pickle module.
00265 //
00266 //               This is similar to __reduce__, but it provides
00267 //               additional support for the missing persistent-state
00268 //               object needed to properly support self-referential
00269 //               BAM objects written to the pickle stream.  This hooks
00270 //               into the pickle and cPickle modules implemented in
00271 //               direct/src/stdpy.
00272 ////////////////////////////////////////////////////////////////////
00273 PyObject *NodePath::
00274 __reduce_persist__(PyObject *self, PyObject *pickler) const {
00275   // We should return at least a 2-tuple, (Class, (args)): the
00276   // necessary class object whose constructor we should call
00277   // (e.g. this), and the arguments necessary to reconstruct this
00278   // object.
00279 
00280   BamWriter *writer = NULL;
00281   if (pickler != NULL) {
00282     PyObject *py_writer = PyObject_GetAttrString(pickler, "bamWriter");
00283     if (py_writer == NULL) {
00284       // It's OK if there's no bamWriter.
00285       PyErr_Clear();
00286     } else {
00287       DTOOL_Call_ExtractThisPointerForType(py_writer, &Dtool_BamWriter, (void **)&writer);
00288       Py_DECREF(py_writer);
00289     }
00290   }
00291 
00292   // We have a non-empty NodePath.
00293 
00294   string bam_stream;
00295   if (!encode_to_bam_stream(bam_stream, writer)) {
00296     ostringstream stream;
00297     stream << "Could not bamify " << this;
00298     string message = stream.str();
00299     PyErr_SetString(PyExc_TypeError, message.c_str());
00300     return NULL;
00301   }
00302 
00303   // Start by getting this class object.
00304   PyObject *this_class = PyObject_Type(self);
00305   if (this_class == NULL) {
00306     return NULL;
00307   }
00308 
00309   PyObject *func;
00310   if (writer != NULL) {
00311     // The modified pickle support: call the "persistent" version of
00312     // this function, which receives the unpickler itself as an
00313     // additional parameter.
00314     func = TypedWritable::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream_persist");
00315     if (func == NULL) {
00316       PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream_persist()");
00317       Py_DECREF(this_class);
00318       return NULL;
00319     }
00320 
00321   } else {
00322     // The traditional pickle support: call the non-persistent version
00323     // of this function.
00324 
00325     func = TypedWritable::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream");
00326     if (func == NULL) {
00327       PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream()");
00328       Py_DECREF(this_class);
00329       return NULL;
00330     }
00331   }
00332 
00333   PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), bam_stream.size());
00334   Py_DECREF(func);
00335   Py_DECREF(this_class);
00336   return result;
00337 }
00338 #endif  // HAVE_PYTHON
00339 
00340 ////////////////////////////////////////////////////////////////////
00341 //     Function: NodePath::operator bool
00342 //       Access: Published
00343 //  Description: Returns true if the NodePath is valid (not empty),
00344 //               or false if it contains no nodes.
00345 ////////////////////////////////////////////////////////////////////
00346 NodePath::
00347 operator bool () const {
00348   switch (empty_node_path) {
00349   case ENP_future:
00350     return !is_empty();
00351 
00352   case ENP_deprecated:
00353     return true;
00354 
00355   case ENP_notify:
00356     {
00357       const char *msg = "NodePath being used as a Boolean (talk to Zac)";
00358 #ifdef HAVE_PYTHON
00359       PyErr_Warn(PyExc_FutureWarning, (char *)msg);
00360 #endif
00361       return !is_empty();
00362     }
00363 
00364 
00365   case ENP_transition:
00366     if (!is_empty()) {
00367       return true;
00368     }
00369     
00370     {
00371       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.";
00372       pgraph_cat.warning()
00373         << message << "\n";
00374 #ifdef HAVE_PYTHON
00375       PyErr_Warn(PyExc_FutureWarning, (char *)message);
00376 #endif
00377     }
00378     return true;
00379   }
00380 
00381   nassertr(false, true);
00382   return true;
00383 }
00384 
00385 ////////////////////////////////////////////////////////////////////
00386 //     Function: NodePath::get_num_nodes
00387 //       Access: Published
00388 //  Description: Returns the number of nodes in the path.
00389 ////////////////////////////////////////////////////////////////////
00390 int NodePath::
00391 get_num_nodes(Thread *current_thread) const {
00392   if (is_empty()) {
00393     return 0;
00394   }
00395   int pipeline_stage = current_thread->get_pipeline_stage();
00396   return _head->get_length(pipeline_stage, current_thread);
00397 }
00398 
00399 ////////////////////////////////////////////////////////////////////
00400 //     Function: NodePath::get_node
00401 //       Access: Published
00402 //  Description: Returns the nth node of the path, where 0 is the
00403 //               referenced (bottom) node and get_num_nodes() - 1 is
00404 //               the top node.  This requires iterating through the
00405 //               path.
00406 //
00407 //               Also see node(), which is a convenience function to
00408 //               return the same thing as get_node(0) (since the
00409 //               bottom node is the most important node in the
00410 //               NodePath, and is the one most frequently referenced).
00411 //
00412 //               Note that this function returns the same thing as
00413 //               get_ancestor(index).node().
00414 ////////////////////////////////////////////////////////////////////
00415 PandaNode *NodePath::
00416 get_node(int index, Thread *current_thread) const {
00417   nassertr(index >= 0 && index < get_num_nodes(), NULL);
00418 
00419   int pipeline_stage = current_thread->get_pipeline_stage();
00420 
00421   NodePathComponent *comp = _head;
00422   while (index > 0) {
00423     // If this assertion fails, the index was out of range; the
00424     // component's length must have been invalid.
00425     nassertr(comp != (NodePathComponent *)NULL, NULL);
00426     comp = comp->get_next(pipeline_stage, current_thread);
00427     index--;
00428   }
00429 
00430   // If this assertion fails, the index was out of range; the
00431   // component's length must have been invalid.
00432   nassertr(comp != (NodePathComponent *)NULL, NULL);
00433   return comp->get_node();
00434 }
00435 
00436 ////////////////////////////////////////////////////////////////////
00437 //     Function: NodePath::get_ancestor
00438 //       Access: Published
00439 //  Description: Returns the nth ancestor of the path, where 0 is the
00440 //               NodePath itself and get_num_nodes() - 1 is get_top().
00441 //               This requires iterating through the path.
00442 //
00443 //               Also see get_node(), which returns the same thing as
00444 //               a PandaNode pointer, not a NodePath.
00445 ////////////////////////////////////////////////////////////////////
00446 NodePath NodePath::
00447 get_ancestor(int index, Thread *current_thread) const {
00448   nassertr(index >= 0 && index < get_num_nodes(), NodePath::fail());
00449 
00450   int pipeline_stage = current_thread->get_pipeline_stage();
00451 
00452   NodePathComponent *comp = _head;
00453   while (index > 0) {
00454     // If this assertion fails, the index was out of range; the
00455     // component's length must have been invalid.
00456     nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
00457     comp = comp->get_next(pipeline_stage, current_thread);
00458     index--;
00459   }
00460 
00461   // If this assertion fails, the index was out of range; the
00462   // component's length must have been invalid.
00463   nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
00464 
00465   NodePath result;
00466   result._head = comp;
00467   return result;
00468 }
00469 
00470 ////////////////////////////////////////////////////////////////////
00471 //     Function: NodePath::get_top
00472 //       Access: Published
00473 //  Description: Returns a singleton NodePath that represents the top
00474 //               of the path, or empty NodePath if this path is empty.
00475 ////////////////////////////////////////////////////////////////////
00476 NodePath NodePath::
00477 get_top(Thread *current_thread) const {
00478   if (is_empty()) {
00479     return *this;
00480   }
00481 
00482   int pipeline_stage = current_thread->get_pipeline_stage();
00483 
00484   NodePathComponent *comp = _head;
00485   while (!comp->is_top_node(pipeline_stage, current_thread)) {
00486     comp = comp->get_next(pipeline_stage, current_thread);
00487     nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
00488   }
00489 
00490   NodePath top;
00491   top._head = comp;
00492   return top;
00493 }
00494 
00495 
00496 ////////////////////////////////////////////////////////////////////
00497 //     Function: NodePath::get_children
00498 //       Access: Published
00499 //  Description: Returns the set of all child nodes of the referenced
00500 //               node.
00501 ////////////////////////////////////////////////////////////////////
00502 NodePathCollection NodePath::
00503 get_children(Thread *current_thread) const {
00504   NodePathCollection result;
00505   nassertr_always(!is_empty(), result);
00506 
00507   PandaNode *bottom_node = node();
00508 
00509   int pipeline_stage = current_thread->get_pipeline_stage();
00510 
00511   PandaNode::Children cr = bottom_node->get_children();
00512   int num_children = cr.get_num_children();
00513   for (int i = 0; i < num_children; i++) {
00514     NodePath child;
00515     child._head = PandaNode::get_component(_head, cr.get_child(i),
00516                                            pipeline_stage, current_thread);
00517     result.add_path(child);
00518   }
00519 
00520   return result;
00521 }
00522 
00523 ////////////////////////////////////////////////////////////////////
00524 //     Function: NodePath::get_stashed_children
00525 //       Access: Published
00526 //  Description: Returns the set of all child nodes of the referenced
00527 //               node that have been stashed.  These children are not
00528 //               normally visible on the node, and do not appear in
00529 //               the list returned by get_children().
00530 ////////////////////////////////////////////////////////////////////
00531 NodePathCollection NodePath::
00532 get_stashed_children(Thread *current_thread) const {
00533   NodePathCollection result;
00534   nassertr_always(!is_empty(), result);
00535 
00536   PandaNode *bottom_node = node();
00537 
00538   int pipeline_stage = current_thread->get_pipeline_stage();
00539 
00540   int num_stashed = bottom_node->get_num_stashed();
00541   for (int i = 0; i < num_stashed; i++) {
00542     NodePath stashed;
00543     stashed._head = PandaNode::get_component(_head, bottom_node->get_stashed(i),
00544                                              pipeline_stage, current_thread);
00545     result.add_path(stashed);
00546   }
00547 
00548   return result;
00549 }
00550 
00551 ////////////////////////////////////////////////////////////////////
00552 //     Function: NodePath::get_sort
00553 //       Access: Published
00554 //  Description: Returns the sort value of the referenced node within
00555 //               its parent; that is, the sort number passed on the
00556 //               last reparenting operation for this node.  This will
00557 //               control the position of the node within its parent's
00558 //               list of children.
00559 ////////////////////////////////////////////////////////////////////
00560 int NodePath::
00561 get_sort(Thread *current_thread) const {
00562   if (!has_parent()) {
00563     return 0;
00564   }
00565 
00566   int pipeline_stage = current_thread->get_pipeline_stage();
00567 
00568   PandaNode *parent = _head->get_next(pipeline_stage, current_thread)->get_node();
00569   PandaNode *child = node();
00570   nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0);
00571   int child_index = parent->find_child(child);
00572   if (child_index != -1) {
00573     return parent->get_child_sort(child_index);
00574   }
00575 
00576   child_index = parent->find_stashed(child);
00577   if (child_index != -1) {
00578     return parent->get_stashed_sort(child_index);
00579   }
00580 
00581   nassertr(false, 0);
00582   return 0;
00583 }
00584 
00585 ////////////////////////////////////////////////////////////////////
00586 //     Function: NodePath::find
00587 //       Access: Published
00588 //  Description: Searches for a node below the referenced node that
00589 //               matches the indicated string.  Returns the shortest
00590 //               match found, if any, or an empty NodePath if no match
00591 //               can be found.
00592 ////////////////////////////////////////////////////////////////////
00593 NodePath NodePath::
00594 find(const string &path) const {
00595   nassertr_always(!is_empty(), fail());
00596 
00597   NodePathCollection col;
00598   find_matches(col, path, 1);
00599 
00600   if (col.is_empty()) {
00601     return NodePath::not_found();
00602   }
00603 
00604   return col.get_path(0);
00605 }
00606 
00607 ////////////////////////////////////////////////////////////////////
00608 //     Function: NodePath::find_path_to
00609 //       Access: Published
00610 //  Description: Searches for the indicated node below this node and
00611 //               returns the shortest NodePath that connects them.
00612 ////////////////////////////////////////////////////////////////////
00613 NodePath NodePath::
00614 find_path_to(PandaNode *node) const {
00615   nassertr_always(!is_empty(), fail());
00616   nassertr(node != (PandaNode *)NULL, fail());
00617 
00618   NodePathCollection col;
00619   FindApproxPath approx_path;
00620   approx_path.add_match_many(0);
00621   approx_path.add_match_pointer(node, 0);
00622   find_matches(col, approx_path, 1);
00623 
00624   if (col.is_empty()) {
00625     return NodePath::not_found();
00626   }
00627 
00628   return col.get_path(0);
00629 }
00630 
00631 ////////////////////////////////////////////////////////////////////
00632 //     Function: NodePath::find_all_matches
00633 //       Access: Published
00634 //  Description: Returns the complete set of all NodePaths that begin
00635 //               with this NodePath and can be extended by
00636 //               path.  The shortest paths will be listed
00637 //               first.
00638 ////////////////////////////////////////////////////////////////////
00639 NodePathCollection NodePath::
00640 find_all_matches(const string &path) const {
00641   NodePathCollection col;
00642   nassertr_always(!is_empty(), col);
00643   nassertr(verify_complete(), col);
00644   find_matches(col, path, -1);
00645   return col;
00646 }
00647 
00648 ////////////////////////////////////////////////////////////////////
00649 //     Function: NodePath::find_all_paths_to
00650 //       Access: Published
00651 //  Description: Returns the set of all NodePaths that extend from
00652 //               this NodePath down to the indicated node.  The
00653 //               shortest paths will be listed first.
00654 ////////////////////////////////////////////////////////////////////
00655 NodePathCollection NodePath::
00656 find_all_paths_to(PandaNode *node) const {
00657   NodePathCollection col;
00658   nassertr_always(!is_empty(), col);
00659   nassertr(verify_complete(), col);
00660   nassertr(node != (PandaNode *)NULL, col);
00661   FindApproxPath approx_path;
00662   approx_path.add_match_many(0);
00663   approx_path.add_match_pointer(node, 0);
00664   find_matches(col, approx_path, -1);
00665   return col;
00666 }
00667 
00668 ////////////////////////////////////////////////////////////////////
00669 //     Function: NodePath::reparent_to
00670 //       Access: Published
00671 //  Description: Removes the referenced node of the NodePath from its
00672 //               current parent and attaches it to the referenced node
00673 //               of the indicated NodePath.  
00674 //
00675 //               If the destination NodePath is empty, this is the
00676 //               same thing as detach_node().
00677 //
00678 //               If the referenced node is already a child of the
00679 //               indicated NodePath (via some other instance), this
00680 //               operation fails and leaves the NodePath detached.
00681 ////////////////////////////////////////////////////////////////////
00682 void NodePath::
00683 reparent_to(const NodePath &other, int sort, Thread *current_thread) {
00684   nassertv(verify_complete());
00685   nassertv(other.verify_complete());
00686   nassertv_always(!is_empty());
00687   nassertv(other._error_type == ET_ok);
00688 
00689   // Reparenting implicitly resets the delta vector.
00690   node()->reset_prev_transform();
00691 
00692   int pipeline_stage = current_thread->get_pipeline_stage();
00693   bool reparented = PandaNode::reparent(other._head, _head, sort, false,
00694                                         pipeline_stage, current_thread);
00695   nassertv(reparented);
00696 }
00697 
00698 ////////////////////////////////////////////////////////////////////
00699 //     Function: NodePath::stash_to
00700 //       Access: Published
00701 //  Description: Similar to reparent_to(), but the node is added to
00702 //               its new parent's stashed list, so that the result is
00703 //               equivalent to calling reparent_to() immediately
00704 //               followed by stash().
00705 ////////////////////////////////////////////////////////////////////
00706 void NodePath::
00707 stash_to(const NodePath &other, int sort, Thread *current_thread) {
00708   nassertv(verify_complete());
00709   nassertv(other.verify_complete());
00710   nassertv_always(!is_empty());
00711   nassertv(other._error_type == ET_ok);
00712 
00713   // Reparenting implicitly resets the delta vector.
00714   node()->reset_prev_transform();
00715 
00716   int pipeline_stage = current_thread->get_pipeline_stage();
00717   bool reparented = PandaNode::reparent(other._head, _head, sort, true,
00718                                         pipeline_stage, current_thread);
00719   nassertv(reparented);
00720 }
00721 
00722 ////////////////////////////////////////////////////////////////////
00723 //     Function: NodePath::wrt_reparent_to
00724 //       Access: Published
00725 //  Description: This functions identically to reparent_to(), except
00726 //               the transform on this node is also adjusted so that
00727 //               the node remains in the same place in world
00728 //               coordinates, even if it is reparented into a
00729 //               different coordinate system.
00730 ////////////////////////////////////////////////////////////////////
00731 void NodePath::
00732 wrt_reparent_to(const NodePath &other, int sort, Thread *current_thread) {
00733   nassertv(verify_complete(current_thread));
00734   nassertv(other.verify_complete(current_thread));
00735   nassertv_always(!is_empty());
00736   nassertv(other._error_type == ET_ok);
00737 
00738   if (get_transform(current_thread) == get_prev_transform(current_thread)) {
00739     set_transform(get_transform(other, current_thread), current_thread);
00740     node()->reset_prev_transform(current_thread);
00741   } else {
00742     set_transform(get_transform(other, current_thread), current_thread);
00743     set_prev_transform(get_prev_transform(other, current_thread), current_thread);
00744   }
00745 
00746   reparent_to(other, sort, current_thread);
00747 }
00748 
00749 ////////////////////////////////////////////////////////////////////
00750 //     Function: NodePath::instance_to
00751 //       Access: Published
00752 //  Description: Adds the referenced node of the NodePath as a child
00753 //               of the referenced node of the indicated other
00754 //               NodePath.  Any other parent-child relations of the
00755 //               node are unchanged; in particular, the node is not
00756 //               removed from its existing parent, if any.
00757 //
00758 //               If the node already had an existing parent, this
00759 //               method will create a new instance of the node within
00760 //               the scene graph.
00761 //
00762 //               This does not change the NodePath itself, but does
00763 //               return a new NodePath that reflects the new instance
00764 //               node.
00765 //
00766 //               If the destination NodePath is empty, this creates a
00767 //               new instance which is not yet parented to any node.
00768 //               A new instance of this sort cannot easily be
00769 //               differentiated from other similar instances, but it
00770 //               is nevertheless a different instance and it will
00771 //               return a different get_id() value.
00772 //
00773 //               If the referenced node is already a child of the
00774 //               indicated NodePath, returns that already-existing
00775 //               instance, unstashing it first if necessary.
00776 ////////////////////////////////////////////////////////////////////
00777 NodePath NodePath::
00778 instance_to(const NodePath &other, int sort, Thread *current_thread) const {
00779   nassertr(verify_complete(), NodePath::fail());
00780   nassertr(other.verify_complete(), NodePath::fail());
00781   nassertr_always(!is_empty(), NodePath::fail());
00782   nassertr(other._error_type == ET_ok, NodePath::fail());
00783 
00784   NodePath new_instance;
00785 
00786   // First, we'll attach to NULL, to guarantee we get a brand new
00787   // instance.
00788   int pipeline_stage = current_thread->get_pipeline_stage();
00789   new_instance._head = PandaNode::attach(NULL, node(), sort, pipeline_stage,
00790                                          current_thread);
00791 
00792   // Now, we'll reparent the new instance to the target node.
00793   bool reparented = PandaNode::reparent(other._head, new_instance._head,
00794                                         sort, false, pipeline_stage,
00795                                         current_thread);
00796   if (!reparented) {
00797     // Hmm, couldn't reparent.  Either making this instance would
00798     // create a cycle, or it was already a child of that node.  If it
00799     // was already a child, return that existing NodePath instead.
00800     NodePath orig(other, node(), current_thread);
00801     if (!orig.is_empty()) {
00802       if (orig.is_stashed()) {
00803         orig.unstash();
00804       }
00805       return orig;
00806     }
00807     
00808     // Nope, it must be a cycle.
00809     nassertr(reparented, new_instance);
00810   }
00811 
00812   // instance_to() doesn't reset the velocity delta, unlike most of
00813   // the other reparenting operations.  The reasoning is that
00814   // instance_to() is not necessarily a reparenting operation, since
00815   // it doesn't change the original instance.
00816 
00817   return new_instance;
00818 }
00819 
00820 ////////////////////////////////////////////////////////////////////
00821 //     Function: NodePath::instance_under_node
00822 //       Access: Published
00823 //  Description: Behaves like instance_to(), but implicitly creates a
00824 //               new node to instance the geometry under, and returns a
00825 //               NodePath to that new node.  This allows the
00826 //               programmer to set a unique state and/or transform on
00827 //               this instance.
00828 ////////////////////////////////////////////////////////////////////
00829 NodePath NodePath::
00830 instance_under_node(const NodePath &other, const string &name, int sort,
00831                     Thread *current_thread) const {
00832   NodePath new_node = other.attach_new_node(name, sort, current_thread);
00833   NodePath instance = instance_to(new_node, 0, current_thread);
00834   if (instance.is_empty()) {
00835     new_node.remove_node(current_thread);
00836     return instance;
00837   }
00838   return new_node;
00839 }
00840 
00841 ////////////////////////////////////////////////////////////////////
00842 //     Function: NodePath::copy_to
00843 //       Access: Published
00844 //  Description: Functions like instance_to(), except a deep
00845 //               copy is made of the referenced node and all of its
00846 //               descendents, which is then parented to the indicated
00847 //               node.  A NodePath to the newly created copy is
00848 //               returned.
00849 ////////////////////////////////////////////////////////////////////
00850 NodePath NodePath::
00851 copy_to(const NodePath &other, int sort, Thread *current_thread) const {
00852   nassertr(verify_complete(current_thread), fail());
00853   nassertr(other.verify_complete(current_thread), fail());
00854   nassertr_always(!is_empty(), fail());
00855   nassertr(other._error_type == ET_ok, fail());
00856 
00857   PandaNode *source_node = node();
00858   PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread);
00859   nassertr(copy_node != (PandaNode *)NULL, fail());
00860 
00861   copy_node->reset_prev_transform(current_thread);
00862 
00863   return other.attach_new_node(copy_node, sort, current_thread);
00864 }
00865 
00866 ////////////////////////////////////////////////////////////////////
00867 //     Function: NodePath::attach_new_node
00868 //       Access: Published
00869 //  Description: Attaches a new node, with or without existing
00870 //               parents, to the scene graph below the referenced node
00871 //               of this NodePath.  This is the preferred way to add
00872 //               nodes to the graph.
00873 //
00874 //               If the node was already a child of the parent, this
00875 //               returns a NodePath to the existing child.
00876 //
00877 //               This does *not* automatically extend the current
00878 //               NodePath to reflect the attachment; however, a
00879 //               NodePath that does reflect this extension is
00880 //               returned.
00881 ////////////////////////////////////////////////////////////////////
00882 NodePath NodePath::
00883 attach_new_node(PandaNode *node, int sort, Thread *current_thread) const {
00884   nassertr(verify_complete(current_thread), NodePath::fail());
00885   nassertr(_error_type == ET_ok, NodePath::fail());
00886   nassertr(node != (PandaNode *)NULL, NodePath::fail());
00887 
00888   NodePath new_path(*this);
00889   int pipeline_stage = current_thread->get_pipeline_stage();
00890   new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage,
00891                                      current_thread);
00892   return new_path;
00893 }
00894 
00895 ////////////////////////////////////////////////////////////////////
00896 //     Function: NodePath::remove_node
00897 //       Access: Published
00898 //  Description: Disconnects the referenced node from the scene graph.
00899 //               This will also delete the node if there are no other
00900 //               pointers to it.
00901 //
00902 //               Normally, this should be called only when you are
00903 //               really done with the node.  If you want to remove a
00904 //               node from the scene graph but keep it around for
00905 //               later, you should probably use detach_node() instead.
00906 //
00907 //               In practice, the only difference between
00908 //               remove_node() and detach_node() is that remove_node()
00909 //               also resets the NodePath to empty, which will cause
00910 //               the node to be deleted immediately if there are no
00911 //               other references.  On the other hand, detach_node()
00912 //               leaves the NodePath referencing the node, which will
00913 //               keep at least one reference to the node for as long
00914 //               as the NodePath exists.
00915 ////////////////////////////////////////////////////////////////////
00916 void NodePath::
00917 remove_node(Thread *current_thread) {
00918   nassertv(_error_type != ET_not_found);
00919 
00920   // If we have no parents, remove_node() is just a do-nothing
00921   // operation; if we have no nodes, maybe we were already removed.
00922   // In either case, quietly do nothing except to ensure the
00923   // NodePath is clear.
00924   if (!is_empty() && !is_singleton(current_thread)) {
00925     node()->reset_prev_transform(current_thread);
00926     int pipeline_stage = current_thread->get_pipeline_stage();
00927     PandaNode::detach(_head, pipeline_stage, current_thread);
00928   }
00929 
00930   if (is_empty() || _head->has_key()) {
00931     // Preserve the key we had on the node before we removed it.
00932     int key = get_key();
00933     (*this) = NodePath::removed();
00934     _backup_key = key;
00935 
00936   } else {
00937     // We didn't have a key; just clear the NodePath.
00938     (*this) = NodePath::removed();
00939   }
00940 }
00941 
00942 ////////////////////////////////////////////////////////////////////
00943 //     Function: NodePath::detach_node
00944 //       Access: Published
00945 //  Description: Disconnects the referenced node from its parent, but
00946 //               does not immediately delete it.  The NodePath retains
00947 //               a pointer to the node, and becomes a singleton
00948 //               NodePath.
00949 //
00950 //               This should be called to detach a node from the scene
00951 //               graph, with the option of reattaching it later to the
00952 //               same parent or to a different parent.
00953 //
00954 //               In practice, the only difference between
00955 //               remove_node() and detach_node() is that remove_node()
00956 //               also resets the NodePath to empty, which will cause
00957 //               the node to be deleted immediately if there are no
00958 //               other references.  On the other hand, detach_node()
00959 //               leaves the NodePath referencing the node, which will
00960 //               keep at least one reference to the node for as long
00961 //               as the NodePath exists.
00962 ////////////////////////////////////////////////////////////////////
00963 void NodePath::
00964 detach_node(Thread *current_thread) {
00965   nassertv(_error_type != ET_not_found);
00966   if (!is_empty() && !is_singleton()) {
00967     node()->reset_prev_transform();
00968     int pipeline_stage = current_thread->get_pipeline_stage();
00969     PandaNode::detach(_head, pipeline_stage, current_thread);
00970   }
00971 }
00972 
00973 ////////////////////////////////////////////////////////////////////
00974 //     Function: NodePath::output
00975 //       Access: Published
00976 //  Description: Writes a sensible description of the NodePath to the
00977 //               indicated output stream.
00978 ////////////////////////////////////////////////////////////////////
00979 void NodePath::
00980 output(ostream &out) const {
00981   switch (_error_type) {
00982   case ET_not_found:
00983     out << "**not found**";
00984     return;
00985   case ET_removed:
00986     out << "**removed**";
00987     return;
00988   case ET_fail:
00989     out << "**error**";
00990     return;
00991   default:
00992     break;
00993   }
00994 
00995   if (_head == (NodePathComponent *)NULL) {
00996     out << "(empty)";
00997   } else {
00998     _head->output(out);
00999   }
01000 }
01001 
01002 ////////////////////////////////////////////////////////////////////
01003 //     Function: NodePath::get_state
01004 //       Access: Published
01005 //  Description: Returns the complete state object set on this node.
01006 ////////////////////////////////////////////////////////////////////
01007 const RenderState *NodePath::
01008 get_state(Thread *current_thread) const {
01009   // This method is declared non-inline to avoid a compiler bug in
01010   // gcc-3.4 and gcc-4.0.
01011   nassertr_always(!is_empty(), RenderState::make_empty());
01012   return node()->get_state(current_thread);
01013 }
01014 
01015 ////////////////////////////////////////////////////////////////////
01016 //     Function: NodePath::get_state
01017 //       Access: Published
01018 //  Description: Returns the state changes that must be made to
01019 //               transition to the render state of this node from the
01020 //               render state of the other node.
01021 ////////////////////////////////////////////////////////////////////
01022 CPT(RenderState) NodePath::
01023 get_state(const NodePath &other, Thread *current_thread) const {
01024   nassertr(_error_type == ET_ok && other._error_type == ET_ok, RenderState::make_empty());
01025 
01026   if (other.is_empty()) {
01027     return get_net_state(current_thread);
01028   }
01029   if (is_empty()) {
01030     return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty());
01031   }
01032     
01033   nassertr(verify_complete(current_thread), RenderState::make_empty());
01034   nassertr(other.verify_complete(current_thread), RenderState::make_empty());
01035 
01036   int a_count, b_count;
01037   if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
01038     if (allow_unrelated_wrt) {
01039       pgraph_cat.debug()
01040         << *this << " is not related to " << other << "\n";
01041     } else {
01042       pgraph_cat.error()
01043         << *this << " is not related to " << other << "\n";
01044       nassertr(false, RenderState::make_empty());
01045     }
01046   }
01047 
01048   CPT(RenderState) a_state = r_get_partial_state(_head, a_count, current_thread);
01049   CPT(RenderState) b_state = r_get_partial_state(other._head, b_count, current_thread);
01050   return b_state->invert_compose(a_state);
01051 }
01052 
01053 ////////////////////////////////////////////////////////////////////
01054 //     Function: NodePath::set_state
01055 //       Access: Published
01056 //  Description: Sets the state object on this node, relative to
01057 //               the other node.  This computes a new state object
01058 //               that will have the indicated value when seen from the
01059 //               other node.
01060 ////////////////////////////////////////////////////////////////////
01061 void NodePath::
01062 set_state(const NodePath &other, const RenderState *state,
01063           Thread *current_thread) {
01064   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
01065   nassertv_always(!is_empty());
01066 
01067   // First, we perform a wrt to the parent, to get the conversion.
01068   CPT(RenderState) rel_state;
01069   if (has_parent()) {
01070     rel_state = other.get_state(get_parent(current_thread), current_thread);
01071   } else {
01072     rel_state = other.get_state(NodePath(), current_thread);
01073   }
01074 
01075   CPT(RenderState) new_state = rel_state->compose(state);
01076   set_state(new_state, current_thread);
01077 }
01078 
01079 ////////////////////////////////////////////////////////////////////
01080 //     Function: NodePath::get_transform
01081 //       Access: Published
01082 //  Description: Returns the complete transform object set on this node.
01083 ////////////////////////////////////////////////////////////////////
01084 const TransformState *NodePath::
01085 get_transform(Thread *current_thread) const {
01086   // This method is declared non-inline to avoid a compiler bug in
01087   // gcc-3.4 and gcc-4.0.
01088   nassertr_always(!is_empty(), TransformState::make_identity());
01089   return node()->get_transform(current_thread);
01090 }
01091 
01092 ////////////////////////////////////////////////////////////////////
01093 //     Function: NodePath::get_transform
01094 //       Access: Published
01095 //  Description: Returns the relative transform to this node from the
01096 //               other node; i.e. the transformation of this node
01097 //               as seen from the other node.
01098 ////////////////////////////////////////////////////////////////////
01099 CPT(TransformState) NodePath::
01100 get_transform(const NodePath &other, Thread *current_thread) const {
01101   nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
01102   PStatTimer timer(_get_transform_pcollector);
01103 
01104   if (other.is_empty()) {
01105     return get_net_transform(current_thread);
01106   }
01107   if (is_empty()) {
01108     return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity());
01109   }
01110 
01111   nassertr(verify_complete(current_thread), TransformState::make_identity());
01112   nassertr(other.verify_complete(current_thread), TransformState::make_identity());
01113 
01114   int a_count, b_count;
01115   if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
01116     if (allow_unrelated_wrt) {
01117       if (pgraph_cat.is_debug()) {
01118         pgraph_cat.debug()
01119           << *this << " is not related to " << other << "\n";
01120       }
01121     } else {
01122       pgraph_cat.error()
01123         << *this << " is not related to " << other << "\n";
01124       nassertr(false, TransformState::make_identity());
01125     }
01126   }
01127 
01128   CPT(TransformState) a_transform, b_transform;
01129 
01130   a_transform = r_get_partial_transform(_head, a_count, current_thread);
01131   if (a_transform != (TransformState *)NULL) {
01132     b_transform = r_get_partial_transform(other._head, b_count, current_thread);
01133   }
01134   if (b_transform == (TransformState *)NULL) {
01135     // If either path involved a node with a net_transform
01136     // RenderEffect applied, we have to go all the way up to the root
01137     // to get the right answer.
01138     a_transform = r_get_net_transform(_head, current_thread);
01139     b_transform = r_get_net_transform(other._head, current_thread);
01140   }
01141 
01142   return b_transform->invert_compose(a_transform);
01143 }
01144 
01145 ////////////////////////////////////////////////////////////////////
01146 //     Function: NodePath::set_transform
01147 //       Access: Published
01148 //  Description: Sets the transform object on this node, relative to
01149 //               the other node.  This computes a new transform object
01150 //               that will have the indicated value when seen from the
01151 //               other node.
01152 ////////////////////////////////////////////////////////////////////
01153 void NodePath::
01154 set_transform(const NodePath &other, const TransformState *transform,
01155               Thread *current_thread) {
01156   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
01157   nassertv_always(!is_empty());
01158 
01159   // First, we perform a wrt to the parent, to get the conversion.
01160   CPT(TransformState) rel_trans;
01161   if (has_parent()) {
01162     rel_trans = other.get_transform(get_parent(current_thread), current_thread);
01163   } else {
01164     rel_trans = other.get_transform(NodePath(), current_thread);
01165   }
01166 
01167   CPT(TransformState) new_trans = rel_trans->compose(transform);
01168   set_transform(new_trans, current_thread);
01169 }
01170 
01171 ////////////////////////////////////////////////////////////////////
01172 //     Function: NodePath::get_prev_transform
01173 //       Access: Published
01174 //  Description: Returns the transform that has been set as this
01175 //               node's "previous" position.  See
01176 //               set_prev_transform().
01177 ////////////////////////////////////////////////////////////////////
01178 const TransformState *NodePath::
01179 get_prev_transform(Thread *current_thread) const {
01180   // This method is declared non-inline to avoid a compiler bug in
01181   // gcc-3.4 and gcc-4.0.
01182   nassertr_always(!is_empty(), TransformState::make_identity());
01183   return node()->get_prev_transform(current_thread);
01184 }
01185 
01186 ////////////////////////////////////////////////////////////////////
01187 //     Function: NodePath::get_prev_transform
01188 //       Access: Published
01189 //  Description: Returns the relative "previous" transform to this
01190 //               node from the other node; i.e. the position of this
01191 //               node in the previous frame, as seen by the other node
01192 //               in the previous frame.
01193 ////////////////////////////////////////////////////////////////////
01194 CPT(TransformState) NodePath::
01195 get_prev_transform(const NodePath &other, Thread *current_thread) const {
01196   nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
01197 
01198   if (other.is_empty()) {
01199     return get_net_prev_transform(current_thread);
01200   }
01201   if (is_empty()) {
01202     return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity());
01203   }
01204     
01205   nassertr(verify_complete(current_thread), TransformState::make_identity());
01206   nassertr(other.verify_complete(current_thread), TransformState::make_identity());
01207 
01208   int a_count, b_count;
01209   if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
01210     if (allow_unrelated_wrt) {
01211       pgraph_cat.debug()
01212         << *this << " is not related to " << other << "\n";
01213     } else {
01214       pgraph_cat.error()
01215         << *this << " is not related to " << other << "\n";
01216       nassertr(false, TransformState::make_identity());
01217     }
01218   }
01219 
01220   CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count, current_thread);
01221   CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count, current_thread);
01222   return b_prev_transform->invert_compose(a_prev_transform);
01223 }
01224 
01225 ////////////////////////////////////////////////////////////////////
01226 //     Function: NodePath::set_prev_transform
01227 //       Access: Published
01228 //  Description: Sets the "previous" transform object on this node,
01229 //               relative to the other node.  This computes a new
01230 //               transform object that will have the indicated value
01231 //               when seen from the other node.
01232 ////////////////////////////////////////////////////////////////////
01233 void NodePath::
01234 set_prev_transform(const NodePath &other, const TransformState *transform,
01235                    Thread *current_thread) {
01236   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
01237   nassertv_always(!is_empty());
01238 
01239   // First, we perform a wrt to the parent, to get the conversion.
01240   CPT(TransformState) rel_trans;
01241   if (has_parent(current_thread)) {
01242     rel_trans = other.get_prev_transform(get_parent(current_thread), current_thread);
01243   } else {
01244     rel_trans = other.get_prev_transform(NodePath(), current_thread);
01245   }
01246 
01247   CPT(TransformState) new_trans = rel_trans->compose(transform);
01248   set_prev_transform(new_trans, current_thread);
01249 }
01250 
01251 ////////////////////////////////////////////////////////////////////
01252 //     Function: NodePath::set_pos
01253 //       Access: Published
01254 //  Description: Sets the translation component of the transform,
01255 //               leaving rotation and scale untouched.  This also
01256 //               resets the node's "previous" position, so that the
01257 //               collision system will see the node as having suddenly
01258 //               appeared in the new position, without passing any
01259 //               points in between.
01260 //     See Also: NodePath::set_fluid_pos
01261 ////////////////////////////////////////////////////////////////////
01262 void NodePath::
01263 set_pos(const LVecBase3 &pos) {
01264   nassertv_always(!is_empty());
01265   set_transform(get_transform()->set_pos(pos));
01266   node()->reset_prev_transform();
01267 }
01268 
01269 void NodePath::
01270 set_x(PN_stdfloat x) {
01271   nassertv_always(!is_empty());
01272   LPoint3 pos = get_pos();
01273   pos[0] = x;
01274   set_pos(pos);
01275 }
01276 
01277 void NodePath::
01278 set_y(PN_stdfloat y) {
01279   nassertv_always(!is_empty());
01280   LPoint3 pos = get_pos();
01281   pos[1] = y;
01282   set_pos(pos);
01283 }
01284 
01285 void NodePath::
01286 set_z(PN_stdfloat z) {
01287   nassertv_always(!is_empty());
01288   LPoint3 pos = get_pos();
01289   pos[2] = z;
01290   set_pos(pos);
01291 }
01292 
01293 ////////////////////////////////////////////////////////////////////
01294 //     Function: NodePath::set_fluid_pos
01295 //       Access: Published
01296 //  Description: Sets the translation component, without changing the
01297 //               "previous" position, so that the collision system
01298 //               will see the node as moving fluidly from its previous
01299 //               position to its new position.
01300 //     See Also: NodePath::set_pos
01301 ////////////////////////////////////////////////////////////////////
01302 void NodePath::
01303 set_fluid_pos(const LVecBase3 &pos) {
01304   nassertv_always(!is_empty());
01305   set_transform(get_transform()->set_pos(pos));
01306 }
01307 
01308 void NodePath::
01309 set_fluid_x(PN_stdfloat x) {
01310   nassertv_always(!is_empty());
01311   LPoint3 pos = get_pos();
01312   pos[0] = x;
01313   set_fluid_pos(pos);
01314 }
01315 
01316 void NodePath::
01317 set_fluid_y(PN_stdfloat y) {
01318   nassertv_always(!is_empty());
01319   LPoint3 pos = get_pos();
01320   pos[1] = y;
01321   set_fluid_pos(pos);
01322 }
01323 
01324 void NodePath::
01325 set_fluid_z(PN_stdfloat z) {
01326   nassertv_always(!is_empty());
01327   LPoint3 pos = get_pos();
01328   pos[2] = z;
01329   set_fluid_pos(pos);
01330 }
01331 
01332 ////////////////////////////////////////////////////////////////////
01333 //     Function: NodePath::get_pos
01334 //       Access: Published
01335 //  Description: Retrieves the translation component of the transform.
01336 ////////////////////////////////////////////////////////////////////
01337 LPoint3 NodePath::
01338 get_pos() const {
01339   nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
01340   return get_transform()->get_pos();
01341 }
01342 
01343 ////////////////////////////////////////////////////////////////////
01344 //     Function: NodePath::get_pos_delta
01345 //       Access: Published
01346 //  Description: Returns the delta vector from this node's position in
01347 //               the previous frame (according to
01348 //               set_prev_transform(), typically set via the use of
01349 //               set_fluid_pos()) and its position in the current
01350 //               frame.  This is the vector used to determine
01351 //               collisions.  Generally, if the node was last
01352 //               repositioned via set_pos(), the delta will be zero;
01353 //               if it was adjusted via set_fluid_pos(), the delta
01354 //               will represent the change from the previous frame's
01355 //               position.
01356 ////////////////////////////////////////////////////////////////////
01357 LVector3 NodePath::
01358 get_pos_delta() const {
01359   nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
01360   return get_transform()->get_pos() - get_prev_transform()->get_pos();
01361 }
01362 
01363 ////////////////////////////////////////////////////////////////////
01364 //     Function: NodePath::set_hpr
01365 //       Access: Published
01366 //  Description: Sets the rotation component of the transform,
01367 //               leaving translation and scale untouched.
01368 ////////////////////////////////////////////////////////////////////
01369 void NodePath::
01370 set_hpr(const LVecBase3 &hpr) {
01371   nassertv_always(!is_empty());
01372   CPT(TransformState) transform = get_transform();
01373   nassertv(transform->has_hpr());
01374   set_transform(transform->set_hpr(hpr));
01375 }
01376 
01377 void NodePath::
01378 set_h(PN_stdfloat h) {
01379   nassertv_always(!is_empty());
01380   CPT(TransformState) transform = get_transform();
01381   nassertv(transform->has_hpr());
01382   LVecBase3 hpr = transform->get_hpr();
01383   hpr[0] = h;
01384   set_transform(transform->set_hpr(hpr));
01385 }
01386 
01387 void NodePath::
01388 set_p(PN_stdfloat p) {
01389   nassertv_always(!is_empty());
01390   CPT(TransformState) transform = get_transform();
01391   nassertv(transform->has_hpr());
01392   LVecBase3 hpr = transform->get_hpr();
01393   hpr[1] = p;
01394   set_transform(transform->set_hpr(hpr));
01395 }
01396 
01397 void NodePath::
01398 set_r(PN_stdfloat r) {
01399   nassertv_always(!is_empty());
01400   CPT(TransformState) transform = get_transform();
01401   nassertv(transform->has_hpr());
01402   LVecBase3 hpr = transform->get_hpr();
01403   hpr[2] = r;
01404   set_transform(transform->set_hpr(hpr));
01405 }
01406 
01407 ////////////////////////////////////////////////////////////////////
01408 //     Function: NodePath::get_hpr
01409 //       Access: Published
01410 //  Description: Retrieves the rotation component of the transform.
01411 ////////////////////////////////////////////////////////////////////
01412 LVecBase3 NodePath::
01413 get_hpr() const {
01414   nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
01415   CPT(TransformState) transform = get_transform();
01416   nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f));
01417   return transform->get_hpr();
01418 }
01419 
01420 ////////////////////////////////////////////////////////////////////
01421 //     Function: NodePath::set_quat
01422 //       Access: Published
01423 //  Description: Sets the rotation component of the transform,
01424 //               leaving translation and scale untouched.
01425 ////////////////////////////////////////////////////////////////////
01426 void NodePath::
01427 set_quat(const LQuaternion &quat) {
01428   nassertv_always(!is_empty());
01429   CPT(TransformState) transform = get_transform();
01430   set_transform(transform->set_quat(quat));
01431 }
01432 
01433 ////////////////////////////////////////////////////////////////////
01434 //     Function: NodePath::get_quat
01435 //       Access: Published
01436 //  Description: Retrieves the rotation component of the transform.
01437 ////////////////////////////////////////////////////////////////////
01438 LQuaternion NodePath::
01439 get_quat() const {
01440   nassertr_always(!is_empty(), LQuaternion::ident_quat());
01441   CPT(TransformState) transform = get_transform();
01442   return transform->get_quat();
01443 }
01444 
01445 ////////////////////////////////////////////////////////////////////
01446 //     Function: NodePath::set_scale
01447 //       Access: Published
01448 //  Description: Sets the scale component of the transform,
01449 //               leaving translation and rotation untouched.
01450 ////////////////////////////////////////////////////////////////////
01451 void NodePath::
01452 set_scale(const LVecBase3 &scale) {
01453   nassertv_always(!is_empty());
01454   CPT(TransformState) transform = get_transform();
01455   set_transform(transform->set_scale(scale));
01456 }
01457 
01458 void NodePath::
01459 set_sx(PN_stdfloat sx) {
01460   nassertv_always(!is_empty());
01461   CPT(TransformState) transform = get_transform();
01462   LVecBase3 scale = transform->get_scale();
01463   scale[0] = sx;
01464   set_transform(transform->set_scale(scale));
01465 }
01466 
01467 void NodePath::
01468 set_sy(PN_stdfloat sy) {
01469   nassertv_always(!is_empty());
01470   CPT(TransformState) transform = get_transform();
01471   LVecBase3 scale = transform->get_scale();
01472   scale[1] = sy;
01473   set_transform(transform->set_scale(scale));
01474 }
01475 
01476 void NodePath::
01477 set_sz(PN_stdfloat sz) {
01478   nassertv_always(!is_empty());
01479   CPT(TransformState) transform = get_transform();
01480   LVecBase3 scale = transform->get_scale();
01481   scale[2] = sz;
01482   set_transform(transform->set_scale(scale));
01483 }
01484 
01485 ////////////////////////////////////////////////////////////////////
01486 //     Function: NodePath::get_scale
01487 //       Access: Published
01488 //  Description: Retrieves the scale component of the transform.
01489 ////////////////////////////////////////////////////////////////////
01490 LVecBase3 NodePath::
01491 get_scale() const {
01492   nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
01493   CPT(TransformState) transform = get_transform();
01494   return transform->get_scale();
01495 }
01496 
01497 ////////////////////////////////////////////////////////////////////
01498 //     Function: NodePath::set_shear
01499 //       Access: Published
01500 //  Description: Sets the shear component of the transform,
01501 //               leaving translation and rotation untouched.
01502 ////////////////////////////////////////////////////////////////////
01503 void NodePath::
01504 set_shear(const LVecBase3 &shear) {
01505   nassertv_always(!is_empty());
01506   CPT(TransformState) transform = get_transform();
01507   set_transform(transform->set_shear(shear));
01508 }
01509 
01510 void NodePath::
01511 set_shxy(PN_stdfloat shxy) {
01512   nassertv_always(!is_empty());
01513   CPT(TransformState) transform = get_transform();
01514   LVecBase3 shear = transform->get_shear();
01515   shear[0] = shxy;
01516   set_transform(transform->set_shear(shear));
01517 }
01518 
01519 void NodePath::
01520 set_shxz(PN_stdfloat shxz) {
01521   nassertv_always(!is_empty());
01522   CPT(TransformState) transform = get_transform();
01523   LVecBase3 shear = transform->get_shear();
01524   shear[1] = shxz;
01525   set_transform(transform->set_shear(shear));
01526 }
01527 
01528 void NodePath::
01529 set_shyz(PN_stdfloat shyz) {
01530   nassertv_always(!is_empty());
01531   CPT(TransformState) transform = get_transform();
01532   LVecBase3 shear = transform->get_shear();
01533   shear[2] = shyz;
01534   set_transform(transform->set_shear(shear));
01535 }
01536 
01537 ////////////////////////////////////////////////////////////////////
01538 //     Function: NodePath::get_shear
01539 //       Access: Published
01540 //  Description: Retrieves the shear component of the transform.
01541 ////////////////////////////////////////////////////////////////////
01542 LVecBase3 NodePath::
01543 get_shear() const {
01544   nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
01545   CPT(TransformState) transform = get_transform();
01546   return transform->get_shear();
01547 }
01548 
01549 ////////////////////////////////////////////////////////////////////
01550 //     Function: NodePath::set_pos_hpr
01551 //       Access: Published
01552 //  Description: Sets the translation and rotation component of the
01553 //               transform, leaving scale untouched.
01554 ////////////////////////////////////////////////////////////////////
01555 void NodePath::
01556 set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr) {
01557   nassertv_always(!is_empty());
01558   CPT(TransformState) transform = get_transform();
01559   transform = TransformState::make_pos_hpr_scale_shear
01560     (pos, hpr, transform->get_scale(), transform->get_shear());
01561   set_transform(transform);
01562   node()->reset_prev_transform();
01563 }
01564 
01565 ////////////////////////////////////////////////////////////////////
01566 //     Function: NodePath::set_pos_quat
01567 //       Access: Published
01568 //  Description: Sets the translation and rotation component of the
01569 //               transform, leaving scale untouched.
01570 ////////////////////////////////////////////////////////////////////
01571 void NodePath::
01572 set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat) {
01573   nassertv_always(!is_empty());
01574   CPT(TransformState) transform = get_transform();
01575   transform = TransformState::make_pos_quat_scale_shear
01576     (pos, quat, transform->get_scale(), transform->get_shear());
01577   set_transform(transform);
01578   node()->reset_prev_transform();
01579 }
01580 
01581 ////////////////////////////////////////////////////////////////////
01582 //     Function: NodePath::set_hpr_scale
01583 //       Access: Published
01584 //  Description: Sets the rotation and scale components of the
01585 //               transform, leaving translation untouched.
01586 ////////////////////////////////////////////////////////////////////
01587 void NodePath::
01588 set_hpr_scale(const LVecBase3 &hpr, const LVecBase3 &scale) {
01589   nassertv_always(!is_empty());
01590   CPT(TransformState) transform = get_transform();
01591   transform = TransformState::make_pos_hpr_scale_shear
01592     (transform->get_pos(), hpr, scale, transform->get_shear());
01593   set_transform(transform);
01594 }
01595 
01596 ////////////////////////////////////////////////////////////////////
01597 //     Function: NodePath::set_quat_scale
01598 //       Access: Published
01599 //  Description: Sets the rotation and scale components of the
01600 //               transform, leaving translation untouched.
01601 ////////////////////////////////////////////////////////////////////
01602 void NodePath::
01603 set_quat_scale(const LQuaternion &quat, const LVecBase3 &scale) {
01604   nassertv_always(!is_empty());
01605   CPT(TransformState) transform = get_transform();
01606   transform = TransformState::make_pos_quat_scale_shear
01607     (transform->get_pos(), quat, scale, transform->get_shear());
01608   set_transform(transform);
01609 }
01610 
01611 ////////////////////////////////////////////////////////////////////
01612 //     Function: NodePath::set_pos_hpr_scale
01613 //       Access: Published
01614 //  Description: Replaces the translation, rotation, and scale
01615 //               components, implicitly setting shear to 0.
01616 ////////////////////////////////////////////////////////////////////
01617 void NodePath::
01618 set_pos_hpr_scale(const LVecBase3 &pos, const LVecBase3 &hpr,
01619                   const LVecBase3 &scale) {
01620   nassertv_always(!is_empty());
01621   set_transform(TransformState::make_pos_hpr_scale
01622                 (pos, hpr, scale));
01623   node()->reset_prev_transform();
01624 }
01625 
01626 ////////////////////////////////////////////////////////////////////
01627 //     Function: NodePath::set_pos_quat_scale
01628 //       Access: Published
01629 //  Description: Replaces the translation, rotation, and scale
01630 //               components, implicitly setting shear to 0.
01631 ////////////////////////////////////////////////////////////////////
01632 void NodePath::
01633 set_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat,
01634                    const LVecBase3 &scale) {
01635   nassertv_always(!is_empty());
01636   set_transform(TransformState::make_pos_quat_scale
01637                 (pos, quat, scale));
01638   node()->reset_prev_transform();
01639 }
01640 
01641 ////////////////////////////////////////////////////////////////////
01642 //     Function: NodePath::set_pos_hpr_scale_shear
01643 //       Access: Published
01644 //  Description: Completely replaces the transform with new
01645 //               translation, rotation, scale, and shear components.
01646 ////////////////////////////////////////////////////////////////////
01647 void NodePath::
01648 set_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr,
01649                         const LVecBase3 &scale, const LVecBase3 &shear) {
01650   nassertv_always(!is_empty());
01651   set_transform(TransformState::make_pos_hpr_scale_shear
01652                 (pos, hpr, scale, shear));
01653   node()->reset_prev_transform();
01654 }
01655 
01656 ////////////////////////////////////////////////////////////////////
01657 //     Function: NodePath::set_pos_quat_scale_shear
01658 //       Access: Published
01659 //  Description: Completely replaces the transform with new
01660 //               translation, rotation, scale, and shear components.
01661 ////////////////////////////////////////////////////////////////////
01662 void NodePath::
01663 set_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat,
01664                          const LVecBase3 &scale, const LVecBase3 &shear) {
01665   nassertv_always(!is_empty());
01666   set_transform(TransformState::make_pos_quat_scale_shear
01667                 (pos, quat, scale, shear));
01668   node()->reset_prev_transform();
01669 }
01670 
01671 ////////////////////////////////////////////////////////////////////
01672 //     Function: NodePath::set_mat
01673 //       Access: Published
01674 //  Description: Directly sets an arbitrary 4x4 transform matrix.
01675 ////////////////////////////////////////////////////////////////////
01676 void NodePath::
01677 set_mat(const LMatrix4 &mat) {
01678   nassertv_always(!is_empty());
01679   set_transform(TransformState::make_mat(mat));
01680   node()->reset_prev_transform();
01681 }
01682 
01683 ////////////////////////////////////////////////////////////////////
01684 //     Function: NodePath::look_at
01685 //       Access: Published
01686 //  Description: Sets the hpr on this NodePath so that it
01687 //               rotates to face the indicated point in space.
01688 ////////////////////////////////////////////////////////////////////
01689 void NodePath::
01690 look_at(const LPoint3 &point, const LVector3 &up) {
01691   nassertv_always(!is_empty());
01692 
01693   LPoint3 pos = get_pos();
01694 
01695   LQuaternion quat;
01696   ::look_at(quat, point - pos, up);
01697   set_quat(quat);
01698 }
01699 
01700 ////////////////////////////////////////////////////////////////////
01701 //     Function: NodePath::heads_up
01702 //       Access: Published
01703 //  Description: Behaves like look_at(), but with a strong preference
01704 //               to keeping the up vector oriented in the indicated
01705 //               "up" direction.
01706 ////////////////////////////////////////////////////////////////////
01707 void NodePath::
01708 heads_up(const LPoint3 &point, const LVector3 &up) {
01709   nassertv_always(!is_empty());
01710 
01711   LPoint3 pos = get_pos();
01712 
01713   LQuaternion quat;
01714   ::heads_up(quat, point - pos, up);
01715   set_quat(quat);
01716 }
01717 
01718 ////////////////////////////////////////////////////////////////////
01719 //     Function: NodePath::set_pos
01720 //       Access: Published
01721 //  Description: Sets the translation component of the transform,
01722 //               relative to the other node.
01723 ////////////////////////////////////////////////////////////////////
01724 void NodePath::
01725 set_pos(const NodePath &other, const LVecBase3 &pos) {
01726   nassertv_always(!is_empty());
01727   CPT(TransformState) rel_transform = get_transform(other);
01728 
01729   CPT(TransformState) orig_transform = get_transform();
01730   if (orig_transform->has_components()) {
01731     // If we had a componentwise transform before we started, we
01732     // should be careful to preserve the other three components.  We
01733     // wouldn't need to do this, except for the possibility of
01734     // numerical error or decompose ambiguity.
01735     const LVecBase3 &orig_hpr = orig_transform->get_hpr();
01736     const LVecBase3 &orig_scale = orig_transform->get_scale();
01737     const LVecBase3 &orig_shear = orig_transform->get_shear();
01738 
01739     set_transform(other, rel_transform->set_pos(pos));
01740     set_pos_hpr_scale_shear(get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear);
01741 
01742   } else {
01743     // If we didn't have a componentwise transform already, never
01744     // mind.
01745     set_transform(other, rel_transform->set_pos(pos));
01746   }
01747   node()->reset_prev_transform();
01748 }
01749 
01750 void NodePath::
01751 set_x(const NodePath &other, PN_stdfloat x) {
01752   nassertv_always(!is_empty());
01753   LPoint3 pos = get_pos(other);
01754   pos[0] = x;
01755   set_pos(other, pos);
01756 }
01757 
01758 void NodePath::
01759 set_y(const NodePath &other, PN_stdfloat y) {
01760   nassertv_always(!is_empty());
01761   LPoint3 pos = get_pos(other);
01762   pos[1] = y;
01763   set_pos(other, pos);
01764 }
01765 
01766 void NodePath::
01767 set_z(const NodePath &other, PN_stdfloat z) {
01768   nassertv_always(!is_empty());
01769   LPoint3 pos = get_pos(other);
01770   pos[2] = z;
01771   set_pos(other, pos);
01772 }
01773 
01774 ////////////////////////////////////////////////////////////////////
01775 //     Function: NodePath::set_fluid_pos
01776 //       Access: Published
01777 //  Description: Sets the translation component of the transform,
01778 //               relative to the other node.
01779 ////////////////////////////////////////////////////////////////////
01780 void NodePath::
01781 set_fluid_pos(const NodePath &other, const LVecBase3 &pos) {
01782   nassertv_always(!is_empty());
01783   CPT(TransformState) rel_transform = get_transform(other);
01784 
01785   CPT(TransformState) orig_transform = get_transform();
01786   if (orig_transform->has_components()) {
01787     // If we had a componentwise transform before we started, we
01788     // should be careful to preserve the other three components.  We
01789     // wouldn't need to do this, except for the possibility of
01790     // numerical error or decompose ambiguity.
01791     const LVecBase3 &orig_hpr = orig_transform->get_hpr();
01792     const LVecBase3 &orig_scale = orig_transform->get_scale();
01793     const LVecBase3 &orig_shear = orig_transform->get_shear();
01794 
01795     // Use the relative set_transform() to compute the relative pos, and
01796     // then reset all of the other components back to the way they were.
01797     set_transform(other, rel_transform->set_pos(pos));
01798     set_transform(TransformState::make_pos_hpr_scale_shear
01799                   (get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear));
01800 
01801   } else {
01802     // If we didn't have a componentwise transform already, never
01803     // mind.
01804     set_transform(other, rel_transform->set_pos(pos));
01805   }
01806 }
01807 
01808 void NodePath::
01809 set_fluid_x(const NodePath &other, PN_stdfloat x) {
01810   nassertv_always(!is_empty());
01811   LPoint3 pos = get_pos(other);
01812   pos[0] = x;
01813   set_fluid_pos(other, pos);
01814 }
01815 
01816 void NodePath::
01817 set_fluid_y(const NodePath &other, PN_stdfloat y) {
01818   nassertv_always(!is_empty());
01819   LPoint3 pos = get_pos(other);
01820   pos[1] = y;
01821   set_fluid_pos(other, pos);
01822 }
01823 
01824 void NodePath::
01825 set_fluid_z(const NodePath &other, PN_stdfloat z) {
01826   nassertv_always(!is_empty());
01827   LPoint3 pos = get_pos(other);
01828   pos[2] = z;
01829   set_fluid_pos(other, pos);
01830 }
01831 
01832 ////////////////////////////////////////////////////////////////////
01833 //     Function: NodePath::get_pos
01834 //       Access: Published
01835 //  Description: Returns the relative position of the referenced node
01836 //               as seen from the other node.
01837 ////////////////////////////////////////////////////////////////////
01838 LPoint3 NodePath::
01839 get_pos(const NodePath &other) const {
01840   nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
01841   return get_transform(other)->get_pos();
01842 }
01843 
01844 ////////////////////////////////////////////////////////////////////
01845 //     Function: NodePath::get_pos_delta
01846 //       Access: Published
01847 //  Description: Returns the delta vector from this node's position in
01848 //               the previous frame (according to
01849 //               set_prev_transform(), typically set via the use of
01850 //               set_fluid_pos()) and its position in the current
01851 //               frame, as seen in the indicated node's coordinate
01852 //               space.  This is the vector used to determine
01853 //               collisions.  Generally, if the node was last
01854 //               repositioned via set_pos(), the delta will be zero;
01855 //               if it was adjusted via set_fluid_pos(), the delta
01856 //               will represent the change from the previous frame's
01857 //               position.
01858 ////////////////////////////////////////////////////////////////////
01859 LVector3 NodePath::
01860 get_pos_delta(const NodePath &other) const {
01861   nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f));
01862   return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos();
01863 }
01864 
01865 ////////////////////////////////////////////////////////////////////
01866 //     Function: NodePath::set_hpr
01867 //       Access: Published
01868 //  Description: Sets the rotation component of the transform,
01869 //               relative to the other node.
01870 ////////////////////////////////////////////////////////////////////
01871 void NodePath::
01872 set_hpr(const NodePath &other, const LVecBase3 &hpr) {
01873   nassertv_always(!is_empty());
01874   CPT(TransformState) rel_transform = get_transform(other);
01875   nassertv(rel_transform->has_hpr());
01876 
01877   CPT(TransformState) orig_transform = get_transform();
01878   if (orig_transform->has_components()) {
01879     // If we had a componentwise transform before we started, we
01880     // should be careful to preserve the other three components.  We
01881     // wouldn't need to do this, except for the possibility of
01882     // numerical error or decompose ambiguity.
01883     const LVecBase3 &orig_pos = orig_transform->get_pos();
01884     const LVecBase3 &orig_scale = orig_transform->get_scale();
01885     const LVecBase3 &orig_shear = orig_transform->get_shear();
01886 
01887     set_transform(other, rel_transform->set_hpr(hpr));
01888     const TransformState *new_transform = get_transform();
01889     if (new_transform->has_components()) {
01890       set_transform(TransformState::make_pos_hpr_scale_shear
01891                     (orig_pos, new_transform->get_hpr(), orig_scale, orig_shear));
01892     }
01893 
01894   } else {
01895     // If we didn't have a componentwise transform already, never
01896     // mind.
01897     set_transform(other, rel_transform->set_hpr(hpr));
01898   }
01899 }
01900 
01901 void NodePath::
01902 set_h(const NodePath &other, PN_stdfloat h) {
01903   nassertv_always(!is_empty());
01904   LVecBase3 hpr = get_hpr(other);
01905   hpr[0] = h;
01906   set_hpr(other, hpr);
01907 }
01908 
01909 void NodePath::
01910 set_p(const NodePath &other, PN_stdfloat p) {
01911   nassertv_always(!is_empty());
01912   LVecBase3 hpr = get_hpr(other);
01913   hpr[1] = p;
01914   set_hpr(other, hpr);
01915 }
01916 
01917 void NodePath::
01918 set_r(const NodePath &other, PN_stdfloat r) {
01919   nassertv_always(!is_empty());
01920   LVecBase3 hpr = get_hpr(other);
01921   hpr[2] = r;
01922   set_hpr(other, hpr);
01923 }
01924 
01925 ////////////////////////////////////////////////////////////////////
01926 //     Function: NodePath::get_hpr
01927 //       Access: Published
01928 //  Description: Returns the relative orientation of the bottom node
01929 //               as seen from the other node.
01930 ////////////////////////////////////////////////////////////////////
01931 LVecBase3 NodePath::
01932 get_hpr(const NodePath &other) const {
01933   nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
01934   CPT(TransformState) transform = get_transform(other);
01935   nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f));
01936   return transform->get_hpr();
01937 }
01938 
01939 ////////////////////////////////////////////////////////////////////
01940 //     Function: NodePath::set_quat
01941 //       Access: Published
01942 //  Description: Sets the rotation component of the transform,
01943 //               relative to the other node.
01944 ////////////////////////////////////////////////////////////////////
01945 void NodePath::
01946 set_quat(const NodePath &other, const LQuaternion &quat) {
01947   nassertv_always(!is_empty());
01948   CPT(TransformState) rel_transform = get_transform(other);
01949 
01950   CPT(TransformState) orig_transform = get_transform();
01951   if (orig_transform->has_components()) {
01952     // If we had a componentwise transform before we started, we
01953     // should be careful to preserve the other three components.  We
01954     // wouldn't need to do this, except for the possibility of
01955     // numerical error or decompose ambiguity.
01956     const LVecBase3 &orig_pos = orig_transform->get_pos();
01957     const LVecBase3 &orig_scale = orig_transform->get_scale();
01958     const LVecBase3 &orig_shear = orig_transform->get_shear();
01959 
01960     set_transform(other, rel_transform->set_quat(quat));
01961     const TransformState *new_transform = get_transform();
01962     if (new_transform->has_components()) {
01963       set_transform(TransformState::make_pos_quat_scale_shear
01964                     (orig_pos, new_transform->get_quat(), orig_scale, orig_shear));
01965     }
01966 
01967   } else {
01968     // If we didn't have a componentwise transform already, never
01969     // mind.
01970     set_transform(other, rel_transform->set_quat(quat));
01971   }
01972 }
01973 
01974 ////////////////////////////////////////////////////////////////////
01975 //     Function: NodePath::get_quat
01976 //       Access: Published
01977 //  Description: Returns the relative orientation of the bottom node
01978 //               as seen from the other node.
01979 ////////////////////////////////////////////////////////////////////
01980 LQuaternion NodePath::
01981 get_quat(const NodePath &other) const {
01982   nassertr_always(!is_empty(), LQuaternion::ident_quat());
01983   CPT(TransformState) transform = get_transform(other);
01984   return transform->get_quat();
01985 }
01986 
01987 ////////////////////////////////////////////////////////////////////
01988 //     Function: NodePath::set_scale
01989 //       Access: Published
01990 //  Description: Sets the scale component of the transform,
01991 //               relative to the other node.
01992 ////////////////////////////////////////////////////////////////////
01993 void NodePath::
01994 set_scale(const NodePath &other, const LVecBase3 &scale) {
01995   nassertv_always(!is_empty());
01996   CPT(TransformState) rel_transform = get_transform(other);
01997 
01998   CPT(TransformState) orig_transform = get_transform();
01999   if (orig_transform->has_components()) {
02000     // If we had a componentwise transform before we started, we
02001     // should be careful to preserve the other three components.  We
02002     // wouldn't need to do this, except for the possibility of
02003     // numerical error or decompose ambiguity.
02004     const LVecBase3 &orig_pos = orig_transform->get_pos();
02005     const LVecBase3 &orig_hpr = orig_transform->get_hpr();
02006     const LVecBase3 &orig_shear = orig_transform->get_shear();
02007 
02008     set_transform(other, rel_transform->set_scale(scale));
02009     const TransformState *new_transform = get_transform();
02010     if (new_transform->has_components()) {
02011       set_transform(TransformState::make_pos_hpr_scale_shear
02012                     (orig_pos, orig_hpr, new_transform->get_scale(), orig_shear));
02013     }
02014 
02015   } else {
02016     // If we didn't have a componentwise transform already, never
02017     // mind.
02018     set_transform(other, rel_transform->set_scale(scale));
02019   }
02020 }
02021 
02022 void NodePath::
02023 set_sx(const NodePath &other, PN_stdfloat sx) {
02024   nassertv_always(!is_empty());
02025   LVecBase3 scale = get_scale(other);
02026   scale[0] = sx;
02027   set_scale(other, scale);
02028 }
02029 
02030 void NodePath::
02031 set_sy(const NodePath &other, PN_stdfloat sy) {
02032   nassertv_always(!is_empty());
02033   LVecBase3 scale = get_scale(other);
02034   scale[1] = sy;
02035   set_scale(other, scale);
02036 }
02037 
02038 void NodePath::
02039 set_sz(const NodePath &other, PN_stdfloat sz) {
02040   nassertv_always(!is_empty());
02041   LVecBase3 scale = get_scale(other);
02042   scale[2] = sz;
02043   set_scale(other, scale);
02044 }
02045 
02046 ////////////////////////////////////////////////////////////////////
02047 //     Function: NodePath::get_scale
02048 //       Access: Published
02049 //  Description: Returns the relative scale of the bottom node
02050 //               as seen from the other node.
02051 ////////////////////////////////////////////////////////////////////
02052 LVecBase3 NodePath::
02053 get_scale(const NodePath &other) const {
02054   nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
02055   CPT(TransformState) transform = get_transform(other);
02056   return transform->get_scale();
02057 }
02058 
02059 ////////////////////////////////////////////////////////////////////
02060 //     Function: NodePath::set_shear
02061 //       Access: Published
02062 //  Description: Sets the shear component of the transform,
02063 //               relative to the other node.
02064 ////////////////////////////////////////////////////////////////////
02065 void NodePath::
02066 set_shear(const NodePath &other, const LVecBase3 &shear) {
02067   nassertv_always(!is_empty());
02068   CPT(TransformState) rel_transform = get_transform(other);
02069 
02070   CPT(TransformState) orig_transform = get_transform();
02071   if (orig_transform->has_components()) {
02072     // If we had a componentwise transform before we started, we
02073     // should be careful to preserve the other three components.  We
02074     // wouldn't need to do this, except for the possibility of
02075     // numerical error or decompose ambiguity.
02076     const LVecBase3 &orig_pos = orig_transform->get_pos();
02077     const LVecBase3 &orig_hpr = orig_transform->get_hpr();
02078     const LVecBase3 &orig_scale = orig_transform->get_scale();
02079 
02080     set_transform(other, rel_transform->set_shear(shear));
02081     const TransformState *new_transform = get_transform();
02082     if (new_transform->has_components()) {
02083       set_transform(TransformState::make_pos_hpr_scale_shear
02084                     (orig_pos, orig_hpr, orig_scale, new_transform->get_shear()));
02085     }
02086 
02087   } else {
02088     // If we didn't have a componentwise transform already, never
02089     // mind.
02090     set_transform(other, rel_transform->set_shear(shear));
02091   }
02092 }
02093 
02094 void NodePath::
02095 set_shxy(const NodePath &other, PN_stdfloat shxy) {
02096   nassertv_always(!is_empty());
02097   LVecBase3 shear = get_shear(other);
02098   shear[0] = shxy;
02099   set_shear(other, shear);
02100 }
02101 
02102 void NodePath::
02103 set_shxz(const NodePath &other, PN_stdfloat shxz) {
02104   nassertv_always(!is_empty());
02105   LVecBase3 shear = get_shear(other);
02106   shear[1] = shxz;
02107   set_shear(other, shear);
02108 }
02109 
02110 void NodePath::
02111 set_shyz(const NodePath &other, PN_stdfloat shyz) {
02112   nassertv_always(!is_empty());
02113   LVecBase3 shear = get_shear(other);
02114   shear[2] = shyz;
02115   set_shear(other, shear);
02116 }
02117 
02118 ////////////////////////////////////////////////////////////////////
02119 //     Function: NodePath::get_shear
02120 //       Access: Published
02121 //  Description: Returns the relative shear of the bottom node
02122 //               as seen from the other node.
02123 ////////////////////////////////////////////////////////////////////
02124 LVecBase3 NodePath::
02125 get_shear(const NodePath &other) const {
02126   nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f));
02127   CPT(TransformState) transform = get_transform(other);
02128   return transform->get_shear();
02129 }
02130 
02131 ////////////////////////////////////////////////////////////////////
02132 //     Function: NodePath::set_pos_hpr
02133 //       Access: Published
02134 //  Description: Sets the translation and rotation component of the
02135 //               transform, relative to the other node.
02136 ////////////////////////////////////////////////////////////////////
02137 void NodePath::
02138 set_pos_hpr(const NodePath &other, const LVecBase3 &pos,
02139             const LVecBase3 &hpr) {
02140   nassertv_always(!is_empty());
02141   CPT(TransformState) rel_transform = get_transform(other);
02142 
02143   CPT(TransformState) orig_transform = get_transform();
02144   if (orig_transform->has_components()) {
02145     // If we had a componentwise transform before we started, we
02146     // should be careful to preserve the other two components.  We
02147     // wouldn't need to do this, except for the possibility of
02148     // numerical error or decompose ambiguity.
02149     const LVecBase3 &orig_scale = orig_transform->get_scale();
02150     const LVecBase3 &orig_shear = orig_transform->get_shear();
02151 
02152     set_transform(other, TransformState::make_pos_hpr_scale_shear
02153                   (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
02154     const TransformState *new_transform = get_transform();
02155     if (new_transform->has_components()) {
02156       set_pos_hpr_scale_shear(new_transform->get_pos(), new_transform->get_hpr(),
02157                               orig_scale, orig_shear);
02158     }
02159 
02160   } else {
02161     // If we didn't have a componentwise transform already, never
02162     // mind.
02163     set_transform(other, TransformState::make_pos_hpr_scale_shear
02164                   (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
02165     node()->reset_prev_transform();
02166   }
02167 }
02168 
02169 ////////////////////////////////////////////////////////////////////
02170 //     Function: NodePath::set_pos_quat
02171 //       Access: Published
02172 //  Description: Sets the translation and rotation component of the
02173 //               transform, relative to the other node.
02174 ////////////////////////////////////////////////////////////////////
02175 void NodePath::
02176 set_pos_quat(const NodePath &other, const LVecBase3 &pos,
02177              const LQuaternion &quat) {
02178   nassertv_always(!is_empty());
02179   CPT(TransformState) rel_transform = get_transform(other);
02180   
02181   CPT(TransformState) orig_transform = get_transform();
02182   if (orig_transform->has_components()) {
02183     // If we had a componentwise transform before we started, we
02184     // should be careful to preserve the other two components.  We
02185     // wouldn't need to do this, except for the possibility of
02186     // numerical error or decompose ambiguity.
02187     const LVecBase3 &orig_scale = orig_transform->get_scale();
02188     const LVecBase3 &orig_shear = orig_transform->get_shear();
02189 
02190     set_transform(other, TransformState::make_pos_quat_scale_shear
02191                   (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
02192     const TransformState *new_transform = get_transform();
02193     if (new_transform->has_components()) {
02194       set_pos_quat_scale_shear(new_transform->get_pos(), new_transform->get_quat(),
02195                                orig_scale, orig_shear);
02196     }
02197 
02198   } else {
02199     // If we didn't have a componentwise transform already, never
02200     // mind.
02201     set_transform(other, TransformState::make_pos_quat_scale_shear
02202                   (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
02203     node()->reset_prev_transform();
02204   }
02205 }
02206 
02207 ////////////////////////////////////////////////////////////////////
02208 //     Function: NodePath::set_hpr_scale
02209 //       Access: Published
02210 //  Description: Sets the rotation and scale components of the
02211 //               transform, leaving translation untouched.  This, or
02212 //               set_pos_hpr_scale, is the preferred way to update a
02213 //               transform when both hpr and scale are to be changed.
02214 ////////////////////////////////////////////////////////////////////
02215 void NodePath::
02216 set_hpr_scale(const NodePath &other, const LVecBase3 &hpr, const LVecBase3 &scale) {
02217   // We don't bother trying very hard to preserve pos across this
02218   // operation, unlike the work we do above to preserve hpr or scale,
02219   // since it generally doesn't matter that much if pos is off by a
02220   // few thousandths.
02221   nassertv_always(!is_empty());
02222   CPT(TransformState) transform = get_transform(other);
02223   transform = TransformState::make_pos_hpr_scale_shear
02224     (transform->get_pos(), hpr, scale, transform->get_shear());
02225   set_transform(other, transform);
02226 }
02227 
02228 ////////////////////////////////////////////////////////////////////
02229 //     Function: NodePath::set_quat_scale
02230 //       Access: Published
02231 //  Description: Sets the rotation and scale components of the
02232 //               transform, leaving translation untouched.  This, or
02233 //               set_pos_quat_scale, is the preferred way to update a
02234 //               transform when both quat and scale are to be changed.
02235 ////////////////////////////////////////////////////////////////////
02236 void NodePath::
02237 set_quat_scale(const NodePath &other, const LQuaternion &quat, 
02238                const LVecBase3 &scale) {
02239   // We don't bother trying very hard to preserve pos across this
02240   // operation, unlike the work we do above to preserve quat or scale,
02241   // since it generally doesn't matter that much if pos is off by a
02242   // few thousandths.
02243   nassertv_always(!is_empty());
02244   CPT(TransformState) transform = get_transform(other);
02245   transform = TransformState::make_pos_quat_scale_shear
02246     (transform->get_pos(), quat, scale, transform->get_shear());
02247   set_transform(other, transform);
02248 }
02249 
02250 ////////////////////////////////////////////////////////////////////
02251 //     Function: NodePath::set_pos_hpr_scale
02252 //       Access: Published
02253 //  Description: Completely replaces the transform with new
02254 //               translation, rotation, and scale components, relative
02255 //               to the other node, implicitly setting shear to 0.
02256 ////////////////////////////////////////////////////////////////////
02257 void NodePath::
02258 set_pos_hpr_scale(const NodePath &other,
02259                   const LVecBase3 &pos, const LVecBase3 &hpr,
02260                   const LVecBase3 &scale) {
02261   nassertv_always(!is_empty());
02262   set_transform(other, TransformState::make_pos_hpr_scale
02263                 (pos, hpr, scale));
02264   node()->reset_prev_transform();
02265 }
02266 
02267 ////////////////////////////////////////////////////////////////////
02268 //     Function: NodePath::set_pos_quat_scale
02269 //       Access: Published
02270 //  Description: Completely replaces the transform with new
02271 //               translation, rotation, and scale components, relative
02272 //               to the other node, implicitly setting shear to 0.
02273 ////////////////////////////////////////////////////////////////////
02274 void NodePath::
02275 set_pos_quat_scale(const NodePath &other,
02276                    const LVecBase3 &pos, const LQuaternion &quat,
02277                    const LVecBase3 &scale) {
02278   nassertv_always(!is_empty());
02279   set_transform(other, TransformState::make_pos_quat_scale
02280                 (pos, quat, scale));
02281   node()->reset_prev_transform();
02282 }
02283 
02284 ////////////////////////////////////////////////////////////////////
02285 //     Function: NodePath::set_pos_hpr_scale_shear
02286 //       Access: Published
02287 //  Description: Completely replaces the transform with new
02288 //               translation, rotation, scale, and shear components,
02289 //               relative to the other node.
02290 ////////////////////////////////////////////////////////////////////
02291 void NodePath::
02292 set_pos_hpr_scale_shear(const NodePath &other,
02293                         const LVecBase3 &pos, const LVecBase3 &hpr,
02294                         const LVecBase3 &scale, const LVecBase3 &shear) {
02295   nassertv_always(!is_empty());
02296   set_transform(other, TransformState::make_pos_hpr_scale_shear
02297                 (pos, hpr, scale, shear));
02298   node()->reset_prev_transform();
02299 }
02300 
02301 ////////////////////////////////////////////////////////////////////
02302 //     Function: NodePath::set_pos_quat_scale_shear
02303 //       Access: Published
02304 //  Description: Completely replaces the transform with new
02305 //               translation, rotation, scale, and shear components,
02306 //               relative to the other node.
02307 ////////////////////////////////////////////////////////////////////
02308 void NodePath::
02309 set_pos_quat_scale_shear(const NodePath &other,
02310                          const LVecBase3 &pos, const LQuaternion &quat,
02311                          const LVecBase3 &scale, const LVecBase3 &shear) {
02312   nassertv_always(!is_empty());
02313   set_transform(other, TransformState::make_pos_quat_scale_shear
02314                 (pos, quat, scale, shear));
02315   node()->reset_prev_transform();
02316 }
02317 
02318 ////////////////////////////////////////////////////////////////////
02319 //     Function: NodePath::get_mat
02320 //       Access: Published
02321 //  Description: Returns the matrix that describes the coordinate
02322 //               space of the bottom node, relative to the other
02323 //               path's bottom node's coordinate space.
02324 ////////////////////////////////////////////////////////////////////
02325 LMatrix4 NodePath::
02326 get_mat(const NodePath &other) const {
02327   CPT(TransformState) transform = get_transform(other);
02328   // We can't safely return a reference to the matrix, because we
02329   // can't assume the transform won't go away when the function
02330   // returns.  If the transform was partially modified by, say, a
02331   // CompassEffect, it won't be stored in the cache, and thus we might
02332   // have the only reference to it.
02333   return transform->get_mat();
02334 }
02335 
02336 ////////////////////////////////////////////////////////////////////
02337 //     Function: NodePath::set_mat
02338 //       Access: Published
02339 //  Description: Converts the indicated matrix from the other's
02340 //               coordinate space to the local coordinate space, and
02341 //               applies it to the node.
02342 ////////////////////////////////////////////////////////////////////
02343 void NodePath::
02344 set_mat(const NodePath &other, const LMatrix4 &mat) {
02345   nassertv_always(!is_empty());
02346   set_transform(other, TransformState::make_mat(mat));
02347   node()->reset_prev_transform();
02348 }
02349 
02350 ////////////////////////////////////////////////////////////////////
02351 //     Function: NodePath::get_relative_point
02352 //       Access: Published
02353 //  Description: Given that the indicated point is in the coordinate
02354 //               system of the other node, returns the same point in
02355 //               this node's coordinate system.
02356 ////////////////////////////////////////////////////////////////////
02357 LPoint3 NodePath::
02358 get_relative_point(const NodePath &other, const LVecBase3 &point) const {
02359   CPT(TransformState) transform = other.get_transform(*this);
02360   LPoint3 rel_point = LPoint3(point) * transform->get_mat();
02361   return rel_point;
02362 }
02363 
02364 ////////////////////////////////////////////////////////////////////
02365 //     Function: NodePath::get_relative_vector
02366 //       Access: Published
02367 //  Description: Given that the indicated vector is in the coordinate
02368 //               system of the other node, returns the same vector in
02369 //               this node's coordinate system.
02370 ////////////////////////////////////////////////////////////////////
02371 LVector3 NodePath::
02372 get_relative_vector(const NodePath &other, const LVecBase3 &vec) const {
02373   CPT(TransformState) transform = other.get_transform(*this);
02374   LVector3 rel_vector = LVector3(vec) * transform->get_mat();
02375   return rel_vector;
02376 }
02377 
02378 ////////////////////////////////////////////////////////////////////
02379 //     Function: NodePath::look_at
02380 //       Access: Published
02381 //  Description: Sets the transform on this NodePath so that it
02382 //               rotates to face the indicated point in space, which
02383 //               is relative to the other NodePath.
02384 ////////////////////////////////////////////////////////////////////
02385 void NodePath::
02386 look_at(const NodePath &other, const LPoint3 &point, const LVector3 &up) {
02387   nassertv_always(!is_empty());
02388 
02389   CPT(TransformState) transform = other.get_transform(get_parent());
02390   LPoint3 rel_point = point * transform->get_mat();
02391 
02392   LPoint3 pos = get_pos();
02393 
02394   LQuaternion quat;
02395   ::look_at(quat, rel_point - pos, up);
02396   set_quat(quat);
02397 }
02398 
02399 ////////////////////////////////////////////////////////////////////
02400 //     Function: NodePath::heads_up
02401 //       Access: Published
02402 //  Description: Behaves like look_at(), but with a strong preference
02403 //               to keeping the up vector oriented in the indicated
02404 //               "up" direction.
02405 ////////////////////////////////////////////////////////////////////
02406 void NodePath::
02407 heads_up(const NodePath &other, const LPoint3 &point, const LVector3 &up) {
02408   nassertv_always(!is_empty());
02409 
02410   CPT(TransformState) transform = other.get_transform(get_parent());
02411   LPoint3 rel_point = point * transform->get_mat();
02412 
02413   LPoint3 pos = get_pos();
02414 
02415   LQuaternion quat;
02416   ::heads_up(quat, rel_point - pos, up);
02417   set_quat(quat);
02418 }
02419 
02420 
02421 ////////////////////////////////////////////////////////////////////
02422 //     Function: NodePath::set_color
02423 //       Access: Published
02424 //  Description: Applies a scene-graph color to the referenced node.
02425 //               This color will apply to all geometry at this level
02426 //               and below (that does not specify a new color or a
02427 //               set_color_off()).
02428 ////////////////////////////////////////////////////////////////////
02429 void NodePath::
02430 set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a,
02431           int priority) {
02432   set_color(LColor(r, g, b, a), priority);
02433 }
02434 
02435 ////////////////////////////////////////////////////////////////////
02436 //     Function: NodePath::set_color
02437 //       Access: Published
02438 //  Description: Applies a scene-graph color to the referenced node.
02439 //               This color will apply to all geometry at this level
02440 //               and below (that does not specify a new color or a
02441 //               set_color_off()).
02442 ////////////////////////////////////////////////////////////////////
02443 void NodePath::
02444 set_color(const LColor &color, int priority) {
02445   nassertv_always(!is_empty());
02446   node()->set_attrib(ColorAttrib::make_flat(color), priority);
02447 }
02448 
02449 ////////////////////////////////////////////////////////////////////
02450 //     Function: NodePath::set_color_off
02451 //       Access: Published
02452 //  Description: Sets the geometry at this level and below to render
02453 //               using the geometry color.  This is normally the
02454 //               default, but it may be useful to use this to
02455 //               contradict set_color() at a higher node level (or,
02456 //               with a priority, to override a set_color() at a lower
02457 //               level).
02458 ////////////////////////////////////////////////////////////////////
02459 void NodePath::
02460 set_color_off(int priority) {
02461   nassertv_always(!is_empty());
02462   node()->set_attrib(ColorAttrib::make_vertex(), priority);
02463 }
02464 
02465 ////////////////////////////////////////////////////////////////////
02466 //     Function: NodePath::clear_color
02467 //       Access: Published
02468 //  Description: Completely removes any color adjustment from the node.
02469 //               This allows the natural color of the geometry, or
02470 //               whatever color transitions might be otherwise
02471 //               affecting the geometry, to show instead.
02472 ////////////////////////////////////////////////////////////////////
02473 void NodePath::
02474 clear_color() {
02475   nassertv_always(!is_empty());
02476   node()->clear_attrib(ColorAttrib::get_class_slot());
02477 }
02478 
02479 ////////////////////////////////////////////////////////////////////
02480 //     Function: NodePath::has_color
02481 //       Access: Published
02482 //  Description: Returns true if a color has been applied to the given
02483 //               node, false otherwise.
02484 ////////////////////////////////////////////////////////////////////
02485 bool NodePath::
02486 has_color() const {
02487   nassertr_always(!is_empty(), false);
02488   return node()->has_attrib(ColorAttrib::get_class_slot());
02489 }
02490 
02491 ////////////////////////////////////////////////////////////////////
02492 //     Function: NodePath::get_color
02493 //       Access: Published
02494 //  Description: Returns the color that has been assigned to the node,
02495 //               or black if no color has been assigned.
02496 ////////////////////////////////////////////////////////////////////
02497 LColor NodePath::
02498 get_color() const {
02499   nassertr_always(!is_empty(), false);
02500   const RenderAttrib *attrib =
02501     node()->get_attrib(ColorAttrib::get_class_slot());
02502   if (attrib != (const RenderAttrib *)NULL) {
02503     const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
02504     if (ca->get_color_type() == ColorAttrib::T_flat) {
02505       return ca->get_color();
02506     }
02507   }
02508 
02509   pgraph_cat.warning()
02510     << "get_color() called on " << *this << " which has no color set.\n";
02511 
02512   return LColor(1.0f, 1.0f, 1.0f, 1.0f);
02513 }
02514 
02515 ////////////////////////////////////////////////////////////////////
02516 //     Function: NodePath::has_color_scale
02517 //       Access: Published
02518 //  Description: Returns true if a color scale has been applied
02519 //               to the referenced node, false otherwise.  It is still
02520 //               possible that color at this node might have been
02521 //               scaled by an ancestor node.
02522 ////////////////////////////////////////////////////////////////////
02523 bool NodePath::
02524 has_color_scale() const {
02525   nassertr_always(!is_empty(), false);
02526   return node()->has_attrib(ColorScaleAttrib::get_class_slot());
02527 }
02528 
02529 ////////////////////////////////////////////////////////////////////
02530 //     Function: NodePath::clear_color_scale
02531 //       Access: Published
02532 //  Description: Completely removes any color scale from the
02533 //               referenced node.  This is preferable to simply
02534 //               setting the color scale to identity, as it also
02535 //               removes the overhead associated with having a color
02536 //               scale at all.
02537 ////////////////////////////////////////////////////////////////////
02538 void NodePath::
02539 clear_color_scale() {
02540   nassertv_always(!is_empty());
02541   node()->clear_attrib(ColorScaleAttrib::get_class_slot());
02542 }
02543 
02544 ////////////////////////////////////////////////////////////////////
02545 //     Function: NodePath::compose_color_scale
02546 //       Access: Published
02547 //  Description: multiplies the color scale component of the transform,
02548 //               with previous color scale leaving translation and 
02549 //               rotation untouched.
02550 ////////////////////////////////////////////////////////////////////
02551 void NodePath::
02552 compose_color_scale(const LVecBase4 &scale, int priority) {
02553   nassertv_always(!is_empty());
02554 
02555   const RenderAttrib *attrib =
02556     node()->get_attrib(ColorScaleAttrib::get_class_slot());
02557   if (attrib != (const RenderAttrib *)NULL) {
02558     priority = max(priority,
02559                    node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
02560     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
02561 
02562     // Modify the existing ColorScaleAttrib by multiplying with the 
02563     // indicated colorScale.
02564     LVecBase4 prev_color_scale = csa->get_scale();
02565     LVecBase4 new_color_scale(prev_color_scale[0]*scale[0],
02566                                prev_color_scale[1]*scale[1],
02567                                prev_color_scale[2]*scale[2],
02568                                prev_color_scale[3]*scale[3]);
02569     node()->set_attrib(csa->set_scale(new_color_scale), priority);
02570 
02571   } else {
02572     // Create a new ColorScaleAttrib for this node.
02573     node()->set_attrib(ColorScaleAttrib::make(scale), priority);
02574   }
02575 }
02576 
02577 ////////////////////////////////////////////////////////////////////
02578 //     Function: NodePath::set_color_scale
02579 //       Access: Published
02580 //  Description: Sets the color scale component of the transform,
02581 //               leaving translation and rotation untouched.
02582 ////////////////////////////////////////////////////////////////////
02583 void NodePath::
02584 set_color_scale(const LVecBase4 &scale, int priority) {
02585   nassertv_always(!is_empty());
02586 
02587   const RenderAttrib *attrib =
02588     node()->get_attrib(ColorScaleAttrib::get_class_slot());
02589   if (attrib != (const RenderAttrib *)NULL) {
02590     priority = max(priority,
02591                    node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
02592     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
02593 
02594     // Modify the existing ColorScaleAttrib to add the indicated
02595     // colorScale.
02596     node()->set_attrib(csa->set_scale(scale), priority);
02597 
02598   } else {
02599     // Create a new ColorScaleAttrib for this node.
02600     node()->set_attrib(ColorScaleAttrib::make(scale), priority);
02601   }
02602 }
02603 
02604 ////////////////////////////////////////////////////////////////////
02605 //     Function: NodePath::set_color_scale_off
02606 //       Access: Published
02607 //  Description: Disables any color scale attribute inherited from
02608 //               above.  This is not the same thing as
02609 //               clear_color_scale(), which undoes any previous
02610 //               set_color_scale() operation on this node; rather,
02611 //               this actively disables any set_color_scale() that
02612 //               might be inherited from a parent node.  This also
02613 //               disables set_alpha_scale() at the same time.
02614 //
02615 //               It is legal to specify a new color scale on the same
02616 //               node with a subsequent call to set_color_scale() or
02617 //               set_alpha_scale(); this new scale will apply to lower
02618 //               geometry.
02619 ////////////////////////////////////////////////////////////////////
02620 void NodePath::
02621 set_color_scale_off(int priority) {
02622   nassertv_always(!is_empty());
02623   node()->set_attrib(ColorScaleAttrib::make_off(), priority);
02624 }
02625 
02626 ////////////////////////////////////////////////////////////////////
02627 //     Function: NodePath::set_alpha_scale
02628 //       Access: Published
02629 //  Description: Sets the alpha scale component of the transform
02630 //               without (much) affecting the color scale.  Note that
02631 //               any priority specified will also apply to the color
02632 //               scale.
02633 ////////////////////////////////////////////////////////////////////
02634 void NodePath::
02635 set_alpha_scale(PN_stdfloat scale, int priority) {
02636   nassertv_always(!is_empty());
02637 
02638   const RenderAttrib *attrib =
02639     node()->get_attrib(ColorScaleAttrib::get_class_slot());
02640   if (attrib != (const RenderAttrib *)NULL) {
02641     priority = max(priority,
02642                    node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
02643     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
02644 
02645     // Modify the existing ColorScaleAttrib to add the indicated
02646     // colorScale.
02647     const LVecBase4 &sc = csa->get_scale();
02648     node()->set_attrib(csa->set_scale(LVecBase4(sc[0], sc[1], sc[2], scale)), priority);
02649 
02650   } else {
02651     // Create a new ColorScaleAttrib for this node.
02652     node()->set_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, scale)), priority);
02653   }
02654 }
02655 
02656 ////////////////////////////////////////////////////////////////////
02657 //     Function: NodePath::set_all_color_scale
02658 //       Access: Published
02659 //  Description: Scales all the color components of the object by the
02660 //               same amount, darkening the object, without (much)
02661 //               affecting alpha.  Note that any priority specified
02662 //               will also apply to the alpha scale.
02663 ////////////////////////////////////////////////////////////////////
02664 void NodePath::
02665 set_all_color_scale(PN_stdfloat scale, int priority) {
02666   nassertv_always(!is_empty());
02667 
02668   const RenderAttrib *attrib =
02669     node()->get_attrib(ColorScaleAttrib::get_class_slot());
02670   if (attrib != (const RenderAttrib *)NULL) {
02671     priority = max(priority,
02672                    node()->get_state()->get_override(ColorScaleAttrib::get_class_slot()));
02673     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
02674 
02675     // Modify the existing ColorScaleAttrib to add the indicated
02676     // colorScale.
02677     const LVecBase4 &sc = csa->get_scale();
02678     node()->set_attrib(csa->set_scale(LVecBase4(scale, scale, scale, sc[3])), priority);
02679 
02680   } else {
02681     // Create a new ColorScaleAttrib for this node.
02682     node()->set_attrib(ColorScaleAttrib::make(LVecBase4(scale, scale, scale, 1.0f)), priority);
02683   }
02684 }
02685 
02686 ////////////////////////////////////////////////////////////////////
02687 //     Function: NodePath::get_color_scale
02688 //       Access: Published
02689 //  Description: Returns the complete color scale vector that has been
02690 //               applied to this node via a previous call to
02691 //               set_color_scale() and/or set_alpha_scale(), or all
02692 //               1's (identity) if no scale has been applied to this
02693 //               particular node.
02694 ////////////////////////////////////////////////////////////////////
02695 const LVecBase4 &NodePath::
02696 get_color_scale() const {
02697   static const LVecBase4 ident_scale(1.0f, 1.0f, 1.0f, 1.0f);
02698   nassertr_always(!is_empty(), ident_scale);
02699   const RenderAttrib *attrib =
02700     node()->get_attrib(ColorScaleAttrib::get_class_slot());
02701   if (attrib != (const RenderAttrib *)NULL) {
02702     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
02703     return csa->get_scale();
02704   }
02705 
02706   return ident_scale;
02707 }
02708 
02709 ////////////////////////////////////////////////////////////////////
02710 //     Function: NodePath::set_light
02711 //       Access: Published
02712 //  Description: Adds the indicated Light or PolylightNode to the list
02713 //               of lights that illuminate geometry at this node and
02714 //               below.  The light itself should be parented into the
02715 //               scene graph elsewhere, to represent the light's
02716 //               position in space; but until set_light() is called it
02717 //               will illuminate no geometry.
02718 ////////////////////////////////////////////////////////////////////
02719 void NodePath::
02720 set_light(const NodePath &light, int priority) {
02721   nassertv_always(!is_empty());
02722   if (!light.is_empty()) {
02723     Light *light_obj = light.node()->as_light();
02724     if (light_obj != (Light *)NULL) {
02725       // It's an actual Light object.
02726       const RenderAttrib *attrib =
02727         node()->get_attrib(LightAttrib::get_class_slot());
02728       if (attrib != (const RenderAttrib *)NULL) {
02729         priority = max(priority,
02730                        node()->get_state()->get_override(LightAttrib::get_class_slot()));
02731         const LightAttrib *la = DCAST(LightAttrib, attrib);
02732         
02733         // Modify the existing LightAttrib to add the indicated
02734         // light.
02735         node()->set_attrib(la->add_on_light(light), priority);
02736         
02737       } else {
02738         // Create a new LightAttrib for this node.
02739         CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
02740         node()->set_attrib(la->add_on_light(light), priority);
02741       }
02742       return;
02743 
02744     } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
02745       // It's a Polylight object.
02746       if (priority != 0) {
02747         // PolylightEffects can't have a priority, since they're just
02748         // an effect to be applied immediately.
02749         pgraph_cat.warning()
02750           << "Ignoring priority on set_light(" << light << ")\n";
02751       }
02752 
02753       const RenderEffect *effect =
02754         node()->get_effect(PolylightEffect::get_class_type());
02755       if (effect != (const RenderEffect *)NULL) {
02756         const PolylightEffect *ple = DCAST(PolylightEffect, effect);
02757         
02758         // Modify the existing PolylightEffect to add the indicated
02759         // light.
02760         node()->set_effect(ple->add_light(light));
02761         
02762       } else {
02763         // Create a new PolylightEffect for this node.
02764         CPT(PolylightEffect) ple = DCAST(PolylightEffect, PolylightEffect::make());
02765         node()->set_effect(ple->add_light(light));
02766       }
02767       return;
02768     }
02769   }
02770   nassert_raise("Not a Light object.");
02771 }
02772 
02773 ////////////////////////////////////////////////////////////////////
02774 //     Function: NodePath::set_light_off
02775 //       Access: Published
02776 //  Description: Sets the geometry at this level and below to render
02777 //               using no lights at all.  This is different
02778 //               from not specifying a light; rather, this
02779 //               specifically contradicts set_light() at a higher
02780 //               node level (or, with a priority, overrides a
02781 //               set_light() at a lower level).
02782 //
02783 //               If no lights are in effect on a particular piece of
02784 //               geometry, that geometry is rendered with lighting
02785 //               disabled.
02786 ////////////////////////////////////////////////////////////////////
02787 void NodePath::
02788 set_light_off(int priority) {
02789   nassertv_always(!is_empty());
02790   node()->set_attrib(LightAttrib::make_all_off(), priority);
02791   node()->clear_effect(PolylightEffect::get_class_type());
02792 }
02793 
02794 ////////////////////////////////////////////////////////////////////
02795 //     Function: NodePath::set_light_off
02796 //       Access: Published
02797 //  Description: Sets the geometry at this level and below to render
02798 //               without using the indicated Light.  This is different
02799 //               from not specifying the Light; rather, this
02800 //               specifically contradicts set_light() at a higher node
02801 //               level (or, with a priority, overrides a set_light()
02802 //               at a lower level).
02803 //
02804 //               This interface does not support PolylightNodes, which
02805 //               cannot be turned off at a lower level.
02806 ////////////////////////////////////////////////////////////////////
02807 void NodePath::
02808 set_light_off(const NodePath &light, int priority) {
02809   nassertv_always(!is_empty());
02810 
02811   if (!light.is_empty()) {
02812     Light *light_obj = light.node()->as_light();
02813     if (light_obj != (Light *)NULL) {
02814       const RenderAttrib *attrib =
02815         node()->get_attrib(LightAttrib::get_class_slot());
02816       if (attrib != (const RenderAttrib *)NULL) {
02817         priority = max(priority,
02818                        node()->get_state()->get_override(LightAttrib::get_class_slot()));
02819         const LightAttrib *la = DCAST(LightAttrib, attrib);
02820         
02821         // Modify the existing LightAttrib to add the indicated light
02822         // to the "off" list.  This also, incidentally, removes it from
02823         // the "on" list if it is there.
02824         node()->set_attrib(la->add_off_light(light), priority);
02825         
02826       } else {
02827         // Create a new LightAttrib for this node that turns off the
02828         // indicated light.
02829         CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
02830         node()->set_attrib(la->add_off_light(light), priority);
02831       }
02832       return;
02833     }
02834   }
02835   nassert_raise("Not a Light object.");
02836 }
02837 
02838 ////////////////////////////////////////////////////////////////////
02839 //     Function: NodePath::clear_light
02840 //       Access: Published
02841 //  Description: Completely removes any lighting operations that may
02842 //               have been set via set_light() or set_light_off()
02843 //               from this particular node.
02844 ////////////////////////////////////////////////////////////////////
02845 void NodePath::
02846 clear_light() {
02847   nassertv_always(!is_empty());
02848   node()->clear_attrib(LightAttrib::get_class_slot());
02849   node()->clear_effect(PolylightEffect::get_class_type());
02850 }
02851 
02852 ////////////////////////////////////////////////////////////////////
02853 //     Function: NodePath::clear_light
02854 //       Access: Published
02855 //  Description: Removes any reference to the indicated Light or
02856 //               PolylightNode from the NodePath.
02857 ////////////////////////////////////////////////////////////////////
02858 void NodePath::
02859 clear_light(const NodePath &light) {
02860   nassertv_always(!is_empty());
02861 
02862   if (!light.is_empty()) {
02863     Light *light_obj = light.node()->as_light();
02864     if (light_obj != (Light *)NULL) {
02865       const RenderAttrib *attrib =
02866         node()->get_attrib(LightAttrib::get_class_slot());
02867       if (attrib != (const RenderAttrib *)NULL) {
02868         CPT(LightAttrib) la = DCAST(LightAttrib, attrib);
02869         la = DCAST(LightAttrib, la->remove_on_light(light));
02870         la = DCAST(LightAttrib, la->remove_off_light(light));
02871         
02872         if (la->is_identity()) {
02873           node()->clear_attrib(LightAttrib::get_class_slot());
02874           
02875         } else {
02876           int priority = node()->get_state()->get_override(LightAttrib::get_class_slot());
02877           node()->set_attrib(la, priority);
02878         }
02879       }
02880       return;
02881 
02882     } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
02883       const RenderEffect *effect =
02884         node()->get_effect(PolylightEffect::get_class_type());
02885       if (effect != (const RenderEffect *)NULL) {
02886         CPT(PolylightEffect) ple = DCAST(PolylightEffect, effect);
02887         ple = DCAST(PolylightEffect, ple->remove_light(light));
02888         node()->set_effect(ple);
02889       }
02890       return;
02891     }
02892   }
02893   nassert_raise("Not a Light object.");
02894 }
02895 
02896 ////////////////////////////////////////////////////////////////////
02897 //     Function: NodePath::has_light
02898 //       Access: Published
02899 //  Description: Returns true if the indicated Light or PolylightNode
02900 //               has been specifically enabled on this particular
02901 //               node.  This means that someone called set_light() on
02902 //               this node with the indicated light.
02903 ////////////////////////////////////////////////////////////////////
02904 bool NodePath::
02905 has_light(const NodePath &light) const {
02906   nassertr_always(!is_empty(), false);
02907 
02908   if (!light.is_empty()) {
02909     Light *light_obj = light.node()->as_light();
02910     if (light_obj != (Light *)NULL) {
02911       const RenderAttrib *attrib =
02912         node()->get_attrib(LightAttrib::get_class_slot());
02913       if (attrib != (const RenderAttrib *)NULL) {
02914         const LightAttrib *la = DCAST(LightAttrib, attrib);
02915         return la->has_on_light(light);
02916       }
02917       return false;
02918 
02919     } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
02920       const RenderEffect *effect =
02921         node()->get_effect(PolylightEffect::get_class_type());
02922       if (effect != (const RenderEffect *)NULL) {
02923         const PolylightEffect *ple = DCAST(PolylightEffect, effect);
02924         return ple->has_light(light);
02925       }
02926       return false;
02927     }
02928   }
02929   nassert_raise("Not a Light object.");
02930   return false;
02931 }
02932 
02933 ////////////////////////////////////////////////////////////////////
02934 //     Function: NodePath::has_light_off
02935 //       Access: Published
02936 //  Description: Returns true if all Lights have been specifically
02937 //               disabled on this particular node.  This means that
02938 //               someone called set_light_off() on this node with no
02939 //               parameters.
02940 ////////////////////////////////////////////////////////////////////
02941 bool NodePath::
02942 has_light_off() const {
02943   nassertr_always(!is_empty(), false);
02944 
02945   const RenderAttrib *attrib =
02946     node()->get_attrib(LightAttrib::get_class_slot());
02947   if (attrib != (const RenderAttrib *)NULL) {
02948     const LightAttrib *la = DCAST(LightAttrib, attrib);
02949     return la->has_all_off();
02950   }
02951 
02952   return false;
02953 }
02954 
02955 ////////////////////////////////////////////////////////////////////
02956 //     Function: NodePath::has_light_off
02957 //       Access: Published
02958 //  Description: Returns true if the indicated Light has been
02959 //               specifically disabled on this particular node.  This
02960 //               means that someone called set_light_off() on this
02961 //               node with the indicated light.
02962 //
02963 //               This interface does not support PolylightNodes, which
02964 //               cannot be turned off at a lower level.
02965 ////////////////////////////////////////////////////////////////////
02966 bool NodePath::
02967 has_light_off(const NodePath &light) const {
02968   nassertr_always(!is_empty(), false);
02969   if (!light.is_empty()) {
02970     Light *light_obj = light.node()->as_light();
02971     if (light_obj != (Light *)NULL) {
02972       const RenderAttrib *attrib =
02973         node()->get_attrib(LightAttrib::get_class_slot());
02974       if (attrib != (const RenderAttrib *)NULL) {
02975         const LightAttrib *la = DCAST(LightAttrib, attrib);
02976         return la->has_off_light(light);
02977       }
02978     }
02979   }
02980   nassert_raise("Not a Light object.");
02981   return false;
02982 }
02983 
02984 ////////////////////////////////////////////////////////////////////
02985 //     Function: NodePath::set_clip_plane
02986 //       Access: Published
02987 //  Description: Adds the indicated clipping plane to the list of
02988 //               planes that apply to geometry at this node and below.
02989 //               The clipping plane itself, a PlaneNode, should be
02990 //               parented into the scene graph elsewhere, to represent
02991 //               the plane's position in space; but until
02992 //               set_clip_plane() is called it will clip no geometry.
02993 ////////////////////////////////////////////////////////////////////
02994 void NodePath::
02995 set_clip_plane(const NodePath &clip_plane, int priority) {
02996   nassertv_always(!is_empty());
02997   if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
02998     const RenderAttrib *attrib =
02999       node()->get_attrib(ClipPlaneAttrib::get_class_slot());
03000     if (attrib != (const RenderAttrib *)NULL) {
03001       priority = max(priority,
03002                      node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()));
03003       const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
03004       
03005       // Modify the existing ClipPlaneAttrib to add the indicated
03006       // clip_plane.
03007       node()->set_attrib(la->add_on_plane(clip_plane), priority);
03008       
03009     } else {
03010       // Create a new ClipPlaneAttrib for this node.
03011       CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
03012       node()->set_attrib(la->add_on_plane(clip_plane), priority);
03013     }
03014     return;
03015   }
03016   nassert_raise("Not a PlaneNode object.");
03017 }
03018 
03019 ////////////////////////////////////////////////////////////////////
03020 //     Function: NodePath::set_clip_plane_off
03021 //       Access: Published
03022 //  Description: Sets the geometry at this level and below to render
03023 //               using no clip_planes at all.  This is different
03024 //               from not specifying a clip_plane; rather, this
03025 //               specifically contradicts set_clip_plane() at a higher
03026 //               node level (or, with a priority, overrides a
03027 //               set_clip_plane() at a lower level).
03028 //
03029 //               If no clip_planes are in effect on a particular piece
03030 //               of geometry, that geometry is rendered without being
03031 //               clipped (other than by the viewing frustum).
03032 ////////////////////////////////////////////////////////////////////
03033 void NodePath::
03034 set_clip_plane_off(int priority) {
03035   nassertv_always(!is_empty());
03036   node()->set_attrib(ClipPlaneAttrib::make_all_off(), priority);
03037 }
03038 
03039 ////////////////////////////////////////////////////////////////////
03040 //     Function: NodePath::set_clip_plane_off
03041 //       Access: Published
03042 //  Description: Sets the geometry at this level and below to render
03043 //               without being clipped by the indicated PlaneNode.
03044 //               This is different from not specifying the PlaneNode;
03045 //               rather, this specifically contradicts
03046 //               set_clip_plane() at a higher node level (or, with a
03047 //               priority, overrides a set_clip_plane() at a lower
03048 //               level).
03049 ////////////////////////////////////////////////////////////////////
03050 void NodePath::
03051 set_clip_plane_off(const NodePath &clip_plane, int priority) {
03052   nassertv_always(!is_empty());
03053 
03054   if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
03055     const RenderAttrib *attrib =
03056       node()->get_attrib(ClipPlaneAttrib::get_class_slot());
03057     if (attrib != (const RenderAttrib *)NULL) {
03058       priority = max(priority,
03059                      node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()));
03060       const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
03061       
03062       // Modify the existing ClipPlaneAttrib to add the indicated clip_plane
03063       // to the "off" list.  This also, incidentally, removes it from
03064       // the "on" list if it is there.
03065       node()->set_attrib(la->add_off_plane(clip_plane), priority);
03066       
03067     } else {
03068       // Create a new ClipPlaneAttrib for this node that turns off the
03069       // indicated clip_plane.
03070       CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
03071       node()->set_attrib(la->add_off_plane(clip_plane), priority);
03072     }
03073     return;
03074   }
03075   nassert_raise("Not a PlaneNode object.");
03076 }
03077 
03078 ////////////////////////////////////////////////////////////////////
03079 //     Function: NodePath::clear_clip_plane
03080 //       Access: Published
03081 //  Description: Completely removes any clip planes that may have been
03082 //               set via set_clip_plane() or set_clip_plane_off() from
03083 //               this particular node.
03084 ////////////////////////////////////////////////////////////////////
03085 void NodePath::
03086 clear_clip_plane() {
03087   nassertv_always(!is_empty());
03088   node()->clear_attrib(ClipPlaneAttrib::get_class_slot());
03089 }
03090 
03091 ////////////////////////////////////////////////////////////////////
03092 //     Function: NodePath::clear_clip_plane
03093 //       Access: Published
03094 //  Description: Removes any reference to the indicated clipping plane
03095 //               from the NodePath.
03096 ////////////////////////////////////////////////////////////////////
03097 void NodePath::
03098 clear_clip_plane(const NodePath &clip_plane) {
03099   nassertv_always(!is_empty());
03100 
03101   if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
03102     const RenderAttrib *attrib =
03103       node()->get_attrib(ClipPlaneAttrib::get_class_slot());
03104     if (attrib != (const RenderAttrib *)NULL) {
03105       CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib);
03106       la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane));
03107       la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane));
03108         
03109       if (la->is_identity()) {
03110         node()->clear_attrib(ClipPlaneAttrib::get_class_slot());
03111           
03112       } else {
03113         int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot());
03114         node()->set_attrib(la, priority);
03115       }
03116     }
03117     return;
03118   }
03119   nassert_raise("Not a PlaneNode object.");
03120 }
03121 
03122 ////////////////////////////////////////////////////////////////////
03123 //     Function: NodePath::has_clip_plane
03124 //       Access: Published
03125 //  Description: Returns true if the indicated clipping plane has been
03126 //               specifically applied to this particular node.  This
03127 //               means that someone called set_clip_plane() on this
03128 //               node with the indicated clip_plane.
03129 ////////////////////////////////////////////////////////////////////
03130 bool NodePath::
03131 has_clip_plane(const NodePath &clip_plane) const {
03132   nassertr_always(!is_empty(), false);
03133 
03134   if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
03135     const RenderAttrib *attrib =
03136       node()->get_attrib(ClipPlaneAttrib::get_class_slot());
03137     if (attrib != (const RenderAttrib *)NULL) {
03138       const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
03139       return la->has_on_plane(clip_plane);
03140     }
03141     return false;
03142   }
03143   nassert_raise("Not a PlaneNode object.");
03144   return false;
03145 }
03146 
03147 ////////////////////////////////////////////////////////////////////
03148 //     Function: NodePath::has_clip_plane_off
03149 //       Access: Published
03150 //  Description: Returns true if all clipping planes have been
03151 //               specifically disabled on this particular node.  This
03152 //               means that someone called set_clip_plane_off() on
03153 //               this node with no parameters.
03154 ////////////////////////////////////////////////////////////////////
03155 bool NodePath::
03156 has_clip_plane_off() const {
03157   nassertr_always(!is_empty(), false);
03158 
03159   const RenderAttrib *attrib =
03160     node()->get_attrib(ClipPlaneAttrib::get_class_slot());
03161   if (attrib != (const RenderAttrib *)NULL) {
03162     const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
03163     return la->has_all_off();
03164   }
03165 
03166   return false;
03167 }
03168 
03169 ////////////////////////////////////////////////////////////////////
03170 //     Function: NodePath::has_clip_plane_off
03171 //       Access: Published
03172 //  Description: Returns true if the indicated clipping plane has been
03173 //               specifically disabled on this particular node.  This
03174 //               means that someone called set_clip_plane_off() on
03175 //               this node with the indicated clip_plane.
03176 ////////////////////////////////////////////////////////////////////
03177 bool NodePath::
03178 has_clip_plane_off(const NodePath &clip_plane) const {
03179   nassertr_always(!is_empty(), false);
03180   if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
03181     const RenderAttrib *attrib =
03182       node()->get_attrib(ClipPlaneAttrib::get_class_slot());
03183     if (attrib != (const RenderAttrib *)NULL) {
03184       const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
03185       return la->has_off_plane(clip_plane);
03186     }
03187   }
03188   nassert_raise("Not a PlaneNode object.");
03189   return false;
03190 }
03191 
03192 ////////////////////////////////////////////////////////////////////
03193 //     Function: NodePath::set_occluder
03194 //       Access: Published
03195 //  Description: Adds the indicated occluder to the list of
03196 //               occluders that apply to geometry at this node and below.
03197 //               The occluder itself, an OccluderNode, should be
03198 //               parented into the scene graph elsewhere, to represent
03199 //               the occluder's position in space; but until
03200 //               set_occluder() is called it will clip no geometry.
03201 ////////////////////////////////////////////////////////////////////
03202 void NodePath::
03203 set_occluder(const NodePath &occluder) {
03204   nassertv_always(!is_empty());
03205   if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
03206     const RenderEffect *effect =
03207       node()->get_effect(OccluderEffect::get_class_type());
03208     if (effect != (const RenderEffect *)NULL) {
03209       const OccluderEffect *la = DCAST(OccluderEffect, effect);
03210       
03211       // Modify the existing OccluderEffect to add the indicated
03212       // occluder.
03213       node()->set_effect(la->add_on_occluder(occluder));
03214       
03215     } else {
03216       // Create a new OccluderEffect for this node.
03217       CPT(OccluderEffect) la = DCAST(OccluderEffect, OccluderEffect::make());
03218       node()->set_effect(la->add_on_occluder(occluder));
03219     }
03220     return;
03221   }
03222   nassert_raise("Not an OccluderNode object.");
03223 }
03224 
03225 ////////////////////////////////////////////////////////////////////
03226 //     Function: NodePath::clear_occluder
03227 //       Access: Published
03228 //  Description: Completely removes any occluders that may have been
03229 //               set via set_occluder() from this particular node.
03230 ////////////////////////////////////////////////////////////////////
03231 void NodePath::
03232 clear_occluder() {
03233   nassertv_always(!is_empty());
03234   node()->clear_effect(OccluderEffect::get_class_type());
03235 }
03236 
03237 ////////////////////////////////////////////////////////////////////
03238 //     Function: NodePath::clear_occluder
03239 //       Access: Published
03240 //  Description: Removes any reference to the indicated occluder
03241 //               from the NodePath.
03242 ////////////////////////////////////////////////////////////////////
03243 void NodePath::
03244 clear_occluder(const NodePath &occluder) {
03245   nassertv_always(!is_empty());
03246 
03247   if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
03248     const RenderEffect *effect =
03249       node()->get_effect(OccluderEffect::get_class_type());
03250     if (effect != (const RenderEffect *)NULL) {
03251       CPT(OccluderEffect) la = DCAST(OccluderEffect, effect);
03252       la = DCAST(OccluderEffect, la->remove_on_occluder(occluder));
03253         
03254       if (la->is_identity()) {
03255         node()->clear_effect(OccluderEffect::get_class_type());
03256           
03257       } else {
03258         node()->set_effect(la);
03259       }
03260     }
03261     return;
03262   }
03263   nassert_raise("Not an OccluderNode object.");
03264 }
03265 
03266 ////////////////////////////////////////////////////////////////////
03267 //     Function: NodePath::has_occluder
03268 //       Access: Published
03269 //  Description: Returns true if the indicated occluder has been
03270 //               specifically applied to this particular node.  This
03271 //               means that someone called set_occluder() on this
03272 //               node with the indicated occluder.
03273 ////////////////////////////////////////////////////////////////////
03274 bool NodePath::
03275 has_occluder(const NodePath &occluder) const {
03276   nassertr_always(!is_empty(), false);
03277 
03278   if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) {
03279     const RenderEffect *effect =
03280       node()->get_effect(OccluderEffect::get_class_type());
03281     if (effect != (const RenderEffect *)NULL) {
03282       const OccluderEffect *la = DCAST(OccluderEffect, effect);
03283       return la->has_on_occluder(occluder);
03284     }
03285     return false;
03286   }
03287   nassert_raise("Not an OccluderNode object.");
03288   return false;
03289 }
03290 
03291 ////////////////////////////////////////////////////////////////////
03292 //     Function: NodePath::set_scissor
03293 //       Access: Published
03294 //  Description: Sets up a scissor region on the nodes rendered at
03295 //               this level and below.  The four coordinates are
03296 //               understood to define a rectangle in screen space.
03297 //               These numbers are relative to the current
03298 //               DisplayRegion, where (0,0) is the lower-left corner
03299 //               of the DisplayRegion, and (1,1) is the upper-right
03300 //               corner.
03301 ////////////////////////////////////////////////////////////////////
03302 void NodePath::
03303 set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
03304   set_effect(ScissorEffect::make_screen(LVecBase4(left, right, bottom, top)));
03305 }
03306 
03307 ////////////////////////////////////////////////////////////////////
03308 //     Function: NodePath::set_scissor
03309 //       Access: Published
03310 //  Description: Sets up a scissor region on the nodes rendered at
03311 //               this level and below.  The two points are understood
03312 //               to be relative to this node.  When these points are
03313 //               projected into screen space, they define the
03314 //               diagonally-opposite points that determine the scissor
03315 //               region.
03316 ////////////////////////////////////////////////////////////////////
03317 void NodePath::
03318 set_scissor(const LPoint3 &a, const LPoint3 &b) {
03319   set_effect(ScissorEffect::make_node(a, b));
03320 }
03321 
03322 ////////////////////////////////////////////////////////////////////
03323 //     Function: NodePath::set_scissor
03324 //       Access: Published
03325 //  Description: Sets up a scissor region on the nodes rendered at
03326 //               this level and below.  The four points are understood
03327 //               to be relative to this node.  When these points are
03328 //               projected into screen space, they define the
03329 //               bounding volume of the scissor region (the scissor
03330 //               region is the smallest onscreen rectangle that
03331 //               encloses all four points).
03332 ////////////////////////////////////////////////////////////////////
03333 void NodePath::
03334 set_scissor(const LPoint3 &a, const LPoint3 &b,
03335             const LPoint3 &c, const LPoint3 &d) {
03336   set_effect(ScissorEffect::make_node(a, b, c, d));
03337 }
03338 
03339 ////////////////////////////////////////////////////////////////////
03340 //     Function: NodePath::set_scissor
03341 //       Access: Published
03342 //  Description: Sets up a scissor region on the nodes rendered at
03343 //               this level and below.  The two points are understood
03344 //               to be relative to the indicated other node.  When
03345 //               these points are projected into screen space, they
03346 //               define the diagonally-opposite points that determine
03347 //               the scissor region.
03348 ////////////////////////////////////////////////////////////////////
03349 void NodePath::
03350 set_scissor(const NodePath &other, const LPoint3 &a, const LPoint3 &b) {
03351   set_effect(ScissorEffect::make_node(a, b, other));
03352 }
03353 
03354 ////////////////////////////////////////////////////////////////////
03355 //     Function: NodePath::set_scissor
03356 //       Access: Published
03357 //  Description: Sets up a scissor region on the nodes rendered at
03358 //               this level and below.  The four points are understood
03359 //               to be relative to the indicated other node.  When
03360 //               these points are projected into screen space, they
03361 //               define the bounding volume of the scissor region (the
03362 //               scissor region is the smallest onscreen rectangle
03363 //               that encloses all four points).
03364 ////////////////////////////////////////////////////////////////////
03365 void NodePath::
03366 set_scissor(const NodePath &other,
03367             const LPoint3 &a, const LPoint3 &b,
03368             const LPoint3 &c, const LPoint3 &d) {
03369   set_effect(ScissorEffect::make_node(a, b, c, d, other));
03370 }
03371 
03372 ////////////////////////////////////////////////////////////////////
03373 //     Function: NodePath::clear_scissor
03374 //       Access: Published
03375 //  Description: Removes the scissor region that was defined at this
03376 //               node level by a previous call to set_scissor().
03377 ////////////////////////////////////////////////////////////////////
03378 void NodePath::
03379 clear_scissor() {
03380   clear_effect(ScissorEffect::get_class_type());
03381 }
03382 
03383 ////////////////////////////////////////////////////////////////////
03384 //     Function: NodePath::has_scissor
03385 //       Access: Published
03386 //  Description: Returns true if a scissor region was defined at this
03387 //               node by a previous call to set_scissor().  This does
03388 //               not check for scissor regions inherited from a parent
03389 //               class.  It also does not check for the presence of a
03390 //               low-level ScissorAttrib, which is different from the
03391 //               ScissorEffect added by set_scissor.
03392 ////////////////////////////////////////////////////////////////////
03393 bool NodePath::
03394 has_scissor() const {
03395   return has_effect(ScissorEffect::get_class_type());
03396 }
03397 
03398 ////////////////////////////////////////////////////////////////////
03399 //     Function: NodePath::set_bin
03400 //       Access: Published
03401 //  Description: Assigns the geometry at this level and below to the
03402 //               named rendering bin.  It is the user's responsibility
03403 //               to ensure that such a bin already exists, either via
03404 //               the cull-bin Configrc variable, or by explicitly
03405 //               creating a GeomBin of the appropriate type at
03406 //               runtime.
03407 //
03408 //               There are two default bins created when Panda is
03409 //               started: "default" and "fixed".  Normally, all
03410 //               geometry is assigned to "default" unless specified
03411 //               otherwise.  This bin renders opaque geometry in
03412 //               state-sorted order, followed by transparent geometry
03413 //               sorted back-to-front.  If any geometry is assigned to
03414 //               "fixed", this will be rendered following all the
03415 //               geometry in "default", in the order specified by
03416 //               draw_order for each piece of geometry so assigned.
03417 //
03418 //               The draw_order parameter is meaningful only for
03419 //               GeomBinFixed type bins, e.g. "fixed".  Other kinds of
03420 //               bins ignore it.
03421 ////////////////////////////////////////////////////////////////////
03422 void NodePath::
03423 set_bin(const string &bin_name, int draw_order, int priority) {
03424   nassertv_always(!is_empty());
03425   node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority);
03426 }
03427 
03428 ////////////////////////////////////////////////////////////////////
03429 //     Function: NodePath::clear_bin
03430 //       Access: Published
03431 //  Description: Completely removes any bin adjustment that may have
03432 //               been set via set_bin() from this particular node.
03433 ////////////////////////////////////////////////////////////////////
03434 void NodePath::
03435 clear_bin() {
03436   nassertv_always(!is_empty());
03437   node()->clear_attrib(CullBinAttrib::get_class_slot());
03438 }
03439 
03440 ////////////////////////////////////////////////////////////////////
03441 //     Function: NodePath::has_bin
03442 //       Access: Published
03443 //  Description: Returns true if the node has been assigned to the a
03444 //               particular rendering bin via set_bin(), false
03445 //               otherwise.
03446 ////////////////////////////////////////////////////////////////////
03447 bool NodePath::
03448 has_bin() const {
03449   nassertr_always(!is_empty(), false);
03450   return node()->has_attrib(CullBinAttrib::get_class_slot());
03451 }
03452 
03453 ////////////////////////////////////////////////////////////////////
03454 //     Function: NodePath::get_bin_name
03455 //       Access: Published
03456 //  Description: Returns the name of the bin that this particular node
03457 //               was assigned to via set_bin(), or the empty string if
03458 //               no bin was assigned.  See set_bin() and has_bin().
03459 ////////////////////////////////////////////////////////////////////
03460 string NodePath::
03461 get_bin_name() const {
03462   nassertr_always(!is_empty(), string());
03463   const RenderAttrib *attrib =
03464     node()->get_attrib(CullBinAttrib::get_class_slot());
03465   if (attrib != (const RenderAttrib *)NULL) {
03466     const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
03467     return ba->get_bin_name();
03468   }
03469 
03470   return string();
03471 }
03472 
03473 ////////////////////////////////////////////////////////////////////
03474 //     Function: NodePath::get_bin_draw_order
03475 //       Access: Published
03476 //  Description: Returns the drawing order associated with the bin
03477 //               that this particular node was assigned to via
03478 //               set_bin(), or 0 if no bin was assigned.  See
03479 //               set_bin() and has_bin().
03480 ////////////////////////////////////////////////////////////////////
03481 int NodePath::
03482 get_bin_draw_order() const {
03483   nassertr_always(!is_empty(), false);
03484   const RenderAttrib *attrib =
03485     node()->get_attrib(CullBinAttrib::get_class_slot());
03486   if (attrib != (const RenderAttrib *)NULL) {
03487     const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
03488     return ba->get_draw_order();
03489   }
03490 
03491   return 0;
03492 }
03493 
03494 ////////////////////////////////////////////////////////////////////
03495 //     Function: NodePath::set_texture
03496 //       Access: Published
03497 //  Description: Adds the indicated texture to the list of textures
03498 //               that will be rendered on the default texture stage.
03499 //
03500 //               This is the convenience single-texture variant of
03501 //               this method; it is now superceded by set_texture()
03502 //               that accepts a stage and texture.  You may use this
03503 //               method if you just want to adjust the default stage.
03504 ////////////////////////////////////////////////////////////////////
03505 void NodePath::
03506 set_texture(Texture *tex, int priority) {
03507   nassertv_always(!is_empty());
03508   PT(TextureStage) stage = TextureStage::get_default();
03509   set_texture(stage, tex, priority);
03510 }
03511 
03512 ////////////////////////////////////////////////////////////////////
03513 //     Function: NodePath::set_texture
03514 //       Access: Published
03515 //  Description: Adds the indicated texture to the list of textures
03516 //               that will be rendered on the indicated multitexture
03517 //               stage.  If there are multiple texture stages
03518 //               specified (possibly on multiple different nodes at
03519 //               different levels), they will all be applied to
03520 //               geometry together, according to the stage
03521 //               specification set up in the TextureStage object.
03522 ////////////////////////////////////////////////////////////////////
03523 void NodePath::
03524 set_texture(TextureStage *stage, Texture *tex, int priority) {
03525   nassertv_always(!is_empty());
03526 
03527   const RenderAttrib *attrib =
03528     node()->get_attrib(TextureAttrib::get_class_slot());
03529   if (attrib != (const RenderAttrib *)NULL) {
03530     const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
03531     int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
03532 
03533     // Modify the existing TextureAttrib to add the indicated
03534     // texture.
03535     node()->set_attrib(tsa->add_on_stage(stage, tex, priority), sg_priority);
03536 
03537   } else {
03538     // Create a new TextureAttrib for this node.
03539     CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
03540     node()->set_attrib(tsa->add_on_stage(stage, tex, priority));
03541   }
03542 }
03543 
03544 ////////////////////////////////////////////////////////////////////
03545 //     Function: NodePath::set_texture_off
03546 //       Access: Published
03547 //  Description: Sets the geometry at this level and below to render
03548 //               using no texture, on any stage.  This is different
03549 //               from not specifying a texture; rather, this
03550 //               specifically contradicts set_texture() at a higher
03551 //               node level (or, with a priority, overrides a
03552 //               set_texture() at a lower level).
03553 ////////////////////////////////////////////////////////////////////
03554 void NodePath::
03555 set_texture_off(int priority) {
03556   nassertv_always(!is_empty());
03557   node()->set_attrib(TextureAttrib::make_all_off(), priority);
03558 }
03559 
03560 ////////////////////////////////////////////////////////////////////
03561 //     Function: NodePath::set_texture_off
03562 //       Access: Published
03563 //  Description: Sets the geometry at this level and below to render
03564 //               using no texture, on the indicated stage.  This is
03565 //               different from not specifying a texture; rather, this
03566 //               specifically contradicts set_texture() at a higher
03567 //               node level (or, with a priority, overrides a
03568 //               set_texture() at a lower level).
03569 ////////////////////////////////////////////////////////////////////
03570 void NodePath::
03571 set_texture_off(TextureStage *stage, int priority) {
03572   nassertv_always(!is_empty());
03573 
03574   const RenderAttrib *attrib =
03575     node()->get_attrib(TextureAttrib::get_class_slot());
03576   if (attrib != (const RenderAttrib *)NULL) {
03577     const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
03578     int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
03579 
03580     // Modify the existing TextureAttrib to add the indicated texture
03581     // to the "off" list.  This also, incidentally, removes it from
03582     // the "on" list if it is there.
03583     node()->set_attrib(tsa->add_off_stage(stage, priority), sg_priority);
03584 
03585   } else {
03586     // Create a new TextureAttrib for this node that turns off the
03587     // indicated stage.
03588     CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
03589     node()->set_attrib(tsa->add_off_stage(stage, priority));
03590   }
03591 }
03592 
03593 ////////////////////////////////////////////////////////////////////
03594 //     Function: NodePath::clear_texture
03595 //       Access: Published
03596 //  Description: Completely removes any texture adjustment that may
03597 //               have been set via set_texture() or set_texture_off()
03598 //               from this particular node.  This allows whatever
03599 //               textures might be otherwise affecting the geometry to
03600 //               show instead.
03601 ////////////////////////////////////////////////////////////////////
03602 void NodePath::
03603 clear_texture() {
03604   nassertv_always(!is_empty());
03605   node()->clear_attrib(TextureAttrib::get_class_slot());
03606 }
03607 
03608 ////////////////////////////////////////////////////////////////////
03609 //     Function: NodePath::clear_texture
03610 //       Access: Published
03611 //  Description: Removes any reference to the indicated texture stage
03612 //               from the NodePath.
03613 ////////////////////////////////////////////////////////////////////
03614 void NodePath::
03615 clear_texture(TextureStage *stage) {
03616   nassertv_always(!is_empty());
03617 
03618   const RenderAttrib *attrib =
03619     node()->get_attrib(TextureAttrib::get_class_slot());
03620   if (attrib != (const RenderAttrib *)NULL) {
03621     CPT(TextureAttrib) tsa = DCAST(TextureAttrib, attrib);
03622     tsa = DCAST(TextureAttrib, tsa->remove_on_stage(stage));
03623     tsa = DCAST(TextureAttrib, tsa->remove_off_stage(stage));
03624 
03625     if (tsa->is_identity()) {
03626       node()->clear_attrib(TextureAttrib::get_class_slot());
03627 
03628     } else {
03629       int priority = node()->get_state()->get_override(TextureAttrib::get_class_slot());
03630       node()->set_attrib(tsa, priority);
03631     }
03632   }
03633 }
03634 
03635 ////////////////////////////////////////////////////////////////////
03636 //     Function: NodePath::has_texture
03637 //       Access: Published
03638 //  Description: Returns true if a texture has been applied to this
03639 //               particular node via set_texture(), false otherwise.
03640 //               This is not the same thing as asking whether the
03641 //               geometry at this node will be rendered with
03642 //               texturing, as there may be a texture in effect from a
03643 //               higher or lower level.
03644 ////////////////////////////////////////////////////////////////////
03645 bool NodePath::
03646 has_texture() const {
03647   return get_texture() != (Texture *)NULL;
03648 }
03649 
03650 ////////////////////////////////////////////////////////////////////
03651 //     Function: NodePath::has_texture
03652 //       Access: Published
03653 //  Description: Returns true if texturing has been specifically
03654 //               enabled on this particular node for the indicated
03655 //               stage.  This means that someone called
03656 //               set_texture() on this node with the indicated stage
03657 //               name, or the stage_name is the default stage_name,
03658 //               and someone called set_texture() on this node.
03659 ////////////////////////////////////////////////////////////////////
03660 bool NodePath::
03661 has_texture(TextureStage *stage) const {
03662   nassertr_always(!is_empty(), false);
03663 
03664   const RenderAttrib *attrib =
03665     node()->get_attrib(TextureAttrib::get_class_slot());
03666   if (attrib != (const RenderAttrib *)NULL) {
03667     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03668     return ta->has_on_stage(stage);
03669   }
03670 
03671   return false;
03672 }
03673 
03674 ////////////////////////////////////////////////////////////////////
03675 //     Function: NodePath::has_texture_off
03676 //       Access: Published
03677 //  Description: Returns true if texturing has been specifically
03678 //               disabled on this particular node via
03679 //               set_texture_off(), false otherwise.  This is not the
03680 //               same thing as asking whether the geometry at this
03681 //               node will be rendered untextured, as there may be a
03682 //               texture in effect from a higher or lower level.
03683 ////////////////////////////////////////////////////////////////////
03684 bool NodePath::
03685 has_texture_off() const {
03686   nassertr_always(!is_empty(), false);
03687   const RenderAttrib *attrib =
03688     node()->get_attrib(TextureAttrib::get_class_slot());
03689   if (attrib != (const RenderAttrib *)NULL) {
03690     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03691     return ta->has_all_off();
03692   }
03693 
03694   return false;
03695 }
03696 
03697 ////////////////////////////////////////////////////////////////////
03698 //     Function: NodePath::has_texture_off
03699 //       Access: Published
03700 //  Description: Returns true if texturing has been specifically
03701 //               disabled on this particular node for the indicated
03702 //               stage.  This means that someone called
03703 //               set_texture_off() on this node with the indicated
03704 //               stage name, or that someone called set_texture_off()
03705 //               on this node to remove all stages.
03706 ////////////////////////////////////////////////////////////////////
03707 bool NodePath::
03708 has_texture_off(TextureStage *stage) const {
03709   nassertr_always(!is_empty(), false);
03710 
03711   const RenderAttrib *attrib =
03712     node()->get_attrib(TextureAttrib::get_class_slot());
03713   if (attrib != (const RenderAttrib *)NULL) {
03714     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03715     return ta->has_off_stage(stage);
03716   }
03717 
03718   return false;
03719 }
03720 
03721 ////////////////////////////////////////////////////////////////////
03722 //     Function: NodePath::get_texture
03723 //       Access: Published
03724 //  Description: Returns the base-level texture that has been set on
03725 //               this particular node, or NULL if no texture has been
03726 //               set.  This is not necessarily the texture that will
03727 //               be applied to the geometry at or below this level, as
03728 //               another texture at a higher or lower level may
03729 //               override.
03730 //
03731 //               See also find_texture().
03732 ////////////////////////////////////////////////////////////////////
03733 Texture *NodePath::
03734 get_texture() const {
03735   nassertr_always(!is_empty(), NULL);
03736   const RenderAttrib *attrib =
03737     node()->get_attrib(TextureAttrib::get_class_slot());
03738   if (attrib != (const RenderAttrib *)NULL) {
03739     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03740     return ta->get_texture();
03741   }
03742 
03743   return NULL;
03744 }
03745 
03746 ////////////////////////////////////////////////////////////////////
03747 //     Function: NodePath::get_texture
03748 //       Access: Published
03749 //  Description: Returns the texture that has been set on the
03750 //               indicated stage for this particular node, or NULL if
03751 //               no texture has been set for this stage.
03752 ////////////////////////////////////////////////////////////////////
03753 Texture *NodePath::
03754 get_texture(TextureStage *stage) const {
03755   nassertr_always(!is_empty(), NULL);
03756   const RenderAttrib *attrib =
03757     node()->get_attrib(TextureAttrib::get_class_slot());
03758   if (attrib != (const RenderAttrib *)NULL) {
03759     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
03760     return ta->get_on_texture(stage);
03761   }
03762 
03763   return NULL;
03764 }
03765 
03766 ////////////////////////////////////////////////////////////////////
03767 //     Function: NodePath::set_shader
03768 //       Access: Published
03769 //  Description: 
03770 ////////////////////////////////////////////////////////////////////
03771 void NodePath::
03772 set_shader(const Shader *sha, int priority) {
03773   nassertv_always(!is_empty());
03774 
03775   const RenderAttrib *attrib =
03776     node()->get_attrib(ShaderAttrib::get_class_slot());
03777   if (attrib != (const RenderAttrib *)NULL) {
03778     priority = max(priority,
03779                    node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
03780     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03781     node()->set_attrib(sa->set_shader(sha, priority));
03782   } else {
03783     // Create a new ShaderAttrib for this node.
03784     CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03785     node()->set_attrib(sa->set_shader(sha, priority));
03786   }
03787 }
03788 
03789 ////////////////////////////////////////////////////////////////////
03790 //     Function: NodePath::set_shader_off
03791 //       Access: Published
03792 //  Description: 
03793 ////////////////////////////////////////////////////////////////////
03794 void NodePath::
03795 set_shader_off(int priority) {
03796   set_shader(NULL, priority);
03797 }
03798 
03799 ////////////////////////////////////////////////////////////////////
03800 //     Function: NodePath::set_shader_auto
03801 //       Access: Published
03802 //  Description: 
03803 ////////////////////////////////////////////////////////////////////
03804 void NodePath::
03805 set_shader_auto(int priority) {
03806   nassertv_always(!is_empty());
03807 
03808   const RenderAttrib *attrib =
03809     node()->get_attrib(ShaderAttrib::get_class_slot());
03810   if (attrib != (const RenderAttrib *)NULL) {
03811     priority = max(priority,
03812                    node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
03813     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03814     node()->set_attrib(sa->set_shader_auto(priority));
03815   } else {
03816     // Create a new ShaderAttrib for this node.
03817     CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03818     node()->set_attrib(sa->set_shader_auto(priority));
03819   }
03820 }
03821 
03822 ////////////////////////////////////////////////////////////////////
03823 //     Function: NodePath::set_shader_auto
03824 //       Access: Published
03825 //  Description: overloaded for auto shader customization
03826 ////////////////////////////////////////////////////////////////////
03827 void NodePath::
03828 set_shader_auto(BitMask32 shader_switch, int priority) {
03829   nassertv_always(!is_empty());
03830 
03831   const RenderAttrib *attrib =
03832     node()->get_attrib(ShaderAttrib::get_class_slot());
03833   if (attrib != (const RenderAttrib *)NULL) {
03834     priority = max(priority,
03835                    node()->get_state()->get_override(ShaderAttrib::get_class_slot()));
03836     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03837     node()->set_attrib(sa->set_shader_auto(shader_switch, priority));
03838   } else {
03839     // Create a new ShaderAttrib for this node.
03840     CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03841     node()->set_attrib(sa->set_shader_auto(shader_switch, priority));
03842   }
03843 }
03844 ////////////////////////////////////////////////////////////////////
03845 //     Function: NodePath::clear_shader
03846 //       Access: Published
03847 //  Description: 
03848 ////////////////////////////////////////////////////////////////////
03849 void NodePath::
03850 clear_shader() {
03851   nassertv_always(!is_empty());
03852 
03853   const RenderAttrib *attrib =
03854     node()->get_attrib(ShaderAttrib::get_class_slot());
03855   if (attrib != (const RenderAttrib *)NULL) {
03856     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03857     node()->set_attrib(sa->clear_shader());
03858   }
03859 }
03860 
03861 ////////////////////////////////////////////////////////////////////
03862 //     Function: NodePath::get_shader
03863 //       Access: Published
03864 //  Description: 
03865 ////////////////////////////////////////////////////////////////////
03866 const Shader *NodePath::
03867 get_shader() const {
03868   nassertr_always(!is_empty(), NULL);
03869   const RenderAttrib *attrib =
03870     node()->get_attrib(ShaderAttrib::get_class_slot());
03871   if (attrib != (const RenderAttrib *)NULL) {
03872     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03873     return sa->get_shader();
03874   }
03875   return NULL;
03876 }
03877 
03878 ////////////////////////////////////////////////////////////////////
03879 //     Function: NodePath::set_shader_input
03880 //       Access: Published
03881 //  Description: 
03882 ////////////////////////////////////////////////////////////////////
03883 void NodePath::
03884 set_shader_input(const ShaderInput *inp) {
03885   nassertv_always(!is_empty());
03886 
03887   const RenderAttrib *attrib =
03888     node()->get_attrib(ShaderAttrib::get_class_slot());
03889   if (attrib != (const RenderAttrib *)NULL) {
03890     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03891     node()->set_attrib(sa->set_shader_input(inp));
03892   } else {
03893     // Create a new ShaderAttrib for this node.
03894     CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03895     node()->set_attrib(sa->set_shader_input(inp));
03896   }
03897 }
03898 
03899 ////////////////////////////////////////////////////////////////////
03900 //     Function: NodePath::get_shader_input
03901 //       Access: Published
03902 //  Description: 
03903 ////////////////////////////////////////////////////////////////////
03904 const ShaderInput *NodePath::
03905 get_shader_input(const InternalName *id) const {
03906   nassertr_always(!is_empty(), NULL);
03907   
03908   const RenderAttrib *attrib =
03909     node()->get_attrib(ShaderAttrib::get_class_slot());
03910   if (attrib != (const RenderAttrib *)NULL) {
03911     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03912     return sa->get_shader_input(id);
03913   }
03914   return NULL;
03915 }
03916 
03917 ////////////////////////////////////////////////////////////////////
03918 //     Function: NodePath::get_instance_count
03919 //       Access: Published
03920 //  Description: Returns the geometry instance count, or 0 if
03921 //               disabled. See set_instance_count.
03922 ////////////////////////////////////////////////////////////////////
03923 const int NodePath::
03924 get_instance_count() const {
03925   nassertr_always(!is_empty(), 0);
03926 
03927   const RenderAttrib *attrib =
03928     node()->get_attrib(ShaderAttrib::get_class_slot());
03929 
03930   if (attrib != (const RenderAttrib *)NULL) {
03931     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03932     return sa->get_instance_count();
03933   }
03934 
03935   return 0;
03936 }
03937 
03938 ////////////////////////////////////////////////////////////////////
03939 //     Function: NodePath::clear_shader_input
03940 //       Access: Published
03941 //  Description: 
03942 ////////////////////////////////////////////////////////////////////
03943 void NodePath::
03944 clear_shader_input(const InternalName *id) {
03945   nassertv_always(!is_empty());
03946 
03947   const RenderAttrib *attrib =
03948     node()->get_attrib(ShaderAttrib::get_class_slot());
03949   if (attrib != (const RenderAttrib *)NULL) {
03950     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
03951     node()->set_attrib(sa->clear_shader_input(id));
03952   }
03953 }
03954 
03955 
03956 ////////////////////////////////////////////////////////////////////
03957 //     Function: NodePath::set_shader_input
03958 //       Access: Published
03959 //  Description: 
03960 ////////////////////////////////////////////////////////////////////
03961 void NodePath:: 
03962 set_shader_input(const InternalName *id, const PTA_float &v, int priority) {
03963   set_shader_input(new ShaderInput(id,v,priority));
03964 }
03965 
03966 ////////////////////////////////////////////////////////////////////
03967 //     Function: NodePath::set_shader_input
03968 //       Access: Published
03969 //  Description: 
03970 ////////////////////////////////////////////////////////////////////
03971 void NodePath:: 
03972 set_shader_input(const InternalName *id, const PTA_double &v, int priority) {
03973   set_shader_input(new ShaderInput(id,v,priority));
03974 }
03975 
03976 ////////////////////////////////////////////////////////////////////
03977 //     Function: NodePath::set_shader_input
03978 //       Access: Published
03979 //  Description: 
03980 ////////////////////////////////////////////////////////////////////
03981 void NodePath:: 
03982 set_shader_input(const InternalName *id, const PTA_LVecBase4 &v, int priority) {
03983   set_shader_input(new ShaderInput(id,v,priority));
03984 }
03985 
03986 ////////////////////////////////////////////////////////////////////
03987 //     Function: NodePath::set_shader_input
03988 //       Access: Published
03989 //  Description: 
03990 ////////////////////////////////////////////////////////////////////
03991 void NodePath:: 
03992 set_shader_input(const InternalName *id, const PTA_LVecBase3 &v, int priority) {
03993   set_shader_input(new ShaderInput(id,v,priority));
03994 }
03995 
03996 
03997 ////////////////////////////////////////////////////////////////////
03998 //     Function: NodePath::set_shader_input
03999 //       Access: Published
04000 //  Description: 
04001 ////////////////////////////////////////////////////////////////////
04002 void NodePath:: 
04003 set_shader_input(const InternalName *id, const PTA_LVecBase2 &v, int priority) {
04004   set_shader_input(new ShaderInput(id,v,priority));
04005 }
04006 
04007 ////////////////////////////////////////////////////////////////////
04008 //     Function: NodePath::set_shader_input
04009 //       Access: Published
04010 //  Description: 
04011 ////////////////////////////////////////////////////////////////////
04012 void NodePath:: 
04013 set_shader_input(const InternalName *id, const LVecBase4 &v, int priority) {
04014   set_shader_input(new ShaderInput(id,v,priority));
04015 }
04016 
04017 ////////////////////////////////////////////////////////////////////
04018 //     Function: NodePath::set_shader_input
04019 //       Access: Published
04020 //  Description: 
04021 ////////////////////////////////////////////////////////////////////
04022 void NodePath:: 
04023 set_shader_input(const InternalName *id, const LVecBase3 &v, int priority) {
04024   set_shader_input(new ShaderInput(id,v,priority));
04025 }
04026 
04027 ////////////////////////////////////////////////////////////////////
04028 //     Function: NodePath::set_shader_input
04029 //       Access: Published
04030 //  Description: 
04031 ////////////////////////////////////////////////////////////////////
04032 void NodePath:: 
04033 set_shader_input(const InternalName *id, const LVecBase2 &v, int priority) {
04034   set_shader_input(new ShaderInput(id,v,priority));
04035 }
04036 
04037 ////////////////////////////////////////////////////////////////////
04038 //     Function: NodePath::set_shader_input
04039 //       Access: Published
04040 //  Description: 
04041 ////////////////////////////////////////////////////////////////////
04042 void NodePath:: 
04043 set_shader_input(const InternalName *id, const PTA_LMatrix4 &v, int priority) {
04044   set_shader_input(new ShaderInput(id,v,priority));
04045 }
04046 
04047 ////////////////////////////////////////////////////////////////////
04048 //     Function: NodePath::set_shader_input
04049 //       Access: Published
04050 //  Description: 
04051 ////////////////////////////////////////////////////////////////////
04052 void NodePath:: 
04053 set_shader_input(const InternalName *id, const PTA_LMatrix3 &v, int priority) {
04054   set_shader_input(new ShaderInput(id,v,priority));
04055 }
04056 
04057 ////////////////////////////////////////////////////////////////////
04058 //     Function: NodePath::set_shader_input
04059 //       Access: Published
04060 //  Description: 
04061 ////////////////////////////////////////////////////////////////////
04062 void NodePath:: 
04063 set_shader_input(const InternalName *id, const LMatrix4 &v, int priority) {
04064   set_shader_input(new ShaderInput(id,v,priority));
04065 }
04066 
04067 ////////////////////////////////////////////////////////////////////
04068 //     Function: NodePath::set_shader_input
04069 //       Access: Published
04070 //  Description: 
04071 ////////////////////////////////////////////////////////////////////
04072 void NodePath:: 
04073 set_shader_input(const InternalName *id, const LMatrix3 &v, int priority) {
04074   set_shader_input(new ShaderInput(id,v,priority));
04075 }
04076 
04077 ////////////////////////////////////////////////////////////////////
04078 //     Function: NodePath::set_shader_input
04079 //       Access: Published
04080 //  Description: 
04081 ////////////////////////////////////////////////////////////////////
04082 void NodePath::
04083 set_shader_input(const InternalName *id, Texture *tex, int priority) {
04084   set_shader_input(new ShaderInput(id,tex,priority));
04085 }
04086 
04087 ////////////////////////////////////////////////////////////////////
04088 //     Function: NodePath::set_shader_input
04089 //       Access: Published
04090 //  Description: 
04091 ////////////////////////////////////////////////////////////////////
04092 void NodePath::
04093 set_shader_input(const InternalName *id, const NodePath &np, int priority) {
04094   set_shader_input(new ShaderInput(id,np,priority));
04095 }
04096 
04097 ////////////////////////////////////////////////////////////////////
04098 //     Function: NodePath::set_shader_input
04099 //       Access: Published
04100 //  Description: 
04101 ////////////////////////////////////////////////////////////////////
04102 void NodePath:: 
04103 set_shader_input(const InternalName *id, double n1, double n2, double n3, double n4, int priority) {
04104   set_shader_input(new ShaderInput(id, LVecBase4(n1, n2, n3, n4), priority));
04105 }
04106 
04107 ////////////////////////////////////////////////////////////////////
04108 //     Function: NodePath::set_shader_input
04109 //       Access: Published
04110 //  Description: 
04111 ////////////////////////////////////////////////////////////////////
04112 void NodePath:: 
04113 set_shader_input(const string &id, const PTA_float &v, int priority) {
04114   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04115 }
04116 
04117 ////////////////////////////////////////////////////////////////////
04118 //     Function: NodePath::set_shader_input
04119 //       Access: Published
04120 //  Description: 
04121 ////////////////////////////////////////////////////////////////////
04122 void NodePath:: 
04123 set_shader_input(const string &id, const PTA_double &v, int priority) {
04124   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04125 }
04126 
04127 ////////////////////////////////////////////////////////////////////
04128 //     Function: NodePath::set_shader_input
04129 //       Access: Published
04130 //  Description: 
04131 ////////////////////////////////////////////////////////////////////
04132 void NodePath:: 
04133 set_shader_input(const string &id, const PTA_LVecBase4 &v, int priority) {
04134   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04135 }
04136 
04137 ////////////////////////////////////////////////////////////////////
04138 //     Function: NodePath::set_shader_input
04139 //       Access: Published
04140 //  Description: 
04141 ////////////////////////////////////////////////////////////////////
04142 void NodePath:: 
04143 set_shader_input(const string &id, const PTA_LVecBase3 &v, int priority) {
04144   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04145 }
04146 
04147 
04148 ////////////////////////////////////////////////////////////////////
04149 //     Function: NodePath::set_shader_input
04150 //       Access: Published
04151 //  Description: 
04152 ////////////////////////////////////////////////////////////////////
04153 void NodePath:: 
04154 set_shader_input(const string &id, const PTA_LVecBase2 &v, int priority) {
04155   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04156 }
04157 
04158 ////////////////////////////////////////////////////////////////////
04159 //     Function: NodePath::set_shader_input
04160 //       Access: Published
04161 //  Description: 
04162 ////////////////////////////////////////////////////////////////////
04163 void NodePath:: 
04164 set_shader_input(const string &id, const LVecBase4 &v, int priority) {
04165   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04166 }
04167 
04168 ////////////////////////////////////////////////////////////////////
04169 //     Function: NodePath::set_shader_input
04170 //       Access: Published
04171 //  Description: 
04172 ////////////////////////////////////////////////////////////////////
04173 void NodePath:: 
04174 set_shader_input(const string &id, const LVecBase3 &v, int priority) {
04175   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04176 }
04177 
04178 ////////////////////////////////////////////////////////////////////
04179 //     Function: NodePath::set_shader_input
04180 //       Access: Published
04181 //  Description: 
04182 ////////////////////////////////////////////////////////////////////
04183 void NodePath:: 
04184 set_shader_input(const string &id, const LVecBase2 &v, int priority) {
04185   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04186 }
04187 
04188 ////////////////////////////////////////////////////////////////////
04189 //     Function: NodePath::set_shader_input
04190 //       Access: Published
04191 //  Description: 
04192 ////////////////////////////////////////////////////////////////////
04193 void NodePath:: 
04194 set_shader_input(const string &id, const PTA_LMatrix4 &v, int priority) {
04195   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04196 }
04197 
04198 ////////////////////////////////////////////////////////////////////
04199 //     Function: NodePath::set_shader_input
04200 //       Access: Published
04201 //  Description: 
04202 ////////////////////////////////////////////////////////////////////
04203 void NodePath:: 
04204 set_shader_input(const string &id, const PTA_LMatrix3 &v, int priority) {
04205   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04206 }
04207 
04208 ////////////////////////////////////////////////////////////////////
04209 //     Function: NodePath::set_shader_input
04210 //       Access: Published
04211 //  Description: 
04212 ////////////////////////////////////////////////////////////////////
04213 void NodePath:: 
04214 set_shader_input(const string &id, const LMatrix4 &v, int priority) {
04215   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04216 }
04217 
04218 ////////////////////////////////////////////////////////////////////
04219 //     Function: NodePath::set_shader_input
04220 //       Access: Published
04221 //  Description: 
04222 ////////////////////////////////////////////////////////////////////
04223 void NodePath:: 
04224 set_shader_input(const string &id, const LMatrix3 &v, int priority) {
04225   set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
04226 }
04227 ////////////////////////////////////////////////////////////////////
04228 //     Function: NodePath::set_shader_input
04229 //       Access: Published
04230 //  Description: 
04231 ////////////////////////////////////////////////////////////////////
04232 void NodePath::
04233 set_shader_input(const string &id, Texture *tex, int priority) {
04234   set_shader_input(new ShaderInput(InternalName::make(id),tex,priority));
04235 }
04236 
04237 ////////////////////////////////////////////////////////////////////
04238 //     Function: NodePath::set_shader_input
04239 //       Access: Published
04240 //  Description: 
04241 ////////////////////////////////////////////////////////////////////
04242 void NodePath::
04243 set_shader_input(const string &id, const NodePath &np, int priority) {
04244   set_shader_input(new ShaderInput(InternalName::make(id),np,priority));
04245 }
04246 
04247 ////////////////////////////////////////////////////////////////////
04248 //     Function: NodePath::set_shader_input
04249 //       Access: Published
04250 //  Description: 
04251 ////////////////////////////////////////////////////////////////////
04252 void NodePath:: 
04253 set_shader_input(const string &id, double n1, double n2, double n3, double n4, int priority) {
04254   set_shader_input(new ShaderInput(InternalName::make(id), LVecBase4(n1, n2, n3, n4), priority));
04255 }
04256 
04257 ////////////////////////////////////////////////////////////////////
04258 //     Function: NodePath::get_shader_input
04259 //       Access: Published
04260 //  Description: 
04261 ////////////////////////////////////////////////////////////////////
04262 const ShaderInput *NodePath::
04263 get_shader_input(const string &id) const {
04264   return get_shader_input(InternalName::make(id));
04265 }
04266 
04267 ////////////////////////////////////////////////////////////////////
04268 //     Function: NodePath::clear_shader_input
04269 //       Access: Published
04270 //  Description: 
04271 ////////////////////////////////////////////////////////////////////
04272 void NodePath::
04273 clear_shader_input(const string &id) {
04274   clear_shader_input(InternalName::make(id));
04275 }
04276 
04277 ////////////////////////////////////////////////////////////////////
04278 //     Function: NodePath::set_instance_count
04279 //       Access: Published
04280 //  Description: Sets the geometry instance count, or 0 if
04281 //               geometry instancing should be disabled. Do not
04282 //               confuse with instanceTo which only applies to
04283 //               animation instancing.
04284 ////////////////////////////////////////////////////////////////////
04285 void NodePath::
04286 set_instance_count(int instance_count) {
04287   nassertv_always(!is_empty());
04288 
04289   const RenderAttrib *attrib =
04290     node()->get_attrib(ShaderAttrib::get_class_slot());
04291   if (attrib != (const RenderAttrib *)NULL) {
04292     const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
04293     node()->set_attrib(sa->set_instance_count(instance_count));
04294   } else {
04295     // Create a new ShaderAttrib for this node.
04296     CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
04297     node()->set_attrib(sa->set_instance_count(instance_count));
04298   }
04299 }
04300 
04301 ////////////////////////////////////////////////////////////////////
04302 //     Function: NodePath::set_tex_transform
04303 //       Access: Published
04304 //  Description: Sets the texture matrix on the current node to the
04305 //               indicated transform for the given stage.
04306 ////////////////////////////////////////////////////////////////////
04307 void NodePath::
04308 set_tex_transform(TextureStage *stage, const TransformState *transform) {
04309   nassertv_always(!is_empty());
04310 
04311   const RenderAttrib *attrib =
04312     node()->get_attrib(TexMatrixAttrib::get_class_slot());
04313   if (attrib != (const RenderAttrib *)NULL) {
04314     const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
04315 
04316     // Modify the existing TexMatrixAttrib to add the indicated
04317     // stage.
04318     node()->set_attrib(tma->add_stage(stage, transform));
04319 
04320   } else {
04321     // Create a new TexMatrixAttrib for this node.
04322     node()->set_attrib(TexMatrixAttrib::make(stage, transform));
04323   }
04324 }
04325 
04326 ////////////////////////////////////////////////////////////////////
04327 //     Function: NodePath::clear_tex_transform
04328 //       Access: Published
04329 //  Description: Removes all texture matrices from the current node.
04330 ////////////////////////////////////////////////////////////////////
04331 void NodePath::
04332 clear_tex_transform() {
04333   nassertv_always(!is_empty());
04334   node()->clear_attrib(TexMatrixAttrib::get_class_slot());
04335 }
04336 
04337 ////////////////////////////////////////////////////////////////////
04338 //     Function: NodePath::clear_tex_transform
04339 //       Access: Published
04340 //  Description: Removes the texture matrix on the current node for
04341 //               the given stage.
04342 ////////////////////////////////////////////////////////////////////
04343 void NodePath::
04344 clear_tex_transform(TextureStage *stage) {
04345   nassertv_always(!is_empty());
04346 
04347   const RenderAttrib *attrib =
04348     node()->get_attrib(TexMatrixAttrib::get_class_slot());
04349   if (attrib != (const RenderAttrib *)NULL) {
04350     CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, attrib);
04351     tma = DCAST(TexMatrixAttrib, tma->remove_stage(stage));
04352 
04353     if (tma->is_empty()) {
04354       node()->clear_attrib(TexMatrixAttrib::get_class_slot());
04355 
04356     } else {
04357       node()->set_attrib(tma);
04358     }
04359   }
04360 }
04361 
04362 ////////////////////////////////////////////////////////////////////
04363 //     Function: NodePath::has_tex_transform
04364 //       Access: Published
04365 //  Description: Returns true if there is an explicit texture matrix
04366 //               on the current node for the given stage.
04367 ////////////////////////////////////////////////////////////////////
04368 bool NodePath::
04369 has_tex_transform(TextureStage *stage) const {
04370   nassertr_always(!is_empty(), false);
04371 
04372   const RenderAttrib *attrib =
04373     node()->get_attrib(TexMatrixAttrib::get_class_slot());
04374   if (attrib != (const RenderAttrib *)NULL) {
04375     const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
04376     return tma->has_stage(stage);
04377   }
04378 
04379   return false;
04380 }
04381 
04382 ////////////////////////////////////////////////////////////////////
04383 //     Function: NodePath::get_tex_transform
04384 //       Access: Published
04385 //  Description: Returns the texture matrix on the current node for the
04386 //               given stage, or identity transform if there is no
04387 //               explicit transform set for the given stage.
04388 ////////////////////////////////////////////////////////////////////
04389 CPT(TransformState) NodePath::
04390 get_tex_transform(TextureStage *stage) const {
04391   nassertr_always(!is_empty(), NULL);
04392 
04393   const RenderAttrib *attrib =
04394     node()->get_attrib(TexMatrixAttrib::get_class_slot());
04395   if (attrib != (const RenderAttrib *)NULL) {
04396     const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
04397     return tma->get_transform(stage);
04398   }
04399 
04400   return TransformState::make_identity();
04401 }
04402 
04403 ////////////////////////////////////////////////////////////////////
04404 //     Function: NodePath::set_tex_transform
04405 //       Access: Published
04406 //  Description: Sets the texture matrix on the current node to the
04407 //               indicated transform for the given stage.
04408 ////////////////////////////////////////////////////////////////////
04409 void NodePath::
04410 set_tex_transform(const NodePath &other, TextureStage *stage, const TransformState *transform) {
04411   nassertv(_error_type == ET_ok && other._error_type == ET_ok);
04412   nassertv_always(!is_empty());
04413 
04414   CPT(RenderState) state = get_state(other);
04415   const RenderAttrib *attrib =
04416     state->get_attrib(TexMatrixAttrib::get_class_slot());
04417   if (attrib != (const RenderAttrib *)NULL) {
04418     const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
04419 
04420     // Modify the existing TexMatrixAttrib to add the indicated
04421     // stage.
04422     state = state->add_attrib(tma->add_stage(stage, transform));
04423 
04424   } else {
04425     // Create a new TexMatrixAttrib for this node.
04426     state = state->add_attrib(TexMatrixAttrib::make(stage, transform));
04427   }
04428 
04429   // Now compose that with our parent's state.
04430   CPT(RenderState) rel_state;
04431   if (has_parent()) {
04432     rel_state = other.get_state(get_parent());
04433   } else {
04434     rel_state = other.get_state(NodePath());
04435   }
04436   CPT(RenderState) new_state = rel_state->compose(state);
04437 
04438   // And apply only the TexMatrixAttrib to the current node, leaving
04439   // the others unchanged.
04440   node()->set_attrib(new_state->get_attrib(TexMatrixAttrib::get_class_slot()));
04441 }
04442 
04443 ////////////////////////////////////////////////////////////////////
04444 //     Function: NodePath::get_tex_transform
04445 //       Access: Published
04446 //  Description: Returns the texture matrix on the current node for the
04447 //               given stage, relative to the other node.
04448 ////////////////////////////////////////////////////////////////////
04449 CPT(TransformState) NodePath::
04450 get_tex_transform(const NodePath &other, TextureStage *stage) const {
04451   nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
04452 
04453   CPT(RenderState) state = get_state(other);
04454   const RenderAttrib *attrib =
04455     state->get_attrib(TexMatrixAttrib::get_class_slot());
04456   if (attrib != (const RenderAttrib *)NULL) {
04457     const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
04458     return tma->get_transform(stage);
04459   }
04460 
04461   return TransformState::make_identity();
04462 }
04463 
04464 ////////////////////////////////////////////////////////////////////
04465 //     Function: NodePath::set_tex_gen
04466 //       Access: Published
04467 //  Description: Enables automatic texture coordinate generation for
04468 //               the indicated texture stage.
04469 ////////////////////////////////////////////////////////////////////
04470 void NodePath::
04471 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) {
04472   nassertv_always(!is_empty());
04473 
04474   const RenderAttrib *attrib =
04475     node()->get_attrib(TexGenAttrib::get_class_slot());
04476 
04477   CPT(TexGenAttrib) tga;
04478 
04479   if (attrib != (const RenderAttrib *)NULL) {
04480     priority = max(priority,
04481                    node()->get_state()->get_override(TextureAttrib::get_class_slot()));
04482     tga = DCAST(TexGenAttrib, attrib);
04483 
04484   } else {
04485     tga = DCAST(TexGenAttrib, TexGenAttrib::make());
04486   }
04487 
04488   node()->set_attrib(tga->add_stage(stage, mode), priority);
04489 }
04490 
04491 ////////////////////////////////////////////////////////////////////
04492 //     Function: NodePath::set_tex_gen
04493 //       Access: Published
04494 //  Description: Enables automatic texture coordinate generation for
04495 //               the indicated texture stage.  This version of this
04496 //               method is useful when setting M_light_vector, which
04497 //               requires the name of the texture coordinate set that
04498 //               supplies the tangent and binormal, as well as the
04499 //               specific light to generate coordinates for.
04500 ////////////////////////////////////////////////////////////////////
04501 void NodePath::
04502 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 
04503             const string &source_name, const NodePath &light, int priority) {
04504   nassertv_always(!is_empty());
04505 
04506   const RenderAttrib *attrib =
04507     node()->get_attrib(TexGenAttrib::get_class_slot());
04508 
04509   CPT(TexGenAttrib) tga;
04510 
04511   if (attrib != (const RenderAttrib *)NULL) {
04512     priority = max(priority,
04513                    node()->get_state()->get_override(TextureAttrib::get_class_slot()));
04514     tga = DCAST(TexGenAttrib, attrib);
04515 
04516   } else {
04517     tga = DCAST(TexGenAttrib, TexGenAttrib::make());
04518   }
04519 
04520   node()->set_attrib(tga->add_stage(stage, mode, source_name, light), priority);
04521 }
04522 
04523 ////////////////////////////////////////////////////////////////////
04524 //     Function: NodePath::set_tex_gen
04525 //       Access: Published
04526 //  Description: Enables automatic texture coordinate generation for
04527 //               the indicated texture stage.  This version of this
04528 //               method is useful when setting M_constant, which
04529 //               requires a constant texture coordinate value.
04530 ////////////////////////////////////////////////////////////////////
04531 void NodePath::
04532 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 
04533             const LTexCoord3 &constant_value, int priority) {
04534   nassertv_always(!is_empty());
04535 
04536   const RenderAttrib *attrib =
04537     node()->get_attrib(TexGenAttrib::get_class_slot());
04538 
04539   CPT(TexGenAttrib) tga;
04540 
04541   if (attrib != (const RenderAttrib *)NULL) {
04542     priority = max(priority,
04543                    node()->get_state()->get_override(TextureAttrib::get_class_slot()));
04544     tga = DCAST(TexGenAttrib, attrib);
04545 
04546   } else {
04547     tga = DCAST(TexGenAttrib, TexGenAttrib::make());
04548   }
04549 
04550   node()->set_attrib(tga->add_stage(stage, mode, constant_value), priority);
04551 }
04552 
04553 ////////////////////////////////////////////////////////////////////
04554 //     Function: NodePath::clear_tex_gen
04555 //       Access: Published
04556 //  Description: Removes the texture coordinate generation mode from
04557 //               all texture stages on this node.
04558 ////////////////////////////////////////////////////////////////////
04559 void NodePath::
04560 clear_tex_gen() {
04561   nassertv_always(!is_empty());
04562   node()->clear_attrib(TexGenAttrib::get_class_slot());
04563 }
04564 
04565 ////////////////////////////////////////////////////////////////////
04566 //     Function: NodePath::clear_tex_gen
04567 //       Access: Published
04568 //  Description: Disables automatic texture coordinate generation for
04569 //               the indicated texture stage.
04570 ////////////////////////////////////////////////////////////////////
04571 void NodePath::
04572 clear_tex_gen(TextureStage *stage) {
04573   nassertv_always(!is_empty());
04574 
04575   const RenderAttrib *attrib =
04576     node()->get_attrib(TexGenAttrib::get_class_slot());
04577   if (attrib != (const RenderAttrib *)NULL) {
04578     CPT(TexGenAttrib) tga = DCAST(TexGenAttrib, attrib);
04579     tga = DCAST(TexGenAttrib, tga->remove_stage(stage));
04580 
04581     if (tga->is_empty()) {
04582       node()->clear_attrib(TexGenAttrib::get_class_slot());
04583 
04584     } else {
04585       node()->set_attrib(tga);
04586     }
04587   }
04588 }
04589 
04590 ////////////////////////////////////////////////////////////////////
04591 //     Function: NodePath::has_tex_gen
04592 //       Access: Published
04593 //  Description: Returns true if there is a mode for automatic texture
04594 //               coordinate generation on the current node for the
04595 //               given stage.
04596 ////////////////////////////////////////////////////////////////////
04597 bool NodePath::
04598 has_tex_gen(TextureStage *stage) const {
04599   nassertr_always(!is_empty(), false);
04600 
04601   const RenderAttrib *attrib =
04602     node()->get_attrib(TexGenAttrib::get_class_slot());
04603   if (attrib != (const RenderAttrib *)NULL) {
04604     const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
04605     return tga->has_stage(stage);
04606   }
04607 
04608   return false;
04609 }
04610 
04611 ////////////////////////////////////////////////////////////////////
04612 //     Function: NodePath::get_tex_gen
04613 //       Access: Published
04614 //  Description: Returns the texture coordinate generation mode for
04615 //               the given stage, or M_off if there is no explicit
04616 //               mode set for the given stage.
04617 ////////////////////////////////////////////////////////////////////
04618 RenderAttrib::TexGenMode NodePath::
04619 get_tex_gen(TextureStage *stage) const {
04620   nassertr_always(!is_empty(), TexGenAttrib::M_off);
04621 
04622   const RenderAttrib *attrib =
04623     node()->get_attrib(TexGenAttrib::get_class_slot());
04624   if (attrib != (const RenderAttrib *)NULL) {
04625     const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
04626     return tga->get_mode(stage);
04627   }
04628 
04629   return TexGenAttrib::M_off;
04630 }
04631 
04632 ////////////////////////////////////////////////////////////////////
04633 //     Function: NodePath::get_tex_gen_light
04634 //       Access: Published
04635 //  Description: Returns the particular Light set for the indicated
04636 //               texgen mode's texture stage, or empty NodePath if no
04637 //               light is set.  This is only meaningful if the texgen
04638 //               mode (returned by get_tex_gen()) is M_light_vector.
04639 ////////////////////////////////////////////////////////////////////
04640 NodePath NodePath::
04641 get_tex_gen_light(TextureStage *stage) const {
04642   nassertr_always(!is_empty(), NodePath::fail());
04643 
04644   const RenderAttrib *attrib =
04645     node()->get_attrib(TexGenAttrib::get_class_slot());
04646   if (attrib != (const RenderAttrib *)NULL) {
04647     const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
04648     return tga->get_light(stage);
04649   }
04650 
04651   return NodePath();
04652 }
04653 
04654 ////////////////////////////////////////////////////////////////////
04655 //     Function: NodePath::set_tex_projector
04656 //       Access: Published
04657 //  Description: Establishes a TexProjectorEffect on this node, which
04658 //               can be used to establish projective texturing (but
04659 //               see also the NodePath::project_texture() convenience
04660 //               function), or it can be used to bind this node's
04661 //               texture transform to particular node's position in
04662 //               space, allowing a LerpInterval (for instance) to
04663 //               adjust this node's texture coordinates.
04664 //
04665 //               If to is a LensNode, then the fourth parameter,
04666 //               lens_index, can be provided to select a particular
04667 //               lens to apply.  Otherwise lens_index is not used.
04668 ////////////////////////////////////////////////////////////////////
04669 void NodePath::
04670 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to,
04671                   int lens_index) {
04672   nassertv_always(!is_empty());
04673 
04674   const RenderEffect *effect =
04675     node()->get_effect(TexProjectorEffect::get_class_type());
04676 
04677   CPT(TexProjectorEffect) tpe;
04678 
04679   if (effect != (const RenderEffect *)NULL) {
04680     tpe = DCAST(TexProjectorEffect, effect);
04681 
04682   } else {
04683     tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make());
04684   }
04685 
04686   node()->set_effect(tpe->add_stage(stage, from, to, lens_index));
04687 }
04688 
04689 ////////////////////////////////////////////////////////////////////
04690 //     Function: NodePath::clear_tex_projector
04691 //       Access: Published
04692 //  Description: Removes the TexProjectorEffect for the indicated
04693 //               stage from this node.
04694 ////////////////////////////////////////////////////////////////////
04695 void NodePath::
04696 clear_tex_projector(TextureStage *stage) {
04697   nassertv_always(!is_empty());
04698 
04699   const RenderEffect *effect =
04700     node()->get_effect(TexProjectorEffect::get_class_type());
04701   if (effect != (const RenderEffect *)NULL) {
04702     CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect);
04703     tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage));
04704 
04705     if (tpe->is_empty()) {
04706       node()->clear_effect(TexProjectorEffect::get_class_type());
04707 
04708     } else {
04709       node()->set_effect(tpe);
04710     }
04711   }
04712 }
04713 
04714 ////////////////////////////////////////////////////////////////////
04715 //     Function: NodePath::clear_tex_projector
04716 //       Access: Published
04717 //  Description: Removes the TexProjectorEffect for all stages from
04718 //               this node.
04719 ////////////////////////////////////////////////////////////////////
04720 void NodePath::
04721 clear_tex_projector() {
04722   nassertv_always(!is_empty());
04723   node()->clear_effect(TexProjectorEffect::get_class_type());
04724 }
04725 
04726 ////////////////////////////////////////////////////////////////////
04727 //     Function: NodePath::has_tex_projector
04728 //       Access: Published
04729 //  Description: Returns true if this node has a TexProjectorEffect
04730 //               for the indicated stage, false otherwise.
04731 ////////////////////////////////////////////////////////////////////
04732 bool NodePath::
04733 has_tex_projector(TextureStage *stage) const {
04734   nassertr_always(!is_empty(), false);
04735 
04736   const RenderEffect *effect =
04737     node()->get_effect(TexProjectorEffect::get_class_type());
04738   if (effect != (const RenderEffect *)NULL) {
04739     const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04740     return tpe->has_stage(stage);
04741   }
04742 
04743   return false;
04744 }
04745 
04746 ////////////////////////////////////////////////////////////////////
04747 //     Function: NodePath::get_tex_projector_from
04748 //       Access: Published
04749 //  Description: Returns the "from" node associated with the
04750 //               TexProjectorEffect on the indicated stage.  The
04751 //               relative transform between the "from" and the "to"
04752 //               nodes is automatically applied to the texture
04753 //               transform each frame.
04754 ////////////////////////////////////////////////////////////////////
04755 NodePath NodePath::
04756 get_tex_projector_from(TextureStage *stage) const {
04757   nassertr_always(!is_empty(), NodePath::fail());
04758 
04759   const RenderEffect *effect =
04760     node()->get_effect(TexProjectorEffect::get_class_type());
04761   if (effect != (const RenderEffect *)NULL) {
04762     const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04763     return tpe->get_from(stage);
04764   }
04765 
04766   return NodePath::not_found();
04767 }
04768 
04769 ////////////////////////////////////////////////////////////////////
04770 //     Function: NodePath::get_tex_projector_to
04771 //       Access: Published
04772 //  Description: Returns the "to" node associated with the
04773 //               TexProjectorEffect on the indicated stage.  The
04774 //               relative transform between the "from" and the "to"
04775 //               nodes is automatically applied to the texture
04776 //               transform each frame.
04777 ////////////////////////////////////////////////////////////////////
04778 NodePath NodePath::
04779 get_tex_projector_to(TextureStage *stage) const {
04780   nassertr_always(!is_empty(), NodePath::fail());
04781 
04782   const RenderEffect *effect =
04783     node()->get_effect(TexProjectorEffect::get_class_type());
04784   if (effect != (const RenderEffect *)NULL) {
04785     const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04786     return tpe->get_to(stage);
04787   }
04788 
04789   return NodePath::not_found();
04790 }
04791 
04792 ////////////////////////////////////////////////////////////////////
04793 //     Function: NodePath::project_texture
04794 //       Access: Published
04795 //  Description: A convenience function to enable projective texturing
04796 //               at this node level and below, using the indicated
04797 //               NodePath (which should contain a LensNode) as the
04798 //               projector.
04799 ////////////////////////////////////////////////////////////////////
04800 void NodePath::
04801 project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) {
04802   nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type()));
04803   set_texture(stage, tex);
04804   set_tex_gen(stage, TexGenAttrib::M_world_position);
04805   set_tex_projector(stage, NodePath(), projector);
04806 }
04807 
04808 
04809 ////////////////////////////////////////////////////////////////////
04810 //     Function: NodePath::set_normal_map
04811 //       Access: Published
04812 //  Description: A convenience function to set up a normal map on this
04813 //               geometry.  This uses the single highest-priority
04814 //               light on the object only.  It also requires
04815 //               multitexture, and consumes at least two texture
04816 //               stages, in addition to what may already be in use.
04817 //
04818 //               The normal_map parameter is the texture that contains
04819 //               the normal map information (with a 3-d delta vector
04820 //               encoded into the r,g,b of each texel).  texcoord_name is
04821 //               the name of the texture coordinate set that contains
04822 //               the tangent and binormal we wish to use.  If
04823 //               preserve_color is true, then one additional texture
04824 //               stage is consumed to blend in the geometry's original
04825 //               vertex color.
04826 //
04827 //               Only one normal map may be in effect through this
04828 //               interface at any given time.
04829 ////////////////////////////////////////////////////////////////////
04830 void NodePath::
04831 set_normal_map(Texture *normal_map, const string &texcoord_name,
04832                bool preserve_color) {
04833   clear_normal_map();
04834 
04835   // First, we apply the normal map itself, to the bottom layer.
04836   PT(TextureStage) normal_map_ts = new TextureStage("__normal_map");
04837   normal_map_ts->set_texcoord_name(texcoord_name);
04838   normal_map_ts->set_sort(-20);
04839   normal_map_ts->set_mode(TextureStage::M_replace);
04840   set_texture(normal_map_ts, normal_map);
04841 
04842   // Then, we apply a normalization map, to normalize, per-pixel, the
04843   // vector to the light.
04844   PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32);
04845   PT(TextureStage) normalization_map_ts = new TextureStage("__normalization_map");
04846   normalization_map_ts->set_combine_rgb
04847     (TextureStage::CM_dot3_rgb, 
04848      TextureStage::CS_texture, TextureStage::CO_src_color,
04849      TextureStage::CS_previous, TextureStage::CO_src_color);
04850   normalization_map_ts->set_texcoord_name("light_vector");
04851   normalization_map_ts->set_sort(-15);
04852   set_texture(normalization_map_ts, normalization_map);
04853 
04854   // Finally, we enable M_light_vector texture coordinate generation.
04855   set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector, 
04856               texcoord_name, NodePath());
04857 
04858   if (preserve_color) {
04859     // One more stage to get back the original color.
04860     PT(TextureStage) orig_color_ts = new TextureStage("__orig_color");
04861     orig_color_ts->set_combine_rgb
04862       (TextureStage::CM_modulate,
04863        TextureStage::CS_primary_color, TextureStage::CO_src_color,
04864        TextureStage::CS_previous, TextureStage::CO_src_color);
04865     set_texture(orig_color_ts, normal_map);
04866   }
04867 }
04868 
04869 ////////////////////////////////////////////////////////////////////
04870 //     Function: NodePath::clear_normal_map
04871 //       Access: Published
04872 //  Description: Undoes the effect of a previous call to
04873 //               set_normal_map().
04874 ////////////////////////////////////////////////////////////////////
04875 void NodePath::
04876 clear_normal_map() {
04877   // Scan through the TextureStages, and if we find any whose name
04878   // matches one of the stages that would have been left by
04879   // set_normal_map(), remove it from the state.
04880 
04881   CPT(RenderAttrib) attrib =
04882     get_state()->get_attrib(TextureAttrib::get_class_slot());
04883   if (attrib != (const RenderAttrib *)NULL) {
04884     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
04885     for (int i = 0; i < ta->get_num_on_stages(); i++) {
04886       TextureStage *stage = ta->get_on_stage(i);
04887       if (stage->get_name() == "__normal_map") {
04888         clear_texture(stage);
04889 
04890       } else if (stage->get_name() == "__normalization_map") {
04891         clear_texture(stage);
04892         clear_tex_gen(stage);
04893 
04894       } else if (stage->get_name() == "__orig_color") {
04895         clear_texture(stage);
04896       }
04897     }
04898   }
04899 }
04900 
04901 ////////////////////////////////////////////////////////////////////
04902 //     Function: NodePath::has_vertex_column
04903 //       Access: Published
04904 //  Description: Returns true if there are at least some vertices at
04905 //               this node and below that contain a reference to the
04906 //               indicated vertex data column name, false otherwise.
04907 //
04908 //               This is particularly useful for testing whether a
04909 //               particular model has a given texture coordinate set
04910 //               (but see has_texcoord()).
04911 ////////////////////////////////////////////////////////////////////
04912 bool NodePath::
04913 has_vertex_column(const InternalName *name) const {
04914   nassertr_always(!is_empty(), false);
04915   return r_has_vertex_column(node(), name);
04916 }
04917 
04918 ////////////////////////////////////////////////////////////////////
04919 //     Function: NodePath::find_all_vertex_columns
04920 //       Access: Published
04921 //  Description: Returns a list of all vertex array columns stored on
04922 //               some geometry found at this node level and below.
04923 ////////////////////////////////////////////////////////////////////
04924 InternalNameCollection NodePath::
04925 find_all_vertex_columns() const {
04926   nassertr_always(!is_empty(), InternalNameCollection());
04927   InternalNames vertex_columns;
04928   r_find_all_vertex_columns(node(), vertex_columns);
04929 
04930   InternalNameCollection tc;
04931   InternalNames::iterator ti;
04932   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04933     tc.add_name(*ti);
04934   }
04935   return tc;
04936 }
04937 
04938 ////////////////////////////////////////////////////////////////////
04939 //     Function: NodePath::find_all_vertex_columns
04940 //       Access: Published
04941 //  Description: Returns a list of all vertex array columns stored on
04942 //               some geometry found at this node level and below that
04943 //               match the indicated name (which may contain wildcard
04944 //               characters).
04945 ////////////////////////////////////////////////////////////////////
04946 InternalNameCollection NodePath::
04947 find_all_vertex_columns(const string &name) const {
04948   nassertr_always(!is_empty(), InternalNameCollection());
04949   InternalNames vertex_columns;
04950   r_find_all_vertex_columns(node(), vertex_columns);
04951 
04952   GlobPattern glob(name);
04953 
04954   InternalNameCollection tc;
04955   InternalNames::iterator ti;
04956   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04957     InternalName *name = (*ti);
04958     if (glob.matches(name->get_name())) {
04959       tc.add_name(name);
04960     }
04961   }
04962   return tc;
04963 }
04964 
04965 ////////////////////////////////////////////////////////////////////
04966 //     Function: NodePath::find_all_texcoords
04967 //       Access: Published
04968 //  Description: Returns a list of all texture coordinate sets used by
04969 //               any geometry at this node level and below.
04970 ////////////////////////////////////////////////////////////////////
04971 InternalNameCollection NodePath::
04972 find_all_texcoords() const {
04973   nassertr_always(!is_empty(), InternalNameCollection());
04974   InternalNames vertex_columns;
04975   r_find_all_vertex_columns(node(), vertex_columns);
04976 
04977   CPT(InternalName) texcoord_name = InternalName::get_texcoord();
04978   
04979   InternalNameCollection tc;
04980   InternalNames::iterator ti;
04981   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04982     if ((*ti)->get_top() == texcoord_name) {
04983       tc.add_name(*ti);
04984     }
04985   }
04986   return tc;
04987 }
04988 
04989 ////////////////////////////////////////////////////////////////////
04990 //     Function: NodePath::find_all_texcoords
04991 //       Access: Published
04992 //  Description: Returns a list of all texture coordinate sets used by
04993 //               any geometry at this node level and below that match
04994 //               the indicated name (which may contain wildcard
04995 //               characters).
04996 ////////////////////////////////////////////////////////////////////
04997 InternalNameCollection NodePath::
04998 find_all_texcoords(const string &name) const {
04999   nassertr_always(!is_empty(), InternalNameCollection());
05000   InternalNames vertex_columns;
05001   r_find_all_vertex_columns(node(), vertex_columns);
05002 
05003   GlobPattern glob(name);
05004   CPT(InternalName) texcoord_name = InternalName::get_texcoord();
05005 
05006   InternalNameCollection tc;
05007   InternalNames::iterator ti;
05008   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
05009     InternalName *name = (*ti);
05010     if (name->get_top() == texcoord_name) {
05011       // This is a texture coordinate name.  Figure out the basename
05012       // of the texture coordinates.
05013       int index = name->find_ancestor("texcoord");
05014       nassertr(index != -1, InternalNameCollection());
05015       string net_basename = name->get_net_basename(index - 1);
05016 
05017       if (glob.matches(net_basename)) {
05018         tc.add_name(name);
05019       }
05020     }
05021   }
05022   return tc;
05023 }
05024 
05025 ////////////////////////////////////////////////////////////////////
05026 //     Function: NodePath::find_texture
05027 //       Access: Published
05028 //  Description: Returns the first texture found applied to geometry
05029 //               at this node or below that matches the indicated name
05030 //               (which may contain wildcards).  Returns the texture
05031 //               if it is found, or NULL if it is not.
05032 ////////////////////////////////////////////////////////////////////
05033 Texture *NodePath::
05034 find_texture(const string &name) const {
05035   nassertr_always(!is_empty(), NULL);
05036   GlobPattern glob(name);
05037   return r_find_texture(node(), get_net_state(), glob);
05038 }
05039 
05040 ////////////////////////////////////////////////////////////////////
05041 //     Function: NodePath::find_texture
05042 //       Access: Published
05043 //  Description: Returns the first texture found applied to geometry
05044 //               at this node or below that is assigned to the
05045 //               indicated texture stage.  Returns the texture if it
05046 //               is found, or NULL if it is not.
05047 ////////////////////////////////////////////////////////////////////
05048 Texture *NodePath::
05049 find_texture(TextureStage *stage) const {
05050   nassertr_always(!is_empty(), NULL);
05051   return r_find_texture(node(), stage);
05052 }
05053 
05054 ////////////////////////////////////////////////////////////////////
05055 //     Function: NodePath::find_all_textures
05056 //       Access: Published
05057 //  Description: Returns a list of a textures applied to geometry at
05058 //               this node and below.
05059 ////////////////////////////////////////////////////////////////////
05060 TextureCollection NodePath::
05061 find_all_textures() const {
05062   nassertr_always(!is_empty(), TextureCollection());
05063   Textures textures;
05064   r_find_all_textures(node(), get_net_state(), textures);
05065 
05066   TextureCollection tc;
05067   Textures::iterator ti;
05068   for (ti = textures.begin(); ti != textures.end(); ++ti) {
05069     tc.add_texture(*ti);
05070   }
05071   return tc;
05072 }
05073 
05074 ////////////////////////////////////////////////////////////////////
05075 //     Function: NodePath::find_all_textures
05076 //       Access: Published
05077 //  Description: Returns a list of a textures applied to geometry at
05078 //               this node and below that match the indicated name
05079 //               (which may contain wildcard characters).
05080 ////////////////////////////////////////////////////////////////////
05081 TextureCollection NodePath::
05082 find_all_textures(const string &name) const {
05083   nassertr_always(!is_empty(), TextureCollection());
05084   Textures textures;
05085   r_find_all_textures(node(), get_net_state(), textures);
05086 
05087   GlobPattern glob(name);
05088 
05089   TextureCollection tc;
05090   Textures::iterator ti;
05091   for (ti = textures.begin(); ti != textures.end(); ++ti) {
05092     Texture *texture = (*ti);
05093     if (glob.matches(texture->get_name())) {
05094       tc.add_texture(texture);
05095     }
05096   }
05097   return tc;
05098 }
05099 
05100 ////////////////////////////////////////////////////////////////////
05101 //     Function: NodePath::find_all_textures
05102 //       Access: Published
05103 //  Description: Returns a list of a textures on geometry at
05104 //               this node and below that are assigned to the
05105 //               indicated texture stage.
05106 ////////////////////////////////////////////////////////////////////
05107 TextureCollection NodePath::
05108 find_all_textures(TextureStage *stage) const {
05109   nassertr_always(!is_empty(), TextureCollection());
05110   Textures textures;
05111   r_find_all_textures(node(), stage, textures);
05112 
05113   TextureCollection tc;
05114   Textures::iterator ti;
05115   for (ti = textures.begin(); ti != textures.end(); ++ti) {
05116     Texture *texture = (*ti);
05117     tc.add_texture(texture);
05118   }
05119   return tc;
05120 }
05121 
05122 ////////////////////////////////////////////////////////////////////
05123 //     Function: NodePath::find_texture_stage
05124 //       Access: Published
05125 //  Description: Returns the first TextureStage found applied to
05126 //               geometry at this node or below that matches the
05127 //               indicated name (which may contain wildcards).
05128 //               Returns the TextureStage if it is found, or NULL if
05129 //               it is not.
05130 ////////////////////////////////////////////////////////////////////
05131 TextureStage *NodePath::
05132 find_texture_stage(const string &name) const {
05133   nassertr_always(!is_empty(), NULL);
05134   GlobPattern glob(name);
05135   return r_find_texture_stage(node(), get_net_state(), glob);
05136 }
05137 
05138 ////////////////////////////////////////////////////////////////////
05139 //     Function: NodePath::find_all_texture_stages
05140 //       Access: Published
05141 //  Description: Returns a list of a TextureStages applied to geometry
05142 //               at this node and below.
05143 ////////////////////////////////////////////////////////////////////
05144 TextureStageCollection NodePath::
05145 find_all_texture_stages() const {
05146   nassertr_always(!is_empty(), TextureStageCollection());
05147   TextureStages texture_stages;
05148   r_find_all_texture_stages(node(), get_net_state(), texture_stages);
05149 
05150   TextureStageCollection tc;
05151   TextureStages::iterator ti;
05152   for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
05153     tc.add_texture_stage(*ti);
05154   }
05155   return tc;
05156 }
05157 
05158 ////////////////////////////////////////////////////////////////////
05159 //     Function: NodePath::unify_texture_stages
05160 //       Access: Published
05161 //  Description: Searches through all TextureStages at this node and
05162 //               below.  Any TextureStages that share the same name as
05163 //               the indicated TextureStage object are replaced with
05164 //               this object, thus ensuring that all geometry at this
05165 //               node and below with a particular TextureStage name is
05166 //               using the same TextureStage object.
05167 ////////////////////////////////////////////////////////////////////
05168 void NodePath::
05169 unify_texture_stages(TextureStage *stage) {
05170   nassertv_always(!is_empty());
05171   r_unify_texture_stages(node(), stage);
05172 }
05173 
05174 ////////////////////////////////////////////////////////////////////
05175 //     Function: NodePath::find_all_texture_stages
05176 //       Access: Published
05177 //  Description: Returns a list of a TextureStages applied to geometry
05178 //               at this node and below that match the indicated name
05179 //               (which may contain wildcard characters).
05180 ////////////////////////////////////////////////////////////////////
05181 TextureStageCollection NodePath::
05182 find_all_texture_stages(const string &name) const {
05183   nassertr_always(!is_empty(), TextureStageCollection());
05184   TextureStages texture_stages;
05185   r_find_all_texture_stages(node(), get_net_state(), texture_stages);
05186 
05187   GlobPattern glob(name);
05188 
05189   TextureStageCollection tc;
05190   TextureStages::iterator ti;
05191   for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
05192     TextureStage *texture_stage = (*ti);
05193     if (glob.matches(texture_stage->get_name())) {
05194       tc.add_texture_stage(texture_stage);
05195     }
05196   }
05197   return tc;
05198 }
05199 
05200 ////////////////////////////////////////////////////////////////////
05201 //     Function: NodePath::find_material
05202 //       Access: Published
05203 //  Description: Returns the first material found applied to geometry
05204 //               at this node or below that matches the indicated name
05205 //               (which may contain wildcards).  Returns the material
05206 //               if it is found, or NULL if it is not.
05207 ////////////////////////////////////////////////////////////////////
05208 Material *NodePath::
05209 find_material(const string &name) const {
05210   nassertr_always(!is_empty(), NULL);
05211   GlobPattern glob(name);
05212   return r_find_material(node(), get_net_state(), glob);
05213 }
05214 
05215 ////////////////////////////////////////////////////////////////////
05216 //     Function: NodePath::find_all_materials
05217 //       Access: Published
05218 //  Description: Returns a list of a materials applied to geometry at
05219 //               this node and below.
05220 ////////////////////////////////////////////////////////////////////
05221 MaterialCollection NodePath::
05222 find_all_materials() const {
05223   nassertr_always(!is_empty(), MaterialCollection());
05224   Materials materials;
05225   r_find_all_materials(node(), get_net_state(), materials);
05226 
05227   MaterialCollection tc;
05228   Materials::iterator ti;
05229   for (ti = materials.begin(); ti != materials.end(); ++ti) {
05230     tc.add_material(*ti);
05231   }
05232   return tc;
05233 }
05234 
05235 ////////////////////////////////////////////////////////////////////
05236 //     Function: NodePath::find_all_materials
05237 //       Access: Published
05238 //  Description: Returns a list of a materials applied to geometry at
05239 //               this node and below that match the indicated name
05240 //               (which may contain wildcard characters).
05241 ////////////////////////////////////////////////////////////////////
05242 MaterialCollection NodePath::
05243 find_all_materials(const string &name) const {
05244   nassertr_always(!is_empty(), MaterialCollection());
05245   Materials materials;
05246   r_find_all_materials(node(), get_net_state(), materials);
05247 
05248   GlobPattern glob(name);
05249 
05250   MaterialCollection tc;
05251   Materials::iterator ti;
05252   for (ti = materials.begin(); ti != materials.end(); ++ti) {
05253     Material *material = (*ti);
05254     if (glob.matches(material->get_name())) {
05255       tc.add_material(material);
05256     }
05257   }
05258   return tc;
05259 }
05260 
05261 ////////////////////////////////////////////////////////////////////
05262 //     Function: NodePath::set_material
05263 //       Access: Published
05264 //  Description: Sets the geometry at this level and below to render
05265 //               using the indicated material.
05266 //
05267 //               Previously, this operation made a copy of the
05268 //               material structure, but nowadays it assigns the
05269 //               pointer directly.
05270 ////////////////////////////////////////////////////////////////////
05271 void NodePath::
05272 set_material(Material *mat, int priority) {
05273   nassertv_always(!is_empty());
05274   nassertv(mat != NULL);
05275   node()->set_attrib(MaterialAttrib::make(mat), priority);
05276 }
05277 
05278 ////////////////////////////////////////////////////////////////////
05279 //     Function: NodePath::set_material_off
05280 //       Access: Published
05281 //  Description: Sets the geometry at this level and below to render
05282 //               using no material.  This is normally the default, but
05283 //               it may be useful to use this to contradict
05284 //               set_material() at a higher node level (or, with a
05285 //               priority, to override a set_material() at a lower
05286 //               level).
05287 ////////////////////////////////////////////////////////////////////
05288 void NodePath::
05289 set_material_off(int priority) {
05290   nassertv_always(!is_empty());
05291   node()->set_attrib(MaterialAttrib::make_off(), priority);
05292 }
05293 
05294 ////////////////////////////////////////////////////////////////////
05295 //     Function: NodePath::clear_material
05296 //       Access: Published
05297 //  Description: Completely removes any material adjustment that may
05298 //               have been set via set_material() from this particular
05299 //               node.
05300 ////////////////////////////////////////////////////////////////////
05301 void NodePath::
05302 clear_material() {
05303   nassertv_always(!is_empty());
05304   node()->clear_attrib(MaterialAttrib::get_class_slot());
05305 }
05306 
05307 ////////////////////////////////////////////////////////////////////
05308 //     Function: NodePath::has_material
05309 //       Access: Published
05310 //  Description: Returns true if a material has been applied to this
05311 //               particular node via set_material(), false otherwise.
05312 ////////////////////////////////////////////////////////////////////
05313 bool NodePath::
05314 has_material() const {
05315   nassertr_always(!is_empty(), false);
05316   const RenderAttrib *attrib =
05317     node()->get_attrib(MaterialAttrib::get_class_slot());
05318   if (attrib != (const RenderAttrib *)NULL) {
05319     const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
05320     return !ma->is_off();
05321   }
05322 
05323   return false;
05324 }
05325 
05326 ////////////////////////////////////////////////////////////////////
05327 //     Function: NodePath::get_material
05328 //       Access: Published
05329 //  Description: Returns the material that has been set on this
05330 //               particular node, or NULL if no material has been set.
05331 //               This is not necessarily the material that will be
05332 //               applied to the geometry at or below this level, as
05333 //               another material at a higher or lower level may
05334 //               override.
05335 
05336 //               See also find_material().
05337 ////////////////////////////////////////////////////////////////////
05338 PT(Material) NodePath::
05339 get_material() const {
05340   nassertr_always(!is_empty(), NULL);
05341   const RenderAttrib *attrib =
05342     node()->get_attrib(MaterialAttrib::get_class_slot());
05343   if (attrib != (const RenderAttrib *)NULL) {
05344     const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
05345     return ma->get_material();
05346   }
05347 
05348   return NULL;
05349 }
05350 
05351 ////////////////////////////////////////////////////////////////////
05352 //     Function: NodePath::set_fog
05353 //       Access: Published
05354 //  Description: Sets the geometry at this level and below to render
05355 //               using the indicated fog.
05356 ////////////////////////////////////////////////////////////////////
05357 void NodePath::
05358 set_fog(Fog *fog, int priority) {
05359   nassertv_always(!is_empty());
05360   node()->set_attrib(FogAttrib::make(fog), priority);
05361 }
05362 
05363 ////////////////////////////////////////////////////////////////////
05364 //     Function: NodePath::set_fog_off
05365 //       Access: Published
05366 //  Description: Sets the geometry at this level and below to render
05367 //               using no fog.  This is normally the default, but
05368 //               it may be useful to use this to contradict
05369 //               set_fog() at a higher node level (or, with a
05370 //               priority, to override a set_fog() at a lower
05371 //               level).
05372 ////////////////////////////////////////////////////////////////////
05373 void NodePath::
05374 set_fog_off(int priority) {
05375   nassertv_always(!is_empty());
05376   node()->set_attrib(FogAttrib::make_off(), priority);
05377 }
05378 
05379 ////////////////////////////////////////////////////////////////////
05380 //     Function: NodePath::clear_fog
05381 //       Access: Published
05382 //  Description: Completely removes any fog adjustment that may
05383 //               have been set via set_fog() or set_fog_off()
05384 //               from this particular node.  This allows whatever
05385 //               fogs might be otherwise affecting the geometry to
05386 //               show instead.
05387 ////////////////////////////////////////////////////////////////////
05388 void NodePath::
05389 clear_fog() {
05390   nassertv_always(!is_empty());
05391   node()->clear_attrib(FogAttrib::get_class_slot());
05392 }
05393 
05394 ////////////////////////////////////////////////////////////////////
05395 //     Function: NodePath::has_fog
05396 //       Access: Published
05397 //  Description: Returns true if a fog has been applied to this
05398 //               particular node via set_fog(), false otherwise.
05399 //               This is not the same thing as asking whether the
05400 //               geometry at this node will be rendered with
05401 //               fog, as there may be a fog in effect from a higher or
05402 //               lower level.
05403 ////////////////////////////////////////////////////////////////////
05404 bool NodePath::
05405 has_fog() const {
05406   nassertr_always(!is_empty(), false);
05407   const RenderAttrib *attrib =
05408     node()->get_attrib(FogAttrib::get_class_slot());
05409   if (attrib != (const RenderAttrib *)NULL) {
05410     const FogAttrib *fa = DCAST(FogAttrib, attrib);
05411     return !fa->is_off();
05412   }
05413 
05414   return false;
05415 }
05416 
05417 ////////////////////////////////////////////////////////////////////
05418 //     Function: NodePath::has_fog_off
05419 //       Access: Published
05420 //  Description: Returns true if a fog has been specifically
05421 //               disabled on this particular node via
05422 //               set_fog_off(), false otherwise.  This is not the
05423 //               same thing as asking whether the geometry at this
05424 //               node will be rendered unfogged, as there may be a
05425 //               fog in effect from a higher or lower level.
05426 ////////////////////////////////////////////////////////////////////
05427 bool NodePath::
05428 has_fog_off() const {
05429   nassertr_always(!is_empty(), false);
05430   const RenderAttrib *attrib =
05431     node()->get_attrib(FogAttrib::get_class_slot());
05432   if (attrib != (const RenderAttrib *)NULL) {
05433     const FogAttrib *fa = DCAST(FogAttrib, attrib);
05434     return fa->is_off();
05435   }
05436 
05437   return false;
05438 }
05439 
05440 ////////////////////////////////////////////////////////////////////
05441 //     Function: NodePath::get_fog
05442 //       Access: Published
05443 //  Description: Returns the fog that has been set on this
05444 //               particular node, or NULL if no fog has been set.
05445 //               This is not necessarily the fog that will be
05446 //               applied to the geometry at or below this level, as
05447 //               another fog at a higher or lower level may
05448 //               override.
05449 ////////////////////////////////////////////////////////////////////
05450 Fog *NodePath::
05451 get_fog() const {
05452   nassertr_always(!is_empty(), NULL);
05453   const RenderAttrib *attrib =
05454     node()->get_attrib(FogAttrib::get_class_slot());
05455   if (attrib != (const RenderAttrib *)NULL) {
05456     const FogAttrib *fa = DCAST(FogAttrib, attrib);
05457     return fa->get_fog();
05458   }
05459 
05460   return NULL;
05461 }
05462 
05463 ////////////////////////////////////////////////////////////////////
05464 //     Function: NodePath::set_render_mode_wireframe
05465 //       Access: Published
05466 //  Description: Sets up the geometry at this level and below (unless
05467 //               overridden) to render in wireframe mode.
05468 ////////////////////////////////////////////////////////////////////
05469 void NodePath::
05470 set_render_mode_wireframe(int priority) {
05471   nassertv_always(!is_empty());
05472   PN_stdfloat thickness = get_render_mode_thickness();
05473   bool perspective = get_render_mode_perspective();
05474   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, thickness, perspective), priority);
05475 }
05476 
05477 ////////////////////////////////////////////////////////////////////
05478 //     Function: NodePath::set_render_mode_filled
05479 //       Access: Published
05480 //  Description: Sets up the geometry at this level and below (unless
05481 //               overridden) to render in filled (i.e. not wireframe)
05482 //               mode.
05483 ////////////////////////////////////////////////////////////////////
05484 void NodePath::
05485 set_render_mode_filled(int priority) {
05486   nassertv_always(!is_empty());
05487   PN_stdfloat thickness = get_render_mode_thickness();
05488   bool perspective = get_render_mode_perspective();
05489   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority);
05490 }
05491 
05492 ////////////////////////////////////////////////////////////////////
05493 //     Function: NodePath::set_render_mode_perspective
05494 //       Access: Published
05495 //  Description: Sets up the point geometry at this level and below to
05496 //               render as perspective sprites (that is, billboarded
05497 //               quads).  The thickness, as specified with
05498 //               set_render_mode_thickness(), is the width of each
05499 //               point in 3-D units, unless it is overridden on a
05500 //               per-vertex basis.  This does not affect geometry
05501 //               other than points.
05502 //
05503 //               If you want the quads to be individually textured,
05504 //               you should also set a TexGenAttrib::M_point_sprite on
05505 //               the node.
05506 ////////////////////////////////////////////////////////////////////
05507 void NodePath::
05508 set_render_mode_perspective(bool perspective, int priority) {
05509   nassertv_always(!is_empty());
05510   RenderModeAttrib::Mode mode = get_render_mode();
05511   PN_stdfloat thickness = get_render_mode_thickness();
05512   node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
05513 }
05514 
05515 ////////////////////////////////////////////////////////////////////
05516 //     Function: NodePath::set_render_mode_thickness
05517 //       Access: Published
05518 //  Description: Sets up the point geometry at this level and below to
05519 //               render as thick points (that is, billboarded
05520 //               quads).  The thickness is in pixels, unless
05521 //               set_render_mode_perspective is also true, in which
05522 //               case it is in 3-D units.
05523 //
05524 //               If you want the quads to be individually textured,
05525 //               you should also set a TexGenAttrib::M_point_sprite on
05526 //               the node.
05527 ////////////////////////////////////////////////////////////////////
05528 void NodePath::
05529 set_render_mode_thickness(PN_stdfloat thickness, int priority) {
05530   nassertv_always(!is_empty());
05531   RenderModeAttrib::Mode mode = get_render_mode();
05532   bool perspective = get_render_mode_perspective();
05533   node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
05534 }
05535 
05536 ////////////////////////////////////////////////////////////////////
05537 //     Function: NodePath::set_render_mode
05538 //       Access: Published
05539 //  Description: Sets up the geometry at this level and below (unless
05540 //               overridden) to render in the specified mode and with
05541 //               the indicated line and/or point thickness.
05542 ////////////////////////////////////////////////////////////////////
05543 void NodePath::
05544 set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority) {
05545   nassertv_always(!is_empty());
05546 
05547   node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority);
05548 }
05549 
05550 ////////////////////////////////////////////////////////////////////
05551 //     Function: NodePath::clear_render_mode
05552 //       Access: Published
05553 //  Description: Completely removes any render mode adjustment that
05554 //               may have been set on this node via
05555 //               set_render_mode_wireframe() or
05556 //               set_render_mode_filled().
05557 ////////////////////////////////////////////////////////////////////
05558 void NodePath::
05559 clear_render_mode() {
05560   nassertv_always(!is_empty());
05561   node()->clear_attrib(RenderModeAttrib::get_class_slot());
05562 }
05563 
05564 ////////////////////////////////////////////////////////////////////
05565 //     Function: NodePath::has_render_mode
05566 //       Access: Published
05567 //  Description: Returns true if a render mode has been explicitly set
05568 //               on this particular node via set_render_mode() (or
05569 //               set_render_mode_wireframe() or
05570 //               set_render_mode_filled()), false otherwise.
05571 ////////////////////////////////////////////////////////////////////
05572 bool NodePath::
05573 has_render_mode() const {
05574   nassertr_always(!is_empty(), false);
05575   return node()->has_attrib(RenderModeAttrib::get_class_slot());
05576 }
05577 
05578 ////////////////////////////////////////////////////////////////////
05579 //     Function: NodePath::get_render_mode
05580 //       Access: Published
05581 //  Description: Returns the render mode that has been specifically
05582 //               set on this node via set_render_mode(), or
05583 //               M_unchanged if nothing has been set.
05584 ////////////////////////////////////////////////////////////////////
05585 RenderModeAttrib::Mode NodePath::
05586 get_render_mode() const {
05587   nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged);
05588   const RenderAttrib *attrib =
05589     node()->get_attrib(RenderModeAttrib::get_class_slot());
05590   if (attrib != (const RenderAttrib *)NULL) {
05591     const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05592     return ta->get_mode();
05593   }
05594 
05595   return RenderModeAttrib::M_unchanged;
05596 }
05597 
05598 ////////////////////////////////////////////////////////////////////
05599 //     Function: NodePath::get_render_mode_thickness
05600 //       Access: Published
05601 //  Description: Returns the render mode thickness that has been
05602 //               specifically set on this node via set_render_mode(),
05603 //               or 1.0 if nothing has been set.
05604 ////////////////////////////////////////////////////////////////////
05605 PN_stdfloat NodePath::
05606 get_render_mode_thickness() const {
05607   nassertr_always(!is_empty(), 0.0f);
05608   const RenderAttrib *attrib =
05609     node()->get_attrib(RenderModeAttrib::get_class_slot());
05610   if (attrib != (const RenderAttrib *)NULL) {
05611     const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05612     return ta->get_thickness();
05613   }
05614 
05615   return 1.0f;
05616 }
05617 
05618 ////////////////////////////////////////////////////////////////////
05619 //     Function: NodePath::get_render_mode_perspective
05620 //       Access: Published
05621 //  Description: Returns the flag that has been set on this node via
05622 //               set_render_mode_perspective(), or false if no flag
05623 //               has been set.
05624 ////////////////////////////////////////////////////////////////////
05625 bool NodePath::
05626 get_render_mode_perspective() const {
05627   nassertr_always(!is_empty(), 0.0f);
05628   const RenderAttrib *attrib =
05629     node()->get_attrib(RenderModeAttrib::get_class_slot());
05630   if (attrib != (const RenderAttrib *)NULL) {
05631     const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05632     return ta->get_perspective();
05633   }
05634 
05635   return false;
05636 }
05637 
05638 ////////////////////////////////////////////////////////////////////
05639 //     Function: NodePath::set_two_sided
05640 //       Access: Published
05641 //  Description: Specifically sets or disables two-sided rendering
05642 //               mode on this particular node.  If no other nodes
05643 //               override, this will cause backfacing polygons to be
05644 //               drawn (in two-sided mode, true) or culled (in
05645 //               one-sided mode, false).
05646 ////////////////////////////////////////////////////////////////////
05647 void NodePath::
05648 set_two_sided(bool two_sided, int priority) {
05649   nassertv_always(!is_empty());
05650 
05651   CullFaceAttrib::Mode mode =
05652     two_sided ?
05653     CullFaceAttrib::M_cull_none :
05654     CullFaceAttrib::M_cull_clockwise;
05655 
05656   node()->set_attrib(CullFaceAttrib::make(mode), priority);
05657 }
05658 
05659 ////////////////////////////////////////////////////////////////////
05660 //     Function: NodePath::clear_two_sided
05661 //       Access: Published
05662 //  Description: Completely removes any two-sided adjustment that
05663 //               may have been set on this node via set_two_sided().
05664 //               The geometry at this level and below will
05665 //               subsequently be rendered either two-sided or
05666 //               one-sided, according to whatever other nodes may have
05667 //               had set_two_sided() on it, or according to the
05668 //               initial state otherwise.
05669 ////////////////////////////////////////////////////////////////////
05670 void NodePath::
05671 clear_two_sided() {
05672   nassertv_always(!is_empty());
05673   node()->clear_attrib(CullFaceAttrib::get_class_slot());
05674 }
05675 
05676 ////////////////////////////////////////////////////////////////////
05677 //     Function: NodePath::has_two_sided
05678 //       Access: Published
05679 //  Description: Returns true if a two-sided adjustment has been
05680 //               explicitly set on this particular node via
05681 //               set_two_sided().  If this returns true, then
05682 //               get_two_sided() may be called to determine which has
05683 //               been set.
05684 ////////////////////////////////////////////////////////////////////
05685 bool NodePath::
05686 has_two_sided() const {
05687   nassertr_always(!is_empty(), false);
05688   return node()->has_attrib(CullFaceAttrib::get_class_slot());
05689 }
05690 
05691 ////////////////////////////////////////////////////////////////////
05692 //     Function: NodePath::get_two_sided
05693 //       Access: Published
05694 //  Description: Returns true if two-sided rendering has been
05695 //               specifically set on this node via set_two_sided(), or
05696 //               false if one-sided rendering has been specifically
05697 //               set, or if nothing has been specifically set.  See
05698 //               also has_two_sided().  This does not necessarily
05699 //               imply that the geometry will or will not be rendered
05700 //               two-sided, as there may be other nodes that override.
05701 ////////////////////////////////////////////////////////////////////
05702 bool NodePath::
05703 get_two_sided() const {
05704   nassertr_always(!is_empty(), false);
05705   const RenderAttrib *attrib =
05706     node()->get_attrib(CullFaceAttrib::get_class_slot());
05707   if (attrib != (const RenderAttrib *)NULL) {
05708     const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
05709     return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
05710   }
05711 
05712   return false;
05713 }
05714 
05715 ////////////////////////////////////////////////////////////////////
05716 //     Function: NodePath::set_depth_test
05717 //       Access: Published
05718 //  Description: Specifically sets or disables the testing of the
05719 //               depth buffer on this particular node.  This is
05720 //               normally on in the 3-d scene graph and off in the 2-d
05721 //               scene graph; it should be on for rendering most 3-d
05722 //               objects properly.
05723 ////////////////////////////////////////////////////////////////////
05724 void NodePath::
05725 set_depth_test(bool depth_test, int priority) {
05726   nassertv_always(!is_empty());
05727 
05728   DepthTestAttrib::PandaCompareFunc mode =
05729     depth_test ?
05730     DepthTestAttrib::M_less :
05731     DepthTestAttrib::M_none;
05732 
05733   node()->set_attrib(DepthTestAttrib::make(mode), priority);
05734 }
05735 
05736 ////////////////////////////////////////////////////////////////////
05737 //     Function: NodePath::clear_depth_test
05738 //       Access: Published
05739 //  Description: Completely removes any depth-test adjustment that
05740 //               may have been set on this node via set_depth_test().
05741 ////////////////////////////////////////////////////////////////////
05742 void NodePath::
05743 clear_depth_test() {
05744   nassertv_always(!is_empty());
05745   node()->clear_attrib(DepthTestAttrib::get_class_slot());
05746 }
05747 
05748 ////////////////////////////////////////////////////////////////////
05749 //     Function: NodePath::has_depth_test
05750 //       Access: Published
05751 //  Description: Returns true if a depth-test adjustment has been
05752 //               explicitly set on this particular node via
05753 //               set_depth_test().  If this returns true, then
05754 //               get_depth_test() may be called to determine which has
05755 //               been set.
05756 ////////////////////////////////////////////////////////////////////
05757 bool NodePath::
05758 has_depth_test() const {
05759   nassertr_always(!is_empty(), false);
05760   return node()->has_attrib(DepthTestAttrib::get_class_slot());
05761 }
05762 
05763 ////////////////////////////////////////////////////////////////////
05764 //     Function: NodePath::get_depth_test
05765 //       Access: Published
05766 //  Description: Returns true if depth-test rendering has been
05767 //               specifically set on this node via set_depth_test(), or
05768 //               false if depth-test rendering has been specifically
05769 //               disabled.  If nothing has been specifically set,
05770 //               returns true.  See also has_depth_test().
05771 ////////////////////////////////////////////////////////////////////
05772 bool NodePath::
05773 get_depth_test() const {
05774   nassertr_always(!is_empty(), false);
05775   const RenderAttrib *attrib =
05776     node()->get_attrib(DepthTestAttrib::get_class_slot());
05777   if (attrib != (const RenderAttrib *)NULL) {
05778     const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
05779     return (dta->get_mode() != DepthTestAttrib::M_none);
05780   }
05781 
05782   return true;
05783 }
05784 
05785 ////////////////////////////////////////////////////////////////////
05786 //     Function: NodePath::set_depth_write
05787 //       Access: Published
05788 //  Description: Specifically sets or disables the writing to the
05789 //               depth buffer on this particular node.  This is
05790 //               normally on in the 3-d scene graph and off in the 2-d
05791 //               scene graph; it should be on for rendering most 3-d
05792 //               objects properly.
05793 ////////////////////////////////////////////////////////////////////
05794 void NodePath::
05795 set_depth_write(bool depth_write, int priority) {
05796   nassertv_always(!is_empty());
05797 
05798   DepthWriteAttrib::Mode mode =
05799     depth_write ?
05800     DepthWriteAttrib::M_on :
05801     DepthWriteAttrib::M_off;
05802 
05803   node()->set_attrib(DepthWriteAttrib::make(mode), priority);
05804 }
05805 
05806 ////////////////////////////////////////////////////////////////////
05807 //     Function: NodePath::clear_depth_write
05808 //       Access: Published
05809 //  Description: Completely removes any depth-write adjustment that
05810 //               may have been set on this node via set_depth_write().
05811 ////////////////////////////////////////////////////////////////////
05812 void NodePath::
05813 clear_depth_write() {
05814   nassertv_always(!is_empty());
05815   node()->clear_attrib(DepthWriteAttrib::get_class_slot());
05816 }
05817 
05818 ////////////////////////////////////////////////////////////////////
05819 //     Function: NodePath::has_depth_write
05820 //       Access: Published
05821 //  Description: Returns true if a depth-write adjustment has been
05822 //               explicitly set on this particular node via
05823 //               set_depth_write().  If this returns true, then
05824 //               get_depth_write() may be called to determine which has
05825 //               been set.
05826 ////////////////////////////////////////////////////////////////////
05827 bool NodePath::
05828 has_depth_write() const {
05829   nassertr_always(!is_empty(), false);
05830   return node()->has_attrib(DepthWriteAttrib::get_class_slot());
05831 }
05832 
05833 ////////////////////////////////////////////////////////////////////
05834 //     Function: NodePath::get_depth_write
05835 //       Access: Published
05836 //  Description: Returns true if depth-write rendering has been
05837 //               specifically set on this node via set_depth_write(), or
05838 //               false if depth-write rendering has been specifically
05839 //               disabled.  If nothing has been specifically set,
05840 //               returns true.  See also has_depth_write().
05841 ////////////////////////////////////////////////////////////////////
05842 bool NodePath::
05843 get_depth_write() const {
05844   nassertr_always(!is_empty(), false);
05845   const RenderAttrib *attrib =
05846     node()->get_attrib(DepthWriteAttrib::get_class_slot());
05847   if (attrib != (const RenderAttrib *)NULL) {
05848     const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
05849     return (dta->get_mode() != DepthWriteAttrib::M_off);
05850   }
05851 
05852   return true;
05853 }
05854 
05855 ////////////////////////////////////////////////////////////////////
05856 //     Function: NodePath::set_depth_offset
05857 //       Access: Published
05858 //  Description: This instructs the graphics driver to apply an
05859 //               offset or bias to the generated depth values for
05860 //               rendered polygons, before they are written to the
05861 //               depth buffer. This can be used to shift polygons
05862 //               forward slightly, to resolve depth conflicts, or
05863 //               self-shadowing artifacts on thin objects.
05864 //               The bias is always an integer number, and each
05865 //               integer increment represents the smallest possible
05866 //               increment in Z that is sufficient to completely
05867 //               resolve two coplanar polygons. Positive numbers
05868 //               are closer towards the camera.
05869 ////////////////////////////////////////////////////////////////////
05870 void NodePath::
05871 set_depth_offset(int bias, int priority) {
05872   nassertv_always(!is_empty());
05873 
05874   node()->set_attrib(DepthOffsetAttrib::make(bias), priority);
05875 }
05876 
05877 ////////////////////////////////////////////////////////////////////
05878 //     Function: NodePath::clear_depth_offset
05879 //       Access: Published
05880 //  Description: Completely removes any depth-offset adjustment that
05881 //               may have been set on this node via set_depth_offset().
05882 ////////////////////////////////////////////////////////////////////
05883 void NodePath::
05884 clear_depth_offset() {
05885   nassertv_always(!is_empty());
05886   node()->clear_attrib(DepthOffsetAttrib::get_class_slot());
05887 }
05888 
05889 ////////////////////////////////////////////////////////////////////
05890 //     Function: NodePath::has_depth_offset
05891 //       Access: Published
05892 //  Description: Returns true if a depth-offset adjustment has been
05893 //               explicitly set on this particular node via
05894 //               set_depth_offset().  If this returns true, then
05895 //               get_depth_offset() may be called to determine which has
05896 //               been set.
05897 ////////////////////////////////////////////////////////////////////
05898 bool NodePath::
05899 has_depth_offset() const {
05900   nassertr_always(!is_empty(), false);
05901   return node()->has_attrib(DepthOffsetAttrib::get_class_slot());
05902 }
05903 
05904 ////////////////////////////////////////////////////////////////////
05905 //     Function: NodePath::get_depth_offset
05906 //       Access: Published
05907 //  Description: Returns the depth offset value if it has been
05908 //               specified using set_depth_offset, or 0 if not.
05909 ////////////////////////////////////////////////////////////////////
05910 int NodePath::
05911 get_depth_offset() const {
05912   nassertr_always(!is_empty(), 0);
05913   const RenderAttrib *attrib =
05914     node()->get_attrib(DepthOffsetAttrib::get_class_slot());
05915   if (attrib != (const RenderAttrib *)NULL) {
05916     const DepthOffsetAttrib *doa = DCAST(DepthOffsetAttrib, attrib);
05917     return doa->get_offset();
05918   }
05919 
05920   return 0;
05921 }
05922 
05923 ////////////////////////////////////////////////////////////////////
05924 //     Function: NodePath::do_billboard_axis
05925 //       Access: Published
05926 //  Description: Performs a billboard-type rotate to the indicated
05927 //               camera node, one time only, and leaves the object
05928 //               rotated.  This is similar in principle to heads_up().
05929 ////////////////////////////////////////////////////////////////////
05930 void NodePath::
05931 do_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
05932   nassertv_always(!is_empty());
05933 
05934   CPT(TransformState) transform = camera.get_transform(get_parent());
05935   const LMatrix4 &rel_mat = transform->get_mat();
05936 
05937   LVector3 up = LVector3::up();
05938   LVector3 rel_pos = -rel_mat.get_row3(3);
05939 
05940   LQuaternion quat;
05941   ::heads_up(quat, rel_pos, up);
05942   set_quat(quat);
05943 
05944   // Also slide the geometry towards the camera according to the
05945   // offset factor.
05946   if (offset != 0.0f) {
05947     LVector3 translate = rel_mat.get_row3(3);
05948     translate.normalize();
05949     translate *= offset;
05950     set_pos(translate);
05951   }
05952 }
05953 
05954 ////////////////////////////////////////////////////////////////////
05955 //     Function: NodePath::do_billboard_point_eye
05956 //       Access: Published
05957 //  Description: Performs a billboard-type rotate to the indicated
05958 //               camera node, one time only, and leaves the object
05959 //               rotated.  This is similar in principle to look_at(),
05960 //               although the point_eye billboard effect cannot be
05961 //               achieved using the ordinary look_at() call.
05962 ////////////////////////////////////////////////////////////////////
05963 void NodePath::
05964 do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
05965   nassertv_always(!is_empty());
05966 
05967   CPT(TransformState) transform = camera.get_transform(get_parent());
05968   const LMatrix4 &rel_mat = transform->get_mat();
05969 
05970   LVector3 up = LVector3::up() * rel_mat;
05971   LVector3 rel_pos = LVector3::forward() * rel_mat;
05972 
05973   LQuaternion quat;
05974   ::look_at(quat, rel_pos, up);
05975   set_quat(quat);
05976 
05977   // Also slide the geometry towards the camera according to the
05978   // offset factor.
05979   if (offset != 0.0f) {
05980     LVector3 translate = rel_mat.get_row3(3);
05981     translate.normalize();
05982     translate *= offset;
05983     set_pos(translate);
05984   }
05985 }
05986 
05987 ////////////////////////////////////////////////////////////////////
05988 //     Function: NodePath::do_billboard_point_world
05989 //       Access: Published
05990 //  Description: Performs a billboard-type rotate to the indicated
05991 //               camera node, one time only, and leaves the object
05992 //               rotated.  This is similar in principle to look_at().
05993 ////////////////////////////////////////////////////////////////////
05994 void NodePath::
05995 do_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
05996   nassertv_always(!is_empty());
05997 
05998   CPT(TransformState) transform = camera.get_transform(get_parent());
05999   const LMatrix4 &rel_mat = transform->get_mat();
06000 
06001   LVector3 up = LVector3::up();
06002   LVector3 rel_pos = -rel_mat.get_row3(3);
06003 
06004   LQuaternion quat;
06005   ::look_at(quat, rel_pos, up);
06006   set_quat(quat);
06007 
06008   // Also slide the geometry towards the camera according to the
06009   // offset factor.
06010   if (offset != 0.0f) {
06011     LVector3 translate = rel_mat.get_row3(3);
06012     translate.normalize();
06013     translate *= offset;
06014     set_pos(translate);
06015   }
06016 }
06017 
06018 ////////////////////////////////////////////////////////////////////
06019 //     Function: NodePath::set_billboard_axis
06020 //       Access: Published
06021 //  Description: Puts a billboard transition on the node such that it
06022 //               will rotate in two dimensions around the up axis,
06023 //               towards a specified "camera" instead of to the
06024 //               viewing camera.
06025 ////////////////////////////////////////////////////////////////////
06026 void NodePath::
06027 set_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
06028   nassertv_always(!is_empty());
06029   CPT(RenderEffect) billboard = BillboardEffect::make
06030     (LVector3::up(), false, true, 
06031      offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06032   node()->set_effect(billboard);
06033 }
06034 
06035 ////////////////////////////////////////////////////////////////////
06036 //     Function: NodePath::set_billboard_point_eye
06037 //       Access: Published
06038 //  Description: Puts a billboard transition on the node such that it
06039 //               will rotate in three dimensions about the origin,
06040 //               keeping its up vector oriented to the top of the
06041 //               camera, towards a specified "camera" instead of to
06042 //               the viewing camera.
06043 ////////////////////////////////////////////////////////////////////
06044 void NodePath::
06045 set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
06046   nassertv_always(!is_empty());
06047   CPT(RenderEffect) billboard = BillboardEffect::make
06048     (LVector3::up(), true, false,
06049      offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06050   node()->set_effect(billboard);
06051 }
06052 
06053 ////////////////////////////////////////////////////////////////////
06054 //     Function: NodePath::set_billboard_point_world
06055 //       Access: Published
06056 //  Description: Puts a billboard transition on the node such that it
06057 //               will rotate in three dimensions about the origin,
06058 //               keeping its up vector oriented to the sky, towards a
06059 //               specified "camera" instead of to the viewing camera.
06060 ////////////////////////////////////////////////////////////////////
06061 void NodePath::
06062 set_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
06063   nassertv_always(!is_empty());
06064   CPT(RenderEffect) billboard = BillboardEffect::make
06065     (LVector3::up(), false, false,
06066      offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06067   node()->set_effect(billboard);
06068 }
06069 
06070 ////////////////////////////////////////////////////////////////////
06071 //     Function: NodePath::clear_billboard
06072 //       Access: Published
06073 //  Description: Removes any billboard effect from the node.
06074 ////////////////////////////////////////////////////////////////////
06075 void NodePath::
06076 clear_billboard() {
06077   nassertv_always(!is_empty());
06078   node()->clear_effect(BillboardEffect::get_class_type());
06079 }
06080 
06081 ////////////////////////////////////////////////////////////////////
06082 //     Function: NodePath::has_billboard
06083 //       Access: Published
06084 //  Description: Returns true if there is any billboard effect on
06085 //               the node.
06086 ////////////////////////////////////////////////////////////////////
06087 bool NodePath::
06088 has_billboard() const {
06089   nassertr_always(!is_empty(), false);
06090   return node()->has_effect(BillboardEffect::get_class_type());
06091 }
06092 
06093 ////////////////////////////////////////////////////////////////////
06094 //     Function: NodePath::set_compass
06095 //       Access: Published
06096 //  Description: Puts a compass effect on the node, so that it will
06097 //               retain a fixed rotation relative to the reference
06098 //               node (or render if the reference node is empty)
06099 //               regardless of the transforms above it.
06100 ////////////////////////////////////////////////////////////////////
06101 void NodePath::
06102 set_compass(const NodePath &reference) {
06103   nassertv_always(!is_empty());
06104   node()->set_effect(CompassEffect::make(reference));
06105 }
06106 
06107 ////////////////////////////////////////////////////////////////////
06108 //     Function: NodePath::clear_compass
06109 //       Access: Published
06110 //  Description: Removes any compass effect from the node.
06111 ////////////////////////////////////////////////////////////////////
06112 void NodePath::
06113 clear_compass() {
06114   nassertv_always(!is_empty());
06115   node()->clear_effect(CompassEffect::get_class_type());
06116 }
06117 
06118 ////////////////////////////////////////////////////////////////////
06119 //     Function: NodePath::has_compass
06120 //       Access: Published
06121 //  Description: Returns true if there is any compass effect on
06122 //               the node.
06123 ////////////////////////////////////////////////////////////////////
06124 bool NodePath::
06125 has_compass() const {
06126   nassertr_always(!is_empty(), false);
06127   return node()->has_effect(CompassEffect::get_class_type());
06128 }
06129 
06130 ////////////////////////////////////////////////////////////////////
06131 //     Function: NodePath::set_transparency
06132 //       Access: Published
06133 //  Description: Specifically sets or disables transparent rendering
06134 //               mode on this particular node.  If no other nodes
06135 //               override, this will cause items with a non-1 value
06136 //               for alpha color to be rendered partially transparent.
06137 ////////////////////////////////////////////////////////////////////
06138 void NodePath::
06139 set_transparency(TransparencyAttrib::Mode mode, int priority) {
06140   nassertv_always(!is_empty());
06141 
06142   node()->set_attrib(TransparencyAttrib::make(mode), priority);
06143 }
06144 
06145 ////////////////////////////////////////////////////////////////////
06146 //     Function: NodePath::clear_transparency
06147 //       Access: Published
06148 //  Description: Completely removes any transparency adjustment that
06149 //               may have been set on this node via set_transparency().
06150 //               The geometry at this level and below will
06151 //               subsequently be rendered either transparent or not,
06152 //               to whatever other nodes may have had
06153 //               set_transparency() on them.
06154 ////////////////////////////////////////////////////////////////////
06155 void NodePath::
06156 clear_transparency() {
06157   nassertv_always(!is_empty());
06158   node()->clear_attrib(TransparencyAttrib::get_class_slot());
06159 }
06160 
06161 ////////////////////////////////////////////////////////////////////
06162 //     Function: NodePath::has_transparency
06163 //       Access: Published
06164 //  Description: Returns true if a transparent-rendering adjustment
06165 //               has been explicitly set on this particular node via
06166 //               set_transparency().  If this returns true, then
06167 //               get_transparency() may be called to determine whether
06168 //               transparency has been explicitly enabled or
06169 //               explicitly disabled for this node.
06170 ////////////////////////////////////////////////////////////////////
06171 bool NodePath::
06172 has_transparency() const {
06173   nassertr_always(!is_empty(), false);
06174   return node()->has_attrib(TransparencyAttrib::get_class_slot());
06175 }
06176 
06177 ////////////////////////////////////////////////////////////////////
06178 //     Function: NodePath::get_transparency
06179 //       Access: Published
06180 //  Description: Returns the transparent rendering that has been
06181 //               specifically set on this node via set_transparency(), or
06182 //               M_none if nontransparent rendering has been specifically
06183 //               set, or if nothing has been specifically set.  See
06184 //               also has_transparency().  This does not necessarily
06185 //               imply that the geometry will or will not be rendered
06186 //               transparent, as there may be other nodes that override.
06187 ////////////////////////////////////////////////////////////////////
06188 TransparencyAttrib::Mode NodePath::
06189 get_transparency() const {
06190   nassertr_always(!is_empty(), TransparencyAttrib::M_none);
06191   const RenderAttrib *attrib =
06192     node()->get_attrib(TransparencyAttrib::get_class_slot());
06193   if (attrib != (const RenderAttrib *)NULL) {
06194     const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
06195     return ta->get_mode();
06196   }
06197 
06198   return TransparencyAttrib::M_none;
06199 }
06200 
06201 ////////////////////////////////////////////////////////////////////
06202 //     Function: NodePath::set_antialias
06203 //       Access: Published
06204 //  Description: Specifies the antialiasing type that should be
06205 //               applied at this node and below.  See AntialiasAttrib.
06206 ////////////////////////////////////////////////////////////////////
06207 void NodePath::
06208 set_antialias(unsigned short mode, int priority) {
06209   nassertv_always(!is_empty());
06210 
06211   node()->set_attrib(AntialiasAttrib::make(mode), priority);
06212 }
06213 
06214 ////////////////////////////////////////////////////////////////////
06215 //     Function: NodePath::clear_antialias
06216 //       Access: Published
06217 //  Description: Completely removes any antialias setting that
06218 //               may have been set on this node via set_antialias().
06219 ////////////////////////////////////////////////////////////////////
06220 void NodePath::
06221 clear_antialias() {
06222   nassertv_always(!is_empty());
06223   node()->clear_attrib(AntialiasAttrib::get_class_slot());
06224 }
06225 
06226 ////////////////////////////////////////////////////////////////////
06227 //     Function: NodePath::has_antialias
06228 //       Access: Published
06229 //  Description: Returns true if an antialias setting has been
06230 //               explicitly mode on this particular node via
06231 //               set_antialias().  If this returns true, then
06232 //               get_antialias() may be called to determine what the
06233 //               setting was.
06234 ////////////////////////////////////////////////////////////////////
06235 bool NodePath::
06236 has_antialias() const {
06237   nassertr_always(!is_empty(), false);
06238   return node()->has_attrib(AntialiasAttrib::get_class_slot());
06239 }
06240 
06241 ////////////////////////////////////////////////////////////////////
06242 //     Function: NodePath::get_antialias
06243 //       Access: Published
06244 //  Description: Returns the antialias setting that has been
06245 //               specifically set on this node via set_antialias(), or
06246 //               M_none if no setting has been made.
06247 ////////////////////////////////////////////////////////////////////
06248 unsigned short NodePath::
06249 get_antialias() const {
06250   nassertr_always(!is_empty(), AntialiasAttrib::M_none);
06251   const RenderAttrib *attrib =
06252     node()->get_attrib(AntialiasAttrib::get_class_slot());
06253   if (attrib != (const RenderAttrib *)NULL) {
06254     const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib);
06255     return ta->get_mode();
06256   }
06257 
06258   return AntialiasAttrib::M_none;
06259 }
06260 
06261 ////////////////////////////////////////////////////////////////////
06262 //     Function: NodePath::has_audio_volume
06263 //       Access: Published
06264 //  Description: Returns true if an audio volume has been applied
06265 //               to the referenced node, false otherwise.  It is still
06266 //               possible that volume at this node might have been
06267 //               scaled by an ancestor node.
06268 ////////////////////////////////////////////////////////////////////
06269 bool NodePath::
06270 has_audio_volume() const {
06271   nassertr_always(!is_empty(), false);
06272   return node()->has_attrib(AudioVolumeAttrib::get_class_slot());
06273 }
06274 
06275 ////////////////////////////////////////////////////////////////////
06276 //     Function: NodePath::clear_audio_volume
06277 //       Access: Published
06278 //  Description: Completely removes any audio volume from the
06279 //               referenced node.  This is preferable to simply
06280 //               setting the audio volume to identity, as it also
06281 //               removes the overhead associated with having an audio
06282 //               volume at all.
06283 ////////////////////////////////////////////////////////////////////
06284 void NodePath::
06285 clear_audio_volume() {
06286   nassertv_always(!is_empty());
06287   node()->clear_attrib(AudioVolumeAttrib::get_class_slot());
06288 }
06289 
06290 ////////////////////////////////////////////////////////////////////
06291 //     Function: NodePath::set_audio_volume
06292 //       Access: Published
06293 //  Description: Sets the audio volume component of the transform
06294 ////////////////////////////////////////////////////////////////////
06295 void NodePath::
06296 set_audio_volume(PN_stdfloat volume, int priority) {
06297   nassertv_always(!is_empty());
06298 
06299   const RenderAttrib *attrib =
06300     node()->get_attrib(AudioVolumeAttrib::get_class_slot());
06301   if (attrib != (const RenderAttrib *)NULL) {
06302     priority = max(priority,
06303                    node()->get_state()->get_override(AudioVolumeAttrib::get_class_slot()));
06304     CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib);
06305 
06306     // Modify the existing AudioVolumeAttrib to add the indicated
06307     // volume.
06308     node()->set_attrib(ava->set_volume(volume), priority);
06309 
06310   } else {
06311     // Create a new AudioVolumeAttrib for this node.
06312     node()->set_attrib(AudioVolumeAttrib::make(volume), priority);
06313   }
06314 }
06315 
06316 ////////////////////////////////////////////////////////////////////
06317 //     Function: NodePath::set_audio_volume_off
06318 //       Access: Published
06319 //  Description: Disables any audio volume attribute inherited from
06320 //               above.  This is not the same thing as
06321 //               clear_audio_volume(), which undoes any previous
06322 //               set_audio_volume() operation on this node; rather,
06323 //               this actively disables any set_audio_volume() that
06324 //               might be inherited from a parent node.
06325 //
06326 //               It is legal to specify a new volume on the same
06327 //               node with a subsequent call to set_audio_volume();
06328 //               this new scale will apply to lower nodes.
06329 ////////////////////////////////////////////////////////////////////
06330 void NodePath::
06331 set_audio_volume_off(int priority) {
06332   nassertv_always(!is_empty());
06333   node()->set_attrib(AudioVolumeAttrib::make_off(), priority);
06334 }
06335 
06336 ////////////////////////////////////////////////////////////////////
06337 //     Function: NodePath::get_audio_volume
06338 //       Access: Published
06339 //  Description: Returns the complete audio volume that has been
06340 //               applied to this node via a previous call to
06341 //               set_audio_volume(), or 1. (identity) if no volume has
06342 //               been applied to this particular node.
06343 ////////////////////////////////////////////////////////////////////
06344 PN_stdfloat NodePath::
06345 get_audio_volume() const {
06346   const RenderAttrib *attrib =
06347     node()->get_attrib(AudioVolumeAttrib::get_class_slot());
06348   if (attrib != (const RenderAttrib *)NULL) {
06349     const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
06350     return ava->get_volume();
06351   }
06352 
06353   return 1.0f;
06354 }
06355 
06356 ////////////////////////////////////////////////////////////////////
06357 //     Function: NodePath::get_net_audio_volume
06358 //       Access: Published
06359 //  Description: Returns the complete audio volume for this node
06360 //               taking highers nodes in the graph into account.
06361 ////////////////////////////////////////////////////////////////////
06362 PN_stdfloat NodePath::
06363 get_net_audio_volume() const {
06364   CPT(RenderState) net_state = get_net_state();
06365   const RenderAttrib *attrib = net_state->get_attrib(AudioVolumeAttrib::get_class_slot());
06366   if (attrib != (const RenderAttrib *)NULL) {
06367     const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
06368     if (ava != (const AudioVolumeAttrib *)NULL) {
06369       return ava->get_volume();
06370     }
06371   }
06372 
06373   return 1.0f;
06374 }
06375 
06376 ////////////////////////////////////////////////////////////////////
06377 //     Function: NodePath::get_hidden_ancestor
06378 //       Access: Published
06379 //  Description: Returns the NodePath at or above the referenced node
06380 //               that is hidden to the indicated camera(s), or an
06381 //               empty NodePath if no ancestor of the referenced node
06382 //               is hidden (and the node should be visible).
06383 ////////////////////////////////////////////////////////////////////
06384 NodePath NodePath::
06385 get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const {
06386   int pipeline_stage = current_thread->get_pipeline_stage();
06387 
06388   NodePathComponent *comp;
06389   for (comp = _head; 
06390        comp != (NodePathComponent *)NULL; 
06391        comp = comp->get_next(pipeline_stage, current_thread)) {
06392     PandaNode *node = comp->get_node();
06393     if (node->is_overall_hidden() ||
06394         ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
06395       NodePath result;
06396       result._head = comp;
06397       return result;
06398     }
06399   }
06400 
06401   return not_found();
06402 }
06403 
06404 ////////////////////////////////////////////////////////////////////
06405 //     Function: NodePath::stash
06406 //       Access: Published
06407 //  Description: Removes the referenced node (and the entire subgraph
06408 //               below this node) from the scene graph in any normal
06409 //               sense.  The node will no longer be visible and is not
06410 //               tested for collisions; furthermore, no normal scene
06411 //               graph traversal will visit the node.  The node's
06412 //               bounding volume no longer contributes to its parent's
06413 //               bounding volume.
06414 //
06415 //               A stashed node cannot be located by a normal find()
06416 //               operation (although a special find string can still
06417 //               retrieve it).
06418 ////////////////////////////////////////////////////////////////////
06419 void NodePath::
06420 stash(int sort, Thread *current_thread) {
06421   nassertv_always(!is_singleton() && !is_empty());
06422   nassertv(verify_complete());
06423 
06424   int pipeline_stage = current_thread->get_pipeline_stage();
06425   bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
06426                                         _head, sort, true, pipeline_stage,
06427                                         current_thread);
06428   nassertv(reparented);
06429 }
06430 
06431 ////////////////////////////////////////////////////////////////////
06432