Panda3D
|
00001 // Filename: nodePath.cxx 00002 // Created by: drose (25Feb02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "nodePath.h" 00016 #include "nodePathCollection.h" 00017 #include "findApproxPath.h" 00018 #include "findApproxLevelEntry.h" 00019 #include "internalNameCollection.h" 00020 #include "config_pgraph.h" 00021 #include "colorAttrib.h" 00022 #include "colorScaleAttrib.h" 00023 #include "cullBinAttrib.h" 00024 #include "textureAttrib.h" 00025 #include "texMatrixAttrib.h" 00026 #include "texGenAttrib.h" 00027 #include "materialAttrib.h" 00028 #include "materialCollection.h" 00029 #include "lightAttrib.h" 00030 #include "clipPlaneAttrib.h" 00031 #include "polylightEffect.h" 00032 #include "fogAttrib.h" 00033 #include "renderModeAttrib.h" 00034 #include "cullFaceAttrib.h" 00035 #include "alphaTestAttrib.h" 00036 #include "depthTestAttrib.h" 00037 #include "depthWriteAttrib.h" 00038 #include "depthOffsetAttrib.h" 00039 #include "shaderAttrib.h" 00040 #include "billboardEffect.h" 00041 #include "compassEffect.h" 00042 #include "showBoundsEffect.h" 00043 #include "transparencyAttrib.h" 00044 #include "antialiasAttrib.h" 00045 #include "audioVolumeAttrib.h" 00046 #include "texProjectorEffect.h" 00047 #include "scissorEffect.h" 00048 #include "texturePool.h" 00049 #include "planeNode.h" 00050 #include "lensNode.h" 00051 #include "materialPool.h" 00052 #include "look_at.h" 00053 #include "plist.h" 00054 #include "boundingSphere.h" 00055 #include "geomNode.h" 00056 #include "sceneGraphReducer.h" 00057 #include "textureCollection.h" 00058 #include "textureStageCollection.h" 00059 #include "globPattern.h" 00060 #include "shader.h" 00061 #include "shaderInput.h" 00062 #include "config_gobj.h" 00063 #include "bamFile.h" 00064 #include "preparedGraphicsObjects.h" 00065 #include "dcast.h" 00066 #include "pStatCollector.h" 00067 #include "pStatTimer.h" 00068 #include "modelNode.h" 00069 #include "py_panda.h" 00070 #include "bam.h" 00071 #include "bamWriter.h" 00072 00073 // stack seems to overflow on Intel C++ at 7000. If we need more than 00074 // 7000, need to increase stack size. 00075 int NodePath::_max_search_depth = 7000; 00076 TypeHandle NodePath::_type_handle; 00077 00078 00079 #ifdef HAVE_PYTHON 00080 #include "py_panda.h" 00081 #ifndef CPPPARSER 00082 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamWriter; 00083 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamReader; 00084 #endif // CPPPARSER 00085 #endif // HAVE_PYTHON 00086 00087 // ***Begin temporary transition code for operator bool 00088 enum EmptyNodePathType { 00089 ENP_future, 00090 ENP_transition, 00091 ENP_deprecated, 00092 ENP_notify, 00093 }; 00094 00095 ostream &operator << (ostream &out, EmptyNodePathType enp) { 00096 switch (enp) { 00097 case ENP_future: 00098 return out << "future"; 00099 case ENP_transition: 00100 return out << "transition"; 00101 case ENP_deprecated: 00102 return out << "deprecated"; 00103 case ENP_notify: 00104 return out << "notify"; 00105 } 00106 return out << "**invalid EmptyNodePathType value (" << (int)enp << ")**"; 00107 } 00108 00109 istream &operator >> (istream &in, EmptyNodePathType &enp) { 00110 string word; 00111 in >> word; 00112 if (word == "future") { 00113 enp = ENP_future; 00114 } else if (word == "transition") { 00115 enp = ENP_transition; 00116 } else if (word == "deprecated") { 00117 enp = ENP_deprecated; 00118 } else if (word == "notify") { 00119 enp = ENP_notify; 00120 } else { 00121 pgraph_cat.warning() 00122 << "Invalid EmptyNodePathType value (\"" << word << "\")\n"; 00123 enp = ENP_transition; 00124 } 00125 return in; 00126 } 00127 00128 static ConfigVariableEnum<EmptyNodePathType> empty_node_path 00129 ("empty-node-path", ENP_future, 00130 PRC_DESC("This is a temporary transition variable to control the behavior " 00131 "of a NodePath when it is used as a boolean false. Set this to " 00132 "'deprecated' to preserve the original behavior: every NodePath " 00133 "evaluates true, even an empty NodePath. Set it to 'future' to " 00134 "support the new behavior: non-empty NodePaths evaluate true, " 00135 "and empty NodePaths evaluate false. Set it to 'transition' to " 00136 "raise an exception if an empty NodePath is used as a boolean.")); 00137 00138 // ***End temporary transition code for operator bool 00139 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: NodePath::Constructor 00143 // Access: Published 00144 // Description: Constructs a NodePath with the indicated parent 00145 // NodePath and child node; the child node must be a 00146 // stashed or unstashed child of the parent. 00147 //////////////////////////////////////////////////////////////////// 00148 NodePath:: 00149 NodePath(const NodePath &parent, PandaNode *child_node, 00150 Thread *current_thread) : 00151 _error_type(ET_fail) 00152 { 00153 nassertv(child_node != (PandaNode *)NULL); 00154 int pipeline_stage = current_thread->get_pipeline_stage(); 00155 00156 if (parent.is_empty()) { 00157 // Special case: constructing a NodePath at the root. 00158 _head = PandaNode::get_top_component(child_node, true, 00159 pipeline_stage, current_thread); 00160 00161 } else { 00162 _head = PandaNode::get_component(parent._head, child_node, pipeline_stage, 00163 current_thread); 00164 } 00165 nassertv(_head != (NodePathComponent *)NULL); 00166 00167 if (_head != (NodePathComponent *)NULL) { 00168 _error_type = ET_ok; 00169 } 00170 _backup_key = 0; 00171 } 00172 00173 #ifdef HAVE_PYTHON 00174 //////////////////////////////////////////////////////////////////// 00175 // Function: NodePath::__copy__ 00176 // Access: Published 00177 // Description: A special Python method that is invoked by 00178 // copy.copy(node). Unlike the NodePath copy 00179 // constructor, this makes a duplicate copy of the 00180 // underlying PandaNode (but shares children, instead of 00181 // copying them or omitting them). 00182 //////////////////////////////////////////////////////////////////// 00183 NodePath NodePath:: 00184 __copy__() const { 00185 if (is_empty()) { 00186 // Invoke the copy constructor if we have no node. 00187 return *this; 00188 } 00189 00190 // If we do have a node, duplicate it, and wrap it in a new 00191 // NodePath. 00192 return NodePath(node()->__copy__()); 00193 } 00194 #endif // HAVE_PYTHON 00195 00196 #ifdef HAVE_PYTHON 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: NodePath::__deepcopy__ 00199 // Access: Published 00200 // Description: A special Python method that is invoked by 00201 // copy.deepcopy(np). This calls copy_to() unless the 00202 // NodePath is already present in the provided 00203 // dictionary. 00204 //////////////////////////////////////////////////////////////////// 00205 PyObject *NodePath:: 00206 __deepcopy__(PyObject *self, PyObject *memo) const { 00207 IMPORT_THIS struct Dtool_PyTypedObject Dtool_NodePath; 00208 00209 // Borrowed reference. 00210 PyObject *dupe = PyDict_GetItem(memo, self); 00211 if (dupe != NULL) { 00212 // Already in the memo dictionary. 00213 Py_INCREF(dupe); 00214 return dupe; 00215 } 00216 00217 NodePath *np_dupe; 00218 if (is_empty()) { 00219 np_dupe = new NodePath(*this); 00220 } else { 00221 np_dupe = new NodePath(copy_to(NodePath())); 00222 } 00223 00224 dupe = DTool_CreatePyInstance((void *)np_dupe, Dtool_NodePath, 00225 true, false); 00226 if (PyDict_SetItem(memo, self, dupe) != 0) { 00227 Py_DECREF(dupe); 00228 return NULL; 00229 } 00230 00231 return dupe; 00232 } 00233 #endif // HAVE_PYTHON 00234 00235 #ifdef HAVE_PYTHON 00236 //////////////////////////////////////////////////////////////////// 00237 // Function: NodePath::__reduce__ 00238 // Access: Published 00239 // Description: This special Python method is implement to provide 00240 // support for the pickle module. 00241 // 00242 // This hooks into the native pickle and cPickle 00243 // modules, but it cannot properly handle 00244 // self-referential BAM objects. 00245 //////////////////////////////////////////////////////////////////// 00246 PyObject *NodePath:: 00247 __reduce__(PyObject *self) const { 00248 return __reduce_persist__(self, NULL); 00249 } 00250 #endif // HAVE_PYTHON 00251 00252 #ifdef HAVE_PYTHON 00253 //////////////////////////////////////////////////////////////////// 00254 // Function: NodePath::__reduce_persist__ 00255 // Access: Published 00256 // Description: This special Python method is implement to provide 00257 // support for the pickle module. 00258 // 00259 // This is similar to __reduce__, but it provides 00260 // additional support for the missing persistent-state 00261 // object needed to properly support self-referential 00262 // BAM objects written to the pickle stream. This hooks 00263 // into the pickle and cPickle modules implemented in 00264 // direct/src/stdpy. 00265 //////////////////////////////////////////////////////////////////// 00266 PyObject *NodePath:: 00267 __reduce_persist__(PyObject *self, PyObject *pickler) const { 00268 // We should return at least a 2-tuple, (Class, (args)): the 00269 // necessary class object whose constructor we should call 00270 // (e.g. this), and the arguments necessary to reconstruct this 00271 // object. 00272 00273 BamWriter *writer = NULL; 00274 if (pickler != NULL) { 00275 PyObject *py_writer = PyObject_GetAttrString(pickler, "bamWriter"); 00276 if (py_writer == NULL) { 00277 // It's OK if there's no bamWriter. 00278 PyErr_Clear(); 00279 } else { 00280 DTOOL_Call_ExtractThisPointerForType(py_writer, &Dtool_BamWriter, (void **)&writer); 00281 Py_DECREF(py_writer); 00282 } 00283 } 00284 00285 // We have a non-empty NodePath. 00286 00287 string bam_stream; 00288 if (!encode_to_bam_stream(bam_stream, writer)) { 00289 ostringstream stream; 00290 stream << "Could not bamify " << this; 00291 string message = stream.str(); 00292 PyErr_SetString(PyExc_TypeError, message.c_str()); 00293 return NULL; 00294 } 00295 00296 // Start by getting this class object. 00297 PyObject *this_class = PyObject_Type(self); 00298 if (this_class == NULL) { 00299 return NULL; 00300 } 00301 00302 PyObject *func; 00303 if (writer != NULL) { 00304 // The modified pickle support: call the "persistent" version of 00305 // this function, which receives the unpickler itself as an 00306 // additional parameter. 00307 func = TypedWritable::find_global_decode(this_class, "pyDecodeNodePathFromBamStreamPersist"); 00308 if (func == NULL) { 00309 PyErr_SetString(PyExc_TypeError, "Couldn't find pyDecodeNodePathFromBamStreamPersist()"); 00310 Py_DECREF(this_class); 00311 return NULL; 00312 } 00313 00314 } else { 00315 // The traditional pickle support: call the non-persistent version 00316 // of this function. 00317 00318 func = TypedWritable::find_global_decode(this_class, "pyDecodeNodePathFromBamStream"); 00319 if (func == NULL) { 00320 PyErr_SetString(PyExc_TypeError, "Couldn't find pyDecodeNodePathFromBamStream()"); 00321 Py_DECREF(this_class); 00322 return NULL; 00323 } 00324 } 00325 00326 PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), bam_stream.size()); 00327 Py_DECREF(func); 00328 Py_DECREF(this_class); 00329 return result; 00330 } 00331 #endif // HAVE_PYTHON 00332 00333 //////////////////////////////////////////////////////////////////// 00334 // Function: NodePath::operator bool 00335 // Access: Published 00336 // Description: Returns true if the NodePath is valid (not empty), 00337 // or false if it contains no nodes. 00338 //////////////////////////////////////////////////////////////////// 00339 NodePath:: 00340 operator bool () const { 00341 switch (empty_node_path) { 00342 case ENP_future: 00343 return !is_empty(); 00344 00345 case ENP_deprecated: 00346 return true; 00347 00348 case ENP_notify: 00349 { 00350 const char *msg = "NodePath being used as a Boolean (talk to Zac)"; 00351 #ifdef HAVE_PYTHON 00352 PyErr_Warn(PyExc_FutureWarning, (char *)msg); 00353 #endif 00354 return !is_empty(); 00355 } 00356 00357 00358 case ENP_transition: 00359 if (!is_empty()) { 00360 return true; 00361 } 00362 00363 { 00364 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."; 00365 pgraph_cat.warning() 00366 << message << "\n"; 00367 #ifdef HAVE_PYTHON 00368 PyErr_Warn(PyExc_FutureWarning, (char *)message); 00369 #endif 00370 } 00371 return true; 00372 } 00373 00374 nassertr(false, true); 00375 return true; 00376 } 00377 00378 //////////////////////////////////////////////////////////////////// 00379 // Function: NodePath::get_num_nodes 00380 // Access: Published 00381 // Description: Returns the number of nodes in the path. 00382 //////////////////////////////////////////////////////////////////// 00383 int NodePath:: 00384 get_num_nodes(Thread *current_thread) const { 00385 if (is_empty()) { 00386 return 0; 00387 } 00388 int pipeline_stage = current_thread->get_pipeline_stage(); 00389 return _head->get_length(pipeline_stage, current_thread); 00390 } 00391 00392 //////////////////////////////////////////////////////////////////// 00393 // Function: NodePath::get_node 00394 // Access: Published 00395 // Description: Returns the nth node of the path, where 0 is the 00396 // referenced (bottom) node and get_num_nodes() - 1 is 00397 // the top node. This requires iterating through the 00398 // path. 00399 // 00400 // Also see node(), which is a convenience function to 00401 // return the same thing as get_node(0) (since the 00402 // bottom node is the most important node in the 00403 // NodePath, and is the one most frequently referenced). 00404 // 00405 // Note that this function returns the same thing as 00406 // get_ancestor(index).node(). 00407 //////////////////////////////////////////////////////////////////// 00408 PandaNode *NodePath:: 00409 get_node(int index, Thread *current_thread) const { 00410 nassertr(index >= 0 && index < get_num_nodes(), NULL); 00411 00412 int pipeline_stage = current_thread->get_pipeline_stage(); 00413 00414 NodePathComponent *comp = _head; 00415 while (index > 0) { 00416 // If this assertion fails, the index was out of range; the 00417 // component's length must have been invalid. 00418 nassertr(comp != (NodePathComponent *)NULL, NULL); 00419 comp = comp->get_next(pipeline_stage, current_thread); 00420 index--; 00421 } 00422 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 return comp->get_node(); 00427 } 00428 00429 //////////////////////////////////////////////////////////////////// 00430 // Function: NodePath::get_ancestor 00431 // Access: Published 00432 // Description: Returns the nth ancestor of the path, where 0 is the 00433 // NodePath itself and get_num_nodes() - 1 is get_top(). 00434 // This requires iterating through the path. 00435 // 00436 // Also see get_node(), which returns the same thing as 00437 // a PandaNode pointer, not a NodePath. 00438 //////////////////////////////////////////////////////////////////// 00439 NodePath NodePath:: 00440 get_ancestor(int index, Thread *current_thread) const { 00441 nassertr(index >= 0 && index < get_num_nodes(), NodePath::fail()); 00442 00443 int pipeline_stage = current_thread->get_pipeline_stage(); 00444 00445 NodePathComponent *comp = _head; 00446 while (index > 0) { 00447 // If this assertion fails, the index was out of range; the 00448 // component's length must have been invalid. 00449 nassertr(comp != (NodePathComponent *)NULL, NodePath::fail()); 00450 comp = comp->get_next(pipeline_stage, current_thread); 00451 index--; 00452 } 00453 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 00458 NodePath result; 00459 result._head = comp; 00460 return result; 00461 } 00462 00463 //////////////////////////////////////////////////////////////////// 00464 // Function: NodePath::get_top 00465 // Access: Published 00466 // Description: Returns a singleton NodePath that represents the top 00467 // of the path, or empty NodePath if this path is empty. 00468 //////////////////////////////////////////////////////////////////// 00469 NodePath NodePath:: 00470 get_top(Thread *current_thread) const { 00471 if (is_empty()) { 00472 return *this; 00473 } 00474 00475 int pipeline_stage = current_thread->get_pipeline_stage(); 00476 00477 NodePathComponent *comp = _head; 00478 while (!comp->is_top_node(pipeline_stage, current_thread)) { 00479 comp = comp->get_next(pipeline_stage, current_thread); 00480 nassertr(comp != (NodePathComponent *)NULL, NodePath::fail()); 00481 } 00482 00483 NodePath top; 00484 top._head = comp; 00485 return top; 00486 } 00487 00488 00489 //////////////////////////////////////////////////////////////////// 00490 // Function: NodePath::get_children 00491 // Access: Published 00492 // Description: Returns the set of all child nodes of the referenced 00493 // node. 00494 //////////////////////////////////////////////////////////////////// 00495 NodePathCollection NodePath:: 00496 get_children(Thread *current_thread) const { 00497 NodePathCollection result; 00498 nassertr_always(!is_empty(), result); 00499 00500 PandaNode *bottom_node = node(); 00501 00502 int pipeline_stage = current_thread->get_pipeline_stage(); 00503 00504 PandaNode::Children cr = bottom_node->get_children(); 00505 int num_children = cr.get_num_children(); 00506 for (int i = 0; i < num_children; i++) { 00507 NodePath child; 00508 child._head = PandaNode::get_component(_head, cr.get_child(i), 00509 pipeline_stage, current_thread); 00510 result.add_path(child); 00511 } 00512 00513 return result; 00514 } 00515 00516 //////////////////////////////////////////////////////////////////// 00517 // Function: NodePath::get_stashed_children 00518 // Access: Published 00519 // Description: Returns the set of all child nodes of the referenced 00520 // node that have been stashed. These children are not 00521 // normally visible on the node, and do not appear in 00522 // the list returned by get_children(). 00523 //////////////////////////////////////////////////////////////////// 00524 NodePathCollection NodePath:: 00525 get_stashed_children(Thread *current_thread) const { 00526 NodePathCollection result; 00527 nassertr_always(!is_empty(), result); 00528 00529 PandaNode *bottom_node = node(); 00530 00531 int pipeline_stage = current_thread->get_pipeline_stage(); 00532 00533 int num_stashed = bottom_node->get_num_stashed(); 00534 for (int i = 0; i < num_stashed; i++) { 00535 NodePath stashed; 00536 stashed._head = PandaNode::get_component(_head, bottom_node->get_stashed(i), 00537 pipeline_stage, current_thread); 00538 result.add_path(stashed); 00539 } 00540 00541 return result; 00542 } 00543 00544 //////////////////////////////////////////////////////////////////// 00545 // Function: NodePath::get_sort 00546 // Access: Published 00547 // Description: Returns the sort value of the referenced node within 00548 // its parent; that is, the sort number passed on the 00549 // last reparenting operation for this node. This will 00550 // control the position of the node within its parent's 00551 // list of children. 00552 //////////////////////////////////////////////////////////////////// 00553 int NodePath:: 00554 get_sort(Thread *current_thread) const { 00555 if (!has_parent()) { 00556 return 0; 00557 } 00558 00559 int pipeline_stage = current_thread->get_pipeline_stage(); 00560 00561 PandaNode *parent = _head->get_next(pipeline_stage, current_thread)->get_node(); 00562 PandaNode *child = node(); 00563 nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0); 00564 int child_index = parent->find_child(child); 00565 if (child_index != -1) { 00566 return parent->get_child_sort(child_index); 00567 } 00568 00569 child_index = parent->find_stashed(child); 00570 if (child_index != -1) { 00571 return parent->get_stashed_sort(child_index); 00572 } 00573 00574 nassertr(false, 0); 00575 return 0; 00576 } 00577 00578 //////////////////////////////////////////////////////////////////// 00579 // Function: NodePath::find 00580 // Access: Published 00581 // Description: Searches for a node below the referenced node that 00582 // matches the indicated string. Returns the shortest 00583 // match found, if any, or an empty NodePath if no match 00584 // can be found. 00585 //////////////////////////////////////////////////////////////////// 00586 NodePath NodePath:: 00587 find(const string &path) const { 00588 nassertr_always(!is_empty(), fail()); 00589 00590 NodePathCollection col; 00591 find_matches(col, path, 1); 00592 00593 if (col.is_empty()) { 00594 return NodePath::not_found(); 00595 } 00596 00597 return col.get_path(0); 00598 } 00599 00600 //////////////////////////////////////////////////////////////////// 00601 // Function: NodePath::find_path_to 00602 // Access: Published 00603 // Description: Searches for the indicated node below this node and 00604 // returns the shortest NodePath that connects them. 00605 //////////////////////////////////////////////////////////////////// 00606 NodePath NodePath:: 00607 find_path_to(PandaNode *node) const { 00608 nassertr_always(!is_empty(), fail()); 00609 nassertr(node != (PandaNode *)NULL, fail()); 00610 00611 NodePathCollection col; 00612 FindApproxPath approx_path; 00613 approx_path.add_match_many(0); 00614 approx_path.add_match_pointer(node, 0); 00615 find_matches(col, approx_path, 1); 00616 00617 if (col.is_empty()) { 00618 return NodePath::not_found(); 00619 } 00620 00621 return col.get_path(0); 00622 } 00623 00624 //////////////////////////////////////////////////////////////////// 00625 // Function: NodePath::find_all_matches 00626 // Access: Published 00627 // Description: Returns the complete set of all NodePaths that begin 00628 // with this NodePath and can be extended by 00629 // path. The shortest paths will be listed 00630 // first. 00631 //////////////////////////////////////////////////////////////////// 00632 NodePathCollection NodePath:: 00633 find_all_matches(const string &path) const { 00634 NodePathCollection col; 00635 nassertr_always(!is_empty(), col); 00636 nassertr(verify_complete(), col); 00637 find_matches(col, path, -1); 00638 return col; 00639 } 00640 00641 //////////////////////////////////////////////////////////////////// 00642 // Function: NodePath::find_all_paths_to 00643 // Access: Published 00644 // Description: Returns the set of all NodePaths that extend from 00645 // this NodePath down to the indicated node. The 00646 // shortest paths will be listed first. 00647 //////////////////////////////////////////////////////////////////// 00648 NodePathCollection NodePath:: 00649 find_all_paths_to(PandaNode *node) const { 00650 NodePathCollection col; 00651 nassertr_always(!is_empty(), col); 00652 nassertr(verify_complete(), col); 00653 nassertr(node != (PandaNode *)NULL, col); 00654 FindApproxPath approx_path; 00655 approx_path.add_match_many(0); 00656 approx_path.add_match_pointer(node, 0); 00657 find_matches(col, approx_path, -1); 00658 return col; 00659 } 00660 00661 //////////////////////////////////////////////////////////////////// 00662 // Function: NodePath::reparent_to 00663 // Access: Published 00664 // Description: Removes the referenced node of the NodePath from its 00665 // current parent and attaches it to the referenced node 00666 // of the indicated NodePath. 00667 // 00668 // If the destination NodePath is empty, this is the 00669 // same thing as detach_node(). 00670 // 00671 // If the referenced node is already a child of the 00672 // indicated NodePath (via some other instance), this 00673 // operation fails and leaves the NodePath detached. 00674 //////////////////////////////////////////////////////////////////// 00675 void NodePath:: 00676 reparent_to(const NodePath &other, int sort, Thread *current_thread) { 00677 nassertv(verify_complete()); 00678 nassertv(other.verify_complete()); 00679 nassertv_always(!is_empty()); 00680 nassertv(other._error_type == ET_ok); 00681 00682 // Reparenting implicitly resets the delta vector. 00683 node()->reset_prev_transform(); 00684 00685 int pipeline_stage = current_thread->get_pipeline_stage(); 00686 bool reparented = PandaNode::reparent(other._head, _head, sort, false, 00687 pipeline_stage, current_thread); 00688 nassertv(reparented); 00689 } 00690 00691 //////////////////////////////////////////////////////////////////// 00692 // Function: NodePath::stash_to 00693 // Access: Published 00694 // Description: Similar to reparent_to(), but the node is added to 00695 // its new parent's stashed list, so that the result is 00696 // equivalent to calling reparent_to() immediately 00697 // followed by stash(). 00698 //////////////////////////////////////////////////////////////////// 00699 void NodePath:: 00700 stash_to(const NodePath &other, int sort, Thread *current_thread) { 00701 nassertv(verify_complete()); 00702 nassertv(other.verify_complete()); 00703 nassertv_always(!is_empty()); 00704 nassertv(other._error_type == ET_ok); 00705 00706 // Reparenting implicitly resets the delta vector. 00707 node()->reset_prev_transform(); 00708 00709 int pipeline_stage = current_thread->get_pipeline_stage(); 00710 bool reparented = PandaNode::reparent(other._head, _head, sort, true, 00711 pipeline_stage, current_thread); 00712 nassertv(reparented); 00713 } 00714 00715 //////////////////////////////////////////////////////////////////// 00716 // Function: NodePath::wrt_reparent_to 00717 // Access: Published 00718 // Description: This functions identically to reparent_to(), except 00719 // the transform on this node is also adjusted so that 00720 // the node remains in the same place in world 00721 // coordinates, even if it is reparented into a 00722 // different coordinate system. 00723 //////////////////////////////////////////////////////////////////// 00724 void NodePath:: 00725 wrt_reparent_to(const NodePath &other, int sort, Thread *current_thread) { 00726 nassertv(verify_complete(current_thread)); 00727 nassertv(other.verify_complete(current_thread)); 00728 nassertv_always(!is_empty()); 00729 nassertv(other._error_type == ET_ok); 00730 00731 if (get_transform(current_thread) == get_prev_transform(current_thread)) { 00732 set_transform(get_transform(other, current_thread), current_thread); 00733 node()->reset_prev_transform(current_thread); 00734 } else { 00735 set_transform(get_transform(other, current_thread), current_thread); 00736 set_prev_transform(get_prev_transform(other, current_thread), current_thread); 00737 } 00738 00739 reparent_to(other, sort, current_thread); 00740 } 00741 00742 //////////////////////////////////////////////////////////////////// 00743 // Function: NodePath::instance_to 00744 // Access: Published 00745 // Description: Adds the referenced node of the NodePath as a child 00746 // of the referenced node of the indicated other 00747 // NodePath. Any other parent-child relations of the 00748 // node are unchanged; in particular, the node is not 00749 // removed from its existing parent, if any. 00750 // 00751 // If the node already had an existing parent, this 00752 // method will create a new instance of the node within 00753 // the scene graph. 00754 // 00755 // This does not change the NodePath itself, but does 00756 // return a new NodePath that reflects the new instance 00757 // node. 00758 // 00759 // If the destination NodePath is empty, this creates a 00760 // new instance which is not yet parented to any node. 00761 // A new instance of this sort cannot easily be 00762 // differentiated from other similar instances, but it 00763 // is nevertheless a different instance and it will 00764 // return a different get_id() value. 00765 // 00766 // If the referenced node is already a child of the 00767 // indicated NodePath, returns that already-existing 00768 // instance, unstashing it first if necessary. 00769 //////////////////////////////////////////////////////////////////// 00770 NodePath NodePath:: 00771 instance_to(const NodePath &other, int sort, Thread *current_thread) const { 00772 nassertr(verify_complete(), NodePath::fail()); 00773 nassertr(other.verify_complete(), NodePath::fail()); 00774 nassertr_always(!is_empty(), NodePath::fail()); 00775 nassertr(other._error_type == ET_ok, NodePath::fail()); 00776 00777 NodePath new_instance; 00778 00779 // First, we'll attach to NULL, to guarantee we get a brand new 00780 // instance. 00781 int pipeline_stage = current_thread->get_pipeline_stage(); 00782 new_instance._head = PandaNode::attach(NULL, node(), sort, pipeline_stage, 00783 current_thread); 00784 00785 // Now, we'll reparent the new instance to the target node. 00786 bool reparented = PandaNode::reparent(other._head, new_instance._head, 00787 sort, false, pipeline_stage, 00788 current_thread); 00789 if (!reparented) { 00790 // Hmm, couldn't reparent. Either making this instance would 00791 // create a cycle, or it was already a child of that node. If it 00792 // was already a child, return that existing NodePath instead. 00793 NodePath orig(other, node(), current_thread); 00794 if (!orig.is_empty()) { 00795 if (orig.is_stashed()) { 00796 orig.unstash(); 00797 } 00798 return orig; 00799 } 00800 00801 // Nope, it must be a cycle. 00802 nassertr(reparented, new_instance); 00803 } 00804 00805 // instance_to() doesn't reset the velocity delta, unlike most of 00806 // the other reparenting operations. The reasoning is that 00807 // instance_to() is not necessarily a reparenting operation, since 00808 // it doesn't change the original instance. 00809 00810 return new_instance; 00811 } 00812 00813 //////////////////////////////////////////////////////////////////// 00814 // Function: NodePath::instance_under_node 00815 // Access: Published 00816 // Description: Behaves like instance_to(), but implicitly creates a 00817 // new node to instance the geometry under, and returns a 00818 // NodePath to that new node. This allows the 00819 // programmer to set a unique state and/or transform on 00820 // this instance. 00821 //////////////////////////////////////////////////////////////////// 00822 NodePath NodePath:: 00823 instance_under_node(const NodePath &other, const string &name, int sort, 00824 Thread *current_thread) const { 00825 NodePath new_node = other.attach_new_node(name, sort, current_thread); 00826 NodePath instance = instance_to(new_node, 0, current_thread); 00827 if (instance.is_empty()) { 00828 new_node.remove_node(current_thread); 00829 return instance; 00830 } 00831 return new_node; 00832 } 00833 00834 //////////////////////////////////////////////////////////////////// 00835 // Function: NodePath::copy_to 00836 // Access: Published 00837 // Description: Functions like instance_to(), except a deep 00838 // copy is made of the referenced node and all of its 00839 // descendents, which is then parented to the indicated 00840 // node. A NodePath to the newly created copy is 00841 // returned. 00842 //////////////////////////////////////////////////////////////////// 00843 NodePath NodePath:: 00844 copy_to(const NodePath &other, int sort, Thread *current_thread) const { 00845 nassertr(verify_complete(current_thread), fail()); 00846 nassertr(other.verify_complete(current_thread), fail()); 00847 nassertr_always(!is_empty(), fail()); 00848 nassertr(other._error_type == ET_ok, fail()); 00849 00850 PandaNode *source_node = node(); 00851 PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread); 00852 nassertr(copy_node != (PandaNode *)NULL, fail()); 00853 00854 copy_node->reset_prev_transform(current_thread); 00855 00856 return other.attach_new_node(copy_node, sort, current_thread); 00857 } 00858 00859 //////////////////////////////////////////////////////////////////// 00860 // Function: NodePath::attach_new_node 00861 // Access: Published 00862 // Description: Attaches a new node, with or without existing 00863 // parents, to the scene graph below the referenced node 00864 // of this NodePath. This is the preferred way to add 00865 // nodes to the graph. 00866 // 00867 // If the node was already a child of the parent, this 00868 // returns a NodePath to the existing child. 00869 // 00870 // This does *not* automatically extend the current 00871 // NodePath to reflect the attachment; however, a 00872 // NodePath that does reflect this extension is 00873 // returned. 00874 //////////////////////////////////////////////////////////////////// 00875 NodePath NodePath:: 00876 attach_new_node(PandaNode *node, int sort, Thread *current_thread) const { 00877 nassertr(verify_complete(current_thread), NodePath::fail()); 00878 nassertr(_error_type == ET_ok, NodePath::fail()); 00879 nassertr(node != (PandaNode *)NULL, NodePath::fail()); 00880 00881 NodePath new_path(*this); 00882 int pipeline_stage = current_thread->get_pipeline_stage(); 00883 new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage, 00884 current_thread); 00885 return new_path; 00886 } 00887 00888 //////////////////////////////////////////////////////////////////// 00889 // Function: NodePath::remove_node 00890 // Access: Published 00891 // Description: Disconnects the referenced node from the scene graph. 00892 // This will also delete the node if there are no other 00893 // pointers to it. 00894 // 00895 // Normally, this should be called only when you are 00896 // really done with the node. If you want to remove a 00897 // node from the scene graph but keep it around for 00898 // later, you should probably use detach_node() instead. 00899 // 00900 // In practice, the only difference between 00901 // remove_node() and detach_node() is that remove_node() 00902 // also resets the NodePath to empty, which will cause 00903 // the node to be deleted immediately if there are no 00904 // other references. On the other hand, detach_node() 00905 // leaves the NodePath referencing the node, which will 00906 // keep at least one reference to the node for as long 00907 // as the NodePath exists. 00908 //////////////////////////////////////////////////////////////////// 00909 void NodePath:: 00910 remove_node(Thread *current_thread) { 00911 nassertv(_error_type != ET_not_found); 00912 00913 // If we have no parents, remove_node() is just a do-nothing 00914 // operation; if we have no nodes, maybe we were already removed. 00915 // In either case, quietly do nothing except to ensure the 00916 // NodePath is clear. 00917 if (!is_empty() && !is_singleton(current_thread)) { 00918 node()->reset_prev_transform(current_thread); 00919 int pipeline_stage = current_thread->get_pipeline_stage(); 00920 PandaNode::detach(_head, pipeline_stage, current_thread); 00921 } 00922 00923 if (is_empty() || _head->has_key()) { 00924 // Preserve the key we had on the node before we removed it. 00925 int key = get_key(); 00926 (*this) = NodePath::removed(); 00927 _backup_key = key; 00928 00929 } else { 00930 // We didn't have a key; just clear the NodePath. 00931 (*this) = NodePath::removed(); 00932 } 00933 } 00934 00935 //////////////////////////////////////////////////////////////////// 00936 // Function: NodePath::detach_node 00937 // Access: Published 00938 // Description: Disconnects the referenced node from its parent, but 00939 // does not immediately delete it. The NodePath retains 00940 // a pointer to the node, and becomes a singleton 00941 // NodePath. 00942 // 00943 // This should be called to detach a node from the scene 00944 // graph, with the option of reattaching it later to the 00945 // same parent or to a different parent. 00946 // 00947 // In practice, the only difference between 00948 // remove_node() and detach_node() is that remove_node() 00949 // also resets the NodePath to empty, which will cause 00950 // the node to be deleted immediately if there are no 00951 // other references. On the other hand, detach_node() 00952 // leaves the NodePath referencing the node, which will 00953 // keep at least one reference to the node for as long 00954 // as the NodePath exists. 00955 //////////////////////////////////////////////////////////////////// 00956 void NodePath:: 00957 detach_node(Thread *current_thread) { 00958 nassertv(_error_type != ET_not_found); 00959 if (!is_empty() && !is_singleton()) { 00960 node()->reset_prev_transform(); 00961 int pipeline_stage = current_thread->get_pipeline_stage(); 00962 PandaNode::detach(_head, pipeline_stage, current_thread); 00963 } 00964 } 00965 00966 //////////////////////////////////////////////////////////////////// 00967 // Function: NodePath::output 00968 // Access: Published 00969 // Description: Writes a sensible description of the NodePath to the 00970 // indicated output stream. 00971 //////////////////////////////////////////////////////////////////// 00972 void NodePath:: 00973 output(ostream &out) const { 00974 switch (_error_type) { 00975 case ET_not_found: 00976 out << "**not found**"; 00977 return; 00978 case ET_removed: 00979 out << "**removed**"; 00980 return; 00981 case ET_fail: 00982 out << "**error**"; 00983 return; 00984 default: 00985 break; 00986 } 00987 00988 if (_head == (NodePathComponent *)NULL) { 00989 out << "(empty)"; 00990 } else { 00991 _head->output(out); 00992 } 00993 } 00994 00995 //////////////////////////////////////////////////////////////////// 00996 // Function: NodePath::get_state 00997 // Access: Published 00998 // Description: Returns the complete state object set on this node. 00999 //////////////////////////////////////////////////////////////////// 01000 const RenderState *NodePath:: 01001 get_state(Thread *current_thread) const { 01002 // This method is declared non-inline to avoid a compiler bug in 01003 // gcc-3.4 and gcc-4.0. 01004 nassertr_always(!is_empty(), RenderState::make_empty()); 01005 return node()->get_state(current_thread); 01006 } 01007 01008 //////////////////////////////////////////////////////////////////// 01009 // Function: NodePath::get_state 01010 // Access: Published 01011 // Description: Returns the state changes that must be made to 01012 // transition to the render state of this node from the 01013 // render state of the other node. 01014 //////////////////////////////////////////////////////////////////// 01015 CPT(RenderState) NodePath:: 01016 get_state(const NodePath &other, Thread *current_thread) const { 01017 nassertr(_error_type == ET_ok && other._error_type == ET_ok, RenderState::make_empty()); 01018 01019 if (other.is_empty()) { 01020 return get_net_state(current_thread); 01021 } 01022 if (is_empty()) { 01023 return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty()); 01024 } 01025 01026 nassertr(verify_complete(current_thread), RenderState::make_empty()); 01027 nassertr(other.verify_complete(current_thread), RenderState::make_empty()); 01028 01029 int a_count, b_count; 01030 if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { 01031 if (allow_unrelated_wrt) { 01032 pgraph_cat.debug() 01033 << *this << " is not related to " << other << "\n"; 01034 } else { 01035 pgraph_cat.error() 01036 << *this << " is not related to " << other << "\n"; 01037 nassertr(false, RenderState::make_empty()); 01038 } 01039 } 01040 01041 CPT(RenderState) a_state = r_get_partial_state(_head, a_count, current_thread); 01042 CPT(RenderState) b_state = r_get_partial_state(other._head, b_count, current_thread); 01043 return b_state->invert_compose(a_state); 01044 } 01045 01046 //////////////////////////////////////////////////////////////////// 01047 // Function: NodePath::set_state 01048 // Access: Published 01049 // Description: Sets the state object on this node, relative to 01050 // the other node. This computes a new state object 01051 // that will have the indicated value when seen from the 01052 // other node. 01053 //////////////////////////////////////////////////////////////////// 01054 void NodePath:: 01055 set_state(const NodePath &other, const RenderState *state, 01056 Thread *current_thread) { 01057 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 01058 nassertv_always(!is_empty()); 01059 01060 // First, we perform a wrt to the parent, to get the conversion. 01061 CPT(RenderState) rel_state; 01062 if (has_parent()) { 01063 rel_state = other.get_state(get_parent(current_thread), current_thread); 01064 } else { 01065 rel_state = other.get_state(NodePath(), current_thread); 01066 } 01067 01068 CPT(RenderState) new_state = rel_state->compose(state); 01069 set_state(new_state, current_thread); 01070 } 01071 01072 //////////////////////////////////////////////////////////////////// 01073 // Function: NodePath::get_transform 01074 // Access: Published 01075 // Description: Returns the complete transform object set on this node. 01076 //////////////////////////////////////////////////////////////////// 01077 const TransformState *NodePath:: 01078 get_transform(Thread *current_thread) const { 01079 // This method is declared non-inline to avoid a compiler bug in 01080 // gcc-3.4 and gcc-4.0. 01081 nassertr_always(!is_empty(), TransformState::make_identity()); 01082 return node()->get_transform(current_thread); 01083 } 01084 01085 //////////////////////////////////////////////////////////////////// 01086 // Function: NodePath::get_transform 01087 // Access: Published 01088 // Description: Returns the relative transform to this node from the 01089 // other node; i.e. the transformation of this node 01090 // as seen from the other node. 01091 //////////////////////////////////////////////////////////////////// 01092 CPT(TransformState) NodePath:: 01093 get_transform(const NodePath &other, Thread *current_thread) const { 01094 nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity()); 01095 static PStatCollector _get_transform_pcollector("*:NodePath:get_transform"); 01096 PStatTimer timer(_get_transform_pcollector); 01097 01098 if (other.is_empty()) { 01099 return get_net_transform(current_thread); 01100 } 01101 if (is_empty()) { 01102 return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity()); 01103 } 01104 01105 nassertr(verify_complete(current_thread), TransformState::make_identity()); 01106 nassertr(other.verify_complete(current_thread), TransformState::make_identity()); 01107 01108 int a_count, b_count; 01109 if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { 01110 if (allow_unrelated_wrt) { 01111 if (pgraph_cat.is_debug()) { 01112 pgraph_cat.debug() 01113 << *this << " is not related to " << other << "\n"; 01114 } 01115 } else { 01116 pgraph_cat.error() 01117 << *this << " is not related to " << other << "\n"; 01118 nassertr(false, TransformState::make_identity()); 01119 } 01120 } 01121 01122 CPT(TransformState) a_transform, b_transform; 01123 01124 a_transform = r_get_partial_transform(_head, a_count, current_thread); 01125 if (a_transform != (TransformState *)NULL) { 01126 b_transform = r_get_partial_transform(other._head, b_count, current_thread); 01127 } 01128 if (b_transform == (TransformState *)NULL) { 01129 // If either path involved a node with a net_transform 01130 // RenderEffect applied, we have to go all the way up to the root 01131 // to get the right answer. 01132 a_transform = r_get_net_transform(_head, current_thread); 01133 b_transform = r_get_net_transform(other._head, current_thread); 01134 } 01135 01136 return b_transform->invert_compose(a_transform); 01137 } 01138 01139 //////////////////////////////////////////////////////////////////// 01140 // Function: NodePath::set_transform 01141 // Access: Published 01142 // Description: Sets the transform object on this node, relative to 01143 // the other node. This computes a new transform object 01144 // that will have the indicated value when seen from the 01145 // other node. 01146 //////////////////////////////////////////////////////////////////// 01147 void NodePath:: 01148 set_transform(const NodePath &other, const TransformState *transform, 01149 Thread *current_thread) { 01150 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 01151 nassertv_always(!is_empty()); 01152 01153 // First, we perform a wrt to the parent, to get the conversion. 01154 CPT(TransformState) rel_trans; 01155 if (has_parent()) { 01156 rel_trans = other.get_transform(get_parent(current_thread), current_thread); 01157 } else { 01158 rel_trans = other.get_transform(NodePath(), current_thread); 01159 } 01160 01161 CPT(TransformState) new_trans = rel_trans->compose(transform); 01162 set_transform(new_trans, current_thread); 01163 } 01164 01165 //////////////////////////////////////////////////////////////////// 01166 // Function: NodePath::get_prev_transform 01167 // Access: Published 01168 // Description: Returns the transform that has been set as this 01169 // node's "previous" position. See 01170 // set_prev_transform(). 01171 //////////////////////////////////////////////////////////////////// 01172 const TransformState *NodePath:: 01173 get_prev_transform(Thread *current_thread) const { 01174 // This method is declared non-inline to avoid a compiler bug in 01175 // gcc-3.4 and gcc-4.0. 01176 nassertr_always(!is_empty(), TransformState::make_identity()); 01177 return node()->get_prev_transform(current_thread); 01178 } 01179 01180 //////////////////////////////////////////////////////////////////// 01181 // Function: NodePath::get_prev_transform 01182 // Access: Published 01183 // Description: Returns the relative "previous" transform to this 01184 // node from the other node; i.e. the position of this 01185 // node in the previous frame, as seen by the other node 01186 // in the previous frame. 01187 //////////////////////////////////////////////////////////////////// 01188 CPT(TransformState) NodePath:: 01189 get_prev_transform(const NodePath &other, Thread *current_thread) const { 01190 nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity()); 01191 01192 if (other.is_empty()) { 01193 return get_net_prev_transform(current_thread); 01194 } 01195 if (is_empty()) { 01196 return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity()); 01197 } 01198 01199 nassertr(verify_complete(current_thread), TransformState::make_identity()); 01200 nassertr(other.verify_complete(current_thread), TransformState::make_identity()); 01201 01202 int a_count, b_count; 01203 if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { 01204 if (allow_unrelated_wrt) { 01205 pgraph_cat.debug() 01206 << *this << " is not related to " << other << "\n"; 01207 } else { 01208 pgraph_cat.error() 01209 << *this << " is not related to " << other << "\n"; 01210 nassertr(false, TransformState::make_identity()); 01211 } 01212 } 01213 01214 CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count, current_thread); 01215 CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count, current_thread); 01216 return b_prev_transform->invert_compose(a_prev_transform); 01217 } 01218 01219 //////////////////////////////////////////////////////////////////// 01220 // Function: NodePath::set_prev_transform 01221 // Access: Published 01222 // Description: Sets the "previous" transform object on this node, 01223 // relative to the other node. This computes a new 01224 // transform object that will have the indicated value 01225 // when seen from the other node. 01226 //////////////////////////////////////////////////////////////////// 01227 void NodePath:: 01228 set_prev_transform(const NodePath &other, const TransformState *transform, 01229 Thread *current_thread) { 01230 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 01231 nassertv_always(!is_empty()); 01232 01233 // First, we perform a wrt to the parent, to get the conversion. 01234 CPT(TransformState) rel_trans; 01235 if (has_parent(current_thread)) { 01236 rel_trans = other.get_prev_transform(get_parent(current_thread), current_thread); 01237 } else { 01238 rel_trans = other.get_prev_transform(NodePath(), current_thread); 01239 } 01240 01241 CPT(TransformState) new_trans = rel_trans->compose(transform); 01242 set_prev_transform(new_trans, current_thread); 01243 } 01244 01245 //////////////////////////////////////////////////////////////////// 01246 // Function: NodePath::set_pos 01247 // Access: Published 01248 // Description: Sets the translation component of the transform, 01249 // leaving rotation and scale untouched. This also 01250 // resets the node's "previous" position, so that the 01251 // collision system will see the node as having suddenly 01252 // appeared in the new position, without passing any 01253 // points in between. 01254 // See Also: NodePath::set_fluid_pos 01255 //////////////////////////////////////////////////////////////////// 01256 void NodePath:: 01257 set_pos(const LVecBase3f &pos) { 01258 nassertv_always(!is_empty()); 01259 set_transform(get_transform()->set_pos(pos)); 01260 node()->reset_prev_transform(); 01261 } 01262 01263 void NodePath:: 01264 set_x(float x) { 01265 nassertv_always(!is_empty()); 01266 LPoint3f pos = get_pos(); 01267 pos[0] = x; 01268 set_pos(pos); 01269 } 01270 01271 void NodePath:: 01272 set_y(float y) { 01273 nassertv_always(!is_empty()); 01274 LPoint3f pos = get_pos(); 01275 pos[1] = y; 01276 set_pos(pos); 01277 } 01278 01279 void NodePath:: 01280 set_z(float z) { 01281 nassertv_always(!is_empty()); 01282 LPoint3f pos = get_pos(); 01283 pos[2] = z; 01284 set_pos(pos); 01285 } 01286 01287 //////////////////////////////////////////////////////////////////// 01288 // Function: NodePath::set_fluid_pos 01289 // Access: Published 01290 // Description: Sets the translation component, without changing the 01291 // "previous" position, so that the collision system 01292 // will see the node as moving fluidly from its previous 01293 // position to its new position. 01294 // See Also: NodePath::set_pos 01295 //////////////////////////////////////////////////////////////////// 01296 void NodePath:: 01297 set_fluid_pos(const LVecBase3f &pos) { 01298 nassertv_always(!is_empty()); 01299 set_transform(get_transform()->set_pos(pos)); 01300 } 01301 01302 void NodePath:: 01303 set_fluid_x(float x) { 01304 nassertv_always(!is_empty()); 01305 LPoint3f pos = get_pos(); 01306 pos[0] = x; 01307 set_fluid_pos(pos); 01308 } 01309 01310 void NodePath:: 01311 set_fluid_y(float y) { 01312 nassertv_always(!is_empty()); 01313 LPoint3f pos = get_pos(); 01314 pos[1] = y; 01315 set_fluid_pos(pos); 01316 } 01317 01318 void NodePath:: 01319 set_fluid_z(float z) { 01320 nassertv_always(!is_empty()); 01321 LPoint3f pos = get_pos(); 01322 pos[2] = z; 01323 set_fluid_pos(pos); 01324 } 01325 01326 //////////////////////////////////////////////////////////////////// 01327 // Function: NodePath::get_pos 01328 // Access: Published 01329 // Description: Retrieves the translation component of the transform. 01330 //////////////////////////////////////////////////////////////////// 01331 LPoint3f NodePath:: 01332 get_pos() const { 01333 nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); 01334 return get_transform()->get_pos(); 01335 } 01336 01337 //////////////////////////////////////////////////////////////////// 01338 // Function: NodePath::get_pos_delta 01339 // Access: Published 01340 // Description: Returns the delta vector from this node's position in 01341 // the previous frame (according to 01342 // set_prev_transform(), typically set via the use of 01343 // set_fluid_pos()) and its position in the current 01344 // frame. This is the vector used to determine 01345 // collisions. Generally, if the node was last 01346 // repositioned via set_pos(), the delta will be zero; 01347 // if it was adjusted via set_fluid_pos(), the delta 01348 // will represent the change from the previous frame's 01349 // position. 01350 //////////////////////////////////////////////////////////////////// 01351 LVector3f NodePath:: 01352 get_pos_delta() const { 01353 nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); 01354 return get_transform()->get_pos() - get_prev_transform()->get_pos(); 01355 } 01356 01357 //////////////////////////////////////////////////////////////////// 01358 // Function: NodePath::set_hpr 01359 // Access: Published 01360 // Description: Sets the rotation component of the transform, 01361 // leaving translation and scale untouched. 01362 //////////////////////////////////////////////////////////////////// 01363 void NodePath:: 01364 set_hpr(const LVecBase3f &hpr) { 01365 nassertv_always(!is_empty()); 01366 CPT(TransformState) transform = get_transform(); 01367 nassertv(transform->has_hpr()); 01368 set_transform(transform->set_hpr(hpr)); 01369 } 01370 01371 void NodePath:: 01372 set_h(float h) { 01373 nassertv_always(!is_empty()); 01374 CPT(TransformState) transform = get_transform(); 01375 nassertv(transform->has_hpr()); 01376 LVecBase3f hpr = transform->get_hpr(); 01377 hpr[0] = h; 01378 set_transform(transform->set_hpr(hpr)); 01379 } 01380 01381 void NodePath:: 01382 set_p(float p) { 01383 nassertv_always(!is_empty()); 01384 CPT(TransformState) transform = get_transform(); 01385 nassertv(transform->has_hpr()); 01386 LVecBase3f hpr = transform->get_hpr(); 01387 hpr[1] = p; 01388 set_transform(transform->set_hpr(hpr)); 01389 } 01390 01391 void NodePath:: 01392 set_r(float r) { 01393 nassertv_always(!is_empty()); 01394 CPT(TransformState) transform = get_transform(); 01395 nassertv(transform->has_hpr()); 01396 LVecBase3f hpr = transform->get_hpr(); 01397 hpr[2] = r; 01398 set_transform(transform->set_hpr(hpr)); 01399 } 01400 01401 //////////////////////////////////////////////////////////////////// 01402 // Function: NodePath::get_hpr 01403 // Access: Published 01404 // Description: Retrieves the rotation component of the transform. 01405 //////////////////////////////////////////////////////////////////// 01406 LVecBase3f NodePath:: 01407 get_hpr() const { 01408 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); 01409 CPT(TransformState) transform = get_transform(); 01410 nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f)); 01411 return transform->get_hpr(); 01412 } 01413 01414 //////////////////////////////////////////////////////////////////// 01415 // Function: NodePath::set_quat 01416 // Access: Published 01417 // Description: Sets the rotation component of the transform, 01418 // leaving translation and scale untouched. 01419 //////////////////////////////////////////////////////////////////// 01420 void NodePath:: 01421 set_quat(const LQuaternionf &quat) { 01422 nassertv_always(!is_empty()); 01423 CPT(TransformState) transform = get_transform(); 01424 set_transform(transform->set_quat(quat)); 01425 } 01426 01427 //////////////////////////////////////////////////////////////////// 01428 // Function: NodePath::get_quat 01429 // Access: Published 01430 // Description: Retrieves the rotation component of the transform. 01431 //////////////////////////////////////////////////////////////////// 01432 LQuaternionf NodePath:: 01433 get_quat() const { 01434 nassertr_always(!is_empty(), LQuaternionf::ident_quat()); 01435 CPT(TransformState) transform = get_transform(); 01436 return transform->get_quat(); 01437 } 01438 01439 //////////////////////////////////////////////////////////////////// 01440 // Function: NodePath::set_scale 01441 // Access: Published 01442 // Description: Sets the scale component of the transform, 01443 // leaving translation and rotation untouched. 01444 //////////////////////////////////////////////////////////////////// 01445 void NodePath:: 01446 set_scale(const LVecBase3f &scale) { 01447 nassertv_always(!is_empty()); 01448 CPT(TransformState) transform = get_transform(); 01449 set_transform(transform->set_scale(scale)); 01450 } 01451 01452 void NodePath:: 01453 set_sx(float sx) { 01454 nassertv_always(!is_empty()); 01455 CPT(TransformState) transform = get_transform(); 01456 LVecBase3f scale = transform->get_scale(); 01457 scale[0] = sx; 01458 set_transform(transform->set_scale(scale)); 01459 } 01460 01461 void NodePath:: 01462 set_sy(float sy) { 01463 nassertv_always(!is_empty()); 01464 CPT(TransformState) transform = get_transform(); 01465 LVecBase3f scale = transform->get_scale(); 01466 scale[1] = sy; 01467 set_transform(transform->set_scale(scale)); 01468 } 01469 01470 void NodePath:: 01471 set_sz(float sz) { 01472 nassertv_always(!is_empty()); 01473 CPT(TransformState) transform = get_transform(); 01474 LVecBase3f scale = transform->get_scale(); 01475 scale[2] = sz; 01476 set_transform(transform->set_scale(scale)); 01477 } 01478 01479 //////////////////////////////////////////////////////////////////// 01480 // Function: NodePath::get_scale 01481 // Access: Published 01482 // Description: Retrieves the scale component of the transform. 01483 //////////////////////////////////////////////////////////////////// 01484 LVecBase3f NodePath:: 01485 get_scale() const { 01486 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); 01487 CPT(TransformState) transform = get_transform(); 01488 return transform->get_scale(); 01489 } 01490 01491 //////////////////////////////////////////////////////////////////// 01492 // Function: NodePath::set_shear 01493 // Access: Published 01494 // Description: Sets the shear component of the transform, 01495 // leaving translation and rotation untouched. 01496 //////////////////////////////////////////////////////////////////// 01497 void NodePath:: 01498 set_shear(const LVecBase3f &shear) { 01499 nassertv_always(!is_empty()); 01500 CPT(TransformState) transform = get_transform(); 01501 set_transform(transform->set_shear(shear)); 01502 } 01503 01504 void NodePath:: 01505 set_shxy(float shxy) { 01506 nassertv_always(!is_empty()); 01507 CPT(TransformState) transform = get_transform(); 01508 LVecBase3f shear = transform->get_shear(); 01509 shear[0] = shxy; 01510 set_transform(transform->set_shear(shear)); 01511 } 01512 01513 void NodePath:: 01514 set_shxz(float shxz) { 01515 nassertv_always(!is_empty()); 01516 CPT(TransformState) transform = get_transform(); 01517 LVecBase3f shear = transform->get_shear(); 01518 shear[1] = shxz; 01519 set_transform(transform->set_shear(shear)); 01520 } 01521 01522 void NodePath:: 01523 set_shyz(float shyz) { 01524 nassertv_always(!is_empty()); 01525 CPT(TransformState) transform = get_transform(); 01526 LVecBase3f shear = transform->get_shear(); 01527 shear[2] = shyz; 01528 set_transform(transform->set_shear(shear)); 01529 } 01530 01531 //////////////////////////////////////////////////////////////////// 01532 // Function: NodePath::get_shear 01533 // Access: Published 01534 // Description: Retrieves the shear component of the transform. 01535 //////////////////////////////////////////////////////////////////// 01536 LVecBase3f NodePath:: 01537 get_shear() const { 01538 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); 01539 CPT(TransformState) transform = get_transform(); 01540 return transform->get_shear(); 01541 } 01542 01543 //////////////////////////////////////////////////////////////////// 01544 // Function: NodePath::set_pos_hpr 01545 // Access: Published 01546 // Description: Sets the translation and rotation component of the 01547 // transform, leaving scale untouched. 01548 //////////////////////////////////////////////////////////////////// 01549 void NodePath:: 01550 set_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) { 01551 nassertv_always(!is_empty()); 01552 CPT(TransformState) transform = get_transform(); 01553 transform = TransformState::make_pos_hpr_scale_shear 01554 (pos, hpr, transform->get_scale(), transform->get_shear()); 01555 set_transform(transform); 01556 node()->reset_prev_transform(); 01557 } 01558 01559 //////////////////////////////////////////////////////////////////// 01560 // Function: NodePath::set_pos_quat 01561 // Access: Published 01562 // Description: Sets the translation and rotation component of the 01563 // transform, leaving scale untouched. 01564 //////////////////////////////////////////////////////////////////// 01565 void NodePath:: 01566 set_pos_quat(const LVecBase3f &pos, const LQuaternionf &quat) { 01567 nassertv_always(!is_empty()); 01568 CPT(TransformState) transform = get_transform(); 01569 transform = TransformState::make_pos_quat_scale_shear 01570 (pos, quat, transform->get_scale(), transform->get_shear()); 01571 set_transform(transform); 01572 node()->reset_prev_transform(); 01573 } 01574 01575 //////////////////////////////////////////////////////////////////// 01576 // Function: NodePath::set_hpr_scale 01577 // Access: Published 01578 // Description: Sets the rotation and scale components of the 01579 // transform, leaving translation untouched. 01580 //////////////////////////////////////////////////////////////////// 01581 void NodePath:: 01582 set_hpr_scale(const LVecBase3f &hpr, const LVecBase3f &scale) { 01583 nassertv_always(!is_empty()); 01584 CPT(TransformState) transform = get_transform(); 01585 transform = TransformState::make_pos_hpr_scale_shear 01586 (transform->get_pos(), hpr, scale, transform->get_shear()); 01587 set_transform(transform); 01588 } 01589 01590 //////////////////////////////////////////////////////////////////// 01591 // Function: NodePath::set_quat_scale 01592 // Access: Published 01593 // Description: Sets the rotation and scale components of the 01594 // transform, leaving translation untouched. 01595 //////////////////////////////////////////////////////////////////// 01596 void NodePath:: 01597 set_quat_scale(const LQuaternionf &quat, const LVecBase3f &scale) { 01598 nassertv_always(!is_empty()); 01599 CPT(TransformState) transform = get_transform(); 01600 transform = TransformState::make_pos_quat_scale_shear 01601 (transform->get_pos(), quat, scale, transform->get_shear()); 01602 set_transform(transform); 01603 } 01604 01605 //////////////////////////////////////////////////////////////////// 01606 // Function: NodePath::set_pos_hpr_scale 01607 // Access: Published 01608 // Description: Replaces the translation, rotation, and scale 01609 // components, implicitly setting shear to 0. 01610 //////////////////////////////////////////////////////////////////// 01611 void NodePath:: 01612 set_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr, 01613 const LVecBase3f &scale) { 01614 nassertv_always(!is_empty()); 01615 set_transform(TransformState::make_pos_hpr_scale 01616 (pos, hpr, scale)); 01617 node()->reset_prev_transform(); 01618 } 01619 01620 //////////////////////////////////////////////////////////////////// 01621 // Function: NodePath::set_pos_quat_scale 01622 // Access: Published 01623 // Description: Replaces the translation, rotation, and scale 01624 // components, implicitly setting shear to 0. 01625 //////////////////////////////////////////////////////////////////// 01626 void NodePath:: 01627 set_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat, 01628 const LVecBase3f &scale) { 01629 nassertv_always(!is_empty()); 01630 set_transform(TransformState::make_pos_quat_scale 01631 (pos, quat, scale)); 01632 node()->reset_prev_transform(); 01633 } 01634 01635 //////////////////////////////////////////////////////////////////// 01636 // Function: NodePath::set_pos_hpr_scale_shear 01637 // Access: Published 01638 // Description: Completely replaces the transform with new 01639 // translation, rotation, scale, and shear components. 01640 //////////////////////////////////////////////////////////////////// 01641 void NodePath:: 01642 set_pos_hpr_scale_shear(const LVecBase3f &pos, const LVecBase3f &hpr, 01643 const LVecBase3f &scale, const LVecBase3f &shear) { 01644 nassertv_always(!is_empty()); 01645 set_transform(TransformState::make_pos_hpr_scale_shear 01646 (pos, hpr, scale, shear)); 01647 node()->reset_prev_transform(); 01648 } 01649 01650 //////////////////////////////////////////////////////////////////// 01651 // Function: NodePath::set_pos_quat_scale_shear 01652 // Access: Published 01653 // Description: Completely replaces the transform with new 01654 // translation, rotation, scale, and shear components. 01655 //////////////////////////////////////////////////////////////////// 01656 void NodePath:: 01657 set_pos_quat_scale_shear(const LVecBase3f &pos, const LQuaternionf &quat, 01658 const LVecBase3f &scale, const LVecBase3f &shear) { 01659 nassertv_always(!is_empty()); 01660 set_transform(TransformState::make_pos_quat_scale_shear 01661 (pos, quat, scale, shear)); 01662 node()->reset_prev_transform(); 01663 } 01664 01665 //////////////////////////////////////////////////////////////////// 01666 // Function: NodePath::set_mat 01667 // Access: Published 01668 // Description: Directly sets an arbitrary 4x4 transform matrix. 01669 //////////////////////////////////////////////////////////////////// 01670 void NodePath:: 01671 set_mat(const LMatrix4f &mat) { 01672 nassertv_always(!is_empty()); 01673 set_transform(TransformState::make_mat(mat)); 01674 node()->reset_prev_transform(); 01675 } 01676 01677 //////////////////////////////////////////////////////////////////// 01678 // Function: NodePath::look_at 01679 // Access: Published 01680 // Description: Sets the hpr on this NodePath so that it 01681 // rotates to face the indicated point in space. 01682 //////////////////////////////////////////////////////////////////// 01683 void NodePath:: 01684 look_at(const LPoint3f &point, const LVector3f &up) { 01685 nassertv_always(!is_empty()); 01686 01687 LPoint3f pos = get_pos(); 01688 01689 LQuaternionf quat; 01690 ::look_at(quat, point - pos, up); 01691 set_quat(quat); 01692 } 01693 01694 //////////////////////////////////////////////////////////////////// 01695 // Function: NodePath::heads_up 01696 // Access: Published 01697 // Description: Behaves like look_at(), but with a strong preference 01698 // to keeping the up vector oriented in the indicated 01699 // "up" direction. 01700 //////////////////////////////////////////////////////////////////// 01701 void NodePath:: 01702 heads_up(const LPoint3f &point, const LVector3f &up) { 01703 nassertv_always(!is_empty()); 01704 01705 LPoint3f pos = get_pos(); 01706 01707 LQuaternionf quat; 01708 ::heads_up(quat, point - pos, up); 01709 set_quat(quat); 01710 } 01711 01712 //////////////////////////////////////////////////////////////////// 01713 // Function: NodePath::set_pos 01714 // Access: Published 01715 // Description: Sets the translation component of the transform, 01716 // relative to the other node. 01717 //////////////////////////////////////////////////////////////////// 01718 void NodePath:: 01719 set_pos(const NodePath &other, const LVecBase3f &pos) { 01720 nassertv_always(!is_empty()); 01721 CPT(TransformState) rel_transform = get_transform(other); 01722 01723 CPT(TransformState) orig_transform = get_transform(); 01724 if (orig_transform->has_components()) { 01725 // If we had a componentwise transform before we started, we 01726 // should be careful to preserve the other three components. We 01727 // wouldn't need to do this, except for the possibility of 01728 // numerical error or decompose ambiguity. 01729 const LVecBase3f &orig_hpr = orig_transform->get_hpr(); 01730 const LVecBase3f &orig_scale = orig_transform->get_scale(); 01731 const LVecBase3f &orig_shear = orig_transform->get_shear(); 01732 01733 set_transform(other, rel_transform->set_pos(pos)); 01734 set_pos_hpr_scale_shear(get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear); 01735 01736 } else { 01737 // If we didn't have a componentwise transform already, never 01738 // mind. 01739 set_transform(other, rel_transform->set_pos(pos)); 01740 } 01741 node()->reset_prev_transform(); 01742 } 01743 01744 void NodePath:: 01745 set_x(const NodePath &other, float x) { 01746 nassertv_always(!is_empty()); 01747 LPoint3f pos = get_pos(other); 01748 pos[0] = x; 01749 set_pos(other, pos); 01750 } 01751 01752 void NodePath:: 01753 set_y(const NodePath &other, float y) { 01754 nassertv_always(!is_empty()); 01755 LPoint3f pos = get_pos(other); 01756 pos[1] = y; 01757 set_pos(other, pos); 01758 } 01759 01760 void NodePath:: 01761 set_z(const NodePath &other, float z) { 01762 nassertv_always(!is_empty()); 01763 LPoint3f pos = get_pos(other); 01764 pos[2] = z; 01765 set_pos(other, pos); 01766 } 01767 01768 //////////////////////////////////////////////////////////////////// 01769 // Function: NodePath::set_fluid_pos 01770 // Access: Published 01771 // Description: Sets the translation component of the transform, 01772 // relative to the other node. 01773 //////////////////////////////////////////////////////////////////// 01774 void NodePath:: 01775 set_fluid_pos(const NodePath &other, const LVecBase3f &pos) { 01776 nassertv_always(!is_empty()); 01777 CPT(TransformState) rel_transform = get_transform(other); 01778 01779 CPT(TransformState) orig_transform = get_transform(); 01780 if (orig_transform->has_components()) { 01781 // If we had a componentwise transform before we started, we 01782 // should be careful to preserve the other three components. We 01783 // wouldn't need to do this, except for the possibility of 01784 // numerical error or decompose ambiguity. 01785 const LVecBase3f &orig_hpr = orig_transform->get_hpr(); 01786 const LVecBase3f &orig_scale = orig_transform->get_scale(); 01787 const LVecBase3f &orig_shear = orig_transform->get_shear(); 01788 01789 // Use the relative set_transform() to compute the relative pos, and 01790 // then reset all of the other components back to the way they were. 01791 set_transform(other, rel_transform->set_pos(pos)); 01792 set_transform(TransformState::make_pos_hpr_scale_shear 01793 (get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear)); 01794 01795 } else { 01796 // If we didn't have a componentwise transform already, never 01797 // mind. 01798 set_transform(other, rel_transform->set_pos(pos)); 01799 } 01800 } 01801 01802 void NodePath:: 01803 set_fluid_x(const NodePath &other, float x) { 01804 nassertv_always(!is_empty()); 01805 LPoint3f pos = get_pos(other); 01806 pos[0] = x; 01807 set_fluid_pos(other, pos); 01808 } 01809 01810 void NodePath:: 01811 set_fluid_y(const NodePath &other, float y) { 01812 nassertv_always(!is_empty()); 01813 LPoint3f pos = get_pos(other); 01814 pos[1] = y; 01815 set_fluid_pos(other, pos); 01816 } 01817 01818 void NodePath:: 01819 set_fluid_z(const NodePath &other, float z) { 01820 nassertv_always(!is_empty()); 01821 LPoint3f pos = get_pos(other); 01822 pos[2] = z; 01823 set_fluid_pos(other, pos); 01824 } 01825 01826 //////////////////////////////////////////////////////////////////// 01827 // Function: NodePath::get_pos 01828 // Access: Published 01829 // Description: Returns the relative position of the referenced node 01830 // as seen from the other node. 01831 //////////////////////////////////////////////////////////////////// 01832 LPoint3f NodePath:: 01833 get_pos(const NodePath &other) const { 01834 nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); 01835 return get_transform(other)->get_pos(); 01836 } 01837 01838 //////////////////////////////////////////////////////////////////// 01839 // Function: NodePath::get_pos_delta 01840 // Access: Published 01841 // Description: Returns the delta vector from this node's position in 01842 // the previous frame (according to 01843 // set_prev_transform(), typically set via the use of 01844 // set_fluid_pos()) and its position in the current 01845 // frame, as seen in the indicated node's coordinate 01846 // space. This is the vector used to determine 01847 // collisions. Generally, if the node was last 01848 // repositioned via set_pos(), the delta will be zero; 01849 // if it was adjusted via set_fluid_pos(), the delta 01850 // will represent the change from the previous frame's 01851 // position. 01852 //////////////////////////////////////////////////////////////////// 01853 LVector3f NodePath:: 01854 get_pos_delta(const NodePath &other) const { 01855 nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); 01856 return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos(); 01857 } 01858 01859 //////////////////////////////////////////////////////////////////// 01860 // Function: NodePath::set_hpr 01861 // Access: Published 01862 // Description: Sets the rotation component of the transform, 01863 // relative to the other node. 01864 //////////////////////////////////////////////////////////////////// 01865 void NodePath:: 01866 set_hpr(const NodePath &other, const LVecBase3f &hpr) { 01867 nassertv_always(!is_empty()); 01868 CPT(TransformState) rel_transform = get_transform(other); 01869 nassertv(rel_transform->has_hpr()); 01870 01871 CPT(TransformState) orig_transform = get_transform(); 01872 if (orig_transform->has_components()) { 01873 // If we had a componentwise transform before we started, we 01874 // should be careful to preserve the other three components. We 01875 // wouldn't need to do this, except for the possibility of 01876 // numerical error or decompose ambiguity. 01877 const LVecBase3f &orig_pos = orig_transform->get_pos(); 01878 const LVecBase3f &orig_scale = orig_transform->get_scale(); 01879 const LVecBase3f &orig_shear = orig_transform->get_shear(); 01880 01881 set_transform(other, rel_transform->set_hpr(hpr)); 01882 const TransformState *new_transform = get_transform(); 01883 if (new_transform->has_components()) { 01884 set_transform(TransformState::make_pos_hpr_scale_shear 01885 (orig_pos, new_transform->get_hpr(), orig_scale, orig_shear)); 01886 } 01887 01888 } else { 01889 // If we didn't have a componentwise transform already, never 01890 // mind. 01891 set_transform(other, rel_transform->set_hpr(hpr)); 01892 } 01893 } 01894 01895 void NodePath:: 01896 set_h(const NodePath &other, float h) { 01897 nassertv_always(!is_empty()); 01898 LVecBase3f hpr = get_hpr(other); 01899 hpr[0] = h; 01900 set_hpr(other, hpr); 01901 } 01902 01903 void NodePath:: 01904 set_p(const NodePath &other, float p) { 01905 nassertv_always(!is_empty()); 01906 LVecBase3f hpr = get_hpr(other); 01907 hpr[1] = p; 01908 set_hpr(other, hpr); 01909 } 01910 01911 void NodePath:: 01912 set_r(const NodePath &other, float r) { 01913 nassertv_always(!is_empty()); 01914 LVecBase3f hpr = get_hpr(other); 01915 hpr[2] = r; 01916 set_hpr(other, hpr); 01917 } 01918 01919 //////////////////////////////////////////////////////////////////// 01920 // Function: NodePath::get_hpr 01921 // Access: Published 01922 // Description: Returns the relative orientation of the bottom node 01923 // as seen from the other node. 01924 //////////////////////////////////////////////////////////////////// 01925 LVecBase3f NodePath:: 01926 get_hpr(const NodePath &other) const { 01927 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); 01928 CPT(TransformState) transform = get_transform(other); 01929 nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f)); 01930 return transform->get_hpr(); 01931 } 01932 01933 //////////////////////////////////////////////////////////////////// 01934 // Function: NodePath::set_quat 01935 // Access: Published 01936 // Description: Sets the rotation component of the transform, 01937 // relative to the other node. 01938 //////////////////////////////////////////////////////////////////// 01939 void NodePath:: 01940 set_quat(const NodePath &other, const LQuaternionf &quat) { 01941 nassertv_always(!is_empty()); 01942 CPT(TransformState) rel_transform = get_transform(other); 01943 01944 CPT(TransformState) orig_transform = get_transform(); 01945 if (orig_transform->has_components()) { 01946 // If we had a componentwise transform before we started, we 01947 // should be careful to preserve the other three components. We 01948 // wouldn't need to do this, except for the possibility of 01949 // numerical error or decompose ambiguity. 01950 const LVecBase3f &orig_pos = orig_transform->get_pos(); 01951 const LVecBase3f &orig_scale = orig_transform->get_scale(); 01952 const LVecBase3f &orig_shear = orig_transform->get_shear(); 01953 01954 set_transform(other, rel_transform->set_quat(quat)); 01955 const TransformState *new_transform = get_transform(); 01956 if (new_transform->has_components()) { 01957 set_transform(TransformState::make_pos_quat_scale_shear 01958 (orig_pos, new_transform->get_quat(), orig_scale, orig_shear)); 01959 } 01960 01961 } else { 01962 // If we didn't have a componentwise transform already, never 01963 // mind. 01964 set_transform(other, rel_transform->set_quat(quat)); 01965 } 01966 } 01967 01968 //////////////////////////////////////////////////////////////////// 01969 // Function: NodePath::get_quat 01970 // Access: Published 01971 // Description: Returns the relative orientation of the bottom node 01972 // as seen from the other node. 01973 //////////////////////////////////////////////////////////////////// 01974 LQuaternionf NodePath:: 01975 get_quat(const NodePath &other) const { 01976 nassertr_always(!is_empty(), LQuaternionf::ident_quat()); 01977 CPT(TransformState) transform = get_transform(other); 01978 return transform->get_quat(); 01979 } 01980 01981 //////////////////////////////////////////////////////////////////// 01982 // Function: NodePath::set_scale 01983 // Access: Published 01984 // Description: Sets the scale component of the transform, 01985 // relative to the other node. 01986 //////////////////////////////////////////////////////////////////// 01987 void NodePath:: 01988 set_scale(const NodePath &other, const LVecBase3f &scale) { 01989 nassertv_always(!is_empty()); 01990 CPT(TransformState) rel_transform = get_transform(other); 01991 01992 CPT(TransformState) orig_transform = get_transform(); 01993 if (orig_transform->has_components()) { 01994 // If we had a componentwise transform before we started, we 01995 // should be careful to preserve the other three components. We 01996 // wouldn't need to do this, except for the possibility of 01997 // numerical error or decompose ambiguity. 01998 const LVecBase3f &orig_pos = orig_transform->get_pos(); 01999 const LVecBase3f &orig_hpr = orig_transform->get_hpr(); 02000 const LVecBase3f &orig_shear = orig_transform->get_shear(); 02001 02002 set_transform(other, rel_transform->set_scale(scale)); 02003 const TransformState *new_transform = get_transform(); 02004 if (new_transform->has_components()) { 02005 set_transform(TransformState::make_pos_hpr_scale_shear 02006 (orig_pos, orig_hpr, new_transform->get_scale(), orig_shear)); 02007 } 02008 02009 } else { 02010 // If we didn't have a componentwise transform already, never 02011 // mind. 02012 set_transform(other, rel_transform->set_scale(scale)); 02013 } 02014 } 02015 02016 void NodePath:: 02017 set_sx(const NodePath &other, float sx) { 02018 nassertv_always(!is_empty()); 02019 LVecBase3f scale = get_scale(other); 02020 scale[0] = sx; 02021 set_scale(other, scale); 02022 } 02023 02024 void NodePath:: 02025 set_sy(const NodePath &other, float sy) { 02026 nassertv_always(!is_empty()); 02027 LVecBase3f scale = get_scale(other); 02028 scale[1] = sy; 02029 set_scale(other, scale); 02030 } 02031 02032 void NodePath:: 02033 set_sz(const NodePath &other, float sz) { 02034 nassertv_always(!is_empty()); 02035 LVecBase3f scale = get_scale(other); 02036 scale[2] = sz; 02037 set_scale(other, scale); 02038 } 02039 02040 //////////////////////////////////////////////////////////////////// 02041 // Function: NodePath::get_scale 02042 // Access: Published 02043 // Description: Returns the relative scale of the bottom node 02044 // as seen from the other node. 02045 //////////////////////////////////////////////////////////////////// 02046 LVecBase3f NodePath:: 02047 get_scale(const NodePath &other) const { 02048 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); 02049 CPT(TransformState) transform = get_transform(other); 02050 return transform->get_scale(); 02051 } 02052 02053 //////////////////////////////////////////////////////////////////// 02054 // Function: NodePath::set_shear 02055 // Access: Published 02056 // Description: Sets the shear component of the transform, 02057 // relative to the other node. 02058 //////////////////////////////////////////////////////////////////// 02059 void NodePath:: 02060 set_shear(const NodePath &other, const LVecBase3f &shear) { 02061 nassertv_always(!is_empty()); 02062 CPT(TransformState) rel_transform = get_transform(other); 02063 02064 CPT(TransformState) orig_transform = get_transform(); 02065 if (orig_transform->has_components()) { 02066 // If we had a componentwise transform before we started, we 02067 // should be careful to preserve the other three components. We 02068 // wouldn't need to do this, except for the possibility of 02069 // numerical error or decompose ambiguity. 02070 const LVecBase3f &orig_pos = orig_transform->get_pos(); 02071 const LVecBase3f &orig_hpr = orig_transform->get_hpr(); 02072 const LVecBase3f &orig_scale = orig_transform->get_scale(); 02073 02074 set_transform(other, rel_transform->set_shear(shear)); 02075 const TransformState *new_transform = get_transform(); 02076 if (new_transform->has_components()) { 02077 set_transform(TransformState::make_pos_hpr_scale_shear 02078 (orig_pos, orig_hpr, orig_scale, new_transform->get_shear())); 02079 } 02080 02081 } else { 02082 // If we didn't have a componentwise transform already, never 02083 // mind. 02084 set_transform(other, rel_transform->set_shear(shear)); 02085 } 02086 } 02087 02088 void NodePath:: 02089 set_shxy(const NodePath &other, float shxy) { 02090 nassertv_always(!is_empty()); 02091 LVecBase3f shear = get_shear(other); 02092 shear[0] = shxy; 02093 set_shear(other, shear); 02094 } 02095 02096 void NodePath:: 02097 set_shxz(const NodePath &other, float shxz) { 02098 nassertv_always(!is_empty()); 02099 LVecBase3f shear = get_shear(other); 02100 shear[1] = shxz; 02101 set_shear(other, shear); 02102 } 02103 02104 void NodePath:: 02105 set_shyz(const NodePath &other, float shyz) { 02106 nassertv_always(!is_empty()); 02107 LVecBase3f shear = get_shear(other); 02108 shear[2] = shyz; 02109 set_shear(other, shear); 02110 } 02111 02112 //////////////////////////////////////////////////////////////////// 02113 // Function: NodePath::get_shear 02114 // Access: Published 02115 // Description: Returns the relative shear of the bottom node 02116 // as seen from the other node. 02117 //////////////////////////////////////////////////////////////////// 02118 LVecBase3f NodePath:: 02119 get_shear(const NodePath &other) const { 02120 nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f)); 02121 CPT(TransformState) transform = get_transform(other); 02122 return transform->get_shear(); 02123 } 02124 02125 //////////////////////////////////////////////////////////////////// 02126 // Function: NodePath::set_pos_hpr 02127 // Access: Published 02128 // Description: Sets the translation and rotation component of the 02129 // transform, relative to the other node. 02130 //////////////////////////////////////////////////////////////////// 02131 void NodePath:: 02132 set_pos_hpr(const NodePath &other, const LVecBase3f &pos, 02133 const LVecBase3f &hpr) { 02134 nassertv_always(!is_empty()); 02135 CPT(TransformState) rel_transform = get_transform(other); 02136 02137 CPT(TransformState) orig_transform = get_transform(); 02138 if (orig_transform->has_components()) { 02139 // If we had a componentwise transform before we started, we 02140 // should be careful to preserve the other two components. We 02141 // wouldn't need to do this, except for the possibility of 02142 // numerical error or decompose ambiguity. 02143 const LVecBase3f &orig_scale = orig_transform->get_scale(); 02144 const LVecBase3f &orig_shear = orig_transform->get_shear(); 02145 02146 set_transform(other, TransformState::make_pos_hpr_scale_shear 02147 (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear())); 02148 const TransformState *new_transform = get_transform(); 02149 if (new_transform->has_components()) { 02150 set_pos_hpr_scale_shear(new_transform->get_pos(), new_transform->get_hpr(), 02151 orig_scale, orig_shear); 02152 } 02153 02154 } else { 02155 // If we didn't have a componentwise transform already, never 02156 // mind. 02157 set_transform(other, TransformState::make_pos_hpr_scale_shear 02158 (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear())); 02159 node()->reset_prev_transform(); 02160 } 02161 } 02162 02163 //////////////////////////////////////////////////////////////////// 02164 // Function: NodePath::set_pos_quat 02165 // Access: Published 02166 // Description: Sets the translation and rotation component of the 02167 // transform, relative to the other node. 02168 //////////////////////////////////////////////////////////////////// 02169 void NodePath:: 02170 set_pos_quat(const NodePath &other, const LVecBase3f &pos, 02171 const LQuaternionf &quat) { 02172 nassertv_always(!is_empty()); 02173 CPT(TransformState) rel_transform = get_transform(other); 02174 02175 CPT(TransformState) orig_transform = get_transform(); 02176 if (orig_transform->has_components()) { 02177 // If we had a componentwise transform before we started, we 02178 // should be careful to preserve the other two components. We 02179 // wouldn't need to do this, except for the possibility of 02180 // numerical error or decompose ambiguity. 02181 const LVecBase3f &orig_scale = orig_transform->get_scale(); 02182 const LVecBase3f &orig_shear = orig_transform->get_shear(); 02183 02184 set_transform(other, TransformState::make_pos_quat_scale_shear 02185 (pos, quat, rel_transform->get_scale(), rel_transform->get_shear())); 02186 const TransformState *new_transform = get_transform(); 02187 if (new_transform->has_components()) { 02188 set_pos_quat_scale_shear(new_transform->get_pos(), new_transform->get_quat(), 02189 orig_scale, orig_shear); 02190 } 02191 02192 } else { 02193 // If we didn't have a componentwise transform already, never 02194 // mind. 02195 set_transform(other, TransformState::make_pos_quat_scale_shear 02196 (pos, quat, rel_transform->get_scale(), rel_transform->get_shear())); 02197 node()->reset_prev_transform(); 02198 } 02199 } 02200 02201 //////////////////////////////////////////////////////////////////// 02202 // Function: NodePath::set_hpr_scale 02203 // Access: Published 02204 // Description: Sets the rotation and scale components of the 02205 // transform, leaving translation untouched. This, or 02206 // set_pos_hpr_scale, is the preferred way to update a 02207 // transform when both hpr and scale are to be changed. 02208 //////////////////////////////////////////////////////////////////// 02209 void NodePath:: 02210 set_hpr_scale(const NodePath &other, const LVecBase3f &hpr, const LVecBase3f &scale) { 02211 // We don't bother trying very hard to preserve pos across this 02212 // operation, unlike the work we do above to preserve hpr or scale, 02213 // since it generally doesn't matter that much if pos is off by a 02214 // few thousandths. 02215 nassertv_always(!is_empty()); 02216 CPT(TransformState) transform = get_transform(other); 02217 transform = TransformState::make_pos_hpr_scale_shear 02218 (transform->get_pos(), hpr, scale, transform->get_shear()); 02219 set_transform(other, transform); 02220 } 02221 02222 //////////////////////////////////////////////////////////////////// 02223 // Function: NodePath::set_quat_scale 02224 // Access: Published 02225 // Description: Sets the rotation and scale components of the 02226 // transform, leaving translation untouched. This, or 02227 // set_pos_quat_scale, is the preferred way to update a 02228 // transform when both quat and scale are to be changed. 02229 //////////////////////////////////////////////////////////////////// 02230 void NodePath:: 02231 set_quat_scale(const NodePath &other, const LQuaternionf &quat, 02232 const LVecBase3f &scale) { 02233 // We don't bother trying very hard to preserve pos across this 02234 // operation, unlike the work we do above to preserve quat or scale, 02235 // since it generally doesn't matter that much if pos is off by a 02236 // few thousandths. 02237 nassertv_always(!is_empty()); 02238 CPT(TransformState) transform = get_transform(other); 02239 transform = TransformState::make_pos_quat_scale_shear 02240 (transform->get_pos(), quat, scale, transform->get_shear()); 02241 set_transform(other, transform); 02242 } 02243 02244 //////////////////////////////////////////////////////////////////// 02245 // Function: NodePath::set_pos_hpr_scale 02246 // Access: Published 02247 // Description: Completely replaces the transform with new 02248 // translation, rotation, and scale components, relative 02249 // to the other node, implicitly setting shear to 0. 02250 //////////////////////////////////////////////////////////////////// 02251 void NodePath:: 02252 set_pos_hpr_scale(const NodePath &other, 02253 const LVecBase3f &pos, const LVecBase3f &hpr, 02254 const LVecBase3f &scale) { 02255 nassertv_always(!is_empty()); 02256 set_transform(other, TransformState::make_pos_hpr_scale 02257 (pos, hpr, scale)); 02258 node()->reset_prev_transform(); 02259 } 02260 02261 //////////////////////////////////////////////////////////////////// 02262 // Function: NodePath::set_pos_quat_scale 02263 // Access: Published 02264 // Description: Completely replaces the transform with new 02265 // translation, rotation, and scale components, relative 02266 // to the other node, implicitly setting shear to 0. 02267 //////////////////////////////////////////////////////////////////// 02268 void NodePath:: 02269 set_pos_quat_scale(const NodePath &other, 02270 const LVecBase3f &pos, const LQuaternionf &quat, 02271 const LVecBase3f &scale) { 02272 nassertv_always(!is_empty()); 02273 set_transform(other, TransformState::make_pos_quat_scale 02274 (pos, quat, scale)); 02275 node()->reset_prev_transform(); 02276 } 02277 02278 //////////////////////////////////////////////////////////////////// 02279 // Function: NodePath::set_pos_hpr_scale_shear 02280 // Access: Published 02281 // Description: Completely replaces the transform with new 02282 // translation, rotation, scale, and shear components, 02283 // relative to the other node. 02284 //////////////////////////////////////////////////////////////////// 02285 void NodePath:: 02286 set_pos_hpr_scale_shear(const NodePath &other, 02287 const LVecBase3f &pos, const LVecBase3f &hpr, 02288 const LVecBase3f &scale, const LVecBase3f &shear) { 02289 nassertv_always(!is_empty()); 02290 set_transform(other, TransformState::make_pos_hpr_scale_shear 02291 (pos, hpr, scale, shear)); 02292 node()->reset_prev_transform(); 02293 } 02294 02295 //////////////////////////////////////////////////////////////////// 02296 // Function: NodePath::set_pos_quat_scale_shear 02297 // Access: Published 02298 // Description: Completely replaces the transform with new 02299 // translation, rotation, scale, and shear components, 02300 // relative to the other node. 02301 //////////////////////////////////////////////////////////////////// 02302 void NodePath:: 02303 set_pos_quat_scale_shear(const NodePath &other, 02304 const LVecBase3f &pos, const LQuaternionf &quat, 02305 const LVecBase3f &scale, const LVecBase3f &shear) { 02306 nassertv_always(!is_empty()); 02307 set_transform(other, TransformState::make_pos_quat_scale_shear 02308 (pos, quat, scale, shear)); 02309 node()->reset_prev_transform(); 02310 } 02311 02312 //////////////////////////////////////////////////////////////////// 02313 // Function: NodePath::get_mat 02314 // Access: Published 02315 // Description: Returns the matrix that describes the coordinate 02316 // space of the bottom node, relative to the other 02317 // path's bottom node's coordinate space. 02318 //////////////////////////////////////////////////////////////////// 02319 LMatrix4f NodePath:: 02320 get_mat(const NodePath &other) const { 02321 CPT(TransformState) transform = get_transform(other); 02322 // We can't safely return a reference to the matrix, because we 02323 // can't assume the transform won't go away when the function 02324 // returns. If the transform was partially modified by, say, a 02325 // CompassEffect, it won't be stored in the cache, and thus we might 02326 // have the only reference to it. 02327 return transform->get_mat(); 02328 } 02329 02330 //////////////////////////////////////////////////////////////////// 02331 // Function: NodePath::set_mat 02332 // Access: Published 02333 // Description: Converts the indicated matrix from the other's 02334 // coordinate space to the local coordinate space, and 02335 // applies it to the node. 02336 //////////////////////////////////////////////////////////////////// 02337 void NodePath:: 02338 set_mat(const NodePath &other, const LMatrix4f &mat) { 02339 nassertv_always(!is_empty()); 02340 set_transform(other, TransformState::make_mat(mat)); 02341 node()->reset_prev_transform(); 02342 } 02343 02344 //////////////////////////////////////////////////////////////////// 02345 // Function: NodePath::get_relative_point 02346 // Access: Published 02347 // Description: Given that the indicated point is in the coordinate 02348 // system of the other node, returns the same point in 02349 // this node's coordinate system. 02350 //////////////////////////////////////////////////////////////////// 02351 LPoint3f NodePath:: 02352 get_relative_point(const NodePath &other, const LVecBase3f &point) const { 02353 CPT(TransformState) transform = other.get_transform(*this); 02354 LPoint3f rel_point = LPoint3f(point) * transform->get_mat(); 02355 return rel_point; 02356 } 02357 02358 //////////////////////////////////////////////////////////////////// 02359 // Function: NodePath::get_relative_vector 02360 // Access: Published 02361 // Description: Given that the indicated vector is in the coordinate 02362 // system of the other node, returns the same vector in 02363 // this node's coordinate system. 02364 //////////////////////////////////////////////////////////////////// 02365 LVector3f NodePath:: 02366 get_relative_vector(const NodePath &other, const LVecBase3f &vec) const { 02367 CPT(TransformState) transform = other.get_transform(*this); 02368 LVector3f rel_vector = LVector3f(vec) * transform->get_mat(); 02369 return rel_vector; 02370 } 02371 02372 //////////////////////////////////////////////////////////////////// 02373 // Function: NodePath::look_at 02374 // Access: Published 02375 // Description: Sets the transform on this NodePath so that it 02376 // rotates to face the indicated point in space, which 02377 // is relative to the other NodePath. 02378 //////////////////////////////////////////////////////////////////// 02379 void NodePath:: 02380 look_at(const NodePath &other, const LPoint3f &point, const LVector3f &up) { 02381 nassertv_always(!is_empty()); 02382 02383 CPT(TransformState) transform = other.get_transform(get_parent()); 02384 LPoint3f rel_point = point * transform->get_mat(); 02385 02386 LPoint3f pos = get_pos(); 02387 02388 LQuaternionf quat; 02389 ::look_at(quat, rel_point - pos, up); 02390 set_quat(quat); 02391 } 02392 02393 //////////////////////////////////////////////////////////////////// 02394 // Function: NodePath::heads_up 02395 // Access: Published 02396 // Description: Behaves like look_at(), but with a strong preference 02397 // to keeping the up vector oriented in the indicated 02398 // "up" direction. 02399 //////////////////////////////////////////////////////////////////// 02400 void NodePath:: 02401 heads_up(const NodePath &other, const LPoint3f &point, const LVector3f &up) { 02402 nassertv_always(!is_empty()); 02403 02404 CPT(TransformState) transform = other.get_transform(get_parent()); 02405 LPoint3f rel_point = point * transform->get_mat(); 02406 02407 LPoint3f pos = get_pos(); 02408 02409 LQuaternionf quat; 02410 ::heads_up(quat, rel_point - pos, up); 02411 set_quat(quat); 02412 } 02413 02414 02415 //////////////////////////////////////////////////////////////////// 02416 // Function: NodePath::set_color 02417 // Access: Published 02418 // Description: Applies a scene-graph color to the referenced node. 02419 // This color will apply to all geometry at this level 02420 // and below (that does not specify a new color or a 02421 // set_color_off()). 02422 //////////////////////////////////////////////////////////////////// 02423 void NodePath:: 02424 set_color(float r, float g, float b, float a, 02425 int priority) { 02426 set_color(Colorf(r, g, b, a), priority); 02427 } 02428 02429 //////////////////////////////////////////////////////////////////// 02430 // Function: NodePath::set_color 02431 // Access: Published 02432 // Description: Applies a scene-graph color to the referenced node. 02433 // This color will apply to all geometry at this level 02434 // and below (that does not specify a new color or a 02435 // set_color_off()). 02436 //////////////////////////////////////////////////////////////////// 02437 void NodePath:: 02438 set_color(const Colorf &color, int priority) { 02439 nassertv_always(!is_empty()); 02440 node()->set_attrib(ColorAttrib::make_flat(color), priority); 02441 } 02442 02443 //////////////////////////////////////////////////////////////////// 02444 // Function: NodePath::set_color_off 02445 // Access: Published 02446 // Description: Sets the geometry at this level and below to render 02447 // using the geometry color. This is normally the 02448 // default, but it may be useful to use this to 02449 // contradict set_color() at a higher node level (or, 02450 // with a priority, to override a set_color() at a lower 02451 // level). 02452 //////////////////////////////////////////////////////////////////// 02453 void NodePath:: 02454 set_color_off(int priority) { 02455 nassertv_always(!is_empty()); 02456 node()->set_attrib(ColorAttrib::make_vertex(), priority); 02457 } 02458 02459 //////////////////////////////////////////////////////////////////// 02460 // Function: NodePath::clear_color 02461 // Access: Published 02462 // Description: Completely removes any color adjustment from the node. 02463 // This allows the natural color of the geometry, or 02464 // whatever color transitions might be otherwise 02465 // affecting the geometry, to show instead. 02466 //////////////////////////////////////////////////////////////////// 02467 void NodePath:: 02468 clear_color() { 02469 nassertv_always(!is_empty()); 02470 node()->clear_attrib(ColorAttrib::get_class_slot()); 02471 } 02472 02473 //////////////////////////////////////////////////////////////////// 02474 // Function: NodePath::has_color 02475 // Access: Published 02476 // Description: Returns true if a color has been applied to the given 02477 // node, false otherwise. 02478 //////////////////////////////////////////////////////////////////// 02479 bool NodePath:: 02480 has_color() const { 02481 nassertr_always(!is_empty(), false); 02482 return node()->has_attrib(ColorAttrib::get_class_slot()); 02483 } 02484 02485 //////////////////////////////////////////////////////////////////// 02486 // Function: NodePath::get_color 02487 // Access: Published 02488 // Description: Returns the color that has been assigned to the node, 02489 // or black if no color has been assigned. 02490 //////////////////////////////////////////////////////////////////// 02491 Colorf NodePath:: 02492 get_color() const { 02493 nassertr_always(!is_empty(), false); 02494 const RenderAttrib *attrib = 02495 node()->get_attrib(ColorAttrib::get_class_slot()); 02496 if (attrib != (const RenderAttrib *)NULL) { 02497 const ColorAttrib *ca = DCAST(ColorAttrib, attrib); 02498 if (ca->get_color_type() == ColorAttrib::T_flat) { 02499 return ca->get_color(); 02500 } 02501 } 02502 02503 pgraph_cat.warning() 02504 << "get_color() called on " << *this << " which has no color set.\n"; 02505 02506 return Colorf(1.0f, 1.0f, 1.0f, 1.0f); 02507 } 02508 02509 //////////////////////////////////////////////////////////////////// 02510 // Function: NodePath::has_color_scale 02511 // Access: Published 02512 // Description: Returns true if a color scale has been applied 02513 // to the referenced node, false otherwise. It is still 02514 // possible that color at this node might have been 02515 // scaled by an ancestor node. 02516 //////////////////////////////////////////////////////////////////// 02517 bool NodePath:: 02518 has_color_scale() const { 02519 nassertr_always(!is_empty(), false); 02520 return node()->has_attrib(ColorScaleAttrib::get_class_slot()); 02521 } 02522 02523 //////////////////////////////////////////////////////////////////// 02524 // Function: NodePath::clear_color_scale 02525 // Access: Published 02526 // Description: Completely removes any color scale from the 02527 // referenced node. This is preferable to simply 02528 // setting the color scale to identity, as it also 02529 // removes the overhead associated with having a color 02530 // scale at all. 02531 //////////////////////////////////////////////////////////////////// 02532 void NodePath:: 02533 clear_color_scale() { 02534 nassertv_always(!is_empty()); 02535 node()->clear_attrib(ColorScaleAttrib::get_class_slot()); 02536 } 02537 02538 //////////////////////////////////////////////////////////////////// 02539 // Function: NodePath::compose_color_scale 02540 // Access: Published 02541 // Description: multiplies the color scale component of the transform, 02542 // with previous color scale leaving translation and 02543 // rotation untouched. 02544 //////////////////////////////////////////////////////////////////// 02545 void NodePath:: 02546 compose_color_scale(const LVecBase4f &scale, int priority) { 02547 nassertv_always(!is_empty()); 02548 02549 const RenderAttrib *attrib = 02550 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02551 if (attrib != (const RenderAttrib *)NULL) { 02552 priority = max(priority, 02553 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02554 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02555 02556 // Modify the existing ColorScaleAttrib by multiplying with the 02557 // indicated colorScale. 02558 LVecBase4f prev_color_scale = csa->get_scale(); 02559 LVecBase4f new_color_scale(prev_color_scale[0]*scale[0], 02560 prev_color_scale[1]*scale[1], 02561 prev_color_scale[2]*scale[2], 02562 prev_color_scale[3]*scale[3]); 02563 node()->set_attrib(csa->set_scale(new_color_scale), priority); 02564 02565 } else { 02566 // Create a new ColorScaleAttrib for this node. 02567 node()->set_attrib(ColorScaleAttrib::make(scale), priority); 02568 } 02569 } 02570 02571 //////////////////////////////////////////////////////////////////// 02572 // Function: NodePath::set_color_scale 02573 // Access: Published 02574 // Description: Sets the color scale component of the transform, 02575 // leaving translation and rotation untouched. 02576 //////////////////////////////////////////////////////////////////// 02577 void NodePath:: 02578 set_color_scale(const LVecBase4f &scale, int priority) { 02579 nassertv_always(!is_empty()); 02580 02581 const RenderAttrib *attrib = 02582 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02583 if (attrib != (const RenderAttrib *)NULL) { 02584 priority = max(priority, 02585 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02586 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02587 02588 // Modify the existing ColorScaleAttrib to add the indicated 02589 // colorScale. 02590 node()->set_attrib(csa->set_scale(scale), priority); 02591 02592 } else { 02593 // Create a new ColorScaleAttrib for this node. 02594 node()->set_attrib(ColorScaleAttrib::make(scale), priority); 02595 } 02596 } 02597 02598 //////////////////////////////////////////////////////////////////// 02599 // Function: NodePath::set_color_scale_off 02600 // Access: Published 02601 // Description: Disables any color scale attribute inherited from 02602 // above. This is not the same thing as 02603 // clear_color_scale(), which undoes any previous 02604 // set_color_scale() operation on this node; rather, 02605 // this actively disables any set_color_scale() that 02606 // might be inherited from a parent node. This also 02607 // disables set_alpha_scale() at the same time. 02608 // 02609 // It is legal to specify a new color scale on the same 02610 // node with a subsequent call to set_color_scale() or 02611 // set_alpha_scale(); this new scale will apply to lower 02612 // geometry. 02613 //////////////////////////////////////////////////////////////////// 02614 void NodePath:: 02615 set_color_scale_off(int priority) { 02616 nassertv_always(!is_empty()); 02617 node()->set_attrib(ColorScaleAttrib::make_off(), priority); 02618 } 02619 02620 //////////////////////////////////////////////////////////////////// 02621 // Function: NodePath::set_alpha_scale 02622 // Access: Published 02623 // Description: Sets the alpha scale component of the transform 02624 // without (much) affecting the color scale. Note that 02625 // any priority specified will also apply to the color 02626 // scale. 02627 //////////////////////////////////////////////////////////////////// 02628 void NodePath:: 02629 set_alpha_scale(float scale, int priority) { 02630 nassertv_always(!is_empty()); 02631 02632 const RenderAttrib *attrib = 02633 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02634 if (attrib != (const RenderAttrib *)NULL) { 02635 priority = max(priority, 02636 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02637 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02638 02639 // Modify the existing ColorScaleAttrib to add the indicated 02640 // colorScale. 02641 const LVecBase4f &sc = csa->get_scale(); 02642 node()->set_attrib(csa->set_scale(LVecBase4f(sc[0], sc[1], sc[2], scale)), priority); 02643 02644 } else { 02645 // Create a new ColorScaleAttrib for this node. 02646 node()->set_attrib(ColorScaleAttrib::make(LVecBase4f(1.0f, 1.0f, 1.0f, scale)), priority); 02647 } 02648 } 02649 02650 //////////////////////////////////////////////////////////////////// 02651 // Function: NodePath::set_all_color_scale 02652 // Access: Published 02653 // Description: Scales all the color components of the object by the 02654 // same amount, darkening the object, without (much) 02655 // affecting alpha. Note that any priority specified 02656 // will also apply to the alpha scale. 02657 //////////////////////////////////////////////////////////////////// 02658 void NodePath:: 02659 set_all_color_scale(float scale, int priority) { 02660 nassertv_always(!is_empty()); 02661 02662 const RenderAttrib *attrib = 02663 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02664 if (attrib != (const RenderAttrib *)NULL) { 02665 priority = max(priority, 02666 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02667 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02668 02669 // Modify the existing ColorScaleAttrib to add the indicated 02670 // colorScale. 02671 const LVecBase4f &sc = csa->get_scale(); 02672 node()->set_attrib(csa->set_scale(LVecBase4f(scale, scale, scale, sc[3])), priority); 02673 02674 } else { 02675 // Create a new ColorScaleAttrib for this node. 02676 node()->set_attrib(ColorScaleAttrib::make(LVecBase4f(scale, scale, scale, 1.0f)), priority); 02677 } 02678 } 02679 02680 //////////////////////////////////////////////////////////////////// 02681 // Function: NodePath::get_color_scale 02682 // Access: Published 02683 // Description: Returns the complete color scale vector that has been 02684 // applied to this node via a previous call to 02685 // set_color_scale() and/or set_alpha_scale(), or all 02686 // 1's (identity) if no scale has been applied to this 02687 // particular node. 02688 //////////////////////////////////////////////////////////////////// 02689 const LVecBase4f &NodePath:: 02690 get_color_scale() const { 02691 static const LVecBase4f ident_scale(1.0f, 1.0f, 1.0f, 1.0f); 02692 nassertr_always(!is_empty(), ident_scale); 02693 const RenderAttrib *attrib = 02694 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02695 if (attrib != (const RenderAttrib *)NULL) { 02696 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02697 return csa->get_scale(); 02698 } 02699 02700 return ident_scale; 02701 } 02702 02703 //////////////////////////////////////////////////////////////////// 02704 // Function: NodePath::set_light 02705 // Access: Published 02706 // Description: Adds the indicated Light or PolylightNode to the list 02707 // of lights that illuminate geometry at this node and 02708 // below. The light itself should be parented into the 02709 // scene graph elsewhere, to represent the light's 02710 // position in space; but until set_light() is called it 02711 // will illuminate no geometry. 02712 //////////////////////////////////////////////////////////////////// 02713 void NodePath:: 02714 set_light(const NodePath &light, int priority) { 02715 nassertv_always(!is_empty()); 02716 if (!light.is_empty()) { 02717 Light *light_obj = light.node()->as_light(); 02718 if (light_obj != (Light *)NULL) { 02719 // It's an actual Light object. 02720 const RenderAttrib *attrib = 02721 node()->get_attrib(LightAttrib::get_class_slot()); 02722 if (attrib != (const RenderAttrib *)NULL) { 02723 priority = max(priority, 02724 node()->get_state()->get_override(LightAttrib::get_class_slot())); 02725 const LightAttrib *la = DCAST(LightAttrib, attrib); 02726 02727 // Modify the existing LightAttrib to add the indicated 02728 // light. 02729 node()->set_attrib(la->add_on_light(light), priority); 02730 02731 } else { 02732 // Create a new LightAttrib for this node. 02733 CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make()); 02734 node()->set_attrib(la->add_on_light(light), priority); 02735 } 02736 return; 02737 02738 } else if (light.node()->is_of_type(PolylightNode::get_class_type())) { 02739 // It's a Polylight object. 02740 if (priority != 0) { 02741 // PolylightEffects can't have a priority, since they're just 02742 // an effect to be applied immediately. 02743 pgraph_cat.warning() 02744 << "Ignoring priority on set_light(" << light << ")\n"; 02745 } 02746 02747 const RenderEffect *effect = 02748 node()->get_effect(PolylightEffect::get_class_type()); 02749 if (effect != (const RenderEffect *)NULL) { 02750 const PolylightEffect *ple = DCAST(PolylightEffect, effect); 02751 02752 // Modify the existing PolylightEffect to add the indicated 02753 // light. 02754 node()->set_effect(ple->add_light(light)); 02755 02756 } else { 02757 // Create a new PolylightEffect for this node. 02758 CPT(PolylightEffect) ple = DCAST(PolylightEffect, PolylightEffect::make()); 02759 node()->set_effect(ple->add_light(light)); 02760 } 02761 return; 02762 } 02763 } 02764 nassert_raise("Not a Light object."); 02765 } 02766 02767 //////////////////////////////////////////////////////////////////// 02768 // Function: NodePath::set_light_off 02769 // Access: Published 02770 // Description: Sets the geometry at this level and below to render 02771 // using no lights at all. This is different 02772 // from not specifying a light; rather, this 02773 // specifically contradicts set_light() at a higher 02774 // node level (or, with a priority, overrides a 02775 // set_light() at a lower level). 02776 // 02777 // If no lights are in effect on a particular piece of 02778 // geometry, that geometry is rendered with lighting 02779 // disabled. 02780 //////////////////////////////////////////////////////////////////// 02781 void NodePath:: 02782 set_light_off(int priority) { 02783 nassertv_always(!is_empty()); 02784 node()->set_attrib(LightAttrib::make_all_off(), priority); 02785 node()->clear_effect(PolylightEffect::get_class_type()); 02786 } 02787 02788 //////////////////////////////////////////////////////////////////// 02789 // Function: NodePath::set_light_off 02790 // Access: Published 02791 // Description: Sets the geometry at this level and below to render 02792 // without using the indicated Light. This is different 02793 // from not specifying the Light; rather, this 02794 // specifically contradicts set_light() at a higher node 02795 // level (or, with a priority, overrides a set_light() 02796 // at a lower level). 02797 // 02798 // This interface does not support PolylightNodes, which 02799 // cannot be turned off at a lower level. 02800 //////////////////////////////////////////////////////////////////// 02801 void NodePath:: 02802 set_light_off(const NodePath &light, int priority) { 02803 nassertv_always(!is_empty()); 02804 02805 if (!light.is_empty()) { 02806 Light *light_obj = light.node()->as_light(); 02807 if (light_obj != (Light *)NULL) { 02808 const RenderAttrib *attrib = 02809 node()->get_attrib(LightAttrib::get_class_slot()); 02810 if (attrib != (const RenderAttrib *)NULL) { 02811 priority = max(priority, 02812 node()->get_state()->get_override(LightAttrib::get_class_slot())); 02813 const LightAttrib *la = DCAST(LightAttrib, attrib); 02814 02815 // Modify the existing LightAttrib to add the indicated light 02816 // to the "off" list. This also, incidentally, removes it from 02817 // the "on" list if it is there. 02818 node()->set_attrib(la->add_off_light(light), priority); 02819 02820 } else { 02821 // Create a new LightAttrib for this node that turns off the 02822 // indicated light. 02823 CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make()); 02824 node()->set_attrib(la->add_off_light(light), priority); 02825 } 02826 return; 02827 } 02828 } 02829 nassert_raise("Not a Light object."); 02830 } 02831 02832 //////////////////////////////////////////////////////////////////// 02833 // Function: NodePath::clear_light 02834 // Access: Published 02835 // Description: Completely removes any lighting operations that may 02836 // have been set via set_light() or set_light_off() 02837 // from this particular node. 02838 //////////////////////////////////////////////////////////////////// 02839 void NodePath:: 02840 clear_light() { 02841 nassertv_always(!is_empty()); 02842 node()->clear_attrib(LightAttrib::get_class_slot()); 02843 node()->clear_effect(PolylightEffect::get_class_type()); 02844 } 02845 02846 //////////////////////////////////////////////////////////////////// 02847 // Function: NodePath::clear_light 02848 // Access: Published 02849 // Description: Removes any reference to the indicated Light or 02850 // PolylightNode from the NodePath. 02851 //////////////////////////////////////////////////////////////////// 02852 void NodePath:: 02853 clear_light(const NodePath &light) { 02854 nassertv_always(!is_empty()); 02855 02856 if (!light.is_empty()) { 02857 Light *light_obj = light.node()->as_light(); 02858 if (light_obj != (Light *)NULL) { 02859 const RenderAttrib *attrib = 02860 node()->get_attrib(LightAttrib::get_class_slot()); 02861 if (attrib != (const RenderAttrib *)NULL) { 02862 CPT(LightAttrib) la = DCAST(LightAttrib, attrib); 02863 la = DCAST(LightAttrib, la->remove_on_light(light)); 02864 la = DCAST(LightAttrib, la->remove_off_light(light)); 02865 02866 if (la->is_identity()) { 02867 node()->clear_attrib(LightAttrib::get_class_slot()); 02868 02869 } else { 02870 int priority = node()->get_state()->get_override(LightAttrib::get_class_slot()); 02871 node()->set_attrib(la, priority); 02872 } 02873 } 02874 return; 02875 02876 } else if (light.node()->is_of_type(PolylightNode::get_class_type())) { 02877 const RenderEffect *effect = 02878 node()->get_effect(PolylightEffect::get_class_type()); 02879 if (effect != (const RenderEffect *)NULL) { 02880 CPT(PolylightEffect) ple = DCAST(PolylightEffect, effect); 02881 ple = DCAST(PolylightEffect, ple->remove_light(light)); 02882 node()->set_effect(ple); 02883 } 02884 return; 02885 } 02886 } 02887 nassert_raise("Not a Light object."); 02888 } 02889 02890 //////////////////////////////////////////////////////////////////// 02891 // Function: NodePath::has_light 02892 // Access: Published 02893 // Description: Returns true if the indicated Light or PolylightNode 02894 // has been specifically enabled on this particular 02895 // node. This means that someone called set_light() on 02896 // this node with the indicated light. 02897 //////////////////////////////////////////////////////////////////// 02898 bool NodePath:: 02899 has_light(const NodePath &light) const { 02900 nassertr_always(!is_empty(), false); 02901 02902 if (!light.is_empty()) { 02903 Light *light_obj = light.node()->as_light(); 02904 if (light_obj != (Light *)NULL) { 02905 const RenderAttrib *attrib = 02906 node()->get_attrib(LightAttrib::get_class_slot()); 02907 if (attrib != (const RenderAttrib *)NULL) { 02908 const LightAttrib *la = DCAST(LightAttrib, attrib); 02909 return la->has_on_light(light); 02910 } 02911 return false; 02912 02913 } else if (light.node()->is_of_type(PolylightNode::get_class_type())) { 02914 const RenderEffect *effect = 02915 node()->get_effect(PolylightEffect::get_class_type()); 02916 if (effect != (const RenderEffect *)NULL) { 02917 const PolylightEffect *ple = DCAST(PolylightEffect, effect); 02918 return ple->has_light(light); 02919 } 02920 return false; 02921 } 02922 } 02923 nassert_raise("Not a Light object."); 02924 return false; 02925 } 02926 02927 //////////////////////////////////////////////////////////////////// 02928 // Function: NodePath::has_light_off 02929 // Access: Published 02930 // Description: Returns true if all Lights have been specifically 02931 // disabled on this particular node. This means that 02932 // someone called set_light_off() on this node with no 02933 // parameters. 02934 //////////////////////////////////////////////////////////////////// 02935 bool NodePath:: 02936 has_light_off() const { 02937 nassertr_always(!is_empty(), false); 02938 02939 const RenderAttrib *attrib = 02940 node()->get_attrib(LightAttrib::get_class_slot()); 02941 if (attrib != (const RenderAttrib *)NULL) { 02942 const LightAttrib *la = DCAST(LightAttrib, attrib); 02943 return la->has_all_off(); 02944 } 02945 02946 return false; 02947 } 02948 02949 //////////////////////////////////////////////////////////////////// 02950 // Function: NodePath::has_light_off 02951 // Access: Published 02952 // Description: Returns true if the indicated Light has been 02953 // specifically disabled on this particular node. This 02954 // means that someone called set_light_off() on this 02955 // node with the indicated light. 02956 // 02957 // This interface does not support PolylightNodes, which 02958 // cannot be turned off at a lower level. 02959 //////////////////////////////////////////////////////////////////// 02960 bool NodePath:: 02961 has_light_off(const NodePath &light) const { 02962 nassertr_always(!is_empty(), false); 02963 if (!light.is_empty()) { 02964 Light *light_obj = light.node()->as_light(); 02965 if (light_obj != (Light *)NULL) { 02966 const RenderAttrib *attrib = 02967 node()->get_attrib(LightAttrib::get_class_slot()); 02968 if (attrib != (const RenderAttrib *)NULL) { 02969 const LightAttrib *la = DCAST(LightAttrib, attrib); 02970 return la->has_off_light(light); 02971 } 02972 } 02973 } 02974 nassert_raise("Not a Light object."); 02975 return false; 02976 } 02977 02978 //////////////////////////////////////////////////////////////////// 02979 // Function: NodePath::set_clip_plane 02980 // Access: Published 02981 // Description: Adds the indicated clipping plane to the list of 02982 // planes that apply to geometry at this node and below. 02983 // The clipping plane itself, a PlaneNode, should be 02984 // parented into the scene graph elsewhere, to represent 02985 // the plane's position in space; but until 02986 // set_clip_plane() is called it will clip no geometry. 02987 //////////////////////////////////////////////////////////////////// 02988 void NodePath:: 02989 set_clip_plane(const NodePath &clip_plane, int priority) { 02990 nassertv_always(!is_empty()); 02991 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 02992 const RenderAttrib *attrib = 02993 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 02994 if (attrib != (const RenderAttrib *)NULL) { 02995 priority = max(priority, 02996 node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot())); 02997 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 02998 02999 // Modify the existing ClipPlaneAttrib to add the indicated 03000 // clip_plane. 03001 node()->set_attrib(la->add_on_plane(clip_plane), priority); 03002 03003 } else { 03004 // Create a new ClipPlaneAttrib for this node. 03005 CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make()); 03006 node()->set_attrib(la->add_on_plane(clip_plane), priority); 03007 } 03008 return; 03009 } 03010 nassert_raise("Not a PlaneNode object."); 03011 } 03012 03013 //////////////////////////////////////////////////////////////////// 03014 // Function: NodePath::set_clip_plane_off 03015 // Access: Published 03016 // Description: Sets the geometry at this level and below to render 03017 // using no clip_planes at all. This is different 03018 // from not specifying a clip_plane; rather, this 03019 // specifically contradicts set_clip_plane() at a higher 03020 // node level (or, with a priority, overrides a 03021 // set_clip_plane() at a lower level). 03022 // 03023 // If no clip_planes are in effect on a particular piece 03024 // of geometry, that geometry is rendered without being 03025 // clipped (other than by the viewing frustum). 03026 //////////////////////////////////////////////////////////////////// 03027 void NodePath:: 03028 set_clip_plane_off(int priority) { 03029 nassertv_always(!is_empty()); 03030 node()->set_attrib(ClipPlaneAttrib::make_all_off(), priority); 03031 } 03032 03033 //////////////////////////////////////////////////////////////////// 03034 // Function: NodePath::set_clip_plane_off 03035 // Access: Published 03036 // Description: Sets the geometry at this level and below to render 03037 // without being clipped by the indicated PlaneNode. 03038 // This is different from not specifying the PlaneNode; 03039 // rather, this specifically contradicts 03040 // set_clip_plane() at a higher node level (or, with a 03041 // priority, overrides a set_clip_plane() at a lower 03042 // level). 03043 //////////////////////////////////////////////////////////////////// 03044 void NodePath:: 03045 set_clip_plane_off(const NodePath &clip_plane, int priority) { 03046 nassertv_always(!is_empty()); 03047 03048 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03049 const RenderAttrib *attrib = 03050 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03051 if (attrib != (const RenderAttrib *)NULL) { 03052 priority = max(priority, 03053 node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot())); 03054 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03055 03056 // Modify the existing ClipPlaneAttrib to add the indicated clip_plane 03057 // to the "off" list. This also, incidentally, removes it from 03058 // the "on" list if it is there. 03059 node()->set_attrib(la->add_off_plane(clip_plane), priority); 03060 03061 } else { 03062 // Create a new ClipPlaneAttrib for this node that turns off the 03063 // indicated clip_plane. 03064 CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make()); 03065 node()->set_attrib(la->add_off_plane(clip_plane), priority); 03066 } 03067 return; 03068 } 03069 nassert_raise("Not a PlaneNode object."); 03070 } 03071 03072 //////////////////////////////////////////////////////////////////// 03073 // Function: NodePath::clear_clip_plane 03074 // Access: Published 03075 // Description: Completely removes any clip planes that may have been 03076 // set via set_clip_plane() or set_clip_plane_off() from 03077 // this particular node. 03078 //////////////////////////////////////////////////////////////////// 03079 void NodePath:: 03080 clear_clip_plane() { 03081 nassertv_always(!is_empty()); 03082 node()->clear_attrib(ClipPlaneAttrib::get_class_slot()); 03083 } 03084 03085 //////////////////////////////////////////////////////////////////// 03086 // Function: NodePath::clear_clip_plane 03087 // Access: Published 03088 // Description: Removes any reference to the indicated clipping plane 03089 // from the NodePath. 03090 //////////////////////////////////////////////////////////////////// 03091 void NodePath:: 03092 clear_clip_plane(const NodePath &clip_plane) { 03093 nassertv_always(!is_empty()); 03094 03095 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03096 const RenderAttrib *attrib = 03097 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03098 if (attrib != (const RenderAttrib *)NULL) { 03099 CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib); 03100 la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane)); 03101 la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane)); 03102 03103 if (la->is_identity()) { 03104 node()->clear_attrib(ClipPlaneAttrib::get_class_slot()); 03105 03106 } else { 03107 int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()); 03108 node()->set_attrib(la, priority); 03109 } 03110 } 03111 return; 03112 } 03113 nassert_raise("Not a PlaneNode object."); 03114 } 03115 03116 //////////////////////////////////////////////////////////////////// 03117 // Function: NodePath::has_clip_plane 03118 // Access: Published 03119 // Description: Returns true if the indicated clipping plane has been 03120 // specifically applied to this particular node. This 03121 // means that someone called set_clip_plane() on this 03122 // node with the indicated clip_plane. 03123 //////////////////////////////////////////////////////////////////// 03124 bool NodePath:: 03125 has_clip_plane(const NodePath &clip_plane) const { 03126 nassertr_always(!is_empty(), false); 03127 03128 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03129 const RenderAttrib *attrib = 03130 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03131 if (attrib != (const RenderAttrib *)NULL) { 03132 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03133 return la->has_on_plane(clip_plane); 03134 } 03135 return false; 03136 } 03137 nassert_raise("Not a PlaneNode object."); 03138 return false; 03139 } 03140 03141 //////////////////////////////////////////////////////////////////// 03142 // Function: NodePath::has_clip_plane_off 03143 // Access: Published 03144 // Description: Returns true if all clipping planes have been 03145 // specifically disabled on this particular node. This 03146 // means that someone called set_clip_plane_off() on 03147 // this node with no parameters. 03148 //////////////////////////////////////////////////////////////////// 03149 bool NodePath:: 03150 has_clip_plane_off() const { 03151 nassertr_always(!is_empty(), false); 03152 03153 const RenderAttrib *attrib = 03154 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03155 if (attrib != (const RenderAttrib *)NULL) { 03156 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03157 return la->has_all_off(); 03158 } 03159 03160 return false; 03161 } 03162 03163 //////////////////////////////////////////////////////////////////// 03164 // Function: NodePath::has_clip_plane_off 03165 // Access: Published 03166 // Description: Returns true if the indicated clipping plane has been 03167 // specifically disabled on this particular node. This 03168 // means that someone called set_clip_plane_off() on 03169 // this node with the indicated clip_plane. 03170 //////////////////////////////////////////////////////////////////// 03171 bool NodePath:: 03172 has_clip_plane_off(const NodePath &clip_plane) const { 03173 nassertr_always(!is_empty(), false); 03174 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03175 const RenderAttrib *attrib = 03176 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03177 if (attrib != (const RenderAttrib *)NULL) { 03178 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03179 return la->has_off_plane(clip_plane); 03180 } 03181 } 03182 nassert_raise("Not a PlaneNode object."); 03183 return false; 03184 } 03185 03186 //////////////////////////////////////////////////////////////////// 03187 // Function: NodePath::set_scissor 03188 // Access: Published 03189 // Description: Sets up a scissor region on the nodes rendered at 03190 // this level and below. The four coordinates are 03191 // understood to define a rectangle in screen space. 03192 // These numbers are relative to the current 03193 // DisplayRegion, where (0,0) is the lower-left corner 03194 // of the DisplayRegion, and (1,1) is the upper-right 03195 // corner. 03196 //////////////////////////////////////////////////////////////////// 03197 void NodePath:: 03198 set_scissor(float left, float right, float bottom, float top) { 03199 set_effect(ScissorEffect::make_screen(LVecBase4f(left, right, bottom, top))); 03200 } 03201 03202 //////////////////////////////////////////////////////////////////// 03203 // Function: NodePath::set_scissor 03204 // Access: Published 03205 // Description: Sets up a scissor region on the nodes rendered at 03206 // this level and below. The two points are understood 03207 // to be relative to this node. When these points are 03208 // projected into screen space, they define the 03209 // diagonally-opposite points that determine the scissor 03210 // region. 03211 //////////////////////////////////////////////////////////////////// 03212 void NodePath:: 03213 set_scissor(const LPoint3f &a, const LPoint3f &b) { 03214 set_effect(ScissorEffect::make_node(a, b)); 03215 } 03216 03217 //////////////////////////////////////////////////////////////////// 03218 // Function: NodePath::set_scissor 03219 // Access: Published 03220 // Description: Sets up a scissor region on the nodes rendered at 03221 // this level and below. The four points are understood 03222 // to be relative to this node. When these points are 03223 // projected into screen space, they define the 03224 // bounding volume of the scissor region (the scissor 03225 // region is the smallest onscreen rectangle that 03226 // encloses all four points). 03227 //////////////////////////////////////////////////////////////////// 03228 void NodePath:: 03229 set_scissor(const LPoint3f &a, const LPoint3f &b, 03230 const LPoint3f &c, const LPoint3f &d) { 03231 set_effect(ScissorEffect::make_node(a, b, c, d)); 03232 } 03233 03234 //////////////////////////////////////////////////////////////////// 03235 // Function: NodePath::set_scissor 03236 // Access: Published 03237 // Description: Sets up a scissor region on the nodes rendered at 03238 // this level and below. The two points are understood 03239 // to be relative to the indicated other node. When 03240 // these points are projected into screen space, they 03241 // define the diagonally-opposite points that determine 03242 // the scissor region. 03243 //////////////////////////////////////////////////////////////////// 03244 void NodePath:: 03245 set_scissor(const NodePath &other, const LPoint3f &a, const LPoint3f &b) { 03246 set_effect(ScissorEffect::make_node(a, b, other)); 03247 } 03248 03249 //////////////////////////////////////////////////////////////////// 03250 // Function: NodePath::set_scissor 03251 // Access: Published 03252 // Description: Sets up a scissor region on the nodes rendered at 03253 // this level and below. The four points are understood 03254 // to be relative to the indicated other node. When 03255 // these points are projected into screen space, they 03256 // define the bounding volume of the scissor region (the 03257 // scissor region is the smallest onscreen rectangle 03258 // that encloses all four points). 03259 //////////////////////////////////////////////////////////////////// 03260 void NodePath:: 03261 set_scissor(const NodePath &other, 03262 const LPoint3f &a, const LPoint3f &b, 03263 const LPoint3f &c, const LPoint3f &d) { 03264 set_effect(ScissorEffect::make_node(a, b, c, d, other)); 03265 } 03266 03267 //////////////////////////////////////////////////////////////////// 03268 // Function: NodePath::clear_scissor 03269 // Access: Published 03270 // Description: Removes the scissor region that was defined at this 03271 // node level by a previous call to set_scissor(). 03272 //////////////////////////////////////////////////////////////////// 03273 void NodePath:: 03274 clear_scissor() { 03275 clear_effect(ScissorEffect::get_class_type()); 03276 } 03277 03278 //////////////////////////////////////////////////////////////////// 03279 // Function: NodePath::has_scissor 03280 // Access: Published 03281 // Description: Returns true if a scissor region was defined at this 03282 // node by a previous call to set_scissor(). This does 03283 // not check for scissor regions inherited from a parent 03284 // class. It also does not check for the presence of a 03285 // low-level ScissorAttrib, which is different from the 03286 // ScissorEffect added by set_scissor. 03287 //////////////////////////////////////////////////////////////////// 03288 bool NodePath:: 03289 has_scissor() const { 03290 return has_effect(ScissorEffect::get_class_type()); 03291 } 03292 03293 //////////////////////////////////////////////////////////////////// 03294 // Function: NodePath::set_bin 03295 // Access: Published 03296 // Description: Assigns the geometry at this level and below to the 03297 // named rendering bin. It is the user's responsibility 03298 // to ensure that such a bin already exists, either via 03299 // the cull-bin Configrc variable, or by explicitly 03300 // creating a GeomBin of the appropriate type at 03301 // runtime. 03302 // 03303 // There are two default bins created when Panda is 03304 // started: "default" and "fixed". Normally, all 03305 // geometry is assigned to "default" unless specified 03306 // otherwise. This bin renders opaque geometry in 03307 // state-sorted order, followed by transparent geometry 03308 // sorted back-to-front. If any geometry is assigned to 03309 // "fixed", this will be rendered following all the 03310 // geometry in "default", in the order specified by 03311 // draw_order for each piece of geometry so assigned. 03312 // 03313 // The draw_order parameter is meaningful only for 03314 // GeomBinFixed type bins, e.g. "fixed". Other kinds of 03315 // bins ignore it. 03316 //////////////////////////////////////////////////////////////////// 03317 void NodePath:: 03318 set_bin(const string &bin_name, int draw_order, int priority) { 03319 nassertv_always(!is_empty()); 03320 node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority); 03321 } 03322 03323 //////////////////////////////////////////////////////////////////// 03324 // Function: NodePath::clear_bin 03325 // Access: Published 03326 // Description: Completely removes any bin adjustment that may have 03327 // been set via set_bin() from this particular node. 03328 //////////////////////////////////////////////////////////////////// 03329 void NodePath:: 03330 clear_bin() { 03331 nassertv_always(!is_empty()); 03332 node()->clear_attrib(CullBinAttrib::get_class_slot()); 03333 } 03334 03335 //////////////////////////////////////////////////////////////////// 03336 // Function: NodePath::has_bin 03337 // Access: Published 03338 // Description: Returns true if the node has been assigned to the a 03339 // particular rendering bin via set_bin(), false 03340 // otherwise. 03341 //////////////////////////////////////////////////////////////////// 03342 bool NodePath:: 03343 has_bin() const { 03344 nassertr_always(!is_empty(), false); 03345 return node()->has_attrib(CullBinAttrib::get_class_slot()); 03346 } 03347 03348 //////////////////////////////////////////////////////////////////// 03349 // Function: NodePath::get_bin_name 03350 // Access: Published 03351 // Description: Returns the name of the bin that this particular node 03352 // was assigned to via set_bin(), or the empty string if 03353 // no bin was assigned. See set_bin() and has_bin(). 03354 //////////////////////////////////////////////////////////////////// 03355 string NodePath:: 03356 get_bin_name() const { 03357 nassertr_always(!is_empty(), string()); 03358 const RenderAttrib *attrib = 03359 node()->get_attrib(CullBinAttrib::get_class_slot()); 03360 if (attrib != (const RenderAttrib *)NULL) { 03361 const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib); 03362 return ba->get_bin_name(); 03363 } 03364 03365 return string(); 03366 } 03367 03368 //////////////////////////////////////////////////////////////////// 03369 // Function: NodePath::get_bin_draw_order 03370 // Access: Published 03371 // Description: Returns the drawing order associated with the bin 03372 // that this particular node was assigned to via 03373 // set_bin(), or 0 if no bin was assigned. See 03374 // set_bin() and has_bin(). 03375 //////////////////////////////////////////////////////////////////// 03376 int NodePath:: 03377 get_bin_draw_order() const { 03378 nassertr_always(!is_empty(), false); 03379 const RenderAttrib *attrib = 03380 node()->get_attrib(CullBinAttrib::get_class_slot()); 03381 if (attrib != (const RenderAttrib *)NULL) { 03382 const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib); 03383 return ba->get_draw_order(); 03384 } 03385 03386 return 0; 03387 } 03388 03389 //////////////////////////////////////////////////////////////////// 03390 // Function: NodePath::set_texture 03391 // Access: Published 03392 // Description: Adds the indicated texture to the list of textures 03393 // that will be rendered on the default texture stage. 03394 // 03395 // This is the convenience single-texture variant of 03396 // this method; it is now superceded by set_texture() 03397 // that accepts a stage and texture. You may use this 03398 // method if you just want to adjust the default stage. 03399 //////////////////////////////////////////////////////////////////// 03400 void NodePath:: 03401 set_texture(Texture *tex, int priority) { 03402 nassertv_always(!is_empty()); 03403 PT(TextureStage) stage = TextureStage::get_default(); 03404 set_texture(stage, tex, priority); 03405 } 03406 03407 //////////////////////////////////////////////////////////////////// 03408 // Function: NodePath::set_texture 03409 // Access: Published 03410 // Description: Adds the indicated texture to the list of textures 03411 // that will be rendered on the indicated multitexture 03412 // stage. If there are multiple texture stages 03413 // specified (possibly on multiple different nodes at 03414 // different levels), they will all be applied to 03415 // geometry together, according to the stage 03416 // specification set up in the TextureStage object. 03417 //////////////////////////////////////////////////////////////////// 03418 void NodePath:: 03419 set_texture(TextureStage *stage, Texture *tex, int priority) { 03420 nassertv_always(!is_empty()); 03421 03422 const RenderAttrib *attrib = 03423 node()->get_attrib(TextureAttrib::get_class_slot()); 03424 if (attrib != (const RenderAttrib *)NULL) { 03425 const TextureAttrib *tsa = DCAST(TextureAttrib, attrib); 03426 int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); 03427 03428 // Modify the existing TextureAttrib to add the indicated 03429 // texture. 03430 node()->set_attrib(tsa->add_on_stage(stage, tex, priority), sg_priority); 03431 03432 } else { 03433 // Create a new TextureAttrib for this node. 03434 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make()); 03435 node()->set_attrib(tsa->add_on_stage(stage, tex, priority)); 03436 } 03437 } 03438 03439 //////////////////////////////////////////////////////////////////// 03440 // Function: NodePath::set_texture_off 03441 // Access: Published 03442 // Description: Sets the geometry at this level and below to render 03443 // using no texture, on any stage. This is different 03444 // from not specifying a texture; rather, this 03445 // specifically contradicts set_texture() at a higher 03446 // node level (or, with a priority, overrides a 03447 // set_texture() at a lower level). 03448 //////////////////////////////////////////////////////////////////// 03449 void NodePath:: 03450 set_texture_off(int priority) { 03451 nassertv_always(!is_empty()); 03452 node()->set_attrib(TextureAttrib::make_all_off(), priority); 03453 } 03454 03455 //////////////////////////////////////////////////////////////////// 03456 // Function: NodePath::set_texture_off 03457 // Access: Published 03458 // Description: Sets the geometry at this level and below to render 03459 // using no texture, on the indicated stage. This is 03460 // different from not specifying a texture; rather, this 03461 // specifically contradicts set_texture() at a higher 03462 // node level (or, with a priority, overrides a 03463 // set_texture() at a lower level). 03464 //////////////////////////////////////////////////////////////////// 03465 void NodePath:: 03466 set_texture_off(TextureStage *stage, int priority) { 03467 nassertv_always(!is_empty()); 03468 03469 const RenderAttrib *attrib = 03470 node()->get_attrib(TextureAttrib::get_class_slot()); 03471 if (attrib != (const RenderAttrib *)NULL) { 03472 const TextureAttrib *tsa = DCAST(TextureAttrib, attrib); 03473 int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); 03474 03475 // Modify the existing TextureAttrib to add the indicated texture 03476 // to the "off" list. This also, incidentally, removes it from 03477 // the "on" list if it is there. 03478 node()->set_attrib(tsa->add_off_stage(stage, priority), sg_priority); 03479 03480 } else { 03481 // Create a new TextureAttrib for this node that turns off the 03482 // indicated stage. 03483 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make()); 03484 node()->set_attrib(tsa->add_off_stage(stage, priority)); 03485 } 03486 } 03487 03488 //////////////////////////////////////////////////////////////////// 03489 // Function: NodePath::clear_texture 03490 // Access: Published 03491 // Description: Completely removes any texture adjustment that may 03492 // have been set via set_texture() or set_texture_off() 03493 // from this particular node. This allows whatever 03494 // textures might be otherwise affecting the geometry to 03495 // show instead. 03496 //////////////////////////////////////////////////////////////////// 03497 void NodePath:: 03498 clear_texture() { 03499 nassertv_always(!is_empty()); 03500 node()->clear_attrib(TextureAttrib::get_class_slot()); 03501 } 03502 03503 //////////////////////////////////////////////////////////////////// 03504 // Function: NodePath::clear_texture 03505 // Access: Published 03506 // Description: Removes any reference to the indicated texture stage 03507 // from the NodePath. 03508 //////////////////////////////////////////////////////////////////// 03509 void NodePath:: 03510 clear_texture(TextureStage *stage) { 03511 nassertv_always(!is_empty()); 03512 03513 const RenderAttrib *attrib = 03514 node()->get_attrib(TextureAttrib::get_class_slot()); 03515 if (attrib != (const RenderAttrib *)NULL) { 03516 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, attrib); 03517 tsa = DCAST(TextureAttrib, tsa->remove_on_stage(stage)); 03518 tsa = DCAST(TextureAttrib, tsa->remove_off_stage(stage)); 03519 03520 if (tsa->is_identity()) { 03521 node()->clear_attrib(TextureAttrib::get_class_slot()); 03522 03523 } else { 03524 int priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); 03525 node()->set_attrib(tsa, priority); 03526 } 03527 } 03528 } 03529 03530 //////////////////////////////////////////////////////////////////// 03531 // Function: NodePath::has_texture 03532 // Access: Published 03533 // Description: Returns true if a texture has been applied to this 03534 // particular node via set_texture(), false otherwise. 03535 // This is not the same thing as asking whether the 03536 // geometry at this node will be rendered with 03537 // texturing, as there may be a texture in effect from a 03538 // higher or lower level. 03539 //////////////////////////////////////////////////////////////////// 03540 bool NodePath:: 03541 has_texture() const { 03542 return get_texture() != (Texture *)NULL; 03543 } 03544 03545 //////////////////////////////////////////////////////////////////// 03546 // Function: NodePath::has_texture 03547 // Access: Published 03548 // Description: Returns true if texturing has been specifically 03549 // enabled on this particular node for the indicated 03550 // stage. This means that someone called 03551 // set_texture() on this node with the indicated stage 03552 // name, or the stage_name is the default stage_name, 03553 // and someone called set_texture() on this node. 03554 //////////////////////////////////////////////////////////////////// 03555 bool NodePath:: 03556 has_texture(TextureStage *stage) const { 03557 nassertr_always(!is_empty(), false); 03558 03559 const RenderAttrib *attrib = 03560 node()->get_attrib(TextureAttrib::get_class_slot()); 03561 if (attrib != (const RenderAttrib *)NULL) { 03562 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03563 return ta->has_on_stage(stage); 03564 } 03565 03566 return false; 03567 } 03568 03569 //////////////////////////////////////////////////////////////////// 03570 // Function: NodePath::has_texture_off 03571 // Access: Published 03572 // Description: Returns true if texturing has been specifically 03573 // disabled on this particular node via 03574 // set_texture_off(), false otherwise. This is not the 03575 // same thing as asking whether the geometry at this 03576 // node will be rendered untextured, as there may be a 03577 // texture in effect from a higher or lower level. 03578 //////////////////////////////////////////////////////////////////// 03579 bool NodePath:: 03580 has_texture_off() const { 03581 nassertr_always(!is_empty(), false); 03582 const RenderAttrib *attrib = 03583 node()->get_attrib(TextureAttrib::get_class_slot()); 03584 if (attrib != (const RenderAttrib *)NULL) { 03585 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03586 return ta->has_all_off(); 03587 } 03588 03589 return false; 03590 } 03591 03592 //////////////////////////////////////////////////////////////////// 03593 // Function: NodePath::has_texture_off 03594 // Access: Published 03595 // Description: Returns true if texturing has been specifically 03596 // disabled on this particular node for the indicated 03597 // stage. This means that someone called 03598 // set_texture_off() on this node with the indicated 03599 // stage name, or that someone called set_texture_off() 03600 // on this node to remove all stages. 03601 //////////////////////////////////////////////////////////////////// 03602 bool NodePath:: 03603 has_texture_off(TextureStage *stage) const { 03604 nassertr_always(!is_empty(), false); 03605 03606 const RenderAttrib *attrib = 03607 node()->get_attrib(TextureAttrib::get_class_slot()); 03608 if (attrib != (const RenderAttrib *)NULL) { 03609 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03610 return ta->has_off_stage(stage); 03611 } 03612 03613 return false; 03614 } 03615 03616 //////////////////////////////////////////////////////////////////// 03617 // Function: NodePath::get_texture 03618 // Access: Published 03619 // Description: Returns the base-level texture that has been set on 03620 // this particular node, or NULL if no texture has been 03621 // set. This is not necessarily the texture that will 03622 // be applied to the geometry at or below this level, as 03623 // another texture at a higher or lower level may 03624 // override. 03625 // 03626 // See also find_texture(). 03627 //////////////////////////////////////////////////////////////////// 03628 Texture *NodePath:: 03629 get_texture() const { 03630 nassertr_always(!is_empty(), NULL); 03631 const RenderAttrib *attrib = 03632 node()->get_attrib(TextureAttrib::get_class_slot()); 03633 if (attrib != (const RenderAttrib *)NULL) { 03634 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03635 return ta->get_texture(); 03636 } 03637 03638 return NULL; 03639 } 03640 03641 //////////////////////////////////////////////////////////////////// 03642 // Function: NodePath::get_texture 03643 // Access: Published 03644 // Description: Returns the texture that has been set on the 03645 // indicated stage for this particular node, or NULL if 03646 // no texture has been set for this stage. 03647 //////////////////////////////////////////////////////////////////// 03648 Texture *NodePath:: 03649 get_texture(TextureStage *stage) const { 03650 nassertr_always(!is_empty(), NULL); 03651 const RenderAttrib *attrib = 03652 node()->get_attrib(TextureAttrib::get_class_slot()); 03653 if (attrib != (const RenderAttrib *)NULL) { 03654 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03655 return ta->get_on_texture(stage); 03656 } 03657 03658 return NULL; 03659 } 03660 03661 //////////////////////////////////////////////////////////////////// 03662 // Function: NodePath::set_shader 03663 // Access: Published 03664 // Description: 03665 //////////////////////////////////////////////////////////////////// 03666 void NodePath:: 03667 set_shader(const Shader *sha, int priority) { 03668 nassertv_always(!is_empty()); 03669 03670 const RenderAttrib *attrib = 03671 node()->get_attrib(ShaderAttrib::get_class_slot()); 03672 if (attrib != (const RenderAttrib *)NULL) { 03673 priority = max(priority, 03674 node()->get_state()->get_override(ShaderAttrib::get_class_slot())); 03675 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03676 node()->set_attrib(sa->set_shader(sha, priority)); 03677 } else { 03678 // Create a new ShaderAttrib for this node. 03679 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03680 node()->set_attrib(sa->set_shader(sha, priority)); 03681 } 03682 } 03683 03684 //////////////////////////////////////////////////////////////////// 03685 // Function: NodePath::set_shader_off 03686 // Access: Published 03687 // Description: 03688 //////////////////////////////////////////////////////////////////// 03689 void NodePath:: 03690 set_shader_off(int priority) { 03691 set_shader(NULL, priority); 03692 } 03693 03694 //////////////////////////////////////////////////////////////////// 03695 // Function: NodePath::set_shader_auto 03696 // Access: Published 03697 // Description: 03698 //////////////////////////////////////////////////////////////////// 03699 void NodePath:: 03700 set_shader_auto(int priority) { 03701 nassertv_always(!is_empty()); 03702 03703 const RenderAttrib *attrib = 03704 node()->get_attrib(ShaderAttrib::get_class_slot()); 03705 if (attrib != (const RenderAttrib *)NULL) { 03706 priority = max(priority, 03707 node()->get_state()->get_override(ShaderAttrib::get_class_slot())); 03708 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03709 node()->set_attrib(sa->set_shader_auto(priority)); 03710 } else { 03711 // Create a new ShaderAttrib for this node. 03712 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03713 node()->set_attrib(sa->set_shader_auto(priority)); 03714 } 03715 } 03716 03717 //////////////////////////////////////////////////////////////////// 03718 // Function: NodePath::clear_shader 03719 // Access: Published 03720 // Description: 03721 //////////////////////////////////////////////////////////////////// 03722 void NodePath:: 03723 clear_shader() { 03724 nassertv_always(!is_empty()); 03725 03726 const RenderAttrib *attrib = 03727 node()->get_attrib(ShaderAttrib::get_class_slot()); 03728 if (attrib != (const RenderAttrib *)NULL) { 03729 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03730 node()->set_attrib(sa->clear_shader()); 03731 } 03732 } 03733 03734 //////////////////////////////////////////////////////////////////// 03735 // Function: NodePath::get_shader 03736 // Access: Published 03737 // Description: 03738 //////////////////////////////////////////////////////////////////// 03739 const Shader *NodePath:: 03740 get_shader() const { 03741 nassertr_always(!is_empty(), NULL); 03742 const RenderAttrib *attrib = 03743 node()->get_attrib(ShaderAttrib::get_class_slot()); 03744 if (attrib != (const RenderAttrib *)NULL) { 03745 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03746 return sa->get_shader(); 03747 } 03748 return NULL; 03749 } 03750 03751 //////////////////////////////////////////////////////////////////// 03752 // Function: NodePath::set_shader_input 03753 // Access: Published 03754 // Description: 03755 //////////////////////////////////////////////////////////////////// 03756 void NodePath:: 03757 set_shader_input(const ShaderInput *inp) { 03758 nassertv_always(!is_empty()); 03759 03760 const RenderAttrib *attrib = 03761 node()->get_attrib(ShaderAttrib::get_class_slot()); 03762 if (attrib != (const RenderAttrib *)NULL) { 03763 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03764 node()->set_attrib(sa->set_shader_input(inp)); 03765 } else { 03766 // Create a new ShaderAttrib for this node. 03767 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03768 node()->set_attrib(sa->set_shader_input(inp)); 03769 } 03770 } 03771 03772 //////////////////////////////////////////////////////////////////// 03773 // Function: NodePath::get_shader_input 03774 // Access: Published 03775 // Description: 03776 //////////////////////////////////////////////////////////////////// 03777 const ShaderInput *NodePath:: 03778 get_shader_input(InternalName *id) const { 03779 nassertr_always(!is_empty(), NULL); 03780 03781 const RenderAttrib *attrib = 03782 node()->get_attrib(ShaderAttrib::get_class_slot()); 03783 if (attrib != (const RenderAttrib *)NULL) { 03784 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03785 return sa->get_shader_input(id); 03786 } 03787 return NULL; 03788 } 03789 03790 //////////////////////////////////////////////////////////////////// 03791 // Function: NodePath::get_instance_count 03792 // Access: Published 03793 // Description: Returns the geometry instance count, or 0 if 03794 // disabled. See set_instance_count. 03795 //////////////////////////////////////////////////////////////////// 03796 const int NodePath:: 03797 get_instance_count() const { 03798 nassertr_always(!is_empty(), NULL); 03799 const RenderAttrib *attrib = 03800 node()->get_attrib(ShaderAttrib::get_class_slot()); 03801 if (attrib != (const RenderAttrib *)NULL) { 03802 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03803 return sa->get_instance_count(); 03804 } 03805 return 0; 03806 } 03807 03808 //////////////////////////////////////////////////////////////////// 03809 // Function: NodePath::clear_shader_input 03810 // Access: Published 03811 // Description: 03812 //////////////////////////////////////////////////////////////////// 03813 void NodePath:: 03814 clear_shader_input(InternalName *id) { 03815 nassertv_always(!is_empty()); 03816 03817 const RenderAttrib *attrib = 03818 node()->get_attrib(ShaderAttrib::get_class_slot()); 03819 if (attrib != (const RenderAttrib *)NULL) { 03820 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03821 node()->set_attrib(sa->clear_shader_input(id)); 03822 } 03823 } 03824 03825 //////////////////////////////////////////////////////////////////// 03826 // Function: NodePath::set_shader_input 03827 // Access: Published 03828 // Description: 03829 //////////////////////////////////////////////////////////////////// 03830 void NodePath:: 03831 set_shader_input(InternalName *id, Texture *tex, int priority) { 03832 set_shader_input(new ShaderInput(id,tex,priority)); 03833 } 03834 03835 //////////////////////////////////////////////////////////////////// 03836 // Function: NodePath::set_shader_input 03837 // Access: Published 03838 // Description: 03839 //////////////////////////////////////////////////////////////////// 03840 void NodePath:: 03841 set_shader_input(InternalName *id, const NodePath &np, int priority) { 03842 set_shader_input(new ShaderInput(id,np,priority)); 03843 } 03844 03845 //////////////////////////////////////////////////////////////////// 03846 // Function: NodePath::set_shader_input 03847 // Access: Published 03848 // Description: 03849 //////////////////////////////////////////////////////////////////// 03850 void NodePath:: 03851 set_shader_input(InternalName *id, const LVector4f &v, int priority) { 03852 set_shader_input(new ShaderInput(id,v,priority)); 03853 } 03854 03855 //////////////////////////////////////////////////////////////////// 03856 // Function: NodePath::set_shader_input 03857 // Access: Published 03858 // Description: 03859 //////////////////////////////////////////////////////////////////// 03860 void NodePath:: 03861 set_shader_input(InternalName *id, double n1, double n2, double n3, double n4, int priority) { 03862 set_shader_input(new ShaderInput(id,LVector4f(n1,n2,n3,n4),priority)); 03863 } 03864 03865 //////////////////////////////////////////////////////////////////// 03866 // Function: NodePath::set_shader_input 03867 // Access: Published 03868 // Description: 03869 //////////////////////////////////////////////////////////////////// 03870 void NodePath:: 03871 set_shader_input(const string &id, Texture *tex, int priority) { 03872 set_shader_input(new ShaderInput(InternalName::make(id),tex,priority)); 03873 } 03874 03875 //////////////////////////////////////////////////////////////////// 03876 // Function: NodePath::set_shader_input 03877 // Access: Published 03878 // Description: 03879 //////////////////////////////////////////////////////////////////// 03880 void NodePath:: 03881 set_shader_input(const string &id, const NodePath &np, int priority) { 03882 set_shader_input(new ShaderInput(InternalName::make(id),np,priority)); 03883 } 03884 03885 //////////////////////////////////////////////////////////////////// 03886 // Function: NodePath::set_shader_input 03887 // Access: Published 03888 // Description: 03889 //////////////////////////////////////////////////////////////////// 03890 void NodePath:: 03891 set_shader_input(const string &id, const LVector4f &v, int priority) { 03892 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 03893 } 03894 03895 //////////////////////////////////////////////////////////////////// 03896 // Function: NodePath::set_shader_input 03897 // Access: Published 03898 // Description: 03899 //////////////////////////////////////////////////////////////////// 03900 void NodePath:: 03901 set_shader_input(const string &id, double n1, double n2, double n3, double n4, int priority) { 03902 set_shader_input(new ShaderInput(InternalName::make(id),LVector4f(n1,n2,n3,n4),priority)); 03903 } 03904 03905 //////////////////////////////////////////////////////////////////// 03906 // Function: NodePath::get_shader_input 03907 // Access: Published 03908 // Description: 03909 //////////////////////////////////////////////////////////////////// 03910 const ShaderInput *NodePath:: 03911 get_shader_input(const string &id) const { 03912 return get_shader_input(InternalName::make(id)); 03913 } 03914 03915 //////////////////////////////////////////////////////////////////// 03916 // Function: NodePath::clear_shader_input 03917 // Access: Published 03918 // Description: 03919 //////////////////////////////////////////////////////////////////// 03920 void NodePath:: 03921 clear_shader_input(const string &id) { 03922 clear_shader_input(InternalName::make(id)); 03923 } 03924 03925 //////////////////////////////////////////////////////////////////// 03926 // Function: NodePath::set_instance_count 03927 // Access: Published 03928 // Description: Sets the geometry instance count, or 0 if 03929 // geometry instancing should be disabled. Do not 03930 // confuse with instanceTo which only applies to 03931 // animation instancing. 03932 //////////////////////////////////////////////////////////////////// 03933 void NodePath:: 03934 set_instance_count(int instance_count) { 03935 nassertv_always(!is_empty()); 03936 03937 const RenderAttrib *attrib = 03938 node()->get_attrib(ShaderAttrib::get_class_slot()); 03939 if (attrib != (const RenderAttrib *)NULL) { 03940 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03941 node()->set_attrib(sa->set_instance_count(instance_count)); 03942 } else { 03943 // Create a new ShaderAttrib for this node. 03944 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03945 node()->set_attrib(sa->set_instance_count(instance_count)); 03946 } 03947 } 03948 03949 //////////////////////////////////////////////////////////////////// 03950 // Function: NodePath::set_tex_transform 03951 // Access: Published 03952 // Description: Sets the texture matrix on the current node to the 03953 // indicated transform for the given stage. 03954 //////////////////////////////////////////////////////////////////// 03955 void NodePath:: 03956 set_tex_transform(TextureStage *stage, const TransformState *transform) { 03957 nassertv_always(!is_empty()); 03958 03959 const RenderAttrib *attrib = 03960 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 03961 if (attrib != (const RenderAttrib *)NULL) { 03962 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 03963 03964 // Modify the existing TexMatrixAttrib to add the indicated 03965 // stage. 03966 node()->set_attrib(tma->add_stage(stage, transform)); 03967 03968 } else { 03969 // Create a new TexMatrixAttrib for this node. 03970 node()->set_attrib(TexMatrixAttrib::make(stage, transform)); 03971 } 03972 } 03973 03974 //////////////////////////////////////////////////////////////////// 03975 // Function: NodePath::clear_tex_transform 03976 // Access: Published 03977 // Description: Removes all texture matrices from the current node. 03978 //////////////////////////////////////////////////////////////////// 03979 void NodePath:: 03980 clear_tex_transform() { 03981 nassertv_always(!is_empty()); 03982 node()->clear_attrib(TexMatrixAttrib::get_class_slot()); 03983 } 03984 03985 //////////////////////////////////////////////////////////////////// 03986 // Function: NodePath::clear_tex_transform 03987 // Access: Published 03988 // Description: Removes the texture matrix on the current node for 03989 // the given stage. 03990 //////////////////////////////////////////////////////////////////// 03991 void NodePath:: 03992 clear_tex_transform(TextureStage *stage) { 03993 nassertv_always(!is_empty()); 03994 03995 const RenderAttrib *attrib = 03996 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 03997 if (attrib != (const RenderAttrib *)NULL) { 03998 CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, attrib); 03999 tma = DCAST(TexMatrixAttrib, tma->remove_stage(stage)); 04000 04001 if (tma->is_empty()) { 04002 node()->clear_attrib(TexMatrixAttrib::get_class_slot()); 04003 04004 } else { 04005 node()->set_attrib(tma); 04006 } 04007 } 04008 } 04009 04010 //////////////////////////////////////////////////////////////////// 04011 // Function: NodePath::has_tex_transform 04012 // Access: Published 04013 // Description: Returns true if there is an explicit texture matrix 04014 // on the current node for the given stage. 04015 //////////////////////////////////////////////////////////////////// 04016 bool NodePath:: 04017 has_tex_transform(TextureStage *stage) const { 04018 nassertr_always(!is_empty(), false); 04019 04020 const RenderAttrib *attrib = 04021 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 04022 if (attrib != (const RenderAttrib *)NULL) { 04023 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04024 return tma->has_stage(stage); 04025 } 04026 04027 return false; 04028 } 04029 04030 //////////////////////////////////////////////////////////////////// 04031 // Function: NodePath::get_tex_transform 04032 // Access: Published 04033 // Description: Returns the texture matrix on the current node for the 04034 // given stage, or identity transform if there is no 04035 // explicit transform set for the given stage. 04036 //////////////////////////////////////////////////////////////////// 04037 CPT(TransformState) NodePath:: 04038 get_tex_transform(TextureStage *stage) const { 04039 nassertr_always(!is_empty(), NULL); 04040 04041 const RenderAttrib *attrib = 04042 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 04043 if (attrib != (const RenderAttrib *)NULL) { 04044 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04045 return tma->get_transform(stage); 04046 } 04047 04048 return TransformState::make_identity(); 04049 } 04050 04051 //////////////////////////////////////////////////////////////////// 04052 // Function: NodePath::set_tex_transform 04053 // Access: Published 04054 // Description: Sets the texture matrix on the current node to the 04055 // indicated transform for the given stage. 04056 //////////////////////////////////////////////////////////////////// 04057 void NodePath:: 04058 set_tex_transform(const NodePath &other, TextureStage *stage, const TransformState *transform) { 04059 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 04060 nassertv_always(!is_empty()); 04061 04062 CPT(RenderState) state = get_state(other); 04063 const RenderAttrib *attrib = 04064 state->get_attrib(TexMatrixAttrib::get_class_slot()); 04065 if (attrib != (const RenderAttrib *)NULL) { 04066 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04067 04068 // Modify the existing TexMatrixAttrib to add the indicated 04069 // stage. 04070 state = state->add_attrib(tma->add_stage(stage, transform)); 04071 04072 } else { 04073 // Create a new TexMatrixAttrib for this node. 04074 state = state->add_attrib(TexMatrixAttrib::make(stage, transform)); 04075 } 04076 04077 // Now compose that with our parent's state. 04078 CPT(RenderState) rel_state; 04079 if (has_parent()) { 04080 rel_state = other.get_state(get_parent()); 04081 } else { 04082 rel_state = other.get_state(NodePath()); 04083 } 04084 CPT(RenderState) new_state = rel_state->compose(state); 04085 04086 // And apply only the TexMatrixAttrib to the current node, leaving 04087 // the others unchanged. 04088 node()->set_attrib(new_state->get_attrib(TexMatrixAttrib::get_class_slot())); 04089 } 04090 04091 //////////////////////////////////////////////////////////////////// 04092 // Function: NodePath::get_tex_transform 04093 // Access: Published 04094 // Description: Returns the texture matrix on the current node for the 04095 // given stage, relative to the other node. 04096 //////////////////////////////////////////////////////////////////// 04097 CPT(TransformState) NodePath:: 04098 get_tex_transform(const NodePath &other, TextureStage *stage) const { 04099 nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity()); 04100 04101 CPT(RenderState) state = get_state(other); 04102 const RenderAttrib *attrib = 04103 state->get_attrib(TexMatrixAttrib::get_class_slot()); 04104 if (attrib != (const RenderAttrib *)NULL) { 04105 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04106 return tma->get_transform(stage); 04107 } 04108 04109 return TransformState::make_identity(); 04110 } 04111 04112 //////////////////////////////////////////////////////////////////// 04113 // Function: NodePath::set_tex_gen 04114 // Access: Published 04115 // Description: Enables automatic texture coordinate generation for 04116 // the indicated texture stage. 04117 //////////////////////////////////////////////////////////////////// 04118 void NodePath:: 04119 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) { 04120 nassertv_always(!is_empty()); 04121 04122 const RenderAttrib *attrib = 04123 node()->get_attrib(TexGenAttrib::get_class_slot()); 04124 04125 CPT(TexGenAttrib) tga; 04126 04127 if (attrib != (const RenderAttrib *)NULL) { 04128 priority = max(priority, 04129 node()->get_state()->get_override(TextureAttrib::get_class_slot())); 04130 tga = DCAST(TexGenAttrib, attrib); 04131 04132 } else { 04133 tga = DCAST(TexGenAttrib, TexGenAttrib::make()); 04134 } 04135 04136 node()->set_attrib(tga->add_stage(stage, mode), priority); 04137 } 04138 04139 //////////////////////////////////////////////////////////////////// 04140 // Function: NodePath::set_tex_gen 04141 // Access: Published 04142 // Description: Enables automatic texture coordinate generation for 04143 // the indicated texture stage. This version of this 04144 // method is useful when setting M_light_vector, which 04145 // requires the name of the texture coordinate set that 04146 // supplies the tangent and binormal, as well as the 04147 // specific light to generate coordinates for. 04148 //////////////////////////////////////////////////////////////////// 04149 void NodePath:: 04150 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 04151 const string &source_name, const NodePath &light, int priority) { 04152 nassertv_always(!is_empty()); 04153 04154 const RenderAttrib *attrib = 04155 node()->get_attrib(TexGenAttrib::get_class_slot()); 04156 04157 CPT(TexGenAttrib) tga; 04158 04159 if (attrib != (const RenderAttrib *)NULL) { 04160 priority = max(priority, 04161 node()->get_state()->get_override(TextureAttrib::get_class_slot())); 04162 tga = DCAST(TexGenAttrib, attrib); 04163 04164 } else { 04165 tga = DCAST(TexGenAttrib, TexGenAttrib::make()); 04166 } 04167 04168 node()->set_attrib(tga->add_stage(stage, mode, source_name, light), priority); 04169 } 04170 04171 //////////////////////////////////////////////////////////////////// 04172 // Function: NodePath::set_tex_gen 04173 // Access: Published 04174 // Description: Enables automatic texture coordinate generation for 04175 // the indicated texture stage. This version of this 04176 // method is useful when setting M_constant, which 04177 // requires a constant texture coordinate value. 04178 //////////////////////////////////////////////////////////////////// 04179 void NodePath:: 04180 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 04181 const TexCoord3f &constant_value, int priority) { 04182 nassertv_always(!is_empty()); 04183 04184 const RenderAttrib *attrib = 04185 node()->get_attrib(TexGenAttrib::get_class_slot()); 04186 04187 CPT(TexGenAttrib) tga; 04188 04189 if (attrib != (const RenderAttrib *)NULL) { 04190 priority = max(priority, 04191 node()->get_state()->get_override(TextureAttrib::get_class_slot())); 04192 tga = DCAST(TexGenAttrib, attrib); 04193 04194 } else { 04195 tga = DCAST(TexGenAttrib, TexGenAttrib::make()); 04196 } 04197 04198 node()->set_attrib(tga->add_stage(stage, mode, constant_value), priority); 04199 } 04200 04201 //////////////////////////////////////////////////////////////////// 04202 // Function: NodePath::clear_tex_gen 04203 // Access: Published 04204 // Description: Removes the texture coordinate generation mode from 04205 // all texture stages on this node. 04206 //////////////////////////////////////////////////////////////////// 04207 void NodePath:: 04208 clear_tex_gen() { 04209 nassertv_always(!is_empty()); 04210 node()->clear_attrib(TexGenAttrib::get_class_slot()); 04211 } 04212 04213 //////////////////////////////////////////////////////////////////// 04214 // Function: NodePath::clear_tex_gen 04215 // Access: Published 04216 // Description: Disables automatic texture coordinate generation for 04217 // the indicated texture stage. 04218 //////////////////////////////////////////////////////////////////// 04219 void NodePath:: 04220 clear_tex_gen(TextureStage *stage) { 04221 nassertv_always(!is_empty()); 04222 04223 const RenderAttrib *attrib = 04224 node()->get_attrib(TexGenAttrib::get_class_slot()); 04225 if (attrib != (const RenderAttrib *)NULL) { 04226 CPT(TexGenAttrib) tga = DCAST(TexGenAttrib, attrib); 04227 tga = DCAST(TexGenAttrib, tga->remove_stage(stage)); 04228 04229 if (tga->is_empty()) { 04230 node()->clear_attrib(TexGenAttrib::get_class_slot()); 04231 04232 } else { 04233 node()->set_attrib(tga); 04234 } 04235 } 04236 } 04237 04238 //////////////////////////////////////////////////////////////////// 04239 // Function: NodePath::has_tex_gen 04240 // Access: Published 04241 // Description: Returns true if there is a mode for automatic texture 04242 // coordinate generation on the current node for the 04243 // given stage. 04244 //////////////////////////////////////////////////////////////////// 04245 bool NodePath:: 04246 has_tex_gen(TextureStage *stage) const { 04247 nassertr_always(!is_empty(), false); 04248 04249 const RenderAttrib *attrib = 04250 node()->get_attrib(TexGenAttrib::get_class_slot()); 04251 if (attrib != (const RenderAttrib *)NULL) { 04252 const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib); 04253 return tga->has_stage(stage); 04254 } 04255 04256 return false; 04257 } 04258 04259 //////////////////////////////////////////////////////////////////// 04260 // Function: NodePath::get_tex_gen 04261 // Access: Published 04262 // Description: Returns the texture coordinate generation mode for 04263 // the given stage, or M_off if there is no explicit 04264 // mode set for the given stage. 04265 //////////////////////////////////////////////////////////////////// 04266 RenderAttrib::TexGenMode NodePath:: 04267 get_tex_gen(TextureStage *stage) const { 04268 nassertr_always(!is_empty(), TexGenAttrib::M_off); 04269 04270 const RenderAttrib *attrib = 04271 node()->get_attrib(TexGenAttrib::get_class_slot()); 04272 if (attrib != (const RenderAttrib *)NULL) { 04273 const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib); 04274 return tga->get_mode(stage); 04275 } 04276 04277 return TexGenAttrib::M_off; 04278 } 04279 04280 //////////////////////////////////////////////////////////////////// 04281 // Function: NodePath::get_tex_gen_light 04282 // Access: Published 04283 // Description: Returns the particular Light set for the indicated 04284 // texgen mode's texture stage, or empty NodePath if no 04285 // light is set. This is only meaningful if the texgen 04286 // mode (returned by get_tex_gen()) is M_light_vector. 04287 //////////////////////////////////////////////////////////////////// 04288 NodePath NodePath:: 04289 get_tex_gen_light(TextureStage *stage) const { 04290 nassertr_always(!is_empty(), NodePath::fail()); 04291 04292 const RenderAttrib *attrib = 04293 node()->get_attrib(TexGenAttrib::get_class_slot()); 04294 if (attrib != (const RenderAttrib *)NULL) { 04295 const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib); 04296 return tga->get_light(stage); 04297 } 04298 04299 return NodePath(); 04300 } 04301 04302 //////////////////////////////////////////////////////////////////// 04303 // Function: NodePath::set_tex_projector 04304 // Access: Published 04305 // Description: Establishes a TexProjectorEffect on this node, which 04306 // can be used to establish projective texturing (but 04307 // see also the NodePath::project_texture() convenience 04308 // function), or it can be used to bind this node's 04309 // texture transform to particular node's position in 04310 // space, allowing a LerpInterval (for instance) to 04311 // adjust this node's texture coordinates. 04312 //////////////////////////////////////////////////////////////////// 04313 void NodePath:: 04314 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to) { 04315 nassertv_always(!is_empty()); 04316 04317 const RenderEffect *effect = 04318 node()->get_effect(TexProjectorEffect::get_class_type()); 04319 04320 CPT(TexProjectorEffect) tpe; 04321 04322 if (effect != (const RenderEffect *)NULL) { 04323 tpe = DCAST(TexProjectorEffect, effect); 04324 04325 } else { 04326 tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make()); 04327 } 04328 04329 node()->set_effect(tpe->add_stage(stage, from, to)); 04330 } 04331 04332 //////////////////////////////////////////////////////////////////// 04333 // Function: NodePath::clear_tex_projector 04334 // Access: Published 04335 // Description: Removes the TexProjectorEffect for the indicated 04336 // stage from this node. 04337 //////////////////////////////////////////////////////////////////// 04338 void NodePath:: 04339 clear_tex_projector(TextureStage *stage) { 04340 nassertv_always(!is_empty()); 04341 04342 const RenderEffect *effect = 04343 node()->get_effect(TexProjectorEffect::get_class_type()); 04344 if (effect != (const RenderEffect *)NULL) { 04345 CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect); 04346 tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage)); 04347 04348 if (tpe->is_empty()) { 04349 node()->clear_effect(TexProjectorEffect::get_class_type()); 04350 04351 } else { 04352 node()->set_effect(tpe); 04353 } 04354 } 04355 } 04356 04357 //////////////////////////////////////////////////////////////////// 04358 // Function: NodePath::clear_tex_projector 04359 // Access: Published 04360 // Description: Removes the TexProjectorEffect for all stages from 04361 // this node. 04362 //////////////////////////////////////////////////////////////////// 04363 void NodePath:: 04364 clear_tex_projector() { 04365 nassertv_always(!is_empty()); 04366 node()->clear_effect(TexProjectorEffect::get_class_type()); 04367 } 04368 04369 //////////////////////////////////////////////////////////////////// 04370 // Function: NodePath::has_tex_projector 04371 // Access: Published 04372 // Description: Returns true if this node has a TexProjectorEffect 04373 // for the indicated stage, false otherwise. 04374 //////////////////////////////////////////////////////////////////// 04375 bool NodePath:: 04376 has_tex_projector(TextureStage *stage) const { 04377 nassertr_always(!is_empty(), false); 04378 04379 const RenderEffect *effect = 04380 node()->get_effect(TexProjectorEffect::get_class_type()); 04381 if (effect != (const RenderEffect *)NULL) { 04382 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect); 04383 return tpe->has_stage(stage); 04384 } 04385 04386 return false; 04387 } 04388 04389 //////////////////////////////////////////////////////////////////// 04390 // Function: NodePath::get_tex_projector_from 04391 // Access: Published 04392 // Description: Returns the "from" node associated with the 04393 // TexProjectorEffect on the indicated stage. The 04394 // relative transform between the "from" and the "to" 04395 // nodes is automatically applied to the texture 04396 // transform each frame. 04397 //////////////////////////////////////////////////////////////////// 04398 NodePath NodePath:: 04399 get_tex_projector_from(TextureStage *stage) const { 04400 nassertr_always(!is_empty(), NodePath::fail()); 04401 04402 const RenderEffect *effect = 04403 node()->get_effect(TexProjectorEffect::get_class_type()); 04404 if (effect != (const RenderEffect *)NULL) { 04405 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect); 04406 return tpe->get_from(stage); 04407 } 04408 04409 return NodePath::not_found(); 04410 } 04411 04412 //////////////////////////////////////////////////////////////////// 04413 // Function: NodePath::get_tex_projector_to 04414 // Access: Published 04415 // Description: Returns the "to" node associated with the 04416 // TexProjectorEffect on the indicated stage. The 04417 // relative transform between the "from" and the "to" 04418 // nodes is automatically applied to the texture 04419 // transform each frame. 04420 //////////////////////////////////////////////////////////////////// 04421 NodePath NodePath:: 04422 get_tex_projector_to(TextureStage *stage) const { 04423 nassertr_always(!is_empty(), NodePath::fail()); 04424 04425 const RenderEffect *effect = 04426 node()->get_effect(TexProjectorEffect::get_class_type()); 04427 if (effect != (const RenderEffect *)NULL) { 04428 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect); 04429 return tpe->get_to(stage); 04430 } 04431 04432 return NodePath::not_found(); 04433 } 04434 04435 //////////////////////////////////////////////////////////////////// 04436 // Function: NodePath::project_texture 04437 // Access: Published 04438 // Description: A convenience function to enable projective texturing 04439 // at this node level and below, using the indicated 04440 // NodePath (which should contain a LensNode) as the 04441 // projector. 04442 //////////////////////////////////////////////////////////////////// 04443 void NodePath:: 04444 project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) { 04445 nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type())); 04446 set_texture(stage, tex); 04447 set_tex_gen(stage, TexGenAttrib::M_world_position); 04448 set_tex_projector(stage, NodePath(), projector); 04449 } 04450 04451 04452 //////////////////////////////////////////////////////////////////// 04453 // Function: NodePath::set_normal_map 04454 // Access: Published 04455 // Description: A convenience function to set up a normal map on this 04456 // geometry. This uses the single highest-priority 04457 // light on the object only. It also requires 04458 // multitexture, and consumes at least two texture 04459 // stages, in addition to what may already be in use. 04460 // 04461 // The normal_map parameter is the texture that contains 04462 // the normal map information (with a 3-d delta vector 04463 // encoded into the r,g,b of each texel). texcoord_name is 04464 // the name of the texture coordinate set that contains 04465 // the tangent and binormal we wish to use. If 04466 // preserve_color is true, then one additional texture 04467 // stage is consumed to blend in the geometry's original 04468 // vertex color. 04469 // 04470 // Only one normal map may be in effect through this 04471 // interface at any given time. 04472 //////////////////////////////////////////////////////////////////// 04473 void NodePath:: 04474 set_normal_map(Texture *normal_map, const string &texcoord_name, 04475 bool preserve_color) { 04476 clear_normal_map(); 04477 04478 // First, we apply the normal map itself, to the bottom layer. 04479 PT(TextureStage) normal_map_ts = new TextureStage("__normal_map"); 04480 normal_map_ts->set_texcoord_name(texcoord_name); 04481 normal_map_ts->set_sort(-20); 04482 normal_map_ts->set_mode(TextureStage::M_replace); 04483 set_texture(normal_map_ts, normal_map); 04484 04485 // Then, we apply a normalization map, to normalize, per-pixel, the 04486 // vector to the light. 04487 PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32); 04488 PT(TextureStage) normalization_map_ts = new TextureStage("__normalization_map"); 04489 normalization_map_ts->set_combine_rgb 04490 (TextureStage::CM_dot3_rgb, 04491 TextureStage::CS_texture, TextureStage::CO_src_color, 04492 TextureStage::CS_previous, TextureStage::CO_src_color); 04493 normalization_map_ts->set_texcoord_name("light_vector"); 04494 normalization_map_ts->set_sort(-15); 04495 set_texture(normalization_map_ts, normalization_map); 04496 04497 // Finally, we enable M_light_vector texture coordinate generation. 04498 set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector, 04499 texcoord_name, NodePath()); 04500 04501 if (preserve_color) { 04502 // One more stage to get back the original color. 04503 PT(TextureStage) orig_color_ts = new TextureStage("__orig_color"); 04504 orig_color_ts->set_combine_rgb 04505 (TextureStage::CM_modulate, 04506 TextureStage::CS_primary_color, TextureStage::CO_src_color, 04507 TextureStage::CS_previous, TextureStage::CO_src_color); 04508 set_texture(orig_color_ts, normal_map); 04509 } 04510 } 04511 04512 //////////////////////////////////////////////////////////////////// 04513 // Function: NodePath::clear_normal_map 04514 // Access: Published 04515 // Description: Undoes the effect of a previous call to 04516 // set_normal_map(). 04517 //////////////////////////////////////////////////////////////////// 04518 void NodePath:: 04519 clear_normal_map() { 04520 // Scan through the TextureStages, and if we find any whose name 04521 // matches one of the stages that would have been left by 04522 // set_normal_map(), remove it from the state. 04523 04524 CPT(RenderAttrib) attrib = 04525 get_state()->get_attrib(TextureAttrib::get_class_slot()); 04526 if (attrib != (const RenderAttrib *)NULL) { 04527 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 04528 for (int i = 0; i < ta->get_num_on_stages(); i++) { 04529 TextureStage *stage = ta->get_on_stage(i); 04530 if (stage->get_name() == "__normal_map") { 04531 clear_texture(stage); 04532 04533 } else if (stage->get_name() == "__normalization_map") { 04534 clear_texture(stage); 04535 clear_tex_gen(stage); 04536 04537 } else if (stage->get_name() == "__orig_color") { 04538 clear_texture(stage); 04539 } 04540 } 04541 } 04542 } 04543 04544 //////////////////////////////////////////////////////////////////// 04545 // Function: NodePath::has_vertex_column 04546 // Access: Published 04547 // Description: Returns true if there are at least some vertices at 04548 // this node and below that contain a reference to the 04549 // indicated vertex data column name, false otherwise. 04550 // 04551 // This is particularly useful for testing whether a 04552 // particular model has a given texture coordinate set 04553 // (but see has_texcoord()). 04554 //////////////////////////////////////////////////////////////////// 04555 bool NodePath:: 04556 has_vertex_column(const InternalName *name) const { 04557 nassertr_always(!is_empty(), false); 04558 return r_has_vertex_column(node(), name); 04559 } 04560 04561 //////////////////////////////////////////////////////////////////// 04562 // Function: NodePath::find_all_vertex_columns 04563 // Access: Published 04564 // Description: Returns a list of all vertex array columns stored on 04565 // some geometry found at this node level and below. 04566 //////////////////////////////////////////////////////////////////// 04567 InternalNameCollection NodePath:: 04568 find_all_vertex_columns() const { 04569 nassertr_always(!is_empty(), InternalNameCollection()); 04570 InternalNames vertex_columns; 04571 r_find_all_vertex_columns(node(), vertex_columns); 04572 04573 InternalNameCollection tc; 04574 InternalNames::iterator ti; 04575 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 04576 tc.add_name(*ti); 04577 } 04578 return tc; 04579 } 04580 04581 //////////////////////////////////////////////////////////////////// 04582 // Function: NodePath::find_all_vertex_columns 04583 // Access: Published 04584 // Description: Returns a list of all vertex array columns stored on 04585 // some geometry found at this node level and below that 04586 // match the indicated name (which may contain wildcard 04587 // characters). 04588 //////////////////////////////////////////////////////////////////// 04589 InternalNameCollection NodePath:: 04590 find_all_vertex_columns(const string &name) const { 04591 nassertr_always(!is_empty(), InternalNameCollection()); 04592 InternalNames vertex_columns; 04593 r_find_all_vertex_columns(node(), vertex_columns); 04594 04595 GlobPattern glob(name); 04596 04597 InternalNameCollection tc; 04598 InternalNames::iterator ti; 04599 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 04600 InternalName *name = (*ti); 04601 if (glob.matches(name->get_name())) { 04602 tc.add_name(name); 04603 } 04604 } 04605 return tc; 04606 } 04607 04608 //////////////////////////////////////////////////////////////////// 04609 // Function: NodePath::find_all_texcoords 04610 // Access: Published 04611 // Description: Returns a list of all texture coordinate sets used by 04612 // any geometry at this node level and below. 04613 //////////////////////////////////////////////////////////////////// 04614 InternalNameCollection NodePath:: 04615 find_all_texcoords() const { 04616 nassertr_always(!is_empty(), InternalNameCollection()); 04617 InternalNames vertex_columns; 04618 r_find_all_vertex_columns(node(), vertex_columns); 04619 04620 CPT(InternalName) texcoord_name = InternalName::get_texcoord(); 04621 04622 InternalNameCollection tc; 04623 InternalNames::iterator ti; 04624 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 04625 if ((*ti)->get_top() == texcoord_name) { 04626 tc.add_name(*ti); 04627 } 04628 } 04629 return tc; 04630 } 04631 04632 //////////////////////////////////////////////////////////////////// 04633 // Function: NodePath::find_all_texcoords 04634 // Access: Published 04635 // Description: Returns a list of all texture coordinate sets used by 04636 // any geometry at this node level and below that match 04637 // the indicated name (which may contain wildcard 04638 // characters). 04639 //////////////////////////////////////////////////////////////////// 04640 InternalNameCollection NodePath:: 04641 find_all_texcoords(const string &name) const { 04642 nassertr_always(!is_empty(), InternalNameCollection()); 04643 InternalNames vertex_columns; 04644 r_find_all_vertex_columns(node(), vertex_columns); 04645 04646 GlobPattern glob(name); 04647 CPT(InternalName) texcoord_name = InternalName::get_texcoord(); 04648 04649 InternalNameCollection tc; 04650 InternalNames::iterator ti; 04651 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 04652 InternalName *name = (*ti); 04653 if (name->get_top() == texcoord_name) { 04654 // This is a texture coordinate name. Figure out the basename 04655 // of the texture coordinates. 04656 int index = name->find_ancestor("texcoord"); 04657 nassertr(index != -1, InternalNameCollection()); 04658 string net_basename = name->get_net_basename(index - 1); 04659 04660 if (glob.matches(net_basename)) { 04661 tc.add_name(name); 04662 } 04663 } 04664 } 04665 return tc; 04666 } 04667 04668 //////////////////////////////////////////////////////////////////// 04669 // Function: NodePath::find_texture 04670 // Access: Published 04671 // Description: Returns the first texture found applied to geometry 04672 // at this node or below that matches the indicated name 04673 // (which may contain wildcards). Returns the texture 04674 // if it is found, or NULL if it is not. 04675 //////////////////////////////////////////////////////////////////// 04676 Texture *NodePath:: 04677 find_texture(const string &name) const { 04678 nassertr_always(!is_empty(), NULL); 04679 GlobPattern glob(name); 04680 return r_find_texture(node(), get_net_state(), glob); 04681 } 04682 04683 //////////////////////////////////////////////////////////////////// 04684 // Function: NodePath::find_texture 04685 // Access: Published 04686 // Description: Returns the first texture found applied to geometry 04687 // at this node or below that is assigned to the 04688 // indicated texture stage. Returns the texture if it 04689 // is found, or NULL if it is not. 04690 //////////////////////////////////////////////////////////////////// 04691 Texture *NodePath:: 04692 find_texture(TextureStage *stage) const { 04693 nassertr_always(!is_empty(), NULL); 04694 return r_find_texture(node(), stage); 04695 } 04696 04697 //////////////////////////////////////////////////////////////////// 04698 // Function: NodePath::find_all_textures 04699 // Access: Published 04700 // Description: Returns a list of a textures applied to geometry at 04701 // this node and below. 04702 //////////////////////////////////////////////////////////////////// 04703 TextureCollection NodePath:: 04704 find_all_textures() const { 04705 nassertr_always(!is_empty(), TextureCollection()); 04706 Textures textures; 04707 r_find_all_textures(node(), get_net_state(), textures); 04708 04709 TextureCollection tc; 04710 Textures::iterator ti; 04711 for (ti = textures.begin(); ti != textures.end(); ++ti) { 04712 tc.add_texture(*ti); 04713 } 04714 return tc; 04715 } 04716 04717 //////////////////////////////////////////////////////////////////// 04718 // Function: NodePath::find_all_textures 04719 // Access: Published 04720 // Description: Returns a list of a textures applied to geometry at 04721 // this node and below that match the indicated name 04722 // (which may contain wildcard characters). 04723 //////////////////////////////////////////////////////////////////// 04724 TextureCollection NodePath:: 04725 find_all_textures(const string &name) const { 04726 nassertr_always(!is_empty(), TextureCollection()); 04727 Textures textures; 04728 r_find_all_textures(node(), get_net_state(), textures); 04729 04730 GlobPattern glob(name); 04731 04732 TextureCollection tc; 04733 Textures::iterator ti; 04734 for (ti = textures.begin(); ti != textures.end(); ++ti) { 04735 Texture *texture = (*ti); 04736 if (glob.matches(texture->get_name())) { 04737 tc.add_texture(texture); 04738 } 04739 } 04740 return tc; 04741 } 04742 04743 //////////////////////////////////////////////////////////////////// 04744 // Function: NodePath::find_all_textures 04745 // Access: Published 04746 // Description: Returns a list of a textures on geometry at 04747 // this node and below that are assigned to the 04748 // indicated texture stage. 04749 //////////////////////////////////////////////////////////////////// 04750 TextureCollection NodePath:: 04751 find_all_textures(TextureStage *stage) const { 04752 nassertr_always(!is_empty(), TextureCollection()); 04753 Textures textures; 04754 r_find_all_textures(node(), stage, textures); 04755 04756 TextureCollection tc; 04757 Textures::iterator ti; 04758 for (ti = textures.begin(); ti != textures.end(); ++ti) { 04759 Texture *texture = (*ti); 04760 tc.add_texture(texture); 04761 } 04762 return tc; 04763 } 04764 04765 //////////////////////////////////////////////////////////////////// 04766 // Function: NodePath::find_texture_stage 04767 // Access: Published 04768 // Description: Returns the first TextureStage found applied to 04769 // geometry at this node or below that matches the 04770 // indicated name (which may contain wildcards). 04771 // Returns the TextureStage if it is found, or NULL if 04772 // it is not. 04773 //////////////////////////////////////////////////////////////////// 04774 TextureStage *NodePath:: 04775 find_texture_stage(const string &name) const { 04776 nassertr_always(!is_empty(), NULL); 04777 GlobPattern glob(name); 04778 return r_find_texture_stage(node(), get_net_state(), glob); 04779 } 04780 04781 //////////////////////////////////////////////////////////////////// 04782 // Function: NodePath::find_all_texture_stages 04783 // Access: Published 04784 // Description: Returns a list of a TextureStages applied to geometry 04785 // at this node and below. 04786 //////////////////////////////////////////////////////////////////// 04787 TextureStageCollection NodePath:: 04788 find_all_texture_stages() const { 04789 nassertr_always(!is_empty(), TextureStageCollection()); 04790 TextureStages texture_stages; 04791 r_find_all_texture_stages(node(), get_net_state(), texture_stages); 04792 04793 TextureStageCollection tc; 04794 TextureStages::iterator ti; 04795 for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) { 04796 tc.add_texture_stage(*ti); 04797 } 04798 return tc; 04799 } 04800 04801 //////////////////////////////////////////////////////////////////// 04802 // Function: NodePath::unify_texture_stages 04803 // Access: Published 04804 // Description: Searches through all TextureStages at this node and 04805 // below. Any TextureStages that share the same name as 04806 // the indicated TextureStage object are replaced with 04807 // this object, thus ensuring that all geometry at this 04808 // node and below with a particular TextureStage name is 04809 // using the same TextureStage object. 04810 //////////////////////////////////////////////////////////////////// 04811 void NodePath:: 04812 unify_texture_stages(TextureStage *stage) { 04813 nassertv_always(!is_empty()); 04814 r_unify_texture_stages(node(), stage); 04815 } 04816 04817 //////////////////////////////////////////////////////////////////// 04818 // Function: NodePath::find_all_texture_stages 04819 // Access: Published 04820 // Description: Returns a list of a TextureStages applied to geometry 04821 // at this node and below that match the indicated name 04822 // (which may contain wildcard characters). 04823 //////////////////////////////////////////////////////////////////// 04824 TextureStageCollection NodePath:: 04825 find_all_texture_stages(const string &name) const { 04826 nassertr_always(!is_empty(), TextureStageCollection()); 04827 TextureStages texture_stages; 04828 r_find_all_texture_stages(node(), get_net_state(), texture_stages); 04829 04830 GlobPattern glob(name); 04831 04832 TextureStageCollection tc; 04833 TextureStages::iterator ti; 04834 for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) { 04835 TextureStage *texture_stage = (*ti); 04836 if (glob.matches(texture_stage->get_name())) { 04837 tc.add_texture_stage(texture_stage); 04838 } 04839 } 04840 return tc; 04841 } 04842 04843 //////////////////////////////////////////////////////////////////// 04844 // Function: NodePath::find_material 04845 // Access: Published 04846 // Description: Returns the first material found applied to geometry 04847 // at this node or below that matches the indicated name 04848 // (which may contain wildcards). Returns the material 04849 // if it is found, or NULL if it is not. 04850 //////////////////////////////////////////////////////////////////// 04851 Material *NodePath:: 04852 find_material(const string &name) const { 04853 nassertr_always(!is_empty(), NULL); 04854 GlobPattern glob(name); 04855 return r_find_material(node(), get_net_state(), glob); 04856 } 04857 04858 //////////////////////////////////////////////////////////////////// 04859 // Function: NodePath::find_all_materials 04860 // Access: Published 04861 // Description: Returns a list of a materials applied to geometry at 04862 // this node and below. 04863 //////////////////////////////////////////////////////////////////// 04864 MaterialCollection NodePath:: 04865 find_all_materials() const { 04866 nassertr_always(!is_empty(), MaterialCollection()); 04867 Materials materials; 04868 r_find_all_materials(node(), get_net_state(), materials); 04869 04870 MaterialCollection tc; 04871 Materials::iterator ti; 04872 for (ti = materials.begin(); ti != materials.end(); ++ti) { 04873 tc.add_material(*ti); 04874 } 04875 return tc; 04876 } 04877 04878 //////////////////////////////////////////////////////////////////// 04879 // Function: NodePath::find_all_materials 04880 // Access: Published 04881 // Description: Returns a list of a materials applied to geometry at 04882 // this node and below that match the indicated name 04883 // (which may contain wildcard characters). 04884 //////////////////////////////////////////////////////////////////// 04885 MaterialCollection NodePath:: 04886 find_all_materials(const string &name) const { 04887 nassertr_always(!is_empty(), MaterialCollection()); 04888 Materials materials; 04889 r_find_all_materials(node(), get_net_state(), materials); 04890 04891 GlobPattern glob(name); 04892 04893 MaterialCollection tc; 04894 Materials::iterator ti; 04895 for (ti = materials.begin(); ti != materials.end(); ++ti) { 04896 Material *material = (*ti); 04897 if (glob.matches(material->get_name())) { 04898 tc.add_material(material); 04899 } 04900 } 04901 return tc; 04902 } 04903 04904 //////////////////////////////////////////////////////////////////// 04905 // Function: NodePath::set_material 04906 // Access: Published 04907 // Description: Sets the geometry at this level and below to render 04908 // using the indicated material. 04909 // 04910 // Previously, this operation made a copy of the 04911 // material structure, but nowadays it assigns the 04912 // pointer directly. 04913 //////////////////////////////////////////////////////////////////// 04914 void NodePath:: 04915 set_material(Material *mat, int priority) { 04916 nassertv_always(!is_empty()); 04917 nassertv(mat != NULL); 04918 node()->set_attrib(MaterialAttrib::make(mat), priority); 04919 } 04920 04921 //////////////////////////////////////////////////////////////////// 04922 // Function: NodePath::set_material_off 04923 // Access: Published 04924 // Description: Sets the geometry at this level and below to render 04925 // using no material. This is normally the default, but 04926 // it may be useful to use this to contradict 04927 // set_material() at a higher node level (or, with a 04928 // priority, to override a set_material() at a lower 04929 // level). 04930 //////////////////////////////////////////////////////////////////// 04931 void NodePath:: 04932 set_material_off(int priority) { 04933 nassertv_always(!is_empty()); 04934 node()->set_attrib(MaterialAttrib::make_off(), priority); 04935 } 04936 04937 //////////////////////////////////////////////////////////////////// 04938 // Function: NodePath::clear_material 04939 // Access: Published 04940 // Description: Completely removes any material adjustment that may 04941 // have been set via set_material() from this particular 04942 // node. 04943 //////////////////////////////////////////////////////////////////// 04944 void NodePath:: 04945 clear_material() { 04946 nassertv_always(!is_empty()); 04947 node()->clear_attrib(MaterialAttrib::get_class_slot()); 04948 } 04949 04950 //////////////////////////////////////////////////////////////////// 04951 // Function: NodePath::has_material 04952 // Access: Published 04953 // Description: Returns true if a material has been applied to this 04954 // particular node via set_material(), false otherwise. 04955 //////////////////////////////////////////////////////////////////// 04956 bool NodePath:: 04957 has_material() const { 04958 nassertr_always(!is_empty(), false); 04959 const RenderAttrib *attrib = 04960 node()->get_attrib(MaterialAttrib::get_class_slot()); 04961 if (attrib != (const RenderAttrib *)NULL) { 04962 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib); 04963 return !ma->is_off(); 04964 } 04965 04966 return false; 04967 } 04968 04969 //////////////////////////////////////////////////////////////////// 04970 // Function: NodePath::get_material 04971 // Access: Published 04972 // Description: Returns the material that has been set on this 04973 // particular node, or NULL if no material has been set. 04974 // This is not necessarily the material that will be 04975 // applied to the geometry at or below this level, as 04976 // another material at a higher or lower level may 04977 // override. 04978 04979 // See also find_material(). 04980 //////////////////////////////////////////////////////////////////// 04981 PT(Material) NodePath:: 04982 get_material() const { 04983 nassertr_always(!is_empty(), NULL); 04984 const RenderAttrib *attrib = 04985 node()->get_attrib(MaterialAttrib::get_class_slot()); 04986 if (attrib != (const RenderAttrib *)NULL) { 04987 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib); 04988 return ma->get_material(); 04989 } 04990 04991 return NULL; 04992 } 04993 04994 //////////////////////////////////////////////////////////////////// 04995 // Function: NodePath::set_fog 04996 // Access: Published 04997 // Description: Sets the geometry at this level and below to render 04998 // using the indicated fog. 04999 //////////////////////////////////////////////////////////////////// 05000 void NodePath:: 05001 set_fog(Fog *fog, int priority) { 05002 nassertv_always(!is_empty()); 05003 node()->set_attrib(FogAttrib::make(fog), priority); 05004 } 05005 05006 //////////////////////////////////////////////////////////////////// 05007 // Function: NodePath::set_fog_off 05008 // Access: Published 05009 // Description: Sets the geometry at this level and below to render 05010 // using no fog. This is normally the default, but 05011 // it may be useful to use this to contradict 05012 // set_fog() at a higher node level (or, with a 05013 // priority, to override a set_fog() at a lower 05014 // level). 05015 //////////////////////////////////////////////////////////////////// 05016 void NodePath:: 05017 set_fog_off(int priority) { 05018 nassertv_always(!is_empty()); 05019 node()->set_attrib(FogAttrib::make_off(), priority); 05020 } 05021 05022 //////////////////////////////////////////////////////////////////// 05023 // Function: NodePath::clear_fog 05024 // Access: Published 05025 // Description: Completely removes any fog adjustment that may 05026 // have been set via set_fog() or set_fog_off() 05027 // from this particular node. This allows whatever 05028 // fogs might be otherwise affecting the geometry to 05029 // show instead. 05030 //////////////////////////////////////////////////////////////////// 05031 void NodePath:: 05032 clear_fog() { 05033 nassertv_always(!is_empty()); 05034 node()->clear_attrib(FogAttrib::get_class_slot()); 05035 } 05036 05037 //////////////////////////////////////////////////////////////////// 05038 // Function: NodePath::has_fog 05039 // Access: Published 05040 // Description: Returns true if a fog has been applied to this 05041 // particular node via set_fog(), false otherwise. 05042 // This is not the same thing as asking whether the 05043 // geometry at this node will be rendered with 05044 // fog, as there may be a fog in effect from a higher or 05045 // lower level. 05046 //////////////////////////////////////////////////////////////////// 05047 bool NodePath:: 05048 has_fog() const { 05049 nassertr_always(!is_empty(), false); 05050 const RenderAttrib *attrib = 05051 node()->get_attrib(FogAttrib::get_class_slot()); 05052 if (attrib != (const RenderAttrib *)NULL) { 05053 const FogAttrib *fa = DCAST(FogAttrib, attrib); 05054 return !fa->is_off(); 05055 } 05056 05057 return false; 05058 } 05059 05060 //////////////////////////////////////////////////////////////////// 05061 // Function: NodePath::has_fog_off 05062 // Access: Published 05063 // Description: Returns true if a fog has been specifically 05064 // disabled on this particular node via 05065 // set_fog_off(), false otherwise. This is not the 05066 // same thing as asking whether the geometry at this 05067 // node will be rendered unfogged, as there may be a 05068 // fog in effect from a higher or lower level. 05069 //////////////////////////////////////////////////////////////////// 05070 bool NodePath:: 05071 has_fog_off() const { 05072 nassertr_always(!is_empty(), false); 05073 const RenderAttrib *attrib = 05074 node()->get_attrib(FogAttrib::get_class_slot()); 05075 if (attrib != (const RenderAttrib *)NULL) { 05076 const FogAttrib *fa = DCAST(FogAttrib, attrib); 05077 return fa->is_off(); 05078 } 05079 05080 return false; 05081 } 05082 05083 //////////////////////////////////////////////////////////////////// 05084 // Function: NodePath::get_fog 05085 // Access: Published 05086 // Description: Returns the fog that has been set on this 05087 // particular node, or NULL if no fog has been set. 05088 // This is not necessarily the fog that will be 05089 // applied to the geometry at or below this level, as 05090 // another fog at a higher or lower level may 05091 // override. 05092 //////////////////////////////////////////////////////////////////// 05093 Fog *NodePath:: 05094 get_fog() const { 05095 nassertr_always(!is_empty(), NULL); 05096 const RenderAttrib *attrib = 05097 node()->get_attrib(FogAttrib::get_class_slot()); 05098 if (attrib != (const RenderAttrib *)NULL) { 05099 const FogAttrib *fa = DCAST(FogAttrib, attrib); 05100 return fa->get_fog(); 05101 } 05102 05103 return NULL; 05104 } 05105 05106 //////////////////////////////////////////////////////////////////// 05107 // Function: NodePath::set_render_mode_wireframe 05108 // Access: Published 05109 // Description: Sets up the geometry at this level and below (unless 05110 // overridden) to render in wireframe mode. 05111 //////////////////////////////////////////////////////////////////// 05112 void NodePath:: 05113 set_render_mode_wireframe(int priority) { 05114 nassertv_always(!is_empty()); 05115 float thickness = get_render_mode_thickness(); 05116 bool perspective = get_render_mode_perspective(); 05117 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, thickness, perspective), priority); 05118 } 05119 05120 //////////////////////////////////////////////////////////////////// 05121 // Function: NodePath::set_render_mode_filled 05122 // Access: Published 05123 // Description: Sets up the geometry at this level and below (unless 05124 // overridden) to render in filled (i.e. not wireframe) 05125 // mode. 05126 //////////////////////////////////////////////////////////////////// 05127 void NodePath:: 05128 set_render_mode_filled(int priority) { 05129 nassertv_always(!is_empty()); 05130 float thickness = get_render_mode_thickness(); 05131 bool perspective = get_render_mode_perspective(); 05132 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority); 05133 } 05134 05135 //////////////////////////////////////////////////////////////////// 05136 // Function: NodePath::set_render_mode_perspective 05137 // Access: Published 05138 // Description: Sets up the point geometry at this level and below to 05139 // render as perspective sprites (that is, billboarded 05140 // quads). The thickness, as specified with 05141 // set_render_mode_thickness(), is the width of each 05142 // point in 3-D units, unless it is overridden on a 05143 // per-vertex basis. This does not affect geometry 05144 // other than points. 05145 // 05146 // If you want the quads to be individually textured, 05147 // you should also set a TexGenAttrib::M_point_sprite on 05148 // the node. 05149 //////////////////////////////////////////////////////////////////// 05150 void NodePath:: 05151 set_render_mode_perspective(bool perspective, int priority) { 05152 nassertv_always(!is_empty()); 05153 RenderModeAttrib::Mode mode = get_render_mode(); 05154 float thickness = get_render_mode_thickness(); 05155 node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority); 05156 } 05157 05158 //////////////////////////////////////////////////////////////////// 05159 // Function: NodePath::set_render_mode_thickness 05160 // Access: Published 05161 // Description: Sets up the point geometry at this level and below to 05162 // render as thick points (that is, billboarded 05163 // quads). The thickness is in pixels, unless 05164 // set_render_mode_perspective is also true, in which 05165 // case it is in 3-D units. 05166 // 05167 // If you want the quads to be individually textured, 05168 // you should also set a TexGenAttrib::M_point_sprite on 05169 // the node. 05170 //////////////////////////////////////////////////////////////////// 05171 void NodePath:: 05172 set_render_mode_thickness(float thickness, int priority) { 05173 nassertv_always(!is_empty()); 05174 RenderModeAttrib::Mode mode = get_render_mode(); 05175 bool perspective = get_render_mode_perspective(); 05176 node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority); 05177 } 05178 05179 //////////////////////////////////////////////////////////////////// 05180 // Function: NodePath::set_render_mode 05181 // Access: Published 05182 // Description: Sets up the geometry at this level and below (unless 05183 // overridden) to render in the specified mode and with 05184 // the indicated line and/or point thickness. 05185 //////////////////////////////////////////////////////////////////// 05186 void NodePath:: 05187 set_render_mode(RenderModeAttrib::Mode mode, float thickness, int priority) { 05188 nassertv_always(!is_empty()); 05189 05190 node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority); 05191 } 05192 05193 //////////////////////////////////////////////////////////////////// 05194 // Function: NodePath::clear_render_mode 05195 // Access: Published 05196 // Description: Completely removes any render mode adjustment that 05197 // may have been set on this node via 05198 // set_render_mode_wireframe() or 05199 // set_render_mode_filled(). 05200 //////////////////////////////////////////////////////////////////// 05201 void NodePath:: 05202 clear_render_mode() { 05203 nassertv_always(!is_empty()); 05204 node()->clear_attrib(RenderModeAttrib::get_class_slot()); 05205 } 05206 05207 //////////////////////////////////////////////////////////////////// 05208 // Function: NodePath::has_render_mode 05209 // Access: Published 05210 // Description: Returns true if a render mode has been explicitly set 05211 // on this particular node via set_render_mode() (or 05212 // set_render_mode_wireframe() or 05213 // set_render_mode_filled()), false otherwise. 05214 //////////////////////////////////////////////////////////////////// 05215 bool NodePath:: 05216 has_render_mode() const { 05217 nassertr_always(!is_empty(), false); 05218 return node()->has_attrib(RenderModeAttrib::get_class_slot()); 05219 } 05220 05221 //////////////////////////////////////////////////////////////////// 05222 // Function: NodePath::get_render_mode 05223 // Access: Published 05224 // Description: Returns the render mode that has been specifically 05225 // set on this node via set_render_mode(), or 05226 // M_unchanged if nothing has been set. 05227 //////////////////////////////////////////////////////////////////// 05228 RenderModeAttrib::Mode NodePath:: 05229 get_render_mode() const { 05230 nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged); 05231 const RenderAttrib *attrib = 05232 node()->get_attrib(RenderModeAttrib::get_class_slot()); 05233 if (attrib != (const RenderAttrib *)NULL) { 05234 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib); 05235 return ta->get_mode(); 05236 } 05237 05238 return RenderModeAttrib::M_unchanged; 05239 } 05240 05241 //////////////////////////////////////////////////////////////////// 05242 // Function: NodePath::get_render_mode_thickness 05243 // Access: Published 05244 // Description: Returns the render mode thickness that has been 05245 // specifically set on this node via set_render_mode(), 05246 // or 1.0 if nothing has been set. 05247 //////////////////////////////////////////////////////////////////// 05248 float NodePath:: 05249 get_render_mode_thickness() const { 05250 nassertr_always(!is_empty(), 0.0f); 05251 const RenderAttrib *attrib = 05252 node()->get_attrib(RenderModeAttrib::get_class_slot()); 05253 if (attrib != (const RenderAttrib *)NULL) { 05254 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib); 05255 return ta->get_thickness(); 05256 } 05257 05258 return 1.0f; 05259 } 05260 05261 //////////////////////////////////////////////////////////////////// 05262 // Function: NodePath::get_render_mode_perspective 05263 // Access: Published 05264 // Description: Returns the flag that has been set on this node via 05265 // set_render_mode_perspective(), or false if no flag 05266 // has been set. 05267 //////////////////////////////////////////////////////////////////// 05268 bool NodePath:: 05269 get_render_mode_perspective() const { 05270 nassertr_always(!is_empty(), 0.0f); 05271 const RenderAttrib *attrib = 05272 node()->get_attrib(RenderModeAttrib::get_class_slot()); 05273 if (attrib != (const RenderAttrib *)NULL) { 05274 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib); 05275 return ta->get_perspective(); 05276 } 05277 05278 return false; 05279 } 05280 05281 //////////////////////////////////////////////////////////////////// 05282 // Function: NodePath::set_two_sided 05283 // Access: Published 05284 // Description: Specifically sets or disables two-sided rendering 05285 // mode on this particular node. If no other nodes 05286 // override, this will cause backfacing polygons to be 05287 // drawn (in two-sided mode, true) or culled (in 05288 // one-sided mode, false). 05289 //////////////////////////////////////////////////////////////////// 05290 void NodePath:: 05291 set_two_sided(bool two_sided, int priority) { 05292 nassertv_always(!is_empty()); 05293 05294 CullFaceAttrib::Mode mode = 05295 two_sided ? 05296 CullFaceAttrib::M_cull_none : 05297 CullFaceAttrib::M_cull_clockwise; 05298 05299 node()->set_attrib(CullFaceAttrib::make(mode), priority); 05300 } 05301 05302 //////////////////////////////////////////////////////////////////// 05303 // Function: NodePath::clear_two_sided 05304 // Access: Published 05305 // Description: Completely removes any two-sided adjustment that 05306 // may have been set on this node via set_two_sided(). 05307 // The geometry at this level and below will 05308 // subsequently be rendered either two-sided or 05309 // one-sided, according to whatever other nodes may have 05310 // had set_two_sided() on it, or according to the 05311 // initial state otherwise. 05312 //////////////////////////////////////////////////////////////////// 05313 void NodePath:: 05314 clear_two_sided() { 05315 nassertv_always(!is_empty()); 05316 node()->clear_attrib(CullFaceAttrib::get_class_slot()); 05317 } 05318 05319 //////////////////////////////////////////////////////////////////// 05320 // Function: NodePath::has_two_sided 05321 // Access: Published 05322 // Description: Returns true if a two-sided adjustment has been 05323 // explicitly set on this particular node via 05324 // set_two_sided(). If this returns true, then 05325 // get_two_sided() may be called to determine which has 05326 // been set. 05327 //////////////////////////////////////////////////////////////////// 05328 bool NodePath:: 05329 has_two_sided() const { 05330 nassertr_always(!is_empty(), false); 05331 return node()->has_attrib(CullFaceAttrib::get_class_slot()); 05332 } 05333 05334 //////////////////////////////////////////////////////////////////// 05335 // Function: NodePath::get_two_sided 05336 // Access: Published 05337 // Description: Returns true if two-sided rendering has been 05338 // specifically set on this node via set_two_sided(), or 05339 // false if one-sided rendering has been specifically 05340 // set, or if nothing has been specifically set. See 05341 // also has_two_sided(). This does not necessarily 05342 // imply that the geometry will or will not be rendered 05343 // two-sided, as there may be other nodes that override. 05344 //////////////////////////////////////////////////////////////////// 05345 bool NodePath:: 05346 get_two_sided() const { 05347 nassertr_always(!is_empty(), false); 05348 const RenderAttrib *attrib = 05349 node()->get_attrib(CullFaceAttrib::get_class_slot()); 05350 if (attrib != (const RenderAttrib *)NULL) { 05351 const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib); 05352 return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none); 05353 } 05354 05355 return false; 05356 } 05357 05358 //////////////////////////////////////////////////////////////////// 05359 // Function: NodePath::set_depth_test 05360 // Access: Published 05361 // Description: Specifically sets or disables the testing of the 05362 // depth buffer on this particular node. This is 05363 // normally on in the 3-d scene graph and off in the 2-d 05364 // scene graph; it should be on for rendering most 3-d 05365 // objects properly. 05366 //////////////////////////////////////////////////////////////////// 05367 void NodePath:: 05368 set_depth_test(bool depth_test, int priority) { 05369 nassertv_always(!is_empty()); 05370 05371 DepthTestAttrib::PandaCompareFunc mode = 05372 depth_test ? 05373 DepthTestAttrib::M_less : 05374 DepthTestAttrib::M_none; 05375 05376 node()->set_attrib(DepthTestAttrib::make(mode), priority); 05377 } 05378 05379 //////////////////////////////////////////////////////////////////// 05380 // Function: NodePath::clear_depth_test 05381 // Access: Published 05382 // Description: Completely removes any depth-test adjustment that 05383 // may have been set on this node via set_depth_test(). 05384 //////////////////////////////////////////////////////////////////// 05385 void NodePath:: 05386 clear_depth_test() { 05387 nassertv_always(!is_empty()); 05388 node()->clear_attrib(DepthTestAttrib::get_class_slot()); 05389 } 05390 05391 //////////////////////////////////////////////////////////////////// 05392 // Function: NodePath::has_depth_test 05393 // Access: Published 05394 // Description: Returns true if a depth-test adjustment has been 05395 // explicitly set on this particular node via 05396 // set_depth_test(). If this returns true, then 05397 // get_depth_test() may be called to determine which has 05398 // been set. 05399 //////////////////////////////////////////////////////////////////// 05400 bool NodePath:: 05401 has_depth_test() const { 05402 nassertr_always(!is_empty(), false); 05403 return node()->has_attrib(DepthTestAttrib::get_class_slot()); 05404 } 05405 05406 //////////////////////////////////////////////////////////////////// 05407 // Function: NodePath::get_depth_test 05408 // Access: Published 05409 // Description: Returns true if depth-test rendering has been 05410 // specifically set on this node via set_depth_test(), or 05411 // false if depth-test rendering has been specifically 05412 // disabled. If nothing has been specifically set, 05413 // returns true. See also has_depth_test(). 05414 //////////////////////////////////////////////////////////////////// 05415 bool NodePath:: 05416 get_depth_test() const { 05417 nassertr_always(!is_empty(), false); 05418 const RenderAttrib *attrib = 05419 node()->get_attrib(DepthTestAttrib::get_class_slot()); 05420 if (attrib != (const RenderAttrib *)NULL) { 05421 const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib); 05422 return (dta->get_mode() != DepthTestAttrib::M_none); 05423 } 05424 05425 return true; 05426 } 05427 05428 //////////////////////////////////////////////////////////////////// 05429 // Function: NodePath::set_depth_write 05430 // Access: Published 05431 // Description: Specifically sets or disables the writing to the 05432 // depth buffer on this particular node. This is 05433 // normally on in the 3-d scene graph and off in the 2-d 05434 // scene graph; it should be on for rendering most 3-d 05435 // objects properly. 05436 //////////////////////////////////////////////////////////////////// 05437 void NodePath:: 05438 set_depth_write(bool depth_write, int priority) { 05439 nassertv_always(!is_empty()); 05440 05441 DepthWriteAttrib::Mode mode = 05442 depth_write ? 05443 DepthWriteAttrib::M_on : 05444 DepthWriteAttrib::M_off; 05445 05446 node()->set_attrib(DepthWriteAttrib::make(mode), priority); 05447 } 05448 05449 //////////////////////////////////////////////////////////////////// 05450 // Function: NodePath::clear_depth_write 05451 // Access: Published 05452 // Description: Completely removes any depth-write adjustment that 05453 // may have been set on this node via set_depth_write(). 05454 //////////////////////////////////////////////////////////////////// 05455 void NodePath:: 05456 clear_depth_write() { 05457 nassertv_always(!is_empty()); 05458 node()->clear_attrib(DepthWriteAttrib::get_class_slot()); 05459 } 05460 05461 //////////////////////////////////////////////////////////////////// 05462 // Function: NodePath::has_depth_write 05463 // Access: Published 05464 // Description: Returns true if a depth-write adjustment has been 05465 // explicitly set on this particular node via 05466 // set_depth_write(). If this returns true, then 05467 // get_depth_write() may be called to determine which has 05468 // been set. 05469 //////////////////////////////////////////////////////////////////// 05470 bool NodePath:: 05471 has_depth_write() const { 05472 nassertr_always(!is_empty(), false); 05473 return node()->has_attrib(DepthWriteAttrib::get_class_slot()); 05474 } 05475 05476 //////////////////////////////////////////////////////////////////// 05477 // Function: NodePath::get_depth_write 05478 // Access: Published 05479 // Description: Returns true if depth-write rendering has been 05480 // specifically set on this node via set_depth_write(), or 05481 // false if depth-write rendering has been specifically 05482 // disabled. If nothing has been specifically set, 05483 // returns true. See also has_depth_write(). 05484 //////////////////////////////////////////////////////////////////// 05485 bool NodePath:: 05486 get_depth_write() const { 05487 nassertr_always(!is_empty(), false); 05488 const RenderAttrib *attrib = 05489 node()->get_attrib(DepthWriteAttrib::get_class_slot()); 05490 if (attrib != (const RenderAttrib *)NULL) { 05491 const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib); 05492 return (dta->get_mode() != DepthWriteAttrib::M_off); 05493 } 05494 05495 return true; 05496 } 05497 05498 //////////////////////////////////////////////////////////////////// 05499 // Function: NodePath::set_depth_offset 05500 // Access: Published 05501 // Description: This instructs the graphics driver to apply an 05502 // offset or bias to the generated depth values for 05503 // rendered polygons, before they are written to the 05504 // depth buffer. This can be used to shift polygons 05505 // forward slightly, to resolve depth conflicts, or 05506 // self-shadowing artifacts on thin objects. 05507 // The bias is always an integer number, and each 05508 // integer increment represents the smallest possible 05509 // increment in Z that is sufficient to completely 05510 // resolve two coplanar polygons. Positive numbers 05511 // are closer towards the camera. 05512 //////////////////////////////////////////////////////////////////// 05513 void NodePath:: 05514 set_depth_offset(int bias, int priority) { 05515 nassertv_always(!is_empty()); 05516 05517 node()->set_attrib(DepthOffsetAttrib::make(bias), priority); 05518 } 05519 05520 //////////////////////////////////////////////////////////////////// 05521 // Function: NodePath::clear_depth_offset 05522 // Access: Published 05523 // Description: Completely removes any depth-offset adjustment that 05524 // may have been set on this node via set_depth_offset(). 05525 //////////////////////////////////////////////////////////////////// 05526 void NodePath:: 05527 clear_depth_offset() { 05528 nassertv_always(!is_empty()); 05529 node()->clear_attrib(DepthOffsetAttrib::get_class_slot()); 05530 } 05531 05532 //////////////////////////////////////////////////////////////////// 05533 // Function: NodePath::has_depth_offset 05534 // Access: Published 05535 // Description: Returns true if a depth-offset adjustment has been 05536 // explicitly set on this particular node via 05537 // set_depth_offset(). If this returns true, then 05538 // get_depth_offset() may be called to determine which has 05539 // been set. 05540 //////////////////////////////////////////////////////////////////// 05541 bool NodePath:: 05542 has_depth_offset() const { 05543 nassertr_always(!is_empty(), false); 05544 return node()->has_attrib(DepthOffsetAttrib::get_class_slot()); 05545 } 05546 05547 //////////////////////////////////////////////////////////////////// 05548 // Function: NodePath::get_depth_offset 05549 // Access: Published 05550 // Description: Returns the depth offset value if it has been 05551 // specified using set_depth_offset, or 0 if not. 05552 //////////////////////////////////////////////////////////////////// 05553 int NodePath:: 05554 get_depth_offset() const { 05555 nassertr_always(!is_empty(), 0); 05556 const RenderAttrib *attrib = 05557 node()->get_attrib(DepthOffsetAttrib::get_class_slot()); 05558 if (attrib != (const RenderAttrib *)NULL) { 05559 const DepthOffsetAttrib *doa = DCAST(DepthOffsetAttrib, attrib); 05560 return doa->get_offset(); 05561 } 05562 05563 return 0; 05564 } 05565 05566 //////////////////////////////////////////////////////////////////// 05567 // Function: NodePath::do_billboard_axis 05568 // Access: Published 05569 // Description: Performs a billboard-type rotate to the indicated 05570 // camera node, one time only, and leaves the object 05571 // rotated. This is similar in principle to heads_up(). 05572 //////////////////////////////////////////////////////////////////// 05573 void NodePath:: 05574 do_billboard_axis(const NodePath &camera, float offset) { 05575 nassertv_always(!is_empty()); 05576 05577 CPT(TransformState) transform = camera.get_transform(get_parent()); 05578 const LMatrix4f &rel_mat = transform->get_mat(); 05579 05580 LVector3f up = LVector3f::up(); 05581 LVector3f rel_pos = -rel_mat.get_row3(3); 05582 05583 LQuaternionf quat; 05584 ::heads_up(quat, rel_pos, up); 05585 set_quat(quat); 05586 05587 // Also slide the geometry towards the camera according to the 05588 // offset factor. 05589 if (offset != 0.0f) { 05590 LVector3f translate = rel_mat.get_row3(3); 05591 translate.normalize(); 05592 translate *= offset; 05593 set_pos(translate); 05594 } 05595 } 05596 05597 //////////////////////////////////////////////////////////////////// 05598 // Function: NodePath::do_billboard_point_eye 05599 // Access: Published 05600 // Description: Performs a billboard-type rotate to the indicated 05601 // camera node, one time only, and leaves the object 05602 // rotated. This is similar in principle to look_at(), 05603 // although the point_eye billboard effect cannot be 05604 // achieved using the ordinary look_at() call. 05605 //////////////////////////////////////////////////////////////////// 05606 void NodePath:: 05607 do_billboard_point_eye(const NodePath &camera, float offset) { 05608 nassertv_always(!is_empty()); 05609 05610 CPT(TransformState) transform = camera.get_transform(get_parent()); 05611 const LMatrix4f &rel_mat = transform->get_mat(); 05612 05613 LVector3f up = LVector3f::up() * rel_mat; 05614 LVector3f rel_pos = LVector3f::forward() * rel_mat; 05615 05616 LQuaternionf quat; 05617 ::look_at(quat, rel_pos, up); 05618 set_quat(quat); 05619 05620 // Also slide the geometry towards the camera according to the 05621 // offset factor. 05622 if (offset != 0.0f) { 05623 LVector3f translate = rel_mat.get_row3(3); 05624 translate.normalize(); 05625 translate *= offset; 05626 set_pos(translate); 05627 } 05628 } 05629 05630 //////////////////////////////////////////////////////////////////// 05631 // Function: NodePath::do_billboard_point_world 05632 // Access: Published 05633 // Description: Performs a billboard-type rotate to the indicated 05634 // camera node, one time only, and leaves the object 05635 // rotated. This is similar in principle to look_at(). 05636 //////////////////////////////////////////////////////////////////// 05637 void NodePath:: 05638 do_billboard_point_world(const NodePath &camera, float offset) { 05639 nassertv_always(!is_empty()); 05640 05641 CPT(TransformState) transform = camera.get_transform(get_parent()); 05642 const LMatrix4f &rel_mat = transform->get_mat(); 05643 05644 LVector3f up = LVector3f::up(); 05645 LVector3f rel_pos = -rel_mat.get_row3(3); 05646 05647 LQuaternionf quat; 05648 ::look_at(quat, rel_pos, up); 05649 set_quat(quat); 05650 05651 // Also slide the geometry towards the camera according to the 05652 // offset factor. 05653 if (offset != 0.0f) { 05654 LVector3f translate = rel_mat.get_row3(3); 05655 translate.normalize(); 05656 translate *= offset; 05657 set_pos(translate); 05658 } 05659 } 05660 05661 //////////////////////////////////////////////////////////////////// 05662 // Function: NodePath::set_billboard_axis 05663 // Access: Published 05664 // Description: Puts a billboard transition on the node such that it 05665 // will rotate in two dimensions around the up axis, 05666 // towards a specified "camera" instead of to the 05667 // viewing camera. 05668 //////////////////////////////////////////////////////////////////// 05669 void NodePath:: 05670 set_billboard_axis(const NodePath &camera, float offset) { 05671 nassertv_always(!is_empty()); 05672 CPT(RenderEffect) billboard = BillboardEffect::make 05673 (LVector3f::up(), false, true, 05674 offset, camera, LPoint3f(0.0f, 0.0f, 0.0f)); 05675 node()->set_effect(billboard); 05676 } 05677 05678 //////////////////////////////////////////////////////////////////// 05679 // Function: NodePath::set_billboard_point_eye 05680 // Access: Published 05681 // Description: Puts a billboard transition on the node such that it 05682 // will rotate in three dimensions about the origin, 05683 // keeping its up vector oriented to the top of the 05684 // camera, towards a specified "camera" instead of to 05685 // the viewing camera. 05686 //////////////////////////////////////////////////////////////////// 05687 void NodePath:: 05688 set_billboard_point_eye(const NodePath &camera, float offset) { 05689 nassertv_always(!is_empty()); 05690 CPT(RenderEffect) billboard = BillboardEffect::make 05691 (LVector3f::up(), true, false, 05692 offset, camera, LPoint3f(0.0f, 0.0f, 0.0f)); 05693 node()->set_effect(billboard); 05694 } 05695 05696 //////////////////////////////////////////////////////////////////// 05697 // Function: NodePath::set_billboard_point_world 05698 // Access: Published 05699 // Description: Puts a billboard transition on the node such that it 05700 // will rotate in three dimensions about the origin, 05701 // keeping its up vector oriented to the sky, towards a 05702 // specified "camera" instead of to the viewing camera. 05703 //////////////////////////////////////////////////////////////////// 05704 void NodePath:: 05705 set_billboard_point_world(const NodePath &camera, float offset) { 05706 nassertv_always(!is_empty()); 05707 CPT(RenderEffect) billboard = BillboardEffect::make 05708 (LVector3f::up(), false, false, 05709 offset, camera, LPoint3f(0.0f, 0.0f, 0.0f)); 05710 node()->set_effect(billboard); 05711 } 05712 05713 //////////////////////////////////////////////////////////////////// 05714 // Function: NodePath::clear_billboard 05715 // Access: Published 05716 // Description: Removes any billboard effect from the node. 05717 //////////////////////////////////////////////////////////////////// 05718 void NodePath:: 05719 clear_billboard() { 05720 nassertv_always(!is_empty()); 05721 node()->clear_effect(BillboardEffect::get_class_type()); 05722 } 05723 05724 //////////////////////////////////////////////////////////////////// 05725 // Function: NodePath::has_billboard 05726 // Access: Published 05727 // Description: Returns true if there is any billboard effect on 05728 // the node. 05729 //////////////////////////////////////////////////////////////////// 05730 bool NodePath:: 05731 has_billboard() const { 05732 nassertr_always(!is_empty(), false); 05733 return node()->has_effect(BillboardEffect::get_class_type()); 05734 } 05735 05736 //////////////////////////////////////////////////////////////////// 05737 // Function: NodePath::set_compass 05738 // Access: Published 05739 // Description: Puts a compass effect on the node, so that it will 05740 // retain a fixed rotation relative to the reference 05741 // node (or render if the reference node is empty) 05742 // regardless of the transforms above it. 05743 //////////////////////////////////////////////////////////////////// 05744 void NodePath:: 05745 set_compass(const NodePath &reference) { 05746 nassertv_always(!is_empty()); 05747 node()->set_effect(CompassEffect::make(reference)); 05748 } 05749 05750 //////////////////////////////////////////////////////////////////// 05751 // Function: NodePath::clear_compass 05752 // Access: Published 05753 // Description: Removes any compass effect from the node. 05754 //////////////////////////////////////////////////////////////////// 05755 void NodePath:: 05756 clear_compass() { 05757 nassertv_always(!is_empty()); 05758 node()->clear_effect(CompassEffect::get_class_type()); 05759 } 05760 05761 //////////////////////////////////////////////////////////////////// 05762 // Function: NodePath::has_compass 05763 // Access: Published 05764 // Description: Returns true if there is any compass effect on 05765 // the node. 05766 //////////////////////////////////////////////////////////////////// 05767 bool NodePath:: 05768 has_compass() const { 05769 nassertr_always(!is_empty(), false); 05770 return node()->has_effect(CompassEffect::get_class_type()); 05771 } 05772 05773 //////////////////////////////////////////////////////////////////// 05774 // Function: NodePath::set_transparency 05775 // Access: Published 05776 // Description: Specifically sets or disables transparent rendering 05777 // mode on this particular node. If no other nodes 05778 // override, this will cause items with a non-1 value 05779 // for alpha color to be rendered partially transparent. 05780 //////////////////////////////////////////////////////////////////// 05781 void NodePath:: 05782 set_transparency(TransparencyAttrib::Mode mode, int priority) { 05783 nassertv_always(!is_empty()); 05784 05785 node()->set_attrib(TransparencyAttrib::make(mode), priority); 05786 } 05787 05788 //////////////////////////////////////////////////////////////////// 05789 // Function: NodePath::clear_transparency 05790 // Access: Published 05791 // Description: Completely removes any transparency adjustment that 05792 // may have been set on this node via set_transparency(). 05793 // The geometry at this level and below will 05794 // subsequently be rendered either transparent or not, 05795 // to whatever other nodes may have had 05796 // set_transparency() on them. 05797 //////////////////////////////////////////////////////////////////// 05798 void NodePath:: 05799 clear_transparency() { 05800 nassertv_always(!is_empty()); 05801 node()->clear_attrib(TransparencyAttrib::get_class_slot()); 05802 } 05803 05804 //////////////////////////////////////////////////////////////////// 05805 // Function: NodePath::has_transparency 05806 // Access: Published 05807 // Description: Returns true if a transparent-rendering adjustment 05808 // has been explicitly set on this particular node via 05809 // set_transparency(). If this returns true, then 05810 // get_transparency() may be called to determine whether 05811 // transparency has been explicitly enabled or 05812 // explicitly disabled for this node. 05813 //////////////////////////////////////////////////////////////////// 05814 bool NodePath:: 05815 has_transparency() const { 05816 nassertr_always(!is_empty(), false); 05817 return node()->has_attrib(TransparencyAttrib::get_class_slot()); 05818 } 05819 05820 //////////////////////////////////////////////////////////////////// 05821 // Function: NodePath::get_transparency 05822 // Access: Published 05823 // Description: Returns the transparent rendering that has been 05824 // specifically set on this node via set_transparency(), or 05825 // M_none if nontransparent rendering has been specifically 05826 // set, or if nothing has been specifically set. See 05827 // also has_transparency(). This does not necessarily 05828 // imply that the geometry will or will not be rendered 05829 // transparent, as there may be other nodes that override. 05830 //////////////////////////////////////////////////////////////////// 05831 TransparencyAttrib::Mode NodePath:: 05832 get_transparency() const { 05833 nassertr_always(!is_empty(), TransparencyAttrib::M_none); 05834 const RenderAttrib *attrib = 05835 node()->get_attrib(TransparencyAttrib::get_class_slot()); 05836 if (attrib != (const RenderAttrib *)NULL) { 05837 const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib); 05838 return ta->get_mode(); 05839 } 05840 05841 return TransparencyAttrib::M_none; 05842 } 05843 05844 //////////////////////////////////////////////////////////////////// 05845 // Function: NodePath::set_antialias 05846 // Access: Published 05847 // Description: Specifies the antialiasing type that should be 05848 // applied at this node and below. See AntialiasAttrib. 05849 //////////////////////////////////////////////////////////////////// 05850 void NodePath:: 05851 set_antialias(unsigned short mode, int priority) { 05852 nassertv_always(!is_empty()); 05853 05854 node()->set_attrib(AntialiasAttrib::make(mode), priority); 05855 } 05856 05857 //////////////////////////////////////////////////////////////////// 05858 // Function: NodePath::clear_antialias 05859 // Access: Published 05860 // Description: Completely removes any antialias setting that 05861 // may have been set on this node via set_antialias(). 05862 //////////////////////////////////////////////////////////////////// 05863 void NodePath:: 05864 clear_antialias() { 05865 nassertv_always(!is_empty()); 05866 node()->clear_attrib(AntialiasAttrib::get_class_slot()); 05867 } 05868 05869 //////////////////////////////////////////////////////////////////// 05870 // Function: NodePath::has_antialias 05871 // Access: Published 05872 // Description: Returns true if an antialias setting has been 05873 // explicitly mode on this particular node via 05874 // set_antialias(). If this returns true, then 05875 // get_antialias() may be called to determine what the 05876 // setting was. 05877 //////////////////////////////////////////////////////////////////// 05878 bool NodePath:: 05879 has_antialias() const { 05880 nassertr_always(!is_empty(), false); 05881 return node()->has_attrib(AntialiasAttrib::get_class_slot()); 05882 } 05883 05884 //////////////////////////////////////////////////////////////////// 05885 // Function: NodePath::get_antialias 05886 // Access: Published 05887 // Description: Returns the antialias setting that has been 05888 // specifically set on this node via set_antialias(), or 05889 // M_none if no setting has been made. 05890 //////////////////////////////////////////////////////////////////// 05891 unsigned short NodePath:: 05892 get_antialias() const { 05893 nassertr_always(!is_empty(), AntialiasAttrib::M_none); 05894 const RenderAttrib *attrib = 05895 node()->get_attrib(AntialiasAttrib::get_class_slot()); 05896 if (attrib != (const RenderAttrib *)NULL) { 05897 const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib); 05898 return ta->get_mode(); 05899 } 05900 05901 return AntialiasAttrib::M_none; 05902 } 05903 05904 //////////////////////////////////////////////////////////////////// 05905 // Function: NodePath::has_audio_volume 05906 // Access: Published 05907 // Description: Returns true if an audio volume has been applied 05908 // to the referenced node, false otherwise. It is still 05909 // possible that volume at this node might have been 05910 // scaled by an ancestor node. 05911 //////////////////////////////////////////////////////////////////// 05912 bool NodePath:: 05913 has_audio_volume() const { 05914 nassertr_always(!is_empty(), false); 05915 return node()->has_attrib(AudioVolumeAttrib::get_class_slot()); 05916 } 05917 05918 //////////////////////////////////////////////////////////////////// 05919 // Function: NodePath::clear_audio_volume 05920 // Access: Published 05921 // Description: Completely removes any audio volume from the 05922 // referenced node. This is preferable to simply 05923 // setting the audio volume to identity, as it also 05924 // removes the overhead associated with having an audio 05925 // volume at all. 05926 //////////////////////////////////////////////////////////////////// 05927 void NodePath:: 05928 clear_audio_volume() { 05929 nassertv_always(!is_empty()); 05930 node()->clear_attrib(AudioVolumeAttrib::get_class_slot()); 05931 } 05932 05933 //////////////////////////////////////////////////////////////////// 05934 // Function: NodePath::set_audio_volume 05935 // Access: Published 05936 // Description: Sets the audio volume component of the transform 05937 //////////////////////////////////////////////////////////////////// 05938 void NodePath:: 05939 set_audio_volume(float volume, int priority) { 05940 nassertv_always(!is_empty()); 05941 05942 const RenderAttrib *attrib = 05943 node()->get_attrib(AudioVolumeAttrib::get_class_slot()); 05944 if (attrib != (const RenderAttrib *)NULL) { 05945 priority = max(priority, 05946 node()->get_state()->get_override(AudioVolumeAttrib::get_class_slot())); 05947 CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib); 05948 05949 // Modify the existing AudioVolumeAttrib to add the indicated 05950 // volume. 05951 node()->set_attrib(ava->set_volume(volume), priority); 05952 05953 } else { 05954 // Create a new AudioVolumeAttrib for this node. 05955 node()->set_attrib(AudioVolumeAttrib::make(volume), priority); 05956 } 05957 } 05958 05959 //////////////////////////////////////////////////////////////////// 05960 // Function: NodePath::set_audio_volume_off 05961 // Access: Published 05962 // Description: Disables any audio volume attribute inherited from 05963 // above. This is not the same thing as 05964 // clear_audio_volume(), which undoes any previous 05965 // set_audio_volume() operation on this node; rather, 05966 // this actively disables any set_audio_volume() that 05967 // might be inherited from a parent node. 05968 // 05969 // It is legal to specify a new volume on the same 05970 // node with a subsequent call to set_audio_volume(); 05971 // this new scale will apply to lower nodes. 05972 //////////////////////////////////////////////////////////////////// 05973 void NodePath:: 05974 set_audio_volume_off(int priority) { 05975 nassertv_always(!is_empty()); 05976 node()->set_attrib(AudioVolumeAttrib::make_off(), priority); 05977 } 05978 05979 //////////////////////////////////////////////////////////////////// 05980 // Function: NodePath::get_audio_volume 05981 // Access: Published 05982 // Description: Returns the complete audio volume that has been 05983 // applied to this node via a previous call to 05984 // set_audio_volume(), or 1. (identity) if no volume has 05985 // been applied to this particular node. 05986 //////////////////////////////////////////////////////////////////// 05987 float NodePath:: 05988 get_audio_volume() const { 05989 const RenderAttrib *attrib = 05990 node()->get_attrib(AudioVolumeAttrib::get_class_slot()); 05991 if (attrib != (const RenderAttrib *)NULL) { 05992 const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib); 05993 return ava->get_volume(); 05994 } 05995 05996 return 1.0f; 05997 } 05998 05999 //////////////////////////////////////////////////////////////////// 06000 // Function: NodePath::get_net_audio_volume 06001 // Access: Published 06002 // Description: Returns the complete audio volume for this node 06003 // taking highers nodes in the graph into account. 06004 //////////////////////////////////////////////////////////////////// 06005 float NodePath:: 06006 get_net_audio_volume() const { 06007 CPT(RenderState) net_state = get_net_state(); 06008 const RenderAttrib *attrib = net_state->get_attrib(AudioVolumeAttrib::get_class_slot()); 06009 if (attrib != (const RenderAttrib *)NULL) { 06010 const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib); 06011 if (ava != (const AudioVolumeAttrib *)NULL) { 06012 return ava->get_volume(); 06013 } 06014 } 06015 06016 return 1.0f; 06017 } 06018 06019 //////////////////////////////////////////////////////////////////// 06020 // Function: NodePath::get_hidden_ancestor 06021 // Access: Published 06022 // Description: Returns the NodePath at or above the referenced node 06023 // that is hidden to the indicated camera(s), or an 06024 // empty NodePath if no ancestor of the referenced node 06025 // is hidden (and the node should be visible). 06026 //////////////////////////////////////////////////////////////////// 06027 NodePath NodePath:: 06028 get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const { 06029 int pipeline_stage = current_thread->get_pipeline_stage(); 06030 06031 NodePathComponent *comp; 06032 for (comp = _head; 06033 comp != (NodePathComponent *)NULL; 06034 comp = comp->get_next(pipeline_stage, current_thread)) { 06035 PandaNode *node = comp->get_node(); 06036 if (node->is_overall_hidden() || 06037 ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) { 06038 NodePath result; 06039 result._head = comp; 06040 return result; 06041 } 06042 } 06043 06044 return not_found(); 06045 } 06046 06047 //////////////////////////////////////////////////////////////////// 06048 // Function: NodePath::stash 06049 // Access: Published 06050 // Description: Removes the referenced node (and the entire subgraph 06051 // below this node) from the scene graph in any normal 06052 // sense. The node will no longer be visible and is not 06053 // tested for collisions; furthermore, no normal scene 06054 // graph traversal will visit the node. The node's 06055 // bounding volume no longer contributes to its parent's 06056 // bounding volume. 06057 // 06058 // A stashed node cannot be located by a normal find() 06059 // operation (although a special find string can still 06060 // retrieve it). 06061 //////////////////////////////////////////////////////////////////// 06062 void NodePath:: 06063 stash(int sort, Thread *current_thread) { 06064 nassertv_always(!is_singleton() && !is_empty()); 06065 nassertv(verify_complete()); 06066 06067 int pipeline_stage = current_thread->get_pipeline_stage(); 06068 bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread), 06069 _head, sort, true, pipeline_stage, 06070 current_thread); 06071 nassertv(reparented); 06072 } 06073 06074 //////////////////////////////////////////////////////////////////// 06075 // Function: NodePath::unstash 06076 // Access: Published 06077 // Description: Undoes the effect of a previous stash() on this 06078 // node: makes the referenced node (and the entire 06079 // subgraph below this node) once again part of the 06080 // scene graph. 06081 //////////////////////////////////////////////////////////////////// 06082 void NodePath:: 06083 unstash(int sort, Thread *current_thread) { 06084 nassertv_always(!is_singleton() && !is_empty()); 06085 nassertv(verify_complete()); 06086 06087 int pipeline_stage = current_thread->get_pipeline_stage(); 06088 bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread), 06089 _head, sort, false, pipeline_stage, 06090 current_thread); 06091 nassertv(reparented); 06092 } 06093 06094 //////////////////////////////////////////////////////////////////// 06095 // Function: NodePath::unstash_all 06096 // Access: Published 06097 // Description: Unstashes this node and all stashed child nodes. 06098 //////////////////////////////////////////////////////////////////// 06099 void NodePath:: 06100 unstash_all(Thread *current_thread) { 06101 NodePathCollection stashed_descendents = find_all_matches("**/@@*"); 06102 stashed_descendents.unstash(); 06103 unstash(0, current_thread); 06104 } 06105 06106 //////////////////////////////////////////////////////////////////// 06107 // Function: NodePath::get_stashed_ancestor 06108 // Access: Published 06109 // Description: Returns the NodePath at or above the referenced node 06110 // that is stashed, or an empty NodePath if no ancestor 06111 // of the referenced node is stashed (and the node should 06112 // be visible). 06113 //////////////////////////////////////////////////////////////////// 06114 NodePath NodePath:: 06115 get_stashed_ancestor(Thread *current_thread) const { 06116 NodePathComponent *comp = _head; 06117 if (comp != (NodePathComponent *)NULL) { 06118 int pipeline_stage = current_thread->get_pipeline_stage(); 06119 NodePathComponent *next = comp->get_next(pipeline_stage, current_thread); 06120 06121 while (next != (NodePathComponent *)NULL) { 06122 PandaNode *node = comp->get_node(); 06123 PandaNode *parent_node = next->get_node(); 06124 06125 if (parent_node->find_stashed(node) >= 0) { 06126 NodePath result; 06127 result._head = comp; 06128 return result; 06129 } 06130 06131 comp = next; 06132 next = next->get_next(pipeline_stage, current_thread); 06133 } 06134 } 06135 06136 return not_found(); 06137 } 06138 06139 //////////////////////////////////////////////////////////////////// 06140 // Function: NodePath::verify_complete 06141 // Access: Published 06142 // Description: Returns true if all of the nodes described in the 06143 // NodePath are connected, or false otherwise. 06144 //////////////////////////////////////////////////////////////////// 06145 bool NodePath:: 06146 verify_complete(Thread *current_thread) const { 06147 if (is_empty()) { 06148 return true; 06149 } 06150 06151 #ifdef HAVE_THREADS 06152 if (Thread::is_true_threads()) { 06153 // In a threaded environment, we can't reliably test this, since a 06154 // sub-thread may be mucking with the NodePath's ancestry as we 06155 // try to validate it. NodePaths are inherently not thread-safe, 06156 // but generally that's not an issue. 06157 return true; 06158 } 06159 #endif // HAVE_THREADS 06160 06161 static PStatCollector _verify_complete_pcollector("*:NodePath:verify_complete"); 06162 PStatTimer timer(_verify_complete_pcollector); 06163 06164 const NodePathComponent *comp = _head; 06165 nassertr(comp != (const NodePathComponent *)NULL, false); 06166 06167 int pipeline_stage = current_thread->get_pipeline_stage(); 06168 06169 PandaNode *node = comp->get_node(); 06170 nassertr(node != (const PandaNode *)NULL, false); 06171 int length = comp->get_length(pipeline_stage, current_thread); 06172 06173 comp = comp->get_next(pipeline_stage, current_thread); 06174 length--; 06175 while (comp != (const NodePathComponent *)NULL) { 06176 PandaNode *next_node = comp->get_node(); 06177 nassertr(next_node != (const PandaNode *)NULL, false); 06178 06179 if (node->find_parent(next_node) < 0) { 06180 pgraph_cat.warning() 06181 << *this << " is incomplete; " << *node << " is not a child of " 06182 << *next_node << "\n"; 06183 return false; 06184 } 06185 06186 if (comp->get_length(pipeline_stage, current_thread) != length) { 06187 pgraph_cat.warning() 06188 << *this << " is incomplete; length at " << *next_node 06189 << " indicates " << comp->get_length(pipeline_stage, current_thread) 06190 << " while length at " << *node << " indicates " << length << "\n"; 06191 return false; 06192 } 06193 06194 node = next_node; 06195 comp = comp->get_next(pipeline_stage, current_thread); 06196 length--; 06197 } 06198 06199 return true; 06200 } 06201 06202 //////////////////////////////////////////////////////////////////// 06203 // Function: NodePath::premunge_scene 06204 // Access: Published 06205 // Description: Walks through the scene graph beginning at the bottom 06206 // node, and internally adjusts any GeomVertexFormats 06207 // for optimal rendering on the indicated GSG. If this 06208 // step is not done prior to rendering, the formats will 06209 // be optimized at render time instead, for a small 06210 // cost. 06211 // 06212 // It is not normally necessary to do this on a model 06213 // loaded directly from disk, since the loader will do 06214 // this by default. 06215 //////////////////////////////////////////////////////////////////// 06216 void NodePath:: 06217 premunge_scene(GraphicsStateGuardianBase *gsg) { 06218 nassertv_always(!is_empty()); 06219 06220 CPT(RenderState) state = RenderState::make_empty(); 06221 if (has_parent()) { 06222 state = get_parent().get_net_state(); 06223 } 06224 06225 SceneGraphReducer gr(gsg); 06226 gr.premunge(node(), state); 06227 } 06228 06229 //////////////////////////////////////////////////////////////////// 06230 // Function: NodePath::prepare_scene 06231 // Access: Published 06232 // Description: Walks through the scene graph beginning at the bottom 06233 // node, and does whatever initialization is required to 06234 // render the scene properly with the indicated GSG. It 06235 // is not strictly necessary to call this, since the GSG 06236 // will initialize itself when the scene is rendered, 06237 // but this may take some of the overhead away from that 06238 // process. 06239 // 06240 // In particular, this will ensure that textures within 06241 // the scene are loaded in texture memory, and display 06242 // lists are built up from static geometry. 06243 //////////////////////////////////////////////////////////////////// 06244 void NodePath:: 06245 prepare_scene(GraphicsStateGuardianBase *gsg) { 06246 nassertv_always(!is_empty()); 06247 06248 CPT(RenderState) net_state = get_net_state(); 06249 node()->prepare_scene(gsg, net_state); 06250 } 06251 06252 //////////////////////////////////////////////////////////////////// 06253 // Function: NodePath::show_bounds 06254 // Access: Published 06255 // Description: Causes the bounding volume of the bottom node and all 06256 // of its descendants (that is, the bounding volume 06257 // associated with the the bottom arc) to be rendered, 06258 // if possible. The rendering method is less than 06259 // optimal; this is intended primarily for debugging. 06260 //////////////////////////////////////////////////////////////////// 06261 void NodePath:: 06262 show_bounds() { 06263 nassertv_always(!is_empty()); 06264 node()->set_effect(ShowBoundsEffect::make(false)); 06265 } 06266 06267 //////////////////////////////////////////////////////////////////// 06268 // Function: NodePath::show_tight_bounds 06269 // Access: Published 06270 // Description: Similar to show_bounds(), this draws a bounding box 06271 // representing the "tight" bounds of this node and all 06272 // of its descendants. The bounding box is recomputed 06273 // every frame by reexamining all of the vertices; this 06274 // is far from efficient, but this is intended for 06275 // debugging. 06276 //////////////////////////////////////////////////////////////////// 06277 void NodePath:: 06278 show_tight_bounds() { 06279 nassertv_always(!is_empty()); 06280 node()->set_effect(ShowBoundsEffect::make(true)); 06281 } 06282 06283 //////////////////////////////////////////////////////////////////// 06284 // Function: NodePath::hide_bounds 06285 // Access: Published 06286 // Description: Stops the rendering of the bounding volume begun with 06287 // show_bounds(). 06288 //////////////////////////////////////////////////////////////////// 06289 void NodePath:: 06290 hide_bounds() { 06291 nassertv_always(!is_empty()); 06292 node()->clear_effect(ShowBoundsEffect::get_class_type()); 06293 } 06294 06295 //////////////////////////////////////////////////////////////////// 06296 // Function: NodePath::get_bounds 06297 // Access: Published 06298 // Description: Returns a newly-allocated bounding volume containing 06299 // the bottom node and all of its descendants. This is 06300 // the bounding volume on the bottom arc, converted to 06301 // the local coordinate space of the node. 06302 //////////////////////////////////////////////////////////////////// 06303 PT(BoundingVolume) NodePath:: 06304 get_bounds(Thread *current_thread) const { 06305 nassertr_always(!is_empty(), new BoundingSphere); 06306 return node()->get_bounds(current_thread)->make_copy(); 06307 } 06308 06309 //////////////////////////////////////////////////////////////////// 06310 // Function: NodePath::force_recompute_bounds 06311 // Access: Published 06312 // Description: Forces the recomputing of all the bounding volumes at 06313 // every node in the subgraph beginning at this node and 06314 // below. 06315 // 06316 // This should not normally need to be called, since the 06317 // bounding volumes are supposed to be recomputed 06318 // automatically when necessary. It may be useful when 06319 // debugging, to verify that the bounding volumes have 06320 // not become inadvertently stale; it may also be useful 06321 // to force animated characters to update their bounding 06322 // volumes (which does not presently happen 06323 // automatically). 06324 //////////////////////////////////////////////////////////////////// 06325 void NodePath:: 06326 force_recompute_bounds() { 06327 nassertv_always(!is_empty()); 06328 r_force_recompute_bounds(node()); 06329 } 06330 06331 //////////////////////////////////////////////////////////////////// 06332 // Function: NodePath::write_bounds 06333 // Access: Published 06334 // Description: Writes a description of the bounding volume 06335 // containing the bottom node and all of its descendants 06336 // to the indicated output stream. 06337 //////////////////////////////////////////////////////////////////// 06338 void NodePath:: 06339 write_bounds(ostream &out) const { 06340 get_bounds()->write(out); 06341 } 06342 06343 //////////////////////////////////////////////////////////////////// 06344 // Function: NodePath::calc_tight_bounds 06345 // Access: Published 06346 // Description: Calculates the minimum and maximum vertices of all 06347 // Geoms at this NodePath's bottom node and below. This 06348 // is a tight bounding box; it will generally be tighter 06349 // than the bounding volume returned by get_bounds() 06350 // (but it is more expensive to compute). 06351 // 06352 // The return value is true if any points are within the 06353 // bounding volume, or false if none are. 06354 //////////////////////////////////////////////////////////////////// 06355 bool NodePath:: 06356 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, 06357 Thread *current_thread) const { 06358 min_point.set(0.0f, 0.0f, 0.0f); 06359 max_point.set(0.0f, 0.0f, 0.0f); 06360 nassertr_always(!is_empty(), false); 06361 06362 bool found_any = false; 06363 node()->calc_tight_bounds(min_point, max_point, found_any, 06364 TransformState::make_identity(), 06365 current_thread); 06366 06367 return found_any; 06368 } 06369 06370 /* 06371 06372 NB: Had to remove this function to avoid circular dependency when 06373 moving SceneGraphAnalyzer into pgraphnodes, attempting to reduce size 06374 of pgraph. This function is now defined as a Python extension 06375 function instead. 06376 06377 //////////////////////////////////////////////////////////////////// 06378 // Function: NodePath::analyze 06379 // Access: Published 06380 // Description: Analyzes the geometry below this node and reports the 06381 // number of vertices, triangles, etc. This is the same 06382 // information reported by the bam-info program. 06383 //////////////////////////////////////////////////////////////////// 06384 void NodePath:: 06385 analyze() const { 06386 nassertv_always(!is_empty()); 06387 SceneGraphAnalyzer sga; 06388 sga.add_node(node()); 06389 06390 if (sga.get_num_lod_nodes() == 0) { 06391 sga.write(nout); 06392 06393 } else { 06394 nout << "At highest LOD:\n"; 06395 SceneGraphAnalyzer sga2; 06396 sga2.set_lod_mode(SceneGraphAnalyzer::LM_highest); 06397 sga2.add_node(node()); 06398 sga2.write(nout); 06399 06400 nout << "\nAt lowest LOD:\n"; 06401 sga2.clear(); 06402 sga2.set_lod_mode(SceneGraphAnalyzer::LM_lowest); 06403 sga2.add_node(node()); 06404 sga2.write(nout); 06405 06406 nout << "\nAll nodes:\n"; 06407 sga.write(nout); 06408 } 06409 } 06410 */ 06411 06412 //////////////////////////////////////////////////////////////////// 06413 // Function: NodePath::flatten_light 06414 // Access: Published 06415 // Description: Lightly flattens out the hierarchy below this node by 06416 // applying transforms, colors, and texture matrices 06417 // from the nodes onto the vertices, but does not remove 06418 // any nodes. 06419 // 06420 // This can result in improved rendering performance 06421 // because there will be fewer transforms in the 06422 // resulting scene graph, but the number of nodes will 06423 // remain the same. 06424 // 06425 // In particular, any NodePaths that reference nodes 06426 // within this hierarchy will not be damaged. However, 06427 // since this operation will remove transforms from the 06428 // scene graph, it may be dangerous to apply to nodes 06429 // where you expect to dynamically modify the transform, 06430 // or where you expect the geometry to remain in a 06431 // particular local coordinate system. 06432 // 06433 // The return value is always 0, since flatten_light 06434 // does not remove any nodes. 06435 //////////////////////////////////////////////////////////////////// 06436 int NodePath:: 06437 flatten_light() { 06438 nassertr_always(!is_empty(), 0); 06439 SceneGraphReducer gr; 06440 gr.apply_attribs(node()); 06441 06442 return 0; 06443 } 06444 06445 //////////////////////////////////////////////////////////////////// 06446 // Function: NodePath::flatten_medium 06447 // Access: Published 06448 // Description: A more thorough flattening than flatten_light(), this 06449 // first applies all the transforms, colors, and texture 06450 // matrices from the nodes onto the vertices, and then 06451 // removes unneeded grouping nodes--nodes that have 06452 // exactly one child, for instance, but have no special 06453 // properties in themselves. 06454 // 06455 // This results in improved performance over 06456 // flatten_light() because the number of nodes in the 06457 // scene graph is reduced. 06458 // 06459 // The return value is the number of nodes removed. 06460 //////////////////////////////////////////////////////////////////// 06461 int NodePath:: 06462 flatten_medium() { 06463 nassertr_always(!is_empty(), 0); 06464 SceneGraphReducer gr; 06465 gr.apply_attribs(node()); 06466 int num_removed = gr.flatten(node(), 0); 06467 06468 if (flatten_geoms) { 06469 gr.make_compatible_state(node()); 06470 gr.collect_vertex_data(node()); 06471 gr.unify(node(), true); 06472 } 06473 06474 return num_removed; 06475 } 06476 06477 //////////////////////////////////////////////////////////////////// 06478 // Function: NodePath::flatten_strong 06479 // Access: Published 06480 // Description: The strongest possible flattening. This first 06481 // applies all of the transforms to the vertices, as in 06482 // flatten_medium(), but then it will combine sibling 06483 // nodes together when possible, in addition to removing 06484 // unnecessary parent-child nodes. This can result in 06485 // substantially fewer nodes, but any nicely-grouped 06486 // hierachical bounding volumes may be lost. 06487 // 06488 // It is generally a good idea to apply this kind of 06489 // flattening only to nodes that will be culled largely 06490 // as a single unit, like a car. Applying this to an 06491 // entire scene may result in overall poorer performance 06492 // because of less-effective culling. 06493 //////////////////////////////////////////////////////////////////// 06494 int NodePath:: 06495 flatten_strong() { 06496 nassertr_always(!is_empty(), 0); 06497 SceneGraphReducer gr; 06498 gr.apply_attribs(node()); 06499 int num_removed = gr.flatten(node(), ~0); 06500 06501 if (flatten_geoms) { 06502 gr.make_compatible_state(node()); 06503 gr.collect_vertex_data(node(), ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type)); 06504 gr.unify(node(), false); 06505 } 06506 06507 return num_removed; 06508 } 06509 06510 //////////////////////////////////////////////////////////////////// 06511 // Function: NodePath::apply_texture_colors 06512 // Access: Published 06513 // Description: Removes textures from Geoms at this node and below by 06514 // applying the texture colors to the vertices. This is 06515 // primarily useful to simplify a low-LOD model. The 06516 // texture colors are replaced by flat colors that 06517 // approximate the original textures. 06518 // 06519 // Only the bottommost texture on each Geom is used (if 06520 // there is more than one), and it is applied as if it 06521 // were M_modulate, and WM_repeat, regardless of its 06522 // actual settings. If the texture has a 06523 // simple_ram_image, this may be used if the main image 06524 // isn't resident. 06525 // 06526 // After this call, there will be no texturing specified 06527 // at this level and below. Of course, there might 06528 // still be texturing inherited from above. 06529 //////////////////////////////////////////////////////////////////// 06530 void NodePath:: 06531 apply_texture_colors() { 06532 nassertv_always(!is_empty()); 06533 SceneGraphReducer gr; 06534 gr.apply_attribs(node(), SceneGraphReducer::TT_apply_texture_color | SceneGraphReducer::TT_tex_matrix | SceneGraphReducer::TT_other); 06535 } 06536 06537 //////////////////////////////////////////////////////////////////// 06538 // Function: NodePath::find_net_tag 06539 // Access: Published 06540 // Description: Returns the lowest ancestor of this node that 06541 // contains a tag definition with the indicated key, if 06542 // any, or an empty NodePath if no ancestor of this node 06543 // contains this tag definition. See set_tag(). 06544 //////////////////////////////////////////////////////////////////// 06545 NodePath NodePath:: 06546 find_net_tag(const string &key) const { 06547 if (is_empty()) { 06548 return NodePath::not_found(); 06549 } 06550 if (has_tag(key)) { 06551 return *this; 06552 } 06553 return get_parent().find_net_tag(key); 06554 } 06555 06556 #ifdef HAVE_PYTHON 06557 //////////////////////////////////////////////////////////////////// 06558 // Function: NodePath::find_net_python_tag 06559 // Access: Published 06560 // Description: Returns the lowest ancestor of this node that 06561 // contains a tag definition with the indicated key, if 06562 // any, or an empty NodePath if no ancestor of this node 06563 // contains this tag definition. See set_python_tag(). 06564 //////////////////////////////////////////////////////////////////// 06565 NodePath NodePath:: 06566 find_net_python_tag(const string &key) const { 06567 if (is_empty()) { 06568 return NodePath::not_found(); 06569 } 06570 if (has_python_tag(key)) { 06571 return *this; 06572 } 06573 return get_parent().find_net_python_tag(key); 06574 } 06575 #endif // HAVE_PYTHON 06576 06577 //////////////////////////////////////////////////////////////////// 06578 // Function: NodePath::write_bam_file 06579 // Access: Published 06580 // Description: Writes the contents of this node and below out to a 06581 // bam file with the indicated filename. This file may 06582 // then be read in again, as is, at some later point. 06583 // Returns true if successful, false on some kind of 06584 // error. 06585 //////////////////////////////////////////////////////////////////// 06586 bool NodePath:: 06587 write_bam_file(const Filename &filename) const { 06588 nassertr_always(!is_empty(), false); 06589 06590 BamFile bam_file; 06591 06592 bool okflag = false; 06593 06594 if (bam_file.open_write(filename)) { 06595 if (bam_file.write_object(node())) { 06596 okflag = true; 06597 } 06598 bam_file.close(); 06599 } 06600 return okflag; 06601 } 06602 06603 //////////////////////////////////////////////////////////////////// 06604 // Function: NodePath::write_bam_stream 06605 // Access: Published 06606 // Description: Writes the contents of this node and below out to the 06607 // indicated stream. 06608 //////////////////////////////////////////////////////////////////// 06609 bool NodePath:: 06610 write_bam_stream(ostream &out) const { 06611 nassertr_always(!is_empty(), false); 06612 06613 BamFile bam_file; 06614 06615 bool okflag = false; 06616 06617 if (bam_file.open_write(out)) { 06618 if (bam_file.write_object(node())) { 06619 okflag = true; 06620 } 06621 bam_file.close(); 06622 } 06623 return okflag; 06624 } 06625 06626 //////////////////////////////////////////////////////////////////// 06627 // Function: NodePath::encode_to_bam_stream 06628 // Access: Published 06629 // Description: Converts the NodePath object into a single 06630 // stream of data using a BamWriter, and stores that 06631 // data in the indicated string. Returns true on 06632 // success, false on failure. 06633 // 06634 // If the BamWriter is NULL, this behaves the same way 06635 // as NodePath::write_bam_stream() and 06636 // PandaNode::encode_to_bam_stream(), in the sense that 06637 // it only writes this node and all nodes below it. 06638 // 06639 // However, if the BamWriter is not NULL, it behaves 06640 // very differently. In this case, it encodes the 06641 // *entire graph* of all nodes connected to the 06642 // NodePath, including all parent nodes and siblings. 06643 // This is necessary for correct streaming of related 06644 // NodePaths and restoration of instances, etc., but it 06645 // does mean you must detach() a node before writing it 06646 // if you want to limit the nodes that get written. 06647 // 06648 // This method is used by __reduce__ to handle streaming 06649 // of NodePaths to a pickle file. The BamWriter case is 06650 // used by the direct.stdpy.pickle module, while the 06651 // saner, non-BamWriter case is used when the standard 06652 // pickle module calls this function. 06653 //////////////////////////////////////////////////////////////////// 06654 bool NodePath:: 06655 encode_to_bam_stream(string &data, BamWriter *writer) const { 06656 data.clear(); 06657 ostringstream stream; 06658 06659 DatagramOutputFile dout; 06660 if (!dout.open(stream)) { 06661 return false; 06662 } 06663 06664 BamWriter local_writer; 06665 bool used_local_writer = false; 06666 if (writer == NULL) { 06667 // Create our own writer. 06668 06669 if (!dout.write_header(_bam_header)) { 06670 return false; 06671 } 06672 writer = &local_writer; 06673 used_local_writer = true; 06674 } 06675 06676 writer->set_target(&dout); 06677 06678 int num_nodes = get_num_nodes(); 06679 if (used_local_writer && num_nodes > 1) { 06680 // In this case--no BamWriter--we only write the bottom node. 06681 num_nodes = 1; 06682 } 06683 06684 // Write an initial Datagram to represent the error type and 06685 // number of nodes. 06686 Datagram dg; 06687 dg.add_uint8(_error_type); 06688 dg.add_int32(num_nodes); 06689 06690 if (!dout.put_datagram(dg)) { 06691 writer->set_target(NULL); 06692 return false; 06693 } 06694 06695 // Now write the nodes, one at a time. 06696 for (int i = 0; i < num_nodes; ++i) { 06697 PandaNode *node = get_node(num_nodes - i - 1); 06698 nassertr(node != NULL, false); 06699 if (!writer->write_object(node)) { 06700 writer->set_target(NULL); 06701 return false; 06702 } 06703 } 06704 writer->set_target(NULL); 06705 06706 data = stream.str(); 06707 return true; 06708 } 06709 06710 //////////////////////////////////////////////////////////////////// 06711 // Function: NodePath::decode_from_bam_stream 06712 // Access: Published, Static 06713 // Description: Reads the string created by a previous call to 06714 // encode_to_bam_stream(), and extracts and 06715 // returns the NodePath on that string. Returns NULL on 06716 // error. 06717 //////////////////////////////////////////////////////////////////// 06718 NodePath NodePath:: 06719 decode_from_bam_stream(const string &data, BamReader *reader) { 06720 NodePath result; 06721 06722 istringstream stream(data); 06723 06724 DatagramInputFile din; 06725 if (!din.open(stream)) { 06726 return NodePath::fail(); 06727 } 06728 06729 BamReader local_reader; 06730 if (reader == NULL) { 06731 // Create a local reader. 06732 06733 string head; 06734 if (!din.read_header(head, _bam_header.size())) { 06735 return NodePath::fail(); 06736 } 06737 06738 if (head != _bam_header) { 06739 return NodePath::fail(); 06740 } 06741 06742 reader = &local_reader; 06743 } 06744 06745 reader->set_source(&din); 06746 06747 // One initial datagram to encode the error type, and the number of nodes. 06748 Datagram dg; 06749 if (!din.get_datagram(dg)) { 06750 return NodePath::fail(); 06751 } 06752 06753 DatagramIterator dgi(dg); 06754 ErrorType error_type = (ErrorType)dgi.get_uint8(); 06755 int num_nodes = dgi.get_int32(); 06756 if (num_nodes == 0) { 06757 // An empty NodePath. 06758 result._error_type = error_type; 06759 06760 } else { 06761 // A real NodePath. Ignore error_type. 06762 for (int i = 0; i < num_nodes; ++i) { 06763 TypedWritable *object = reader->read_object(); 06764 06765 if (object == (TypedWritable *)NULL || 06766 !object->is_of_type(PandaNode::get_class_type())) { 06767 reader->set_source(NULL); 06768 return NodePath::fail(); 06769 } 06770 06771 if (!reader->resolve()) { 06772 reader->set_source(NULL); 06773 return NodePath::fail(); 06774 } 06775 06776 PandaNode *node = DCAST(PandaNode, object); 06777 result = NodePath(result, node); 06778 } 06779 } 06780 06781 reader->set_source(NULL); 06782 06783 return result; 06784 } 06785 06786 //////////////////////////////////////////////////////////////////// 06787 // Function: NodePath::find_common_ancestor 06788 // Access: Private, Static 06789 // Description: Walks up from both NodePaths to find the first node 06790 // that both have in common, if any. Fills a_count and 06791 // b_count with the number of nodes below the common 06792 // node in each path. 06793 // 06794 // The return value is the NodePathComponent of the node 06795 // they have in common, or NULL if they have nothing in 06796 // common. 06797 //////////////////////////////////////////////////////////////////// 06798 NodePathComponent *NodePath:: 06799 find_common_ancestor(const NodePath &a, const NodePath &b, 06800 int &a_count, int &b_count, Thread *current_thread) { 06801 nassertr(!a.is_empty() && !b.is_empty(), NULL); 06802 NodePathComponent *ac = a._head; 06803 NodePathComponent *bc = b._head; 06804 a_count = 0; 06805 b_count = 0; 06806 06807 int pipeline_stage = current_thread->get_pipeline_stage(); 06808 06809 // Shorten up the longer one until they are the same length. 06810 while (ac->get_length(pipeline_stage, current_thread) > bc->get_length(pipeline_stage, current_thread)) { 06811 nassertr(ac != (NodePathComponent *)NULL, NULL); 06812 ac = ac->get_next(pipeline_stage, current_thread); 06813 a_count++; 06814 } 06815 while (bc->get_length(pipeline_stage, current_thread) > ac->get_length(pipeline_stage, current_thread)) { 06816 nassertr(bc != (NodePathComponent *)NULL, NULL); 06817 bc = bc->get_next(pipeline_stage, current_thread); 06818 b_count++; 06819 } 06820 06821 // Now shorten them both up until we reach the same component. 06822 while (ac != bc) { 06823 // These shouldn't go to NULL unless they both go there together. 06824 nassertr(ac != (NodePathComponent *)NULL, NULL); 06825 nassertr(bc != (NodePathComponent *)NULL, NULL); 06826 ac = ac->get_next(pipeline_stage, current_thread); 06827 a_count++; 06828 bc = bc->get_next(pipeline_stage, current_thread); 06829 b_count++; 06830 } 06831 06832 return ac; 06833 } 06834 06835 //////////////////////////////////////////////////////////////////// 06836 // Function: NodePath::r_get_net_state 06837 // Access: Private 06838 // Description: Recursively determines the net state changes to the 06839 // indicated component node from the root of the graph. 06840 //////////////////////////////////////////////////////////////////// 06841 CPT(RenderState) NodePath:: 06842 r_get_net_state(NodePathComponent *comp, Thread *current_thread) const { 06843 if (comp == (NodePathComponent *)NULL) { 06844 return RenderState::make_empty(); 06845 } else { 06846 CPT(RenderState) state = comp->get_node()->get_state(current_thread); 06847 int pipeline_stage = current_thread->get_pipeline_stage(); 06848 return r_get_net_state(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(state); 06849 } 06850 } 06851 06852 //////////////////////////////////////////////////////////////////// 06853 // Function: NodePath::r_get_partial_state 06854 // Access: Private 06855 // Description: Recursively determines the net state changes to the 06856 // indicated component node from the nth node above it. 06857 // If n exceeds the length of the path, this returns the 06858 // net transform from the root of the graph. 06859 //////////////////////////////////////////////////////////////////// 06860 CPT(RenderState) NodePath:: 06861 r_get_partial_state(NodePathComponent *comp, int n, 06862 Thread *current_thread) const { 06863 if (n == 0 || comp == (NodePathComponent *)NULL) { 06864 return RenderState::make_empty(); 06865 } else { 06866 CPT(RenderState) state = comp->get_node()->get_state(current_thread); 06867 int pipeline_stage = current_thread->get_pipeline_stage(); 06868 return r_get_partial_state(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(state); 06869 } 06870 } 06871 06872 //////////////////////////////////////////////////////////////////// 06873 // Function: NodePath::r_get_net_transform 06874 // Access: Private 06875 // Description: Recursively determines the net transform to the 06876 // indicated component node from the root of the graph. 06877 //////////////////////////////////////////////////////////////////// 06878 CPT(TransformState) NodePath:: 06879 r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const { 06880 if (comp == (NodePathComponent *)NULL) { 06881 return TransformState::make_identity(); 06882 } else { 06883 int pipeline_stage = current_thread->get_pipeline_stage(); 06884 CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread); 06885 PandaNode *node = comp->get_node(); 06886 CPT(TransformState) transform = node->get_transform(current_thread); 06887 06888 CPT(RenderEffects) effects = node->get_effects(current_thread); 06889 if (effects->has_adjust_transform()) { 06890 effects->adjust_transform(net_transform, transform, node); 06891 } 06892 06893 return net_transform->compose(transform); 06894 } 06895 } 06896 06897 //////////////////////////////////////////////////////////////////// 06898 // Function: NodePath::r_get_partial_transform 06899 // Access: Private 06900 // Description: Recursively determines the net transform to the 06901 // indicated component node from the nth node above it. 06902 // If n exceeds the length of the path, this returns the 06903 // net transform from the root of the graph. 06904 // 06905 // If any node in the path had a net_transform effect 06906 // applied, returns NULL--in this case the partial 06907 // transform cannot be easily determined. 06908 //////////////////////////////////////////////////////////////////// 06909 CPT(TransformState) NodePath:: 06910 r_get_partial_transform(NodePathComponent *comp, int n, 06911 Thread *current_thread) const { 06912 if (n == 0 || comp == (NodePathComponent *)NULL) { 06913 return TransformState::make_identity(); 06914 } else { 06915 if (comp->get_node()->get_effects(current_thread)->has_adjust_transform()) { 06916 return NULL; 06917 } 06918 CPT(TransformState) transform = comp->get_node()->get_transform(current_thread); 06919 int pipeline_stage = current_thread->get_pipeline_stage(); 06920 CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread); 06921 if (partial == (const TransformState *)NULL) { 06922 return NULL; 06923 } 06924 return partial->compose(transform); 06925 } 06926 } 06927 06928 //////////////////////////////////////////////////////////////////// 06929 // Function: NodePath::r_get_net_prev_transform 06930 // Access: Private 06931 // Description: Recursively determines the net "previous" transform 06932 // to the indicated component node from the root of the 06933 // graph. 06934 //////////////////////////////////////////////////////////////////// 06935 CPT(TransformState) NodePath:: 06936 r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const { 06937 if (comp == (NodePathComponent *)NULL) { 06938 return TransformState::make_identity(); 06939 } else { 06940 CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread); 06941 int pipeline_stage = current_thread->get_pipeline_stage(); 06942 return r_get_net_prev_transform(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(transform); 06943 } 06944 } 06945 06946 //////////////////////////////////////////////////////////////////// 06947 // Function: NodePath::r_get_partial_prev_transform 06948 // Access: Private 06949 // Description: Recursively determines the net "previous" transform 06950 // to the indicated component node from the nth node 06951 // above it. If n exceeds the length of the path, this 06952 // returns the net previous transform from the root of 06953 // the graph. 06954 //////////////////////////////////////////////////////////////////// 06955 CPT(TransformState) NodePath:: 06956 r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const { 06957 if (n == 0 || comp == (NodePathComponent *)NULL) { 06958 return TransformState::make_identity(); 06959 } else { 06960 CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread); 06961 int pipeline_stage = current_thread->get_pipeline_stage(); 06962 return r_get_partial_prev_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(transform); 06963 } 06964 } 06965 06966 //////////////////////////////////////////////////////////////////// 06967 // Function: NodePath::find_matches 06968 // Access: Private 06969 // Description: Finds up to max_matches matches against the given 06970 // path string from this node and deeper. The 06971 // max_matches count indicates the maximum number of 06972 // matches to return, or -1 not to limit the number 06973 // returned. 06974 //////////////////////////////////////////////////////////////////// 06975 void NodePath:: 06976 find_matches(NodePathCollection &result, const string &path, 06977 int max_matches) const { 06978 if (is_empty()) { 06979 pgraph_cat.warning() 06980 << "Attempt to extend an empty NodePath by '" << path 06981 << "'.\n"; 06982 return; 06983 } 06984 FindApproxPath approx_path; 06985 if (approx_path.add_string(path)) { 06986 find_matches(result, approx_path, max_matches); 06987 } 06988 } 06989 06990 //////////////////////////////////////////////////////////////////// 06991 // Function: NodePath::find_matches 06992 // Access: Private 06993 // Description: Finds up to max_matches matches against the given 06994 // approx_path from this node and deeper. The 06995 // max_matches count indicates the maximum number of 06996 // matches to return, or -1 not to limit the number 06997 // returned. 06998 //////////////////////////////////////////////////////////////////// 06999 void NodePath:: 07000 find_matches(NodePathCollection &result, FindApproxPath &approx_path, 07001 int max_matches) const { 07002 if (is_empty()) { 07003 pgraph_cat.warning() 07004 << "Attempt to extend an empty NodePath by: " << approx_path << ".\n"; 07005 return; 07006 } 07007 07008 // We start with just one entry on the level. 07009 FindApproxLevelEntry *level = 07010 new FindApproxLevelEntry(WorkingNodePath(*this), approx_path); 07011 nassertv(level->_node_path.is_valid()); 07012 07013 find_matches(result, level, max_matches); 07014 } 07015 07016 //////////////////////////////////////////////////////////////////// 07017 // Function: NodePath::find_matches 07018 // Access: Private 07019 // Description: The fundamental implementation of find_matches(), 07020 // given a starting level (a linked list of 07021 // FindApproxLevelEntry objects). 07022 //////////////////////////////////////////////////////////////////// 07023 void NodePath:: 07024 find_matches(NodePathCollection &result, FindApproxLevelEntry *level, 07025 int max_matches) const { 07026 07027 int num_levels_remaining = _max_search_depth; 07028 07029 FindApproxLevelEntry *deleted_entries = NULL; 07030 07031 while (num_levels_remaining > 0 && level != NULL) { 07032 if (pgraph_cat.is_spam()) { 07033 pgraph_cat.spam() 07034 << "find_matches pass: " << result << ", " 07035 << max_matches << ", " << num_levels_remaining << "\n"; 07036 level->write_level(pgraph_cat.spam(false), 4); 07037 } 07038 07039 num_levels_remaining--; 07040 07041 FindApproxLevelEntry *next_level = NULL; 07042 07043 // For each node in the current level, build up the set of possible 07044 // matches in the next level. 07045 FindApproxLevelEntry *entry = level; 07046 while (entry != (FindApproxLevelEntry *)NULL) { 07047 if (entry->consider_node(result, next_level, max_matches, 0)) { 07048 // If we found the requisite number of matches, we can stop. 07049 // Delete all remaining entries and return immediately. 07050 07051 while (entry != (FindApproxLevelEntry *)NULL) { 07052 FindApproxLevelEntry *next = entry->_next; 07053 delete entry; 07054 entry = next; 07055 } 07056 while (next_level != (FindApproxLevelEntry *)NULL) { 07057 FindApproxLevelEntry *next = next_level->_next; 07058 delete next_level; 07059 next_level = next; 07060 } 07061 while (deleted_entries != (FindApproxLevelEntry *)NULL) { 07062 FindApproxLevelEntry *next = deleted_entries->_next; 07063 delete deleted_entries; 07064 deleted_entries = next; 07065 } 07066 return; 07067 } 07068 07069 // Move the entry to the delete chain so we can delete it before 07070 // we return from this method. (We can't delete it immediately, 07071 // because there might be WorkingNodePaths in the next_level 07072 // that reference the WorkingNodePath object within the entry.) 07073 FindApproxLevelEntry *next = entry->_next; 07074 entry->_next = deleted_entries; 07075 deleted_entries = entry; 07076 07077 entry = next; 07078 } 07079 07080 // Make sure the remaining entries from this level are added to 07081 // the delete chain. 07082 while (entry != (FindApproxLevelEntry *)NULL) { 07083 FindApproxLevelEntry *next = entry->_next; 07084 entry->_next = deleted_entries; 07085 deleted_entries = entry; 07086 07087 entry = next; 07088 } 07089 07090 level = next_level; 07091 } 07092 07093 // Now it's safe to delete all entries on the delete chain. 07094 while (deleted_entries != (FindApproxLevelEntry *)NULL) { 07095 FindApproxLevelEntry *next = deleted_entries->_next; 07096 delete deleted_entries; 07097 deleted_entries = next; 07098 } 07099 } 07100 07101 //////////////////////////////////////////////////////////////////// 07102 // Function: NodePath::r_clear_model_nodes 07103 // Access: Private 07104 // Description: The recursive implementation of 07105 // clear_model_nodes(). This walks through the 07106 // subgraph defined by the indicated node and below. 07107 //////////////////////////////////////////////////////////////////// 07108 int NodePath:: 07109 r_clear_model_nodes(PandaNode *node) { 07110 int count = 0; 07111 07112 if (node->is_of_type(ModelNode::get_class_type())) { 07113 ModelNode *mnode; 07114 DCAST_INTO_R(mnode, node, count); 07115 mnode->set_preserve_transform(ModelNode::PT_drop_node); 07116 ++count; 07117 } 07118 07119 PandaNode::Children cr = node->get_children(); 07120 int num_children = cr.get_num_children(); 07121 for (int i = 0; i < num_children; i++) { 07122 count += r_clear_model_nodes(cr.get_child(i)); 07123 } 07124 07125 return count; 07126 } 07127 07128 //////////////////////////////////////////////////////////////////// 07129 // Function: NodePath::r_adjust_all_priorities 07130 // Access: Private 07131 // Description: The recursive implementation of 07132 // adjust_all_priorities(). This walks through the 07133 // subgraph defined by the indicated node and below. 07134 //////////////////////////////////////////////////////////////////// 07135 void NodePath:: 07136 r_adjust_all_priorities(PandaNode *node, int adjustment) { 07137 node->set_state(node->get_state()->adjust_all_priorities(adjustment)); 07138 if (node->is_geom_node()) { 07139 GeomNode *gnode; 07140 DCAST_INTO_V(gnode, node); 07141 07142 int num_geoms = gnode->get_num_geoms(); 07143 for (int i = 0; i < num_geoms; i++) { 07144 gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment)); 07145 } 07146 } 07147 07148 PandaNode::Children cr = node->get_children(); 07149 int num_children = cr.get_num_children(); 07150 for (int i = 0; i < num_children; i++) { 07151 r_adjust_all_priorities(cr.get_child(i), adjustment); 07152 } 07153 } 07154 07155 //////////////////////////////////////////////////////////////////// 07156 // Function: NodePath::r_force_recompute_bounds 07157 // Access: Private 07158 // Description: 07159 //////////////////////////////////////////////////////////////////// 07160 void NodePath:: 07161 r_force_recompute_bounds(PandaNode *node) { 07162 if (node->is_geom_node()) { 07163 GeomNode *gnode; 07164 DCAST_INTO_V(gnode, node); 07165 07166 int num_geoms = gnode->get_num_geoms(); 07167 for (int i = 0; i < num_geoms; i++) { 07168 const Geom *geom = gnode->get_geom(i); 07169 geom->mark_bounds_stale(); 07170 } 07171 } 07172 07173 node->mark_bounds_stale(); 07174 07175 // Now consider children. 07176 PandaNode::Children cr = node->get_children(); 07177 int num_children = cr.get_num_children(); 07178 for (int i = 0; i < num_children; i++) { 07179 r_force_recompute_bounds(cr.get_child(i)); 07180 } 07181 } 07182 07183 //////////////////////////////////////////////////////////////////// 07184 // Function: NodePath::r_set_collide_mask 07185 // Access: Private 07186 // Description: Recursively applies the indicated collide mask to the 07187 // nodes at and below this node. 07188 //////////////////////////////////////////////////////////////////// 07189 void NodePath:: 07190 r_set_collide_mask(PandaNode *node, 07191 CollideMask and_mask, CollideMask or_mask, 07192 TypeHandle node_type) { 07193 if (node->is_of_type(node_type)) { 07194 CollideMask into_collide_mask = node->get_into_collide_mask(); 07195 into_collide_mask = (into_collide_mask & and_mask) | or_mask; 07196 node->set_into_collide_mask(into_collide_mask); 07197 } 07198 07199 PandaNode::Children cr = node->get_children(); 07200 int num_children = cr.get_num_children(); 07201 for (int i = 0; i < num_children; i++) { 07202 r_set_collide_mask(cr.get_child(i), and_mask, or_mask, node_type); 07203 } 07204 } 07205 07206 //////////////////////////////////////////////////////////////////// 07207 // Function: NodePath::r_has_vertex_column 07208 // Access: Private 07209 // Description: 07210 //////////////////////////////////////////////////////////////////// 07211 bool NodePath:: 07212 r_has_vertex_column(PandaNode *node, const InternalName *name) const { 07213 if (node->is_geom_node()) { 07214 GeomNode *gnode; 07215 DCAST_INTO_R(gnode, node, false); 07216 07217 int num_geoms = gnode->get_num_geoms(); 07218 for (int i = 0; i < num_geoms; i++) { 07219 const Geom *geom = gnode->get_geom(i); 07220 CPT(GeomVertexData) vdata = geom->get_vertex_data(); 07221 if (vdata->has_column(name)) { 07222 return true; 07223 } 07224 } 07225 } 07226 07227 // Now consider children. 07228 PandaNode::Children cr = node->get_children(); 07229 int num_children = cr.get_num_children(); 07230 for (int i = 0; i < num_children; i++) { 07231 PandaNode *child = cr.get_child(i); 07232 if (r_has_vertex_column(child, name)) { 07233 return true; 07234 } 07235 } 07236 07237 return false; 07238 } 07239 07240 //////////////////////////////////////////////////////////////////// 07241 // Function: NodePath::r_find_all_vertex_columns 07242 // Access: Private 07243 // Description: 07244 //////////////////////////////////////////////////////////////////// 07245 void NodePath:: 07246 r_find_all_vertex_columns(PandaNode *node, 07247 NodePath::InternalNames &vertex_columns) const { 07248 if (node->is_geom_node()) { 07249 GeomNode *gnode; 07250 DCAST_INTO_V(gnode, node); 07251 07252 int num_geoms = gnode->get_num_geoms(); 07253 for (int i = 0; i < num_geoms; ++i) { 07254 const Geom *geom = gnode->get_geom(i); 07255 const GeomVertexFormat *format = geom->get_vertex_data()->get_format(); 07256 int num_arrays = format->get_num_arrays(); 07257 for (int j = 0; j < num_arrays; ++j) { 07258 const GeomVertexArrayFormat *array = format->get_array(j); 07259 int num_columns = array->get_num_columns(); 07260 for (int k = 0; k < num_columns; ++k) { 07261 const GeomVertexColumn *column = array->get_column(k); 07262 vertex_columns.insert(column->get_name()); 07263 } 07264 } 07265 } 07266 } 07267 07268 // Now consider children. 07269 PandaNode::Children cr = node->get_children(); 07270 int num_children = cr.get_num_children(); 07271 for (int i = 0; i < num_children; i++) { 07272 PandaNode *child = cr.get_child(i); 07273 r_find_all_vertex_columns(child, vertex_columns); 07274 } 07275 } 07276 07277 //////////////////////////////////////////////////////////////////// 07278 // Function: NodePath::r_find_texture 07279 // Access: Private 07280 // Description: 07281 //////////////////////////////////////////////////////////////////// 07282 Texture *NodePath:: 07283 r_find_texture(PandaNode *node, const RenderState *state, 07284 const GlobPattern &glob) const { 07285 if (node->is_geom_node()) { 07286 GeomNode *gnode; 07287 DCAST_INTO_R(gnode, node, NULL); 07288 07289 int num_geoms = gnode->get_num_geoms(); 07290 for (int i = 0; i < num_geoms; i++) { 07291 CPT(RenderState) geom_state = 07292 state->compose(gnode->get_geom_state(i)); 07293 07294 // Look for a TextureAttrib on the state. 07295 const RenderAttrib *attrib = 07296 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07297 if (attrib != (const RenderAttrib *)NULL) { 07298 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07299 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07300 Texture *texture = ta->get_on_texture(ta->get_on_stage(i)); 07301 if (texture != (Texture *)NULL) { 07302 if (glob.matches(texture->get_name())) { 07303 return texture; 07304 } 07305 } 07306 } 07307 } 07308 } 07309 } 07310 07311 // Now consider children. 07312 PandaNode::Children cr = node->get_children(); 07313 int num_children = cr.get_num_children(); 07314 for (int i = 0; i < num_children; i++) { 07315 PandaNode *child = cr.get_child(i); 07316 CPT(RenderState) next_state = state->compose(child->get_state()); 07317 07318 Texture *result = r_find_texture(child, next_state, glob); 07319 if (result != (Texture *)NULL) { 07320 return result; 07321 } 07322 } 07323 07324 return NULL; 07325 } 07326 07327 //////////////////////////////////////////////////////////////////// 07328 // Function: NodePath::r_find_all_textures 07329 // Access: Private 07330 // Description: 07331 //////////////////////////////////////////////////////////////////// 07332 void NodePath:: 07333 r_find_all_textures(PandaNode *node, const RenderState *state, 07334 NodePath::Textures &textures) const { 07335 if (node->is_geom_node()) { 07336 GeomNode *gnode; 07337 DCAST_INTO_V(gnode, node); 07338 07339 int num_geoms = gnode->get_num_geoms(); 07340 for (int i = 0; i < num_geoms; i++) { 07341 CPT(RenderState) geom_state = 07342 state->compose(gnode->get_geom_state(i)); 07343 07344 // Look for a TextureAttrib on the state. 07345 const RenderAttrib *attrib = 07346 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07347 if (attrib != (const RenderAttrib *)NULL) { 07348 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07349 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07350 Texture *texture = ta->get_on_texture(ta->get_on_stage(i)); 07351 if (texture != (Texture *)NULL) { 07352 textures.insert(texture); 07353 } 07354 } 07355 } 07356 } 07357 } 07358 07359 // Now consider children. 07360 PandaNode::Children cr = node->get_children(); 07361 int num_children = cr.get_num_children(); 07362 for (int i = 0; i < num_children; i++) { 07363 PandaNode *child = cr.get_child(i); 07364 CPT(RenderState) next_state = state->compose(child->get_state()); 07365 r_find_all_textures(child, next_state, textures); 07366 } 07367 } 07368 07369 //////////////////////////////////////////////////////////////////// 07370 // Function: NodePath::r_find_texture 07371 // Access: Private 07372 // Description: 07373 //////////////////////////////////////////////////////////////////// 07374 Texture * NodePath:: 07375 r_find_texture(PandaNode *node, TextureStage *stage) const { 07376 // Look for a TextureAttrib on the node. 07377 const RenderAttrib *attrib = 07378 node->get_attrib(TextureAttrib::get_class_slot()); 07379 if (attrib != (const RenderAttrib *)NULL) { 07380 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07381 if (ta->has_on_stage(stage)) { 07382 return ta->get_on_texture(stage); 07383 } 07384 } 07385 07386 if (node->is_geom_node()) { 07387 GeomNode *gnode; 07388 DCAST_INTO_R(gnode, node, NULL); 07389 07390 int num_geoms = gnode->get_num_geoms(); 07391 for (int i = 0; i < num_geoms; i++) { 07392 CPT(RenderState) geom_state = gnode->get_geom_state(i); 07393 07394 // Look for a TextureAttrib on the state. 07395 const RenderAttrib *attrib = 07396 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07397 if (attrib != (const RenderAttrib *)NULL) { 07398 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07399 if (ta->has_on_stage(stage)) { 07400 return ta->get_on_texture(stage); 07401 } 07402 } 07403 } 07404 } 07405 07406 // Now consider children. 07407 PandaNode::Children cr = node->get_children(); 07408 int num_children = cr.get_num_children(); 07409 for (int i = 0; i < num_children; i++) { 07410 PandaNode *child = cr.get_child(i); 07411 07412 Texture *result = r_find_texture(child, stage); 07413 if (result != (Texture *)NULL) { 07414 return result; 07415 } 07416 } 07417 07418 return NULL; 07419 } 07420 07421 //////////////////////////////////////////////////////////////////// 07422 // Function: NodePath::r_find_all_textures 07423 // Access: Private 07424 // Description: 07425 //////////////////////////////////////////////////////////////////// 07426 void NodePath:: 07427 r_find_all_textures(PandaNode *node, TextureStage *stage, 07428 NodePath::Textures &textures) const { 07429 // Look for a TextureAttrib on the node. 07430 const RenderAttrib *attrib = 07431 node->get_attrib(TextureAttrib::get_class_slot()); 07432 if (attrib != (const RenderAttrib *)NULL) { 07433 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07434 if (ta->has_on_stage(stage)) { 07435 textures.insert(ta->get_on_texture(stage)); 07436 } 07437 } 07438 07439 if (node->is_geom_node()) { 07440 GeomNode *gnode; 07441 DCAST_INTO_V(gnode, node); 07442 07443 int num_geoms = gnode->get_num_geoms(); 07444 for (int i = 0; i < num_geoms; i++) { 07445 CPT(RenderState) geom_state = gnode->get_geom_state(i); 07446 07447 // Look for a TextureAttrib on the state. 07448 const RenderAttrib *attrib = 07449 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07450 if (attrib != (const RenderAttrib *)NULL) { 07451 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07452 if (ta->has_on_stage(stage)) { 07453 textures.insert(ta->get_on_texture(stage)); 07454 } 07455 } 07456 } 07457 } 07458 07459 // Now consider children. 07460 PandaNode::Children cr = node->get_children(); 07461 int num_children = cr.get_num_children(); 07462 for (int i = 0; i < num_children; i++) { 07463 PandaNode *child = cr.get_child(i); 07464 r_find_all_textures(child, stage, textures); 07465 } 07466 } 07467 07468 //////////////////////////////////////////////////////////////////// 07469 // Function: NodePath::r_find_texture_stage 07470 // Access: Private 07471 // Description: 07472 //////////////////////////////////////////////////////////////////// 07473 TextureStage * NodePath:: 07474 r_find_texture_stage(PandaNode *node, const RenderState *state, 07475 const GlobPattern &glob) const { 07476 if (node->is_geom_node()) { 07477 GeomNode *gnode; 07478 DCAST_INTO_R(gnode, node, NULL); 07479 07480 int num_geoms = gnode->get_num_geoms(); 07481 for (int i = 0; i < num_geoms; i++) { 07482 CPT(RenderState) geom_state = 07483 state->compose(gnode->get_geom_state(i)); 07484 07485 // Look for a TextureAttrib on the state. 07486 const RenderAttrib *attrib = 07487 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07488 if (attrib != (const RenderAttrib *)NULL) { 07489 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07490 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07491 TextureStage *texture_stage = ta->get_on_stage(i); 07492 if (texture_stage != (TextureStage *)NULL) { 07493 if (glob.matches(texture_stage->get_name())) { 07494 return texture_stage; 07495 } 07496 } 07497 } 07498 } 07499 } 07500 } 07501 07502 // Now consider children. 07503 PandaNode::Children cr = node->get_children(); 07504 int num_children = cr.get_num_children(); 07505 for (int i = 0; i < num_children; i++) { 07506 PandaNode *child = cr.get_child(i); 07507 CPT(RenderState) next_state = state->compose(child->get_state()); 07508 07509 TextureStage *result = r_find_texture_stage(child, next_state, glob); 07510 if (result != (TextureStage *)NULL) { 07511 return result; 07512 } 07513 } 07514 07515 return NULL; 07516 } 07517 07518 //////////////////////////////////////////////////////////////////// 07519 // Function: NodePath::r_find_all_texture_stages 07520 // Access: Private 07521 // Description: 07522 //////////////////////////////////////////////////////////////////// 07523 void NodePath:: 07524 r_find_all_texture_stages(PandaNode *node, const RenderState *state, 07525 NodePath::TextureStages &texture_stages) const { 07526 if (node->is_geom_node()) { 07527 GeomNode *gnode; 07528 DCAST_INTO_V(gnode, node); 07529 07530 int num_geoms = gnode->get_num_geoms(); 07531 for (int i = 0; i < num_geoms; i++) { 07532 CPT(RenderState) geom_state = 07533 state->compose(gnode->get_geom_state(i)); 07534 07535 // Look for a TextureAttrib on the state. 07536 const RenderAttrib *attrib = 07537 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07538 if (attrib != (const RenderAttrib *)NULL) { 07539 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07540 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07541 TextureStage *texture_stage = ta->get_on_stage(i); 07542 if (texture_stage != (TextureStage *)NULL) { 07543 texture_stages.insert(texture_stage); 07544 } 07545 } 07546 } 07547 } 07548 } 07549 07550 // Now consider children. 07551 PandaNode::Children cr = node->get_children(); 07552 int num_children = cr.get_num_children(); 07553 for (int i = 0; i < num_children; i++) { 07554 PandaNode *child = cr.get_child(i); 07555 CPT(RenderState) next_state = state->compose(child->get_state()); 07556 r_find_all_texture_stages(child, next_state, texture_stages); 07557 } 07558 } 07559 07560 //////////////////////////////////////////////////////////////////// 07561 // Function: NodePath::r_unify_texture_stages 07562 // Access: Private 07563 // Description: 07564 //////////////////////////////////////////////////////////////////// 07565 void NodePath:: 07566 r_unify_texture_stages(PandaNode *node, TextureStage *stage) { 07567 // Look for a TextureAttrib on the state. 07568 const RenderAttrib *attrib = 07569 node->get_attrib(TextureAttrib::get_class_slot()); 07570 if (attrib != (const RenderAttrib *)NULL) { 07571 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07572 CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage); 07573 if (new_attrib != ta) { 07574 node->set_attrib(new_attrib); 07575 } 07576 } 07577 07578 if (node->is_geom_node()) { 07579 GeomNode *gnode; 07580 DCAST_INTO_V(gnode, node); 07581 07582 int num_geoms = gnode->get_num_geoms(); 07583 for (int i = 0; i < num_geoms; i++) { 07584 CPT(RenderState) state = gnode->get_geom_state(i); 07585 07586 // Look for a TextureAttrib on the state. 07587 const RenderAttrib *attrib = 07588 state->get_attrib(TextureAttrib::get_class_slot()); 07589 if (attrib != (const RenderAttrib *)NULL) { 07590 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07591 CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage); 07592 if (new_attrib != ta) { 07593 CPT(RenderState) new_state = state->add_attrib(new_attrib); 07594 gnode->set_geom_state(i, new_state); 07595 } 07596 } 07597 } 07598 } 07599 07600 // Now consider children. 07601 PandaNode::Children cr = node->get_children(); 07602 int num_children = cr.get_num_children(); 07603 for (int i = 0; i < num_children; i++) { 07604 PandaNode *child = cr.get_child(i); 07605 r_unify_texture_stages(child, stage); 07606 } 07607 } 07608 07609 //////////////////////////////////////////////////////////////////// 07610 // Function: NodePath::r_find_material 07611 // Access: Private 07612 // Description: 07613 //////////////////////////////////////////////////////////////////// 07614 Material *NodePath:: 07615 r_find_material(PandaNode *node, const RenderState *state, 07616 const GlobPattern &glob) const { 07617 if (node->is_geom_node()) { 07618 GeomNode *gnode; 07619 DCAST_INTO_R(gnode, node, NULL); 07620 07621 int num_geoms = gnode->get_num_geoms(); 07622 for (int i = 0; i < num_geoms; i++) { 07623 CPT(RenderState) geom_state = 07624 state->compose(gnode->get_geom_state(i)); 07625 07626 // Look for a MaterialAttrib on the state. 07627 const RenderAttrib *attrib = 07628 geom_state->get_attrib(MaterialAttrib::get_class_slot()); 07629 if (attrib != (const RenderAttrib *)NULL) { 07630 const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib); 07631 if (!ta->is_off()) { 07632 Material *material = ta->get_material(); 07633 if (material != (Material *)NULL) { 07634 if (glob.matches(material->get_name())) { 07635 return material; 07636 } 07637 } 07638 } 07639 } 07640 } 07641 } 07642 07643 // Now consider children. 07644 PandaNode::Children cr = node->get_children(); 07645 int num_children = cr.get_num_children(); 07646 for (int i = 0; i < num_children; i++) { 07647 PandaNode *child = cr.get_child(i); 07648 CPT(RenderState) next_state = state->compose(child->get_state()); 07649 07650 Material *result = r_find_material(child, next_state, glob); 07651 if (result != (Material *)NULL) { 07652 return result; 07653 } 07654 } 07655 07656 return NULL; 07657 } 07658 07659 //////////////////////////////////////////////////////////////////// 07660 // Function: NodePath::r_find_all_materials 07661 // Access: Private 07662 // Description: 07663 //////////////////////////////////////////////////////////////////// 07664 void NodePath:: 07665 r_find_all_materials(PandaNode *node, const RenderState *state, 07666 NodePath::Materials &materials) const { 07667 if (node->is_geom_node()) { 07668 GeomNode *gnode; 07669 DCAST_INTO_V(gnode, node); 07670 07671 int num_geoms = gnode->get_num_geoms(); 07672 for (int i = 0; i < num_geoms; i++) { 07673 CPT(RenderState) geom_state = 07674 state->compose(gnode->get_geom_state(i)); 07675 07676 // Look for a MaterialAttrib on the state. 07677 const RenderAttrib *attrib = 07678 geom_state->get_attrib(MaterialAttrib::get_class_slot()); 07679 if (attrib != (const RenderAttrib *)NULL) { 07680 const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib); 07681 if (!ta->is_off()) { 07682 Material *material = ta->get_material(); 07683 if (material != (Material *)NULL) { 07684 materials.insert(material); 07685 } 07686 } 07687 } 07688 } 07689 } 07690 07691 // Now consider children. 07692 PandaNode::Children cr = node->get_children(); 07693 int num_children = cr.get_num_children(); 07694 for (int i = 0; i < num_children; i++) { 07695 PandaNode *child = cr.get_child(i); 07696 CPT(RenderState) next_state = state->compose(child->get_state()); 07697 r_find_all_materials(child, next_state, materials); 07698 } 07699 } 07700 07701 #ifdef HAVE_PYTHON 07702 //////////////////////////////////////////////////////////////////// 07703 // Function: py_decode_NodePath_from_bam_stream 07704 // Access: Published 07705 // Description: This wrapper is defined as a global function to suit 07706 // pickle's needs. 07707 //////////////////////////////////////////////////////////////////// 07708 NodePath 07709 py_decode_NodePath_from_bam_stream(const string &data) { 07710 return py_decode_NodePath_from_bam_stream_persist(NULL, data); 07711 } 07712 #endif // HAVE_PYTHON 07713 07714 07715 #ifdef HAVE_PYTHON 07716 //////////////////////////////////////////////////////////////////// 07717 // Function: py_decode_NodePath_from_bam_stream_persist 07718 // Access: Published 07719 // Description: This wrapper is defined as a global function to suit 07720 // pickle's needs. 07721 //////////////////////////////////////////////////////////////////// 07722 NodePath 07723 py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &data) { 07724 BamReader *reader = NULL; 07725 if (unpickler != NULL) { 07726 PyObject *py_reader = PyObject_GetAttrString(unpickler, "bamReader"); 07727 if (py_reader == NULL) { 07728 // It's OK if there's no bamReader. 07729 PyErr_Clear(); 07730 } else { 07731 DTOOL_Call_ExtractThisPointerForType(py_reader, &Dtool_BamReader, (void **)&reader); 07732 Py_DECREF(py_reader); 07733 } 07734 } 07735 07736 return NodePath::decode_from_bam_stream(data, reader); 07737 } 07738 #endif // HAVE_PYTHON 07739