Panda3D

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 void NodePath::
04666 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to) {
04667   nassertv_always(!is_empty());
04668 
04669   const RenderEffect *effect =
04670     node()->get_effect(TexProjectorEffect::get_class_type());
04671 
04672   CPT(TexProjectorEffect) tpe;
04673 
04674   if (effect != (const RenderEffect *)NULL) {
04675     tpe = DCAST(TexProjectorEffect, effect);
04676 
04677   } else {
04678     tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make());
04679   }
04680 
04681   node()->set_effect(tpe->add_stage(stage, from, to));
04682 }
04683 
04684 ////////////////////////////////////////////////////////////////////
04685 //     Function: NodePath::clear_tex_projector
04686 //       Access: Published
04687 //  Description: Removes the TexProjectorEffect for the indicated
04688 //               stage from this node.
04689 ////////////////////////////////////////////////////////////////////
04690 void NodePath::
04691 clear_tex_projector(TextureStage *stage) {
04692   nassertv_always(!is_empty());
04693 
04694   const RenderEffect *effect =
04695     node()->get_effect(TexProjectorEffect::get_class_type());
04696   if (effect != (const RenderEffect *)NULL) {
04697     CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect);
04698     tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage));
04699 
04700     if (tpe->is_empty()) {
04701       node()->clear_effect(TexProjectorEffect::get_class_type());
04702 
04703     } else {
04704       node()->set_effect(tpe);
04705     }
04706   }
04707 }
04708 
04709 ////////////////////////////////////////////////////////////////////
04710 //     Function: NodePath::clear_tex_projector
04711 //       Access: Published
04712 //  Description: Removes the TexProjectorEffect for all stages from
04713 //               this node.
04714 ////////////////////////////////////////////////////////////////////
04715 void NodePath::
04716 clear_tex_projector() {
04717   nassertv_always(!is_empty());
04718   node()->clear_effect(TexProjectorEffect::get_class_type());
04719 }
04720 
04721 ////////////////////////////////////////////////////////////////////
04722 //     Function: NodePath::has_tex_projector
04723 //       Access: Published
04724 //  Description: Returns true if this node has a TexProjectorEffect
04725 //               for the indicated stage, false otherwise.
04726 ////////////////////////////////////////////////////////////////////
04727 bool NodePath::
04728 has_tex_projector(TextureStage *stage) const {
04729   nassertr_always(!is_empty(), false);
04730 
04731   const RenderEffect *effect =
04732     node()->get_effect(TexProjectorEffect::get_class_type());
04733   if (effect != (const RenderEffect *)NULL) {
04734     const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04735     return tpe->has_stage(stage);
04736   }
04737 
04738   return false;
04739 }
04740 
04741 ////////////////////////////////////////////////////////////////////
04742 //     Function: NodePath::get_tex_projector_from
04743 //       Access: Published
04744 //  Description: Returns the "from" node associated with the
04745 //               TexProjectorEffect on the indicated stage.  The
04746 //               relative transform between the "from" and the "to"
04747 //               nodes is automatically applied to the texture
04748 //               transform each frame.
04749 ////////////////////////////////////////////////////////////////////
04750 NodePath NodePath::
04751 get_tex_projector_from(TextureStage *stage) const {
04752   nassertr_always(!is_empty(), NodePath::fail());
04753 
04754   const RenderEffect *effect =
04755     node()->get_effect(TexProjectorEffect::get_class_type());
04756   if (effect != (const RenderEffect *)NULL) {
04757     const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04758     return tpe->get_from(stage);
04759   }
04760 
04761   return NodePath::not_found();
04762 }
04763 
04764 ////////////////////////////////////////////////////////////////////
04765 //     Function: NodePath::get_tex_projector_to
04766 //       Access: Published
04767 //  Description: Returns the "to" node associated with the
04768 //               TexProjectorEffect on the indicated stage.  The
04769 //               relative transform between the "from" and the "to"
04770 //               nodes is automatically applied to the texture
04771 //               transform each frame.
04772 ////////////////////////////////////////////////////////////////////
04773 NodePath NodePath::
04774 get_tex_projector_to(TextureStage *stage) const {
04775   nassertr_always(!is_empty(), NodePath::fail());
04776 
04777   const RenderEffect *effect =
04778     node()->get_effect(TexProjectorEffect::get_class_type());
04779   if (effect != (const RenderEffect *)NULL) {
04780     const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04781     return tpe->get_to(stage);
04782   }
04783 
04784   return NodePath::not_found();
04785 }
04786 
04787 ////////////////////////////////////////////////////////////////////
04788 //     Function: NodePath::project_texture
04789 //       Access: Published
04790 //  Description: A convenience function to enable projective texturing
04791 //               at this node level and below, using the indicated
04792 //               NodePath (which should contain a LensNode) as the
04793 //               projector.
04794 ////////////////////////////////////////////////////////////////////
04795 void NodePath::
04796 project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) {
04797   nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type()));
04798   set_texture(stage, tex);
04799   set_tex_gen(stage, TexGenAttrib::M_world_position);
04800   set_tex_projector(stage, NodePath(), projector);
04801 }
04802 
04803 
04804 ////////////////////////////////////////////////////////////////////
04805 //     Function: NodePath::set_normal_map
04806 //       Access: Published
04807 //  Description: A convenience function to set up a normal map on this
04808 //               geometry.  This uses the single highest-priority
04809 //               light on the object only.  It also requires
04810 //               multitexture, and consumes at least two texture
04811 //               stages, in addition to what may already be in use.
04812 //
04813 //               The normal_map parameter is the texture that contains
04814 //               the normal map information (with a 3-d delta vector
04815 //               encoded into the r,g,b of each texel).  texcoord_name is
04816 //               the name of the texture coordinate set that contains
04817 //               the tangent and binormal we wish to use.  If
04818 //               preserve_color is true, then one additional texture
04819 //               stage is consumed to blend in the geometry's original
04820 //               vertex color.
04821 //
04822 //               Only one normal map may be in effect through this
04823 //               interface at any given time.
04824 ////////////////////////////////////////////////////////////////////
04825 void NodePath::
04826 set_normal_map(Texture *normal_map, const string &texcoord_name,
04827                bool preserve_color) {
04828   clear_normal_map();
04829 
04830   // First, we apply the normal map itself, to the bottom layer.
04831   PT(TextureStage) normal_map_ts = new TextureStage("__normal_map");
04832   normal_map_ts->set_texcoord_name(texcoord_name);
04833   normal_map_ts->set_sort(-20);
04834   normal_map_ts->set_mode(TextureStage::M_replace);
04835   set_texture(normal_map_ts, normal_map);
04836 
04837   // Then, we apply a normalization map, to normalize, per-pixel, the
04838   // vector to the light.
04839   PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32);
04840   PT(TextureStage) normalization_map_ts = new TextureStage("__normalization_map");
04841   normalization_map_ts->set_combine_rgb
04842     (TextureStage::CM_dot3_rgb, 
04843      TextureStage::CS_texture, TextureStage::CO_src_color,
04844      TextureStage::CS_previous, TextureStage::CO_src_color);
04845   normalization_map_ts->set_texcoord_name("light_vector");
04846   normalization_map_ts->set_sort(-15);
04847   set_texture(normalization_map_ts, normalization_map);
04848 
04849   // Finally, we enable M_light_vector texture coordinate generation.
04850   set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector, 
04851               texcoord_name, NodePath());
04852 
04853   if (preserve_color) {
04854     // One more stage to get back the original color.
04855     PT(TextureStage) orig_color_ts = new TextureStage("__orig_color");
04856     orig_color_ts->set_combine_rgb
04857       (TextureStage::CM_modulate,
04858        TextureStage::CS_primary_color, TextureStage::CO_src_color,
04859        TextureStage::CS_previous, TextureStage::CO_src_color);
04860     set_texture(orig_color_ts, normal_map);
04861   }
04862 }
04863 
04864 ////////////////////////////////////////////////////////////////////
04865 //     Function: NodePath::clear_normal_map
04866 //       Access: Published
04867 //  Description: Undoes the effect of a previous call to
04868 //               set_normal_map().
04869 ////////////////////////////////////////////////////////////////////
04870 void NodePath::
04871 clear_normal_map() {
04872   // Scan through the TextureStages, and if we find any whose name
04873   // matches one of the stages that would have been left by
04874   // set_normal_map(), remove it from the state.
04875 
04876   CPT(RenderAttrib) attrib =
04877     get_state()->get_attrib(TextureAttrib::get_class_slot());
04878   if (attrib != (const RenderAttrib *)NULL) {
04879     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
04880     for (int i = 0; i < ta->get_num_on_stages(); i++) {
04881       TextureStage *stage = ta->get_on_stage(i);
04882       if (stage->get_name() == "__normal_map") {
04883         clear_texture(stage);
04884 
04885       } else if (stage->get_name() == "__normalization_map") {
04886         clear_texture(stage);
04887         clear_tex_gen(stage);
04888 
04889       } else if (stage->get_name() == "__orig_color") {
04890         clear_texture(stage);
04891       }
04892     }
04893   }
04894 }
04895 
04896 ////////////////////////////////////////////////////////////////////
04897 //     Function: NodePath::has_vertex_column
04898 //       Access: Published
04899 //  Description: Returns true if there are at least some vertices at
04900 //               this node and below that contain a reference to the
04901 //               indicated vertex data column name, false otherwise.
04902 //
04903 //               This is particularly useful for testing whether a
04904 //               particular model has a given texture coordinate set
04905 //               (but see has_texcoord()).
04906 ////////////////////////////////////////////////////////////////////
04907 bool NodePath::
04908 has_vertex_column(const InternalName *name) const {
04909   nassertr_always(!is_empty(), false);
04910   return r_has_vertex_column(node(), name);
04911 }
04912 
04913 ////////////////////////////////////////////////////////////////////
04914 //     Function: NodePath::find_all_vertex_columns
04915 //       Access: Published
04916 //  Description: Returns a list of all vertex array columns stored on
04917 //               some geometry found at this node level and below.
04918 ////////////////////////////////////////////////////////////////////
04919 InternalNameCollection NodePath::
04920 find_all_vertex_columns() const {
04921   nassertr_always(!is_empty(), InternalNameCollection());
04922   InternalNames vertex_columns;
04923   r_find_all_vertex_columns(node(), vertex_columns);
04924 
04925   InternalNameCollection tc;
04926   InternalNames::iterator ti;
04927   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04928     tc.add_name(*ti);
04929   }
04930   return tc;
04931 }
04932 
04933 ////////////////////////////////////////////////////////////////////
04934 //     Function: NodePath::find_all_vertex_columns
04935 //       Access: Published
04936 //  Description: Returns a list of all vertex array columns stored on
04937 //               some geometry found at this node level and below that
04938 //               match the indicated name (which may contain wildcard
04939 //               characters).
04940 ////////////////////////////////////////////////////////////////////
04941 InternalNameCollection NodePath::
04942 find_all_vertex_columns(const string &name) const {
04943   nassertr_always(!is_empty(), InternalNameCollection());
04944   InternalNames vertex_columns;
04945   r_find_all_vertex_columns(node(), vertex_columns);
04946 
04947   GlobPattern glob(name);
04948 
04949   InternalNameCollection tc;
04950   InternalNames::iterator ti;
04951   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04952     InternalName *name = (*ti);
04953     if (glob.matches(name->get_name())) {
04954       tc.add_name(name);
04955     }
04956   }
04957   return tc;
04958 }
04959 
04960 ////////////////////////////////////////////////////////////////////
04961 //     Function: NodePath::find_all_texcoords
04962 //       Access: Published
04963 //  Description: Returns a list of all texture coordinate sets used by
04964 //               any geometry at this node level and below.
04965 ////////////////////////////////////////////////////////////////////
04966 InternalNameCollection NodePath::
04967 find_all_texcoords() const {
04968   nassertr_always(!is_empty(), InternalNameCollection());
04969   InternalNames vertex_columns;
04970   r_find_all_vertex_columns(node(), vertex_columns);
04971 
04972   CPT(InternalName) texcoord_name = InternalName::get_texcoord();
04973   
04974   InternalNameCollection tc;
04975   InternalNames::iterator ti;
04976   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04977     if ((*ti)->get_top() == texcoord_name) {
04978       tc.add_name(*ti);
04979     }
04980   }
04981   return tc;
04982 }
04983 
04984 ////////////////////////////////////////////////////////////////////
04985 //     Function: NodePath::find_all_texcoords
04986 //       Access: Published
04987 //  Description: Returns a list of all texture coordinate sets used by
04988 //               any geometry at this node level and below that match
04989 //               the indicated name (which may contain wildcard
04990 //               characters).
04991 ////////////////////////////////////////////////////////////////////
04992 InternalNameCollection NodePath::
04993 find_all_texcoords(const string &name) const {
04994   nassertr_always(!is_empty(), InternalNameCollection());
04995   InternalNames vertex_columns;
04996   r_find_all_vertex_columns(node(), vertex_columns);
04997 
04998   GlobPattern glob(name);
04999   CPT(InternalName) texcoord_name = InternalName::get_texcoord();
05000 
05001   InternalNameCollection tc;
05002   InternalNames::iterator ti;
05003   for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
05004     InternalName *name = (*ti);
05005     if (name->get_top() == texcoord_name) {
05006       // This is a texture coordinate name.  Figure out the basename
05007       // of the texture coordinates.
05008       int index = name->find_ancestor("texcoord");
05009       nassertr(index != -1, InternalNameCollection());
05010       string net_basename = name->get_net_basename(index - 1);
05011 
05012       if (glob.matches(net_basename)) {
05013         tc.add_name(name);
05014       }
05015     }
05016   }
05017   return tc;
05018 }
05019 
05020 ////////////////////////////////////////////////////////////////////
05021 //     Function: NodePath::find_texture
05022 //       Access: Published
05023 //  Description: Returns the first texture found applied to geometry
05024 //               at this node or below that matches the indicated name
05025 //               (which may contain wildcards).  Returns the texture
05026 //               if it is found, or NULL if it is not.
05027 ////////////////////////////////////////////////////////////////////
05028 Texture *NodePath::
05029 find_texture(const string &name) const {
05030   nassertr_always(!is_empty(), NULL);
05031   GlobPattern glob(name);
05032   return r_find_texture(node(), get_net_state(), glob);
05033 }
05034 
05035 ////////////////////////////////////////////////////////////////////
05036 //     Function: NodePath::find_texture
05037 //       Access: Published
05038 //  Description: Returns the first texture found applied to geometry
05039 //               at this node or below that is assigned to the
05040 //               indicated texture stage.  Returns the texture if it
05041 //               is found, or NULL if it is not.
05042 ////////////////////////////////////////////////////////////////////
05043 Texture *NodePath::
05044 find_texture(TextureStage *stage) const {
05045   nassertr_always(!is_empty(), NULL);
05046   return r_find_texture(node(), stage);
05047 }
05048 
05049 ////////////////////////////////////////////////////////////////////
05050 //     Function: NodePath::find_all_textures
05051 //       Access: Published
05052 //  Description: Returns a list of a textures applied to geometry at
05053 //               this node and below.
05054 ////////////////////////////////////////////////////////////////////
05055 TextureCollection NodePath::
05056 find_all_textures() const {
05057   nassertr_always(!is_empty(), TextureCollection());
05058   Textures textures;
05059   r_find_all_textures(node(), get_net_state(), textures);
05060 
05061   TextureCollection tc;
05062   Textures::iterator ti;
05063   for (ti = textures.begin(); ti != textures.end(); ++ti) {
05064     tc.add_texture(*ti);
05065   }
05066   return tc;
05067 }
05068 
05069 ////////////////////////////////////////////////////////////////////
05070 //     Function: NodePath::find_all_textures
05071 //       Access: Published
05072 //  Description: Returns a list of a textures applied to geometry at
05073 //               this node and below that match the indicated name
05074 //               (which may contain wildcard characters).
05075 ////////////////////////////////////////////////////////////////////
05076 TextureCollection NodePath::
05077 find_all_textures(const string &name) const {
05078   nassertr_always(!is_empty(), TextureCollection());
05079   Textures textures;
05080   r_find_all_textures(node(), get_net_state(), textures);
05081 
05082   GlobPattern glob(name);
05083 
05084   TextureCollection tc;
05085   Textures::iterator ti;
05086   for (ti = textures.begin(); ti != textures.end(); ++ti) {
05087     Texture *texture = (*ti);
05088     if (glob.matches(texture->get_name())) {
05089       tc.add_texture(texture);
05090     }
05091   }
05092   return tc;
05093 }
05094 
05095 ////////////////////////////////////////////////////////////////////
05096 //     Function: NodePath::find_all_textures
05097 //       Access: Published
05098 //  Description: Returns a list of a textures on geometry at
05099 //               this node and below that are assigned to the
05100 //               indicated texture stage.
05101 ////////////////////////////////////////////////////////////////////
05102 TextureCollection NodePath::
05103 find_all_textures(TextureStage *stage) const {
05104   nassertr_always(!is_empty(), TextureCollection());
05105   Textures textures;
05106   r_find_all_textures(node(), stage, textures);
05107 
05108   TextureCollection tc;
05109   Textures::iterator ti;
05110   for (ti = textures.begin(); ti != textures.end(); ++ti) {
05111     Texture *texture = (*ti);
05112     tc.add_texture(texture);
05113   }
05114   return tc;
05115 }
05116 
05117 ////////////////////////////////////////////////////////////////////
05118 //     Function: NodePath::find_texture_stage
05119 //       Access: Published
05120 //  Description: Returns the first TextureStage found applied to
05121 //               geometry at this node or below that matches the
05122 //               indicated name (which may contain wildcards).
05123 //               Returns the TextureStage if it is found, or NULL if
05124 //               it is not.
05125 ////////////////////////////////////////////////////////////////////
05126 TextureStage *NodePath::
05127 find_texture_stage(const string &name) const {
05128   nassertr_always(!is_empty(), NULL);
05129   GlobPattern glob(name);
05130   return r_find_texture_stage(node(), get_net_state(), glob);
05131 }
05132 
05133 ////////////////////////////////////////////////////////////////////
05134 //     Function: NodePath::find_all_texture_stages
05135 //       Access: Published
05136 //  Description: Returns a list of a TextureStages applied to geometry
05137 //               at this node and below.
05138 ////////////////////////////////////////////////////////////////////
05139 TextureStageCollection NodePath::
05140 find_all_texture_stages() const {
05141   nassertr_always(!is_empty(), TextureStageCollection());
05142   TextureStages texture_stages;
05143   r_find_all_texture_stages(node(), get_net_state(), texture_stages);
05144 
05145   TextureStageCollection tc;
05146   TextureStages::iterator ti;
05147   for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
05148     tc.add_texture_stage(*ti);
05149   }
05150   return tc;
05151 }
05152 
05153 ////////////////////////////////////////////////////////////////////
05154 //     Function: NodePath::unify_texture_stages
05155 //       Access: Published
05156 //  Description: Searches through all TextureStages at this node and
05157 //               below.  Any TextureStages that share the same name as
05158 //               the indicated TextureStage object are replaced with
05159 //               this object, thus ensuring that all geometry at this
05160 //               node and below with a particular TextureStage name is
05161 //               using the same TextureStage object.
05162 ////////////////////////////////////////////////////////////////////
05163 void NodePath::
05164 unify_texture_stages(TextureStage *stage) {
05165   nassertv_always(!is_empty());
05166   r_unify_texture_stages(node(), stage);
05167 }
05168 
05169 ////////////////////////////////////////////////////////////////////
05170 //     Function: NodePath::find_all_texture_stages
05171 //       Access: Published
05172 //  Description: Returns a list of a TextureStages applied to geometry
05173 //               at this node and below that match the indicated name
05174 //               (which may contain wildcard characters).
05175 ////////////////////////////////////////////////////////////////////
05176 TextureStageCollection NodePath::
05177 find_all_texture_stages(const string &name) const {
05178   nassertr_always(!is_empty(), TextureStageCollection());
05179   TextureStages texture_stages;
05180   r_find_all_texture_stages(node(), get_net_state(), texture_stages);
05181 
05182   GlobPattern glob(name);
05183 
05184   TextureStageCollection tc;
05185   TextureStages::iterator ti;
05186   for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
05187     TextureStage *texture_stage = (*ti);
05188     if (glob.matches(texture_stage->get_name())) {
05189       tc.add_texture_stage(texture_stage);
05190     }
05191   }
05192   return tc;
05193 }
05194 
05195 ////////////////////////////////////////////////////////////////////
05196 //     Function: NodePath::find_material
05197 //       Access: Published
05198 //  Description: Returns the first material found applied to geometry
05199 //               at this node or below that matches the indicated name
05200 //               (which may contain wildcards).  Returns the material
05201 //               if it is found, or NULL if it is not.
05202 ////////////////////////////////////////////////////////////////////
05203 Material *NodePath::
05204 find_material(const string &name) const {
05205   nassertr_always(!is_empty(), NULL);
05206   GlobPattern glob(name);
05207   return r_find_material(node(), get_net_state(), glob);
05208 }
05209 
05210 ////////////////////////////////////////////////////////////////////
05211 //     Function: NodePath::find_all_materials
05212 //       Access: Published
05213 //  Description: Returns a list of a materials applied to geometry at
05214 //               this node and below.
05215 ////////////////////////////////////////////////////////////////////
05216 MaterialCollection NodePath::
05217 find_all_materials() const {
05218   nassertr_always(!is_empty(), MaterialCollection());
05219   Materials materials;
05220   r_find_all_materials(node(), get_net_state(), materials);
05221 
05222   MaterialCollection tc;
05223   Materials::iterator ti;
05224   for (ti = materials.begin(); ti != materials.end(); ++ti) {
05225     tc.add_material(*ti);
05226   }
05227   return tc;
05228 }
05229 
05230 ////////////////////////////////////////////////////////////////////
05231 //     Function: NodePath::find_all_materials
05232 //       Access: Published
05233 //  Description: Returns a list of a materials applied to geometry at
05234 //               this node and below that match the indicated name
05235 //               (which may contain wildcard characters).
05236 ////////////////////////////////////////////////////////////////////
05237 MaterialCollection NodePath::
05238 find_all_materials(const string &name) const {
05239   nassertr_always(!is_empty(), MaterialCollection());
05240   Materials materials;
05241   r_find_all_materials(node(), get_net_state(), materials);
05242 
05243   GlobPattern glob(name);
05244 
05245   MaterialCollection tc;
05246   Materials::iterator ti;
05247   for (ti = materials.begin(); ti != materials.end(); ++ti) {
05248     Material *material = (*ti);
05249     if (glob.matches(material->get_name())) {
05250       tc.add_material(material);
05251     }
05252   }
05253   return tc;
05254 }
05255 
05256 ////////////////////////////////////////////////////////////////////
05257 //     Function: NodePath::set_material
05258 //       Access: Published
05259 //  Description: Sets the geometry at this level and below to render
05260 //               using the indicated material.
05261 //
05262 //               Previously, this operation made a copy of the
05263 //               material structure, but nowadays it assigns the
05264 //               pointer directly.
05265 ////////////////////////////////////////////////////////////////////
05266 void NodePath::
05267 set_material(Material *mat, int priority) {
05268   nassertv_always(!is_empty());
05269   nassertv(mat != NULL);
05270   node()->set_attrib(MaterialAttrib::make(mat), priority);
05271 }
05272 
05273 ////////////////////////////////////////////////////////////////////
05274 //     Function: NodePath::set_material_off
05275 //       Access: Published
05276 //  Description: Sets the geometry at this level and below to render
05277 //               using no material.  This is normally the default, but
05278 //               it may be useful to use this to contradict
05279 //               set_material() at a higher node level (or, with a
05280 //               priority, to override a set_material() at a lower
05281 //               level).
05282 ////////////////////////////////////////////////////////////////////
05283 void NodePath::
05284 set_material_off(int priority) {
05285   nassertv_always(!is_empty());
05286   node()->set_attrib(MaterialAttrib::make_off(), priority);
05287 }
05288 
05289 ////////////////////////////////////////////////////////////////////
05290 //     Function: NodePath::clear_material
05291 //       Access: Published
05292 //  Description: Completely removes any material adjustment that may
05293 //               have been set via set_material() from this particular
05294 //               node.
05295 ////////////////////////////////////////////////////////////////////
05296 void NodePath::
05297 clear_material() {
05298   nassertv_always(!is_empty());
05299   node()->clear_attrib(MaterialAttrib::get_class_slot());
05300 }
05301 
05302 ////////////////////////////////////////////////////////////////////
05303 //     Function: NodePath::has_material
05304 //       Access: Published
05305 //  Description: Returns true if a material has been applied to this
05306 //               particular node via set_material(), false otherwise.
05307 ////////////////////////////////////////////////////////////////////
05308 bool NodePath::
05309 has_material() const {
05310   nassertr_always(!is_empty(), false);
05311   const RenderAttrib *attrib =
05312     node()->get_attrib(MaterialAttrib::get_class_slot());
05313   if (attrib != (const RenderAttrib *)NULL) {
05314     const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
05315     return !ma->is_off();
05316   }
05317 
05318   return false;
05319 }
05320 
05321 ////////////////////////////////////////////////////////////////////
05322 //     Function: NodePath::get_material
05323 //       Access: Published
05324 //  Description: Returns the material that has been set on this
05325 //               particular node, or NULL if no material has been set.
05326 //               This is not necessarily the material that will be
05327 //               applied to the geometry at or below this level, as
05328 //               another material at a higher or lower level may
05329 //               override.
05330 
05331 //               See also find_material().
05332 ////////////////////////////////////////////////////////////////////
05333 PT(Material) NodePath::
05334 get_material() const {
05335   nassertr_always(!is_empty(), NULL);
05336   const RenderAttrib *attrib =
05337     node()->get_attrib(MaterialAttrib::get_class_slot());
05338   if (attrib != (const RenderAttrib *)NULL) {
05339     const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
05340     return ma->get_material();
05341   }
05342 
05343   return NULL;
05344 }
05345 
05346 ////////////////////////////////////////////////////////////////////
05347 //     Function: NodePath::set_fog
05348 //       Access: Published
05349 //  Description: Sets the geometry at this level and below to render
05350 //               using the indicated fog.
05351 ////////////////////////////////////////////////////////////////////
05352 void NodePath::
05353 set_fog(Fog *fog, int priority) {
05354   nassertv_always(!is_empty());
05355   node()->set_attrib(FogAttrib::make(fog), priority);
05356 }
05357 
05358 ////////////////////////////////////////////////////////////////////
05359 //     Function: NodePath::set_fog_off
05360 //       Access: Published
05361 //  Description: Sets the geometry at this level and below to render
05362 //               using no fog.  This is normally the default, but
05363 //               it may be useful to use this to contradict
05364 //               set_fog() at a higher node level (or, with a
05365 //               priority, to override a set_fog() at a lower
05366 //               level).
05367 ////////////////////////////////////////////////////////////////////
05368 void NodePath::
05369 set_fog_off(int priority) {
05370   nassertv_always(!is_empty());
05371   node()->set_attrib(FogAttrib::make_off(), priority);
05372 }
05373 
05374 ////////////////////////////////////////////////////////////////////
05375 //     Function: NodePath::clear_fog
05376 //       Access: Published
05377 //  Description: Completely removes any fog adjustment that may
05378 //               have been set via set_fog() or set_fog_off()
05379 //               from this particular node.  This allows whatever
05380 //               fogs might be otherwise affecting the geometry to
05381 //               show instead.
05382 ////////////////////////////////////////////////////////////////////
05383 void NodePath::
05384 clear_fog() {
05385   nassertv_always(!is_empty());
05386   node()->clear_attrib(FogAttrib::get_class_slot());
05387 }
05388 
05389 ////////////////////////////////////////////////////////////////////
05390 //     Function: NodePath::has_fog
05391 //       Access: Published
05392 //  Description: Returns true if a fog has been applied to this
05393 //               particular node via set_fog(), false otherwise.
05394 //               This is not the same thing as asking whether the
05395 //               geometry at this node will be rendered with
05396 //               fog, as there may be a fog in effect from a higher or
05397 //               lower level.
05398 ////////////////////////////////////////////////////////////////////
05399 bool NodePath::
05400 has_fog() const {
05401   nassertr_always(!is_empty(), false);
05402   const RenderAttrib *attrib =
05403     node()->get_attrib(FogAttrib::get_class_slot());
05404   if (attrib != (const RenderAttrib *)NULL) {
05405     const FogAttrib *fa = DCAST(FogAttrib, attrib);
05406     return !fa->is_off();
05407   }
05408 
05409   return false;
05410 }
05411 
05412 ////////////////////////////////////////////////////////////////////
05413 //     Function: NodePath::has_fog_off
05414 //       Access: Published
05415 //  Description: Returns true if a fog has been specifically
05416 //               disabled on this particular node via
05417 //               set_fog_off(), false otherwise.  This is not the
05418 //               same thing as asking whether the geometry at this
05419 //               node will be rendered unfogged, as there may be a
05420 //               fog in effect from a higher or lower level.
05421 ////////////////////////////////////////////////////////////////////
05422 bool NodePath::
05423 has_fog_off() const {
05424   nassertr_always(!is_empty(), false);
05425   const RenderAttrib *attrib =
05426     node()->get_attrib(FogAttrib::get_class_slot());
05427   if (attrib != (const RenderAttrib *)NULL) {
05428     const FogAttrib *fa = DCAST(FogAttrib, attrib);
05429     return fa->is_off();
05430   }
05431 
05432   return false;
05433 }
05434 
05435 ////////////////////////////////////////////////////////////////////
05436 //     Function: NodePath::get_fog
05437 //       Access: Published
05438 //  Description: Returns the fog that has been set on this
05439 //               particular node, or NULL if no fog has been set.
05440 //               This is not necessarily the fog that will be
05441 //               applied to the geometry at or below this level, as
05442 //               another fog at a higher or lower level may
05443 //               override.
05444 ////////////////////////////////////////////////////////////////////
05445 Fog *NodePath::
05446 get_fog() const {
05447   nassertr_always(!is_empty(), NULL);
05448   const RenderAttrib *attrib =
05449     node()->get_attrib(FogAttrib::get_class_slot());
05450   if (attrib != (const RenderAttrib *)NULL) {
05451     const FogAttrib *fa = DCAST(FogAttrib, attrib);
05452     return fa->get_fog();
05453   }
05454 
05455   return NULL;
05456 }
05457 
05458 ////////////////////////////////////////////////////////////////////
05459 //     Function: NodePath::set_render_mode_wireframe
05460 //       Access: Published
05461 //  Description: Sets up the geometry at this level and below (unless
05462 //               overridden) to render in wireframe mode.
05463 ////////////////////////////////////////////////////////////////////
05464 void NodePath::
05465 set_render_mode_wireframe(int priority) {
05466   nassertv_always(!is_empty());
05467   PN_stdfloat thickness = get_render_mode_thickness();
05468   bool perspective = get_render_mode_perspective();
05469   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, thickness, perspective), priority);
05470 }
05471 
05472 ////////////////////////////////////////////////////////////////////
05473 //     Function: NodePath::set_render_mode_filled
05474 //       Access: Published
05475 //  Description: Sets up the geometry at this level and below (unless
05476 //               overridden) to render in filled (i.e. not wireframe)
05477 //               mode.
05478 ////////////////////////////////////////////////////////////////////
05479 void NodePath::
05480 set_render_mode_filled(int priority) {
05481   nassertv_always(!is_empty());
05482   PN_stdfloat thickness = get_render_mode_thickness();
05483   bool perspective = get_render_mode_perspective();
05484   node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority);
05485 }
05486 
05487 ////////////////////////////////////////////////////////////////////
05488 //     Function: NodePath::set_render_mode_perspective
05489 //       Access: Published
05490 //  Description: Sets up the point geometry at this level and below to
05491 //               render as perspective sprites (that is, billboarded
05492 //               quads).  The thickness, as specified with
05493 //               set_render_mode_thickness(), is the width of each
05494 //               point in 3-D units, unless it is overridden on a
05495 //               per-vertex basis.  This does not affect geometry
05496 //               other than points.
05497 //
05498 //               If you want the quads to be individually textured,
05499 //               you should also set a TexGenAttrib::M_point_sprite on
05500 //               the node.
05501 ////////////////////////////////////////////////////////////////////
05502 void NodePath::
05503 set_render_mode_perspective(bool perspective, int priority) {
05504   nassertv_always(!is_empty());
05505   RenderModeAttrib::Mode mode = get_render_mode();
05506   PN_stdfloat thickness = get_render_mode_thickness();
05507   node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
05508 }
05509 
05510 ////////////////////////////////////////////////////////////////////
05511 //     Function: NodePath::set_render_mode_thickness
05512 //       Access: Published
05513 //  Description: Sets up the point geometry at this level and below to
05514 //               render as thick points (that is, billboarded
05515 //               quads).  The thickness is in pixels, unless
05516 //               set_render_mode_perspective is also true, in which
05517 //               case it is in 3-D units.
05518 //
05519 //               If you want the quads to be individually textured,
05520 //               you should also set a TexGenAttrib::M_point_sprite on
05521 //               the node.
05522 ////////////////////////////////////////////////////////////////////
05523 void NodePath::
05524 set_render_mode_thickness(PN_stdfloat thickness, int priority) {
05525   nassertv_always(!is_empty());
05526   RenderModeAttrib::Mode mode = get_render_mode();
05527   bool perspective = get_render_mode_perspective();
05528   node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
05529 }
05530 
05531 ////////////////////////////////////////////////////////////////////
05532 //     Function: NodePath::set_render_mode
05533 //       Access: Published
05534 //  Description: Sets up the geometry at this level and below (unless
05535 //               overridden) to render in the specified mode and with
05536 //               the indicated line and/or point thickness.
05537 ////////////////////////////////////////////////////////////////////
05538 void NodePath::
05539 set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority) {
05540   nassertv_always(!is_empty());
05541 
05542   node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority);
05543 }
05544 
05545 ////////////////////////////////////////////////////////////////////
05546 //     Function: NodePath::clear_render_mode
05547 //       Access: Published
05548 //  Description: Completely removes any render mode adjustment that
05549 //               may have been set on this node via
05550 //               set_render_mode_wireframe() or
05551 //               set_render_mode_filled().
05552 ////////////////////////////////////////////////////////////////////
05553 void NodePath::
05554 clear_render_mode() {
05555   nassertv_always(!is_empty());
05556   node()->clear_attrib(RenderModeAttrib::get_class_slot());
05557 }
05558 
05559 ////////////////////////////////////////////////////////////////////
05560 //     Function: NodePath::has_render_mode
05561 //       Access: Published
05562 //  Description: Returns true if a render mode has been explicitly set
05563 //               on this particular node via set_render_mode() (or
05564 //               set_render_mode_wireframe() or
05565 //               set_render_mode_filled()), false otherwise.
05566 ////////////////////////////////////////////////////////////////////
05567 bool NodePath::
05568 has_render_mode() const {
05569   nassertr_always(!is_empty(), false);
05570   return node()->has_attrib(RenderModeAttrib::get_class_slot());
05571 }
05572 
05573 ////////////////////////////////////////////////////////////////////
05574 //     Function: NodePath::get_render_mode
05575 //       Access: Published
05576 //  Description: Returns the render mode that has been specifically
05577 //               set on this node via set_render_mode(), or
05578 //               M_unchanged if nothing has been set.
05579 ////////////////////////////////////////////////////////////////////
05580 RenderModeAttrib::Mode NodePath::
05581 get_render_mode() const {
05582   nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged);
05583   const RenderAttrib *attrib =
05584     node()->get_attrib(RenderModeAttrib::get_class_slot());
05585   if (attrib != (const RenderAttrib *)NULL) {
05586     const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05587     return ta->get_mode();
05588   }
05589 
05590   return RenderModeAttrib::M_unchanged;
05591 }
05592 
05593 ////////////////////////////////////////////////////////////////////
05594 //     Function: NodePath::get_render_mode_thickness
05595 //       Access: Published
05596 //  Description: Returns the render mode thickness that has been
05597 //               specifically set on this node via set_render_mode(),
05598 //               or 1.0 if nothing has been set.
05599 ////////////////////////////////////////////////////////////////////
05600 PN_stdfloat NodePath::
05601 get_render_mode_thickness() const {
05602   nassertr_always(!is_empty(), 0.0f);
05603   const RenderAttrib *attrib =
05604     node()->get_attrib(RenderModeAttrib::get_class_slot());
05605   if (attrib != (const RenderAttrib *)NULL) {
05606     const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05607     return ta->get_thickness();
05608   }
05609 
05610   return 1.0f;
05611 }
05612 
05613 ////////////////////////////////////////////////////////////////////
05614 //     Function: NodePath::get_render_mode_perspective
05615 //       Access: Published
05616 //  Description: Returns the flag that has been set on this node via
05617 //               set_render_mode_perspective(), or false if no flag
05618 //               has been set.
05619 ////////////////////////////////////////////////////////////////////
05620 bool NodePath::
05621 get_render_mode_perspective() const {
05622   nassertr_always(!is_empty(), 0.0f);
05623   const RenderAttrib *attrib =
05624     node()->get_attrib(RenderModeAttrib::get_class_slot());
05625   if (attrib != (const RenderAttrib *)NULL) {
05626     const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05627     return ta->get_perspective();
05628   }
05629 
05630   return false;
05631 }
05632 
05633 ////////////////////////////////////////////////////////////////////
05634 //     Function: NodePath::set_two_sided
05635 //       Access: Published
05636 //  Description: Specifically sets or disables two-sided rendering
05637 //               mode on this particular node.  If no other nodes
05638 //               override, this will cause backfacing polygons to be
05639 //               drawn (in two-sided mode, true) or culled (in
05640 //               one-sided mode, false).
05641 ////////////////////////////////////////////////////////////////////
05642 void NodePath::
05643 set_two_sided(bool two_sided, int priority) {
05644   nassertv_always(!is_empty());
05645 
05646   CullFaceAttrib::Mode mode =
05647     two_sided ?
05648     CullFaceAttrib::M_cull_none :
05649     CullFaceAttrib::M_cull_clockwise;
05650 
05651   node()->set_attrib(CullFaceAttrib::make(mode), priority);
05652 }
05653 
05654 ////////////////////////////////////////////////////////////////////
05655 //     Function: NodePath::clear_two_sided
05656 //       Access: Published
05657 //  Description: Completely removes any two-sided adjustment that
05658 //               may have been set on this node via set_two_sided().
05659 //               The geometry at this level and below will
05660 //               subsequently be rendered either two-sided or
05661 //               one-sided, according to whatever other nodes may have
05662 //               had set_two_sided() on it, or according to the
05663 //               initial state otherwise.
05664 ////////////////////////////////////////////////////////////////////
05665 void NodePath::
05666 clear_two_sided() {
05667   nassertv_always(!is_empty());
05668   node()->clear_attrib(CullFaceAttrib::get_class_slot());
05669 }
05670 
05671 ////////////////////////////////////////////////////////////////////
05672 //     Function: NodePath::has_two_sided
05673 //       Access: Published
05674 //  Description: Returns true if a two-sided adjustment has been
05675 //               explicitly set on this particular node via
05676 //               set_two_sided().  If this returns true, then
05677 //               get_two_sided() may be called to determine which has
05678 //               been set.
05679 ////////////////////////////////////////////////////////////////////
05680 bool NodePath::
05681 has_two_sided() const {
05682   nassertr_always(!is_empty(), false);
05683   return node()->has_attrib(CullFaceAttrib::get_class_slot());
05684 }
05685 
05686 ////////////////////////////////////////////////////////////////////
05687 //     Function: NodePath::get_two_sided
05688 //       Access: Published
05689 //  Description: Returns true if two-sided rendering has been
05690 //               specifically set on this node via set_two_sided(), or
05691 //               false if one-sided rendering has been specifically
05692 //               set, or if nothing has been specifically set.  See
05693 //               also has_two_sided().  This does not necessarily
05694 //               imply that the geometry will or will not be rendered
05695 //               two-sided, as there may be other nodes that override.
05696 ////////////////////////////////////////////////////////////////////
05697 bool NodePath::
05698 get_two_sided() const {
05699   nassertr_always(!is_empty(), false);
05700   const RenderAttrib *attrib =
05701     node()->get_attrib(CullFaceAttrib::get_class_slot());
05702   if (attrib != (const RenderAttrib *)NULL) {
05703     const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
05704     return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
05705   }
05706 
05707   return false;
05708 }
05709 
05710 ////////////////////////////////////////////////////////////////////
05711 //     Function: NodePath::set_depth_test
05712 //       Access: Published
05713 //  Description: Specifically sets or disables the testing of the
05714 //               depth buffer on this particular node.  This is
05715 //               normally on in the 3-d scene graph and off in the 2-d
05716 //               scene graph; it should be on for rendering most 3-d
05717 //               objects properly.
05718 ////////////////////////////////////////////////////////////////////
05719 void NodePath::
05720 set_depth_test(bool depth_test, int priority) {
05721   nassertv_always(!is_empty());
05722 
05723   DepthTestAttrib::PandaCompareFunc mode =
05724     depth_test ?
05725     DepthTestAttrib::M_less :
05726     DepthTestAttrib::M_none;
05727 
05728   node()->set_attrib(DepthTestAttrib::make(mode), priority);
05729 }
05730 
05731 ////////////////////////////////////////////////////////////////////
05732 //     Function: NodePath::clear_depth_test
05733 //       Access: Published
05734 //  Description: Completely removes any depth-test adjustment that
05735 //               may have been set on this node via set_depth_test().
05736 ////////////////////////////////////////////////////////////////////
05737 void NodePath::
05738 clear_depth_test() {
05739   nassertv_always(!is_empty());
05740   node()->clear_attrib(DepthTestAttrib::get_class_slot());
05741 }
05742 
05743 ////////////////////////////////////////////////////////////////////
05744 //     Function: NodePath::has_depth_test
05745 //       Access: Published
05746 //  Description: Returns true if a depth-test adjustment has been
05747 //               explicitly set on this particular node via
05748 //               set_depth_test().  If this returns true, then
05749 //               get_depth_test() may be called to determine which has
05750 //               been set.
05751 ////////////////////////////////////////////////////////////////////
05752 bool NodePath::
05753 has_depth_test() const {
05754   nassertr_always(!is_empty(), false);
05755   return node()->has_attrib(DepthTestAttrib::get_class_slot());
05756 }
05757 
05758 ////////////////////////////////////////////////////////////////////
05759 //     Function: NodePath::get_depth_test
05760 //       Access: Published
05761 //  Description: Returns true if depth-test rendering has been
05762 //               specifically set on this node via set_depth_test(), or
05763 //               false if depth-test rendering has been specifically
05764 //               disabled.  If nothing has been specifically set,
05765 //               returns true.  See also has_depth_test().
05766 ////////////////////////////////////////////////////////////////////
05767 bool NodePath::
05768 get_depth_test() const {
05769   nassertr_always(!is_empty(), false);
05770   const RenderAttrib *attrib =
05771     node()->get_attrib(DepthTestAttrib::get_class_slot());
05772   if (attrib != (const RenderAttrib *)NULL) {
05773     const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
05774     return (dta->get_mode() != DepthTestAttrib::M_none);
05775   }
05776 
05777   return true;
05778 }
05779 
05780 ////////////////////////////////////////////////////////////////////
05781 //     Function: NodePath::set_depth_write
05782 //       Access: Published
05783 //  Description: Specifically sets or disables the writing to the
05784 //               depth buffer on this particular node.  This is
05785 //               normally on in the 3-d scene graph and off in the 2-d
05786 //               scene graph; it should be on for rendering most 3-d
05787 //               objects properly.
05788 ////////////////////////////////////////////////////////////////////
05789 void NodePath::
05790 set_depth_write(bool depth_write, int priority) {
05791   nassertv_always(!is_empty());
05792 
05793   DepthWriteAttrib::Mode mode =
05794     depth_write ?
05795     DepthWriteAttrib::M_on :
05796     DepthWriteAttrib::M_off;
05797 
05798   node()->set_attrib(DepthWriteAttrib::make(mode), priority);
05799 }
05800 
05801 ////////////////////////////////////////////////////////////////////
05802 //     Function: NodePath::clear_depth_write
05803 //       Access: Published
05804 //  Description: Completely removes any depth-write adjustment that
05805 //               may have been set on this node via set_depth_write().
05806 ////////////////////////////////////////////////////////////////////
05807 void NodePath::
05808 clear_depth_write() {
05809   nassertv_always(!is_empty());
05810   node()->clear_attrib(DepthWriteAttrib::get_class_slot());
05811 }
05812 
05813 ////////////////////////////////////////////////////////////////////
05814 //     Function: NodePath::has_depth_write
05815 //       Access: Published
05816 //  Description: Returns true if a depth-write adjustment has been
05817 //               explicitly set on this particular node via
05818 //               set_depth_write().  If this returns true, then
05819 //               get_depth_write() may be called to determine which has
05820 //               been set.
05821 ////////////////////////////////////////////////////////////////////
05822 bool NodePath::
05823 has_depth_write() const {
05824   nassertr_always(!is_empty(), false);
05825   return node()->has_attrib(DepthWriteAttrib::get_class_slot());
05826 }
05827 
05828 ////////////////////////////////////////////////////////////////////
05829 //     Function: NodePath::get_depth_write
05830 //       Access: Published
05831 //  Description: Returns true if depth-write rendering has been
05832 //               specifically set on this node via set_depth_write(), or
05833 //               false if depth-write rendering has been specifically
05834 //               disabled.  If nothing has been specifically set,
05835 //               returns true.  See also has_depth_write().
05836 ////////////////////////////////////////////////////////////////////
05837 bool NodePath::
05838 get_depth_write() const {
05839   nassertr_always(!is_empty(), false);
05840   const RenderAttrib *attrib =
05841     node()->get_attrib(DepthWriteAttrib::get_class_slot());
05842   if (attrib != (const RenderAttrib *)NULL) {
05843     const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
05844     return (dta->get_mode() != DepthWriteAttrib::M_off);
05845   }
05846 
05847   return true;
05848 }
05849 
05850 ////////////////////////////////////////////////////////////////////
05851 //     Function: NodePath::set_depth_offset
05852 //       Access: Published
05853 //  Description: This instructs the graphics driver to apply an
05854 //               offset or bias to the generated depth values for
05855 //               rendered polygons, before they are written to the
05856 //               depth buffer. This can be used to shift polygons
05857 //               forward slightly, to resolve depth conflicts, or
05858 //               self-shadowing artifacts on thin objects.
05859 //               The bias is always an integer number, and each
05860 //               integer increment represents the smallest possible
05861 //               increment in Z that is sufficient to completely
05862 //               resolve two coplanar polygons. Positive numbers
05863 //               are closer towards the camera.
05864 ////////////////////////////////////////////////////////////////////
05865 void NodePath::
05866 set_depth_offset(int bias, int priority) {
05867   nassertv_always(!is_empty());
05868 
05869   node()->set_attrib(DepthOffsetAttrib::make(bias), priority);
05870 }
05871 
05872 ////////////////////////////////////////////////////////////////////
05873 //     Function: NodePath::clear_depth_offset
05874 //       Access: Published
05875 //  Description: Completely removes any depth-offset adjustment that
05876 //               may have been set on this node via set_depth_offset().
05877 ////////////////////////////////////////////////////////////////////
05878 void NodePath::
05879 clear_depth_offset() {
05880   nassertv_always(!is_empty());
05881   node()->clear_attrib(DepthOffsetAttrib::get_class_slot());
05882 }
05883 
05884 ////////////////////////////////////////////////////////////////////
05885 //     Function: NodePath::has_depth_offset
05886 //       Access: Published
05887 //  Description: Returns true if a depth-offset adjustment has been
05888 //               explicitly set on this particular node via
05889 //               set_depth_offset().  If this returns true, then
05890 //               get_depth_offset() may be called to determine which has
05891 //               been set.
05892 ////////////////////////////////////////////////////////////////////
05893 bool NodePath::
05894 has_depth_offset() const {
05895   nassertr_always(!is_empty(), false);
05896   return node()->has_attrib(DepthOffsetAttrib::get_class_slot());
05897 }
05898 
05899 ////////////////////////////////////////////////////////////////////
05900 //     Function: NodePath::get_depth_offset
05901 //       Access: Published
05902 //  Description: Returns the depth offset value if it has been
05903 //               specified using set_depth_offset, or 0 if not.
05904 ////////////////////////////////////////////////////////////////////
05905 int NodePath::
05906 get_depth_offset() const {
05907   nassertr_always(!is_empty(), 0);
05908   const RenderAttrib *attrib =
05909     node()->get_attrib(DepthOffsetAttrib::get_class_slot());
05910   if (attrib != (const RenderAttrib *)NULL) {
05911     const DepthOffsetAttrib *doa = DCAST(DepthOffsetAttrib, attrib);
05912     return doa->get_offset();
05913   }
05914 
05915   return 0;
05916 }
05917 
05918 ////////////////////////////////////////////////////////////////////
05919 //     Function: NodePath::do_billboard_axis
05920 //       Access: Published
05921 //  Description: Performs a billboard-type rotate to the indicated
05922 //               camera node, one time only, and leaves the object
05923 //               rotated.  This is similar in principle to heads_up().
05924 ////////////////////////////////////////////////////////////////////
05925 void NodePath::
05926 do_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
05927   nassertv_always(!is_empty());
05928 
05929   CPT(TransformState) transform = camera.get_transform(get_parent());
05930   const LMatrix4 &rel_mat = transform->get_mat();
05931 
05932   LVector3 up = LVector3::up();
05933   LVector3 rel_pos = -rel_mat.get_row3(3);
05934 
05935   LQuaternion quat;
05936   ::heads_up(quat, rel_pos, up);
05937   set_quat(quat);
05938 
05939   // Also slide the geometry towards the camera according to the
05940   // offset factor.
05941   if (offset != 0.0f) {
05942     LVector3 translate = rel_mat.get_row3(3);
05943     translate.normalize();
05944     translate *= offset;
05945     set_pos(translate);
05946   }
05947 }
05948 
05949 ////////////////////////////////////////////////////////////////////
05950 //     Function: NodePath::do_billboard_point_eye
05951 //       Access: Published
05952 //  Description: Performs a billboard-type rotate to the indicated
05953 //               camera node, one time only, and leaves the object
05954 //               rotated.  This is similar in principle to look_at(),
05955 //               although the point_eye billboard effect cannot be
05956 //               achieved using the ordinary look_at() call.
05957 ////////////////////////////////////////////////////////////////////
05958 void NodePath::
05959 do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
05960   nassertv_always(!is_empty());
05961 
05962   CPT(TransformState) transform = camera.get_transform(get_parent());
05963   const LMatrix4 &rel_mat = transform->get_mat();
05964 
05965   LVector3 up = LVector3::up() * rel_mat;
05966   LVector3 rel_pos = LVector3::forward() * rel_mat;
05967 
05968   LQuaternion quat;
05969   ::look_at(quat, rel_pos, up);
05970   set_quat(quat);
05971 
05972   // Also slide the geometry towards the camera according to the
05973   // offset factor.
05974   if (offset != 0.0f) {
05975     LVector3 translate = rel_mat.get_row3(3);
05976     translate.normalize();
05977     translate *= offset;
05978     set_pos(translate);
05979   }
05980 }
05981 
05982 ////////////////////////////////////////////////////////////////////
05983 //     Function: NodePath::do_billboard_point_world
05984 //       Access: Published
05985 //  Description: Performs a billboard-type rotate to the indicated
05986 //               camera node, one time only, and leaves the object
05987 //               rotated.  This is similar in principle to look_at().
05988 ////////////////////////////////////////////////////////////////////
05989 void NodePath::
05990 do_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
05991   nassertv_always(!is_empty());
05992 
05993   CPT(TransformState) transform = camera.get_transform(get_parent());
05994   const LMatrix4 &rel_mat = transform->get_mat();
05995 
05996   LVector3 up = LVector3::up();
05997   LVector3 rel_pos = -rel_mat.get_row3(3);
05998 
05999   LQuaternion quat;
06000   ::look_at(quat, rel_pos, up);
06001   set_quat(quat);
06002 
06003   // Also slide the geometry towards the camera according to the
06004   // offset factor.
06005   if (offset != 0.0f) {
06006     LVector3 translate = rel_mat.get_row3(3);
06007     translate.normalize();
06008     translate *= offset;
06009     set_pos(translate);
06010   }
06011 }
06012 
06013 ////////////////////////////////////////////////////////////////////
06014 //     Function: NodePath::set_billboard_axis
06015 //       Access: Published
06016 //  Description: Puts a billboard transition on the node such that it
06017 //               will rotate in two dimensions around the up axis,
06018 //               towards a specified "camera" instead of to the
06019 //               viewing camera.
06020 ////////////////////////////////////////////////////////////////////
06021 void NodePath::
06022 set_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
06023   nassertv_always(!is_empty());
06024   CPT(RenderEffect) billboard = BillboardEffect::make
06025     (LVector3::up(), false, true, 
06026      offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06027   node()->set_effect(billboard);
06028 }
06029 
06030 ////////////////////////////////////////////////////////////////////
06031 //     Function: NodePath::set_billboard_point_eye
06032 //       Access: Published
06033 //  Description: Puts a billboard transition on the node such that it
06034 //               will rotate in three dimensions about the origin,
06035 //               keeping its up vector oriented to the top of the
06036 //               camera, towards a specified "camera" instead of to
06037 //               the viewing camera.
06038 ////////////////////////////////////////////////////////////////////
06039 void NodePath::
06040 set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
06041   nassertv_always(!is_empty());
06042   CPT(RenderEffect) billboard = BillboardEffect::make
06043     (LVector3::up(), true, false,
06044      offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06045   node()->set_effect(billboard);
06046 }
06047 
06048 ////////////////////////////////////////////////////////////////////
06049 //     Function: NodePath::set_billboard_point_world
06050 //       Access: Published
06051 //  Description: Puts a billboard transition on the node such that it
06052 //               will rotate in three dimensions about the origin,
06053 //               keeping its up vector oriented to the sky, towards a
06054 //               specified "camera" instead of to the viewing camera.
06055 ////////////////////////////////////////////////////////////////////
06056 void NodePath::
06057 set_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
06058   nassertv_always(!is_empty());
06059   CPT(RenderEffect) billboard = BillboardEffect::make
06060     (LVector3::up(), false, false,
06061      offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06062   node()->set_effect(billboard);
06063 }
06064 
06065 ////////////////////////////////////////////////////////////////////
06066 //     Function: NodePath::clear_billboard
06067 //       Access: Published
06068 //  Description: Removes any billboard effect from the node.
06069 ////////////////////////////////////////////////////////////////////
06070 void NodePath::
06071 clear_billboard() {
06072   nassertv_always(!is_empty());
06073   node()->clear_effect(BillboardEffect::get_class_type());
06074 }
06075 
06076 ////////////////////////////////////////////////////////////////////
06077 //     Function: NodePath::has_billboard
06078 //       Access: Published
06079 //  Description: Returns true if there is any billboard effect on
06080 //               the node.
06081 ////////////////////////////////////////////////////////////////////
06082 bool NodePath::
06083 has_billboard() const {
06084   nassertr_always(!is_empty(), false);
06085   return node()->has_effect(BillboardEffect::get_class_type());
06086 }
06087 
06088 ////////////////////////////////////////////////////////////////////
06089 //     Function: NodePath::set_compass
06090 //       Access: Published
06091 //  Description: Puts a compass effect on the node, so that it will
06092 //               retain a fixed rotation relative to the reference
06093 //               node (or render if the reference node is empty)
06094 //               regardless of the transforms above it.
06095 ////////////////////////////////////////////////////////////////////
06096 void NodePath::
06097 set_compass(const NodePath &reference) {
06098   nassertv_always(!is_empty());
06099   node()->set_effect(CompassEffect::make(reference));
06100 }
06101 
06102 ////////////////////////////////////////////////////////////////////
06103 //     Function: NodePath::clear_compass
06104 //       Access: Published
06105 //  Description: Removes any compass effect from the node.
06106 ////////////////////////////////////////////////////////////////////
06107 void NodePath::
06108 clear_compass() {
06109   nassertv_always(!is_empty());
06110   node()->clear_effect(CompassEffect::get_class_type());
06111 }
06112 
06113 ////////////////////////////////////////////////////////////////////
06114 //     Function: NodePath::has_compass
06115 //       Access: Published
06116 //  Description: Returns true if there is any compass effect on
06117 //               the node.
06118 ////////////////////////////////////////////////////////////////////
06119 bool NodePath::
06120 has_compass() const {
06121   nassertr_always(!is_empty(), false);
06122   return node()->has_effect(CompassEffect::get_class_type());
06123 }
06124 
06125 ////////////////////////////////////////////////////////////////////
06126 //     Function: NodePath::set_transparency
06127 //       Access: Published
06128 //  Description: Specifically sets or disables transparent rendering
06129 //               mode on this particular node.  If no other nodes
06130 //               override, this will cause items with a non-1 value
06131 //               for alpha color to be rendered partially transparent.
06132 ////////////////////////////////////////////////////////////////////
06133 void NodePath::
06134 set_transparency(TransparencyAttrib::Mode mode, int priority) {
06135   nassertv_always(!is_empty());
06136 
06137   node()->set_attrib(TransparencyAttrib::make(mode), priority);
06138 }
06139 
06140 ////////////////////////////////////////////////////////////////////
06141 //     Function: NodePath::clear_transparency
06142 //       Access: Published
06143 //  Description: Completely removes any transparency adjustment that
06144 //               may have been set on this node via set_transparency().
06145 //               The geometry at this level and below will
06146 //               subsequently be rendered either transparent or not,
06147 //               to whatever other nodes may have had
06148 //               set_transparency() on them.
06149 ////////////////////////////////////////////////////////////////////
06150 void NodePath::
06151 clear_transparency() {
06152   nassertv_always(!is_empty());
06153   node()->clear_attrib(TransparencyAttrib::get_class_slot());
06154 }
06155 
06156 ////////////////////////////////////////////////////////////////////
06157 //     Function: NodePath::has_transparency
06158 //       Access: Published
06159 //  Description: Returns true if a transparent-rendering adjustment
06160 //               has been explicitly set on this particular node via
06161 //               set_transparency().  If this returns true, then
06162 //               get_transparency() may be called to determine whether
06163 //               transparency has been explicitly enabled or
06164 //               explicitly disabled for this node.
06165 ////////////////////////////////////////////////////////////////////
06166 bool NodePath::
06167 has_transparency() const {
06168   nassertr_always(!is_empty(), false);
06169   return node()->has_attrib(TransparencyAttrib::get_class_slot());
06170 }
06171 
06172 ////////////////////////////////////////////////////////////////////
06173 //     Function: NodePath::get_transparency
06174 //       Access: Published
06175 //  Description: Returns the transparent rendering that has been
06176 //               specifically set on this node via set_transparency(), or
06177 //               M_none if nontransparent rendering has been specifically
06178 //               set, or if nothing has been specifically set.  See
06179 //               also has_transparency().  This does not necessarily
06180 //               imply that the geometry will or will not be rendered
06181 //               transparent, as there may be other nodes that override.
06182 ////////////////////////////////////////////////////////////////////
06183 TransparencyAttrib::Mode NodePath::
06184 get_transparency() const {
06185   nassertr_always(!is_empty(), TransparencyAttrib::M_none);
06186   const RenderAttrib *attrib =
06187     node()->get_attrib(TransparencyAttrib::get_class_slot());
06188   if (attrib != (const RenderAttrib *)NULL) {
06189     const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
06190     return ta->get_mode();
06191   }
06192 
06193   return TransparencyAttrib::M_none;
06194 }
06195 
06196 ////////////////////////////////////////////////////////////////////
06197 //     Function: NodePath::set_antialias
06198 //       Access: Published
06199 //  Description: Specifies the antialiasing type that should be
06200 //               applied at this node and below.  See AntialiasAttrib.
06201 ////////////////////////////////////////////////////////////////////
06202 void NodePath::
06203 set_antialias(unsigned short mode, int priority) {
06204   nassertv_always(!is_empty());
06205 
06206   node()->set_attrib(AntialiasAttrib::make(mode), priority);
06207 }
06208 
06209 ////////////////////////////////////////////////////////////////////
06210 //     Function: NodePath::clear_antialias
06211 //       Access: Published
06212 //  Description: Completely removes any antialias setting that
06213 //               may have been set on this node via set_antialias().
06214 ////////////////////////////////////////////////////////////////////
06215 void NodePath::
06216 clear_antialias() {
06217   nassertv_always(!is_empty());
06218   node()->clear_attrib(AntialiasAttrib::get_class_slot());
06219 }
06220 
06221 ////////////////////////////////////////////////////////////////////
06222 //     Function: NodePath::has_antialias
06223 //       Access: Published
06224 //  Description: Returns true if an antialias setting has been
06225 //               explicitly mode on this particular node via
06226 //               set_antialias().  If this returns true, then
06227 //               get_antialias() may be called to determine what the
06228 //               setting was.
06229 ////////////////////////////////////////////////////////////////////
06230 bool NodePath::
06231 has_antialias() const {
06232   nassertr_always(!is_empty(), false);
06233   return node()->has_attrib(AntialiasAttrib::get_class_slot());
06234 }
06235 
06236 ////////////////////////////////////////////////////////////////////
06237 //     Function: NodePath::get_antialias
06238 //       Access: Published
06239 //  Description: Returns the antialias setting that has been
06240 //               specifically set on this node via set_antialias(), or
06241 //               M_none if no setting has been made.
06242 ////////////////////////////////////////////////////////////////////
06243 unsigned short NodePath::
06244 get_antialias() const {
06245   nassertr_always(!is_empty(), AntialiasAttrib::M_none);
06246   const RenderAttrib *attrib =
06247     node()->get_attrib(AntialiasAttrib::get_class_slot());
06248   if (attrib != (const RenderAttrib *)NULL) {
06249     const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib);
06250     return ta->get_mode();
06251   }
06252 
06253   return AntialiasAttrib::M_none;
06254 }
06255 
06256 ////////////////////////////////////////////////////////////////////
06257 //     Function: NodePath::has_audio_volume
06258 //       Access: Published
06259 //  Description: Returns true if an audio volume has been applied
06260 //               to the referenced node, false otherwise.  It is still
06261 //               possible that volume at this node might have been
06262 //               scaled by an ancestor node.
06263 ////////////////////////////////////////////////////////////////////
06264 bool NodePath::
06265 has_audio_volume() const {
06266   nassertr_always(!is_empty(), false);
06267   return node()->has_attrib(AudioVolumeAttrib::get_class_slot());
06268 }
06269 
06270 ////////////////////////////////////////////////////////////////////
06271 //     Function: NodePath::clear_audio_volume
06272 //       Access: Published
06273 //  Description: Completely removes any audio volume from the
06274 //               referenced node.  This is preferable to simply
06275 //               setting the audio volume to identity, as it also
06276 //               removes the overhead associated with having an audio
06277 //               volume at all.
06278 ////////////////////////////////////////////////////////////////////
06279 void NodePath::
06280 clear_audio_volume() {
06281   nassertv_always(!is_empty());
06282   node()->clear_attrib(AudioVolumeAttrib::get_class_slot());
06283 }
06284 
06285 ////////////////////////////////////////////////////////////////////
06286 //     Function: NodePath::set_audio_volume
06287 //       Access: Published
06288 //  Description: Sets the audio volume component of the transform
06289 ////////////////////////////////////////////////////////////////////
06290 void NodePath::
06291 set_audio_volume(PN_stdfloat volume, int priority) {
06292   nassertv_always(!is_empty());
06293 
06294   const RenderAttrib *attrib =
06295     node()->get_attrib(AudioVolumeAttrib::get_class_slot());
06296   if (attrib != (const RenderAttrib *)NULL) {
06297     priority = max(priority,
06298                    node()->get_state()->get_override(AudioVolumeAttrib::get_class_slot()));
06299     CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib);
06300 
06301     // Modify the existing AudioVolumeAttrib to add the indicated
06302     // volume.
06303     node()->set_attrib(ava->set_volume(volume), priority);
06304 
06305   } else {
06306     // Create a new AudioVolumeAttrib for this node.
06307     node()->set_attrib(AudioVolumeAttrib::make(volume), priority);
06308   }
06309 }
06310 
06311 ////////////////////////////////////////////////////////////////////
06312 //     Function: NodePath::set_audio_volume_off
06313 //       Access: Published
06314 //  Description: Disables any audio volume attribute inherited from
06315 //               above.  This is not the same thing as
06316 //               clear_audio_volume(), which undoes any previous
06317 //               set_audio_volume() operation on this node; rather,
06318 //               this actively disables any set_audio_volume() that
06319 //               might be inherited from a parent node.
06320 //
06321 //               It is legal to specify a new volume on the same
06322 //               node with a subsequent call to set_audio_volume();
06323 //               this new scale will apply to lower nodes.
06324 ////////////////////////////////////////////////////////////////////
06325 void NodePath::
06326 set_audio_volume_off(int priority) {
06327   nassertv_always(!is_empty());
06328   node()->set_attrib(AudioVolumeAttrib::make_off(), priority);
06329 }
06330 
06331 ////////////////////////////////////////////////////////////////////
06332 //     Function: NodePath::get_audio_volume
06333 //       Access: Published
06334 //  Description: Returns the complete audio volume that has been
06335 //               applied to this node via a previous call to
06336 //               set_audio_volume(), or 1. (identity) if no volume has
06337 //               been applied to this particular node.
06338 ////////////////////////////////////////////////////////////////////
06339 PN_stdfloat NodePath::
06340 get_audio_volume() const {
06341   const RenderAttrib *attrib =
06342     node()->get_attrib(AudioVolumeAttrib::get_class_slot());
06343   if (attrib != (const RenderAttrib *)NULL) {
06344     const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
06345     return ava->get_volume();
06346   }
06347 
06348   return 1.0f;
06349 }
06350 
06351 ////////////////////////////////////////////////////////////////////
06352 //     Function: NodePath::get_net_audio_volume
06353 //       Access: Published
06354 //  Description: Returns the complete audio volume for this node
06355 //               taking highers nodes in the graph into account.
06356 ////////////////////////////////////////////////////////////////////
06357 PN_stdfloat NodePath::
06358 get_net_audio_volume() const {
06359   CPT(RenderState) net_state = get_net_state();
06360   const RenderAttrib *attrib = net_state->get_attrib(AudioVolumeAttrib::get_class_slot());
06361   if (attrib != (const RenderAttrib *)NULL) {
06362     const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
06363     if (ava != (const AudioVolumeAttrib *)NULL) {
06364       return ava->get_volume();
06365     }
06366   }
06367 
06368   return 1.0f;
06369 }
06370 
06371 ////////////////////////////////////////////////////////////////////
06372 //     Function: NodePath::get_hidden_ancestor
06373 //       Access: Published
06374 //  Description: Returns the NodePath at or above the referenced node
06375 //               that is hidden to the indicated camera(s), or an
06376 //               empty NodePath if no ancestor of the referenced node
06377 //               is hidden (and the node should be visible).
06378 ////////////////////////////////////////////////////////////////////
06379 NodePath NodePath::
06380 get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const {
06381   int pipeline_stage = current_thread->get_pipeline_stage();
06382 
06383   NodePathComponent *comp;
06384   for (comp = _head; 
06385        comp != (NodePathComponent *)NULL; 
06386        comp = comp->get_next(pipeline_stage, current_thread)) {
06387     PandaNode *node = comp->get_node();
06388     if (node->is_overall_hidden() ||
06389         ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
06390       NodePath result;
06391       result._head = comp;
06392       return result;
06393     }
06394   }
06395 
06396   return not_found();
06397 }
06398 
06399 ////////////////////////////////////////////////////////////////////
06400 //     Function: NodePath::stash
06401 //       Access: Published
06402 //  Description: Removes the referenced node (and the entire subgraph
06403 //               below this node) from the scene graph in any normal
06404 //               sense.  The node will no longer be visible and is not
06405 //               tested for collisions; furthermore, no normal scene
06406 //               graph traversal will visit the node.  The node's
06407 //               bounding volume no longer contributes to its parent's
06408 //               bounding volume.
06409 //
06410 //               A stashed node cannot be located by a normal find()
06411 //               operation (although a special find string can still
06412 //               retrieve it).
06413 ////////////////////////////////////////////////////////////////////
06414 void NodePath::
06415 stash(int sort, Thread *current_thread) {
06416   nassertv_always(!is_singleton() && !is_empty());
06417   nassertv(verify_complete());
06418 
06419   int pipeline_stage = current_thread->get_pipeline_stage();
06420   bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
06421                                         _head, sort, true, pipeline_stage,
06422                                         current_thread);
06423   nassertv(reparented);
06424 }
06425 
06426 ////////////////////////////////////////////////////////////////////
06427 //     Function: NodePath::unstash
06428 //       Access: Published
06429 //  Description: Undoes the effect of a previous stash() on this
06430 //               node: makes the referenced node (and the entire
06431 //               subgraph below this node) once again part of the
06432 //               scene graph.
06433 ////////////////////////////////////////////////////////////////////
06434 void NodePath::
06435 unstash(int sort, Thread *current_thread) {
06436   nassertv_always(!is_singleton() && !is_empty());
06437   nassertv(verify_complete());
06438 
06439   int pipeline_stage = current_thread->get_pipeline_stage();
06440   bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
06441                                         _head, sort, false, pipeline_stage,
06442                                         current_thread);
06443   nassertv(reparented);
06444 }
06445 
06446 ////////////////////////////////////////////////////////////////////
06447 //     Function: NodePath::unstash_all
06448 //       Access: Published
06449 //  Description: Unstashes this node and all stashed child nodes.
06450 ////////////////////////////////////////////////////////////////////
06451 void NodePath::
06452 unstash_all(Thread *current_thread) {
06453   NodePathCollection stashed_descendents = find_all_matches("**/@@*");
06454   stashed_descendents.unstash();
06455   unstash(0, current_thread);
06456 }
06457 
06458 ////////////////////////////////////////////////////////////////////
06459 //     Function: NodePath::get_stashed_ancestor
06460 //       Access: Published
06461 //  Description: Returns the NodePath at or above the referenced node
06462 //               that is stashed, or an empty NodePath if no ancestor
06463 //               of the referenced node is stashed (and the node should
06464 //               be visible).
06465 ////////////////////////////////////////////////////////////////////
06466 NodePath NodePath::
06467 get_stashed_ancestor(Thread *current_thread) const {
06468   NodePathComponent *comp = _head;
06469   if (comp != (NodePathComponent *)NULL) {
06470     int pipeline_stage = current_thread->get_pipeline_stage();
06471     NodePathComponent *next = comp->get_next(pipeline_stage, current_thread);
06472 
06473     while (next != (NodePathComponent *)NULL) {
06474       PandaNode *node = comp->get_node();
06475       PandaNode *parent_node = next->get_node();
06476 
06477       if (parent_node->find_stashed(node) >= 0) {
06478         NodePath result;
06479         result._head = comp;
06480         return result;
06481       }
06482 
06483       comp = next;
06484       next = next->get_next(pipeline_stage, current_thread);
06485     }
06486   }
06487 
06488   return not_found();
06489 }
06490 
06491 ////////////////////////////////////////////////////////////////////
06492 //     Function: NodePath::verify_complete
06493 //       Access: Published
06494 //  Description: Returns true if all of the nodes described in the
06495 //               NodePath are connected, or false otherwise.
06496 ////////////////////////////////////////////////////////////////////
06497 bool NodePath::
06498 verify_complete(Thread *current_thread) const {
06499   if (is_empty()) {
06500     return true;
06501   }
06502 
06503 #ifdef HAVE_THREADS
06504   if (Thread::is_true_threads()) {
06505     // In a threaded environment, we can't reliably test this, since a
06506     // sub-thread may be mucking with the NodePath's ancestry as we
06507     // try to validate it.  NodePaths are inherently not thread-safe,
06508     // but generally that's not an issue.
06509     return true;
06510   }
06511 #endif  // HAVE_THREADS
06512 
06513   PStatTimer timer(_verify_complete_pcollector);
06514 
06515   const NodePathComponent *comp = _head;
06516   nassertr(comp != (const NodePathComponent *)NULL, false);
06517 
06518   int pipeline_stage = current_thread->get_pipeline_stage();
06519 
06520   PandaNode *node = comp->get_node();
06521   nassertr(node != (const PandaNode *)NULL, false);
06522   int length = comp->get_length(pipeline_stage, current_thread);
06523   
06524   comp = comp->get_next(pipeline_stage, current_thread);
06525   length--;
06526   while (comp != (const NodePathComponent *)NULL) {
06527     PandaNode *next_node = comp->get_node();
06528     nassertr(next_node != (const PandaNode *)NULL, false);
06529 
06530     if (node->find_parent(next_node) < 0) {
06531       pgraph_cat.warning()
06532         << *this << " is incomplete; " << *node << " is not a child of "
06533         << *next_node << "\n";
06534       return false;
06535     }
06536 
06537     if (comp->get_length(pipeline_stage, current_thread) != length) {
06538       pgraph_cat.warning()
06539         << *this << " is incomplete; length at " << *next_node
06540         << " indicates " << comp->get_length(pipeline_stage, current_thread)
06541         << " while length at " << *node << " indicates " << length << "\n";
06542       return false;
06543     }
06544 
06545     node = next_node;
06546     comp = comp->get_next(pipeline_stage, current_thread);
06547     length--;
06548   }
06549 
06550   return true;
06551 }
06552 
06553 ////////////////////////////////////////////////////////////////////
06554 //     Function: NodePath::premunge_scene
06555 //       Access: Published
06556 //  Description: Walks through the scene graph beginning at the bottom
06557 //               node, and internally adjusts any GeomVertexFormats
06558 //               for optimal rendering on the indicated GSG.  If this
06559 //               step is not done prior to rendering, the formats will
06560 //               be optimized at render time instead, for a small
06561 //               cost.
06562 //
06563 //               It is not normally necessary to do this on a model
06564 //               loaded directly from disk, since the loader will do
06565 //               this by default.
06566 ////////////////////////////////////////////////////////////////////
06567 void NodePath::
06568 premunge_scene(GraphicsStateGuardianBase *gsg) {
06569   nassertv_always(!is_empty());
06570 
06571   CPT(RenderState) state = RenderState::make_empty();
06572   if (has_parent()) {
06573     state = get_parent().get_net_state();
06574   }
06575 
06576   SceneGraphReducer gr(gsg);
06577   gr.premunge(node(), state);
06578 }
06579 
06580 ////////////////////////////////////////////////////////////////////
06581 //     Function: NodePath::prepare_scene
06582 //       Access: Published
06583 //  Description: Walks through the scene graph beginning at the bottom
06584 //               node, and does whatever initialization is required to
06585 //               render the scene properly with the indicated GSG.  It
06586 //               is not strictly necessary to call this, since the GSG
06587 //               will initialize itself when the scene is rendered,
06588 //               but this may take some of the overhead away from that
06589 //               process.
06590 //
06591 //               In particular, this will ensure that textures and
06592 //               vertex buffers within the scene are loaded into
06593 //               graphics memory.
06594 ////////////////////////////////////////////////////////////////////
06595 void NodePath::
06596 prepare_scene(GraphicsStateGuardianBase *gsg) {
06597   nassertv_always(!is_empty());
06598 
06599   node()->prepare_scene(gsg, get_net_state());
06600 }
06601 
06602 ////////////////////////////////////////////////////////////////////
06603 //     Function: NodePath::show_bounds
06604 //       Access: Published
06605 //  Description: Causes the bounding volume of the bottom node and all
06606 //               of its descendants (that is, the bounding volume
06607 //               associated with the the bottom arc) to be rendered,
06608 //               if possible.  The rendering method is less than
06609 //               optimal; this is intended primarily for debugging.
06610 ////////////////////////////////////////////////////////////////////
06611 void NodePath::
06612 show_bounds() {
06613   nassertv_always(!is_empty());
06614   node()->set_effect(ShowBoundsEffect::make(false));
06615 }
06616 
06617 ////////////////////////////////////////////////////////////////////
06618 //     Function: NodePath::show_tight_bounds
06619 //       Access: Published
06620 //  Description: Similar to show_bounds(), this draws a bounding box
06621 //               representing the "tight" bounds of this node and all
06622 //               of its descendants.  The bounding box is recomputed
06623 //               every frame by reexamining all of the vertices; this
06624 //               is far from efficient, but this is intended for
06625 //               debugging.
06626 ////////////////////////////////////////////////////////////////////
06627 void NodePath::
06628 show_tight_bounds() {
06629   nassertv_always(!is_empty());
06630   node()->set_effect(ShowBoundsEffect::make(true));
06631 }
06632 
06633 ////////////////////////////////////////////////////////////////////
06634 //     Function: NodePath::hide_bounds
06635 //       Access: Published
06636 //  Description: Stops the rendering of the bounding volume begun with
06637 //               show_bounds().
06638 ////////////////////////////////////////////////////////////////////
06639 void NodePath::
06640 hide_bounds() {
06641   nassertv_always(!is_empty());
06642   node()->clear_effect(ShowBoundsEffect::get_class_type());
06643 }
06644 
06645 ////////////////////////////////////////////////////////////////////
06646 //     Function: NodePath::get_bounds
06647 //       Access: Published
06648 //  Description: Returns a newly-allocated bounding volume containing
06649 //               the bottom node and all of its descendants.  This is
06650 //               the bounding volume on the bottom arc, converted to
06651 //               the local coordinate space of the node.
06652 ////////////////////////////////////////////////////////////////////
06653 PT(BoundingVolume) NodePath::
06654 get_bounds(Thread *current_thread) const {
06655   nassertr_always(!is_empty(), new BoundingSphere);
06656   return node()->get_bounds(current_thread)->make_copy();
06657 }
06658 
06659 ////////////////////////////////////////////////////////////////////
06660 //     Function: NodePath::force_recompute_bounds
06661 //       Access: Published
06662 //  Description: Forces the recomputing of all the bounding volumes at
06663 //               every node in the subgraph beginning at this node and
06664 //               below.
06665 //
06666 //               This should not normally need to be called, since the
06667 //               bounding volumes are supposed to be recomputed
06668 //               automatically when necessary.  It may be useful when
06669 //               debugging, to verify that the bounding volumes have
06670 //               not become inadvertently stale; it may also be useful
06671 //               to force animated characters to update their bounding
06672 //               volumes (which does not presently happen
06673 //               automatically).
06674 ////////////////////////////////////////////////////////////////////
06675 void NodePath::
06676 force_recompute_bounds() {
06677   nassertv_always(!is_empty());
06678   r_force_recompute_bounds(node());
06679 }
06680 
06681 ////////////////////////////////////////////////////////////////////
06682 //     Function: NodePath::write_bounds
06683 //       Access: Published
06684 //  Description: Writes a description of the bounding volume
06685 //               containing the bottom node and all of its descendants
06686 //               to the indicated output stream.
06687 ////////////////////////////////////////////////////////////////////
06688 void NodePath::
06689 write_bounds(ostream &out) const {
06690   get_bounds()->write(out);
06691 }
06692 
06693 ////////////////////////////////////////////////////////////////////
06694 //     Function: NodePath::calc_tight_bounds
06695 //       Access: Published
06696 //  Description: Calculates the minimum and maximum vertices of all
06697 //               Geoms at this NodePath's bottom node and below.  This
06698 //               is a tight bounding box; it will generally be tighter
06699 //               than the bounding volume returned by get_bounds()
06700 //               (but it is more expensive to compute).
06701 //
06702 //               The return value is true if any points are within the
06703 //               bounding volume, or false if none are.
06704 ////////////////////////////////////////////////////////////////////
06705 bool NodePath::
06706 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
06707                   Thread *current_thread) const {
06708   min_point.set(0.0f, 0.0f, 0.0f);
06709   max_point.set(0.0f, 0.0f, 0.0f);
06710   nassertr_always(!is_empty(), false);
06711 
06712   bool found_any = false;
06713   node()->calc_tight_bounds(min_point, max_point, found_any, 
06714                             TransformState::make_identity(),
06715                             current_thread);
06716 
06717   return found_any;
06718 }
06719 
06720 /*
06721 
06722 NB: Had to remove this function to avoid circular dependency when
06723 moving SceneGraphAnalyzer into pgraphnodes, attempting to reduce size
06724 of pgraph.  This function is now defined as a Python extension
06725 function instead.
06726 
06727 ////////////////////////////////////////////////////////////////////
06728 //     Function: NodePath::analyze
06729 //       Access: Published
06730 //  Description: Analyzes the geometry below this node and reports the
06731 //               number of vertices, triangles, etc.  This is the same
06732 //               information reported by the bam-info program.
06733 ////////////////////////////////////////////////////////////////////
06734 void NodePath::
06735 analyze() const {
06736   nassertv_always(!is_empty());
06737   SceneGraphAnalyzer sga;
06738   sga.add_node(node());
06739 
06740   if (sga.get_num_lod_nodes() == 0) {
06741     sga.write(nout);
06742 
06743   } else {
06744     nout << "At highest LOD:\n";
06745     SceneGraphAnalyzer sga2;
06746     sga2.set_lod_mode(SceneGraphAnalyzer::LM_highest);
06747     sga2.add_node(node());
06748     sga2.write(nout);
06749 
06750     nout << "\nAt lowest LOD:\n";
06751     sga2.clear();
06752     sga2.set_lod_mode(SceneGraphAnalyzer::LM_lowest);
06753     sga2.add_node(node());
06754     sga2.write(nout);
06755 
06756     nout << "\nAll nodes:\n";
06757     sga.write(nout);
06758   }
06759 }
06760 */
06761 
06762 ////////////////////////////////////////////////////////////////////
06763 //     Function: NodePath::flatten_light
06764 //       Access: Published
06765 //  Description: Lightly flattens out the hierarchy below this node by
06766 //               applying transforms, colors, and texture matrices
06767 //               from the nodes onto the vertices, but does not remove
06768 //               any nodes.
06769 //
06770 //               This can result in improved rendering performance
06771 //               because there will be fewer transforms in the
06772 //               resulting scene graph, but the number of nodes will
06773 //               remain the same.
06774 //
06775 //               In particular, any NodePaths that reference nodes
06776 //               within this hierarchy will not be damaged.  However,
06777 //               since this operation will remove transforms from the
06778 //               scene graph, it may be dangerous to apply to nodes
06779 //               where you expect to dynamically modify the transform,
06780 //               or where you expect the geometry to remain in a
06781 //               particular local coordinate system.
06782 //
06783 //               The return value is always 0, since flatten_light
06784 //               does not remove any nodes.
06785 ////////////////////////////////////////////////////////////////////
06786 int NodePath::
06787 flatten_light() {
06788   nassertr_always(!is_empty(), 0);
06789   SceneGraphReducer gr;
06790   gr.apply_attribs(node());
06791 
06792   return 0;
06793 }
06794 
06795 ////////////////////////////////////////////////////////////////////
06796 //     Function: NodePath::flatten_medium
06797 //       Access: Published
06798 //  Description: A more thorough flattening than flatten_light(), this
06799 //               first applies all the transforms, colors, and texture
06800 //               matrices from the nodes onto the vertices, and then
06801 //               removes unneeded grouping nodes--nodes that have
06802 //               exactly one child, for instance, but have no special
06803 //               properties in themselves.
06804 //
06805 //               This results in improved performance over
06806 //               flatten_light() because the number of nodes in the
06807 //               scene graph is reduced.
06808 //
06809 //               The return value is the number of nodes removed.
06810 ////////////////////////////////////////////////////////////////////
06811 int NodePath::
06812 flatten_medium() {
06813   nassertr_always(!is_empty(), 0);
06814   SceneGraphReducer gr;
06815   gr.apply_attribs(node());
06816   int num_removed = gr.flatten(node(), 0);
06817 
06818   if (flatten_geoms) {
06819     gr.make_compatible_state(node());
06820     gr.collect_vertex_data(node());
06821     gr.unify(node(), true);
06822   }
06823 
06824   return num_removed;
06825 }
06826 
06827 ////////////////////////////////////////////////////////////////////
06828 //     Function: NodePath::flatten_strong
06829 //       Access: Published
06830 //  Description: The strongest possible flattening.  This first
06831 //               applies all of the transforms to the vertices, as in
06832 //               flatten_medium(), but then it will combine sibling
06833 //               nodes together when possible, in addition to removing
06834 //               unnecessary parent-child nodes.  This can result in
06835 //               substantially fewer nodes, but any nicely-grouped
06836 //               hierachical bounding volumes may be lost.
06837 //
06838 //               It is generally a good idea to apply this kind of
06839 //               flattening only to nodes that will be culled largely
06840 //               as a single unit, like a car.  Applying this to an
06841 //               entire scene may result in overall poorer performance
06842 //               because of less-effective culling.
06843 ////////////////////////////////////////////////////////////////////
06844 int NodePath::
06845 flatten_strong() {
06846   nassertr_always(!is_empty(), 0);
06847   SceneGraphReducer gr;
06848   gr.apply_attribs(node());
06849   int num_removed = gr.flatten(node(), ~0);
06850 
06851   if (flatten_geoms) {
06852     gr.make_compatible_state(node());
06853     gr.collect_vertex_data(node(), ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type));
06854     gr.unify(node(), false);
06855   }
06856 
06857   return num_removed;
06858 }
06859 
06860 ////////////////////////////////////////////////////////////////////
06861 //     Function: NodePath::apply_texture_colors
06862 //       Access: Published
06863 //  Description: Removes textures from Geoms at this node and below by
06864 //               applying the texture colors to the vertices.  This is
06865 //               primarily useful to simplify a low-LOD model.  The
06866 //               texture colors are replaced by flat colors that
06867 //               approximate the original textures.
06868 //
06869 //               Only the bottommost texture on each Geom is used (if
06870 //               there is more than one), and it is applied as if it
06871 //               were M_modulate, and WM_repeat, regardless of its
06872 //               actual settings.  If the texture has a
06873 //               simple_ram_image, this may be used if the main image
06874 //               isn't resident.
06875 //
06876 //               After this call, there will be no texturing specified
06877 //               at this level and below.  Of course, there might
06878 //               still be texturing inherited from above.
06879 ////////////////////////////////////////////////////////////////////
06880 void NodePath::
06881 apply_texture_colors() {
06882   nassertv_always(!is_empty());
06883   SceneGraphReducer gr;
06884   gr.apply_attribs(node(), SceneGraphReducer::TT_apply_texture_color | SceneGraphReducer::TT_tex_matrix | SceneGraphReducer::TT_other);
06885 }
06886 
06887 ////////////////////////////////////////////////////////////////////
06888 //     Function: NodePath::find_net_tag
06889 //       Access: Published
06890 //  Description: Returns the lowest ancestor of this node that
06891 //               contains a tag definition with the indicated key, if
06892 //               any, or an empty NodePath if no ancestor of this node
06893 //               contains this tag definition.  See set_tag().
06894 ////////////////////////////////////////////////////////////////////
06895 NodePath NodePath::
06896 find_net_tag(const string &key) const {
06897   if (is_empty()) {
06898     return NodePath::not_found();
06899   }
06900   if (has_tag(key)) {
06901     return *this;
06902   }
06903   return get_parent().find_net_tag(key);
06904 }
06905 
06906 #ifdef HAVE_PYTHON 
06907 ////////////////////////////////////////////////////////////////////
06908 //     Function: NodePath::find_net_python_tag
06909 //       Access: Published
06910 //  Description: Returns the lowest ancestor of this node that
06911 //               contains a tag definition with the indicated key, if
06912 //               any, or an empty NodePath if no ancestor of this node
06913 //               contains this tag definition.  See set_python_tag().
06914 ////////////////////////////////////////////////////////////////////
06915 NodePath NodePath::
06916 find_net_python_tag(const string &key) const {
06917   if (is_empty()) {
06918     return NodePath::not_found();
06919   }
06920   if (has_python_tag(key)) {
06921     return *this;
06922   }
06923   return get_parent().find_net_python_tag(key);
06924 }
06925 #endif  // HAVE_PYTHON
06926 
06927 ////////////////////////////////////////////////////////////////////
06928 //     Function: NodePath::write_bam_file
06929 //       Access: Published
06930 //  Description: Writes the contents of this node and below out to a
06931 //               bam file with the indicated filename.  This file may
06932 //               then be read in again, as is, at some later point.
06933 //               Returns true if successful, false on some kind of
06934 //               error.
06935 ////////////////////////////////////////////////////////////////////
06936 bool NodePath::
06937 write_bam_file(const Filename &filename) const {
06938   nassertr_always(!is_empty(), false);
06939 
06940   BamFile bam_file;
06941 
06942   bool okflag = false;
06943 
06944   if (bam_file.open_write(filename)) {
06945     if (bam_file.write_object(node())) {
06946       okflag = true;
06947     }
06948     bam_file.close();
06949   }
06950   return okflag;
06951 }
06952 
06953 ////////////////////////////////////////////////////////////////////
06954 //     Function: NodePath::write_bam_stream
06955 //       Access: Published
06956 //  Description: Writes the contents of this node and below out to the
06957 //               indicated stream.
06958 ////////////////////////////////////////////////////////////////////
06959 bool NodePath::
06960 write_bam_stream(ostream &out) const {
06961   nassertr_always(!is_empty(), false);
06962 
06963   BamFile bam_file;
06964 
06965   bool okflag = false;
06966 
06967   if (bam_file.open_write(out)) {
06968     if (bam_file.write_object(node())) {
06969       okflag = true;
06970     }
06971     bam_file.close();
06972   }
06973   return okflag;
06974 }
06975 
06976 ////////////////////////////////////////////////////////////////////
06977 //     Function: NodePath::encode_to_bam_stream
06978 //       Access: Published
06979 //  Description: Converts the NodePath object into a single
06980 //               stream of data using a BamWriter, and stores that
06981 //               data in the indicated string.  Returns true on
06982 //               success, false on failure.
06983 //
06984 //               If the BamWriter is NULL, this behaves the same way
06985 //               as NodePath::write_bam_stream() and
06986 //               PandaNode::encode_to_bam_stream(), in the sense that
06987 //               it only writes this node and all nodes below it.
06988 //
06989 //               However, if the BamWriter is not NULL, it behaves
06990 //               very differently.  In this case, it encodes the
06991 //               *entire graph* of all nodes connected to the
06992 //               NodePath, including all parent nodes and siblings.
06993 //               This is necessary for correct streaming of related
06994 //               NodePaths and restoration of instances, etc., but it
06995 //               does mean you must detach() a node before writing it
06996 //               if you want to limit the nodes that get written.
06997 //
06998 //               This method is used by __reduce__ to handle streaming
06999 //               of NodePaths to a pickle file.  The BamWriter case is
07000 //               used by the direct.stdpy.pickle module, while the
07001 //               saner, non-BamWriter case is used when the standard
07002 //               pickle module calls this function.
07003 ////////////////////////////////////////////////////////////////////
07004 bool NodePath::
07005 encode_to_bam_stream(string &data, BamWriter *writer) const {
07006   data.clear();
07007   ostringstream stream;
07008 
07009   DatagramOutputFile dout;
07010   if (!dout.open(stream)) {
07011     return false;
07012   }
07013   
07014   BamWriter local_writer;
07015   bool used_local_writer = false;
07016   if (writer == NULL) {
07017     // Create our own writer.
07018     
07019     if (!dout.write_header(_bam_header)) {
07020       return false;
07021     }
07022     writer = &local_writer;
07023     used_local_writer = true;
07024   }
07025   
07026   writer->set_target(&dout);
07027 
07028   int num_nodes = get_num_nodes();
07029   if (used_local_writer && num_nodes > 1) {
07030     // In this case--no BamWriter--we only write the bottom node.
07031     num_nodes = 1;
07032   }
07033 
07034   // Write an initial Datagram to represent the error type and
07035   // number of nodes.
07036   Datagram dg;
07037   dg.add_uint8(_error_type);
07038   dg.add_int32(num_nodes);
07039   
07040   if (!dout.put_datagram(dg)) {
07041     writer->set_target(NULL);
07042     return false;
07043   }
07044 
07045   // Now write the nodes, one at a time.
07046   for (int i = 0; i < num_nodes; ++i) {
07047     PandaNode *node = get_node(num_nodes - i - 1);
07048     nassertr(node != NULL, false);
07049     if (!writer->write_object(node)) {
07050       writer->set_target(NULL);
07051       return false;
07052     }
07053   }
07054   writer->set_target(NULL);
07055   
07056   data = stream.str();
07057   return true;
07058 }
07059 
07060 ////////////////////////////////////////////////////////////////////
07061 //     Function: NodePath::decode_from_bam_stream
07062 //       Access: Published, Static
07063 //  Description: Reads the string created by a previous call to
07064 //               encode_to_bam_stream(), and extracts and
07065 //               returns the NodePath on that string.  Returns NULL on
07066 //               error.
07067 ////////////////////////////////////////////////////////////////////
07068 NodePath NodePath::
07069 decode_from_bam_stream(const string &data, BamReader *reader) {
07070   NodePath result;
07071 
07072   istringstream stream(data);
07073 
07074   DatagramInputFile din;
07075   if (!din.open(stream)) {
07076     return NodePath::fail();
07077   }
07078 
07079   BamReader local_reader;
07080   if (reader == NULL) {
07081     // Create a local reader.
07082 
07083     string head;
07084     if (!din.read_header(head, _bam_header.size())) {
07085       return NodePath::fail();
07086     }
07087     
07088     if (head != _bam_header) {
07089       return NodePath::fail();
07090     }
07091 
07092     reader = &local_reader;
07093   }
07094   
07095   reader->set_source(&din);
07096 
07097   // One initial datagram to encode the error type, and the number of nodes.
07098   Datagram dg;
07099   if (!din.get_datagram(dg)) {
07100     return NodePath::fail();
07101   }
07102 
07103   DatagramIterator dgi(dg);
07104   ErrorType error_type = (ErrorType)dgi.get_uint8();
07105   int num_nodes = dgi.get_int32();
07106   if (num_nodes == 0) {
07107     // An empty NodePath.
07108     result._error_type = error_type;
07109 
07110   } else {
07111     // A real NodePath.  Ignore error_type.
07112     for (int i = 0; i < num_nodes; ++i) {
07113       TypedWritable *object = reader->read_object();
07114 
07115       if (object == (TypedWritable *)NULL ||
07116           !object->is_of_type(PandaNode::get_class_type())) {
07117         reader->set_source(NULL);
07118         return NodePath::fail();
07119       }
07120   
07121       if (!reader->resolve()) {
07122         reader->set_source(NULL);
07123         return NodePath::fail();
07124       }
07125 
07126       PandaNode *node = DCAST(PandaNode, object);
07127       result = NodePath(result, node);
07128     }
07129   }
07130   
07131   reader->set_source(NULL);
07132 
07133   return result;
07134 }
07135 
07136 ////////////////////////////////////////////////////////////////////
07137 //     Function: NodePath::find_common_ancestor
07138 //       Access: Private, Static
07139 //  Description: Walks up from both NodePaths to find the first node
07140 //               that both have in common, if any.  Fills a_count and
07141 //               b_count with the number of nodes below the common
07142 //               node in each path.
07143 //
07144 //               The return value is the NodePathComponent of the node
07145 //               they have in common, or NULL if they have nothing in
07146 //               common.
07147 ////////////////////////////////////////////////////////////////////
07148 NodePathComponent *NodePath::
07149 find_common_ancestor(const NodePath &a, const NodePath &b,
07150                      int &a_count, int &b_count, Thread *current_thread) {
07151   nassertr(!a.is_empty() && !b.is_empty(), NULL);
07152   NodePathComponent *ac = a._head;
07153   NodePathComponent *bc = b._head;
07154   a_count = 0;
07155   b_count = 0;
07156 
07157   int pipeline_stage = current_thread->get_pipeline_stage();
07158 
07159   // Shorten up the longer one until they are the same length.
07160   while (ac->get_length(pipeline_stage, current_thread) > bc->get_length(pipeline_stage, current_thread)) {
07161     nassertr(ac != (NodePathComponent *)NULL, NULL);
07162     ac = ac->get_next(pipeline_stage, current_thread);
07163     a_count++;
07164   }
07165   while (bc->get_length(pipeline_stage, current_thread) > ac->get_length(pipeline_stage, current_thread)) {
07166     nassertr(bc != (NodePathComponent *)NULL, NULL);
07167     bc = bc->get_next(pipeline_stage, current_thread);
07168     b_count++;
07169   }
07170 
07171   // Now shorten them both up until we reach the same component.
07172   while (ac != bc) {
07173     // These shouldn't go to NULL unless they both go there together. 
07174     nassertr(ac != (NodePathComponent *)NULL, NULL);
07175     nassertr(bc != (NodePathComponent *)NULL, NULL);
07176     ac = ac->get_next(pipeline_stage, current_thread);
07177     a_count++;
07178     bc = bc->get_next(pipeline_stage, current_thread);
07179     b_count++;
07180   }
07181 
07182   return ac;
07183 }
07184 
07185 ////////////////////////////////////////////////////////////////////
07186 //     Function: NodePath::r_get_net_state
07187 //       Access: Private
07188 //  Description: Recursively determines the net state changes to the
07189 //               indicated component node from the root of the graph.
07190 ////////////////////////////////////////////////////////////////////
07191 CPT(RenderState) NodePath::
07192 r_get_net_state(NodePathComponent *comp, Thread *current_thread) const {
07193   if (comp == (NodePathComponent *)NULL) {
07194     return RenderState::make_empty();
07195   } else {
07196     CPT(RenderState) state = comp->get_node()->get_state(current_thread);
07197     int pipeline_stage = current_thread->get_pipeline_stage();
07198     return r_get_net_state(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(state);
07199   }
07200 }
07201 
07202 ////////////////////////////////////////////////////////////////////
07203 //     Function: NodePath::r_get_partial_state
07204 //       Access: Private
07205 //  Description: Recursively determines the net state changes to the
07206 //               indicated component node from the nth node above it.
07207 //               If n exceeds the length of the path, this returns the
07208 //               net transform from the root of the graph.
07209 ////////////////////////////////////////////////////////////////////
07210 CPT(RenderState) NodePath::
07211 r_get_partial_state(NodePathComponent *comp, int n, 
07212                     Thread *current_thread) const {
07213   if (n == 0 || comp == (NodePathComponent *)NULL) {
07214     return RenderState::make_empty();
07215   } else {
07216     CPT(RenderState) state = comp->get_node()->get_state(current_thread);
07217     int pipeline_stage = current_thread->get_pipeline_stage();
07218     return r_get_partial_state(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(state);
07219   }
07220 }
07221 
07222 ////////////////////////////////////////////////////////////////////
07223 //     Function: NodePath::r_get_net_transform
07224 //       Access: Private
07225 //  Description: Recursively determines the net transform to the
07226 //               indicated component node from the root of the graph.
07227 ////////////////////////////////////////////////////////////////////
07228 CPT(TransformState) NodePath::
07229 r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const {
07230   if (comp == (NodePathComponent *)NULL) {
07231     return TransformState::make_identity();
07232   } else {
07233     int pipeline_stage = current_thread->get_pipeline_stage();
07234     CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread);
07235     PandaNode *node = comp->get_node();
07236     CPT(TransformState) transform = node->get_transform(current_thread);
07237 
07238     CPT(RenderEffects) effects = node->get_effects(current_thread);
07239     if (effects->has_adjust_transform()) {
07240       effects->adjust_transform(net_transform, transform, node);
07241     }
07242       
07243     return net_transform->compose(transform);
07244   }
07245 }
07246 
07247 ////////////////////////////////////////////////////////////////////
07248 //     Function: NodePath::r_get_partial_transform
07249 //       Access: Private
07250 //  Description: Recursively determines the net transform to the
07251 //               indicated component node from the nth node above it.
07252 //               If n exceeds the length of the path, this returns the
07253 //               net transform from the root of the graph.
07254 //
07255 //               If any node in the path had a net_transform effect
07256 //               applied, returns NULL--in this case the partial
07257 //               transform cannot be easily determined.
07258 ////////////////////////////////////////////////////////////////////
07259 CPT(TransformState) NodePath::
07260 r_get_partial_transform(NodePathComponent *comp, int n, 
07261                         Thread *current_thread) const {
07262   if (n == 0 || comp == (NodePathComponent *)NULL) {
07263     return TransformState::make_identity();
07264   } else {
07265     if (comp->get_node()->get_effects(current_thread)->has_adjust_transform()) {
07266       return NULL;
07267     }
07268     CPT(TransformState) transform = comp->get_node()->get_transform(current_thread);
07269     int pipeline_stage = current_thread->get_pipeline_stage();
07270     CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread);
07271     if (partial == (const TransformState *)NULL) {
07272       return NULL;
07273     }
07274     return partial->compose(transform);
07275   }
07276 }
07277 
07278 ////////////////////////////////////////////////////////////////////
07279 //     Function: NodePath::r_get_net_prev_transform
07280 //       Access: Private
07281 //  Description: Recursively determines the net "previous" transform
07282 //               to the indicated component node from the root of the
07283 //               graph.
07284 ////////////////////////////////////////////////////////////////////
07285 CPT(TransformState) NodePath::
07286 r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const {
07287   if (comp == (NodePathComponent *)NULL) {
07288     return TransformState::make_identity();
07289   } else {
07290     CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
07291     int pipeline_stage = current_thread->get_pipeline_stage();
07292     return r_get_net_prev_transform(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(transform);
07293   }
07294 }
07295 
07296 ////////////////////////////////////////////////////////////////////
07297 //     Function: NodePath::r_get_partial_prev_transform
07298 //       Access: Private
07299 //  Description: Recursively determines the net "previous" transform
07300 //               to the indicated component node from the nth node
07301 //               above it.  If n exceeds the length of the path, this
07302 //               returns the net previous transform from the root of
07303 //               the graph.
07304 ////////////////////////////////////////////////////////////////////
07305 CPT(TransformState) NodePath::
07306 r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const {
07307   if (n == 0 || comp == (NodePathComponent *)NULL) {
07308     return TransformState::make_identity();
07309   } else {
07310     CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
07311     int pipeline_stage = current_thread->get_pipeline_stage();
07312     return r_get_partial_prev_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(transform);
07313   }
07314 }
07315 
07316 ////////////////////////////////////////////////////////////////////
07317 //     Function: NodePath::find_matches
07318 //       Access: Private
07319 //  Description: Finds up to max_matches matches against the given
07320 //               path string from this node and deeper.  The
07321 //               max_matches count indicates the maximum number of
07322 //               matches to return, or -1 not to limit the number
07323 //               returned.
07324 ////////////////////////////////////////////////////////////////////
07325 void NodePath::
07326 find_matches(NodePathCollection &result, const string &path,
07327              int max_matches) const {
07328   if (is_empty()) {
07329     pgraph_cat.warning()
07330       << "Attempt to extend an empty NodePath by '" << path
07331       << "'.\n";
07332     return;
07333   }
07334   FindApproxPath approx_path;
07335   if (approx_path.add_string(path)) {
07336     find_matches(result, approx_path, max_matches);
07337   }
07338 }
07339 
07340 ////////////////////////////////////////////////////////////////////
07341 //     Function: NodePath::find_matches
07342 //       Access: Private
07343 //  Description: Finds up to max_matches matches against the given
07344 //               approx_path from this node and deeper.  The
07345 //               max_matches count indicates the maximum number of
07346 //               matches to return, or -1 not to limit the number
07347 //               returned.
07348 ////////////////////////////////////////////////////////////////////
07349 void NodePath::
07350 find_matches(NodePathCollection &result, FindApproxPath &approx_path,
07351              int max_matches) const {
07352   if (is_empty()) {
07353     pgraph_cat.warning()
07354       << "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
07355     return;
07356   }
07357 
07358   // We start with just one entry on the level.
07359   FindApproxLevelEntry *level = 
07360     new FindApproxLevelEntry(WorkingNodePath(*this), approx_path);
07361   nassertv(level->_node_path.is_valid());
07362 
07363   find_matches(result, level, max_matches);
07364 }
07365 
07366 ////////////////////////////////////////////////////////////////////
07367 //     Function: NodePath::find_matches
07368 //       Access: Private
07369 //  Description: The fundamental implementation of find_matches(),
07370 //               given a starting level (a linked list of
07371 //               FindApproxLevelEntry objects).
07372 ////////////////////////////////////////////////////////////////////
07373 void NodePath::
07374 find_matches(NodePathCollection &result, FindApproxLevelEntry *level,
07375              int max_matches) const {
07376   
07377   int num_levels_remaining = _max_search_depth;
07378 
07379   FindApproxLevelEntry *deleted_entries = NULL;
07380 
07381   while (num_levels_remaining > 0 && level != NULL) {
07382     if (pgraph_cat.is_spam()) {
07383       pgraph_cat.spam()
07384         << "find_matches pass: " << result << ", "
07385         << max_matches << ", " << num_levels_remaining << "\n";
07386       level->write_level(pgraph_cat.spam(false), 4);
07387     }
07388 
07389     num_levels_remaining--;
07390 
07391     FindApproxLevelEntry *next_level = NULL;
07392 
07393     // For each node in the current level, build up the set of possible
07394     // matches in the next level.
07395     FindApproxLevelEntry *entry = level;
07396     while (entry != (FindApproxLevelEntry *)NULL) {
07397       if (entry->consider_node(result, next_level, max_matches, 0)) {
07398         // If we found the requisite number of matches, we can stop.
07399         // Delete all remaining entries and return immediately.
07400 
07401         while (entry != (FindApproxLevelEntry *)NULL) {
07402           FindApproxLevelEntry *next = entry->_next;
07403           delete entry;
07404           entry = next;
07405         }
07406         while (next_level != (FindApproxLevelEntry *)NULL) {
07407           FindApproxLevelEntry *next = next_level->_next;
07408           delete next_level;
07409           next_level = next;
07410         }
07411         while (deleted_entries != (FindApproxLevelEntry *)NULL) {
07412           FindApproxLevelEntry *next = deleted_entries->_next;
07413           delete deleted_entries;
07414           deleted_entries = next;
07415         }
07416         return;
07417       }
07418 
07419       // Move the entry to the delete chain so we can delete it before
07420       // we return from this method.  (We can't delete it immediately,
07421       // because there might be WorkingNodePaths in the next_level
07422       // that reference the WorkingNodePath object within the entry.)
07423       FindApproxLevelEntry *next = entry->_next;
07424       entry->_next = deleted_entries;
07425       deleted_entries = entry;
07426 
07427       entry = next;
07428     }
07429     
07430     // Make sure the remaining entries from this level are added to
07431     // the delete chain.
07432     while (entry != (FindApproxLevelEntry *)NULL) {
07433       FindApproxLevelEntry *next = entry->_next;
07434       entry->_next = deleted_entries;
07435       deleted_entries = entry;
07436 
07437       entry = next;
07438     }
07439 
07440     level = next_level;
07441   }
07442 
07443   // Now it's safe to delete all entries on the delete chain.
07444   while (deleted_entries != (FindApproxLevelEntry *)NULL) {
07445     FindApproxLevelEntry *next = deleted_entries->_next;
07446     delete deleted_entries;
07447     deleted_entries = next;
07448   }
07449 }
07450 
07451 ////////////////////////////////////////////////////////////////////
07452 //     Function: NodePath::r_clear_model_nodes
07453 //       Access: Private
07454 //  Description: The recursive implementation of
07455 //               clear_model_nodes().  This walks through the
07456 //               subgraph defined by the indicated node and below.
07457 ////////////////////////////////////////////////////////////////////
07458 int NodePath::
07459 r_clear_model_nodes(PandaNode *node) {
07460   int count = 0;
07461 
07462   if (node->is_of_type(ModelNode::get_class_type())) {
07463     ModelNode *mnode;
07464     DCAST_INTO_R(mnode, node, count);
07465     mnode->set_preserve_transform(ModelNode::PT_drop_node);
07466     ++count;
07467   }
07468 
07469   PandaNode::Children cr = node->get_children();
07470   int num_children = cr.get_num_children();
07471   for (int i = 0; i < num_children; i++) {
07472     count += r_clear_model_nodes(cr.get_child(i));
07473   }
07474 
07475   return count;
07476 }
07477 
07478 ////////////////////////////////////////////////////////////////////
07479 //     Function: NodePath::r_adjust_all_priorities
07480 //       Access: Private
07481 //  Description: The recursive implementation of
07482 //               adjust_all_priorities().  This walks through the
07483 //               subgraph defined by the indicated node and below.
07484 ////////////////////////////////////////////////////////////////////
07485 void NodePath::
07486 r_adjust_all_priorities(PandaNode *node, int adjustment) {
07487   node->set_state(node->get_state()->adjust_all_priorities(adjustment));
07488   if (node->is_geom_node()) {
07489     GeomNode *gnode;
07490     DCAST_INTO_V(gnode, node);
07491 
07492     int num_geoms = gnode->get_num_geoms();
07493     for (int i = 0; i < num_geoms; i++) {
07494       gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment));
07495     }
07496   }
07497 
07498   PandaNode::Children cr = node->get_children();
07499   int num_children = cr.get_num_children();
07500   for (int i = 0; i < num_children; i++) {
07501     r_adjust_all_priorities(cr.get_child(i), adjustment);
07502   }
07503 }
07504 
07505 ////////////////////////////////////////////////////////////////////
07506 //     Function: NodePath::r_force_recompute_bounds
07507 //       Access: Private
07508 //  Description: 
07509 ////////////////////////////////////////////////////////////////////
07510 void NodePath::
07511 r_force_recompute_bounds(PandaNode *node) {
07512   if (node->is_geom_node()) {
07513     GeomNode *gnode;
07514     DCAST_INTO_V(gnode, node);
07515 
07516     int num_geoms = gnode->get_num_geoms();
07517     for (int i = 0; i < num_geoms; i++) {
07518       const Geom *geom = gnode->get_geom(i);
07519       geom->mark_bounds_stale();
07520     }
07521   }
07522 
07523   node->mark_bounds_stale();
07524 
07525   // Now consider children.
07526   PandaNode::Children cr = node->get_children();
07527   int num_children = cr.get_num_children();
07528   for (int i = 0; i < num_children; i++) {
07529     r_force_recompute_bounds(cr.get_child(i));
07530   }
07531 }
07532 
07533 ////////////////////////////////////////////////////////////////////
07534 //     Function: NodePath::r_set_collide_mask
07535 //       Access: Private
07536 //  Description: Recursively applies the indicated collide mask to the
07537 //               nodes at and below this node.
07538 ////////////////////////////////////////////////////////////////////
07539 void NodePath::
07540 r_set_collide_mask(PandaNode *node, 
07541                    CollideMask and_mask, CollideMask or_mask,
07542                    TypeHandle node_type) {
07543   if (node->is_of_type(node_type)) {
07544     CollideMask into_collide_mask = node->get_into_collide_mask();
07545     into_collide_mask = (into_collide_mask & and_mask) | or_mask;
07546     node->set_into_collide_mask(into_collide_mask);
07547   }
07548 
07549   PandaNode::Children cr = node->get_children();
07550   int num_children = cr.get_num_children();
07551   for (int i = 0; i < num_children; i++) {
07552     r_set_collide_mask(cr.get_child(i), and_mask, or_mask, node_type);
07553   }
07554 }
07555 
07556 ////////////////////////////////////////////////////////////////////
07557 //     Function: NodePath::r_has_vertex_column
07558 //       Access: Private
07559 //  Description: 
07560 ////////////////////////////////////////////////////////////////////
07561 bool NodePath::
07562 r_has_vertex_column(PandaNode *node, const InternalName *name) const {
07563   if (node->is_geom_node()) {
07564     GeomNode *gnode;
07565     DCAST_INTO_R(gnode, node, false);
07566 
07567     int num_geoms = gnode->get_num_geoms();
07568     for (int i = 0; i < num_geoms; i++) {
07569       const Geom *geom = gnode->get_geom(i);
07570       CPT(GeomVertexData) vdata = geom->get_vertex_data();
07571       if (vdata->has_column(name)) {
07572         return true;
07573       }
07574     }
07575   }
07576 
07577   // Now consider children.
07578   PandaNode::Children cr = node->get_children();
07579   int num_children = cr.get_num_children();
07580   for (int i = 0; i < num_children; i++) {
07581     PandaNode *child = cr.get_child(i);
07582     if (r_has_vertex_column(child, name)) {
07583       return true;
07584     }
07585   }
07586 
07587   return false;
07588 }
07589 
07590 ////////////////////////////////////////////////////////////////////
07591 //     Function: NodePath::r_find_all_vertex_columns
07592 //       Access: Private
07593 //  Description: 
07594 ////////////////////////////////////////////////////////////////////
07595 void NodePath::
07596 r_find_all_vertex_columns(PandaNode *node,
07597                           NodePath::InternalNames &vertex_columns) const {
07598   if (node->is_geom_node()) {
07599     GeomNode *gnode;
07600     DCAST_INTO_V(gnode, node);
07601 
07602     int num_geoms = gnode->get_num_geoms();
07603     for (int i = 0; i < num_geoms; ++i) {
07604       const Geom *geom = gnode->get_geom(i);
07605       const GeomVertexFormat *format = geom->get_vertex_data()->get_format();
07606       int num_arrays = format->get_num_arrays();
07607       for (int j = 0; j < num_arrays; ++j) {
07608         const GeomVertexArrayFormat *array = format->get_array(j);
07609         int num_columns = array->get_num_columns();
07610         for (int k = 0; k < num_columns; ++k) {
07611           const GeomVertexColumn *column = array->get_column(k);
07612           vertex_columns.insert(column->get_name());
07613         }
07614       }
07615     }
07616   }
07617 
07618   // Now consider children.
07619   PandaNode::Children cr = node->get_children();
07620   int num_children = cr.get_num_children();
07621   for (int i = 0; i < num_children; i++) {
07622     PandaNode *child = cr.get_child(i);
07623     r_find_all_vertex_columns(child, vertex_columns);
07624   }
07625 }
07626 
07627 ////////////////////////////////////////////////////////////////////
07628 //     Function: NodePath::r_find_texture
07629 //       Access: Private
07630 //  Description: 
07631 ////////////////////////////////////////////////////////////////////
07632 Texture *NodePath::
07633 r_find_texture(PandaNode *node, const RenderState *state,
07634                const GlobPattern &glob) const {
07635   if (node->is_geom_node()) {
07636     GeomNode *gnode;
07637     DCAST_INTO_R(gnode, node, NULL);
07638 
07639     int num_geoms = gnode->get_num_geoms();
07640     for (int i = 0; i < num_geoms; i++) {
07641       CPT(RenderState) geom_state = 
07642         state->compose(gnode->get_geom_state(i));
07643 
07644       // Look for a TextureAttrib on the state.
07645       const RenderAttrib *attrib =
07646         geom_state->get_attrib(TextureAttrib::get_class_slot());
07647       if (attrib != (const RenderAttrib *)NULL) {
07648         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07649         for (int i = 0; i < ta->get_num_on_stages(); i++) {
07650           Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
07651           if (texture != (Texture *)NULL) {
07652             if (glob.matches(texture->get_name())) {
07653               return texture;
07654             }
07655           }
07656         }
07657       }
07658     }
07659   }
07660 
07661   // Now consider children.
07662   PandaNode::Children cr = node->get_children();
07663   int num_children = cr.get_num_children();
07664   for (int i = 0; i < num_children; i++) {
07665     PandaNode *child = cr.get_child(i);
07666     CPT(RenderState) next_state = state->compose(child->get_state());
07667 
07668     Texture *result = r_find_texture(child, next_state, glob);
07669     if (result != (Texture *)NULL) {
07670       return result;
07671     }
07672   }
07673 
07674   return NULL;
07675 }
07676 
07677 ////////////////////////////////////////////////////////////////////
07678 //     Function: NodePath::r_find_all_textures
07679 //       Access: Private
07680 //  Description: 
07681 ////////////////////////////////////////////////////////////////////
07682 void NodePath::
07683 r_find_all_textures(PandaNode *node, const RenderState *state,
07684                     NodePath::Textures &textures) const {
07685   if (node->is_geom_node()) {
07686     GeomNode *gnode;
07687     DCAST_INTO_V(gnode, node);
07688 
07689     int num_geoms = gnode->get_num_geoms();
07690     for (int i = 0; i < num_geoms; i++) {
07691       CPT(RenderState) geom_state = 
07692         state->compose(gnode->get_geom_state(i));
07693 
07694       // Look for a TextureAttrib on the state.
07695       const RenderAttrib *attrib =
07696         geom_state->get_attrib(TextureAttrib::get_class_slot());
07697       if (attrib != (const RenderAttrib *)NULL) {
07698         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07699         for (int i = 0; i < ta->get_num_on_stages(); i++) {
07700           Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
07701           if (texture != (Texture *)NULL) {
07702             textures.insert(texture);
07703           }
07704         }
07705       }
07706     }
07707   }
07708 
07709   // Now consider children.
07710   PandaNode::Children cr = node->get_children();
07711   int num_children = cr.get_num_children();
07712   for (int i = 0; i < num_children; i++) {
07713     PandaNode *child = cr.get_child(i);
07714     CPT(RenderState) next_state = state->compose(child->get_state());
07715     r_find_all_textures(child, next_state, textures);
07716   }
07717 }
07718 
07719 ////////////////////////////////////////////////////////////////////
07720 //     Function: NodePath::r_find_texture
07721 //       Access: Private
07722 //  Description: 
07723 ////////////////////////////////////////////////////////////////////
07724 Texture * NodePath::
07725 r_find_texture(PandaNode *node, TextureStage *stage) const {
07726   // Look for a TextureAttrib on the node.
07727   const RenderAttrib *attrib =
07728     node->get_attrib(TextureAttrib::get_class_slot());
07729   if (attrib != (const RenderAttrib *)NULL) {
07730     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07731     if (ta->has_on_stage(stage)) {
07732       return ta->get_on_texture(stage);
07733     }
07734   }
07735 
07736   if (node->is_geom_node()) {
07737     GeomNode *gnode;
07738     DCAST_INTO_R(gnode, node, NULL);
07739 
07740     int num_geoms = gnode->get_num_geoms();
07741     for (int i = 0; i < num_geoms; i++) {
07742       CPT(RenderState) geom_state = gnode->get_geom_state(i);
07743 
07744       // Look for a TextureAttrib on the state.
07745       const RenderAttrib *attrib =
07746         geom_state->get_attrib(TextureAttrib::get_class_slot());
07747       if (attrib != (const RenderAttrib *)NULL) {
07748         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07749         if (ta->has_on_stage(stage)) {
07750           return ta->get_on_texture(stage);
07751         }
07752       }
07753     }
07754   }
07755 
07756   // Now consider children.
07757   PandaNode::Children cr = node->get_children();
07758   int num_children = cr.get_num_children();
07759   for (int i = 0; i < num_children; i++) {
07760     PandaNode *child = cr.get_child(i);
07761 
07762     Texture *result = r_find_texture(child, stage);
07763     if (result != (Texture *)NULL) {
07764       return result;
07765     }
07766   }
07767 
07768   return NULL;
07769 }
07770 
07771 ////////////////////////////////////////////////////////////////////
07772 //     Function: NodePath::r_find_all_textures
07773 //       Access: Private
07774 //  Description: 
07775 ////////////////////////////////////////////////////////////////////
07776 void NodePath::
07777 r_find_all_textures(PandaNode *node, TextureStage *stage,
07778                     NodePath::Textures &textures) const {
07779   // Look for a TextureAttrib on the node.
07780   const RenderAttrib *attrib =
07781     node->get_attrib(TextureAttrib::get_class_slot());
07782   if (attrib != (const RenderAttrib *)NULL) {
07783     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07784     if (ta->has_on_stage(stage)) {
07785       textures.insert(ta->get_on_texture(stage));
07786     }
07787   }
07788 
07789   if (node->is_geom_node()) {
07790     GeomNode *gnode;
07791     DCAST_INTO_V(gnode, node);
07792 
07793     int num_geoms = gnode->get_num_geoms();
07794     for (int i = 0; i < num_geoms; i++) {
07795       CPT(RenderState) geom_state = gnode->get_geom_state(i);
07796 
07797       // Look for a TextureAttrib on the state.
07798       const RenderAttrib *attrib =
07799         geom_state->get_attrib(TextureAttrib::get_class_slot());
07800       if (attrib != (const RenderAttrib *)NULL) {
07801         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07802         if (ta->has_on_stage(stage)) {
07803           textures.insert(ta->get_on_texture(stage));
07804         }
07805       }
07806     }
07807   }
07808 
07809   // Now consider children.
07810   PandaNode::Children cr = node->get_children();
07811   int num_children = cr.get_num_children();
07812   for (int i = 0; i < num_children; i++) {
07813     PandaNode *child = cr.get_child(i);
07814     r_find_all_textures(child, stage, textures);
07815   }
07816 }
07817 
07818 ////////////////////////////////////////////////////////////////////
07819 //     Function: NodePath::r_find_texture_stage
07820 //       Access: Private
07821 //  Description: 
07822 ////////////////////////////////////////////////////////////////////
07823 TextureStage * NodePath::
07824 r_find_texture_stage(PandaNode *node, const RenderState *state,
07825                      const GlobPattern &glob) const {
07826   if (node->is_geom_node()) {
07827     GeomNode *gnode;
07828     DCAST_INTO_R(gnode, node, NULL);
07829 
07830     int num_geoms = gnode->get_num_geoms();
07831     for (int i = 0; i < num_geoms; i++) {
07832       CPT(RenderState) geom_state = 
07833         state->compose(gnode->get_geom_state(i));
07834 
07835       // Look for a TextureAttrib on the state.
07836       const RenderAttrib *attrib =
07837         geom_state->get_attrib(TextureAttrib::get_class_slot());
07838       if (attrib != (const RenderAttrib *)NULL) {
07839         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07840         for (int i = 0; i < ta->get_num_on_stages(); i++) {
07841           TextureStage *texture_stage = ta->get_on_stage(i);
07842           if (texture_stage != (TextureStage *)NULL) {
07843             if (glob.matches(texture_stage->get_name())) {
07844               return texture_stage;
07845             }
07846           }
07847         }
07848       }
07849     }
07850   }
07851 
07852   // Now consider children.
07853   PandaNode::Children cr = node->get_children();
07854   int num_children = cr.get_num_children();
07855   for (int i = 0; i < num_children; i++) {
07856     PandaNode *child = cr.get_child(i);
07857     CPT(RenderState) next_state = state->compose(child->get_state());
07858 
07859     TextureStage *result = r_find_texture_stage(child, next_state, glob);
07860     if (result != (TextureStage *)NULL) {
07861       return result;
07862     }
07863   }
07864 
07865   return NULL;
07866 }
07867 
07868 ////////////////////////////////////////////////////////////////////
07869 //     Function: NodePath::r_find_all_texture_stages
07870 //       Access: Private
07871 //  Description: 
07872 ////////////////////////////////////////////////////////////////////
07873 void NodePath::
07874 r_find_all_texture_stages(PandaNode *node, const RenderState *state,
07875                           NodePath::TextureStages &texture_stages) const {
07876   if (node->is_geom_node()) {
07877     GeomNode *gnode;
07878     DCAST_INTO_V(gnode, node);
07879 
07880     int num_geoms = gnode->get_num_geoms();
07881     for (int i = 0; i < num_geoms; i++) {
07882       CPT(RenderState) geom_state = 
07883         state->compose(gnode->get_geom_state(i));
07884 
07885       // Look for a TextureAttrib on the state.
07886       const RenderAttrib *attrib =
07887         geom_state->get_attrib(TextureAttrib::get_class_slot());
07888       if (attrib != (const RenderAttrib *)NULL) {
07889         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07890         for (int i = 0; i < ta->get_num_on_stages(); i++) {
07891           TextureStage *texture_stage = ta->get_on_stage(i);
07892           if (texture_stage != (TextureStage *)NULL) {
07893             texture_stages.insert(texture_stage);
07894           }
07895         }
07896       }
07897     }
07898   }
07899 
07900   // Now consider children.
07901   PandaNode::Children cr = node->get_children();
07902   int num_children = cr.get_num_children();
07903   for (int i = 0; i < num_children; i++) {
07904     PandaNode *child = cr.get_child(i);
07905     CPT(RenderState) next_state = state->compose(child->get_state());
07906     r_find_all_texture_stages(child, next_state, texture_stages);
07907   }
07908 }
07909 
07910 ////////////////////////////////////////////////////////////////////
07911 //     Function: NodePath::r_unify_texture_stages
07912 //       Access: Private
07913 //  Description: 
07914 ////////////////////////////////////////////////////////////////////
07915 void NodePath::
07916 r_unify_texture_stages(PandaNode *node, TextureStage *stage) {
07917   // Look for a TextureAttrib on the state.
07918   const RenderAttrib *attrib =
07919     node->get_attrib(TextureAttrib::get_class_slot());
07920   if (attrib != (const RenderAttrib *)NULL) {
07921     const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07922     CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
07923     if (new_attrib != ta) {
07924       node->set_attrib(new_attrib);
07925     }
07926   }
07927 
07928   if (node->is_geom_node()) {
07929     GeomNode *gnode;
07930     DCAST_INTO_V(gnode, node);
07931 
07932     int num_geoms = gnode->get_num_geoms();
07933     for (int i = 0; i < num_geoms; i++) {
07934       CPT(RenderState) state = gnode->get_geom_state(i);
07935 
07936       // Look for a TextureAttrib on the state.
07937       const RenderAttrib *attrib =
07938         state->get_attrib(TextureAttrib::get_class_slot());
07939       if (attrib != (const RenderAttrib *)NULL) {
07940         const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
07941         CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
07942         if (new_attrib != ta) {
07943           CPT(RenderState) new_state = state->add_attrib(new_attrib);
07944           gnode->set_geom_state(i, new_state);
07945         }
07946       }
07947     }
07948   }
07949 
07950   // Now consider children.
07951   PandaNode::Children cr = node->get_children();
07952   int num_children = cr.get_num_children();
07953   for (int i = 0; i < num_children; i++) {
07954     PandaNode *child = cr.get_child(i);
07955     r_unify_texture_stages(child, stage);
07956   }
07957 }
07958 
07959 ////////////////////////////////////////////////////////////////////
07960 //     Function: NodePath::r_find_material
07961 //       Access: Private
07962 //  Description: 
07963 ////////////////////////////////////////////////////////////////////
07964 Material *NodePath::
07965 r_find_material(PandaNode *node, const RenderState *state,
07966                const GlobPattern &glob) const {
07967   if (node->is_geom_node()) {
07968     GeomNode *gnode;
07969     DCAST_INTO_R(gnode, node, NULL);
07970 
07971     int num_geoms = gnode->get_num_geoms();
07972     for (int i = 0; i < num_geoms; i++) {
07973       CPT(RenderState) geom_state = 
07974         state->compose(gnode->get_geom_state(i));
07975 
07976       // Look for a MaterialAttrib on the state.
07977       const RenderAttrib *attrib =
07978         geom_state->get_attrib(MaterialAttrib::get_class_slot());
07979       if (attrib != (const RenderAttrib *)NULL) {
07980         const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
07981         if (!ta->is_off()) {
07982           Material *material = ta->get_material();
07983           if (material != (Material *)NULL) {
07984             if (glob.matches(material->get_name())) {
07985               return material;
07986             }
07987           }
07988         }
07989       }
07990     }
07991   }
07992 
07993   // Now consider children.
07994   PandaNode::Children cr = node->get_children();
07995   int num_children = cr.get_num_children();
07996   for (int i = 0; i < num_children; i++) {
07997     PandaNode *child = cr.get_child(i);
07998     CPT(RenderState) next_state = state->compose(child->get_state());
07999 
08000     Material *result = r_find_material(child, next_state, glob);
08001     if (result != (Material *)NULL) {
08002       return result;
08003     }
08004   }
08005 
08006   return NULL;
08007 }
08008 
08009 ////////////////////////////////////////////////////////////////////
08010 //     Function: NodePath::r_find_all_materials
08011 //       Access: Private
08012 //  Description: 
08013 ////////////////////////////////////////////////////////////////////
08014 void NodePath::
08015 r_find_all_materials(PandaNode *node, const RenderState *state,
08016                     NodePath::Materials &materials) const {
08017   if (node->is_geom_node()) {
08018     GeomNode *gnode;
08019     DCAST_INTO_V(gnode, node);
08020 
08021     int num_geoms = gnode->get_num_geoms();
08022     for (int i = 0; i < num_geoms; i++) {
08023       CPT(RenderState) geom_state = 
08024         state->compose(gnode->get_geom_state(i));
08025 
08026       // Look for a MaterialAttrib on the state.
08027       const RenderAttrib *attrib =
08028         geom_state->get_attrib(MaterialAttrib::get_class_slot());
08029       if (attrib != (const RenderAttrib *)NULL) {
08030         const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
08031         if (!ta->is_off()) {
08032           Material *material = ta->get_material();
08033           if (material != (Material *)NULL) {
08034             materials.insert(material);
08035           }
08036         }
08037       }
08038     }
08039   }
08040 
08041   // Now consider children.
08042   PandaNode::Children cr = node->get_children();
08043   int num_children = cr.get_num_children();
08044   for (int i = 0; i < num_children; i++) {
08045     PandaNode *child = cr.get_child(i);
08046     CPT(RenderState) next_state = state->compose(child->get_state());
08047     r_find_all_materials(child, next_state, materials);
08048   }
08049 }
08050 
08051 #ifdef HAVE_PYTHON
08052 ////////////////////////////////////////////////////////////////////
08053 //     Function: py_decode_NodePath_from_bam_stream
08054 //       Access: Published
08055 //  Description: This wrapper is defined as a global function to suit
08056 //               pickle's needs.
08057 ////////////////////////////////////////////////////////////////////
08058 NodePath
08059 py_decode_NodePath_from_bam_stream(const string &data) {
08060   return py_decode_NodePath_from_bam_stream_persist(NULL, data);
08061 }
08062 #endif  // HAVE_PYTHON
08063 
08064 
08065 #ifdef HAVE_PYTHON
08066 ////////////////////////////////////////////////////////////////////
08067 //     Function: py_decode_NodePath_from_bam_stream_persist
08068 //       Access: Published
08069 //  Description: This wrapper is defined as a global function to suit
08070 //               pickle's needs.
08071 ////////////////////////////////////////////////////////////////////
08072 NodePath
08073 py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &data) {
08074   BamReader *reader = NULL;
08075   if (unpickler != NULL) {
08076     PyObject *py_reader = PyObject_GetAttrString(unpickler, "bamReader");
08077     if (py_reader == NULL) {
08078       // It's OK if there's no bamReader.
08079       PyErr_Clear();
08080     } else {
08081       DTOOL_Call_ExtractThisPointerForType(py_reader, &Dtool_BamReader, (void **)&reader);
08082       Py_DECREF(py_reader);
08083     }
08084   }
08085 
08086   return NodePath::decode_from_bam_stream(data, reader);
08087 }
08088 #endif  // HAVE_PYTHON
08089 
 All Classes Functions Variables Enumerations