Panda3D
|
00001 // Filename: nodePath.cxx 00002 // Created by: drose (25Feb02) 00003 // Updated by: fperazzi, PandaSE (06Apr10) (added more overloads 00004 // for set_shader_input) 00005 // Updated by: weifengh, PandaSE(30Apr10) (added set_shader_auto) 00006 // 00007 //////////////////////////////////////////////////////////////////// 00008 // 00009 // PANDA 3D SOFTWARE 00010 // Copyright (c) Carnegie Mellon University. All rights reserved. 00011 // 00012 // All use of this software is subject to the terms of the revised BSD 00013 // license. You should have received a copy of this license along 00014 // with this source code in a file named "LICENSE." 00015 // 00016 //////////////////////////////////////////////////////////////////// 00017 00018 #include "nodePath.h" 00019 #include "nodePathCollection.h" 00020 #include "findApproxPath.h" 00021 #include "findApproxLevelEntry.h" 00022 #include "internalNameCollection.h" 00023 #include "config_pgraph.h" 00024 #include "colorAttrib.h" 00025 #include "colorScaleAttrib.h" 00026 #include "cullBinAttrib.h" 00027 #include "textureAttrib.h" 00028 #include "texMatrixAttrib.h" 00029 #include "texGenAttrib.h" 00030 #include "materialAttrib.h" 00031 #include "materialCollection.h" 00032 #include "lightAttrib.h" 00033 #include "clipPlaneAttrib.h" 00034 #include "occluderEffect.h" 00035 #include "polylightEffect.h" 00036 #include "fogAttrib.h" 00037 #include "renderModeAttrib.h" 00038 #include "cullFaceAttrib.h" 00039 #include "alphaTestAttrib.h" 00040 #include "depthTestAttrib.h" 00041 #include "depthWriteAttrib.h" 00042 #include "depthOffsetAttrib.h" 00043 #include "shaderAttrib.h" 00044 #include "billboardEffect.h" 00045 #include "compassEffect.h" 00046 #include "showBoundsEffect.h" 00047 #include "transparencyAttrib.h" 00048 #include "antialiasAttrib.h" 00049 #include "audioVolumeAttrib.h" 00050 #include "texProjectorEffect.h" 00051 #include "scissorEffect.h" 00052 #include "texturePool.h" 00053 #include "planeNode.h" 00054 #include "occluderNode.h" 00055 #include "lensNode.h" 00056 #include "materialPool.h" 00057 #include "look_at.h" 00058 #include "plist.h" 00059 #include "boundingSphere.h" 00060 #include "geomNode.h" 00061 #include "sceneGraphReducer.h" 00062 #include "textureCollection.h" 00063 #include "textureStageCollection.h" 00064 #include "globPattern.h" 00065 #include "shader.h" 00066 #include "shaderInput.h" 00067 #include "config_gobj.h" 00068 #include "bamFile.h" 00069 #include "preparedGraphicsObjects.h" 00070 #include "dcast.h" 00071 #include "pStatCollector.h" 00072 #include "pStatTimer.h" 00073 #include "modelNode.h" 00074 #include "py_panda.h" 00075 #include "bam.h" 00076 #include "bamWriter.h" 00077 00078 // stack seems to overflow on Intel C++ at 7000. If we need more than 00079 // 7000, need to increase stack size. 00080 int NodePath::_max_search_depth = 7000; 00081 TypeHandle NodePath::_type_handle; 00082 00083 PStatCollector NodePath::_get_transform_pcollector("*:NodePath:get_transform"); 00084 PStatCollector NodePath::_verify_complete_pcollector("*:NodePath:verify_complete"); 00085 00086 #ifdef HAVE_PYTHON 00087 #include "py_panda.h" 00088 #ifndef CPPPARSER 00089 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamWriter; 00090 extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_BamReader; 00091 #endif // CPPPARSER 00092 #endif // HAVE_PYTHON 00093 00094 // ***Begin temporary transition code for operator bool 00095 enum EmptyNodePathType { 00096 ENP_future, 00097 ENP_transition, 00098 ENP_deprecated, 00099 ENP_notify, 00100 }; 00101 00102 ostream &operator << (ostream &out, EmptyNodePathType enp) { 00103 switch (enp) { 00104 case ENP_future: 00105 return out << "future"; 00106 case ENP_transition: 00107 return out << "transition"; 00108 case ENP_deprecated: 00109 return out << "deprecated"; 00110 case ENP_notify: 00111 return out << "notify"; 00112 } 00113 return out << "**invalid EmptyNodePathType value (" << (int)enp << ")**"; 00114 } 00115 00116 istream &operator >> (istream &in, EmptyNodePathType &enp) { 00117 string word; 00118 in >> word; 00119 if (word == "future") { 00120 enp = ENP_future; 00121 } else if (word == "transition") { 00122 enp = ENP_transition; 00123 } else if (word == "deprecated") { 00124 enp = ENP_deprecated; 00125 } else if (word == "notify") { 00126 enp = ENP_notify; 00127 } else { 00128 pgraph_cat.warning() 00129 << "Invalid EmptyNodePathType value (\"" << word << "\")\n"; 00130 enp = ENP_transition; 00131 } 00132 return in; 00133 } 00134 00135 static ConfigVariableEnum<EmptyNodePathType> empty_node_path 00136 ("empty-node-path", ENP_future, 00137 PRC_DESC("This is a temporary transition variable to control the behavior " 00138 "of a NodePath when it is used as a boolean false. Set this to " 00139 "'deprecated' to preserve the original behavior: every NodePath " 00140 "evaluates true, even an empty NodePath. Set it to 'future' to " 00141 "support the new behavior: non-empty NodePaths evaluate true, " 00142 "and empty NodePaths evaluate false. Set it to 'transition' to " 00143 "raise an exception if an empty NodePath is used as a boolean.")); 00144 00145 // ***End temporary transition code for operator bool 00146 00147 00148 //////////////////////////////////////////////////////////////////// 00149 // Function: NodePath::Constructor 00150 // Access: Published 00151 // Description: Constructs a NodePath with the indicated parent 00152 // NodePath and child node; the child node must be a 00153 // stashed or unstashed child of the parent. 00154 //////////////////////////////////////////////////////////////////// 00155 NodePath:: 00156 NodePath(const NodePath &parent, PandaNode *child_node, 00157 Thread *current_thread) : 00158 _error_type(ET_fail) 00159 { 00160 nassertv(child_node != (PandaNode *)NULL); 00161 int pipeline_stage = current_thread->get_pipeline_stage(); 00162 00163 if (parent.is_empty()) { 00164 // Special case: constructing a NodePath at the root. 00165 _head = PandaNode::get_top_component(child_node, true, 00166 pipeline_stage, current_thread); 00167 00168 } else { 00169 _head = PandaNode::get_component(parent._head, child_node, pipeline_stage, 00170 current_thread); 00171 } 00172 nassertv(_head != (NodePathComponent *)NULL); 00173 00174 if (_head != (NodePathComponent *)NULL) { 00175 _error_type = ET_ok; 00176 } 00177 _backup_key = 0; 00178 } 00179 00180 #ifdef HAVE_PYTHON 00181 //////////////////////////////////////////////////////////////////// 00182 // Function: NodePath::__copy__ 00183 // Access: Published 00184 // Description: A special Python method that is invoked by 00185 // copy.copy(node). Unlike the NodePath copy 00186 // constructor, this makes a duplicate copy of the 00187 // underlying PandaNode (but shares children, instead of 00188 // copying them or omitting them). 00189 //////////////////////////////////////////////////////////////////// 00190 NodePath NodePath:: 00191 __copy__() const { 00192 if (is_empty()) { 00193 // Invoke the copy constructor if we have no node. 00194 return *this; 00195 } 00196 00197 // If we do have a node, duplicate it, and wrap it in a new 00198 // NodePath. 00199 return NodePath(node()->__copy__()); 00200 } 00201 #endif // HAVE_PYTHON 00202 00203 #ifdef HAVE_PYTHON 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: NodePath::__deepcopy__ 00206 // Access: Published 00207 // Description: A special Python method that is invoked by 00208 // copy.deepcopy(np). This calls copy_to() unless the 00209 // NodePath is already present in the provided 00210 // dictionary. 00211 //////////////////////////////////////////////////////////////////// 00212 PyObject *NodePath:: 00213 __deepcopy__(PyObject *self, PyObject *memo) const { 00214 IMPORT_THIS struct Dtool_PyTypedObject Dtool_NodePath; 00215 00216 // Borrowed reference. 00217 PyObject *dupe = PyDict_GetItem(memo, self); 00218 if (dupe != NULL) { 00219 // Already in the memo dictionary. 00220 Py_INCREF(dupe); 00221 return dupe; 00222 } 00223 00224 NodePath *np_dupe; 00225 if (is_empty()) { 00226 np_dupe = new NodePath(*this); 00227 } else { 00228 np_dupe = new NodePath(copy_to(NodePath())); 00229 } 00230 00231 dupe = DTool_CreatePyInstance((void *)np_dupe, Dtool_NodePath, 00232 true, false); 00233 if (PyDict_SetItem(memo, self, dupe) != 0) { 00234 Py_DECREF(dupe); 00235 return NULL; 00236 } 00237 00238 return dupe; 00239 } 00240 #endif // HAVE_PYTHON 00241 00242 #ifdef HAVE_PYTHON 00243 //////////////////////////////////////////////////////////////////// 00244 // Function: NodePath::__reduce__ 00245 // Access: Published 00246 // Description: This special Python method is implement to provide 00247 // support for the pickle module. 00248 // 00249 // This hooks into the native pickle and cPickle 00250 // modules, but it cannot properly handle 00251 // self-referential BAM objects. 00252 //////////////////////////////////////////////////////////////////// 00253 PyObject *NodePath:: 00254 __reduce__(PyObject *self) const { 00255 return __reduce_persist__(self, NULL); 00256 } 00257 #endif // HAVE_PYTHON 00258 00259 #ifdef HAVE_PYTHON 00260 //////////////////////////////////////////////////////////////////// 00261 // Function: NodePath::__reduce_persist__ 00262 // Access: Published 00263 // Description: This special Python method is implement to provide 00264 // support for the pickle module. 00265 // 00266 // This is similar to __reduce__, but it provides 00267 // additional support for the missing persistent-state 00268 // object needed to properly support self-referential 00269 // BAM objects written to the pickle stream. This hooks 00270 // into the pickle and cPickle modules implemented in 00271 // direct/src/stdpy. 00272 //////////////////////////////////////////////////////////////////// 00273 PyObject *NodePath:: 00274 __reduce_persist__(PyObject *self, PyObject *pickler) const { 00275 // We should return at least a 2-tuple, (Class, (args)): the 00276 // necessary class object whose constructor we should call 00277 // (e.g. this), and the arguments necessary to reconstruct this 00278 // object. 00279 00280 BamWriter *writer = NULL; 00281 if (pickler != NULL) { 00282 PyObject *py_writer = PyObject_GetAttrString(pickler, "bamWriter"); 00283 if (py_writer == NULL) { 00284 // It's OK if there's no bamWriter. 00285 PyErr_Clear(); 00286 } else { 00287 DTOOL_Call_ExtractThisPointerForType(py_writer, &Dtool_BamWriter, (void **)&writer); 00288 Py_DECREF(py_writer); 00289 } 00290 } 00291 00292 // We have a non-empty NodePath. 00293 00294 string bam_stream; 00295 if (!encode_to_bam_stream(bam_stream, writer)) { 00296 ostringstream stream; 00297 stream << "Could not bamify " << this; 00298 string message = stream.str(); 00299 PyErr_SetString(PyExc_TypeError, message.c_str()); 00300 return NULL; 00301 } 00302 00303 // Start by getting this class object. 00304 PyObject *this_class = PyObject_Type(self); 00305 if (this_class == NULL) { 00306 return NULL; 00307 } 00308 00309 PyObject *func; 00310 if (writer != NULL) { 00311 // The modified pickle support: call the "persistent" version of 00312 // this function, which receives the unpickler itself as an 00313 // additional parameter. 00314 func = TypedWritable::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream_persist"); 00315 if (func == NULL) { 00316 PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream_persist()"); 00317 Py_DECREF(this_class); 00318 return NULL; 00319 } 00320 00321 } else { 00322 // The traditional pickle support: call the non-persistent version 00323 // of this function. 00324 00325 func = TypedWritable::find_global_decode(this_class, "py_decode_NodePath_from_bam_stream"); 00326 if (func == NULL) { 00327 PyErr_SetString(PyExc_TypeError, "Couldn't find py_decode_NodePath_from_bam_stream()"); 00328 Py_DECREF(this_class); 00329 return NULL; 00330 } 00331 } 00332 00333 PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), bam_stream.size()); 00334 Py_DECREF(func); 00335 Py_DECREF(this_class); 00336 return result; 00337 } 00338 #endif // HAVE_PYTHON 00339 00340 //////////////////////////////////////////////////////////////////// 00341 // Function: NodePath::operator bool 00342 // Access: Published 00343 // Description: Returns true if the NodePath is valid (not empty), 00344 // or false if it contains no nodes. 00345 //////////////////////////////////////////////////////////////////// 00346 NodePath:: 00347 operator bool () const { 00348 switch (empty_node_path) { 00349 case ENP_future: 00350 return !is_empty(); 00351 00352 case ENP_deprecated: 00353 return true; 00354 00355 case ENP_notify: 00356 { 00357 const char *msg = "NodePath being used as a Boolean (talk to Zac)"; 00358 #ifdef HAVE_PYTHON 00359 PyErr_Warn(PyExc_FutureWarning, (char *)msg); 00360 #endif 00361 return !is_empty(); 00362 } 00363 00364 00365 case ENP_transition: 00366 if (!is_empty()) { 00367 return true; 00368 } 00369 00370 { 00371 const char *message = "Using an empty NodePath as a boolean value. Because the meaning of this operation is changing, you should avoid doing this to avoid ambiguity, or set the config variable empty-node-path to 'future' or 'deprecated' to specify the desired behavior."; 00372 pgraph_cat.warning() 00373 << message << "\n"; 00374 #ifdef HAVE_PYTHON 00375 PyErr_Warn(PyExc_FutureWarning, (char *)message); 00376 #endif 00377 } 00378 return true; 00379 } 00380 00381 nassertr(false, true); 00382 return true; 00383 } 00384 00385 //////////////////////////////////////////////////////////////////// 00386 // Function: NodePath::get_num_nodes 00387 // Access: Published 00388 // Description: Returns the number of nodes in the path. 00389 //////////////////////////////////////////////////////////////////// 00390 int NodePath:: 00391 get_num_nodes(Thread *current_thread) const { 00392 if (is_empty()) { 00393 return 0; 00394 } 00395 int pipeline_stage = current_thread->get_pipeline_stage(); 00396 return _head->get_length(pipeline_stage, current_thread); 00397 } 00398 00399 //////////////////////////////////////////////////////////////////// 00400 // Function: NodePath::get_node 00401 // Access: Published 00402 // Description: Returns the nth node of the path, where 0 is the 00403 // referenced (bottom) node and get_num_nodes() - 1 is 00404 // the top node. This requires iterating through the 00405 // path. 00406 // 00407 // Also see node(), which is a convenience function to 00408 // return the same thing as get_node(0) (since the 00409 // bottom node is the most important node in the 00410 // NodePath, and is the one most frequently referenced). 00411 // 00412 // Note that this function returns the same thing as 00413 // get_ancestor(index).node(). 00414 //////////////////////////////////////////////////////////////////// 00415 PandaNode *NodePath:: 00416 get_node(int index, Thread *current_thread) const { 00417 nassertr(index >= 0 && index < get_num_nodes(), NULL); 00418 00419 int pipeline_stage = current_thread->get_pipeline_stage(); 00420 00421 NodePathComponent *comp = _head; 00422 while (index > 0) { 00423 // If this assertion fails, the index was out of range; the 00424 // component's length must have been invalid. 00425 nassertr(comp != (NodePathComponent *)NULL, NULL); 00426 comp = comp->get_next(pipeline_stage, current_thread); 00427 index--; 00428 } 00429 00430 // If this assertion fails, the index was out of range; the 00431 // component's length must have been invalid. 00432 nassertr(comp != (NodePathComponent *)NULL, NULL); 00433 return comp->get_node(); 00434 } 00435 00436 //////////////////////////////////////////////////////////////////// 00437 // Function: NodePath::get_ancestor 00438 // Access: Published 00439 // Description: Returns the nth ancestor of the path, where 0 is the 00440 // NodePath itself and get_num_nodes() - 1 is get_top(). 00441 // This requires iterating through the path. 00442 // 00443 // Also see get_node(), which returns the same thing as 00444 // a PandaNode pointer, not a NodePath. 00445 //////////////////////////////////////////////////////////////////// 00446 NodePath NodePath:: 00447 get_ancestor(int index, Thread *current_thread) const { 00448 nassertr(index >= 0 && index < get_num_nodes(), NodePath::fail()); 00449 00450 int pipeline_stage = current_thread->get_pipeline_stage(); 00451 00452 NodePathComponent *comp = _head; 00453 while (index > 0) { 00454 // If this assertion fails, the index was out of range; the 00455 // component's length must have been invalid. 00456 nassertr(comp != (NodePathComponent *)NULL, NodePath::fail()); 00457 comp = comp->get_next(pipeline_stage, current_thread); 00458 index--; 00459 } 00460 00461 // If this assertion fails, the index was out of range; the 00462 // component's length must have been invalid. 00463 nassertr(comp != (NodePathComponent *)NULL, NodePath::fail()); 00464 00465 NodePath result; 00466 result._head = comp; 00467 return result; 00468 } 00469 00470 //////////////////////////////////////////////////////////////////// 00471 // Function: NodePath::get_top 00472 // Access: Published 00473 // Description: Returns a singleton NodePath that represents the top 00474 // of the path, or empty NodePath if this path is empty. 00475 //////////////////////////////////////////////////////////////////// 00476 NodePath NodePath:: 00477 get_top(Thread *current_thread) const { 00478 if (is_empty()) { 00479 return *this; 00480 } 00481 00482 int pipeline_stage = current_thread->get_pipeline_stage(); 00483 00484 NodePathComponent *comp = _head; 00485 while (!comp->is_top_node(pipeline_stage, current_thread)) { 00486 comp = comp->get_next(pipeline_stage, current_thread); 00487 nassertr(comp != (NodePathComponent *)NULL, NodePath::fail()); 00488 } 00489 00490 NodePath top; 00491 top._head = comp; 00492 return top; 00493 } 00494 00495 00496 //////////////////////////////////////////////////////////////////// 00497 // Function: NodePath::get_children 00498 // Access: Published 00499 // Description: Returns the set of all child nodes of the referenced 00500 // node. 00501 //////////////////////////////////////////////////////////////////// 00502 NodePathCollection NodePath:: 00503 get_children(Thread *current_thread) const { 00504 NodePathCollection result; 00505 nassertr_always(!is_empty(), result); 00506 00507 PandaNode *bottom_node = node(); 00508 00509 int pipeline_stage = current_thread->get_pipeline_stage(); 00510 00511 PandaNode::Children cr = bottom_node->get_children(); 00512 int num_children = cr.get_num_children(); 00513 for (int i = 0; i < num_children; i++) { 00514 NodePath child; 00515 child._head = PandaNode::get_component(_head, cr.get_child(i), 00516 pipeline_stage, current_thread); 00517 result.add_path(child); 00518 } 00519 00520 return result; 00521 } 00522 00523 //////////////////////////////////////////////////////////////////// 00524 // Function: NodePath::get_stashed_children 00525 // Access: Published 00526 // Description: Returns the set of all child nodes of the referenced 00527 // node that have been stashed. These children are not 00528 // normally visible on the node, and do not appear in 00529 // the list returned by get_children(). 00530 //////////////////////////////////////////////////////////////////// 00531 NodePathCollection NodePath:: 00532 get_stashed_children(Thread *current_thread) const { 00533 NodePathCollection result; 00534 nassertr_always(!is_empty(), result); 00535 00536 PandaNode *bottom_node = node(); 00537 00538 int pipeline_stage = current_thread->get_pipeline_stage(); 00539 00540 int num_stashed = bottom_node->get_num_stashed(); 00541 for (int i = 0; i < num_stashed; i++) { 00542 NodePath stashed; 00543 stashed._head = PandaNode::get_component(_head, bottom_node->get_stashed(i), 00544 pipeline_stage, current_thread); 00545 result.add_path(stashed); 00546 } 00547 00548 return result; 00549 } 00550 00551 //////////////////////////////////////////////////////////////////// 00552 // Function: NodePath::get_sort 00553 // Access: Published 00554 // Description: Returns the sort value of the referenced node within 00555 // its parent; that is, the sort number passed on the 00556 // last reparenting operation for this node. This will 00557 // control the position of the node within its parent's 00558 // list of children. 00559 //////////////////////////////////////////////////////////////////// 00560 int NodePath:: 00561 get_sort(Thread *current_thread) const { 00562 if (!has_parent()) { 00563 return 0; 00564 } 00565 00566 int pipeline_stage = current_thread->get_pipeline_stage(); 00567 00568 PandaNode *parent = _head->get_next(pipeline_stage, current_thread)->get_node(); 00569 PandaNode *child = node(); 00570 nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0); 00571 int child_index = parent->find_child(child); 00572 if (child_index != -1) { 00573 return parent->get_child_sort(child_index); 00574 } 00575 00576 child_index = parent->find_stashed(child); 00577 if (child_index != -1) { 00578 return parent->get_stashed_sort(child_index); 00579 } 00580 00581 nassertr(false, 0); 00582 return 0; 00583 } 00584 00585 //////////////////////////////////////////////////////////////////// 00586 // Function: NodePath::find 00587 // Access: Published 00588 // Description: Searches for a node below the referenced node that 00589 // matches the indicated string. Returns the shortest 00590 // match found, if any, or an empty NodePath if no match 00591 // can be found. 00592 //////////////////////////////////////////////////////////////////// 00593 NodePath NodePath:: 00594 find(const string &path) const { 00595 nassertr_always(!is_empty(), fail()); 00596 00597 NodePathCollection col; 00598 find_matches(col, path, 1); 00599 00600 if (col.is_empty()) { 00601 return NodePath::not_found(); 00602 } 00603 00604 return col.get_path(0); 00605 } 00606 00607 //////////////////////////////////////////////////////////////////// 00608 // Function: NodePath::find_path_to 00609 // Access: Published 00610 // Description: Searches for the indicated node below this node and 00611 // returns the shortest NodePath that connects them. 00612 //////////////////////////////////////////////////////////////////// 00613 NodePath NodePath:: 00614 find_path_to(PandaNode *node) const { 00615 nassertr_always(!is_empty(), fail()); 00616 nassertr(node != (PandaNode *)NULL, fail()); 00617 00618 NodePathCollection col; 00619 FindApproxPath approx_path; 00620 approx_path.add_match_many(0); 00621 approx_path.add_match_pointer(node, 0); 00622 find_matches(col, approx_path, 1); 00623 00624 if (col.is_empty()) { 00625 return NodePath::not_found(); 00626 } 00627 00628 return col.get_path(0); 00629 } 00630 00631 //////////////////////////////////////////////////////////////////// 00632 // Function: NodePath::find_all_matches 00633 // Access: Published 00634 // Description: Returns the complete set of all NodePaths that begin 00635 // with this NodePath and can be extended by 00636 // path. The shortest paths will be listed 00637 // first. 00638 //////////////////////////////////////////////////////////////////// 00639 NodePathCollection NodePath:: 00640 find_all_matches(const string &path) const { 00641 NodePathCollection col; 00642 nassertr_always(!is_empty(), col); 00643 nassertr(verify_complete(), col); 00644 find_matches(col, path, -1); 00645 return col; 00646 } 00647 00648 //////////////////////////////////////////////////////////////////// 00649 // Function: NodePath::find_all_paths_to 00650 // Access: Published 00651 // Description: Returns the set of all NodePaths that extend from 00652 // this NodePath down to the indicated node. The 00653 // shortest paths will be listed first. 00654 //////////////////////////////////////////////////////////////////// 00655 NodePathCollection NodePath:: 00656 find_all_paths_to(PandaNode *node) const { 00657 NodePathCollection col; 00658 nassertr_always(!is_empty(), col); 00659 nassertr(verify_complete(), col); 00660 nassertr(node != (PandaNode *)NULL, col); 00661 FindApproxPath approx_path; 00662 approx_path.add_match_many(0); 00663 approx_path.add_match_pointer(node, 0); 00664 find_matches(col, approx_path, -1); 00665 return col; 00666 } 00667 00668 //////////////////////////////////////////////////////////////////// 00669 // Function: NodePath::reparent_to 00670 // Access: Published 00671 // Description: Removes the referenced node of the NodePath from its 00672 // current parent and attaches it to the referenced node 00673 // of the indicated NodePath. 00674 // 00675 // If the destination NodePath is empty, this is the 00676 // same thing as detach_node(). 00677 // 00678 // If the referenced node is already a child of the 00679 // indicated NodePath (via some other instance), this 00680 // operation fails and leaves the NodePath detached. 00681 //////////////////////////////////////////////////////////////////// 00682 void NodePath:: 00683 reparent_to(const NodePath &other, int sort, Thread *current_thread) { 00684 nassertv(verify_complete()); 00685 nassertv(other.verify_complete()); 00686 nassertv_always(!is_empty()); 00687 nassertv(other._error_type == ET_ok); 00688 00689 // Reparenting implicitly resets the delta vector. 00690 node()->reset_prev_transform(); 00691 00692 int pipeline_stage = current_thread->get_pipeline_stage(); 00693 bool reparented = PandaNode::reparent(other._head, _head, sort, false, 00694 pipeline_stage, current_thread); 00695 nassertv(reparented); 00696 } 00697 00698 //////////////////////////////////////////////////////////////////// 00699 // Function: NodePath::stash_to 00700 // Access: Published 00701 // Description: Similar to reparent_to(), but the node is added to 00702 // its new parent's stashed list, so that the result is 00703 // equivalent to calling reparent_to() immediately 00704 // followed by stash(). 00705 //////////////////////////////////////////////////////////////////// 00706 void NodePath:: 00707 stash_to(const NodePath &other, int sort, Thread *current_thread) { 00708 nassertv(verify_complete()); 00709 nassertv(other.verify_complete()); 00710 nassertv_always(!is_empty()); 00711 nassertv(other._error_type == ET_ok); 00712 00713 // Reparenting implicitly resets the delta vector. 00714 node()->reset_prev_transform(); 00715 00716 int pipeline_stage = current_thread->get_pipeline_stage(); 00717 bool reparented = PandaNode::reparent(other._head, _head, sort, true, 00718 pipeline_stage, current_thread); 00719 nassertv(reparented); 00720 } 00721 00722 //////////////////////////////////////////////////////////////////// 00723 // Function: NodePath::wrt_reparent_to 00724 // Access: Published 00725 // Description: This functions identically to reparent_to(), except 00726 // the transform on this node is also adjusted so that 00727 // the node remains in the same place in world 00728 // coordinates, even if it is reparented into a 00729 // different coordinate system. 00730 //////////////////////////////////////////////////////////////////// 00731 void NodePath:: 00732 wrt_reparent_to(const NodePath &other, int sort, Thread *current_thread) { 00733 nassertv(verify_complete(current_thread)); 00734 nassertv(other.verify_complete(current_thread)); 00735 nassertv_always(!is_empty()); 00736 nassertv(other._error_type == ET_ok); 00737 00738 if (get_transform(current_thread) == get_prev_transform(current_thread)) { 00739 set_transform(get_transform(other, current_thread), current_thread); 00740 node()->reset_prev_transform(current_thread); 00741 } else { 00742 set_transform(get_transform(other, current_thread), current_thread); 00743 set_prev_transform(get_prev_transform(other, current_thread), current_thread); 00744 } 00745 00746 reparent_to(other, sort, current_thread); 00747 } 00748 00749 //////////////////////////////////////////////////////////////////// 00750 // Function: NodePath::instance_to 00751 // Access: Published 00752 // Description: Adds the referenced node of the NodePath as a child 00753 // of the referenced node of the indicated other 00754 // NodePath. Any other parent-child relations of the 00755 // node are unchanged; in particular, the node is not 00756 // removed from its existing parent, if any. 00757 // 00758 // If the node already had an existing parent, this 00759 // method will create a new instance of the node within 00760 // the scene graph. 00761 // 00762 // This does not change the NodePath itself, but does 00763 // return a new NodePath that reflects the new instance 00764 // node. 00765 // 00766 // If the destination NodePath is empty, this creates a 00767 // new instance which is not yet parented to any node. 00768 // A new instance of this sort cannot easily be 00769 // differentiated from other similar instances, but it 00770 // is nevertheless a different instance and it will 00771 // return a different get_id() value. 00772 // 00773 // If the referenced node is already a child of the 00774 // indicated NodePath, returns that already-existing 00775 // instance, unstashing it first if necessary. 00776 //////////////////////////////////////////////////////////////////// 00777 NodePath NodePath:: 00778 instance_to(const NodePath &other, int sort, Thread *current_thread) const { 00779 nassertr(verify_complete(), NodePath::fail()); 00780 nassertr(other.verify_complete(), NodePath::fail()); 00781 nassertr_always(!is_empty(), NodePath::fail()); 00782 nassertr(other._error_type == ET_ok, NodePath::fail()); 00783 00784 NodePath new_instance; 00785 00786 // First, we'll attach to NULL, to guarantee we get a brand new 00787 // instance. 00788 int pipeline_stage = current_thread->get_pipeline_stage(); 00789 new_instance._head = PandaNode::attach(NULL, node(), sort, pipeline_stage, 00790 current_thread); 00791 00792 // Now, we'll reparent the new instance to the target node. 00793 bool reparented = PandaNode::reparent(other._head, new_instance._head, 00794 sort, false, pipeline_stage, 00795 current_thread); 00796 if (!reparented) { 00797 // Hmm, couldn't reparent. Either making this instance would 00798 // create a cycle, or it was already a child of that node. If it 00799 // was already a child, return that existing NodePath instead. 00800 NodePath orig(other, node(), current_thread); 00801 if (!orig.is_empty()) { 00802 if (orig.is_stashed()) { 00803 orig.unstash(); 00804 } 00805 return orig; 00806 } 00807 00808 // Nope, it must be a cycle. 00809 nassertr(reparented, new_instance); 00810 } 00811 00812 // instance_to() doesn't reset the velocity delta, unlike most of 00813 // the other reparenting operations. The reasoning is that 00814 // instance_to() is not necessarily a reparenting operation, since 00815 // it doesn't change the original instance. 00816 00817 return new_instance; 00818 } 00819 00820 //////////////////////////////////////////////////////////////////// 00821 // Function: NodePath::instance_under_node 00822 // Access: Published 00823 // Description: Behaves like instance_to(), but implicitly creates a 00824 // new node to instance the geometry under, and returns a 00825 // NodePath to that new node. This allows the 00826 // programmer to set a unique state and/or transform on 00827 // this instance. 00828 //////////////////////////////////////////////////////////////////// 00829 NodePath NodePath:: 00830 instance_under_node(const NodePath &other, const string &name, int sort, 00831 Thread *current_thread) const { 00832 NodePath new_node = other.attach_new_node(name, sort, current_thread); 00833 NodePath instance = instance_to(new_node, 0, current_thread); 00834 if (instance.is_empty()) { 00835 new_node.remove_node(current_thread); 00836 return instance; 00837 } 00838 return new_node; 00839 } 00840 00841 //////////////////////////////////////////////////////////////////// 00842 // Function: NodePath::copy_to 00843 // Access: Published 00844 // Description: Functions like instance_to(), except a deep 00845 // copy is made of the referenced node and all of its 00846 // descendents, which is then parented to the indicated 00847 // node. A NodePath to the newly created copy is 00848 // returned. 00849 //////////////////////////////////////////////////////////////////// 00850 NodePath NodePath:: 00851 copy_to(const NodePath &other, int sort, Thread *current_thread) const { 00852 nassertr(verify_complete(current_thread), fail()); 00853 nassertr(other.verify_complete(current_thread), fail()); 00854 nassertr_always(!is_empty(), fail()); 00855 nassertr(other._error_type == ET_ok, fail()); 00856 00857 PandaNode *source_node = node(); 00858 PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread); 00859 nassertr(copy_node != (PandaNode *)NULL, fail()); 00860 00861 copy_node->reset_prev_transform(current_thread); 00862 00863 return other.attach_new_node(copy_node, sort, current_thread); 00864 } 00865 00866 //////////////////////////////////////////////////////////////////// 00867 // Function: NodePath::attach_new_node 00868 // Access: Published 00869 // Description: Attaches a new node, with or without existing 00870 // parents, to the scene graph below the referenced node 00871 // of this NodePath. This is the preferred way to add 00872 // nodes to the graph. 00873 // 00874 // If the node was already a child of the parent, this 00875 // returns a NodePath to the existing child. 00876 // 00877 // This does *not* automatically extend the current 00878 // NodePath to reflect the attachment; however, a 00879 // NodePath that does reflect this extension is 00880 // returned. 00881 //////////////////////////////////////////////////////////////////// 00882 NodePath NodePath:: 00883 attach_new_node(PandaNode *node, int sort, Thread *current_thread) const { 00884 nassertr(verify_complete(current_thread), NodePath::fail()); 00885 nassertr(_error_type == ET_ok, NodePath::fail()); 00886 nassertr(node != (PandaNode *)NULL, NodePath::fail()); 00887 00888 NodePath new_path(*this); 00889 int pipeline_stage = current_thread->get_pipeline_stage(); 00890 new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage, 00891 current_thread); 00892 return new_path; 00893 } 00894 00895 //////////////////////////////////////////////////////////////////// 00896 // Function: NodePath::remove_node 00897 // Access: Published 00898 // Description: Disconnects the referenced node from the scene graph. 00899 // This will also delete the node if there are no other 00900 // pointers to it. 00901 // 00902 // Normally, this should be called only when you are 00903 // really done with the node. If you want to remove a 00904 // node from the scene graph but keep it around for 00905 // later, you should probably use detach_node() instead. 00906 // 00907 // In practice, the only difference between 00908 // remove_node() and detach_node() is that remove_node() 00909 // also resets the NodePath to empty, which will cause 00910 // the node to be deleted immediately if there are no 00911 // other references. On the other hand, detach_node() 00912 // leaves the NodePath referencing the node, which will 00913 // keep at least one reference to the node for as long 00914 // as the NodePath exists. 00915 //////////////////////////////////////////////////////////////////// 00916 void NodePath:: 00917 remove_node(Thread *current_thread) { 00918 nassertv(_error_type != ET_not_found); 00919 00920 // If we have no parents, remove_node() is just a do-nothing 00921 // operation; if we have no nodes, maybe we were already removed. 00922 // In either case, quietly do nothing except to ensure the 00923 // NodePath is clear. 00924 if (!is_empty() && !is_singleton(current_thread)) { 00925 node()->reset_prev_transform(current_thread); 00926 int pipeline_stage = current_thread->get_pipeline_stage(); 00927 PandaNode::detach(_head, pipeline_stage, current_thread); 00928 } 00929 00930 if (is_empty() || _head->has_key()) { 00931 // Preserve the key we had on the node before we removed it. 00932 int key = get_key(); 00933 (*this) = NodePath::removed(); 00934 _backup_key = key; 00935 00936 } else { 00937 // We didn't have a key; just clear the NodePath. 00938 (*this) = NodePath::removed(); 00939 } 00940 } 00941 00942 //////////////////////////////////////////////////////////////////// 00943 // Function: NodePath::detach_node 00944 // Access: Published 00945 // Description: Disconnects the referenced node from its parent, but 00946 // does not immediately delete it. The NodePath retains 00947 // a pointer to the node, and becomes a singleton 00948 // NodePath. 00949 // 00950 // This should be called to detach a node from the scene 00951 // graph, with the option of reattaching it later to the 00952 // same parent or to a different parent. 00953 // 00954 // In practice, the only difference between 00955 // remove_node() and detach_node() is that remove_node() 00956 // also resets the NodePath to empty, which will cause 00957 // the node to be deleted immediately if there are no 00958 // other references. On the other hand, detach_node() 00959 // leaves the NodePath referencing the node, which will 00960 // keep at least one reference to the node for as long 00961 // as the NodePath exists. 00962 //////////////////////////////////////////////////////////////////// 00963 void NodePath:: 00964 detach_node(Thread *current_thread) { 00965 nassertv(_error_type != ET_not_found); 00966 if (!is_empty() && !is_singleton()) { 00967 node()->reset_prev_transform(); 00968 int pipeline_stage = current_thread->get_pipeline_stage(); 00969 PandaNode::detach(_head, pipeline_stage, current_thread); 00970 } 00971 } 00972 00973 //////////////////////////////////////////////////////////////////// 00974 // Function: NodePath::output 00975 // Access: Published 00976 // Description: Writes a sensible description of the NodePath to the 00977 // indicated output stream. 00978 //////////////////////////////////////////////////////////////////// 00979 void NodePath:: 00980 output(ostream &out) const { 00981 switch (_error_type) { 00982 case ET_not_found: 00983 out << "**not found**"; 00984 return; 00985 case ET_removed: 00986 out << "**removed**"; 00987 return; 00988 case ET_fail: 00989 out << "**error**"; 00990 return; 00991 default: 00992 break; 00993 } 00994 00995 if (_head == (NodePathComponent *)NULL) { 00996 out << "(empty)"; 00997 } else { 00998 _head->output(out); 00999 } 01000 } 01001 01002 //////////////////////////////////////////////////////////////////// 01003 // Function: NodePath::get_state 01004 // Access: Published 01005 // Description: Returns the complete state object set on this node. 01006 //////////////////////////////////////////////////////////////////// 01007 const RenderState *NodePath:: 01008 get_state(Thread *current_thread) const { 01009 // This method is declared non-inline to avoid a compiler bug in 01010 // gcc-3.4 and gcc-4.0. 01011 nassertr_always(!is_empty(), RenderState::make_empty()); 01012 return node()->get_state(current_thread); 01013 } 01014 01015 //////////////////////////////////////////////////////////////////// 01016 // Function: NodePath::get_state 01017 // Access: Published 01018 // Description: Returns the state changes that must be made to 01019 // transition to the render state of this node from the 01020 // render state of the other node. 01021 //////////////////////////////////////////////////////////////////// 01022 CPT(RenderState) NodePath:: 01023 get_state(const NodePath &other, Thread *current_thread) const { 01024 nassertr(_error_type == ET_ok && other._error_type == ET_ok, RenderState::make_empty()); 01025 01026 if (other.is_empty()) { 01027 return get_net_state(current_thread); 01028 } 01029 if (is_empty()) { 01030 return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty()); 01031 } 01032 01033 nassertr(verify_complete(current_thread), RenderState::make_empty()); 01034 nassertr(other.verify_complete(current_thread), RenderState::make_empty()); 01035 01036 int a_count, b_count; 01037 if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { 01038 if (allow_unrelated_wrt) { 01039 pgraph_cat.debug() 01040 << *this << " is not related to " << other << "\n"; 01041 } else { 01042 pgraph_cat.error() 01043 << *this << " is not related to " << other << "\n"; 01044 nassertr(false, RenderState::make_empty()); 01045 } 01046 } 01047 01048 CPT(RenderState) a_state = r_get_partial_state(_head, a_count, current_thread); 01049 CPT(RenderState) b_state = r_get_partial_state(other._head, b_count, current_thread); 01050 return b_state->invert_compose(a_state); 01051 } 01052 01053 //////////////////////////////////////////////////////////////////// 01054 // Function: NodePath::set_state 01055 // Access: Published 01056 // Description: Sets the state object on this node, relative to 01057 // the other node. This computes a new state object 01058 // that will have the indicated value when seen from the 01059 // other node. 01060 //////////////////////////////////////////////////////////////////// 01061 void NodePath:: 01062 set_state(const NodePath &other, const RenderState *state, 01063 Thread *current_thread) { 01064 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 01065 nassertv_always(!is_empty()); 01066 01067 // First, we perform a wrt to the parent, to get the conversion. 01068 CPT(RenderState) rel_state; 01069 if (has_parent()) { 01070 rel_state = other.get_state(get_parent(current_thread), current_thread); 01071 } else { 01072 rel_state = other.get_state(NodePath(), current_thread); 01073 } 01074 01075 CPT(RenderState) new_state = rel_state->compose(state); 01076 set_state(new_state, current_thread); 01077 } 01078 01079 //////////////////////////////////////////////////////////////////// 01080 // Function: NodePath::get_transform 01081 // Access: Published 01082 // Description: Returns the complete transform object set on this node. 01083 //////////////////////////////////////////////////////////////////// 01084 const TransformState *NodePath:: 01085 get_transform(Thread *current_thread) const { 01086 // This method is declared non-inline to avoid a compiler bug in 01087 // gcc-3.4 and gcc-4.0. 01088 nassertr_always(!is_empty(), TransformState::make_identity()); 01089 return node()->get_transform(current_thread); 01090 } 01091 01092 //////////////////////////////////////////////////////////////////// 01093 // Function: NodePath::get_transform 01094 // Access: Published 01095 // Description: Returns the relative transform to this node from the 01096 // other node; i.e. the transformation of this node 01097 // as seen from the other node. 01098 //////////////////////////////////////////////////////////////////// 01099 CPT(TransformState) NodePath:: 01100 get_transform(const NodePath &other, Thread *current_thread) const { 01101 nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity()); 01102 PStatTimer timer(_get_transform_pcollector); 01103 01104 if (other.is_empty()) { 01105 return get_net_transform(current_thread); 01106 } 01107 if (is_empty()) { 01108 return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity()); 01109 } 01110 01111 nassertr(verify_complete(current_thread), TransformState::make_identity()); 01112 nassertr(other.verify_complete(current_thread), TransformState::make_identity()); 01113 01114 int a_count, b_count; 01115 if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { 01116 if (allow_unrelated_wrt) { 01117 if (pgraph_cat.is_debug()) { 01118 pgraph_cat.debug() 01119 << *this << " is not related to " << other << "\n"; 01120 } 01121 } else { 01122 pgraph_cat.error() 01123 << *this << " is not related to " << other << "\n"; 01124 nassertr(false, TransformState::make_identity()); 01125 } 01126 } 01127 01128 CPT(TransformState) a_transform, b_transform; 01129 01130 a_transform = r_get_partial_transform(_head, a_count, current_thread); 01131 if (a_transform != (TransformState *)NULL) { 01132 b_transform = r_get_partial_transform(other._head, b_count, current_thread); 01133 } 01134 if (b_transform == (TransformState *)NULL) { 01135 // If either path involved a node with a net_transform 01136 // RenderEffect applied, we have to go all the way up to the root 01137 // to get the right answer. 01138 a_transform = r_get_net_transform(_head, current_thread); 01139 b_transform = r_get_net_transform(other._head, current_thread); 01140 } 01141 01142 return b_transform->invert_compose(a_transform); 01143 } 01144 01145 //////////////////////////////////////////////////////////////////// 01146 // Function: NodePath::set_transform 01147 // Access: Published 01148 // Description: Sets the transform object on this node, relative to 01149 // the other node. This computes a new transform object 01150 // that will have the indicated value when seen from the 01151 // other node. 01152 //////////////////////////////////////////////////////////////////// 01153 void NodePath:: 01154 set_transform(const NodePath &other, const TransformState *transform, 01155 Thread *current_thread) { 01156 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 01157 nassertv_always(!is_empty()); 01158 01159 // First, we perform a wrt to the parent, to get the conversion. 01160 CPT(TransformState) rel_trans; 01161 if (has_parent()) { 01162 rel_trans = other.get_transform(get_parent(current_thread), current_thread); 01163 } else { 01164 rel_trans = other.get_transform(NodePath(), current_thread); 01165 } 01166 01167 CPT(TransformState) new_trans = rel_trans->compose(transform); 01168 set_transform(new_trans, current_thread); 01169 } 01170 01171 //////////////////////////////////////////////////////////////////// 01172 // Function: NodePath::get_prev_transform 01173 // Access: Published 01174 // Description: Returns the transform that has been set as this 01175 // node's "previous" position. See 01176 // set_prev_transform(). 01177 //////////////////////////////////////////////////////////////////// 01178 const TransformState *NodePath:: 01179 get_prev_transform(Thread *current_thread) const { 01180 // This method is declared non-inline to avoid a compiler bug in 01181 // gcc-3.4 and gcc-4.0. 01182 nassertr_always(!is_empty(), TransformState::make_identity()); 01183 return node()->get_prev_transform(current_thread); 01184 } 01185 01186 //////////////////////////////////////////////////////////////////// 01187 // Function: NodePath::get_prev_transform 01188 // Access: Published 01189 // Description: Returns the relative "previous" transform to this 01190 // node from the other node; i.e. the position of this 01191 // node in the previous frame, as seen by the other node 01192 // in the previous frame. 01193 //////////////////////////////////////////////////////////////////// 01194 CPT(TransformState) NodePath:: 01195 get_prev_transform(const NodePath &other, Thread *current_thread) const { 01196 nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity()); 01197 01198 if (other.is_empty()) { 01199 return get_net_prev_transform(current_thread); 01200 } 01201 if (is_empty()) { 01202 return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity()); 01203 } 01204 01205 nassertr(verify_complete(current_thread), TransformState::make_identity()); 01206 nassertr(other.verify_complete(current_thread), TransformState::make_identity()); 01207 01208 int a_count, b_count; 01209 if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { 01210 if (allow_unrelated_wrt) { 01211 pgraph_cat.debug() 01212 << *this << " is not related to " << other << "\n"; 01213 } else { 01214 pgraph_cat.error() 01215 << *this << " is not related to " << other << "\n"; 01216 nassertr(false, TransformState::make_identity()); 01217 } 01218 } 01219 01220 CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count, current_thread); 01221 CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count, current_thread); 01222 return b_prev_transform->invert_compose(a_prev_transform); 01223 } 01224 01225 //////////////////////////////////////////////////////////////////// 01226 // Function: NodePath::set_prev_transform 01227 // Access: Published 01228 // Description: Sets the "previous" transform object on this node, 01229 // relative to the other node. This computes a new 01230 // transform object that will have the indicated value 01231 // when seen from the other node. 01232 //////////////////////////////////////////////////////////////////// 01233 void NodePath:: 01234 set_prev_transform(const NodePath &other, const TransformState *transform, 01235 Thread *current_thread) { 01236 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 01237 nassertv_always(!is_empty()); 01238 01239 // First, we perform a wrt to the parent, to get the conversion. 01240 CPT(TransformState) rel_trans; 01241 if (has_parent(current_thread)) { 01242 rel_trans = other.get_prev_transform(get_parent(current_thread), current_thread); 01243 } else { 01244 rel_trans = other.get_prev_transform(NodePath(), current_thread); 01245 } 01246 01247 CPT(TransformState) new_trans = rel_trans->compose(transform); 01248 set_prev_transform(new_trans, current_thread); 01249 } 01250 01251 //////////////////////////////////////////////////////////////////// 01252 // Function: NodePath::set_pos 01253 // Access: Published 01254 // Description: Sets the translation component of the transform, 01255 // leaving rotation and scale untouched. This also 01256 // resets the node's "previous" position, so that the 01257 // collision system will see the node as having suddenly 01258 // appeared in the new position, without passing any 01259 // points in between. 01260 // See Also: NodePath::set_fluid_pos 01261 //////////////////////////////////////////////////////////////////// 01262 void NodePath:: 01263 set_pos(const LVecBase3 &pos) { 01264 nassertv_always(!is_empty()); 01265 set_transform(get_transform()->set_pos(pos)); 01266 node()->reset_prev_transform(); 01267 } 01268 01269 void NodePath:: 01270 set_x(PN_stdfloat x) { 01271 nassertv_always(!is_empty()); 01272 LPoint3 pos = get_pos(); 01273 pos[0] = x; 01274 set_pos(pos); 01275 } 01276 01277 void NodePath:: 01278 set_y(PN_stdfloat y) { 01279 nassertv_always(!is_empty()); 01280 LPoint3 pos = get_pos(); 01281 pos[1] = y; 01282 set_pos(pos); 01283 } 01284 01285 void NodePath:: 01286 set_z(PN_stdfloat z) { 01287 nassertv_always(!is_empty()); 01288 LPoint3 pos = get_pos(); 01289 pos[2] = z; 01290 set_pos(pos); 01291 } 01292 01293 //////////////////////////////////////////////////////////////////// 01294 // Function: NodePath::set_fluid_pos 01295 // Access: Published 01296 // Description: Sets the translation component, without changing the 01297 // "previous" position, so that the collision system 01298 // will see the node as moving fluidly from its previous 01299 // position to its new position. 01300 // See Also: NodePath::set_pos 01301 //////////////////////////////////////////////////////////////////// 01302 void NodePath:: 01303 set_fluid_pos(const LVecBase3 &pos) { 01304 nassertv_always(!is_empty()); 01305 set_transform(get_transform()->set_pos(pos)); 01306 } 01307 01308 void NodePath:: 01309 set_fluid_x(PN_stdfloat x) { 01310 nassertv_always(!is_empty()); 01311 LPoint3 pos = get_pos(); 01312 pos[0] = x; 01313 set_fluid_pos(pos); 01314 } 01315 01316 void NodePath:: 01317 set_fluid_y(PN_stdfloat y) { 01318 nassertv_always(!is_empty()); 01319 LPoint3 pos = get_pos(); 01320 pos[1] = y; 01321 set_fluid_pos(pos); 01322 } 01323 01324 void NodePath:: 01325 set_fluid_z(PN_stdfloat z) { 01326 nassertv_always(!is_empty()); 01327 LPoint3 pos = get_pos(); 01328 pos[2] = z; 01329 set_fluid_pos(pos); 01330 } 01331 01332 //////////////////////////////////////////////////////////////////// 01333 // Function: NodePath::get_pos 01334 // Access: Published 01335 // Description: Retrieves the translation component of the transform. 01336 //////////////////////////////////////////////////////////////////// 01337 LPoint3 NodePath:: 01338 get_pos() const { 01339 nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f)); 01340 return get_transform()->get_pos(); 01341 } 01342 01343 //////////////////////////////////////////////////////////////////// 01344 // Function: NodePath::get_pos_delta 01345 // Access: Published 01346 // Description: Returns the delta vector from this node's position in 01347 // the previous frame (according to 01348 // set_prev_transform(), typically set via the use of 01349 // set_fluid_pos()) and its position in the current 01350 // frame. This is the vector used to determine 01351 // collisions. Generally, if the node was last 01352 // repositioned via set_pos(), the delta will be zero; 01353 // if it was adjusted via set_fluid_pos(), the delta 01354 // will represent the change from the previous frame's 01355 // position. 01356 //////////////////////////////////////////////////////////////////// 01357 LVector3 NodePath:: 01358 get_pos_delta() const { 01359 nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f)); 01360 return get_transform()->get_pos() - get_prev_transform()->get_pos(); 01361 } 01362 01363 //////////////////////////////////////////////////////////////////// 01364 // Function: NodePath::set_hpr 01365 // Access: Published 01366 // Description: Sets the rotation component of the transform, 01367 // leaving translation and scale untouched. 01368 //////////////////////////////////////////////////////////////////// 01369 void NodePath:: 01370 set_hpr(const LVecBase3 &hpr) { 01371 nassertv_always(!is_empty()); 01372 CPT(TransformState) transform = get_transform(); 01373 nassertv(transform->has_hpr()); 01374 set_transform(transform->set_hpr(hpr)); 01375 } 01376 01377 void NodePath:: 01378 set_h(PN_stdfloat h) { 01379 nassertv_always(!is_empty()); 01380 CPT(TransformState) transform = get_transform(); 01381 nassertv(transform->has_hpr()); 01382 LVecBase3 hpr = transform->get_hpr(); 01383 hpr[0] = h; 01384 set_transform(transform->set_hpr(hpr)); 01385 } 01386 01387 void NodePath:: 01388 set_p(PN_stdfloat p) { 01389 nassertv_always(!is_empty()); 01390 CPT(TransformState) transform = get_transform(); 01391 nassertv(transform->has_hpr()); 01392 LVecBase3 hpr = transform->get_hpr(); 01393 hpr[1] = p; 01394 set_transform(transform->set_hpr(hpr)); 01395 } 01396 01397 void NodePath:: 01398 set_r(PN_stdfloat r) { 01399 nassertv_always(!is_empty()); 01400 CPT(TransformState) transform = get_transform(); 01401 nassertv(transform->has_hpr()); 01402 LVecBase3 hpr = transform->get_hpr(); 01403 hpr[2] = r; 01404 set_transform(transform->set_hpr(hpr)); 01405 } 01406 01407 //////////////////////////////////////////////////////////////////// 01408 // Function: NodePath::get_hpr 01409 // Access: Published 01410 // Description: Retrieves the rotation component of the transform. 01411 //////////////////////////////////////////////////////////////////// 01412 LVecBase3 NodePath:: 01413 get_hpr() const { 01414 nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f)); 01415 CPT(TransformState) transform = get_transform(); 01416 nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f)); 01417 return transform->get_hpr(); 01418 } 01419 01420 //////////////////////////////////////////////////////////////////// 01421 // Function: NodePath::set_quat 01422 // Access: Published 01423 // Description: Sets the rotation component of the transform, 01424 // leaving translation and scale untouched. 01425 //////////////////////////////////////////////////////////////////// 01426 void NodePath:: 01427 set_quat(const LQuaternion &quat) { 01428 nassertv_always(!is_empty()); 01429 CPT(TransformState) transform = get_transform(); 01430 set_transform(transform->set_quat(quat)); 01431 } 01432 01433 //////////////////////////////////////////////////////////////////// 01434 // Function: NodePath::get_quat 01435 // Access: Published 01436 // Description: Retrieves the rotation component of the transform. 01437 //////////////////////////////////////////////////////////////////// 01438 LQuaternion NodePath:: 01439 get_quat() const { 01440 nassertr_always(!is_empty(), LQuaternion::ident_quat()); 01441 CPT(TransformState) transform = get_transform(); 01442 return transform->get_quat(); 01443 } 01444 01445 //////////////////////////////////////////////////////////////////// 01446 // Function: NodePath::set_scale 01447 // Access: Published 01448 // Description: Sets the scale component of the transform, 01449 // leaving translation and rotation untouched. 01450 //////////////////////////////////////////////////////////////////// 01451 void NodePath:: 01452 set_scale(const LVecBase3 &scale) { 01453 nassertv_always(!is_empty()); 01454 CPT(TransformState) transform = get_transform(); 01455 set_transform(transform->set_scale(scale)); 01456 } 01457 01458 void NodePath:: 01459 set_sx(PN_stdfloat sx) { 01460 nassertv_always(!is_empty()); 01461 CPT(TransformState) transform = get_transform(); 01462 LVecBase3 scale = transform->get_scale(); 01463 scale[0] = sx; 01464 set_transform(transform->set_scale(scale)); 01465 } 01466 01467 void NodePath:: 01468 set_sy(PN_stdfloat sy) { 01469 nassertv_always(!is_empty()); 01470 CPT(TransformState) transform = get_transform(); 01471 LVecBase3 scale = transform->get_scale(); 01472 scale[1] = sy; 01473 set_transform(transform->set_scale(scale)); 01474 } 01475 01476 void NodePath:: 01477 set_sz(PN_stdfloat sz) { 01478 nassertv_always(!is_empty()); 01479 CPT(TransformState) transform = get_transform(); 01480 LVecBase3 scale = transform->get_scale(); 01481 scale[2] = sz; 01482 set_transform(transform->set_scale(scale)); 01483 } 01484 01485 //////////////////////////////////////////////////////////////////// 01486 // Function: NodePath::get_scale 01487 // Access: Published 01488 // Description: Retrieves the scale component of the transform. 01489 //////////////////////////////////////////////////////////////////// 01490 LVecBase3 NodePath:: 01491 get_scale() const { 01492 nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f)); 01493 CPT(TransformState) transform = get_transform(); 01494 return transform->get_scale(); 01495 } 01496 01497 //////////////////////////////////////////////////////////////////// 01498 // Function: NodePath::set_shear 01499 // Access: Published 01500 // Description: Sets the shear component of the transform, 01501 // leaving translation and rotation untouched. 01502 //////////////////////////////////////////////////////////////////// 01503 void NodePath:: 01504 set_shear(const LVecBase3 &shear) { 01505 nassertv_always(!is_empty()); 01506 CPT(TransformState) transform = get_transform(); 01507 set_transform(transform->set_shear(shear)); 01508 } 01509 01510 void NodePath:: 01511 set_shxy(PN_stdfloat shxy) { 01512 nassertv_always(!is_empty()); 01513 CPT(TransformState) transform = get_transform(); 01514 LVecBase3 shear = transform->get_shear(); 01515 shear[0] = shxy; 01516 set_transform(transform->set_shear(shear)); 01517 } 01518 01519 void NodePath:: 01520 set_shxz(PN_stdfloat shxz) { 01521 nassertv_always(!is_empty()); 01522 CPT(TransformState) transform = get_transform(); 01523 LVecBase3 shear = transform->get_shear(); 01524 shear[1] = shxz; 01525 set_transform(transform->set_shear(shear)); 01526 } 01527 01528 void NodePath:: 01529 set_shyz(PN_stdfloat shyz) { 01530 nassertv_always(!is_empty()); 01531 CPT(TransformState) transform = get_transform(); 01532 LVecBase3 shear = transform->get_shear(); 01533 shear[2] = shyz; 01534 set_transform(transform->set_shear(shear)); 01535 } 01536 01537 //////////////////////////////////////////////////////////////////// 01538 // Function: NodePath::get_shear 01539 // Access: Published 01540 // Description: Retrieves the shear component of the transform. 01541 //////////////////////////////////////////////////////////////////// 01542 LVecBase3 NodePath:: 01543 get_shear() const { 01544 nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f)); 01545 CPT(TransformState) transform = get_transform(); 01546 return transform->get_shear(); 01547 } 01548 01549 //////////////////////////////////////////////////////////////////// 01550 // Function: NodePath::set_pos_hpr 01551 // Access: Published 01552 // Description: Sets the translation and rotation component of the 01553 // transform, leaving scale untouched. 01554 //////////////////////////////////////////////////////////////////// 01555 void NodePath:: 01556 set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr) { 01557 nassertv_always(!is_empty()); 01558 CPT(TransformState) transform = get_transform(); 01559 transform = TransformState::make_pos_hpr_scale_shear 01560 (pos, hpr, transform->get_scale(), transform->get_shear()); 01561 set_transform(transform); 01562 node()->reset_prev_transform(); 01563 } 01564 01565 //////////////////////////////////////////////////////////////////// 01566 // Function: NodePath::set_pos_quat 01567 // Access: Published 01568 // Description: Sets the translation and rotation component of the 01569 // transform, leaving scale untouched. 01570 //////////////////////////////////////////////////////////////////// 01571 void NodePath:: 01572 set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat) { 01573 nassertv_always(!is_empty()); 01574 CPT(TransformState) transform = get_transform(); 01575 transform = TransformState::make_pos_quat_scale_shear 01576 (pos, quat, transform->get_scale(), transform->get_shear()); 01577 set_transform(transform); 01578 node()->reset_prev_transform(); 01579 } 01580 01581 //////////////////////////////////////////////////////////////////// 01582 // Function: NodePath::set_hpr_scale 01583 // Access: Published 01584 // Description: Sets the rotation and scale components of the 01585 // transform, leaving translation untouched. 01586 //////////////////////////////////////////////////////////////////// 01587 void NodePath:: 01588 set_hpr_scale(const LVecBase3 &hpr, const LVecBase3 &scale) { 01589 nassertv_always(!is_empty()); 01590 CPT(TransformState) transform = get_transform(); 01591 transform = TransformState::make_pos_hpr_scale_shear 01592 (transform->get_pos(), hpr, scale, transform->get_shear()); 01593 set_transform(transform); 01594 } 01595 01596 //////////////////////////////////////////////////////////////////// 01597 // Function: NodePath::set_quat_scale 01598 // Access: Published 01599 // Description: Sets the rotation and scale components of the 01600 // transform, leaving translation untouched. 01601 //////////////////////////////////////////////////////////////////// 01602 void NodePath:: 01603 set_quat_scale(const LQuaternion &quat, const LVecBase3 &scale) { 01604 nassertv_always(!is_empty()); 01605 CPT(TransformState) transform = get_transform(); 01606 transform = TransformState::make_pos_quat_scale_shear 01607 (transform->get_pos(), quat, scale, transform->get_shear()); 01608 set_transform(transform); 01609 } 01610 01611 //////////////////////////////////////////////////////////////////// 01612 // Function: NodePath::set_pos_hpr_scale 01613 // Access: Published 01614 // Description: Replaces the translation, rotation, and scale 01615 // components, implicitly setting shear to 0. 01616 //////////////////////////////////////////////////////////////////// 01617 void NodePath:: 01618 set_pos_hpr_scale(const LVecBase3 &pos, const LVecBase3 &hpr, 01619 const LVecBase3 &scale) { 01620 nassertv_always(!is_empty()); 01621 set_transform(TransformState::make_pos_hpr_scale 01622 (pos, hpr, scale)); 01623 node()->reset_prev_transform(); 01624 } 01625 01626 //////////////////////////////////////////////////////////////////// 01627 // Function: NodePath::set_pos_quat_scale 01628 // Access: Published 01629 // Description: Replaces the translation, rotation, and scale 01630 // components, implicitly setting shear to 0. 01631 //////////////////////////////////////////////////////////////////// 01632 void NodePath:: 01633 set_pos_quat_scale(const LVecBase3 &pos, const LQuaternion &quat, 01634 const LVecBase3 &scale) { 01635 nassertv_always(!is_empty()); 01636 set_transform(TransformState::make_pos_quat_scale 01637 (pos, quat, scale)); 01638 node()->reset_prev_transform(); 01639 } 01640 01641 //////////////////////////////////////////////////////////////////// 01642 // Function: NodePath::set_pos_hpr_scale_shear 01643 // Access: Published 01644 // Description: Completely replaces the transform with new 01645 // translation, rotation, scale, and shear components. 01646 //////////////////////////////////////////////////////////////////// 01647 void NodePath:: 01648 set_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr, 01649 const LVecBase3 &scale, const LVecBase3 &shear) { 01650 nassertv_always(!is_empty()); 01651 set_transform(TransformState::make_pos_hpr_scale_shear 01652 (pos, hpr, scale, shear)); 01653 node()->reset_prev_transform(); 01654 } 01655 01656 //////////////////////////////////////////////////////////////////// 01657 // Function: NodePath::set_pos_quat_scale_shear 01658 // Access: Published 01659 // Description: Completely replaces the transform with new 01660 // translation, rotation, scale, and shear components. 01661 //////////////////////////////////////////////////////////////////// 01662 void NodePath:: 01663 set_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat, 01664 const LVecBase3 &scale, const LVecBase3 &shear) { 01665 nassertv_always(!is_empty()); 01666 set_transform(TransformState::make_pos_quat_scale_shear 01667 (pos, quat, scale, shear)); 01668 node()->reset_prev_transform(); 01669 } 01670 01671 //////////////////////////////////////////////////////////////////// 01672 // Function: NodePath::set_mat 01673 // Access: Published 01674 // Description: Directly sets an arbitrary 4x4 transform matrix. 01675 //////////////////////////////////////////////////////////////////// 01676 void NodePath:: 01677 set_mat(const LMatrix4 &mat) { 01678 nassertv_always(!is_empty()); 01679 set_transform(TransformState::make_mat(mat)); 01680 node()->reset_prev_transform(); 01681 } 01682 01683 //////////////////////////////////////////////////////////////////// 01684 // Function: NodePath::look_at 01685 // Access: Published 01686 // Description: Sets the hpr on this NodePath so that it 01687 // rotates to face the indicated point in space. 01688 //////////////////////////////////////////////////////////////////// 01689 void NodePath:: 01690 look_at(const LPoint3 &point, const LVector3 &up) { 01691 nassertv_always(!is_empty()); 01692 01693 LPoint3 pos = get_pos(); 01694 01695 LQuaternion quat; 01696 ::look_at(quat, point - pos, up); 01697 set_quat(quat); 01698 } 01699 01700 //////////////////////////////////////////////////////////////////// 01701 // Function: NodePath::heads_up 01702 // Access: Published 01703 // Description: Behaves like look_at(), but with a strong preference 01704 // to keeping the up vector oriented in the indicated 01705 // "up" direction. 01706 //////////////////////////////////////////////////////////////////// 01707 void NodePath:: 01708 heads_up(const LPoint3 &point, const LVector3 &up) { 01709 nassertv_always(!is_empty()); 01710 01711 LPoint3 pos = get_pos(); 01712 01713 LQuaternion quat; 01714 ::heads_up(quat, point - pos, up); 01715 set_quat(quat); 01716 } 01717 01718 //////////////////////////////////////////////////////////////////// 01719 // Function: NodePath::set_pos 01720 // Access: Published 01721 // Description: Sets the translation component of the transform, 01722 // relative to the other node. 01723 //////////////////////////////////////////////////////////////////// 01724 void NodePath:: 01725 set_pos(const NodePath &other, const LVecBase3 &pos) { 01726 nassertv_always(!is_empty()); 01727 CPT(TransformState) rel_transform = get_transform(other); 01728 01729 CPT(TransformState) orig_transform = get_transform(); 01730 if (orig_transform->has_components()) { 01731 // If we had a componentwise transform before we started, we 01732 // should be careful to preserve the other three components. We 01733 // wouldn't need to do this, except for the possibility of 01734 // numerical error or decompose ambiguity. 01735 const LVecBase3 &orig_hpr = orig_transform->get_hpr(); 01736 const LVecBase3 &orig_scale = orig_transform->get_scale(); 01737 const LVecBase3 &orig_shear = orig_transform->get_shear(); 01738 01739 set_transform(other, rel_transform->set_pos(pos)); 01740 set_pos_hpr_scale_shear(get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear); 01741 01742 } else { 01743 // If we didn't have a componentwise transform already, never 01744 // mind. 01745 set_transform(other, rel_transform->set_pos(pos)); 01746 } 01747 node()->reset_prev_transform(); 01748 } 01749 01750 void NodePath:: 01751 set_x(const NodePath &other, PN_stdfloat x) { 01752 nassertv_always(!is_empty()); 01753 LPoint3 pos = get_pos(other); 01754 pos[0] = x; 01755 set_pos(other, pos); 01756 } 01757 01758 void NodePath:: 01759 set_y(const NodePath &other, PN_stdfloat y) { 01760 nassertv_always(!is_empty()); 01761 LPoint3 pos = get_pos(other); 01762 pos[1] = y; 01763 set_pos(other, pos); 01764 } 01765 01766 void NodePath:: 01767 set_z(const NodePath &other, PN_stdfloat z) { 01768 nassertv_always(!is_empty()); 01769 LPoint3 pos = get_pos(other); 01770 pos[2] = z; 01771 set_pos(other, pos); 01772 } 01773 01774 //////////////////////////////////////////////////////////////////// 01775 // Function: NodePath::set_fluid_pos 01776 // Access: Published 01777 // Description: Sets the translation component of the transform, 01778 // relative to the other node. 01779 //////////////////////////////////////////////////////////////////// 01780 void NodePath:: 01781 set_fluid_pos(const NodePath &other, const LVecBase3 &pos) { 01782 nassertv_always(!is_empty()); 01783 CPT(TransformState) rel_transform = get_transform(other); 01784 01785 CPT(TransformState) orig_transform = get_transform(); 01786 if (orig_transform->has_components()) { 01787 // If we had a componentwise transform before we started, we 01788 // should be careful to preserve the other three components. We 01789 // wouldn't need to do this, except for the possibility of 01790 // numerical error or decompose ambiguity. 01791 const LVecBase3 &orig_hpr = orig_transform->get_hpr(); 01792 const LVecBase3 &orig_scale = orig_transform->get_scale(); 01793 const LVecBase3 &orig_shear = orig_transform->get_shear(); 01794 01795 // Use the relative set_transform() to compute the relative pos, and 01796 // then reset all of the other components back to the way they were. 01797 set_transform(other, rel_transform->set_pos(pos)); 01798 set_transform(TransformState::make_pos_hpr_scale_shear 01799 (get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear)); 01800 01801 } else { 01802 // If we didn't have a componentwise transform already, never 01803 // mind. 01804 set_transform(other, rel_transform->set_pos(pos)); 01805 } 01806 } 01807 01808 void NodePath:: 01809 set_fluid_x(const NodePath &other, PN_stdfloat x) { 01810 nassertv_always(!is_empty()); 01811 LPoint3 pos = get_pos(other); 01812 pos[0] = x; 01813 set_fluid_pos(other, pos); 01814 } 01815 01816 void NodePath:: 01817 set_fluid_y(const NodePath &other, PN_stdfloat y) { 01818 nassertv_always(!is_empty()); 01819 LPoint3 pos = get_pos(other); 01820 pos[1] = y; 01821 set_fluid_pos(other, pos); 01822 } 01823 01824 void NodePath:: 01825 set_fluid_z(const NodePath &other, PN_stdfloat z) { 01826 nassertv_always(!is_empty()); 01827 LPoint3 pos = get_pos(other); 01828 pos[2] = z; 01829 set_fluid_pos(other, pos); 01830 } 01831 01832 //////////////////////////////////////////////////////////////////// 01833 // Function: NodePath::get_pos 01834 // Access: Published 01835 // Description: Returns the relative position of the referenced node 01836 // as seen from the other node. 01837 //////////////////////////////////////////////////////////////////// 01838 LPoint3 NodePath:: 01839 get_pos(const NodePath &other) const { 01840 nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f)); 01841 return get_transform(other)->get_pos(); 01842 } 01843 01844 //////////////////////////////////////////////////////////////////// 01845 // Function: NodePath::get_pos_delta 01846 // Access: Published 01847 // Description: Returns the delta vector from this node's position in 01848 // the previous frame (according to 01849 // set_prev_transform(), typically set via the use of 01850 // set_fluid_pos()) and its position in the current 01851 // frame, as seen in the indicated node's coordinate 01852 // space. This is the vector used to determine 01853 // collisions. Generally, if the node was last 01854 // repositioned via set_pos(), the delta will be zero; 01855 // if it was adjusted via set_fluid_pos(), the delta 01856 // will represent the change from the previous frame's 01857 // position. 01858 //////////////////////////////////////////////////////////////////// 01859 LVector3 NodePath:: 01860 get_pos_delta(const NodePath &other) const { 01861 nassertr_always(!is_empty(), LPoint3(0.0f, 0.0f, 0.0f)); 01862 return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos(); 01863 } 01864 01865 //////////////////////////////////////////////////////////////////// 01866 // Function: NodePath::set_hpr 01867 // Access: Published 01868 // Description: Sets the rotation component of the transform, 01869 // relative to the other node. 01870 //////////////////////////////////////////////////////////////////// 01871 void NodePath:: 01872 set_hpr(const NodePath &other, const LVecBase3 &hpr) { 01873 nassertv_always(!is_empty()); 01874 CPT(TransformState) rel_transform = get_transform(other); 01875 nassertv(rel_transform->has_hpr()); 01876 01877 CPT(TransformState) orig_transform = get_transform(); 01878 if (orig_transform->has_components()) { 01879 // If we had a componentwise transform before we started, we 01880 // should be careful to preserve the other three components. We 01881 // wouldn't need to do this, except for the possibility of 01882 // numerical error or decompose ambiguity. 01883 const LVecBase3 &orig_pos = orig_transform->get_pos(); 01884 const LVecBase3 &orig_scale = orig_transform->get_scale(); 01885 const LVecBase3 &orig_shear = orig_transform->get_shear(); 01886 01887 set_transform(other, rel_transform->set_hpr(hpr)); 01888 const TransformState *new_transform = get_transform(); 01889 if (new_transform->has_components()) { 01890 set_transform(TransformState::make_pos_hpr_scale_shear 01891 (orig_pos, new_transform->get_hpr(), orig_scale, orig_shear)); 01892 } 01893 01894 } else { 01895 // If we didn't have a componentwise transform already, never 01896 // mind. 01897 set_transform(other, rel_transform->set_hpr(hpr)); 01898 } 01899 } 01900 01901 void NodePath:: 01902 set_h(const NodePath &other, PN_stdfloat h) { 01903 nassertv_always(!is_empty()); 01904 LVecBase3 hpr = get_hpr(other); 01905 hpr[0] = h; 01906 set_hpr(other, hpr); 01907 } 01908 01909 void NodePath:: 01910 set_p(const NodePath &other, PN_stdfloat p) { 01911 nassertv_always(!is_empty()); 01912 LVecBase3 hpr = get_hpr(other); 01913 hpr[1] = p; 01914 set_hpr(other, hpr); 01915 } 01916 01917 void NodePath:: 01918 set_r(const NodePath &other, PN_stdfloat r) { 01919 nassertv_always(!is_empty()); 01920 LVecBase3 hpr = get_hpr(other); 01921 hpr[2] = r; 01922 set_hpr(other, hpr); 01923 } 01924 01925 //////////////////////////////////////////////////////////////////// 01926 // Function: NodePath::get_hpr 01927 // Access: Published 01928 // Description: Returns the relative orientation of the bottom node 01929 // as seen from the other node. 01930 //////////////////////////////////////////////////////////////////// 01931 LVecBase3 NodePath:: 01932 get_hpr(const NodePath &other) const { 01933 nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f)); 01934 CPT(TransformState) transform = get_transform(other); 01935 nassertr(transform->has_hpr(), LVecBase3(0.0f, 0.0f, 0.0f)); 01936 return transform->get_hpr(); 01937 } 01938 01939 //////////////////////////////////////////////////////////////////// 01940 // Function: NodePath::set_quat 01941 // Access: Published 01942 // Description: Sets the rotation component of the transform, 01943 // relative to the other node. 01944 //////////////////////////////////////////////////////////////////// 01945 void NodePath:: 01946 set_quat(const NodePath &other, const LQuaternion &quat) { 01947 nassertv_always(!is_empty()); 01948 CPT(TransformState) rel_transform = get_transform(other); 01949 01950 CPT(TransformState) orig_transform = get_transform(); 01951 if (orig_transform->has_components()) { 01952 // If we had a componentwise transform before we started, we 01953 // should be careful to preserve the other three components. We 01954 // wouldn't need to do this, except for the possibility of 01955 // numerical error or decompose ambiguity. 01956 const LVecBase3 &orig_pos = orig_transform->get_pos(); 01957 const LVecBase3 &orig_scale = orig_transform->get_scale(); 01958 const LVecBase3 &orig_shear = orig_transform->get_shear(); 01959 01960 set_transform(other, rel_transform->set_quat(quat)); 01961 const TransformState *new_transform = get_transform(); 01962 if (new_transform->has_components()) { 01963 set_transform(TransformState::make_pos_quat_scale_shear 01964 (orig_pos, new_transform->get_quat(), orig_scale, orig_shear)); 01965 } 01966 01967 } else { 01968 // If we didn't have a componentwise transform already, never 01969 // mind. 01970 set_transform(other, rel_transform->set_quat(quat)); 01971 } 01972 } 01973 01974 //////////////////////////////////////////////////////////////////// 01975 // Function: NodePath::get_quat 01976 // Access: Published 01977 // Description: Returns the relative orientation of the bottom node 01978 // as seen from the other node. 01979 //////////////////////////////////////////////////////////////////// 01980 LQuaternion NodePath:: 01981 get_quat(const NodePath &other) const { 01982 nassertr_always(!is_empty(), LQuaternion::ident_quat()); 01983 CPT(TransformState) transform = get_transform(other); 01984 return transform->get_quat(); 01985 } 01986 01987 //////////////////////////////////////////////////////////////////// 01988 // Function: NodePath::set_scale 01989 // Access: Published 01990 // Description: Sets the scale component of the transform, 01991 // relative to the other node. 01992 //////////////////////////////////////////////////////////////////// 01993 void NodePath:: 01994 set_scale(const NodePath &other, const LVecBase3 &scale) { 01995 nassertv_always(!is_empty()); 01996 CPT(TransformState) rel_transform = get_transform(other); 01997 01998 CPT(TransformState) orig_transform = get_transform(); 01999 if (orig_transform->has_components()) { 02000 // If we had a componentwise transform before we started, we 02001 // should be careful to preserve the other three components. We 02002 // wouldn't need to do this, except for the possibility of 02003 // numerical error or decompose ambiguity. 02004 const LVecBase3 &orig_pos = orig_transform->get_pos(); 02005 const LVecBase3 &orig_hpr = orig_transform->get_hpr(); 02006 const LVecBase3 &orig_shear = orig_transform->get_shear(); 02007 02008 set_transform(other, rel_transform->set_scale(scale)); 02009 const TransformState *new_transform = get_transform(); 02010 if (new_transform->has_components()) { 02011 set_transform(TransformState::make_pos_hpr_scale_shear 02012 (orig_pos, orig_hpr, new_transform->get_scale(), orig_shear)); 02013 } 02014 02015 } else { 02016 // If we didn't have a componentwise transform already, never 02017 // mind. 02018 set_transform(other, rel_transform->set_scale(scale)); 02019 } 02020 } 02021 02022 void NodePath:: 02023 set_sx(const NodePath &other, PN_stdfloat sx) { 02024 nassertv_always(!is_empty()); 02025 LVecBase3 scale = get_scale(other); 02026 scale[0] = sx; 02027 set_scale(other, scale); 02028 } 02029 02030 void NodePath:: 02031 set_sy(const NodePath &other, PN_stdfloat sy) { 02032 nassertv_always(!is_empty()); 02033 LVecBase3 scale = get_scale(other); 02034 scale[1] = sy; 02035 set_scale(other, scale); 02036 } 02037 02038 void NodePath:: 02039 set_sz(const NodePath &other, PN_stdfloat sz) { 02040 nassertv_always(!is_empty()); 02041 LVecBase3 scale = get_scale(other); 02042 scale[2] = sz; 02043 set_scale(other, scale); 02044 } 02045 02046 //////////////////////////////////////////////////////////////////// 02047 // Function: NodePath::get_scale 02048 // Access: Published 02049 // Description: Returns the relative scale of the bottom node 02050 // as seen from the other node. 02051 //////////////////////////////////////////////////////////////////// 02052 LVecBase3 NodePath:: 02053 get_scale(const NodePath &other) const { 02054 nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f)); 02055 CPT(TransformState) transform = get_transform(other); 02056 return transform->get_scale(); 02057 } 02058 02059 //////////////////////////////////////////////////////////////////// 02060 // Function: NodePath::set_shear 02061 // Access: Published 02062 // Description: Sets the shear component of the transform, 02063 // relative to the other node. 02064 //////////////////////////////////////////////////////////////////// 02065 void NodePath:: 02066 set_shear(const NodePath &other, const LVecBase3 &shear) { 02067 nassertv_always(!is_empty()); 02068 CPT(TransformState) rel_transform = get_transform(other); 02069 02070 CPT(TransformState) orig_transform = get_transform(); 02071 if (orig_transform->has_components()) { 02072 // If we had a componentwise transform before we started, we 02073 // should be careful to preserve the other three components. We 02074 // wouldn't need to do this, except for the possibility of 02075 // numerical error or decompose ambiguity. 02076 const LVecBase3 &orig_pos = orig_transform->get_pos(); 02077 const LVecBase3 &orig_hpr = orig_transform->get_hpr(); 02078 const LVecBase3 &orig_scale = orig_transform->get_scale(); 02079 02080 set_transform(other, rel_transform->set_shear(shear)); 02081 const TransformState *new_transform = get_transform(); 02082 if (new_transform->has_components()) { 02083 set_transform(TransformState::make_pos_hpr_scale_shear 02084 (orig_pos, orig_hpr, orig_scale, new_transform->get_shear())); 02085 } 02086 02087 } else { 02088 // If we didn't have a componentwise transform already, never 02089 // mind. 02090 set_transform(other, rel_transform->set_shear(shear)); 02091 } 02092 } 02093 02094 void NodePath:: 02095 set_shxy(const NodePath &other, PN_stdfloat shxy) { 02096 nassertv_always(!is_empty()); 02097 LVecBase3 shear = get_shear(other); 02098 shear[0] = shxy; 02099 set_shear(other, shear); 02100 } 02101 02102 void NodePath:: 02103 set_shxz(const NodePath &other, PN_stdfloat shxz) { 02104 nassertv_always(!is_empty()); 02105 LVecBase3 shear = get_shear(other); 02106 shear[1] = shxz; 02107 set_shear(other, shear); 02108 } 02109 02110 void NodePath:: 02111 set_shyz(const NodePath &other, PN_stdfloat shyz) { 02112 nassertv_always(!is_empty()); 02113 LVecBase3 shear = get_shear(other); 02114 shear[2] = shyz; 02115 set_shear(other, shear); 02116 } 02117 02118 //////////////////////////////////////////////////////////////////// 02119 // Function: NodePath::get_shear 02120 // Access: Published 02121 // Description: Returns the relative shear of the bottom node 02122 // as seen from the other node. 02123 //////////////////////////////////////////////////////////////////// 02124 LVecBase3 NodePath:: 02125 get_shear(const NodePath &other) const { 02126 nassertr_always(!is_empty(), LVecBase3(0.0f, 0.0f, 0.0f)); 02127 CPT(TransformState) transform = get_transform(other); 02128 return transform->get_shear(); 02129 } 02130 02131 //////////////////////////////////////////////////////////////////// 02132 // Function: NodePath::set_pos_hpr 02133 // Access: Published 02134 // Description: Sets the translation and rotation component of the 02135 // transform, relative to the other node. 02136 //////////////////////////////////////////////////////////////////// 02137 void NodePath:: 02138 set_pos_hpr(const NodePath &other, const LVecBase3 &pos, 02139 const LVecBase3 &hpr) { 02140 nassertv_always(!is_empty()); 02141 CPT(TransformState) rel_transform = get_transform(other); 02142 02143 CPT(TransformState) orig_transform = get_transform(); 02144 if (orig_transform->has_components()) { 02145 // If we had a componentwise transform before we started, we 02146 // should be careful to preserve the other two components. We 02147 // wouldn't need to do this, except for the possibility of 02148 // numerical error or decompose ambiguity. 02149 const LVecBase3 &orig_scale = orig_transform->get_scale(); 02150 const LVecBase3 &orig_shear = orig_transform->get_shear(); 02151 02152 set_transform(other, TransformState::make_pos_hpr_scale_shear 02153 (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear())); 02154 const TransformState *new_transform = get_transform(); 02155 if (new_transform->has_components()) { 02156 set_pos_hpr_scale_shear(new_transform->get_pos(), new_transform->get_hpr(), 02157 orig_scale, orig_shear); 02158 } 02159 02160 } else { 02161 // If we didn't have a componentwise transform already, never 02162 // mind. 02163 set_transform(other, TransformState::make_pos_hpr_scale_shear 02164 (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear())); 02165 node()->reset_prev_transform(); 02166 } 02167 } 02168 02169 //////////////////////////////////////////////////////////////////// 02170 // Function: NodePath::set_pos_quat 02171 // Access: Published 02172 // Description: Sets the translation and rotation component of the 02173 // transform, relative to the other node. 02174 //////////////////////////////////////////////////////////////////// 02175 void NodePath:: 02176 set_pos_quat(const NodePath &other, const LVecBase3 &pos, 02177 const LQuaternion &quat) { 02178 nassertv_always(!is_empty()); 02179 CPT(TransformState) rel_transform = get_transform(other); 02180 02181 CPT(TransformState) orig_transform = get_transform(); 02182 if (orig_transform->has_components()) { 02183 // If we had a componentwise transform before we started, we 02184 // should be careful to preserve the other two components. We 02185 // wouldn't need to do this, except for the possibility of 02186 // numerical error or decompose ambiguity. 02187 const LVecBase3 &orig_scale = orig_transform->get_scale(); 02188 const LVecBase3 &orig_shear = orig_transform->get_shear(); 02189 02190 set_transform(other, TransformState::make_pos_quat_scale_shear 02191 (pos, quat, rel_transform->get_scale(), rel_transform->get_shear())); 02192 const TransformState *new_transform = get_transform(); 02193 if (new_transform->has_components()) { 02194 set_pos_quat_scale_shear(new_transform->get_pos(), new_transform->get_quat(), 02195 orig_scale, orig_shear); 02196 } 02197 02198 } else { 02199 // If we didn't have a componentwise transform already, never 02200 // mind. 02201 set_transform(other, TransformState::make_pos_quat_scale_shear 02202 (pos, quat, rel_transform->get_scale(), rel_transform->get_shear())); 02203 node()->reset_prev_transform(); 02204 } 02205 } 02206 02207 //////////////////////////////////////////////////////////////////// 02208 // Function: NodePath::set_hpr_scale 02209 // Access: Published 02210 // Description: Sets the rotation and scale components of the 02211 // transform, leaving translation untouched. This, or 02212 // set_pos_hpr_scale, is the preferred way to update a 02213 // transform when both hpr and scale are to be changed. 02214 //////////////////////////////////////////////////////////////////// 02215 void NodePath:: 02216 set_hpr_scale(const NodePath &other, const LVecBase3 &hpr, const LVecBase3 &scale) { 02217 // We don't bother trying very hard to preserve pos across this 02218 // operation, unlike the work we do above to preserve hpr or scale, 02219 // since it generally doesn't matter that much if pos is off by a 02220 // few thousandths. 02221 nassertv_always(!is_empty()); 02222 CPT(TransformState) transform = get_transform(other); 02223 transform = TransformState::make_pos_hpr_scale_shear 02224 (transform->get_pos(), hpr, scale, transform->get_shear()); 02225 set_transform(other, transform); 02226 } 02227 02228 //////////////////////////////////////////////////////////////////// 02229 // Function: NodePath::set_quat_scale 02230 // Access: Published 02231 // Description: Sets the rotation and scale components of the 02232 // transform, leaving translation untouched. This, or 02233 // set_pos_quat_scale, is the preferred way to update a 02234 // transform when both quat and scale are to be changed. 02235 //////////////////////////////////////////////////////////////////// 02236 void NodePath:: 02237 set_quat_scale(const NodePath &other, const LQuaternion &quat, 02238 const LVecBase3 &scale) { 02239 // We don't bother trying very hard to preserve pos across this 02240 // operation, unlike the work we do above to preserve quat or scale, 02241 // since it generally doesn't matter that much if pos is off by a 02242 // few thousandths. 02243 nassertv_always(!is_empty()); 02244 CPT(TransformState) transform = get_transform(other); 02245 transform = TransformState::make_pos_quat_scale_shear 02246 (transform->get_pos(), quat, scale, transform->get_shear()); 02247 set_transform(other, transform); 02248 } 02249 02250 //////////////////////////////////////////////////////////////////// 02251 // Function: NodePath::set_pos_hpr_scale 02252 // Access: Published 02253 // Description: Completely replaces the transform with new 02254 // translation, rotation, and scale components, relative 02255 // to the other node, implicitly setting shear to 0. 02256 //////////////////////////////////////////////////////////////////// 02257 void NodePath:: 02258 set_pos_hpr_scale(const NodePath &other, 02259 const LVecBase3 &pos, const LVecBase3 &hpr, 02260 const LVecBase3 &scale) { 02261 nassertv_always(!is_empty()); 02262 set_transform(other, TransformState::make_pos_hpr_scale 02263 (pos, hpr, scale)); 02264 node()->reset_prev_transform(); 02265 } 02266 02267 //////////////////////////////////////////////////////////////////// 02268 // Function: NodePath::set_pos_quat_scale 02269 // Access: Published 02270 // Description: Completely replaces the transform with new 02271 // translation, rotation, and scale components, relative 02272 // to the other node, implicitly setting shear to 0. 02273 //////////////////////////////////////////////////////////////////// 02274 void NodePath:: 02275 set_pos_quat_scale(const NodePath &other, 02276 const LVecBase3 &pos, const LQuaternion &quat, 02277 const LVecBase3 &scale) { 02278 nassertv_always(!is_empty()); 02279 set_transform(other, TransformState::make_pos_quat_scale 02280 (pos, quat, scale)); 02281 node()->reset_prev_transform(); 02282 } 02283 02284 //////////////////////////////////////////////////////////////////// 02285 // Function: NodePath::set_pos_hpr_scale_shear 02286 // Access: Published 02287 // Description: Completely replaces the transform with new 02288 // translation, rotation, scale, and shear components, 02289 // relative to the other node. 02290 //////////////////////////////////////////////////////////////////// 02291 void NodePath:: 02292 set_pos_hpr_scale_shear(const NodePath &other, 02293 const LVecBase3 &pos, const LVecBase3 &hpr, 02294 const LVecBase3 &scale, const LVecBase3 &shear) { 02295 nassertv_always(!is_empty()); 02296 set_transform(other, TransformState::make_pos_hpr_scale_shear 02297 (pos, hpr, scale, shear)); 02298 node()->reset_prev_transform(); 02299 } 02300 02301 //////////////////////////////////////////////////////////////////// 02302 // Function: NodePath::set_pos_quat_scale_shear 02303 // Access: Published 02304 // Description: Completely replaces the transform with new 02305 // translation, rotation, scale, and shear components, 02306 // relative to the other node. 02307 //////////////////////////////////////////////////////////////////// 02308 void NodePath:: 02309 set_pos_quat_scale_shear(const NodePath &other, 02310 const LVecBase3 &pos, const LQuaternion &quat, 02311 const LVecBase3 &scale, const LVecBase3 &shear) { 02312 nassertv_always(!is_empty()); 02313 set_transform(other, TransformState::make_pos_quat_scale_shear 02314 (pos, quat, scale, shear)); 02315 node()->reset_prev_transform(); 02316 } 02317 02318 //////////////////////////////////////////////////////////////////// 02319 // Function: NodePath::get_mat 02320 // Access: Published 02321 // Description: Returns the matrix that describes the coordinate 02322 // space of the bottom node, relative to the other 02323 // path's bottom node's coordinate space. 02324 //////////////////////////////////////////////////////////////////// 02325 LMatrix4 NodePath:: 02326 get_mat(const NodePath &other) const { 02327 CPT(TransformState) transform = get_transform(other); 02328 // We can't safely return a reference to the matrix, because we 02329 // can't assume the transform won't go away when the function 02330 // returns. If the transform was partially modified by, say, a 02331 // CompassEffect, it won't be stored in the cache, and thus we might 02332 // have the only reference to it. 02333 return transform->get_mat(); 02334 } 02335 02336 //////////////////////////////////////////////////////////////////// 02337 // Function: NodePath::set_mat 02338 // Access: Published 02339 // Description: Converts the indicated matrix from the other's 02340 // coordinate space to the local coordinate space, and 02341 // applies it to the node. 02342 //////////////////////////////////////////////////////////////////// 02343 void NodePath:: 02344 set_mat(const NodePath &other, const LMatrix4 &mat) { 02345 nassertv_always(!is_empty()); 02346 set_transform(other, TransformState::make_mat(mat)); 02347 node()->reset_prev_transform(); 02348 } 02349 02350 //////////////////////////////////////////////////////////////////// 02351 // Function: NodePath::get_relative_point 02352 // Access: Published 02353 // Description: Given that the indicated point is in the coordinate 02354 // system of the other node, returns the same point in 02355 // this node's coordinate system. 02356 //////////////////////////////////////////////////////////////////// 02357 LPoint3 NodePath:: 02358 get_relative_point(const NodePath &other, const LVecBase3 &point) const { 02359 CPT(TransformState) transform = other.get_transform(*this); 02360 LPoint3 rel_point = LPoint3(point) * transform->get_mat(); 02361 return rel_point; 02362 } 02363 02364 //////////////////////////////////////////////////////////////////// 02365 // Function: NodePath::get_relative_vector 02366 // Access: Published 02367 // Description: Given that the indicated vector is in the coordinate 02368 // system of the other node, returns the same vector in 02369 // this node's coordinate system. 02370 //////////////////////////////////////////////////////////////////// 02371 LVector3 NodePath:: 02372 get_relative_vector(const NodePath &other, const LVecBase3 &vec) const { 02373 CPT(TransformState) transform = other.get_transform(*this); 02374 LVector3 rel_vector = LVector3(vec) * transform->get_mat(); 02375 return rel_vector; 02376 } 02377 02378 //////////////////////////////////////////////////////////////////// 02379 // Function: NodePath::look_at 02380 // Access: Published 02381 // Description: Sets the transform on this NodePath so that it 02382 // rotates to face the indicated point in space, which 02383 // is relative to the other NodePath. 02384 //////////////////////////////////////////////////////////////////// 02385 void NodePath:: 02386 look_at(const NodePath &other, const LPoint3 &point, const LVector3 &up) { 02387 nassertv_always(!is_empty()); 02388 02389 CPT(TransformState) transform = other.get_transform(get_parent()); 02390 LPoint3 rel_point = point * transform->get_mat(); 02391 02392 LPoint3 pos = get_pos(); 02393 02394 LQuaternion quat; 02395 ::look_at(quat, rel_point - pos, up); 02396 set_quat(quat); 02397 } 02398 02399 //////////////////////////////////////////////////////////////////// 02400 // Function: NodePath::heads_up 02401 // Access: Published 02402 // Description: Behaves like look_at(), but with a strong preference 02403 // to keeping the up vector oriented in the indicated 02404 // "up" direction. 02405 //////////////////////////////////////////////////////////////////// 02406 void NodePath:: 02407 heads_up(const NodePath &other, const LPoint3 &point, const LVector3 &up) { 02408 nassertv_always(!is_empty()); 02409 02410 CPT(TransformState) transform = other.get_transform(get_parent()); 02411 LPoint3 rel_point = point * transform->get_mat(); 02412 02413 LPoint3 pos = get_pos(); 02414 02415 LQuaternion quat; 02416 ::heads_up(quat, rel_point - pos, up); 02417 set_quat(quat); 02418 } 02419 02420 02421 //////////////////////////////////////////////////////////////////// 02422 // Function: NodePath::set_color 02423 // Access: Published 02424 // Description: Applies a scene-graph color to the referenced node. 02425 // This color will apply to all geometry at this level 02426 // and below (that does not specify a new color or a 02427 // set_color_off()). 02428 //////////////////////////////////////////////////////////////////// 02429 void NodePath:: 02430 set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a, 02431 int priority) { 02432 set_color(LColor(r, g, b, a), priority); 02433 } 02434 02435 //////////////////////////////////////////////////////////////////// 02436 // Function: NodePath::set_color 02437 // Access: Published 02438 // Description: Applies a scene-graph color to the referenced node. 02439 // This color will apply to all geometry at this level 02440 // and below (that does not specify a new color or a 02441 // set_color_off()). 02442 //////////////////////////////////////////////////////////////////// 02443 void NodePath:: 02444 set_color(const LColor &color, int priority) { 02445 nassertv_always(!is_empty()); 02446 node()->set_attrib(ColorAttrib::make_flat(color), priority); 02447 } 02448 02449 //////////////////////////////////////////////////////////////////// 02450 // Function: NodePath::set_color_off 02451 // Access: Published 02452 // Description: Sets the geometry at this level and below to render 02453 // using the geometry color. This is normally the 02454 // default, but it may be useful to use this to 02455 // contradict set_color() at a higher node level (or, 02456 // with a priority, to override a set_color() at a lower 02457 // level). 02458 //////////////////////////////////////////////////////////////////// 02459 void NodePath:: 02460 set_color_off(int priority) { 02461 nassertv_always(!is_empty()); 02462 node()->set_attrib(ColorAttrib::make_vertex(), priority); 02463 } 02464 02465 //////////////////////////////////////////////////////////////////// 02466 // Function: NodePath::clear_color 02467 // Access: Published 02468 // Description: Completely removes any color adjustment from the node. 02469 // This allows the natural color of the geometry, or 02470 // whatever color transitions might be otherwise 02471 // affecting the geometry, to show instead. 02472 //////////////////////////////////////////////////////////////////// 02473 void NodePath:: 02474 clear_color() { 02475 nassertv_always(!is_empty()); 02476 node()->clear_attrib(ColorAttrib::get_class_slot()); 02477 } 02478 02479 //////////////////////////////////////////////////////////////////// 02480 // Function: NodePath::has_color 02481 // Access: Published 02482 // Description: Returns true if a color has been applied to the given 02483 // node, false otherwise. 02484 //////////////////////////////////////////////////////////////////// 02485 bool NodePath:: 02486 has_color() const { 02487 nassertr_always(!is_empty(), false); 02488 return node()->has_attrib(ColorAttrib::get_class_slot()); 02489 } 02490 02491 //////////////////////////////////////////////////////////////////// 02492 // Function: NodePath::get_color 02493 // Access: Published 02494 // Description: Returns the color that has been assigned to the node, 02495 // or black if no color has been assigned. 02496 //////////////////////////////////////////////////////////////////// 02497 LColor NodePath:: 02498 get_color() const { 02499 nassertr_always(!is_empty(), false); 02500 const RenderAttrib *attrib = 02501 node()->get_attrib(ColorAttrib::get_class_slot()); 02502 if (attrib != (const RenderAttrib *)NULL) { 02503 const ColorAttrib *ca = DCAST(ColorAttrib, attrib); 02504 if (ca->get_color_type() == ColorAttrib::T_flat) { 02505 return ca->get_color(); 02506 } 02507 } 02508 02509 pgraph_cat.warning() 02510 << "get_color() called on " << *this << " which has no color set.\n"; 02511 02512 return LColor(1.0f, 1.0f, 1.0f, 1.0f); 02513 } 02514 02515 //////////////////////////////////////////////////////////////////// 02516 // Function: NodePath::has_color_scale 02517 // Access: Published 02518 // Description: Returns true if a color scale has been applied 02519 // to the referenced node, false otherwise. It is still 02520 // possible that color at this node might have been 02521 // scaled by an ancestor node. 02522 //////////////////////////////////////////////////////////////////// 02523 bool NodePath:: 02524 has_color_scale() const { 02525 nassertr_always(!is_empty(), false); 02526 return node()->has_attrib(ColorScaleAttrib::get_class_slot()); 02527 } 02528 02529 //////////////////////////////////////////////////////////////////// 02530 // Function: NodePath::clear_color_scale 02531 // Access: Published 02532 // Description: Completely removes any color scale from the 02533 // referenced node. This is preferable to simply 02534 // setting the color scale to identity, as it also 02535 // removes the overhead associated with having a color 02536 // scale at all. 02537 //////////////////////////////////////////////////////////////////// 02538 void NodePath:: 02539 clear_color_scale() { 02540 nassertv_always(!is_empty()); 02541 node()->clear_attrib(ColorScaleAttrib::get_class_slot()); 02542 } 02543 02544 //////////////////////////////////////////////////////////////////// 02545 // Function: NodePath::compose_color_scale 02546 // Access: Published 02547 // Description: multiplies the color scale component of the transform, 02548 // with previous color scale leaving translation and 02549 // rotation untouched. 02550 //////////////////////////////////////////////////////////////////// 02551 void NodePath:: 02552 compose_color_scale(const LVecBase4 &scale, int priority) { 02553 nassertv_always(!is_empty()); 02554 02555 const RenderAttrib *attrib = 02556 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02557 if (attrib != (const RenderAttrib *)NULL) { 02558 priority = max(priority, 02559 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02560 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02561 02562 // Modify the existing ColorScaleAttrib by multiplying with the 02563 // indicated colorScale. 02564 LVecBase4 prev_color_scale = csa->get_scale(); 02565 LVecBase4 new_color_scale(prev_color_scale[0]*scale[0], 02566 prev_color_scale[1]*scale[1], 02567 prev_color_scale[2]*scale[2], 02568 prev_color_scale[3]*scale[3]); 02569 node()->set_attrib(csa->set_scale(new_color_scale), priority); 02570 02571 } else { 02572 // Create a new ColorScaleAttrib for this node. 02573 node()->set_attrib(ColorScaleAttrib::make(scale), priority); 02574 } 02575 } 02576 02577 //////////////////////////////////////////////////////////////////// 02578 // Function: NodePath::set_color_scale 02579 // Access: Published 02580 // Description: Sets the color scale component of the transform, 02581 // leaving translation and rotation untouched. 02582 //////////////////////////////////////////////////////////////////// 02583 void NodePath:: 02584 set_color_scale(const LVecBase4 &scale, int priority) { 02585 nassertv_always(!is_empty()); 02586 02587 const RenderAttrib *attrib = 02588 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02589 if (attrib != (const RenderAttrib *)NULL) { 02590 priority = max(priority, 02591 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02592 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02593 02594 // Modify the existing ColorScaleAttrib to add the indicated 02595 // colorScale. 02596 node()->set_attrib(csa->set_scale(scale), priority); 02597 02598 } else { 02599 // Create a new ColorScaleAttrib for this node. 02600 node()->set_attrib(ColorScaleAttrib::make(scale), priority); 02601 } 02602 } 02603 02604 //////////////////////////////////////////////////////////////////// 02605 // Function: NodePath::set_color_scale_off 02606 // Access: Published 02607 // Description: Disables any color scale attribute inherited from 02608 // above. This is not the same thing as 02609 // clear_color_scale(), which undoes any previous 02610 // set_color_scale() operation on this node; rather, 02611 // this actively disables any set_color_scale() that 02612 // might be inherited from a parent node. This also 02613 // disables set_alpha_scale() at the same time. 02614 // 02615 // It is legal to specify a new color scale on the same 02616 // node with a subsequent call to set_color_scale() or 02617 // set_alpha_scale(); this new scale will apply to lower 02618 // geometry. 02619 //////////////////////////////////////////////////////////////////// 02620 void NodePath:: 02621 set_color_scale_off(int priority) { 02622 nassertv_always(!is_empty()); 02623 node()->set_attrib(ColorScaleAttrib::make_off(), priority); 02624 } 02625 02626 //////////////////////////////////////////////////////////////////// 02627 // Function: NodePath::set_alpha_scale 02628 // Access: Published 02629 // Description: Sets the alpha scale component of the transform 02630 // without (much) affecting the color scale. Note that 02631 // any priority specified will also apply to the color 02632 // scale. 02633 //////////////////////////////////////////////////////////////////// 02634 void NodePath:: 02635 set_alpha_scale(PN_stdfloat scale, int priority) { 02636 nassertv_always(!is_empty()); 02637 02638 const RenderAttrib *attrib = 02639 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02640 if (attrib != (const RenderAttrib *)NULL) { 02641 priority = max(priority, 02642 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02643 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02644 02645 // Modify the existing ColorScaleAttrib to add the indicated 02646 // colorScale. 02647 const LVecBase4 &sc = csa->get_scale(); 02648 node()->set_attrib(csa->set_scale(LVecBase4(sc[0], sc[1], sc[2], scale)), priority); 02649 02650 } else { 02651 // Create a new ColorScaleAttrib for this node. 02652 node()->set_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, scale)), priority); 02653 } 02654 } 02655 02656 //////////////////////////////////////////////////////////////////// 02657 // Function: NodePath::set_all_color_scale 02658 // Access: Published 02659 // Description: Scales all the color components of the object by the 02660 // same amount, darkening the object, without (much) 02661 // affecting alpha. Note that any priority specified 02662 // will also apply to the alpha scale. 02663 //////////////////////////////////////////////////////////////////// 02664 void NodePath:: 02665 set_all_color_scale(PN_stdfloat scale, int priority) { 02666 nassertv_always(!is_empty()); 02667 02668 const RenderAttrib *attrib = 02669 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02670 if (attrib != (const RenderAttrib *)NULL) { 02671 priority = max(priority, 02672 node()->get_state()->get_override(ColorScaleAttrib::get_class_slot())); 02673 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02674 02675 // Modify the existing ColorScaleAttrib to add the indicated 02676 // colorScale. 02677 const LVecBase4 &sc = csa->get_scale(); 02678 node()->set_attrib(csa->set_scale(LVecBase4(scale, scale, scale, sc[3])), priority); 02679 02680 } else { 02681 // Create a new ColorScaleAttrib for this node. 02682 node()->set_attrib(ColorScaleAttrib::make(LVecBase4(scale, scale, scale, 1.0f)), priority); 02683 } 02684 } 02685 02686 //////////////////////////////////////////////////////////////////// 02687 // Function: NodePath::get_color_scale 02688 // Access: Published 02689 // Description: Returns the complete color scale vector that has been 02690 // applied to this node via a previous call to 02691 // set_color_scale() and/or set_alpha_scale(), or all 02692 // 1's (identity) if no scale has been applied to this 02693 // particular node. 02694 //////////////////////////////////////////////////////////////////// 02695 const LVecBase4 &NodePath:: 02696 get_color_scale() const { 02697 static const LVecBase4 ident_scale(1.0f, 1.0f, 1.0f, 1.0f); 02698 nassertr_always(!is_empty(), ident_scale); 02699 const RenderAttrib *attrib = 02700 node()->get_attrib(ColorScaleAttrib::get_class_slot()); 02701 if (attrib != (const RenderAttrib *)NULL) { 02702 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib); 02703 return csa->get_scale(); 02704 } 02705 02706 return ident_scale; 02707 } 02708 02709 //////////////////////////////////////////////////////////////////// 02710 // Function: NodePath::set_light 02711 // Access: Published 02712 // Description: Adds the indicated Light or PolylightNode to the list 02713 // of lights that illuminate geometry at this node and 02714 // below. The light itself should be parented into the 02715 // scene graph elsewhere, to represent the light's 02716 // position in space; but until set_light() is called it 02717 // will illuminate no geometry. 02718 //////////////////////////////////////////////////////////////////// 02719 void NodePath:: 02720 set_light(const NodePath &light, int priority) { 02721 nassertv_always(!is_empty()); 02722 if (!light.is_empty()) { 02723 Light *light_obj = light.node()->as_light(); 02724 if (light_obj != (Light *)NULL) { 02725 // It's an actual Light object. 02726 const RenderAttrib *attrib = 02727 node()->get_attrib(LightAttrib::get_class_slot()); 02728 if (attrib != (const RenderAttrib *)NULL) { 02729 priority = max(priority, 02730 node()->get_state()->get_override(LightAttrib::get_class_slot())); 02731 const LightAttrib *la = DCAST(LightAttrib, attrib); 02732 02733 // Modify the existing LightAttrib to add the indicated 02734 // light. 02735 node()->set_attrib(la->add_on_light(light), priority); 02736 02737 } else { 02738 // Create a new LightAttrib for this node. 02739 CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make()); 02740 node()->set_attrib(la->add_on_light(light), priority); 02741 } 02742 return; 02743 02744 } else if (light.node()->is_of_type(PolylightNode::get_class_type())) { 02745 // It's a Polylight object. 02746 if (priority != 0) { 02747 // PolylightEffects can't have a priority, since they're just 02748 // an effect to be applied immediately. 02749 pgraph_cat.warning() 02750 << "Ignoring priority on set_light(" << light << ")\n"; 02751 } 02752 02753 const RenderEffect *effect = 02754 node()->get_effect(PolylightEffect::get_class_type()); 02755 if (effect != (const RenderEffect *)NULL) { 02756 const PolylightEffect *ple = DCAST(PolylightEffect, effect); 02757 02758 // Modify the existing PolylightEffect to add the indicated 02759 // light. 02760 node()->set_effect(ple->add_light(light)); 02761 02762 } else { 02763 // Create a new PolylightEffect for this node. 02764 CPT(PolylightEffect) ple = DCAST(PolylightEffect, PolylightEffect::make()); 02765 node()->set_effect(ple->add_light(light)); 02766 } 02767 return; 02768 } 02769 } 02770 nassert_raise("Not a Light object."); 02771 } 02772 02773 //////////////////////////////////////////////////////////////////// 02774 // Function: NodePath::set_light_off 02775 // Access: Published 02776 // Description: Sets the geometry at this level and below to render 02777 // using no lights at all. This is different 02778 // from not specifying a light; rather, this 02779 // specifically contradicts set_light() at a higher 02780 // node level (or, with a priority, overrides a 02781 // set_light() at a lower level). 02782 // 02783 // If no lights are in effect on a particular piece of 02784 // geometry, that geometry is rendered with lighting 02785 // disabled. 02786 //////////////////////////////////////////////////////////////////// 02787 void NodePath:: 02788 set_light_off(int priority) { 02789 nassertv_always(!is_empty()); 02790 node()->set_attrib(LightAttrib::make_all_off(), priority); 02791 node()->clear_effect(PolylightEffect::get_class_type()); 02792 } 02793 02794 //////////////////////////////////////////////////////////////////// 02795 // Function: NodePath::set_light_off 02796 // Access: Published 02797 // Description: Sets the geometry at this level and below to render 02798 // without using the indicated Light. This is different 02799 // from not specifying the Light; rather, this 02800 // specifically contradicts set_light() at a higher node 02801 // level (or, with a priority, overrides a set_light() 02802 // at a lower level). 02803 // 02804 // This interface does not support PolylightNodes, which 02805 // cannot be turned off at a lower level. 02806 //////////////////////////////////////////////////////////////////// 02807 void NodePath:: 02808 set_light_off(const NodePath &light, int priority) { 02809 nassertv_always(!is_empty()); 02810 02811 if (!light.is_empty()) { 02812 Light *light_obj = light.node()->as_light(); 02813 if (light_obj != (Light *)NULL) { 02814 const RenderAttrib *attrib = 02815 node()->get_attrib(LightAttrib::get_class_slot()); 02816 if (attrib != (const RenderAttrib *)NULL) { 02817 priority = max(priority, 02818 node()->get_state()->get_override(LightAttrib::get_class_slot())); 02819 const LightAttrib *la = DCAST(LightAttrib, attrib); 02820 02821 // Modify the existing LightAttrib to add the indicated light 02822 // to the "off" list. This also, incidentally, removes it from 02823 // the "on" list if it is there. 02824 node()->set_attrib(la->add_off_light(light), priority); 02825 02826 } else { 02827 // Create a new LightAttrib for this node that turns off the 02828 // indicated light. 02829 CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make()); 02830 node()->set_attrib(la->add_off_light(light), priority); 02831 } 02832 return; 02833 } 02834 } 02835 nassert_raise("Not a Light object."); 02836 } 02837 02838 //////////////////////////////////////////////////////////////////// 02839 // Function: NodePath::clear_light 02840 // Access: Published 02841 // Description: Completely removes any lighting operations that may 02842 // have been set via set_light() or set_light_off() 02843 // from this particular node. 02844 //////////////////////////////////////////////////////////////////// 02845 void NodePath:: 02846 clear_light() { 02847 nassertv_always(!is_empty()); 02848 node()->clear_attrib(LightAttrib::get_class_slot()); 02849 node()->clear_effect(PolylightEffect::get_class_type()); 02850 } 02851 02852 //////////////////////////////////////////////////////////////////// 02853 // Function: NodePath::clear_light 02854 // Access: Published 02855 // Description: Removes any reference to the indicated Light or 02856 // PolylightNode from the NodePath. 02857 //////////////////////////////////////////////////////////////////// 02858 void NodePath:: 02859 clear_light(const NodePath &light) { 02860 nassertv_always(!is_empty()); 02861 02862 if (!light.is_empty()) { 02863 Light *light_obj = light.node()->as_light(); 02864 if (light_obj != (Light *)NULL) { 02865 const RenderAttrib *attrib = 02866 node()->get_attrib(LightAttrib::get_class_slot()); 02867 if (attrib != (const RenderAttrib *)NULL) { 02868 CPT(LightAttrib) la = DCAST(LightAttrib, attrib); 02869 la = DCAST(LightAttrib, la->remove_on_light(light)); 02870 la = DCAST(LightAttrib, la->remove_off_light(light)); 02871 02872 if (la->is_identity()) { 02873 node()->clear_attrib(LightAttrib::get_class_slot()); 02874 02875 } else { 02876 int priority = node()->get_state()->get_override(LightAttrib::get_class_slot()); 02877 node()->set_attrib(la, priority); 02878 } 02879 } 02880 return; 02881 02882 } else if (light.node()->is_of_type(PolylightNode::get_class_type())) { 02883 const RenderEffect *effect = 02884 node()->get_effect(PolylightEffect::get_class_type()); 02885 if (effect != (const RenderEffect *)NULL) { 02886 CPT(PolylightEffect) ple = DCAST(PolylightEffect, effect); 02887 ple = DCAST(PolylightEffect, ple->remove_light(light)); 02888 node()->set_effect(ple); 02889 } 02890 return; 02891 } 02892 } 02893 nassert_raise("Not a Light object."); 02894 } 02895 02896 //////////////////////////////////////////////////////////////////// 02897 // Function: NodePath::has_light 02898 // Access: Published 02899 // Description: Returns true if the indicated Light or PolylightNode 02900 // has been specifically enabled on this particular 02901 // node. This means that someone called set_light() on 02902 // this node with the indicated light. 02903 //////////////////////////////////////////////////////////////////// 02904 bool NodePath:: 02905 has_light(const NodePath &light) const { 02906 nassertr_always(!is_empty(), false); 02907 02908 if (!light.is_empty()) { 02909 Light *light_obj = light.node()->as_light(); 02910 if (light_obj != (Light *)NULL) { 02911 const RenderAttrib *attrib = 02912 node()->get_attrib(LightAttrib::get_class_slot()); 02913 if (attrib != (const RenderAttrib *)NULL) { 02914 const LightAttrib *la = DCAST(LightAttrib, attrib); 02915 return la->has_on_light(light); 02916 } 02917 return false; 02918 02919 } else if (light.node()->is_of_type(PolylightNode::get_class_type())) { 02920 const RenderEffect *effect = 02921 node()->get_effect(PolylightEffect::get_class_type()); 02922 if (effect != (const RenderEffect *)NULL) { 02923 const PolylightEffect *ple = DCAST(PolylightEffect, effect); 02924 return ple->has_light(light); 02925 } 02926 return false; 02927 } 02928 } 02929 nassert_raise("Not a Light object."); 02930 return false; 02931 } 02932 02933 //////////////////////////////////////////////////////////////////// 02934 // Function: NodePath::has_light_off 02935 // Access: Published 02936 // Description: Returns true if all Lights have been specifically 02937 // disabled on this particular node. This means that 02938 // someone called set_light_off() on this node with no 02939 // parameters. 02940 //////////////////////////////////////////////////////////////////// 02941 bool NodePath:: 02942 has_light_off() const { 02943 nassertr_always(!is_empty(), false); 02944 02945 const RenderAttrib *attrib = 02946 node()->get_attrib(LightAttrib::get_class_slot()); 02947 if (attrib != (const RenderAttrib *)NULL) { 02948 const LightAttrib *la = DCAST(LightAttrib, attrib); 02949 return la->has_all_off(); 02950 } 02951 02952 return false; 02953 } 02954 02955 //////////////////////////////////////////////////////////////////// 02956 // Function: NodePath::has_light_off 02957 // Access: Published 02958 // Description: Returns true if the indicated Light has been 02959 // specifically disabled on this particular node. This 02960 // means that someone called set_light_off() on this 02961 // node with the indicated light. 02962 // 02963 // This interface does not support PolylightNodes, which 02964 // cannot be turned off at a lower level. 02965 //////////////////////////////////////////////////////////////////// 02966 bool NodePath:: 02967 has_light_off(const NodePath &light) const { 02968 nassertr_always(!is_empty(), false); 02969 if (!light.is_empty()) { 02970 Light *light_obj = light.node()->as_light(); 02971 if (light_obj != (Light *)NULL) { 02972 const RenderAttrib *attrib = 02973 node()->get_attrib(LightAttrib::get_class_slot()); 02974 if (attrib != (const RenderAttrib *)NULL) { 02975 const LightAttrib *la = DCAST(LightAttrib, attrib); 02976 return la->has_off_light(light); 02977 } 02978 } 02979 } 02980 nassert_raise("Not a Light object."); 02981 return false; 02982 } 02983 02984 //////////////////////////////////////////////////////////////////// 02985 // Function: NodePath::set_clip_plane 02986 // Access: Published 02987 // Description: Adds the indicated clipping plane to the list of 02988 // planes that apply to geometry at this node and below. 02989 // The clipping plane itself, a PlaneNode, should be 02990 // parented into the scene graph elsewhere, to represent 02991 // the plane's position in space; but until 02992 // set_clip_plane() is called it will clip no geometry. 02993 //////////////////////////////////////////////////////////////////// 02994 void NodePath:: 02995 set_clip_plane(const NodePath &clip_plane, int priority) { 02996 nassertv_always(!is_empty()); 02997 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 02998 const RenderAttrib *attrib = 02999 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03000 if (attrib != (const RenderAttrib *)NULL) { 03001 priority = max(priority, 03002 node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot())); 03003 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03004 03005 // Modify the existing ClipPlaneAttrib to add the indicated 03006 // clip_plane. 03007 node()->set_attrib(la->add_on_plane(clip_plane), priority); 03008 03009 } else { 03010 // Create a new ClipPlaneAttrib for this node. 03011 CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make()); 03012 node()->set_attrib(la->add_on_plane(clip_plane), priority); 03013 } 03014 return; 03015 } 03016 nassert_raise("Not a PlaneNode object."); 03017 } 03018 03019 //////////////////////////////////////////////////////////////////// 03020 // Function: NodePath::set_clip_plane_off 03021 // Access: Published 03022 // Description: Sets the geometry at this level and below to render 03023 // using no clip_planes at all. This is different 03024 // from not specifying a clip_plane; rather, this 03025 // specifically contradicts set_clip_plane() at a higher 03026 // node level (or, with a priority, overrides a 03027 // set_clip_plane() at a lower level). 03028 // 03029 // If no clip_planes are in effect on a particular piece 03030 // of geometry, that geometry is rendered without being 03031 // clipped (other than by the viewing frustum). 03032 //////////////////////////////////////////////////////////////////// 03033 void NodePath:: 03034 set_clip_plane_off(int priority) { 03035 nassertv_always(!is_empty()); 03036 node()->set_attrib(ClipPlaneAttrib::make_all_off(), priority); 03037 } 03038 03039 //////////////////////////////////////////////////////////////////// 03040 // Function: NodePath::set_clip_plane_off 03041 // Access: Published 03042 // Description: Sets the geometry at this level and below to render 03043 // without being clipped by the indicated PlaneNode. 03044 // This is different from not specifying the PlaneNode; 03045 // rather, this specifically contradicts 03046 // set_clip_plane() at a higher node level (or, with a 03047 // priority, overrides a set_clip_plane() at a lower 03048 // level). 03049 //////////////////////////////////////////////////////////////////// 03050 void NodePath:: 03051 set_clip_plane_off(const NodePath &clip_plane, int priority) { 03052 nassertv_always(!is_empty()); 03053 03054 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03055 const RenderAttrib *attrib = 03056 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03057 if (attrib != (const RenderAttrib *)NULL) { 03058 priority = max(priority, 03059 node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot())); 03060 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03061 03062 // Modify the existing ClipPlaneAttrib to add the indicated clip_plane 03063 // to the "off" list. This also, incidentally, removes it from 03064 // the "on" list if it is there. 03065 node()->set_attrib(la->add_off_plane(clip_plane), priority); 03066 03067 } else { 03068 // Create a new ClipPlaneAttrib for this node that turns off the 03069 // indicated clip_plane. 03070 CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make()); 03071 node()->set_attrib(la->add_off_plane(clip_plane), priority); 03072 } 03073 return; 03074 } 03075 nassert_raise("Not a PlaneNode object."); 03076 } 03077 03078 //////////////////////////////////////////////////////////////////// 03079 // Function: NodePath::clear_clip_plane 03080 // Access: Published 03081 // Description: Completely removes any clip planes that may have been 03082 // set via set_clip_plane() or set_clip_plane_off() from 03083 // this particular node. 03084 //////////////////////////////////////////////////////////////////// 03085 void NodePath:: 03086 clear_clip_plane() { 03087 nassertv_always(!is_empty()); 03088 node()->clear_attrib(ClipPlaneAttrib::get_class_slot()); 03089 } 03090 03091 //////////////////////////////////////////////////////////////////// 03092 // Function: NodePath::clear_clip_plane 03093 // Access: Published 03094 // Description: Removes any reference to the indicated clipping plane 03095 // from the NodePath. 03096 //////////////////////////////////////////////////////////////////// 03097 void NodePath:: 03098 clear_clip_plane(const NodePath &clip_plane) { 03099 nassertv_always(!is_empty()); 03100 03101 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03102 const RenderAttrib *attrib = 03103 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03104 if (attrib != (const RenderAttrib *)NULL) { 03105 CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib); 03106 la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane)); 03107 la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane)); 03108 03109 if (la->is_identity()) { 03110 node()->clear_attrib(ClipPlaneAttrib::get_class_slot()); 03111 03112 } else { 03113 int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_slot()); 03114 node()->set_attrib(la, priority); 03115 } 03116 } 03117 return; 03118 } 03119 nassert_raise("Not a PlaneNode object."); 03120 } 03121 03122 //////////////////////////////////////////////////////////////////// 03123 // Function: NodePath::has_clip_plane 03124 // Access: Published 03125 // Description: Returns true if the indicated clipping plane has been 03126 // specifically applied to this particular node. This 03127 // means that someone called set_clip_plane() on this 03128 // node with the indicated clip_plane. 03129 //////////////////////////////////////////////////////////////////// 03130 bool NodePath:: 03131 has_clip_plane(const NodePath &clip_plane) const { 03132 nassertr_always(!is_empty(), false); 03133 03134 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03135 const RenderAttrib *attrib = 03136 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03137 if (attrib != (const RenderAttrib *)NULL) { 03138 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03139 return la->has_on_plane(clip_plane); 03140 } 03141 return false; 03142 } 03143 nassert_raise("Not a PlaneNode object."); 03144 return false; 03145 } 03146 03147 //////////////////////////////////////////////////////////////////// 03148 // Function: NodePath::has_clip_plane_off 03149 // Access: Published 03150 // Description: Returns true if all clipping planes have been 03151 // specifically disabled on this particular node. This 03152 // means that someone called set_clip_plane_off() on 03153 // this node with no parameters. 03154 //////////////////////////////////////////////////////////////////// 03155 bool NodePath:: 03156 has_clip_plane_off() const { 03157 nassertr_always(!is_empty(), false); 03158 03159 const RenderAttrib *attrib = 03160 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03161 if (attrib != (const RenderAttrib *)NULL) { 03162 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03163 return la->has_all_off(); 03164 } 03165 03166 return false; 03167 } 03168 03169 //////////////////////////////////////////////////////////////////// 03170 // Function: NodePath::has_clip_plane_off 03171 // Access: Published 03172 // Description: Returns true if the indicated clipping plane has been 03173 // specifically disabled on this particular node. This 03174 // means that someone called set_clip_plane_off() on 03175 // this node with the indicated clip_plane. 03176 //////////////////////////////////////////////////////////////////// 03177 bool NodePath:: 03178 has_clip_plane_off(const NodePath &clip_plane) const { 03179 nassertr_always(!is_empty(), false); 03180 if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) { 03181 const RenderAttrib *attrib = 03182 node()->get_attrib(ClipPlaneAttrib::get_class_slot()); 03183 if (attrib != (const RenderAttrib *)NULL) { 03184 const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib); 03185 return la->has_off_plane(clip_plane); 03186 } 03187 } 03188 nassert_raise("Not a PlaneNode object."); 03189 return false; 03190 } 03191 03192 //////////////////////////////////////////////////////////////////// 03193 // Function: NodePath::set_occluder 03194 // Access: Published 03195 // Description: Adds the indicated occluder to the list of 03196 // occluders that apply to geometry at this node and below. 03197 // The occluder itself, an OccluderNode, should be 03198 // parented into the scene graph elsewhere, to represent 03199 // the occluder's position in space; but until 03200 // set_occluder() is called it will clip no geometry. 03201 //////////////////////////////////////////////////////////////////// 03202 void NodePath:: 03203 set_occluder(const NodePath &occluder) { 03204 nassertv_always(!is_empty()); 03205 if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) { 03206 const RenderEffect *effect = 03207 node()->get_effect(OccluderEffect::get_class_type()); 03208 if (effect != (const RenderEffect *)NULL) { 03209 const OccluderEffect *la = DCAST(OccluderEffect, effect); 03210 03211 // Modify the existing OccluderEffect to add the indicated 03212 // occluder. 03213 node()->set_effect(la->add_on_occluder(occluder)); 03214 03215 } else { 03216 // Create a new OccluderEffect for this node. 03217 CPT(OccluderEffect) la = DCAST(OccluderEffect, OccluderEffect::make()); 03218 node()->set_effect(la->add_on_occluder(occluder)); 03219 } 03220 return; 03221 } 03222 nassert_raise("Not an OccluderNode object."); 03223 } 03224 03225 //////////////////////////////////////////////////////////////////// 03226 // Function: NodePath::clear_occluder 03227 // Access: Published 03228 // Description: Completely removes any occluders that may have been 03229 // set via set_occluder() from this particular node. 03230 //////////////////////////////////////////////////////////////////// 03231 void NodePath:: 03232 clear_occluder() { 03233 nassertv_always(!is_empty()); 03234 node()->clear_effect(OccluderEffect::get_class_type()); 03235 } 03236 03237 //////////////////////////////////////////////////////////////////// 03238 // Function: NodePath::clear_occluder 03239 // Access: Published 03240 // Description: Removes any reference to the indicated occluder 03241 // from the NodePath. 03242 //////////////////////////////////////////////////////////////////// 03243 void NodePath:: 03244 clear_occluder(const NodePath &occluder) { 03245 nassertv_always(!is_empty()); 03246 03247 if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) { 03248 const RenderEffect *effect = 03249 node()->get_effect(OccluderEffect::get_class_type()); 03250 if (effect != (const RenderEffect *)NULL) { 03251 CPT(OccluderEffect) la = DCAST(OccluderEffect, effect); 03252 la = DCAST(OccluderEffect, la->remove_on_occluder(occluder)); 03253 03254 if (la->is_identity()) { 03255 node()->clear_effect(OccluderEffect::get_class_type()); 03256 03257 } else { 03258 node()->set_effect(la); 03259 } 03260 } 03261 return; 03262 } 03263 nassert_raise("Not an OccluderNode object."); 03264 } 03265 03266 //////////////////////////////////////////////////////////////////// 03267 // Function: NodePath::has_occluder 03268 // Access: Published 03269 // Description: Returns true if the indicated occluder has been 03270 // specifically applied to this particular node. This 03271 // means that someone called set_occluder() on this 03272 // node with the indicated occluder. 03273 //////////////////////////////////////////////////////////////////// 03274 bool NodePath:: 03275 has_occluder(const NodePath &occluder) const { 03276 nassertr_always(!is_empty(), false); 03277 03278 if (!occluder.is_empty() && occluder.node()->is_of_type(OccluderNode::get_class_type())) { 03279 const RenderEffect *effect = 03280 node()->get_effect(OccluderEffect::get_class_type()); 03281 if (effect != (const RenderEffect *)NULL) { 03282 const OccluderEffect *la = DCAST(OccluderEffect, effect); 03283 return la->has_on_occluder(occluder); 03284 } 03285 return false; 03286 } 03287 nassert_raise("Not an OccluderNode object."); 03288 return false; 03289 } 03290 03291 //////////////////////////////////////////////////////////////////// 03292 // Function: NodePath::set_scissor 03293 // Access: Published 03294 // Description: Sets up a scissor region on the nodes rendered at 03295 // this level and below. The four coordinates are 03296 // understood to define a rectangle in screen space. 03297 // These numbers are relative to the current 03298 // DisplayRegion, where (0,0) is the lower-left corner 03299 // of the DisplayRegion, and (1,1) is the upper-right 03300 // corner. 03301 //////////////////////////////////////////////////////////////////// 03302 void NodePath:: 03303 set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) { 03304 set_effect(ScissorEffect::make_screen(LVecBase4(left, right, bottom, top))); 03305 } 03306 03307 //////////////////////////////////////////////////////////////////// 03308 // Function: NodePath::set_scissor 03309 // Access: Published 03310 // Description: Sets up a scissor region on the nodes rendered at 03311 // this level and below. The two points are understood 03312 // to be relative to this node. When these points are 03313 // projected into screen space, they define the 03314 // diagonally-opposite points that determine the scissor 03315 // region. 03316 //////////////////////////////////////////////////////////////////// 03317 void NodePath:: 03318 set_scissor(const LPoint3 &a, const LPoint3 &b) { 03319 set_effect(ScissorEffect::make_node(a, b)); 03320 } 03321 03322 //////////////////////////////////////////////////////////////////// 03323 // Function: NodePath::set_scissor 03324 // Access: Published 03325 // Description: Sets up a scissor region on the nodes rendered at 03326 // this level and below. The four points are understood 03327 // to be relative to this node. When these points are 03328 // projected into screen space, they define the 03329 // bounding volume of the scissor region (the scissor 03330 // region is the smallest onscreen rectangle that 03331 // encloses all four points). 03332 //////////////////////////////////////////////////////////////////// 03333 void NodePath:: 03334 set_scissor(const LPoint3 &a, const LPoint3 &b, 03335 const LPoint3 &c, const LPoint3 &d) { 03336 set_effect(ScissorEffect::make_node(a, b, c, d)); 03337 } 03338 03339 //////////////////////////////////////////////////////////////////// 03340 // Function: NodePath::set_scissor 03341 // Access: Published 03342 // Description: Sets up a scissor region on the nodes rendered at 03343 // this level and below. The two points are understood 03344 // to be relative to the indicated other node. When 03345 // these points are projected into screen space, they 03346 // define the diagonally-opposite points that determine 03347 // the scissor region. 03348 //////////////////////////////////////////////////////////////////// 03349 void NodePath:: 03350 set_scissor(const NodePath &other, const LPoint3 &a, const LPoint3 &b) { 03351 set_effect(ScissorEffect::make_node(a, b, other)); 03352 } 03353 03354 //////////////////////////////////////////////////////////////////// 03355 // Function: NodePath::set_scissor 03356 // Access: Published 03357 // Description: Sets up a scissor region on the nodes rendered at 03358 // this level and below. The four points are understood 03359 // to be relative to the indicated other node. When 03360 // these points are projected into screen space, they 03361 // define the bounding volume of the scissor region (the 03362 // scissor region is the smallest onscreen rectangle 03363 // that encloses all four points). 03364 //////////////////////////////////////////////////////////////////// 03365 void NodePath:: 03366 set_scissor(const NodePath &other, 03367 const LPoint3 &a, const LPoint3 &b, 03368 const LPoint3 &c, const LPoint3 &d) { 03369 set_effect(ScissorEffect::make_node(a, b, c, d, other)); 03370 } 03371 03372 //////////////////////////////////////////////////////////////////// 03373 // Function: NodePath::clear_scissor 03374 // Access: Published 03375 // Description: Removes the scissor region that was defined at this 03376 // node level by a previous call to set_scissor(). 03377 //////////////////////////////////////////////////////////////////// 03378 void NodePath:: 03379 clear_scissor() { 03380 clear_effect(ScissorEffect::get_class_type()); 03381 } 03382 03383 //////////////////////////////////////////////////////////////////// 03384 // Function: NodePath::has_scissor 03385 // Access: Published 03386 // Description: Returns true if a scissor region was defined at this 03387 // node by a previous call to set_scissor(). This does 03388 // not check for scissor regions inherited from a parent 03389 // class. It also does not check for the presence of a 03390 // low-level ScissorAttrib, which is different from the 03391 // ScissorEffect added by set_scissor. 03392 //////////////////////////////////////////////////////////////////// 03393 bool NodePath:: 03394 has_scissor() const { 03395 return has_effect(ScissorEffect::get_class_type()); 03396 } 03397 03398 //////////////////////////////////////////////////////////////////// 03399 // Function: NodePath::set_bin 03400 // Access: Published 03401 // Description: Assigns the geometry at this level and below to the 03402 // named rendering bin. It is the user's responsibility 03403 // to ensure that such a bin already exists, either via 03404 // the cull-bin Configrc variable, or by explicitly 03405 // creating a GeomBin of the appropriate type at 03406 // runtime. 03407 // 03408 // There are two default bins created when Panda is 03409 // started: "default" and "fixed". Normally, all 03410 // geometry is assigned to "default" unless specified 03411 // otherwise. This bin renders opaque geometry in 03412 // state-sorted order, followed by transparent geometry 03413 // sorted back-to-front. If any geometry is assigned to 03414 // "fixed", this will be rendered following all the 03415 // geometry in "default", in the order specified by 03416 // draw_order for each piece of geometry so assigned. 03417 // 03418 // The draw_order parameter is meaningful only for 03419 // GeomBinFixed type bins, e.g. "fixed". Other kinds of 03420 // bins ignore it. 03421 //////////////////////////////////////////////////////////////////// 03422 void NodePath:: 03423 set_bin(const string &bin_name, int draw_order, int priority) { 03424 nassertv_always(!is_empty()); 03425 node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority); 03426 } 03427 03428 //////////////////////////////////////////////////////////////////// 03429 // Function: NodePath::clear_bin 03430 // Access: Published 03431 // Description: Completely removes any bin adjustment that may have 03432 // been set via set_bin() from this particular node. 03433 //////////////////////////////////////////////////////////////////// 03434 void NodePath:: 03435 clear_bin() { 03436 nassertv_always(!is_empty()); 03437 node()->clear_attrib(CullBinAttrib::get_class_slot()); 03438 } 03439 03440 //////////////////////////////////////////////////////////////////// 03441 // Function: NodePath::has_bin 03442 // Access: Published 03443 // Description: Returns true if the node has been assigned to the a 03444 // particular rendering bin via set_bin(), false 03445 // otherwise. 03446 //////////////////////////////////////////////////////////////////// 03447 bool NodePath:: 03448 has_bin() const { 03449 nassertr_always(!is_empty(), false); 03450 return node()->has_attrib(CullBinAttrib::get_class_slot()); 03451 } 03452 03453 //////////////////////////////////////////////////////////////////// 03454 // Function: NodePath::get_bin_name 03455 // Access: Published 03456 // Description: Returns the name of the bin that this particular node 03457 // was assigned to via set_bin(), or the empty string if 03458 // no bin was assigned. See set_bin() and has_bin(). 03459 //////////////////////////////////////////////////////////////////// 03460 string NodePath:: 03461 get_bin_name() const { 03462 nassertr_always(!is_empty(), string()); 03463 const RenderAttrib *attrib = 03464 node()->get_attrib(CullBinAttrib::get_class_slot()); 03465 if (attrib != (const RenderAttrib *)NULL) { 03466 const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib); 03467 return ba->get_bin_name(); 03468 } 03469 03470 return string(); 03471 } 03472 03473 //////////////////////////////////////////////////////////////////// 03474 // Function: NodePath::get_bin_draw_order 03475 // Access: Published 03476 // Description: Returns the drawing order associated with the bin 03477 // that this particular node was assigned to via 03478 // set_bin(), or 0 if no bin was assigned. See 03479 // set_bin() and has_bin(). 03480 //////////////////////////////////////////////////////////////////// 03481 int NodePath:: 03482 get_bin_draw_order() const { 03483 nassertr_always(!is_empty(), false); 03484 const RenderAttrib *attrib = 03485 node()->get_attrib(CullBinAttrib::get_class_slot()); 03486 if (attrib != (const RenderAttrib *)NULL) { 03487 const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib); 03488 return ba->get_draw_order(); 03489 } 03490 03491 return 0; 03492 } 03493 03494 //////////////////////////////////////////////////////////////////// 03495 // Function: NodePath::set_texture 03496 // Access: Published 03497 // Description: Adds the indicated texture to the list of textures 03498 // that will be rendered on the default texture stage. 03499 // 03500 // This is the convenience single-texture variant of 03501 // this method; it is now superceded by set_texture() 03502 // that accepts a stage and texture. You may use this 03503 // method if you just want to adjust the default stage. 03504 //////////////////////////////////////////////////////////////////// 03505 void NodePath:: 03506 set_texture(Texture *tex, int priority) { 03507 nassertv_always(!is_empty()); 03508 PT(TextureStage) stage = TextureStage::get_default(); 03509 set_texture(stage, tex, priority); 03510 } 03511 03512 //////////////////////////////////////////////////////////////////// 03513 // Function: NodePath::set_texture 03514 // Access: Published 03515 // Description: Adds the indicated texture to the list of textures 03516 // that will be rendered on the indicated multitexture 03517 // stage. If there are multiple texture stages 03518 // specified (possibly on multiple different nodes at 03519 // different levels), they will all be applied to 03520 // geometry together, according to the stage 03521 // specification set up in the TextureStage object. 03522 //////////////////////////////////////////////////////////////////// 03523 void NodePath:: 03524 set_texture(TextureStage *stage, Texture *tex, int priority) { 03525 nassertv_always(!is_empty()); 03526 03527 const RenderAttrib *attrib = 03528 node()->get_attrib(TextureAttrib::get_class_slot()); 03529 if (attrib != (const RenderAttrib *)NULL) { 03530 const TextureAttrib *tsa = DCAST(TextureAttrib, attrib); 03531 int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); 03532 03533 // Modify the existing TextureAttrib to add the indicated 03534 // texture. 03535 node()->set_attrib(tsa->add_on_stage(stage, tex, priority), sg_priority); 03536 03537 } else { 03538 // Create a new TextureAttrib for this node. 03539 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make()); 03540 node()->set_attrib(tsa->add_on_stage(stage, tex, priority)); 03541 } 03542 } 03543 03544 //////////////////////////////////////////////////////////////////// 03545 // Function: NodePath::set_texture_off 03546 // Access: Published 03547 // Description: Sets the geometry at this level and below to render 03548 // using no texture, on any stage. This is different 03549 // from not specifying a texture; rather, this 03550 // specifically contradicts set_texture() at a higher 03551 // node level (or, with a priority, overrides a 03552 // set_texture() at a lower level). 03553 //////////////////////////////////////////////////////////////////// 03554 void NodePath:: 03555 set_texture_off(int priority) { 03556 nassertv_always(!is_empty()); 03557 node()->set_attrib(TextureAttrib::make_all_off(), priority); 03558 } 03559 03560 //////////////////////////////////////////////////////////////////// 03561 // Function: NodePath::set_texture_off 03562 // Access: Published 03563 // Description: Sets the geometry at this level and below to render 03564 // using no texture, on the indicated stage. This is 03565 // different from not specifying a texture; rather, this 03566 // specifically contradicts set_texture() at a higher 03567 // node level (or, with a priority, overrides a 03568 // set_texture() at a lower level). 03569 //////////////////////////////////////////////////////////////////// 03570 void NodePath:: 03571 set_texture_off(TextureStage *stage, int priority) { 03572 nassertv_always(!is_empty()); 03573 03574 const RenderAttrib *attrib = 03575 node()->get_attrib(TextureAttrib::get_class_slot()); 03576 if (attrib != (const RenderAttrib *)NULL) { 03577 const TextureAttrib *tsa = DCAST(TextureAttrib, attrib); 03578 int sg_priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); 03579 03580 // Modify the existing TextureAttrib to add the indicated texture 03581 // to the "off" list. This also, incidentally, removes it from 03582 // the "on" list if it is there. 03583 node()->set_attrib(tsa->add_off_stage(stage, priority), sg_priority); 03584 03585 } else { 03586 // Create a new TextureAttrib for this node that turns off the 03587 // indicated stage. 03588 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make()); 03589 node()->set_attrib(tsa->add_off_stage(stage, priority)); 03590 } 03591 } 03592 03593 //////////////////////////////////////////////////////////////////// 03594 // Function: NodePath::clear_texture 03595 // Access: Published 03596 // Description: Completely removes any texture adjustment that may 03597 // have been set via set_texture() or set_texture_off() 03598 // from this particular node. This allows whatever 03599 // textures might be otherwise affecting the geometry to 03600 // show instead. 03601 //////////////////////////////////////////////////////////////////// 03602 void NodePath:: 03603 clear_texture() { 03604 nassertv_always(!is_empty()); 03605 node()->clear_attrib(TextureAttrib::get_class_slot()); 03606 } 03607 03608 //////////////////////////////////////////////////////////////////// 03609 // Function: NodePath::clear_texture 03610 // Access: Published 03611 // Description: Removes any reference to the indicated texture stage 03612 // from the NodePath. 03613 //////////////////////////////////////////////////////////////////// 03614 void NodePath:: 03615 clear_texture(TextureStage *stage) { 03616 nassertv_always(!is_empty()); 03617 03618 const RenderAttrib *attrib = 03619 node()->get_attrib(TextureAttrib::get_class_slot()); 03620 if (attrib != (const RenderAttrib *)NULL) { 03621 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, attrib); 03622 tsa = DCAST(TextureAttrib, tsa->remove_on_stage(stage)); 03623 tsa = DCAST(TextureAttrib, tsa->remove_off_stage(stage)); 03624 03625 if (tsa->is_identity()) { 03626 node()->clear_attrib(TextureAttrib::get_class_slot()); 03627 03628 } else { 03629 int priority = node()->get_state()->get_override(TextureAttrib::get_class_slot()); 03630 node()->set_attrib(tsa, priority); 03631 } 03632 } 03633 } 03634 03635 //////////////////////////////////////////////////////////////////// 03636 // Function: NodePath::has_texture 03637 // Access: Published 03638 // Description: Returns true if a texture has been applied to this 03639 // particular node via set_texture(), false otherwise. 03640 // This is not the same thing as asking whether the 03641 // geometry at this node will be rendered with 03642 // texturing, as there may be a texture in effect from a 03643 // higher or lower level. 03644 //////////////////////////////////////////////////////////////////// 03645 bool NodePath:: 03646 has_texture() const { 03647 return get_texture() != (Texture *)NULL; 03648 } 03649 03650 //////////////////////////////////////////////////////////////////// 03651 // Function: NodePath::has_texture 03652 // Access: Published 03653 // Description: Returns true if texturing has been specifically 03654 // enabled on this particular node for the indicated 03655 // stage. This means that someone called 03656 // set_texture() on this node with the indicated stage 03657 // name, or the stage_name is the default stage_name, 03658 // and someone called set_texture() on this node. 03659 //////////////////////////////////////////////////////////////////// 03660 bool NodePath:: 03661 has_texture(TextureStage *stage) const { 03662 nassertr_always(!is_empty(), false); 03663 03664 const RenderAttrib *attrib = 03665 node()->get_attrib(TextureAttrib::get_class_slot()); 03666 if (attrib != (const RenderAttrib *)NULL) { 03667 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03668 return ta->has_on_stage(stage); 03669 } 03670 03671 return false; 03672 } 03673 03674 //////////////////////////////////////////////////////////////////// 03675 // Function: NodePath::has_texture_off 03676 // Access: Published 03677 // Description: Returns true if texturing has been specifically 03678 // disabled on this particular node via 03679 // set_texture_off(), false otherwise. This is not the 03680 // same thing as asking whether the geometry at this 03681 // node will be rendered untextured, as there may be a 03682 // texture in effect from a higher or lower level. 03683 //////////////////////////////////////////////////////////////////// 03684 bool NodePath:: 03685 has_texture_off() const { 03686 nassertr_always(!is_empty(), false); 03687 const RenderAttrib *attrib = 03688 node()->get_attrib(TextureAttrib::get_class_slot()); 03689 if (attrib != (const RenderAttrib *)NULL) { 03690 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03691 return ta->has_all_off(); 03692 } 03693 03694 return false; 03695 } 03696 03697 //////////////////////////////////////////////////////////////////// 03698 // Function: NodePath::has_texture_off 03699 // Access: Published 03700 // Description: Returns true if texturing has been specifically 03701 // disabled on this particular node for the indicated 03702 // stage. This means that someone called 03703 // set_texture_off() on this node with the indicated 03704 // stage name, or that someone called set_texture_off() 03705 // on this node to remove all stages. 03706 //////////////////////////////////////////////////////////////////// 03707 bool NodePath:: 03708 has_texture_off(TextureStage *stage) const { 03709 nassertr_always(!is_empty(), false); 03710 03711 const RenderAttrib *attrib = 03712 node()->get_attrib(TextureAttrib::get_class_slot()); 03713 if (attrib != (const RenderAttrib *)NULL) { 03714 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03715 return ta->has_off_stage(stage); 03716 } 03717 03718 return false; 03719 } 03720 03721 //////////////////////////////////////////////////////////////////// 03722 // Function: NodePath::get_texture 03723 // Access: Published 03724 // Description: Returns the base-level texture that has been set on 03725 // this particular node, or NULL if no texture has been 03726 // set. This is not necessarily the texture that will 03727 // be applied to the geometry at or below this level, as 03728 // another texture at a higher or lower level may 03729 // override. 03730 // 03731 // See also find_texture(). 03732 //////////////////////////////////////////////////////////////////// 03733 Texture *NodePath:: 03734 get_texture() const { 03735 nassertr_always(!is_empty(), NULL); 03736 const RenderAttrib *attrib = 03737 node()->get_attrib(TextureAttrib::get_class_slot()); 03738 if (attrib != (const RenderAttrib *)NULL) { 03739 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03740 return ta->get_texture(); 03741 } 03742 03743 return NULL; 03744 } 03745 03746 //////////////////////////////////////////////////////////////////// 03747 // Function: NodePath::get_texture 03748 // Access: Published 03749 // Description: Returns the texture that has been set on the 03750 // indicated stage for this particular node, or NULL if 03751 // no texture has been set for this stage. 03752 //////////////////////////////////////////////////////////////////// 03753 Texture *NodePath:: 03754 get_texture(TextureStage *stage) const { 03755 nassertr_always(!is_empty(), NULL); 03756 const RenderAttrib *attrib = 03757 node()->get_attrib(TextureAttrib::get_class_slot()); 03758 if (attrib != (const RenderAttrib *)NULL) { 03759 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 03760 return ta->get_on_texture(stage); 03761 } 03762 03763 return NULL; 03764 } 03765 03766 //////////////////////////////////////////////////////////////////// 03767 // Function: NodePath::set_shader 03768 // Access: Published 03769 // Description: 03770 //////////////////////////////////////////////////////////////////// 03771 void NodePath:: 03772 set_shader(const Shader *sha, int priority) { 03773 nassertv_always(!is_empty()); 03774 03775 const RenderAttrib *attrib = 03776 node()->get_attrib(ShaderAttrib::get_class_slot()); 03777 if (attrib != (const RenderAttrib *)NULL) { 03778 priority = max(priority, 03779 node()->get_state()->get_override(ShaderAttrib::get_class_slot())); 03780 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03781 node()->set_attrib(sa->set_shader(sha, priority)); 03782 } else { 03783 // Create a new ShaderAttrib for this node. 03784 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03785 node()->set_attrib(sa->set_shader(sha, priority)); 03786 } 03787 } 03788 03789 //////////////////////////////////////////////////////////////////// 03790 // Function: NodePath::set_shader_off 03791 // Access: Published 03792 // Description: 03793 //////////////////////////////////////////////////////////////////// 03794 void NodePath:: 03795 set_shader_off(int priority) { 03796 set_shader(NULL, priority); 03797 } 03798 03799 //////////////////////////////////////////////////////////////////// 03800 // Function: NodePath::set_shader_auto 03801 // Access: Published 03802 // Description: 03803 //////////////////////////////////////////////////////////////////// 03804 void NodePath:: 03805 set_shader_auto(int priority) { 03806 nassertv_always(!is_empty()); 03807 03808 const RenderAttrib *attrib = 03809 node()->get_attrib(ShaderAttrib::get_class_slot()); 03810 if (attrib != (const RenderAttrib *)NULL) { 03811 priority = max(priority, 03812 node()->get_state()->get_override(ShaderAttrib::get_class_slot())); 03813 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03814 node()->set_attrib(sa->set_shader_auto(priority)); 03815 } else { 03816 // Create a new ShaderAttrib for this node. 03817 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03818 node()->set_attrib(sa->set_shader_auto(priority)); 03819 } 03820 } 03821 03822 //////////////////////////////////////////////////////////////////// 03823 // Function: NodePath::set_shader_auto 03824 // Access: Published 03825 // Description: overloaded for auto shader customization 03826 //////////////////////////////////////////////////////////////////// 03827 void NodePath:: 03828 set_shader_auto(BitMask32 shader_switch, int priority) { 03829 nassertv_always(!is_empty()); 03830 03831 const RenderAttrib *attrib = 03832 node()->get_attrib(ShaderAttrib::get_class_slot()); 03833 if (attrib != (const RenderAttrib *)NULL) { 03834 priority = max(priority, 03835 node()->get_state()->get_override(ShaderAttrib::get_class_slot())); 03836 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03837 node()->set_attrib(sa->set_shader_auto(shader_switch, priority)); 03838 } else { 03839 // Create a new ShaderAttrib for this node. 03840 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03841 node()->set_attrib(sa->set_shader_auto(shader_switch, priority)); 03842 } 03843 } 03844 //////////////////////////////////////////////////////////////////// 03845 // Function: NodePath::clear_shader 03846 // Access: Published 03847 // Description: 03848 //////////////////////////////////////////////////////////////////// 03849 void NodePath:: 03850 clear_shader() { 03851 nassertv_always(!is_empty()); 03852 03853 const RenderAttrib *attrib = 03854 node()->get_attrib(ShaderAttrib::get_class_slot()); 03855 if (attrib != (const RenderAttrib *)NULL) { 03856 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03857 node()->set_attrib(sa->clear_shader()); 03858 } 03859 } 03860 03861 //////////////////////////////////////////////////////////////////// 03862 // Function: NodePath::get_shader 03863 // Access: Published 03864 // Description: 03865 //////////////////////////////////////////////////////////////////// 03866 const Shader *NodePath:: 03867 get_shader() const { 03868 nassertr_always(!is_empty(), NULL); 03869 const RenderAttrib *attrib = 03870 node()->get_attrib(ShaderAttrib::get_class_slot()); 03871 if (attrib != (const RenderAttrib *)NULL) { 03872 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03873 return sa->get_shader(); 03874 } 03875 return NULL; 03876 } 03877 03878 //////////////////////////////////////////////////////////////////// 03879 // Function: NodePath::set_shader_input 03880 // Access: Published 03881 // Description: 03882 //////////////////////////////////////////////////////////////////// 03883 void NodePath:: 03884 set_shader_input(const ShaderInput *inp) { 03885 nassertv_always(!is_empty()); 03886 03887 const RenderAttrib *attrib = 03888 node()->get_attrib(ShaderAttrib::get_class_slot()); 03889 if (attrib != (const RenderAttrib *)NULL) { 03890 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03891 node()->set_attrib(sa->set_shader_input(inp)); 03892 } else { 03893 // Create a new ShaderAttrib for this node. 03894 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 03895 node()->set_attrib(sa->set_shader_input(inp)); 03896 } 03897 } 03898 03899 //////////////////////////////////////////////////////////////////// 03900 // Function: NodePath::get_shader_input 03901 // Access: Published 03902 // Description: 03903 //////////////////////////////////////////////////////////////////// 03904 const ShaderInput *NodePath:: 03905 get_shader_input(const InternalName *id) const { 03906 nassertr_always(!is_empty(), NULL); 03907 03908 const RenderAttrib *attrib = 03909 node()->get_attrib(ShaderAttrib::get_class_slot()); 03910 if (attrib != (const RenderAttrib *)NULL) { 03911 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03912 return sa->get_shader_input(id); 03913 } 03914 return NULL; 03915 } 03916 03917 //////////////////////////////////////////////////////////////////// 03918 // Function: NodePath::get_instance_count 03919 // Access: Published 03920 // Description: Returns the geometry instance count, or 0 if 03921 // disabled. See set_instance_count. 03922 //////////////////////////////////////////////////////////////////// 03923 const int NodePath:: 03924 get_instance_count() const { 03925 nassertr_always(!is_empty(), 0); 03926 03927 const RenderAttrib *attrib = 03928 node()->get_attrib(ShaderAttrib::get_class_slot()); 03929 03930 if (attrib != (const RenderAttrib *)NULL) { 03931 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03932 return sa->get_instance_count(); 03933 } 03934 03935 return 0; 03936 } 03937 03938 //////////////////////////////////////////////////////////////////// 03939 // Function: NodePath::clear_shader_input 03940 // Access: Published 03941 // Description: 03942 //////////////////////////////////////////////////////////////////// 03943 void NodePath:: 03944 clear_shader_input(const InternalName *id) { 03945 nassertv_always(!is_empty()); 03946 03947 const RenderAttrib *attrib = 03948 node()->get_attrib(ShaderAttrib::get_class_slot()); 03949 if (attrib != (const RenderAttrib *)NULL) { 03950 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 03951 node()->set_attrib(sa->clear_shader_input(id)); 03952 } 03953 } 03954 03955 03956 //////////////////////////////////////////////////////////////////// 03957 // Function: NodePath::set_shader_input 03958 // Access: Published 03959 // Description: 03960 //////////////////////////////////////////////////////////////////// 03961 void NodePath:: 03962 set_shader_input(const InternalName *id, const PTA_float &v, int priority) { 03963 set_shader_input(new ShaderInput(id,v,priority)); 03964 } 03965 03966 //////////////////////////////////////////////////////////////////// 03967 // Function: NodePath::set_shader_input 03968 // Access: Published 03969 // Description: 03970 //////////////////////////////////////////////////////////////////// 03971 void NodePath:: 03972 set_shader_input(const InternalName *id, const PTA_double &v, int priority) { 03973 set_shader_input(new ShaderInput(id,v,priority)); 03974 } 03975 03976 //////////////////////////////////////////////////////////////////// 03977 // Function: NodePath::set_shader_input 03978 // Access: Published 03979 // Description: 03980 //////////////////////////////////////////////////////////////////// 03981 void NodePath:: 03982 set_shader_input(const InternalName *id, const PTA_LVecBase4 &v, int priority) { 03983 set_shader_input(new ShaderInput(id,v,priority)); 03984 } 03985 03986 //////////////////////////////////////////////////////////////////// 03987 // Function: NodePath::set_shader_input 03988 // Access: Published 03989 // Description: 03990 //////////////////////////////////////////////////////////////////// 03991 void NodePath:: 03992 set_shader_input(const InternalName *id, const PTA_LVecBase3 &v, int priority) { 03993 set_shader_input(new ShaderInput(id,v,priority)); 03994 } 03995 03996 03997 //////////////////////////////////////////////////////////////////// 03998 // Function: NodePath::set_shader_input 03999 // Access: Published 04000 // Description: 04001 //////////////////////////////////////////////////////////////////// 04002 void NodePath:: 04003 set_shader_input(const InternalName *id, const PTA_LVecBase2 &v, int priority) { 04004 set_shader_input(new ShaderInput(id,v,priority)); 04005 } 04006 04007 //////////////////////////////////////////////////////////////////// 04008 // Function: NodePath::set_shader_input 04009 // Access: Published 04010 // Description: 04011 //////////////////////////////////////////////////////////////////// 04012 void NodePath:: 04013 set_shader_input(const InternalName *id, const LVecBase4 &v, int priority) { 04014 set_shader_input(new ShaderInput(id,v,priority)); 04015 } 04016 04017 //////////////////////////////////////////////////////////////////// 04018 // Function: NodePath::set_shader_input 04019 // Access: Published 04020 // Description: 04021 //////////////////////////////////////////////////////////////////// 04022 void NodePath:: 04023 set_shader_input(const InternalName *id, const LVecBase3 &v, int priority) { 04024 set_shader_input(new ShaderInput(id,v,priority)); 04025 } 04026 04027 //////////////////////////////////////////////////////////////////// 04028 // Function: NodePath::set_shader_input 04029 // Access: Published 04030 // Description: 04031 //////////////////////////////////////////////////////////////////// 04032 void NodePath:: 04033 set_shader_input(const InternalName *id, const LVecBase2 &v, int priority) { 04034 set_shader_input(new ShaderInput(id,v,priority)); 04035 } 04036 04037 //////////////////////////////////////////////////////////////////// 04038 // Function: NodePath::set_shader_input 04039 // Access: Published 04040 // Description: 04041 //////////////////////////////////////////////////////////////////// 04042 void NodePath:: 04043 set_shader_input(const InternalName *id, const PTA_LMatrix4 &v, int priority) { 04044 set_shader_input(new ShaderInput(id,v,priority)); 04045 } 04046 04047 //////////////////////////////////////////////////////////////////// 04048 // Function: NodePath::set_shader_input 04049 // Access: Published 04050 // Description: 04051 //////////////////////////////////////////////////////////////////// 04052 void NodePath:: 04053 set_shader_input(const InternalName *id, const PTA_LMatrix3 &v, int priority) { 04054 set_shader_input(new ShaderInput(id,v,priority)); 04055 } 04056 04057 //////////////////////////////////////////////////////////////////// 04058 // Function: NodePath::set_shader_input 04059 // Access: Published 04060 // Description: 04061 //////////////////////////////////////////////////////////////////// 04062 void NodePath:: 04063 set_shader_input(const InternalName *id, const LMatrix4 &v, int priority) { 04064 set_shader_input(new ShaderInput(id,v,priority)); 04065 } 04066 04067 //////////////////////////////////////////////////////////////////// 04068 // Function: NodePath::set_shader_input 04069 // Access: Published 04070 // Description: 04071 //////////////////////////////////////////////////////////////////// 04072 void NodePath:: 04073 set_shader_input(const InternalName *id, const LMatrix3 &v, int priority) { 04074 set_shader_input(new ShaderInput(id,v,priority)); 04075 } 04076 04077 //////////////////////////////////////////////////////////////////// 04078 // Function: NodePath::set_shader_input 04079 // Access: Published 04080 // Description: 04081 //////////////////////////////////////////////////////////////////// 04082 void NodePath:: 04083 set_shader_input(const InternalName *id, Texture *tex, int priority) { 04084 set_shader_input(new ShaderInput(id,tex,priority)); 04085 } 04086 04087 //////////////////////////////////////////////////////////////////// 04088 // Function: NodePath::set_shader_input 04089 // Access: Published 04090 // Description: 04091 //////////////////////////////////////////////////////////////////// 04092 void NodePath:: 04093 set_shader_input(const InternalName *id, const NodePath &np, int priority) { 04094 set_shader_input(new ShaderInput(id,np,priority)); 04095 } 04096 04097 //////////////////////////////////////////////////////////////////// 04098 // Function: NodePath::set_shader_input 04099 // Access: Published 04100 // Description: 04101 //////////////////////////////////////////////////////////////////// 04102 void NodePath:: 04103 set_shader_input(const InternalName *id, double n1, double n2, double n3, double n4, int priority) { 04104 set_shader_input(new ShaderInput(id, LVecBase4(n1, n2, n3, n4), priority)); 04105 } 04106 04107 //////////////////////////////////////////////////////////////////// 04108 // Function: NodePath::set_shader_input 04109 // Access: Published 04110 // Description: 04111 //////////////////////////////////////////////////////////////////// 04112 void NodePath:: 04113 set_shader_input(const string &id, const PTA_float &v, int priority) { 04114 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04115 } 04116 04117 //////////////////////////////////////////////////////////////////// 04118 // Function: NodePath::set_shader_input 04119 // Access: Published 04120 // Description: 04121 //////////////////////////////////////////////////////////////////// 04122 void NodePath:: 04123 set_shader_input(const string &id, const PTA_double &v, int priority) { 04124 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04125 } 04126 04127 //////////////////////////////////////////////////////////////////// 04128 // Function: NodePath::set_shader_input 04129 // Access: Published 04130 // Description: 04131 //////////////////////////////////////////////////////////////////// 04132 void NodePath:: 04133 set_shader_input(const string &id, const PTA_LVecBase4 &v, int priority) { 04134 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04135 } 04136 04137 //////////////////////////////////////////////////////////////////// 04138 // Function: NodePath::set_shader_input 04139 // Access: Published 04140 // Description: 04141 //////////////////////////////////////////////////////////////////// 04142 void NodePath:: 04143 set_shader_input(const string &id, const PTA_LVecBase3 &v, int priority) { 04144 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04145 } 04146 04147 04148 //////////////////////////////////////////////////////////////////// 04149 // Function: NodePath::set_shader_input 04150 // Access: Published 04151 // Description: 04152 //////////////////////////////////////////////////////////////////// 04153 void NodePath:: 04154 set_shader_input(const string &id, const PTA_LVecBase2 &v, int priority) { 04155 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04156 } 04157 04158 //////////////////////////////////////////////////////////////////// 04159 // Function: NodePath::set_shader_input 04160 // Access: Published 04161 // Description: 04162 //////////////////////////////////////////////////////////////////// 04163 void NodePath:: 04164 set_shader_input(const string &id, const LVecBase4 &v, int priority) { 04165 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04166 } 04167 04168 //////////////////////////////////////////////////////////////////// 04169 // Function: NodePath::set_shader_input 04170 // Access: Published 04171 // Description: 04172 //////////////////////////////////////////////////////////////////// 04173 void NodePath:: 04174 set_shader_input(const string &id, const LVecBase3 &v, int priority) { 04175 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04176 } 04177 04178 //////////////////////////////////////////////////////////////////// 04179 // Function: NodePath::set_shader_input 04180 // Access: Published 04181 // Description: 04182 //////////////////////////////////////////////////////////////////// 04183 void NodePath:: 04184 set_shader_input(const string &id, const LVecBase2 &v, int priority) { 04185 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04186 } 04187 04188 //////////////////////////////////////////////////////////////////// 04189 // Function: NodePath::set_shader_input 04190 // Access: Published 04191 // Description: 04192 //////////////////////////////////////////////////////////////////// 04193 void NodePath:: 04194 set_shader_input(const string &id, const PTA_LMatrix4 &v, int priority) { 04195 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04196 } 04197 04198 //////////////////////////////////////////////////////////////////// 04199 // Function: NodePath::set_shader_input 04200 // Access: Published 04201 // Description: 04202 //////////////////////////////////////////////////////////////////// 04203 void NodePath:: 04204 set_shader_input(const string &id, const PTA_LMatrix3 &v, int priority) { 04205 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04206 } 04207 04208 //////////////////////////////////////////////////////////////////// 04209 // Function: NodePath::set_shader_input 04210 // Access: Published 04211 // Description: 04212 //////////////////////////////////////////////////////////////////// 04213 void NodePath:: 04214 set_shader_input(const string &id, const LMatrix4 &v, int priority) { 04215 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04216 } 04217 04218 //////////////////////////////////////////////////////////////////// 04219 // Function: NodePath::set_shader_input 04220 // Access: Published 04221 // Description: 04222 //////////////////////////////////////////////////////////////////// 04223 void NodePath:: 04224 set_shader_input(const string &id, const LMatrix3 &v, int priority) { 04225 set_shader_input(new ShaderInput(InternalName::make(id),v,priority)); 04226 } 04227 //////////////////////////////////////////////////////////////////// 04228 // Function: NodePath::set_shader_input 04229 // Access: Published 04230 // Description: 04231 //////////////////////////////////////////////////////////////////// 04232 void NodePath:: 04233 set_shader_input(const string &id, Texture *tex, int priority) { 04234 set_shader_input(new ShaderInput(InternalName::make(id),tex,priority)); 04235 } 04236 04237 //////////////////////////////////////////////////////////////////// 04238 // Function: NodePath::set_shader_input 04239 // Access: Published 04240 // Description: 04241 //////////////////////////////////////////////////////////////////// 04242 void NodePath:: 04243 set_shader_input(const string &id, const NodePath &np, int priority) { 04244 set_shader_input(new ShaderInput(InternalName::make(id),np,priority)); 04245 } 04246 04247 //////////////////////////////////////////////////////////////////// 04248 // Function: NodePath::set_shader_input 04249 // Access: Published 04250 // Description: 04251 //////////////////////////////////////////////////////////////////// 04252 void NodePath:: 04253 set_shader_input(const string &id, double n1, double n2, double n3, double n4, int priority) { 04254 set_shader_input(new ShaderInput(InternalName::make(id), LVecBase4(n1, n2, n3, n4), priority)); 04255 } 04256 04257 //////////////////////////////////////////////////////////////////// 04258 // Function: NodePath::get_shader_input 04259 // Access: Published 04260 // Description: 04261 //////////////////////////////////////////////////////////////////// 04262 const ShaderInput *NodePath:: 04263 get_shader_input(const string &id) const { 04264 return get_shader_input(InternalName::make(id)); 04265 } 04266 04267 //////////////////////////////////////////////////////////////////// 04268 // Function: NodePath::clear_shader_input 04269 // Access: Published 04270 // Description: 04271 //////////////////////////////////////////////////////////////////// 04272 void NodePath:: 04273 clear_shader_input(const string &id) { 04274 clear_shader_input(InternalName::make(id)); 04275 } 04276 04277 //////////////////////////////////////////////////////////////////// 04278 // Function: NodePath::set_instance_count 04279 // Access: Published 04280 // Description: Sets the geometry instance count, or 0 if 04281 // geometry instancing should be disabled. Do not 04282 // confuse with instanceTo which only applies to 04283 // animation instancing. 04284 //////////////////////////////////////////////////////////////////// 04285 void NodePath:: 04286 set_instance_count(int instance_count) { 04287 nassertv_always(!is_empty()); 04288 04289 const RenderAttrib *attrib = 04290 node()->get_attrib(ShaderAttrib::get_class_slot()); 04291 if (attrib != (const RenderAttrib *)NULL) { 04292 const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); 04293 node()->set_attrib(sa->set_instance_count(instance_count)); 04294 } else { 04295 // Create a new ShaderAttrib for this node. 04296 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); 04297 node()->set_attrib(sa->set_instance_count(instance_count)); 04298 } 04299 } 04300 04301 //////////////////////////////////////////////////////////////////// 04302 // Function: NodePath::set_tex_transform 04303 // Access: Published 04304 // Description: Sets the texture matrix on the current node to the 04305 // indicated transform for the given stage. 04306 //////////////////////////////////////////////////////////////////// 04307 void NodePath:: 04308 set_tex_transform(TextureStage *stage, const TransformState *transform) { 04309 nassertv_always(!is_empty()); 04310 04311 const RenderAttrib *attrib = 04312 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 04313 if (attrib != (const RenderAttrib *)NULL) { 04314 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04315 04316 // Modify the existing TexMatrixAttrib to add the indicated 04317 // stage. 04318 node()->set_attrib(tma->add_stage(stage, transform)); 04319 04320 } else { 04321 // Create a new TexMatrixAttrib for this node. 04322 node()->set_attrib(TexMatrixAttrib::make(stage, transform)); 04323 } 04324 } 04325 04326 //////////////////////////////////////////////////////////////////// 04327 // Function: NodePath::clear_tex_transform 04328 // Access: Published 04329 // Description: Removes all texture matrices from the current node. 04330 //////////////////////////////////////////////////////////////////// 04331 void NodePath:: 04332 clear_tex_transform() { 04333 nassertv_always(!is_empty()); 04334 node()->clear_attrib(TexMatrixAttrib::get_class_slot()); 04335 } 04336 04337 //////////////////////////////////////////////////////////////////// 04338 // Function: NodePath::clear_tex_transform 04339 // Access: Published 04340 // Description: Removes the texture matrix on the current node for 04341 // the given stage. 04342 //////////////////////////////////////////////////////////////////// 04343 void NodePath:: 04344 clear_tex_transform(TextureStage *stage) { 04345 nassertv_always(!is_empty()); 04346 04347 const RenderAttrib *attrib = 04348 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 04349 if (attrib != (const RenderAttrib *)NULL) { 04350 CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, attrib); 04351 tma = DCAST(TexMatrixAttrib, tma->remove_stage(stage)); 04352 04353 if (tma->is_empty()) { 04354 node()->clear_attrib(TexMatrixAttrib::get_class_slot()); 04355 04356 } else { 04357 node()->set_attrib(tma); 04358 } 04359 } 04360 } 04361 04362 //////////////////////////////////////////////////////////////////// 04363 // Function: NodePath::has_tex_transform 04364 // Access: Published 04365 // Description: Returns true if there is an explicit texture matrix 04366 // on the current node for the given stage. 04367 //////////////////////////////////////////////////////////////////// 04368 bool NodePath:: 04369 has_tex_transform(TextureStage *stage) const { 04370 nassertr_always(!is_empty(), false); 04371 04372 const RenderAttrib *attrib = 04373 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 04374 if (attrib != (const RenderAttrib *)NULL) { 04375 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04376 return tma->has_stage(stage); 04377 } 04378 04379 return false; 04380 } 04381 04382 //////////////////////////////////////////////////////////////////// 04383 // Function: NodePath::get_tex_transform 04384 // Access: Published 04385 // Description: Returns the texture matrix on the current node for the 04386 // given stage, or identity transform if there is no 04387 // explicit transform set for the given stage. 04388 //////////////////////////////////////////////////////////////////// 04389 CPT(TransformState) NodePath:: 04390 get_tex_transform(TextureStage *stage) const { 04391 nassertr_always(!is_empty(), NULL); 04392 04393 const RenderAttrib *attrib = 04394 node()->get_attrib(TexMatrixAttrib::get_class_slot()); 04395 if (attrib != (const RenderAttrib *)NULL) { 04396 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04397 return tma->get_transform(stage); 04398 } 04399 04400 return TransformState::make_identity(); 04401 } 04402 04403 //////////////////////////////////////////////////////////////////// 04404 // Function: NodePath::set_tex_transform 04405 // Access: Published 04406 // Description: Sets the texture matrix on the current node to the 04407 // indicated transform for the given stage. 04408 //////////////////////////////////////////////////////////////////// 04409 void NodePath:: 04410 set_tex_transform(const NodePath &other, TextureStage *stage, const TransformState *transform) { 04411 nassertv(_error_type == ET_ok && other._error_type == ET_ok); 04412 nassertv_always(!is_empty()); 04413 04414 CPT(RenderState) state = get_state(other); 04415 const RenderAttrib *attrib = 04416 state->get_attrib(TexMatrixAttrib::get_class_slot()); 04417 if (attrib != (const RenderAttrib *)NULL) { 04418 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04419 04420 // Modify the existing TexMatrixAttrib to add the indicated 04421 // stage. 04422 state = state->add_attrib(tma->add_stage(stage, transform)); 04423 04424 } else { 04425 // Create a new TexMatrixAttrib for this node. 04426 state = state->add_attrib(TexMatrixAttrib::make(stage, transform)); 04427 } 04428 04429 // Now compose that with our parent's state. 04430 CPT(RenderState) rel_state; 04431 if (has_parent()) { 04432 rel_state = other.get_state(get_parent()); 04433 } else { 04434 rel_state = other.get_state(NodePath()); 04435 } 04436 CPT(RenderState) new_state = rel_state->compose(state); 04437 04438 // And apply only the TexMatrixAttrib to the current node, leaving 04439 // the others unchanged. 04440 node()->set_attrib(new_state->get_attrib(TexMatrixAttrib::get_class_slot())); 04441 } 04442 04443 //////////////////////////////////////////////////////////////////// 04444 // Function: NodePath::get_tex_transform 04445 // Access: Published 04446 // Description: Returns the texture matrix on the current node for the 04447 // given stage, relative to the other node. 04448 //////////////////////////////////////////////////////////////////// 04449 CPT(TransformState) NodePath:: 04450 get_tex_transform(const NodePath &other, TextureStage *stage) const { 04451 nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity()); 04452 04453 CPT(RenderState) state = get_state(other); 04454 const RenderAttrib *attrib = 04455 state->get_attrib(TexMatrixAttrib::get_class_slot()); 04456 if (attrib != (const RenderAttrib *)NULL) { 04457 const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib); 04458 return tma->get_transform(stage); 04459 } 04460 04461 return TransformState::make_identity(); 04462 } 04463 04464 //////////////////////////////////////////////////////////////////// 04465 // Function: NodePath::set_tex_gen 04466 // Access: Published 04467 // Description: Enables automatic texture coordinate generation for 04468 // the indicated texture stage. 04469 //////////////////////////////////////////////////////////////////// 04470 void NodePath:: 04471 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) { 04472 nassertv_always(!is_empty()); 04473 04474 const RenderAttrib *attrib = 04475 node()->get_attrib(TexGenAttrib::get_class_slot()); 04476 04477 CPT(TexGenAttrib) tga; 04478 04479 if (attrib != (const RenderAttrib *)NULL) { 04480 priority = max(priority, 04481 node()->get_state()->get_override(TextureAttrib::get_class_slot())); 04482 tga = DCAST(TexGenAttrib, attrib); 04483 04484 } else { 04485 tga = DCAST(TexGenAttrib, TexGenAttrib::make()); 04486 } 04487 04488 node()->set_attrib(tga->add_stage(stage, mode), priority); 04489 } 04490 04491 //////////////////////////////////////////////////////////////////// 04492 // Function: NodePath::set_tex_gen 04493 // Access: Published 04494 // Description: Enables automatic texture coordinate generation for 04495 // the indicated texture stage. This version of this 04496 // method is useful when setting M_light_vector, which 04497 // requires the name of the texture coordinate set that 04498 // supplies the tangent and binormal, as well as the 04499 // specific light to generate coordinates for. 04500 //////////////////////////////////////////////////////////////////// 04501 void NodePath:: 04502 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 04503 const string &source_name, const NodePath &light, int priority) { 04504 nassertv_always(!is_empty()); 04505 04506 const RenderAttrib *attrib = 04507 node()->get_attrib(TexGenAttrib::get_class_slot()); 04508 04509 CPT(TexGenAttrib) tga; 04510 04511 if (attrib != (const RenderAttrib *)NULL) { 04512 priority = max(priority, 04513 node()->get_state()->get_override(TextureAttrib::get_class_slot())); 04514 tga = DCAST(TexGenAttrib, attrib); 04515 04516 } else { 04517 tga = DCAST(TexGenAttrib, TexGenAttrib::make()); 04518 } 04519 04520 node()->set_attrib(tga->add_stage(stage, mode, source_name, light), priority); 04521 } 04522 04523 //////////////////////////////////////////////////////////////////// 04524 // Function: NodePath::set_tex_gen 04525 // Access: Published 04526 // Description: Enables automatic texture coordinate generation for 04527 // the indicated texture stage. This version of this 04528 // method is useful when setting M_constant, which 04529 // requires a constant texture coordinate value. 04530 //////////////////////////////////////////////////////////////////// 04531 void NodePath:: 04532 set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, 04533 const LTexCoord3 &constant_value, int priority) { 04534 nassertv_always(!is_empty()); 04535 04536 const RenderAttrib *attrib = 04537 node()->get_attrib(TexGenAttrib::get_class_slot()); 04538 04539 CPT(TexGenAttrib) tga; 04540 04541 if (attrib != (const RenderAttrib *)NULL) { 04542 priority = max(priority, 04543 node()->get_state()->get_override(TextureAttrib::get_class_slot())); 04544 tga = DCAST(TexGenAttrib, attrib); 04545 04546 } else { 04547 tga = DCAST(TexGenAttrib, TexGenAttrib::make()); 04548 } 04549 04550 node()->set_attrib(tga->add_stage(stage, mode, constant_value), priority); 04551 } 04552 04553 //////////////////////////////////////////////////////////////////// 04554 // Function: NodePath::clear_tex_gen 04555 // Access: Published 04556 // Description: Removes the texture coordinate generation mode from 04557 // all texture stages on this node. 04558 //////////////////////////////////////////////////////////////////// 04559 void NodePath:: 04560 clear_tex_gen() { 04561 nassertv_always(!is_empty()); 04562 node()->clear_attrib(TexGenAttrib::get_class_slot()); 04563 } 04564 04565 //////////////////////////////////////////////////////////////////// 04566 // Function: NodePath::clear_tex_gen 04567 // Access: Published 04568 // Description: Disables automatic texture coordinate generation for 04569 // the indicated texture stage. 04570 //////////////////////////////////////////////////////////////////// 04571 void NodePath:: 04572 clear_tex_gen(TextureStage *stage) { 04573 nassertv_always(!is_empty()); 04574 04575 const RenderAttrib *attrib = 04576 node()->get_attrib(TexGenAttrib::get_class_slot()); 04577 if (attrib != (const RenderAttrib *)NULL) { 04578 CPT(TexGenAttrib) tga = DCAST(TexGenAttrib, attrib); 04579 tga = DCAST(TexGenAttrib, tga->remove_stage(stage)); 04580 04581 if (tga->is_empty()) { 04582 node()->clear_attrib(TexGenAttrib::get_class_slot()); 04583 04584 } else { 04585 node()->set_attrib(tga); 04586 } 04587 } 04588 } 04589 04590 //////////////////////////////////////////////////////////////////// 04591 // Function: NodePath::has_tex_gen 04592 // Access: Published 04593 // Description: Returns true if there is a mode for automatic texture 04594 // coordinate generation on the current node for the 04595 // given stage. 04596 //////////////////////////////////////////////////////////////////// 04597 bool NodePath:: 04598 has_tex_gen(TextureStage *stage) const { 04599 nassertr_always(!is_empty(), false); 04600 04601 const RenderAttrib *attrib = 04602 node()->get_attrib(TexGenAttrib::get_class_slot()); 04603 if (attrib != (const RenderAttrib *)NULL) { 04604 const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib); 04605 return tga->has_stage(stage); 04606 } 04607 04608 return false; 04609 } 04610 04611 //////////////////////////////////////////////////////////////////// 04612 // Function: NodePath::get_tex_gen 04613 // Access: Published 04614 // Description: Returns the texture coordinate generation mode for 04615 // the given stage, or M_off if there is no explicit 04616 // mode set for the given stage. 04617 //////////////////////////////////////////////////////////////////// 04618 RenderAttrib::TexGenMode NodePath:: 04619 get_tex_gen(TextureStage *stage) const { 04620 nassertr_always(!is_empty(), TexGenAttrib::M_off); 04621 04622 const RenderAttrib *attrib = 04623 node()->get_attrib(TexGenAttrib::get_class_slot()); 04624 if (attrib != (const RenderAttrib *)NULL) { 04625 const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib); 04626 return tga->get_mode(stage); 04627 } 04628 04629 return TexGenAttrib::M_off; 04630 } 04631 04632 //////////////////////////////////////////////////////////////////// 04633 // Function: NodePath::get_tex_gen_light 04634 // Access: Published 04635 // Description: Returns the particular Light set for the indicated 04636 // texgen mode's texture stage, or empty NodePath if no 04637 // light is set. This is only meaningful if the texgen 04638 // mode (returned by get_tex_gen()) is M_light_vector. 04639 //////////////////////////////////////////////////////////////////// 04640 NodePath NodePath:: 04641 get_tex_gen_light(TextureStage *stage) const { 04642 nassertr_always(!is_empty(), NodePath::fail()); 04643 04644 const RenderAttrib *attrib = 04645 node()->get_attrib(TexGenAttrib::get_class_slot()); 04646 if (attrib != (const RenderAttrib *)NULL) { 04647 const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib); 04648 return tga->get_light(stage); 04649 } 04650 04651 return NodePath(); 04652 } 04653 04654 //////////////////////////////////////////////////////////////////// 04655 // Function: NodePath::set_tex_projector 04656 // Access: Published 04657 // Description: Establishes a TexProjectorEffect on this node, which 04658 // can be used to establish projective texturing (but 04659 // see also the NodePath::project_texture() convenience 04660 // function), or it can be used to bind this node's 04661 // texture transform to particular node's position in 04662 // space, allowing a LerpInterval (for instance) to 04663 // adjust this node's texture coordinates. 04664 //////////////////////////////////////////////////////////////////// 04665 void NodePath:: 04666 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to) { 04667 nassertv_always(!is_empty()); 04668 04669 const RenderEffect *effect = 04670 node()->get_effect(TexProjectorEffect::get_class_type()); 04671 04672 CPT(TexProjectorEffect) tpe; 04673 04674 if (effect != (const RenderEffect *)NULL) { 04675 tpe = DCAST(TexProjectorEffect, effect); 04676 04677 } else { 04678 tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make()); 04679 } 04680 04681 node()->set_effect(tpe->add_stage(stage, from, to)); 04682 } 04683 04684 //////////////////////////////////////////////////////////////////// 04685 // Function: NodePath::clear_tex_projector 04686 // Access: Published 04687 // Description: Removes the TexProjectorEffect for the indicated 04688 // stage from this node. 04689 //////////////////////////////////////////////////////////////////// 04690 void NodePath:: 04691 clear_tex_projector(TextureStage *stage) { 04692 nassertv_always(!is_empty()); 04693 04694 const RenderEffect *effect = 04695 node()->get_effect(TexProjectorEffect::get_class_type()); 04696 if (effect != (const RenderEffect *)NULL) { 04697 CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect); 04698 tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage)); 04699 04700 if (tpe->is_empty()) { 04701 node()->clear_effect(TexProjectorEffect::get_class_type()); 04702 04703 } else { 04704 node()->set_effect(tpe); 04705 } 04706 } 04707 } 04708 04709 //////////////////////////////////////////////////////////////////// 04710 // Function: NodePath::clear_tex_projector 04711 // Access: Published 04712 // Description: Removes the TexProjectorEffect for all stages from 04713 // this node. 04714 //////////////////////////////////////////////////////////////////// 04715 void NodePath:: 04716 clear_tex_projector() { 04717 nassertv_always(!is_empty()); 04718 node()->clear_effect(TexProjectorEffect::get_class_type()); 04719 } 04720 04721 //////////////////////////////////////////////////////////////////// 04722 // Function: NodePath::has_tex_projector 04723 // Access: Published 04724 // Description: Returns true if this node has a TexProjectorEffect 04725 // for the indicated stage, false otherwise. 04726 //////////////////////////////////////////////////////////////////// 04727 bool NodePath:: 04728 has_tex_projector(TextureStage *stage) const { 04729 nassertr_always(!is_empty(), false); 04730 04731 const RenderEffect *effect = 04732 node()->get_effect(TexProjectorEffect::get_class_type()); 04733 if (effect != (const RenderEffect *)NULL) { 04734 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect); 04735 return tpe->has_stage(stage); 04736 } 04737 04738 return false; 04739 } 04740 04741 //////////////////////////////////////////////////////////////////// 04742 // Function: NodePath::get_tex_projector_from 04743 // Access: Published 04744 // Description: Returns the "from" node associated with the 04745 // TexProjectorEffect on the indicated stage. The 04746 // relative transform between the "from" and the "to" 04747 // nodes is automatically applied to the texture 04748 // transform each frame. 04749 //////////////////////////////////////////////////////////////////// 04750 NodePath NodePath:: 04751 get_tex_projector_from(TextureStage *stage) const { 04752 nassertr_always(!is_empty(), NodePath::fail()); 04753 04754 const RenderEffect *effect = 04755 node()->get_effect(TexProjectorEffect::get_class_type()); 04756 if (effect != (const RenderEffect *)NULL) { 04757 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect); 04758 return tpe->get_from(stage); 04759 } 04760 04761 return NodePath::not_found(); 04762 } 04763 04764 //////////////////////////////////////////////////////////////////// 04765 // Function: NodePath::get_tex_projector_to 04766 // Access: Published 04767 // Description: Returns the "to" node associated with the 04768 // TexProjectorEffect on the indicated stage. The 04769 // relative transform between the "from" and the "to" 04770 // nodes is automatically applied to the texture 04771 // transform each frame. 04772 //////////////////////////////////////////////////////////////////// 04773 NodePath NodePath:: 04774 get_tex_projector_to(TextureStage *stage) const { 04775 nassertr_always(!is_empty(), NodePath::fail()); 04776 04777 const RenderEffect *effect = 04778 node()->get_effect(TexProjectorEffect::get_class_type()); 04779 if (effect != (const RenderEffect *)NULL) { 04780 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect); 04781 return tpe->get_to(stage); 04782 } 04783 04784 return NodePath::not_found(); 04785 } 04786 04787 //////////////////////////////////////////////////////////////////// 04788 // Function: NodePath::project_texture 04789 // Access: Published 04790 // Description: A convenience function to enable projective texturing 04791 // at this node level and below, using the indicated 04792 // NodePath (which should contain a LensNode) as the 04793 // projector. 04794 //////////////////////////////////////////////////////////////////// 04795 void NodePath:: 04796 project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) { 04797 nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type())); 04798 set_texture(stage, tex); 04799 set_tex_gen(stage, TexGenAttrib::M_world_position); 04800 set_tex_projector(stage, NodePath(), projector); 04801 } 04802 04803 04804 //////////////////////////////////////////////////////////////////// 04805 // Function: NodePath::set_normal_map 04806 // Access: Published 04807 // Description: A convenience function to set up a normal map on this 04808 // geometry. This uses the single highest-priority 04809 // light on the object only. It also requires 04810 // multitexture, and consumes at least two texture 04811 // stages, in addition to what may already be in use. 04812 // 04813 // The normal_map parameter is the texture that contains 04814 // the normal map information (with a 3-d delta vector 04815 // encoded into the r,g,b of each texel). texcoord_name is 04816 // the name of the texture coordinate set that contains 04817 // the tangent and binormal we wish to use. If 04818 // preserve_color is true, then one additional texture 04819 // stage is consumed to blend in the geometry's original 04820 // vertex color. 04821 // 04822 // Only one normal map may be in effect through this 04823 // interface at any given time. 04824 //////////////////////////////////////////////////////////////////// 04825 void NodePath:: 04826 set_normal_map(Texture *normal_map, const string &texcoord_name, 04827 bool preserve_color) { 04828 clear_normal_map(); 04829 04830 // First, we apply the normal map itself, to the bottom layer. 04831 PT(TextureStage) normal_map_ts = new TextureStage("__normal_map"); 04832 normal_map_ts->set_texcoord_name(texcoord_name); 04833 normal_map_ts->set_sort(-20); 04834 normal_map_ts->set_mode(TextureStage::M_replace); 04835 set_texture(normal_map_ts, normal_map); 04836 04837 // Then, we apply a normalization map, to normalize, per-pixel, the 04838 // vector to the light. 04839 PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32); 04840 PT(TextureStage) normalization_map_ts = new TextureStage("__normalization_map"); 04841 normalization_map_ts->set_combine_rgb 04842 (TextureStage::CM_dot3_rgb, 04843 TextureStage::CS_texture, TextureStage::CO_src_color, 04844 TextureStage::CS_previous, TextureStage::CO_src_color); 04845 normalization_map_ts->set_texcoord_name("light_vector"); 04846 normalization_map_ts->set_sort(-15); 04847 set_texture(normalization_map_ts, normalization_map); 04848 04849 // Finally, we enable M_light_vector texture coordinate generation. 04850 set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector, 04851 texcoord_name, NodePath()); 04852 04853 if (preserve_color) { 04854 // One more stage to get back the original color. 04855 PT(TextureStage) orig_color_ts = new TextureStage("__orig_color"); 04856 orig_color_ts->set_combine_rgb 04857 (TextureStage::CM_modulate, 04858 TextureStage::CS_primary_color, TextureStage::CO_src_color, 04859 TextureStage::CS_previous, TextureStage::CO_src_color); 04860 set_texture(orig_color_ts, normal_map); 04861 } 04862 } 04863 04864 //////////////////////////////////////////////////////////////////// 04865 // Function: NodePath::clear_normal_map 04866 // Access: Published 04867 // Description: Undoes the effect of a previous call to 04868 // set_normal_map(). 04869 //////////////////////////////////////////////////////////////////// 04870 void NodePath:: 04871 clear_normal_map() { 04872 // Scan through the TextureStages, and if we find any whose name 04873 // matches one of the stages that would have been left by 04874 // set_normal_map(), remove it from the state. 04875 04876 CPT(RenderAttrib) attrib = 04877 get_state()->get_attrib(TextureAttrib::get_class_slot()); 04878 if (attrib != (const RenderAttrib *)NULL) { 04879 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 04880 for (int i = 0; i < ta->get_num_on_stages(); i++) { 04881 TextureStage *stage = ta->get_on_stage(i); 04882 if (stage->get_name() == "__normal_map") { 04883 clear_texture(stage); 04884 04885 } else if (stage->get_name() == "__normalization_map") { 04886 clear_texture(stage); 04887 clear_tex_gen(stage); 04888 04889 } else if (stage->get_name() == "__orig_color") { 04890 clear_texture(stage); 04891 } 04892 } 04893 } 04894 } 04895 04896 //////////////////////////////////////////////////////////////////// 04897 // Function: NodePath::has_vertex_column 04898 // Access: Published 04899 // Description: Returns true if there are at least some vertices at 04900 // this node and below that contain a reference to the 04901 // indicated vertex data column name, false otherwise. 04902 // 04903 // This is particularly useful for testing whether a 04904 // particular model has a given texture coordinate set 04905 // (but see has_texcoord()). 04906 //////////////////////////////////////////////////////////////////// 04907 bool NodePath:: 04908 has_vertex_column(const InternalName *name) const { 04909 nassertr_always(!is_empty(), false); 04910 return r_has_vertex_column(node(), name); 04911 } 04912 04913 //////////////////////////////////////////////////////////////////// 04914 // Function: NodePath::find_all_vertex_columns 04915 // Access: Published 04916 // Description: Returns a list of all vertex array columns stored on 04917 // some geometry found at this node level and below. 04918 //////////////////////////////////////////////////////////////////// 04919 InternalNameCollection NodePath:: 04920 find_all_vertex_columns() const { 04921 nassertr_always(!is_empty(), InternalNameCollection()); 04922 InternalNames vertex_columns; 04923 r_find_all_vertex_columns(node(), vertex_columns); 04924 04925 InternalNameCollection tc; 04926 InternalNames::iterator ti; 04927 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 04928 tc.add_name(*ti); 04929 } 04930 return tc; 04931 } 04932 04933 //////////////////////////////////////////////////////////////////// 04934 // Function: NodePath::find_all_vertex_columns 04935 // Access: Published 04936 // Description: Returns a list of all vertex array columns stored on 04937 // some geometry found at this node level and below that 04938 // match the indicated name (which may contain wildcard 04939 // characters). 04940 //////////////////////////////////////////////////////////////////// 04941 InternalNameCollection NodePath:: 04942 find_all_vertex_columns(const string &name) const { 04943 nassertr_always(!is_empty(), InternalNameCollection()); 04944 InternalNames vertex_columns; 04945 r_find_all_vertex_columns(node(), vertex_columns); 04946 04947 GlobPattern glob(name); 04948 04949 InternalNameCollection tc; 04950 InternalNames::iterator ti; 04951 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 04952 InternalName *name = (*ti); 04953 if (glob.matches(name->get_name())) { 04954 tc.add_name(name); 04955 } 04956 } 04957 return tc; 04958 } 04959 04960 //////////////////////////////////////////////////////////////////// 04961 // Function: NodePath::find_all_texcoords 04962 // Access: Published 04963 // Description: Returns a list of all texture coordinate sets used by 04964 // any geometry at this node level and below. 04965 //////////////////////////////////////////////////////////////////// 04966 InternalNameCollection NodePath:: 04967 find_all_texcoords() const { 04968 nassertr_always(!is_empty(), InternalNameCollection()); 04969 InternalNames vertex_columns; 04970 r_find_all_vertex_columns(node(), vertex_columns); 04971 04972 CPT(InternalName) texcoord_name = InternalName::get_texcoord(); 04973 04974 InternalNameCollection tc; 04975 InternalNames::iterator ti; 04976 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 04977 if ((*ti)->get_top() == texcoord_name) { 04978 tc.add_name(*ti); 04979 } 04980 } 04981 return tc; 04982 } 04983 04984 //////////////////////////////////////////////////////////////////// 04985 // Function: NodePath::find_all_texcoords 04986 // Access: Published 04987 // Description: Returns a list of all texture coordinate sets used by 04988 // any geometry at this node level and below that match 04989 // the indicated name (which may contain wildcard 04990 // characters). 04991 //////////////////////////////////////////////////////////////////// 04992 InternalNameCollection NodePath:: 04993 find_all_texcoords(const string &name) const { 04994 nassertr_always(!is_empty(), InternalNameCollection()); 04995 InternalNames vertex_columns; 04996 r_find_all_vertex_columns(node(), vertex_columns); 04997 04998 GlobPattern glob(name); 04999 CPT(InternalName) texcoord_name = InternalName::get_texcoord(); 05000 05001 InternalNameCollection tc; 05002 InternalNames::iterator ti; 05003 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { 05004 InternalName *name = (*ti); 05005 if (name->get_top() == texcoord_name) { 05006 // This is a texture coordinate name. Figure out the basename 05007 // of the texture coordinates. 05008 int index = name->find_ancestor("texcoord"); 05009 nassertr(index != -1, InternalNameCollection()); 05010 string net_basename = name->get_net_basename(index - 1); 05011 05012 if (glob.matches(net_basename)) { 05013 tc.add_name(name); 05014 } 05015 } 05016 } 05017 return tc; 05018 } 05019 05020 //////////////////////////////////////////////////////////////////// 05021 // Function: NodePath::find_texture 05022 // Access: Published 05023 // Description: Returns the first texture found applied to geometry 05024 // at this node or below that matches the indicated name 05025 // (which may contain wildcards). Returns the texture 05026 // if it is found, or NULL if it is not. 05027 //////////////////////////////////////////////////////////////////// 05028 Texture *NodePath:: 05029 find_texture(const string &name) const { 05030 nassertr_always(!is_empty(), NULL); 05031 GlobPattern glob(name); 05032 return r_find_texture(node(), get_net_state(), glob); 05033 } 05034 05035 //////////////////////////////////////////////////////////////////// 05036 // Function: NodePath::find_texture 05037 // Access: Published 05038 // Description: Returns the first texture found applied to geometry 05039 // at this node or below that is assigned to the 05040 // indicated texture stage. Returns the texture if it 05041 // is found, or NULL if it is not. 05042 //////////////////////////////////////////////////////////////////// 05043 Texture *NodePath:: 05044 find_texture(TextureStage *stage) const { 05045 nassertr_always(!is_empty(), NULL); 05046 return r_find_texture(node(), stage); 05047 } 05048 05049 //////////////////////////////////////////////////////////////////// 05050 // Function: NodePath::find_all_textures 05051 // Access: Published 05052 // Description: Returns a list of a textures applied to geometry at 05053 // this node and below. 05054 //////////////////////////////////////////////////////////////////// 05055 TextureCollection NodePath:: 05056 find_all_textures() const { 05057 nassertr_always(!is_empty(), TextureCollection()); 05058 Textures textures; 05059 r_find_all_textures(node(), get_net_state(), textures); 05060 05061 TextureCollection tc; 05062 Textures::iterator ti; 05063 for (ti = textures.begin(); ti != textures.end(); ++ti) { 05064 tc.add_texture(*ti); 05065 } 05066 return tc; 05067 } 05068 05069 //////////////////////////////////////////////////////////////////// 05070 // Function: NodePath::find_all_textures 05071 // Access: Published 05072 // Description: Returns a list of a textures applied to geometry at 05073 // this node and below that match the indicated name 05074 // (which may contain wildcard characters). 05075 //////////////////////////////////////////////////////////////////// 05076 TextureCollection NodePath:: 05077 find_all_textures(const string &name) const { 05078 nassertr_always(!is_empty(), TextureCollection()); 05079 Textures textures; 05080 r_find_all_textures(node(), get_net_state(), textures); 05081 05082 GlobPattern glob(name); 05083 05084 TextureCollection tc; 05085 Textures::iterator ti; 05086 for (ti = textures.begin(); ti != textures.end(); ++ti) { 05087 Texture *texture = (*ti); 05088 if (glob.matches(texture->get_name())) { 05089 tc.add_texture(texture); 05090 } 05091 } 05092 return tc; 05093 } 05094 05095 //////////////////////////////////////////////////////////////////// 05096 // Function: NodePath::find_all_textures 05097 // Access: Published 05098 // Description: Returns a list of a textures on geometry at 05099 // this node and below that are assigned to the 05100 // indicated texture stage. 05101 //////////////////////////////////////////////////////////////////// 05102 TextureCollection NodePath:: 05103 find_all_textures(TextureStage *stage) const { 05104 nassertr_always(!is_empty(), TextureCollection()); 05105 Textures textures; 05106 r_find_all_textures(node(), stage, textures); 05107 05108 TextureCollection tc; 05109 Textures::iterator ti; 05110 for (ti = textures.begin(); ti != textures.end(); ++ti) { 05111 Texture *texture = (*ti); 05112 tc.add_texture(texture); 05113 } 05114 return tc; 05115 } 05116 05117 //////////////////////////////////////////////////////////////////// 05118 // Function: NodePath::find_texture_stage 05119 // Access: Published 05120 // Description: Returns the first TextureStage found applied to 05121 // geometry at this node or below that matches the 05122 // indicated name (which may contain wildcards). 05123 // Returns the TextureStage if it is found, or NULL if 05124 // it is not. 05125 //////////////////////////////////////////////////////////////////// 05126 TextureStage *NodePath:: 05127 find_texture_stage(const string &name) const { 05128 nassertr_always(!is_empty(), NULL); 05129 GlobPattern glob(name); 05130 return r_find_texture_stage(node(), get_net_state(), glob); 05131 } 05132 05133 //////////////////////////////////////////////////////////////////// 05134 // Function: NodePath::find_all_texture_stages 05135 // Access: Published 05136 // Description: Returns a list of a TextureStages applied to geometry 05137 // at this node and below. 05138 //////////////////////////////////////////////////////////////////// 05139 TextureStageCollection NodePath:: 05140 find_all_texture_stages() const { 05141 nassertr_always(!is_empty(), TextureStageCollection()); 05142 TextureStages texture_stages; 05143 r_find_all_texture_stages(node(), get_net_state(), texture_stages); 05144 05145 TextureStageCollection tc; 05146 TextureStages::iterator ti; 05147 for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) { 05148 tc.add_texture_stage(*ti); 05149 } 05150 return tc; 05151 } 05152 05153 //////////////////////////////////////////////////////////////////// 05154 // Function: NodePath::unify_texture_stages 05155 // Access: Published 05156 // Description: Searches through all TextureStages at this node and 05157 // below. Any TextureStages that share the same name as 05158 // the indicated TextureStage object are replaced with 05159 // this object, thus ensuring that all geometry at this 05160 // node and below with a particular TextureStage name is 05161 // using the same TextureStage object. 05162 //////////////////////////////////////////////////////////////////// 05163 void NodePath:: 05164 unify_texture_stages(TextureStage *stage) { 05165 nassertv_always(!is_empty()); 05166 r_unify_texture_stages(node(), stage); 05167 } 05168 05169 //////////////////////////////////////////////////////////////////// 05170 // Function: NodePath::find_all_texture_stages 05171 // Access: Published 05172 // Description: Returns a list of a TextureStages applied to geometry 05173 // at this node and below that match the indicated name 05174 // (which may contain wildcard characters). 05175 //////////////////////////////////////////////////////////////////// 05176 TextureStageCollection NodePath:: 05177 find_all_texture_stages(const string &name) const { 05178 nassertr_always(!is_empty(), TextureStageCollection()); 05179 TextureStages texture_stages; 05180 r_find_all_texture_stages(node(), get_net_state(), texture_stages); 05181 05182 GlobPattern glob(name); 05183 05184 TextureStageCollection tc; 05185 TextureStages::iterator ti; 05186 for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) { 05187 TextureStage *texture_stage = (*ti); 05188 if (glob.matches(texture_stage->get_name())) { 05189 tc.add_texture_stage(texture_stage); 05190 } 05191 } 05192 return tc; 05193 } 05194 05195 //////////////////////////////////////////////////////////////////// 05196 // Function: NodePath::find_material 05197 // Access: Published 05198 // Description: Returns the first material found applied to geometry 05199 // at this node or below that matches the indicated name 05200 // (which may contain wildcards). Returns the material 05201 // if it is found, or NULL if it is not. 05202 //////////////////////////////////////////////////////////////////// 05203 Material *NodePath:: 05204 find_material(const string &name) const { 05205 nassertr_always(!is_empty(), NULL); 05206 GlobPattern glob(name); 05207 return r_find_material(node(), get_net_state(), glob); 05208 } 05209 05210 //////////////////////////////////////////////////////////////////// 05211 // Function: NodePath::find_all_materials 05212 // Access: Published 05213 // Description: Returns a list of a materials applied to geometry at 05214 // this node and below. 05215 //////////////////////////////////////////////////////////////////// 05216 MaterialCollection NodePath:: 05217 find_all_materials() const { 05218 nassertr_always(!is_empty(), MaterialCollection()); 05219 Materials materials; 05220 r_find_all_materials(node(), get_net_state(), materials); 05221 05222 MaterialCollection tc; 05223 Materials::iterator ti; 05224 for (ti = materials.begin(); ti != materials.end(); ++ti) { 05225 tc.add_material(*ti); 05226 } 05227 return tc; 05228 } 05229 05230 //////////////////////////////////////////////////////////////////// 05231 // Function: NodePath::find_all_materials 05232 // Access: Published 05233 // Description: Returns a list of a materials applied to geometry at 05234 // this node and below that match the indicated name 05235 // (which may contain wildcard characters). 05236 //////////////////////////////////////////////////////////////////// 05237 MaterialCollection NodePath:: 05238 find_all_materials(const string &name) const { 05239 nassertr_always(!is_empty(), MaterialCollection()); 05240 Materials materials; 05241 r_find_all_materials(node(), get_net_state(), materials); 05242 05243 GlobPattern glob(name); 05244 05245 MaterialCollection tc; 05246 Materials::iterator ti; 05247 for (ti = materials.begin(); ti != materials.end(); ++ti) { 05248 Material *material = (*ti); 05249 if (glob.matches(material->get_name())) { 05250 tc.add_material(material); 05251 } 05252 } 05253 return tc; 05254 } 05255 05256 //////////////////////////////////////////////////////////////////// 05257 // Function: NodePath::set_material 05258 // Access: Published 05259 // Description: Sets the geometry at this level and below to render 05260 // using the indicated material. 05261 // 05262 // Previously, this operation made a copy of the 05263 // material structure, but nowadays it assigns the 05264 // pointer directly. 05265 //////////////////////////////////////////////////////////////////// 05266 void NodePath:: 05267 set_material(Material *mat, int priority) { 05268 nassertv_always(!is_empty()); 05269 nassertv(mat != NULL); 05270 node()->set_attrib(MaterialAttrib::make(mat), priority); 05271 } 05272 05273 //////////////////////////////////////////////////////////////////// 05274 // Function: NodePath::set_material_off 05275 // Access: Published 05276 // Description: Sets the geometry at this level and below to render 05277 // using no material. This is normally the default, but 05278 // it may be useful to use this to contradict 05279 // set_material() at a higher node level (or, with a 05280 // priority, to override a set_material() at a lower 05281 // level). 05282 //////////////////////////////////////////////////////////////////// 05283 void NodePath:: 05284 set_material_off(int priority) { 05285 nassertv_always(!is_empty()); 05286 node()->set_attrib(MaterialAttrib::make_off(), priority); 05287 } 05288 05289 //////////////////////////////////////////////////////////////////// 05290 // Function: NodePath::clear_material 05291 // Access: Published 05292 // Description: Completely removes any material adjustment that may 05293 // have been set via set_material() from this particular 05294 // node. 05295 //////////////////////////////////////////////////////////////////// 05296 void NodePath:: 05297 clear_material() { 05298 nassertv_always(!is_empty()); 05299 node()->clear_attrib(MaterialAttrib::get_class_slot()); 05300 } 05301 05302 //////////////////////////////////////////////////////////////////// 05303 // Function: NodePath::has_material 05304 // Access: Published 05305 // Description: Returns true if a material has been applied to this 05306 // particular node via set_material(), false otherwise. 05307 //////////////////////////////////////////////////////////////////// 05308 bool NodePath:: 05309 has_material() const { 05310 nassertr_always(!is_empty(), false); 05311 const RenderAttrib *attrib = 05312 node()->get_attrib(MaterialAttrib::get_class_slot()); 05313 if (attrib != (const RenderAttrib *)NULL) { 05314 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib); 05315 return !ma->is_off(); 05316 } 05317 05318 return false; 05319 } 05320 05321 //////////////////////////////////////////////////////////////////// 05322 // Function: NodePath::get_material 05323 // Access: Published 05324 // Description: Returns the material that has been set on this 05325 // particular node, or NULL if no material has been set. 05326 // This is not necessarily the material that will be 05327 // applied to the geometry at or below this level, as 05328 // another material at a higher or lower level may 05329 // override. 05330 05331 // See also find_material(). 05332 //////////////////////////////////////////////////////////////////// 05333 PT(Material) NodePath:: 05334 get_material() const { 05335 nassertr_always(!is_empty(), NULL); 05336 const RenderAttrib *attrib = 05337 node()->get_attrib(MaterialAttrib::get_class_slot()); 05338 if (attrib != (const RenderAttrib *)NULL) { 05339 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib); 05340 return ma->get_material(); 05341 } 05342 05343 return NULL; 05344 } 05345 05346 //////////////////////////////////////////////////////////////////// 05347 // Function: NodePath::set_fog 05348 // Access: Published 05349 // Description: Sets the geometry at this level and below to render 05350 // using the indicated fog. 05351 //////////////////////////////////////////////////////////////////// 05352 void NodePath:: 05353 set_fog(Fog *fog, int priority) { 05354 nassertv_always(!is_empty()); 05355 node()->set_attrib(FogAttrib::make(fog), priority); 05356 } 05357 05358 //////////////////////////////////////////////////////////////////// 05359 // Function: NodePath::set_fog_off 05360 // Access: Published 05361 // Description: Sets the geometry at this level and below to render 05362 // using no fog. This is normally the default, but 05363 // it may be useful to use this to contradict 05364 // set_fog() at a higher node level (or, with a 05365 // priority, to override a set_fog() at a lower 05366 // level). 05367 //////////////////////////////////////////////////////////////////// 05368 void NodePath:: 05369 set_fog_off(int priority) { 05370 nassertv_always(!is_empty()); 05371 node()->set_attrib(FogAttrib::make_off(), priority); 05372 } 05373 05374 //////////////////////////////////////////////////////////////////// 05375 // Function: NodePath::clear_fog 05376 // Access: Published 05377 // Description: Completely removes any fog adjustment that may 05378 // have been set via set_fog() or set_fog_off() 05379 // from this particular node. This allows whatever 05380 // fogs might be otherwise affecting the geometry to 05381 // show instead. 05382 //////////////////////////////////////////////////////////////////// 05383 void NodePath:: 05384 clear_fog() { 05385 nassertv_always(!is_empty()); 05386 node()->clear_attrib(FogAttrib::get_class_slot()); 05387 } 05388 05389 //////////////////////////////////////////////////////////////////// 05390 // Function: NodePath::has_fog 05391 // Access: Published 05392 // Description: Returns true if a fog has been applied to this 05393 // particular node via set_fog(), false otherwise. 05394 // This is not the same thing as asking whether the 05395 // geometry at this node will be rendered with 05396 // fog, as there may be a fog in effect from a higher or 05397 // lower level. 05398 //////////////////////////////////////////////////////////////////// 05399 bool NodePath:: 05400 has_fog() const { 05401 nassertr_always(!is_empty(), false); 05402 const RenderAttrib *attrib = 05403 node()->get_attrib(FogAttrib::get_class_slot()); 05404 if (attrib != (const RenderAttrib *)NULL) { 05405 const FogAttrib *fa = DCAST(FogAttrib, attrib); 05406 return !fa->is_off(); 05407 } 05408 05409 return false; 05410 } 05411 05412 //////////////////////////////////////////////////////////////////// 05413 // Function: NodePath::has_fog_off 05414 // Access: Published 05415 // Description: Returns true if a fog has been specifically 05416 // disabled on this particular node via 05417 // set_fog_off(), false otherwise. This is not the 05418 // same thing as asking whether the geometry at this 05419 // node will be rendered unfogged, as there may be a 05420 // fog in effect from a higher or lower level. 05421 //////////////////////////////////////////////////////////////////// 05422 bool NodePath:: 05423 has_fog_off() const { 05424 nassertr_always(!is_empty(), false); 05425 const RenderAttrib *attrib = 05426 node()->get_attrib(FogAttrib::get_class_slot()); 05427 if (attrib != (const RenderAttrib *)NULL) { 05428 const FogAttrib *fa = DCAST(FogAttrib, attrib); 05429 return fa->is_off(); 05430 } 05431 05432 return false; 05433 } 05434 05435 //////////////////////////////////////////////////////////////////// 05436 // Function: NodePath::get_fog 05437 // Access: Published 05438 // Description: Returns the fog that has been set on this 05439 // particular node, or NULL if no fog has been set. 05440 // This is not necessarily the fog that will be 05441 // applied to the geometry at or below this level, as 05442 // another fog at a higher or lower level may 05443 // override. 05444 //////////////////////////////////////////////////////////////////// 05445 Fog *NodePath:: 05446 get_fog() const { 05447 nassertr_always(!is_empty(), NULL); 05448 const RenderAttrib *attrib = 05449 node()->get_attrib(FogAttrib::get_class_slot()); 05450 if (attrib != (const RenderAttrib *)NULL) { 05451 const FogAttrib *fa = DCAST(FogAttrib, attrib); 05452 return fa->get_fog(); 05453 } 05454 05455 return NULL; 05456 } 05457 05458 //////////////////////////////////////////////////////////////////// 05459 // Function: NodePath::set_render_mode_wireframe 05460 // Access: Published 05461 // Description: Sets up the geometry at this level and below (unless 05462 // overridden) to render in wireframe mode. 05463 //////////////////////////////////////////////////////////////////// 05464 void NodePath:: 05465 set_render_mode_wireframe(int priority) { 05466 nassertv_always(!is_empty()); 05467 PN_stdfloat thickness = get_render_mode_thickness(); 05468 bool perspective = get_render_mode_perspective(); 05469 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, thickness, perspective), priority); 05470 } 05471 05472 //////////////////////////////////////////////////////////////////// 05473 // Function: NodePath::set_render_mode_filled 05474 // Access: Published 05475 // Description: Sets up the geometry at this level and below (unless 05476 // overridden) to render in filled (i.e. not wireframe) 05477 // mode. 05478 //////////////////////////////////////////////////////////////////// 05479 void NodePath:: 05480 set_render_mode_filled(int priority) { 05481 nassertv_always(!is_empty()); 05482 PN_stdfloat thickness = get_render_mode_thickness(); 05483 bool perspective = get_render_mode_perspective(); 05484 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority); 05485 } 05486 05487 //////////////////////////////////////////////////////////////////// 05488 // Function: NodePath::set_render_mode_perspective 05489 // Access: Published 05490 // Description: Sets up the point geometry at this level and below to 05491 // render as perspective sprites (that is, billboarded 05492 // quads). The thickness, as specified with 05493 // set_render_mode_thickness(), is the width of each 05494 // point in 3-D units, unless it is overridden on a 05495 // per-vertex basis. This does not affect geometry 05496 // other than points. 05497 // 05498 // If you want the quads to be individually textured, 05499 // you should also set a TexGenAttrib::M_point_sprite on 05500 // the node. 05501 //////////////////////////////////////////////////////////////////// 05502 void NodePath:: 05503 set_render_mode_perspective(bool perspective, int priority) { 05504 nassertv_always(!is_empty()); 05505 RenderModeAttrib::Mode mode = get_render_mode(); 05506 PN_stdfloat thickness = get_render_mode_thickness(); 05507 node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority); 05508 } 05509 05510 //////////////////////////////////////////////////////////////////// 05511 // Function: NodePath::set_render_mode_thickness 05512 // Access: Published 05513 // Description: Sets up the point geometry at this level and below to 05514 // render as thick points (that is, billboarded 05515 // quads). The thickness is in pixels, unless 05516 // set_render_mode_perspective is also true, in which 05517 // case it is in 3-D units. 05518 // 05519 // If you want the quads to be individually textured, 05520 // you should also set a TexGenAttrib::M_point_sprite on 05521 // the node. 05522 //////////////////////////////////////////////////////////////////// 05523 void NodePath:: 05524 set_render_mode_thickness(PN_stdfloat thickness, int priority) { 05525 nassertv_always(!is_empty()); 05526 RenderModeAttrib::Mode mode = get_render_mode(); 05527 bool perspective = get_render_mode_perspective(); 05528 node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority); 05529 } 05530 05531 //////////////////////////////////////////////////////////////////// 05532 // Function: NodePath::set_render_mode 05533 // Access: Published 05534 // Description: Sets up the geometry at this level and below (unless 05535 // overridden) to render in the specified mode and with 05536 // the indicated line and/or point thickness. 05537 //////////////////////////////////////////////////////////////////// 05538 void NodePath:: 05539 set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority) { 05540 nassertv_always(!is_empty()); 05541 05542 node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority); 05543 } 05544 05545 //////////////////////////////////////////////////////////////////// 05546 // Function: NodePath::clear_render_mode 05547 // Access: Published 05548 // Description: Completely removes any render mode adjustment that 05549 // may have been set on this node via 05550 // set_render_mode_wireframe() or 05551 // set_render_mode_filled(). 05552 //////////////////////////////////////////////////////////////////// 05553 void NodePath:: 05554 clear_render_mode() { 05555 nassertv_always(!is_empty()); 05556 node()->clear_attrib(RenderModeAttrib::get_class_slot()); 05557 } 05558 05559 //////////////////////////////////////////////////////////////////// 05560 // Function: NodePath::has_render_mode 05561 // Access: Published 05562 // Description: Returns true if a render mode has been explicitly set 05563 // on this particular node via set_render_mode() (or 05564 // set_render_mode_wireframe() or 05565 // set_render_mode_filled()), false otherwise. 05566 //////////////////////////////////////////////////////////////////// 05567 bool NodePath:: 05568 has_render_mode() const { 05569 nassertr_always(!is_empty(), false); 05570 return node()->has_attrib(RenderModeAttrib::get_class_slot()); 05571 } 05572 05573 //////////////////////////////////////////////////////////////////// 05574 // Function: NodePath::get_render_mode 05575 // Access: Published 05576 // Description: Returns the render mode that has been specifically 05577 // set on this node via set_render_mode(), or 05578 // M_unchanged if nothing has been set. 05579 //////////////////////////////////////////////////////////////////// 05580 RenderModeAttrib::Mode NodePath:: 05581 get_render_mode() const { 05582 nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged); 05583 const RenderAttrib *attrib = 05584 node()->get_attrib(RenderModeAttrib::get_class_slot()); 05585 if (attrib != (const RenderAttrib *)NULL) { 05586 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib); 05587 return ta->get_mode(); 05588 } 05589 05590 return RenderModeAttrib::M_unchanged; 05591 } 05592 05593 //////////////////////////////////////////////////////////////////// 05594 // Function: NodePath::get_render_mode_thickness 05595 // Access: Published 05596 // Description: Returns the render mode thickness that has been 05597 // specifically set on this node via set_render_mode(), 05598 // or 1.0 if nothing has been set. 05599 //////////////////////////////////////////////////////////////////// 05600 PN_stdfloat NodePath:: 05601 get_render_mode_thickness() const { 05602 nassertr_always(!is_empty(), 0.0f); 05603 const RenderAttrib *attrib = 05604 node()->get_attrib(RenderModeAttrib::get_class_slot()); 05605 if (attrib != (const RenderAttrib *)NULL) { 05606 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib); 05607 return ta->get_thickness(); 05608 } 05609 05610 return 1.0f; 05611 } 05612 05613 //////////////////////////////////////////////////////////////////// 05614 // Function: NodePath::get_render_mode_perspective 05615 // Access: Published 05616 // Description: Returns the flag that has been set on this node via 05617 // set_render_mode_perspective(), or false if no flag 05618 // has been set. 05619 //////////////////////////////////////////////////////////////////// 05620 bool NodePath:: 05621 get_render_mode_perspective() const { 05622 nassertr_always(!is_empty(), 0.0f); 05623 const RenderAttrib *attrib = 05624 node()->get_attrib(RenderModeAttrib::get_class_slot()); 05625 if (attrib != (const RenderAttrib *)NULL) { 05626 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib); 05627 return ta->get_perspective(); 05628 } 05629 05630 return false; 05631 } 05632 05633 //////////////////////////////////////////////////////////////////// 05634 // Function: NodePath::set_two_sided 05635 // Access: Published 05636 // Description: Specifically sets or disables two-sided rendering 05637 // mode on this particular node. If no other nodes 05638 // override, this will cause backfacing polygons to be 05639 // drawn (in two-sided mode, true) or culled (in 05640 // one-sided mode, false). 05641 //////////////////////////////////////////////////////////////////// 05642 void NodePath:: 05643 set_two_sided(bool two_sided, int priority) { 05644 nassertv_always(!is_empty()); 05645 05646 CullFaceAttrib::Mode mode = 05647 two_sided ? 05648 CullFaceAttrib::M_cull_none : 05649 CullFaceAttrib::M_cull_clockwise; 05650 05651 node()->set_attrib(CullFaceAttrib::make(mode), priority); 05652 } 05653 05654 //////////////////////////////////////////////////////////////////// 05655 // Function: NodePath::clear_two_sided 05656 // Access: Published 05657 // Description: Completely removes any two-sided adjustment that 05658 // may have been set on this node via set_two_sided(). 05659 // The geometry at this level and below will 05660 // subsequently be rendered either two-sided or 05661 // one-sided, according to whatever other nodes may have 05662 // had set_two_sided() on it, or according to the 05663 // initial state otherwise. 05664 //////////////////////////////////////////////////////////////////// 05665 void NodePath:: 05666 clear_two_sided() { 05667 nassertv_always(!is_empty()); 05668 node()->clear_attrib(CullFaceAttrib::get_class_slot()); 05669 } 05670 05671 //////////////////////////////////////////////////////////////////// 05672 // Function: NodePath::has_two_sided 05673 // Access: Published 05674 // Description: Returns true if a two-sided adjustment has been 05675 // explicitly set on this particular node via 05676 // set_two_sided(). If this returns true, then 05677 // get_two_sided() may be called to determine which has 05678 // been set. 05679 //////////////////////////////////////////////////////////////////// 05680 bool NodePath:: 05681 has_two_sided() const { 05682 nassertr_always(!is_empty(), false); 05683 return node()->has_attrib(CullFaceAttrib::get_class_slot()); 05684 } 05685 05686 //////////////////////////////////////////////////////////////////// 05687 // Function: NodePath::get_two_sided 05688 // Access: Published 05689 // Description: Returns true if two-sided rendering has been 05690 // specifically set on this node via set_two_sided(), or 05691 // false if one-sided rendering has been specifically 05692 // set, or if nothing has been specifically set. See 05693 // also has_two_sided(). This does not necessarily 05694 // imply that the geometry will or will not be rendered 05695 // two-sided, as there may be other nodes that override. 05696 //////////////////////////////////////////////////////////////////// 05697 bool NodePath:: 05698 get_two_sided() const { 05699 nassertr_always(!is_empty(), false); 05700 const RenderAttrib *attrib = 05701 node()->get_attrib(CullFaceAttrib::get_class_slot()); 05702 if (attrib != (const RenderAttrib *)NULL) { 05703 const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib); 05704 return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none); 05705 } 05706 05707 return false; 05708 } 05709 05710 //////////////////////////////////////////////////////////////////// 05711 // Function: NodePath::set_depth_test 05712 // Access: Published 05713 // Description: Specifically sets or disables the testing of the 05714 // depth buffer on this particular node. This is 05715 // normally on in the 3-d scene graph and off in the 2-d 05716 // scene graph; it should be on for rendering most 3-d 05717 // objects properly. 05718 //////////////////////////////////////////////////////////////////// 05719 void NodePath:: 05720 set_depth_test(bool depth_test, int priority) { 05721 nassertv_always(!is_empty()); 05722 05723 DepthTestAttrib::PandaCompareFunc mode = 05724 depth_test ? 05725 DepthTestAttrib::M_less : 05726 DepthTestAttrib::M_none; 05727 05728 node()->set_attrib(DepthTestAttrib::make(mode), priority); 05729 } 05730 05731 //////////////////////////////////////////////////////////////////// 05732 // Function: NodePath::clear_depth_test 05733 // Access: Published 05734 // Description: Completely removes any depth-test adjustment that 05735 // may have been set on this node via set_depth_test(). 05736 //////////////////////////////////////////////////////////////////// 05737 void NodePath:: 05738 clear_depth_test() { 05739 nassertv_always(!is_empty()); 05740 node()->clear_attrib(DepthTestAttrib::get_class_slot()); 05741 } 05742 05743 //////////////////////////////////////////////////////////////////// 05744 // Function: NodePath::has_depth_test 05745 // Access: Published 05746 // Description: Returns true if a depth-test adjustment has been 05747 // explicitly set on this particular node via 05748 // set_depth_test(). If this returns true, then 05749 // get_depth_test() may be called to determine which has 05750 // been set. 05751 //////////////////////////////////////////////////////////////////// 05752 bool NodePath:: 05753 has_depth_test() const { 05754 nassertr_always(!is_empty(), false); 05755 return node()->has_attrib(DepthTestAttrib::get_class_slot()); 05756 } 05757 05758 //////////////////////////////////////////////////////////////////// 05759 // Function: NodePath::get_depth_test 05760 // Access: Published 05761 // Description: Returns true if depth-test rendering has been 05762 // specifically set on this node via set_depth_test(), or 05763 // false if depth-test rendering has been specifically 05764 // disabled. If nothing has been specifically set, 05765 // returns true. See also has_depth_test(). 05766 //////////////////////////////////////////////////////////////////// 05767 bool NodePath:: 05768 get_depth_test() const { 05769 nassertr_always(!is_empty(), false); 05770 const RenderAttrib *attrib = 05771 node()->get_attrib(DepthTestAttrib::get_class_slot()); 05772 if (attrib != (const RenderAttrib *)NULL) { 05773 const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib); 05774 return (dta->get_mode() != DepthTestAttrib::M_none); 05775 } 05776 05777 return true; 05778 } 05779 05780 //////////////////////////////////////////////////////////////////// 05781 // Function: NodePath::set_depth_write 05782 // Access: Published 05783 // Description: Specifically sets or disables the writing to the 05784 // depth buffer on this particular node. This is 05785 // normally on in the 3-d scene graph and off in the 2-d 05786 // scene graph; it should be on for rendering most 3-d 05787 // objects properly. 05788 //////////////////////////////////////////////////////////////////// 05789 void NodePath:: 05790 set_depth_write(bool depth_write, int priority) { 05791 nassertv_always(!is_empty()); 05792 05793 DepthWriteAttrib::Mode mode = 05794 depth_write ? 05795 DepthWriteAttrib::M_on : 05796 DepthWriteAttrib::M_off; 05797 05798 node()->set_attrib(DepthWriteAttrib::make(mode), priority); 05799 } 05800 05801 //////////////////////////////////////////////////////////////////// 05802 // Function: NodePath::clear_depth_write 05803 // Access: Published 05804 // Description: Completely removes any depth-write adjustment that 05805 // may have been set on this node via set_depth_write(). 05806 //////////////////////////////////////////////////////////////////// 05807 void NodePath:: 05808 clear_depth_write() { 05809 nassertv_always(!is_empty()); 05810 node()->clear_attrib(DepthWriteAttrib::get_class_slot()); 05811 } 05812 05813 //////////////////////////////////////////////////////////////////// 05814 // Function: NodePath::has_depth_write 05815 // Access: Published 05816 // Description: Returns true if a depth-write adjustment has been 05817 // explicitly set on this particular node via 05818 // set_depth_write(). If this returns true, then 05819 // get_depth_write() may be called to determine which has 05820 // been set. 05821 //////////////////////////////////////////////////////////////////// 05822 bool NodePath:: 05823 has_depth_write() const { 05824 nassertr_always(!is_empty(), false); 05825 return node()->has_attrib(DepthWriteAttrib::get_class_slot()); 05826 } 05827 05828 //////////////////////////////////////////////////////////////////// 05829 // Function: NodePath::get_depth_write 05830 // Access: Published 05831 // Description: Returns true if depth-write rendering has been 05832 // specifically set on this node via set_depth_write(), or 05833 // false if depth-write rendering has been specifically 05834 // disabled. If nothing has been specifically set, 05835 // returns true. See also has_depth_write(). 05836 //////////////////////////////////////////////////////////////////// 05837 bool NodePath:: 05838 get_depth_write() const { 05839 nassertr_always(!is_empty(), false); 05840 const RenderAttrib *attrib = 05841 node()->get_attrib(DepthWriteAttrib::get_class_slot()); 05842 if (attrib != (const RenderAttrib *)NULL) { 05843 const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib); 05844 return (dta->get_mode() != DepthWriteAttrib::M_off); 05845 } 05846 05847 return true; 05848 } 05849 05850 //////////////////////////////////////////////////////////////////// 05851 // Function: NodePath::set_depth_offset 05852 // Access: Published 05853 // Description: This instructs the graphics driver to apply an 05854 // offset or bias to the generated depth values for 05855 // rendered polygons, before they are written to the 05856 // depth buffer. This can be used to shift polygons 05857 // forward slightly, to resolve depth conflicts, or 05858 // self-shadowing artifacts on thin objects. 05859 // The bias is always an integer number, and each 05860 // integer increment represents the smallest possible 05861 // increment in Z that is sufficient to completely 05862 // resolve two coplanar polygons. Positive numbers 05863 // are closer towards the camera. 05864 //////////////////////////////////////////////////////////////////// 05865 void NodePath:: 05866 set_depth_offset(int bias, int priority) { 05867 nassertv_always(!is_empty()); 05868 05869 node()->set_attrib(DepthOffsetAttrib::make(bias), priority); 05870 } 05871 05872 //////////////////////////////////////////////////////////////////// 05873 // Function: NodePath::clear_depth_offset 05874 // Access: Published 05875 // Description: Completely removes any depth-offset adjustment that 05876 // may have been set on this node via set_depth_offset(). 05877 //////////////////////////////////////////////////////////////////// 05878 void NodePath:: 05879 clear_depth_offset() { 05880 nassertv_always(!is_empty()); 05881 node()->clear_attrib(DepthOffsetAttrib::get_class_slot()); 05882 } 05883 05884 //////////////////////////////////////////////////////////////////// 05885 // Function: NodePath::has_depth_offset 05886 // Access: Published 05887 // Description: Returns true if a depth-offset adjustment has been 05888 // explicitly set on this particular node via 05889 // set_depth_offset(). If this returns true, then 05890 // get_depth_offset() may be called to determine which has 05891 // been set. 05892 //////////////////////////////////////////////////////////////////// 05893 bool NodePath:: 05894 has_depth_offset() const { 05895 nassertr_always(!is_empty(), false); 05896 return node()->has_attrib(DepthOffsetAttrib::get_class_slot()); 05897 } 05898 05899 //////////////////////////////////////////////////////////////////// 05900 // Function: NodePath::get_depth_offset 05901 // Access: Published 05902 // Description: Returns the depth offset value if it has been 05903 // specified using set_depth_offset, or 0 if not. 05904 //////////////////////////////////////////////////////////////////// 05905 int NodePath:: 05906 get_depth_offset() const { 05907 nassertr_always(!is_empty(), 0); 05908 const RenderAttrib *attrib = 05909 node()->get_attrib(DepthOffsetAttrib::get_class_slot()); 05910 if (attrib != (const RenderAttrib *)NULL) { 05911 const DepthOffsetAttrib *doa = DCAST(DepthOffsetAttrib, attrib); 05912 return doa->get_offset(); 05913 } 05914 05915 return 0; 05916 } 05917 05918 //////////////////////////////////////////////////////////////////// 05919 // Function: NodePath::do_billboard_axis 05920 // Access: Published 05921 // Description: Performs a billboard-type rotate to the indicated 05922 // camera node, one time only, and leaves the object 05923 // rotated. This is similar in principle to heads_up(). 05924 //////////////////////////////////////////////////////////////////// 05925 void NodePath:: 05926 do_billboard_axis(const NodePath &camera, PN_stdfloat offset) { 05927 nassertv_always(!is_empty()); 05928 05929 CPT(TransformState) transform = camera.get_transform(get_parent()); 05930 const LMatrix4 &rel_mat = transform->get_mat(); 05931 05932 LVector3 up = LVector3::up(); 05933 LVector3 rel_pos = -rel_mat.get_row3(3); 05934 05935 LQuaternion quat; 05936 ::heads_up(quat, rel_pos, up); 05937 set_quat(quat); 05938 05939 // Also slide the geometry towards the camera according to the 05940 // offset factor. 05941 if (offset != 0.0f) { 05942 LVector3 translate = rel_mat.get_row3(3); 05943 translate.normalize(); 05944 translate *= offset; 05945 set_pos(translate); 05946 } 05947 } 05948 05949 //////////////////////////////////////////////////////////////////// 05950 // Function: NodePath::do_billboard_point_eye 05951 // Access: Published 05952 // Description: Performs a billboard-type rotate to the indicated 05953 // camera node, one time only, and leaves the object 05954 // rotated. This is similar in principle to look_at(), 05955 // although the point_eye billboard effect cannot be 05956 // achieved using the ordinary look_at() call. 05957 //////////////////////////////////////////////////////////////////// 05958 void NodePath:: 05959 do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) { 05960 nassertv_always(!is_empty()); 05961 05962 CPT(TransformState) transform = camera.get_transform(get_parent()); 05963 const LMatrix4 &rel_mat = transform->get_mat(); 05964 05965 LVector3 up = LVector3::up() * rel_mat; 05966 LVector3 rel_pos = LVector3::forward() * rel_mat; 05967 05968 LQuaternion quat; 05969 ::look_at(quat, rel_pos, up); 05970 set_quat(quat); 05971 05972 // Also slide the geometry towards the camera according to the 05973 // offset factor. 05974 if (offset != 0.0f) { 05975 LVector3 translate = rel_mat.get_row3(3); 05976 translate.normalize(); 05977 translate *= offset; 05978 set_pos(translate); 05979 } 05980 } 05981 05982 //////////////////////////////////////////////////////////////////// 05983 // Function: NodePath::do_billboard_point_world 05984 // Access: Published 05985 // Description: Performs a billboard-type rotate to the indicated 05986 // camera node, one time only, and leaves the object 05987 // rotated. This is similar in principle to look_at(). 05988 //////////////////////////////////////////////////////////////////// 05989 void NodePath:: 05990 do_billboard_point_world(const NodePath &camera, PN_stdfloat offset) { 05991 nassertv_always(!is_empty()); 05992 05993 CPT(TransformState) transform = camera.get_transform(get_parent()); 05994 const LMatrix4 &rel_mat = transform->get_mat(); 05995 05996 LVector3 up = LVector3::up(); 05997 LVector3 rel_pos = -rel_mat.get_row3(3); 05998 05999 LQuaternion quat; 06000 ::look_at(quat, rel_pos, up); 06001 set_quat(quat); 06002 06003 // Also slide the geometry towards the camera according to the 06004 // offset factor. 06005 if (offset != 0.0f) { 06006 LVector3 translate = rel_mat.get_row3(3); 06007 translate.normalize(); 06008 translate *= offset; 06009 set_pos(translate); 06010 } 06011 } 06012 06013 //////////////////////////////////////////////////////////////////// 06014 // Function: NodePath::set_billboard_axis 06015 // Access: Published 06016 // Description: Puts a billboard transition on the node such that it 06017 // will rotate in two dimensions around the up axis, 06018 // towards a specified "camera" instead of to the 06019 // viewing camera. 06020 //////////////////////////////////////////////////////////////////// 06021 void NodePath:: 06022 set_billboard_axis(const NodePath &camera, PN_stdfloat offset) { 06023 nassertv_always(!is_empty()); 06024 CPT(RenderEffect) billboard = BillboardEffect::make 06025 (LVector3::up(), false, true, 06026 offset, camera, LPoint3(0.0f, 0.0f, 0.0f)); 06027 node()->set_effect(billboard); 06028 } 06029 06030 //////////////////////////////////////////////////////////////////// 06031 // Function: NodePath::set_billboard_point_eye 06032 // Access: Published 06033 // Description: Puts a billboard transition on the node such that it 06034 // will rotate in three dimensions about the origin, 06035 // keeping its up vector oriented to the top of the 06036 // camera, towards a specified "camera" instead of to 06037 // the viewing camera. 06038 //////////////////////////////////////////////////////////////////// 06039 void NodePath:: 06040 set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) { 06041 nassertv_always(!is_empty()); 06042 CPT(RenderEffect) billboard = BillboardEffect::make 06043 (LVector3::up(), true, false, 06044 offset, camera, LPoint3(0.0f, 0.0f, 0.0f)); 06045 node()->set_effect(billboard); 06046 } 06047 06048 //////////////////////////////////////////////////////////////////// 06049 // Function: NodePath::set_billboard_point_world 06050 // Access: Published 06051 // Description: Puts a billboard transition on the node such that it 06052 // will rotate in three dimensions about the origin, 06053 // keeping its up vector oriented to the sky, towards a 06054 // specified "camera" instead of to the viewing camera. 06055 //////////////////////////////////////////////////////////////////// 06056 void NodePath:: 06057 set_billboard_point_world(const NodePath &camera, PN_stdfloat offset) { 06058 nassertv_always(!is_empty()); 06059 CPT(RenderEffect) billboard = BillboardEffect::make 06060 (LVector3::up(), false, false, 06061 offset, camera, LPoint3(0.0f, 0.0f, 0.0f)); 06062 node()->set_effect(billboard); 06063 } 06064 06065 //////////////////////////////////////////////////////////////////// 06066 // Function: NodePath::clear_billboard 06067 // Access: Published 06068 // Description: Removes any billboard effect from the node. 06069 //////////////////////////////////////////////////////////////////// 06070 void NodePath:: 06071 clear_billboard() { 06072 nassertv_always(!is_empty()); 06073 node()->clear_effect(BillboardEffect::get_class_type()); 06074 } 06075 06076 //////////////////////////////////////////////////////////////////// 06077 // Function: NodePath::has_billboard 06078 // Access: Published 06079 // Description: Returns true if there is any billboard effect on 06080 // the node. 06081 //////////////////////////////////////////////////////////////////// 06082 bool NodePath:: 06083 has_billboard() const { 06084 nassertr_always(!is_empty(), false); 06085 return node()->has_effect(BillboardEffect::get_class_type()); 06086 } 06087 06088 //////////////////////////////////////////////////////////////////// 06089 // Function: NodePath::set_compass 06090 // Access: Published 06091 // Description: Puts a compass effect on the node, so that it will 06092 // retain a fixed rotation relative to the reference 06093 // node (or render if the reference node is empty) 06094 // regardless of the transforms above it. 06095 //////////////////////////////////////////////////////////////////// 06096 void NodePath:: 06097 set_compass(const NodePath &reference) { 06098 nassertv_always(!is_empty()); 06099 node()->set_effect(CompassEffect::make(reference)); 06100 } 06101 06102 //////////////////////////////////////////////////////////////////// 06103 // Function: NodePath::clear_compass 06104 // Access: Published 06105 // Description: Removes any compass effect from the node. 06106 //////////////////////////////////////////////////////////////////// 06107 void NodePath:: 06108 clear_compass() { 06109 nassertv_always(!is_empty()); 06110 node()->clear_effect(CompassEffect::get_class_type()); 06111 } 06112 06113 //////////////////////////////////////////////////////////////////// 06114 // Function: NodePath::has_compass 06115 // Access: Published 06116 // Description: Returns true if there is any compass effect on 06117 // the node. 06118 //////////////////////////////////////////////////////////////////// 06119 bool NodePath:: 06120 has_compass() const { 06121 nassertr_always(!is_empty(), false); 06122 return node()->has_effect(CompassEffect::get_class_type()); 06123 } 06124 06125 //////////////////////////////////////////////////////////////////// 06126 // Function: NodePath::set_transparency 06127 // Access: Published 06128 // Description: Specifically sets or disables transparent rendering 06129 // mode on this particular node. If no other nodes 06130 // override, this will cause items with a non-1 value 06131 // for alpha color to be rendered partially transparent. 06132 //////////////////////////////////////////////////////////////////// 06133 void NodePath:: 06134 set_transparency(TransparencyAttrib::Mode mode, int priority) { 06135 nassertv_always(!is_empty()); 06136 06137 node()->set_attrib(TransparencyAttrib::make(mode), priority); 06138 } 06139 06140 //////////////////////////////////////////////////////////////////// 06141 // Function: NodePath::clear_transparency 06142 // Access: Published 06143 // Description: Completely removes any transparency adjustment that 06144 // may have been set on this node via set_transparency(). 06145 // The geometry at this level and below will 06146 // subsequently be rendered either transparent or not, 06147 // to whatever other nodes may have had 06148 // set_transparency() on them. 06149 //////////////////////////////////////////////////////////////////// 06150 void NodePath:: 06151 clear_transparency() { 06152 nassertv_always(!is_empty()); 06153 node()->clear_attrib(TransparencyAttrib::get_class_slot()); 06154 } 06155 06156 //////////////////////////////////////////////////////////////////// 06157 // Function: NodePath::has_transparency 06158 // Access: Published 06159 // Description: Returns true if a transparent-rendering adjustment 06160 // has been explicitly set on this particular node via 06161 // set_transparency(). If this returns true, then 06162 // get_transparency() may be called to determine whether 06163 // transparency has been explicitly enabled or 06164 // explicitly disabled for this node. 06165 //////////////////////////////////////////////////////////////////// 06166 bool NodePath:: 06167 has_transparency() const { 06168 nassertr_always(!is_empty(), false); 06169 return node()->has_attrib(TransparencyAttrib::get_class_slot()); 06170 } 06171 06172 //////////////////////////////////////////////////////////////////// 06173 // Function: NodePath::get_transparency 06174 // Access: Published 06175 // Description: Returns the transparent rendering that has been 06176 // specifically set on this node via set_transparency(), or 06177 // M_none if nontransparent rendering has been specifically 06178 // set, or if nothing has been specifically set. See 06179 // also has_transparency(). This does not necessarily 06180 // imply that the geometry will or will not be rendered 06181 // transparent, as there may be other nodes that override. 06182 //////////////////////////////////////////////////////////////////// 06183 TransparencyAttrib::Mode NodePath:: 06184 get_transparency() const { 06185 nassertr_always(!is_empty(), TransparencyAttrib::M_none); 06186 const RenderAttrib *attrib = 06187 node()->get_attrib(TransparencyAttrib::get_class_slot()); 06188 if (attrib != (const RenderAttrib *)NULL) { 06189 const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib); 06190 return ta->get_mode(); 06191 } 06192 06193 return TransparencyAttrib::M_none; 06194 } 06195 06196 //////////////////////////////////////////////////////////////////// 06197 // Function: NodePath::set_antialias 06198 // Access: Published 06199 // Description: Specifies the antialiasing type that should be 06200 // applied at this node and below. See AntialiasAttrib. 06201 //////////////////////////////////////////////////////////////////// 06202 void NodePath:: 06203 set_antialias(unsigned short mode, int priority) { 06204 nassertv_always(!is_empty()); 06205 06206 node()->set_attrib(AntialiasAttrib::make(mode), priority); 06207 } 06208 06209 //////////////////////////////////////////////////////////////////// 06210 // Function: NodePath::clear_antialias 06211 // Access: Published 06212 // Description: Completely removes any antialias setting that 06213 // may have been set on this node via set_antialias(). 06214 //////////////////////////////////////////////////////////////////// 06215 void NodePath:: 06216 clear_antialias() { 06217 nassertv_always(!is_empty()); 06218 node()->clear_attrib(AntialiasAttrib::get_class_slot()); 06219 } 06220 06221 //////////////////////////////////////////////////////////////////// 06222 // Function: NodePath::has_antialias 06223 // Access: Published 06224 // Description: Returns true if an antialias setting has been 06225 // explicitly mode on this particular node via 06226 // set_antialias(). If this returns true, then 06227 // get_antialias() may be called to determine what the 06228 // setting was. 06229 //////////////////////////////////////////////////////////////////// 06230 bool NodePath:: 06231 has_antialias() const { 06232 nassertr_always(!is_empty(), false); 06233 return node()->has_attrib(AntialiasAttrib::get_class_slot()); 06234 } 06235 06236 //////////////////////////////////////////////////////////////////// 06237 // Function: NodePath::get_antialias 06238 // Access: Published 06239 // Description: Returns the antialias setting that has been 06240 // specifically set on this node via set_antialias(), or 06241 // M_none if no setting has been made. 06242 //////////////////////////////////////////////////////////////////// 06243 unsigned short NodePath:: 06244 get_antialias() const { 06245 nassertr_always(!is_empty(), AntialiasAttrib::M_none); 06246 const RenderAttrib *attrib = 06247 node()->get_attrib(AntialiasAttrib::get_class_slot()); 06248 if (attrib != (const RenderAttrib *)NULL) { 06249 const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib); 06250 return ta->get_mode(); 06251 } 06252 06253 return AntialiasAttrib::M_none; 06254 } 06255 06256 //////////////////////////////////////////////////////////////////// 06257 // Function: NodePath::has_audio_volume 06258 // Access: Published 06259 // Description: Returns true if an audio volume has been applied 06260 // to the referenced node, false otherwise. It is still 06261 // possible that volume at this node might have been 06262 // scaled by an ancestor node. 06263 //////////////////////////////////////////////////////////////////// 06264 bool NodePath:: 06265 has_audio_volume() const { 06266 nassertr_always(!is_empty(), false); 06267 return node()->has_attrib(AudioVolumeAttrib::get_class_slot()); 06268 } 06269 06270 //////////////////////////////////////////////////////////////////// 06271 // Function: NodePath::clear_audio_volume 06272 // Access: Published 06273 // Description: Completely removes any audio volume from the 06274 // referenced node. This is preferable to simply 06275 // setting the audio volume to identity, as it also 06276 // removes the overhead associated with having an audio 06277 // volume at all. 06278 //////////////////////////////////////////////////////////////////// 06279 void NodePath:: 06280 clear_audio_volume() { 06281 nassertv_always(!is_empty()); 06282 node()->clear_attrib(AudioVolumeAttrib::get_class_slot()); 06283 } 06284 06285 //////////////////////////////////////////////////////////////////// 06286 // Function: NodePath::set_audio_volume 06287 // Access: Published 06288 // Description: Sets the audio volume component of the transform 06289 //////////////////////////////////////////////////////////////////// 06290 void NodePath:: 06291 set_audio_volume(PN_stdfloat volume, int priority) { 06292 nassertv_always(!is_empty()); 06293 06294 const RenderAttrib *attrib = 06295 node()->get_attrib(AudioVolumeAttrib::get_class_slot()); 06296 if (attrib != (const RenderAttrib *)NULL) { 06297 priority = max(priority, 06298 node()->get_state()->get_override(AudioVolumeAttrib::get_class_slot())); 06299 CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib); 06300 06301 // Modify the existing AudioVolumeAttrib to add the indicated 06302 // volume. 06303 node()->set_attrib(ava->set_volume(volume), priority); 06304 06305 } else { 06306 // Create a new AudioVolumeAttrib for this node. 06307 node()->set_attrib(AudioVolumeAttrib::make(volume), priority); 06308 } 06309 } 06310 06311 //////////////////////////////////////////////////////////////////// 06312 // Function: NodePath::set_audio_volume_off 06313 // Access: Published 06314 // Description: Disables any audio volume attribute inherited from 06315 // above. This is not the same thing as 06316 // clear_audio_volume(), which undoes any previous 06317 // set_audio_volume() operation on this node; rather, 06318 // this actively disables any set_audio_volume() that 06319 // might be inherited from a parent node. 06320 // 06321 // It is legal to specify a new volume on the same 06322 // node with a subsequent call to set_audio_volume(); 06323 // this new scale will apply to lower nodes. 06324 //////////////////////////////////////////////////////////////////// 06325 void NodePath:: 06326 set_audio_volume_off(int priority) { 06327 nassertv_always(!is_empty()); 06328 node()->set_attrib(AudioVolumeAttrib::make_off(), priority); 06329 } 06330 06331 //////////////////////////////////////////////////////////////////// 06332 // Function: NodePath::get_audio_volume 06333 // Access: Published 06334 // Description: Returns the complete audio volume that has been 06335 // applied to this node via a previous call to 06336 // set_audio_volume(), or 1. (identity) if no volume has 06337 // been applied to this particular node. 06338 //////////////////////////////////////////////////////////////////// 06339 PN_stdfloat NodePath:: 06340 get_audio_volume() const { 06341 const RenderAttrib *attrib = 06342 node()->get_attrib(AudioVolumeAttrib::get_class_slot()); 06343 if (attrib != (const RenderAttrib *)NULL) { 06344 const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib); 06345 return ava->get_volume(); 06346 } 06347 06348 return 1.0f; 06349 } 06350 06351 //////////////////////////////////////////////////////////////////// 06352 // Function: NodePath::get_net_audio_volume 06353 // Access: Published 06354 // Description: Returns the complete audio volume for this node 06355 // taking highers nodes in the graph into account. 06356 //////////////////////////////////////////////////////////////////// 06357 PN_stdfloat NodePath:: 06358 get_net_audio_volume() const { 06359 CPT(RenderState) net_state = get_net_state(); 06360 const RenderAttrib *attrib = net_state->get_attrib(AudioVolumeAttrib::get_class_slot()); 06361 if (attrib != (const RenderAttrib *)NULL) { 06362 const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib); 06363 if (ava != (const AudioVolumeAttrib *)NULL) { 06364 return ava->get_volume(); 06365 } 06366 } 06367 06368 return 1.0f; 06369 } 06370 06371 //////////////////////////////////////////////////////////////////// 06372 // Function: NodePath::get_hidden_ancestor 06373 // Access: Published 06374 // Description: Returns the NodePath at or above the referenced node 06375 // that is hidden to the indicated camera(s), or an 06376 // empty NodePath if no ancestor of the referenced node 06377 // is hidden (and the node should be visible). 06378 //////////////////////////////////////////////////////////////////// 06379 NodePath NodePath:: 06380 get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const { 06381 int pipeline_stage = current_thread->get_pipeline_stage(); 06382 06383 NodePathComponent *comp; 06384 for (comp = _head; 06385 comp != (NodePathComponent *)NULL; 06386 comp = comp->get_next(pipeline_stage, current_thread)) { 06387 PandaNode *node = comp->get_node(); 06388 if (node->is_overall_hidden() || 06389 ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) { 06390 NodePath result; 06391 result._head = comp; 06392 return result; 06393 } 06394 } 06395 06396 return not_found(); 06397 } 06398 06399 //////////////////////////////////////////////////////////////////// 06400 // Function: NodePath::stash 06401 // Access: Published 06402 // Description: Removes the referenced node (and the entire subgraph 06403 // below this node) from the scene graph in any normal 06404 // sense. The node will no longer be visible and is not 06405 // tested for collisions; furthermore, no normal scene 06406 // graph traversal will visit the node. The node's 06407 // bounding volume no longer contributes to its parent's 06408 // bounding volume. 06409 // 06410 // A stashed node cannot be located by a normal find() 06411 // operation (although a special find string can still 06412 // retrieve it). 06413 //////////////////////////////////////////////////////////////////// 06414 void NodePath:: 06415 stash(int sort, Thread *current_thread) { 06416 nassertv_always(!is_singleton() && !is_empty()); 06417 nassertv(verify_complete()); 06418 06419 int pipeline_stage = current_thread->get_pipeline_stage(); 06420 bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread), 06421 _head, sort, true, pipeline_stage, 06422 current_thread); 06423 nassertv(reparented); 06424 } 06425 06426 //////////////////////////////////////////////////////////////////// 06427 // Function: NodePath::unstash 06428 // Access: Published 06429 // Description: Undoes the effect of a previous stash() on this 06430 // node: makes the referenced node (and the entire 06431 // subgraph below this node) once again part of the 06432 // scene graph. 06433 //////////////////////////////////////////////////////////////////// 06434 void NodePath:: 06435 unstash(int sort, Thread *current_thread) { 06436 nassertv_always(!is_singleton() && !is_empty()); 06437 nassertv(verify_complete()); 06438 06439 int pipeline_stage = current_thread->get_pipeline_stage(); 06440 bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread), 06441 _head, sort, false, pipeline_stage, 06442 current_thread); 06443 nassertv(reparented); 06444 } 06445 06446 //////////////////////////////////////////////////////////////////// 06447 // Function: NodePath::unstash_all 06448 // Access: Published 06449 // Description: Unstashes this node and all stashed child nodes. 06450 //////////////////////////////////////////////////////////////////// 06451 void NodePath:: 06452 unstash_all(Thread *current_thread) { 06453 NodePathCollection stashed_descendents = find_all_matches("**/@@*"); 06454 stashed_descendents.unstash(); 06455 unstash(0, current_thread); 06456 } 06457 06458 //////////////////////////////////////////////////////////////////// 06459 // Function: NodePath::get_stashed_ancestor 06460 // Access: Published 06461 // Description: Returns the NodePath at or above the referenced node 06462 // that is stashed, or an empty NodePath if no ancestor 06463 // of the referenced node is stashed (and the node should 06464 // be visible). 06465 //////////////////////////////////////////////////////////////////// 06466 NodePath NodePath:: 06467 get_stashed_ancestor(Thread *current_thread) const { 06468 NodePathComponent *comp = _head; 06469 if (comp != (NodePathComponent *)NULL) { 06470 int pipeline_stage = current_thread->get_pipeline_stage(); 06471 NodePathComponent *next = comp->get_next(pipeline_stage, current_thread); 06472 06473 while (next != (NodePathComponent *)NULL) { 06474 PandaNode *node = comp->get_node(); 06475 PandaNode *parent_node = next->get_node(); 06476 06477 if (parent_node->find_stashed(node) >= 0) { 06478 NodePath result; 06479 result._head = comp; 06480 return result; 06481 } 06482 06483 comp = next; 06484 next = next->get_next(pipeline_stage, current_thread); 06485 } 06486 } 06487 06488 return not_found(); 06489 } 06490 06491 //////////////////////////////////////////////////////////////////// 06492 // Function: NodePath::verify_complete 06493 // Access: Published 06494 // Description: Returns true if all of the nodes described in the 06495 // NodePath are connected, or false otherwise. 06496 //////////////////////////////////////////////////////////////////// 06497 bool NodePath:: 06498 verify_complete(Thread *current_thread) const { 06499 if (is_empty()) { 06500 return true; 06501 } 06502 06503 #ifdef HAVE_THREADS 06504 if (Thread::is_true_threads()) { 06505 // In a threaded environment, we can't reliably test this, since a 06506 // sub-thread may be mucking with the NodePath's ancestry as we 06507 // try to validate it. NodePaths are inherently not thread-safe, 06508 // but generally that's not an issue. 06509 return true; 06510 } 06511 #endif // HAVE_THREADS 06512 06513 PStatTimer timer(_verify_complete_pcollector); 06514 06515 const NodePathComponent *comp = _head; 06516 nassertr(comp != (const NodePathComponent *)NULL, false); 06517 06518 int pipeline_stage = current_thread->get_pipeline_stage(); 06519 06520 PandaNode *node = comp->get_node(); 06521 nassertr(node != (const PandaNode *)NULL, false); 06522 int length = comp->get_length(pipeline_stage, current_thread); 06523 06524 comp = comp->get_next(pipeline_stage, current_thread); 06525 length--; 06526 while (comp != (const NodePathComponent *)NULL) { 06527 PandaNode *next_node = comp->get_node(); 06528 nassertr(next_node != (const PandaNode *)NULL, false); 06529 06530 if (node->find_parent(next_node) < 0) { 06531 pgraph_cat.warning() 06532 << *this << " is incomplete; " << *node << " is not a child of " 06533 << *next_node << "\n"; 06534 return false; 06535 } 06536 06537 if (comp->get_length(pipeline_stage, current_thread) != length) { 06538 pgraph_cat.warning() 06539 << *this << " is incomplete; length at " << *next_node 06540 << " indicates " << comp->get_length(pipeline_stage, current_thread) 06541 << " while length at " << *node << " indicates " << length << "\n"; 06542 return false; 06543 } 06544 06545 node = next_node; 06546 comp = comp->get_next(pipeline_stage, current_thread); 06547 length--; 06548 } 06549 06550 return true; 06551 } 06552 06553 //////////////////////////////////////////////////////////////////// 06554 // Function: NodePath::premunge_scene 06555 // Access: Published 06556 // Description: Walks through the scene graph beginning at the bottom 06557 // node, and internally adjusts any GeomVertexFormats 06558 // for optimal rendering on the indicated GSG. If this 06559 // step is not done prior to rendering, the formats will 06560 // be optimized at render time instead, for a small 06561 // cost. 06562 // 06563 // It is not normally necessary to do this on a model 06564 // loaded directly from disk, since the loader will do 06565 // this by default. 06566 //////////////////////////////////////////////////////////////////// 06567 void NodePath:: 06568 premunge_scene(GraphicsStateGuardianBase *gsg) { 06569 nassertv_always(!is_empty()); 06570 06571 CPT(RenderState) state = RenderState::make_empty(); 06572 if (has_parent()) { 06573 state = get_parent().get_net_state(); 06574 } 06575 06576 SceneGraphReducer gr(gsg); 06577 gr.premunge(node(), state); 06578 } 06579 06580 //////////////////////////////////////////////////////////////////// 06581 // Function: NodePath::prepare_scene 06582 // Access: Published 06583 // Description: Walks through the scene graph beginning at the bottom 06584 // node, and does whatever initialization is required to 06585 // render the scene properly with the indicated GSG. It 06586 // is not strictly necessary to call this, since the GSG 06587 // will initialize itself when the scene is rendered, 06588 // but this may take some of the overhead away from that 06589 // process. 06590 // 06591 // In particular, this will ensure that textures and 06592 // vertex buffers within the scene are loaded into 06593 // graphics memory. 06594 //////////////////////////////////////////////////////////////////// 06595 void NodePath:: 06596 prepare_scene(GraphicsStateGuardianBase *gsg) { 06597 nassertv_always(!is_empty()); 06598 06599 node()->prepare_scene(gsg, get_net_state()); 06600 } 06601 06602 //////////////////////////////////////////////////////////////////// 06603 // Function: NodePath::show_bounds 06604 // Access: Published 06605 // Description: Causes the bounding volume of the bottom node and all 06606 // of its descendants (that is, the bounding volume 06607 // associated with the the bottom arc) to be rendered, 06608 // if possible. The rendering method is less than 06609 // optimal; this is intended primarily for debugging. 06610 //////////////////////////////////////////////////////////////////// 06611 void NodePath:: 06612 show_bounds() { 06613 nassertv_always(!is_empty()); 06614 node()->set_effect(ShowBoundsEffect::make(false)); 06615 } 06616 06617 //////////////////////////////////////////////////////////////////// 06618 // Function: NodePath::show_tight_bounds 06619 // Access: Published 06620 // Description: Similar to show_bounds(), this draws a bounding box 06621 // representing the "tight" bounds of this node and all 06622 // of its descendants. The bounding box is recomputed 06623 // every frame by reexamining all of the vertices; this 06624 // is far from efficient, but this is intended for 06625 // debugging. 06626 //////////////////////////////////////////////////////////////////// 06627 void NodePath:: 06628 show_tight_bounds() { 06629 nassertv_always(!is_empty()); 06630 node()->set_effect(ShowBoundsEffect::make(true)); 06631 } 06632 06633 //////////////////////////////////////////////////////////////////// 06634 // Function: NodePath::hide_bounds 06635 // Access: Published 06636 // Description: Stops the rendering of the bounding volume begun with 06637 // show_bounds(). 06638 //////////////////////////////////////////////////////////////////// 06639 void NodePath:: 06640 hide_bounds() { 06641 nassertv_always(!is_empty()); 06642 node()->clear_effect(ShowBoundsEffect::get_class_type()); 06643 } 06644 06645 //////////////////////////////////////////////////////////////////// 06646 // Function: NodePath::get_bounds 06647 // Access: Published 06648 // Description: Returns a newly-allocated bounding volume containing 06649 // the bottom node and all of its descendants. This is 06650 // the bounding volume on the bottom arc, converted to 06651 // the local coordinate space of the node. 06652 //////////////////////////////////////////////////////////////////// 06653 PT(BoundingVolume) NodePath:: 06654 get_bounds(Thread *current_thread) const { 06655 nassertr_always(!is_empty(), new BoundingSphere); 06656 return node()->get_bounds(current_thread)->make_copy(); 06657 } 06658 06659 //////////////////////////////////////////////////////////////////// 06660 // Function: NodePath::force_recompute_bounds 06661 // Access: Published 06662 // Description: Forces the recomputing of all the bounding volumes at 06663 // every node in the subgraph beginning at this node and 06664 // below. 06665 // 06666 // This should not normally need to be called, since the 06667 // bounding volumes are supposed to be recomputed 06668 // automatically when necessary. It may be useful when 06669 // debugging, to verify that the bounding volumes have 06670 // not become inadvertently stale; it may also be useful 06671 // to force animated characters to update their bounding 06672 // volumes (which does not presently happen 06673 // automatically). 06674 //////////////////////////////////////////////////////////////////// 06675 void NodePath:: 06676 force_recompute_bounds() { 06677 nassertv_always(!is_empty()); 06678 r_force_recompute_bounds(node()); 06679 } 06680 06681 //////////////////////////////////////////////////////////////////// 06682 // Function: NodePath::write_bounds 06683 // Access: Published 06684 // Description: Writes a description of the bounding volume 06685 // containing the bottom node and all of its descendants 06686 // to the indicated output stream. 06687 //////////////////////////////////////////////////////////////////// 06688 void NodePath:: 06689 write_bounds(ostream &out) const { 06690 get_bounds()->write(out); 06691 } 06692 06693 //////////////////////////////////////////////////////////////////// 06694 // Function: NodePath::calc_tight_bounds 06695 // Access: Published 06696 // Description: Calculates the minimum and maximum vertices of all 06697 // Geoms at this NodePath's bottom node and below. This 06698 // is a tight bounding box; it will generally be tighter 06699 // than the bounding volume returned by get_bounds() 06700 // (but it is more expensive to compute). 06701 // 06702 // The return value is true if any points are within the 06703 // bounding volume, or false if none are. 06704 //////////////////////////////////////////////////////////////////// 06705 bool NodePath:: 06706 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, 06707 Thread *current_thread) const { 06708 min_point.set(0.0f, 0.0f, 0.0f); 06709 max_point.set(0.0f, 0.0f, 0.0f); 06710 nassertr_always(!is_empty(), false); 06711 06712 bool found_any = false; 06713 node()->calc_tight_bounds(min_point, max_point, found_any, 06714 TransformState::make_identity(), 06715 current_thread); 06716 06717 return found_any; 06718 } 06719 06720 /* 06721 06722 NB: Had to remove this function to avoid circular dependency when 06723 moving SceneGraphAnalyzer into pgraphnodes, attempting to reduce size 06724 of pgraph. This function is now defined as a Python extension 06725 function instead. 06726 06727 //////////////////////////////////////////////////////////////////// 06728 // Function: NodePath::analyze 06729 // Access: Published 06730 // Description: Analyzes the geometry below this node and reports the 06731 // number of vertices, triangles, etc. This is the same 06732 // information reported by the bam-info program. 06733 //////////////////////////////////////////////////////////////////// 06734 void NodePath:: 06735 analyze() const { 06736 nassertv_always(!is_empty()); 06737 SceneGraphAnalyzer sga; 06738 sga.add_node(node()); 06739 06740 if (sga.get_num_lod_nodes() == 0) { 06741 sga.write(nout); 06742 06743 } else { 06744 nout << "At highest LOD:\n"; 06745 SceneGraphAnalyzer sga2; 06746 sga2.set_lod_mode(SceneGraphAnalyzer::LM_highest); 06747 sga2.add_node(node()); 06748 sga2.write(nout); 06749 06750 nout << "\nAt lowest LOD:\n"; 06751 sga2.clear(); 06752 sga2.set_lod_mode(SceneGraphAnalyzer::LM_lowest); 06753 sga2.add_node(node()); 06754 sga2.write(nout); 06755 06756 nout << "\nAll nodes:\n"; 06757 sga.write(nout); 06758 } 06759 } 06760 */ 06761 06762 //////////////////////////////////////////////////////////////////// 06763 // Function: NodePath::flatten_light 06764 // Access: Published 06765 // Description: Lightly flattens out the hierarchy below this node by 06766 // applying transforms, colors, and texture matrices 06767 // from the nodes onto the vertices, but does not remove 06768 // any nodes. 06769 // 06770 // This can result in improved rendering performance 06771 // because there will be fewer transforms in the 06772 // resulting scene graph, but the number of nodes will 06773 // remain the same. 06774 // 06775 // In particular, any NodePaths that reference nodes 06776 // within this hierarchy will not be damaged. However, 06777 // since this operation will remove transforms from the 06778 // scene graph, it may be dangerous to apply to nodes 06779 // where you expect to dynamically modify the transform, 06780 // or where you expect the geometry to remain in a 06781 // particular local coordinate system. 06782 // 06783 // The return value is always 0, since flatten_light 06784 // does not remove any nodes. 06785 //////////////////////////////////////////////////////////////////// 06786 int NodePath:: 06787 flatten_light() { 06788 nassertr_always(!is_empty(), 0); 06789 SceneGraphReducer gr; 06790 gr.apply_attribs(node()); 06791 06792 return 0; 06793 } 06794 06795 //////////////////////////////////////////////////////////////////// 06796 // Function: NodePath::flatten_medium 06797 // Access: Published 06798 // Description: A more thorough flattening than flatten_light(), this 06799 // first applies all the transforms, colors, and texture 06800 // matrices from the nodes onto the vertices, and then 06801 // removes unneeded grouping nodes--nodes that have 06802 // exactly one child, for instance, but have no special 06803 // properties in themselves. 06804 // 06805 // This results in improved performance over 06806 // flatten_light() because the number of nodes in the 06807 // scene graph is reduced. 06808 // 06809 // The return value is the number of nodes removed. 06810 //////////////////////////////////////////////////////////////////// 06811 int NodePath:: 06812 flatten_medium() { 06813 nassertr_always(!is_empty(), 0); 06814 SceneGraphReducer gr; 06815 gr.apply_attribs(node()); 06816 int num_removed = gr.flatten(node(), 0); 06817 06818 if (flatten_geoms) { 06819 gr.make_compatible_state(node()); 06820 gr.collect_vertex_data(node()); 06821 gr.unify(node(), true); 06822 } 06823 06824 return num_removed; 06825 } 06826 06827 //////////////////////////////////////////////////////////////////// 06828 // Function: NodePath::flatten_strong 06829 // Access: Published 06830 // Description: The strongest possible flattening. This first 06831 // applies all of the transforms to the vertices, as in 06832 // flatten_medium(), but then it will combine sibling 06833 // nodes together when possible, in addition to removing 06834 // unnecessary parent-child nodes. This can result in 06835 // substantially fewer nodes, but any nicely-grouped 06836 // hierachical bounding volumes may be lost. 06837 // 06838 // It is generally a good idea to apply this kind of 06839 // flattening only to nodes that will be culled largely 06840 // as a single unit, like a car. Applying this to an 06841 // entire scene may result in overall poorer performance 06842 // because of less-effective culling. 06843 //////////////////////////////////////////////////////////////////// 06844 int NodePath:: 06845 flatten_strong() { 06846 nassertr_always(!is_empty(), 0); 06847 SceneGraphReducer gr; 06848 gr.apply_attribs(node()); 06849 int num_removed = gr.flatten(node(), ~0); 06850 06851 if (flatten_geoms) { 06852 gr.make_compatible_state(node()); 06853 gr.collect_vertex_data(node(), ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type)); 06854 gr.unify(node(), false); 06855 } 06856 06857 return num_removed; 06858 } 06859 06860 //////////////////////////////////////////////////////////////////// 06861 // Function: NodePath::apply_texture_colors 06862 // Access: Published 06863 // Description: Removes textures from Geoms at this node and below by 06864 // applying the texture colors to the vertices. This is 06865 // primarily useful to simplify a low-LOD model. The 06866 // texture colors are replaced by flat colors that 06867 // approximate the original textures. 06868 // 06869 // Only the bottommost texture on each Geom is used (if 06870 // there is more than one), and it is applied as if it 06871 // were M_modulate, and WM_repeat, regardless of its 06872 // actual settings. If the texture has a 06873 // simple_ram_image, this may be used if the main image 06874 // isn't resident. 06875 // 06876 // After this call, there will be no texturing specified 06877 // at this level and below. Of course, there might 06878 // still be texturing inherited from above. 06879 //////////////////////////////////////////////////////////////////// 06880 void NodePath:: 06881 apply_texture_colors() { 06882 nassertv_always(!is_empty()); 06883 SceneGraphReducer gr; 06884 gr.apply_attribs(node(), SceneGraphReducer::TT_apply_texture_color | SceneGraphReducer::TT_tex_matrix | SceneGraphReducer::TT_other); 06885 } 06886 06887 //////////////////////////////////////////////////////////////////// 06888 // Function: NodePath::find_net_tag 06889 // Access: Published 06890 // Description: Returns the lowest ancestor of this node that 06891 // contains a tag definition with the indicated key, if 06892 // any, or an empty NodePath if no ancestor of this node 06893 // contains this tag definition. See set_tag(). 06894 //////////////////////////////////////////////////////////////////// 06895 NodePath NodePath:: 06896 find_net_tag(const string &key) const { 06897 if (is_empty()) { 06898 return NodePath::not_found(); 06899 } 06900 if (has_tag(key)) { 06901 return *this; 06902 } 06903 return get_parent().find_net_tag(key); 06904 } 06905 06906 #ifdef HAVE_PYTHON 06907 //////////////////////////////////////////////////////////////////// 06908 // Function: NodePath::find_net_python_tag 06909 // Access: Published 06910 // Description: Returns the lowest ancestor of this node that 06911 // contains a tag definition with the indicated key, if 06912 // any, or an empty NodePath if no ancestor of this node 06913 // contains this tag definition. See set_python_tag(). 06914 //////////////////////////////////////////////////////////////////// 06915 NodePath NodePath:: 06916 find_net_python_tag(const string &key) const { 06917 if (is_empty()) { 06918 return NodePath::not_found(); 06919 } 06920 if (has_python_tag(key)) { 06921 return *this; 06922 } 06923 return get_parent().find_net_python_tag(key); 06924 } 06925 #endif // HAVE_PYTHON 06926 06927 //////////////////////////////////////////////////////////////////// 06928 // Function: NodePath::write_bam_file 06929 // Access: Published 06930 // Description: Writes the contents of this node and below out to a 06931 // bam file with the indicated filename. This file may 06932 // then be read in again, as is, at some later point. 06933 // Returns true if successful, false on some kind of 06934 // error. 06935 //////////////////////////////////////////////////////////////////// 06936 bool NodePath:: 06937 write_bam_file(const Filename &filename) const { 06938 nassertr_always(!is_empty(), false); 06939 06940 BamFile bam_file; 06941 06942 bool okflag = false; 06943 06944 if (bam_file.open_write(filename)) { 06945 if (bam_file.write_object(node())) { 06946 okflag = true; 06947 } 06948 bam_file.close(); 06949 } 06950 return okflag; 06951 } 06952 06953 //////////////////////////////////////////////////////////////////// 06954 // Function: NodePath::write_bam_stream 06955 // Access: Published 06956 // Description: Writes the contents of this node and below out to the 06957 // indicated stream. 06958 //////////////////////////////////////////////////////////////////// 06959 bool NodePath:: 06960 write_bam_stream(ostream &out) const { 06961 nassertr_always(!is_empty(), false); 06962 06963 BamFile bam_file; 06964 06965 bool okflag = false; 06966 06967 if (bam_file.open_write(out)) { 06968 if (bam_file.write_object(node())) { 06969 okflag = true; 06970 } 06971 bam_file.close(); 06972 } 06973 return okflag; 06974 } 06975 06976 //////////////////////////////////////////////////////////////////// 06977 // Function: NodePath::encode_to_bam_stream 06978 // Access: Published 06979 // Description: Converts the NodePath object into a single 06980 // stream of data using a BamWriter, and stores that 06981 // data in the indicated string. Returns true on 06982 // success, false on failure. 06983 // 06984 // If the BamWriter is NULL, this behaves the same way 06985 // as NodePath::write_bam_stream() and 06986 // PandaNode::encode_to_bam_stream(), in the sense that 06987 // it only writes this node and all nodes below it. 06988 // 06989 // However, if the BamWriter is not NULL, it behaves 06990 // very differently. In this case, it encodes the 06991 // *entire graph* of all nodes connected to the 06992 // NodePath, including all parent nodes and siblings. 06993 // This is necessary for correct streaming of related 06994 // NodePaths and restoration of instances, etc., but it 06995 // does mean you must detach() a node before writing it 06996 // if you want to limit the nodes that get written. 06997 // 06998 // This method is used by __reduce__ to handle streaming 06999 // of NodePaths to a pickle file. The BamWriter case is 07000 // used by the direct.stdpy.pickle module, while the 07001 // saner, non-BamWriter case is used when the standard 07002 // pickle module calls this function. 07003 //////////////////////////////////////////////////////////////////// 07004 bool NodePath:: 07005 encode_to_bam_stream(string &data, BamWriter *writer) const { 07006 data.clear(); 07007 ostringstream stream; 07008 07009 DatagramOutputFile dout; 07010 if (!dout.open(stream)) { 07011 return false; 07012 } 07013 07014 BamWriter local_writer; 07015 bool used_local_writer = false; 07016 if (writer == NULL) { 07017 // Create our own writer. 07018 07019 if (!dout.write_header(_bam_header)) { 07020 return false; 07021 } 07022 writer = &local_writer; 07023 used_local_writer = true; 07024 } 07025 07026 writer->set_target(&dout); 07027 07028 int num_nodes = get_num_nodes(); 07029 if (used_local_writer && num_nodes > 1) { 07030 // In this case--no BamWriter--we only write the bottom node. 07031 num_nodes = 1; 07032 } 07033 07034 // Write an initial Datagram to represent the error type and 07035 // number of nodes. 07036 Datagram dg; 07037 dg.add_uint8(_error_type); 07038 dg.add_int32(num_nodes); 07039 07040 if (!dout.put_datagram(dg)) { 07041 writer->set_target(NULL); 07042 return false; 07043 } 07044 07045 // Now write the nodes, one at a time. 07046 for (int i = 0; i < num_nodes; ++i) { 07047 PandaNode *node = get_node(num_nodes - i - 1); 07048 nassertr(node != NULL, false); 07049 if (!writer->write_object(node)) { 07050 writer->set_target(NULL); 07051 return false; 07052 } 07053 } 07054 writer->set_target(NULL); 07055 07056 data = stream.str(); 07057 return true; 07058 } 07059 07060 //////////////////////////////////////////////////////////////////// 07061 // Function: NodePath::decode_from_bam_stream 07062 // Access: Published, Static 07063 // Description: Reads the string created by a previous call to 07064 // encode_to_bam_stream(), and extracts and 07065 // returns the NodePath on that string. Returns NULL on 07066 // error. 07067 //////////////////////////////////////////////////////////////////// 07068 NodePath NodePath:: 07069 decode_from_bam_stream(const string &data, BamReader *reader) { 07070 NodePath result; 07071 07072 istringstream stream(data); 07073 07074 DatagramInputFile din; 07075 if (!din.open(stream)) { 07076 return NodePath::fail(); 07077 } 07078 07079 BamReader local_reader; 07080 if (reader == NULL) { 07081 // Create a local reader. 07082 07083 string head; 07084 if (!din.read_header(head, _bam_header.size())) { 07085 return NodePath::fail(); 07086 } 07087 07088 if (head != _bam_header) { 07089 return NodePath::fail(); 07090 } 07091 07092 reader = &local_reader; 07093 } 07094 07095 reader->set_source(&din); 07096 07097 // One initial datagram to encode the error type, and the number of nodes. 07098 Datagram dg; 07099 if (!din.get_datagram(dg)) { 07100 return NodePath::fail(); 07101 } 07102 07103 DatagramIterator dgi(dg); 07104 ErrorType error_type = (ErrorType)dgi.get_uint8(); 07105 int num_nodes = dgi.get_int32(); 07106 if (num_nodes == 0) { 07107 // An empty NodePath. 07108 result._error_type = error_type; 07109 07110 } else { 07111 // A real NodePath. Ignore error_type. 07112 for (int i = 0; i < num_nodes; ++i) { 07113 TypedWritable *object = reader->read_object(); 07114 07115 if (object == (TypedWritable *)NULL || 07116 !object->is_of_type(PandaNode::get_class_type())) { 07117 reader->set_source(NULL); 07118 return NodePath::fail(); 07119 } 07120 07121 if (!reader->resolve()) { 07122 reader->set_source(NULL); 07123 return NodePath::fail(); 07124 } 07125 07126 PandaNode *node = DCAST(PandaNode, object); 07127 result = NodePath(result, node); 07128 } 07129 } 07130 07131 reader->set_source(NULL); 07132 07133 return result; 07134 } 07135 07136 //////////////////////////////////////////////////////////////////// 07137 // Function: NodePath::find_common_ancestor 07138 // Access: Private, Static 07139 // Description: Walks up from both NodePaths to find the first node 07140 // that both have in common, if any. Fills a_count and 07141 // b_count with the number of nodes below the common 07142 // node in each path. 07143 // 07144 // The return value is the NodePathComponent of the node 07145 // they have in common, or NULL if they have nothing in 07146 // common. 07147 //////////////////////////////////////////////////////////////////// 07148 NodePathComponent *NodePath:: 07149 find_common_ancestor(const NodePath &a, const NodePath &b, 07150 int &a_count, int &b_count, Thread *current_thread) { 07151 nassertr(!a.is_empty() && !b.is_empty(), NULL); 07152 NodePathComponent *ac = a._head; 07153 NodePathComponent *bc = b._head; 07154 a_count = 0; 07155 b_count = 0; 07156 07157 int pipeline_stage = current_thread->get_pipeline_stage(); 07158 07159 // Shorten up the longer one until they are the same length. 07160 while (ac->get_length(pipeline_stage, current_thread) > bc->get_length(pipeline_stage, current_thread)) { 07161 nassertr(ac != (NodePathComponent *)NULL, NULL); 07162 ac = ac->get_next(pipeline_stage, current_thread); 07163 a_count++; 07164 } 07165 while (bc->get_length(pipeline_stage, current_thread) > ac->get_length(pipeline_stage, current_thread)) { 07166 nassertr(bc != (NodePathComponent *)NULL, NULL); 07167 bc = bc->get_next(pipeline_stage, current_thread); 07168 b_count++; 07169 } 07170 07171 // Now shorten them both up until we reach the same component. 07172 while (ac != bc) { 07173 // These shouldn't go to NULL unless they both go there together. 07174 nassertr(ac != (NodePathComponent *)NULL, NULL); 07175 nassertr(bc != (NodePathComponent *)NULL, NULL); 07176 ac = ac->get_next(pipeline_stage, current_thread); 07177 a_count++; 07178 bc = bc->get_next(pipeline_stage, current_thread); 07179 b_count++; 07180 } 07181 07182 return ac; 07183 } 07184 07185 //////////////////////////////////////////////////////////////////// 07186 // Function: NodePath::r_get_net_state 07187 // Access: Private 07188 // Description: Recursively determines the net state changes to the 07189 // indicated component node from the root of the graph. 07190 //////////////////////////////////////////////////////////////////// 07191 CPT(RenderState) NodePath:: 07192 r_get_net_state(NodePathComponent *comp, Thread *current_thread) const { 07193 if (comp == (NodePathComponent *)NULL) { 07194 return RenderState::make_empty(); 07195 } else { 07196 CPT(RenderState) state = comp->get_node()->get_state(current_thread); 07197 int pipeline_stage = current_thread->get_pipeline_stage(); 07198 return r_get_net_state(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(state); 07199 } 07200 } 07201 07202 //////////////////////////////////////////////////////////////////// 07203 // Function: NodePath::r_get_partial_state 07204 // Access: Private 07205 // Description: Recursively determines the net state changes to the 07206 // indicated component node from the nth node above it. 07207 // If n exceeds the length of the path, this returns the 07208 // net transform from the root of the graph. 07209 //////////////////////////////////////////////////////////////////// 07210 CPT(RenderState) NodePath:: 07211 r_get_partial_state(NodePathComponent *comp, int n, 07212 Thread *current_thread) const { 07213 if (n == 0 || comp == (NodePathComponent *)NULL) { 07214 return RenderState::make_empty(); 07215 } else { 07216 CPT(RenderState) state = comp->get_node()->get_state(current_thread); 07217 int pipeline_stage = current_thread->get_pipeline_stage(); 07218 return r_get_partial_state(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(state); 07219 } 07220 } 07221 07222 //////////////////////////////////////////////////////////////////// 07223 // Function: NodePath::r_get_net_transform 07224 // Access: Private 07225 // Description: Recursively determines the net transform to the 07226 // indicated component node from the root of the graph. 07227 //////////////////////////////////////////////////////////////////// 07228 CPT(TransformState) NodePath:: 07229 r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const { 07230 if (comp == (NodePathComponent *)NULL) { 07231 return TransformState::make_identity(); 07232 } else { 07233 int pipeline_stage = current_thread->get_pipeline_stage(); 07234 CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread); 07235 PandaNode *node = comp->get_node(); 07236 CPT(TransformState) transform = node->get_transform(current_thread); 07237 07238 CPT(RenderEffects) effects = node->get_effects(current_thread); 07239 if (effects->has_adjust_transform()) { 07240 effects->adjust_transform(net_transform, transform, node); 07241 } 07242 07243 return net_transform->compose(transform); 07244 } 07245 } 07246 07247 //////////////////////////////////////////////////////////////////// 07248 // Function: NodePath::r_get_partial_transform 07249 // Access: Private 07250 // Description: Recursively determines the net transform to the 07251 // indicated component node from the nth node above it. 07252 // If n exceeds the length of the path, this returns the 07253 // net transform from the root of the graph. 07254 // 07255 // If any node in the path had a net_transform effect 07256 // applied, returns NULL--in this case the partial 07257 // transform cannot be easily determined. 07258 //////////////////////////////////////////////////////////////////// 07259 CPT(TransformState) NodePath:: 07260 r_get_partial_transform(NodePathComponent *comp, int n, 07261 Thread *current_thread) const { 07262 if (n == 0 || comp == (NodePathComponent *)NULL) { 07263 return TransformState::make_identity(); 07264 } else { 07265 if (comp->get_node()->get_effects(current_thread)->has_adjust_transform()) { 07266 return NULL; 07267 } 07268 CPT(TransformState) transform = comp->get_node()->get_transform(current_thread); 07269 int pipeline_stage = current_thread->get_pipeline_stage(); 07270 CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread); 07271 if (partial == (const TransformState *)NULL) { 07272 return NULL; 07273 } 07274 return partial->compose(transform); 07275 } 07276 } 07277 07278 //////////////////////////////////////////////////////////////////// 07279 // Function: NodePath::r_get_net_prev_transform 07280 // Access: Private 07281 // Description: Recursively determines the net "previous" transform 07282 // to the indicated component node from the root of the 07283 // graph. 07284 //////////////////////////////////////////////////////////////////// 07285 CPT(TransformState) NodePath:: 07286 r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const { 07287 if (comp == (NodePathComponent *)NULL) { 07288 return TransformState::make_identity(); 07289 } else { 07290 CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread); 07291 int pipeline_stage = current_thread->get_pipeline_stage(); 07292 return r_get_net_prev_transform(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(transform); 07293 } 07294 } 07295 07296 //////////////////////////////////////////////////////////////////// 07297 // Function: NodePath::r_get_partial_prev_transform 07298 // Access: Private 07299 // Description: Recursively determines the net "previous" transform 07300 // to the indicated component node from the nth node 07301 // above it. If n exceeds the length of the path, this 07302 // returns the net previous transform from the root of 07303 // the graph. 07304 //////////////////////////////////////////////////////////////////// 07305 CPT(TransformState) NodePath:: 07306 r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const { 07307 if (n == 0 || comp == (NodePathComponent *)NULL) { 07308 return TransformState::make_identity(); 07309 } else { 07310 CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread); 07311 int pipeline_stage = current_thread->get_pipeline_stage(); 07312 return r_get_partial_prev_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(transform); 07313 } 07314 } 07315 07316 //////////////////////////////////////////////////////////////////// 07317 // Function: NodePath::find_matches 07318 // Access: Private 07319 // Description: Finds up to max_matches matches against the given 07320 // path string from this node and deeper. The 07321 // max_matches count indicates the maximum number of 07322 // matches to return, or -1 not to limit the number 07323 // returned. 07324 //////////////////////////////////////////////////////////////////// 07325 void NodePath:: 07326 find_matches(NodePathCollection &result, const string &path, 07327 int max_matches) const { 07328 if (is_empty()) { 07329 pgraph_cat.warning() 07330 << "Attempt to extend an empty NodePath by '" << path 07331 << "'.\n"; 07332 return; 07333 } 07334 FindApproxPath approx_path; 07335 if (approx_path.add_string(path)) { 07336 find_matches(result, approx_path, max_matches); 07337 } 07338 } 07339 07340 //////////////////////////////////////////////////////////////////// 07341 // Function: NodePath::find_matches 07342 // Access: Private 07343 // Description: Finds up to max_matches matches against the given 07344 // approx_path from this node and deeper. The 07345 // max_matches count indicates the maximum number of 07346 // matches to return, or -1 not to limit the number 07347 // returned. 07348 //////////////////////////////////////////////////////////////////// 07349 void NodePath:: 07350 find_matches(NodePathCollection &result, FindApproxPath &approx_path, 07351 int max_matches) const { 07352 if (is_empty()) { 07353 pgraph_cat.warning() 07354 << "Attempt to extend an empty NodePath by: " << approx_path << ".\n"; 07355 return; 07356 } 07357 07358 // We start with just one entry on the level. 07359 FindApproxLevelEntry *level = 07360 new FindApproxLevelEntry(WorkingNodePath(*this), approx_path); 07361 nassertv(level->_node_path.is_valid()); 07362 07363 find_matches(result, level, max_matches); 07364 } 07365 07366 //////////////////////////////////////////////////////////////////// 07367 // Function: NodePath::find_matches 07368 // Access: Private 07369 // Description: The fundamental implementation of find_matches(), 07370 // given a starting level (a linked list of 07371 // FindApproxLevelEntry objects). 07372 //////////////////////////////////////////////////////////////////// 07373 void NodePath:: 07374 find_matches(NodePathCollection &result, FindApproxLevelEntry *level, 07375 int max_matches) const { 07376 07377 int num_levels_remaining = _max_search_depth; 07378 07379 FindApproxLevelEntry *deleted_entries = NULL; 07380 07381 while (num_levels_remaining > 0 && level != NULL) { 07382 if (pgraph_cat.is_spam()) { 07383 pgraph_cat.spam() 07384 << "find_matches pass: " << result << ", " 07385 << max_matches << ", " << num_levels_remaining << "\n"; 07386 level->write_level(pgraph_cat.spam(false), 4); 07387 } 07388 07389 num_levels_remaining--; 07390 07391 FindApproxLevelEntry *next_level = NULL; 07392 07393 // For each node in the current level, build up the set of possible 07394 // matches in the next level. 07395 FindApproxLevelEntry *entry = level; 07396 while (entry != (FindApproxLevelEntry *)NULL) { 07397 if (entry->consider_node(result, next_level, max_matches, 0)) { 07398 // If we found the requisite number of matches, we can stop. 07399 // Delete all remaining entries and return immediately. 07400 07401 while (entry != (FindApproxLevelEntry *)NULL) { 07402 FindApproxLevelEntry *next = entry->_next; 07403 delete entry; 07404 entry = next; 07405 } 07406 while (next_level != (FindApproxLevelEntry *)NULL) { 07407 FindApproxLevelEntry *next = next_level->_next; 07408 delete next_level; 07409 next_level = next; 07410 } 07411 while (deleted_entries != (FindApproxLevelEntry *)NULL) { 07412 FindApproxLevelEntry *next = deleted_entries->_next; 07413 delete deleted_entries; 07414 deleted_entries = next; 07415 } 07416 return; 07417 } 07418 07419 // Move the entry to the delete chain so we can delete it before 07420 // we return from this method. (We can't delete it immediately, 07421 // because there might be WorkingNodePaths in the next_level 07422 // that reference the WorkingNodePath object within the entry.) 07423 FindApproxLevelEntry *next = entry->_next; 07424 entry->_next = deleted_entries; 07425 deleted_entries = entry; 07426 07427 entry = next; 07428 } 07429 07430 // Make sure the remaining entries from this level are added to 07431 // the delete chain. 07432 while (entry != (FindApproxLevelEntry *)NULL) { 07433 FindApproxLevelEntry *next = entry->_next; 07434 entry->_next = deleted_entries; 07435 deleted_entries = entry; 07436 07437 entry = next; 07438 } 07439 07440 level = next_level; 07441 } 07442 07443 // Now it's safe to delete all entries on the delete chain. 07444 while (deleted_entries != (FindApproxLevelEntry *)NULL) { 07445 FindApproxLevelEntry *next = deleted_entries->_next; 07446 delete deleted_entries; 07447 deleted_entries = next; 07448 } 07449 } 07450 07451 //////////////////////////////////////////////////////////////////// 07452 // Function: NodePath::r_clear_model_nodes 07453 // Access: Private 07454 // Description: The recursive implementation of 07455 // clear_model_nodes(). This walks through the 07456 // subgraph defined by the indicated node and below. 07457 //////////////////////////////////////////////////////////////////// 07458 int NodePath:: 07459 r_clear_model_nodes(PandaNode *node) { 07460 int count = 0; 07461 07462 if (node->is_of_type(ModelNode::get_class_type())) { 07463 ModelNode *mnode; 07464 DCAST_INTO_R(mnode, node, count); 07465 mnode->set_preserve_transform(ModelNode::PT_drop_node); 07466 ++count; 07467 } 07468 07469 PandaNode::Children cr = node->get_children(); 07470 int num_children = cr.get_num_children(); 07471 for (int i = 0; i < num_children; i++) { 07472 count += r_clear_model_nodes(cr.get_child(i)); 07473 } 07474 07475 return count; 07476 } 07477 07478 //////////////////////////////////////////////////////////////////// 07479 // Function: NodePath::r_adjust_all_priorities 07480 // Access: Private 07481 // Description: The recursive implementation of 07482 // adjust_all_priorities(). This walks through the 07483 // subgraph defined by the indicated node and below. 07484 //////////////////////////////////////////////////////////////////// 07485 void NodePath:: 07486 r_adjust_all_priorities(PandaNode *node, int adjustment) { 07487 node->set_state(node->get_state()->adjust_all_priorities(adjustment)); 07488 if (node->is_geom_node()) { 07489 GeomNode *gnode; 07490 DCAST_INTO_V(gnode, node); 07491 07492 int num_geoms = gnode->get_num_geoms(); 07493 for (int i = 0; i < num_geoms; i++) { 07494 gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment)); 07495 } 07496 } 07497 07498 PandaNode::Children cr = node->get_children(); 07499 int num_children = cr.get_num_children(); 07500 for (int i = 0; i < num_children; i++) { 07501 r_adjust_all_priorities(cr.get_child(i), adjustment); 07502 } 07503 } 07504 07505 //////////////////////////////////////////////////////////////////// 07506 // Function: NodePath::r_force_recompute_bounds 07507 // Access: Private 07508 // Description: 07509 //////////////////////////////////////////////////////////////////// 07510 void NodePath:: 07511 r_force_recompute_bounds(PandaNode *node) { 07512 if (node->is_geom_node()) { 07513 GeomNode *gnode; 07514 DCAST_INTO_V(gnode, node); 07515 07516 int num_geoms = gnode->get_num_geoms(); 07517 for (int i = 0; i < num_geoms; i++) { 07518 const Geom *geom = gnode->get_geom(i); 07519 geom->mark_bounds_stale(); 07520 } 07521 } 07522 07523 node->mark_bounds_stale(); 07524 07525 // Now consider children. 07526 PandaNode::Children cr = node->get_children(); 07527 int num_children = cr.get_num_children(); 07528 for (int i = 0; i < num_children; i++) { 07529 r_force_recompute_bounds(cr.get_child(i)); 07530 } 07531 } 07532 07533 //////////////////////////////////////////////////////////////////// 07534 // Function: NodePath::r_set_collide_mask 07535 // Access: Private 07536 // Description: Recursively applies the indicated collide mask to the 07537 // nodes at and below this node. 07538 //////////////////////////////////////////////////////////////////// 07539 void NodePath:: 07540 r_set_collide_mask(PandaNode *node, 07541 CollideMask and_mask, CollideMask or_mask, 07542 TypeHandle node_type) { 07543 if (node->is_of_type(node_type)) { 07544 CollideMask into_collide_mask = node->get_into_collide_mask(); 07545 into_collide_mask = (into_collide_mask & and_mask) | or_mask; 07546 node->set_into_collide_mask(into_collide_mask); 07547 } 07548 07549 PandaNode::Children cr = node->get_children(); 07550 int num_children = cr.get_num_children(); 07551 for (int i = 0; i < num_children; i++) { 07552 r_set_collide_mask(cr.get_child(i), and_mask, or_mask, node_type); 07553 } 07554 } 07555 07556 //////////////////////////////////////////////////////////////////// 07557 // Function: NodePath::r_has_vertex_column 07558 // Access: Private 07559 // Description: 07560 //////////////////////////////////////////////////////////////////// 07561 bool NodePath:: 07562 r_has_vertex_column(PandaNode *node, const InternalName *name) const { 07563 if (node->is_geom_node()) { 07564 GeomNode *gnode; 07565 DCAST_INTO_R(gnode, node, false); 07566 07567 int num_geoms = gnode->get_num_geoms(); 07568 for (int i = 0; i < num_geoms; i++) { 07569 const Geom *geom = gnode->get_geom(i); 07570 CPT(GeomVertexData) vdata = geom->get_vertex_data(); 07571 if (vdata->has_column(name)) { 07572 return true; 07573 } 07574 } 07575 } 07576 07577 // Now consider children. 07578 PandaNode::Children cr = node->get_children(); 07579 int num_children = cr.get_num_children(); 07580 for (int i = 0; i < num_children; i++) { 07581 PandaNode *child = cr.get_child(i); 07582 if (r_has_vertex_column(child, name)) { 07583 return true; 07584 } 07585 } 07586 07587 return false; 07588 } 07589 07590 //////////////////////////////////////////////////////////////////// 07591 // Function: NodePath::r_find_all_vertex_columns 07592 // Access: Private 07593 // Description: 07594 //////////////////////////////////////////////////////////////////// 07595 void NodePath:: 07596 r_find_all_vertex_columns(PandaNode *node, 07597 NodePath::InternalNames &vertex_columns) const { 07598 if (node->is_geom_node()) { 07599 GeomNode *gnode; 07600 DCAST_INTO_V(gnode, node); 07601 07602 int num_geoms = gnode->get_num_geoms(); 07603 for (int i = 0; i < num_geoms; ++i) { 07604 const Geom *geom = gnode->get_geom(i); 07605 const GeomVertexFormat *format = geom->get_vertex_data()->get_format(); 07606 int num_arrays = format->get_num_arrays(); 07607 for (int j = 0; j < num_arrays; ++j) { 07608 const GeomVertexArrayFormat *array = format->get_array(j); 07609 int num_columns = array->get_num_columns(); 07610 for (int k = 0; k < num_columns; ++k) { 07611 const GeomVertexColumn *column = array->get_column(k); 07612 vertex_columns.insert(column->get_name()); 07613 } 07614 } 07615 } 07616 } 07617 07618 // Now consider children. 07619 PandaNode::Children cr = node->get_children(); 07620 int num_children = cr.get_num_children(); 07621 for (int i = 0; i < num_children; i++) { 07622 PandaNode *child = cr.get_child(i); 07623 r_find_all_vertex_columns(child, vertex_columns); 07624 } 07625 } 07626 07627 //////////////////////////////////////////////////////////////////// 07628 // Function: NodePath::r_find_texture 07629 // Access: Private 07630 // Description: 07631 //////////////////////////////////////////////////////////////////// 07632 Texture *NodePath:: 07633 r_find_texture(PandaNode *node, const RenderState *state, 07634 const GlobPattern &glob) const { 07635 if (node->is_geom_node()) { 07636 GeomNode *gnode; 07637 DCAST_INTO_R(gnode, node, NULL); 07638 07639 int num_geoms = gnode->get_num_geoms(); 07640 for (int i = 0; i < num_geoms; i++) { 07641 CPT(RenderState) geom_state = 07642 state->compose(gnode->get_geom_state(i)); 07643 07644 // Look for a TextureAttrib on the state. 07645 const RenderAttrib *attrib = 07646 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07647 if (attrib != (const RenderAttrib *)NULL) { 07648 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07649 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07650 Texture *texture = ta->get_on_texture(ta->get_on_stage(i)); 07651 if (texture != (Texture *)NULL) { 07652 if (glob.matches(texture->get_name())) { 07653 return texture; 07654 } 07655 } 07656 } 07657 } 07658 } 07659 } 07660 07661 // Now consider children. 07662 PandaNode::Children cr = node->get_children(); 07663 int num_children = cr.get_num_children(); 07664 for (int i = 0; i < num_children; i++) { 07665 PandaNode *child = cr.get_child(i); 07666 CPT(RenderState) next_state = state->compose(child->get_state()); 07667 07668 Texture *result = r_find_texture(child, next_state, glob); 07669 if (result != (Texture *)NULL) { 07670 return result; 07671 } 07672 } 07673 07674 return NULL; 07675 } 07676 07677 //////////////////////////////////////////////////////////////////// 07678 // Function: NodePath::r_find_all_textures 07679 // Access: Private 07680 // Description: 07681 //////////////////////////////////////////////////////////////////// 07682 void NodePath:: 07683 r_find_all_textures(PandaNode *node, const RenderState *state, 07684 NodePath::Textures &textures) const { 07685 if (node->is_geom_node()) { 07686 GeomNode *gnode; 07687 DCAST_INTO_V(gnode, node); 07688 07689 int num_geoms = gnode->get_num_geoms(); 07690 for (int i = 0; i < num_geoms; i++) { 07691 CPT(RenderState) geom_state = 07692 state->compose(gnode->get_geom_state(i)); 07693 07694 // Look for a TextureAttrib on the state. 07695 const RenderAttrib *attrib = 07696 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07697 if (attrib != (const RenderAttrib *)NULL) { 07698 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07699 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07700 Texture *texture = ta->get_on_texture(ta->get_on_stage(i)); 07701 if (texture != (Texture *)NULL) { 07702 textures.insert(texture); 07703 } 07704 } 07705 } 07706 } 07707 } 07708 07709 // Now consider children. 07710 PandaNode::Children cr = node->get_children(); 07711 int num_children = cr.get_num_children(); 07712 for (int i = 0; i < num_children; i++) { 07713 PandaNode *child = cr.get_child(i); 07714 CPT(RenderState) next_state = state->compose(child->get_state()); 07715 r_find_all_textures(child, next_state, textures); 07716 } 07717 } 07718 07719 //////////////////////////////////////////////////////////////////// 07720 // Function: NodePath::r_find_texture 07721 // Access: Private 07722 // Description: 07723 //////////////////////////////////////////////////////////////////// 07724 Texture * NodePath:: 07725 r_find_texture(PandaNode *node, TextureStage *stage) const { 07726 // Look for a TextureAttrib on the node. 07727 const RenderAttrib *attrib = 07728 node->get_attrib(TextureAttrib::get_class_slot()); 07729 if (attrib != (const RenderAttrib *)NULL) { 07730 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07731 if (ta->has_on_stage(stage)) { 07732 return ta->get_on_texture(stage); 07733 } 07734 } 07735 07736 if (node->is_geom_node()) { 07737 GeomNode *gnode; 07738 DCAST_INTO_R(gnode, node, NULL); 07739 07740 int num_geoms = gnode->get_num_geoms(); 07741 for (int i = 0; i < num_geoms; i++) { 07742 CPT(RenderState) geom_state = gnode->get_geom_state(i); 07743 07744 // Look for a TextureAttrib on the state. 07745 const RenderAttrib *attrib = 07746 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07747 if (attrib != (const RenderAttrib *)NULL) { 07748 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07749 if (ta->has_on_stage(stage)) { 07750 return ta->get_on_texture(stage); 07751 } 07752 } 07753 } 07754 } 07755 07756 // Now consider children. 07757 PandaNode::Children cr = node->get_children(); 07758 int num_children = cr.get_num_children(); 07759 for (int i = 0; i < num_children; i++) { 07760 PandaNode *child = cr.get_child(i); 07761 07762 Texture *result = r_find_texture(child, stage); 07763 if (result != (Texture *)NULL) { 07764 return result; 07765 } 07766 } 07767 07768 return NULL; 07769 } 07770 07771 //////////////////////////////////////////////////////////////////// 07772 // Function: NodePath::r_find_all_textures 07773 // Access: Private 07774 // Description: 07775 //////////////////////////////////////////////////////////////////// 07776 void NodePath:: 07777 r_find_all_textures(PandaNode *node, TextureStage *stage, 07778 NodePath::Textures &textures) const { 07779 // Look for a TextureAttrib on the node. 07780 const RenderAttrib *attrib = 07781 node->get_attrib(TextureAttrib::get_class_slot()); 07782 if (attrib != (const RenderAttrib *)NULL) { 07783 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07784 if (ta->has_on_stage(stage)) { 07785 textures.insert(ta->get_on_texture(stage)); 07786 } 07787 } 07788 07789 if (node->is_geom_node()) { 07790 GeomNode *gnode; 07791 DCAST_INTO_V(gnode, node); 07792 07793 int num_geoms = gnode->get_num_geoms(); 07794 for (int i = 0; i < num_geoms; i++) { 07795 CPT(RenderState) geom_state = gnode->get_geom_state(i); 07796 07797 // Look for a TextureAttrib on the state. 07798 const RenderAttrib *attrib = 07799 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07800 if (attrib != (const RenderAttrib *)NULL) { 07801 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07802 if (ta->has_on_stage(stage)) { 07803 textures.insert(ta->get_on_texture(stage)); 07804 } 07805 } 07806 } 07807 } 07808 07809 // Now consider children. 07810 PandaNode::Children cr = node->get_children(); 07811 int num_children = cr.get_num_children(); 07812 for (int i = 0; i < num_children; i++) { 07813 PandaNode *child = cr.get_child(i); 07814 r_find_all_textures(child, stage, textures); 07815 } 07816 } 07817 07818 //////////////////////////////////////////////////////////////////// 07819 // Function: NodePath::r_find_texture_stage 07820 // Access: Private 07821 // Description: 07822 //////////////////////////////////////////////////////////////////// 07823 TextureStage * NodePath:: 07824 r_find_texture_stage(PandaNode *node, const RenderState *state, 07825 const GlobPattern &glob) const { 07826 if (node->is_geom_node()) { 07827 GeomNode *gnode; 07828 DCAST_INTO_R(gnode, node, NULL); 07829 07830 int num_geoms = gnode->get_num_geoms(); 07831 for (int i = 0; i < num_geoms; i++) { 07832 CPT(RenderState) geom_state = 07833 state->compose(gnode->get_geom_state(i)); 07834 07835 // Look for a TextureAttrib on the state. 07836 const RenderAttrib *attrib = 07837 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07838 if (attrib != (const RenderAttrib *)NULL) { 07839 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07840 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07841 TextureStage *texture_stage = ta->get_on_stage(i); 07842 if (texture_stage != (TextureStage *)NULL) { 07843 if (glob.matches(texture_stage->get_name())) { 07844 return texture_stage; 07845 } 07846 } 07847 } 07848 } 07849 } 07850 } 07851 07852 // Now consider children. 07853 PandaNode::Children cr = node->get_children(); 07854 int num_children = cr.get_num_children(); 07855 for (int i = 0; i < num_children; i++) { 07856 PandaNode *child = cr.get_child(i); 07857 CPT(RenderState) next_state = state->compose(child->get_state()); 07858 07859 TextureStage *result = r_find_texture_stage(child, next_state, glob); 07860 if (result != (TextureStage *)NULL) { 07861 return result; 07862 } 07863 } 07864 07865 return NULL; 07866 } 07867 07868 //////////////////////////////////////////////////////////////////// 07869 // Function: NodePath::r_find_all_texture_stages 07870 // Access: Private 07871 // Description: 07872 //////////////////////////////////////////////////////////////////// 07873 void NodePath:: 07874 r_find_all_texture_stages(PandaNode *node, const RenderState *state, 07875 NodePath::TextureStages &texture_stages) const { 07876 if (node->is_geom_node()) { 07877 GeomNode *gnode; 07878 DCAST_INTO_V(gnode, node); 07879 07880 int num_geoms = gnode->get_num_geoms(); 07881 for (int i = 0; i < num_geoms; i++) { 07882 CPT(RenderState) geom_state = 07883 state->compose(gnode->get_geom_state(i)); 07884 07885 // Look for a TextureAttrib on the state. 07886 const RenderAttrib *attrib = 07887 geom_state->get_attrib(TextureAttrib::get_class_slot()); 07888 if (attrib != (const RenderAttrib *)NULL) { 07889 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07890 for (int i = 0; i < ta->get_num_on_stages(); i++) { 07891 TextureStage *texture_stage = ta->get_on_stage(i); 07892 if (texture_stage != (TextureStage *)NULL) { 07893 texture_stages.insert(texture_stage); 07894 } 07895 } 07896 } 07897 } 07898 } 07899 07900 // Now consider children. 07901 PandaNode::Children cr = node->get_children(); 07902 int num_children = cr.get_num_children(); 07903 for (int i = 0; i < num_children; i++) { 07904 PandaNode *child = cr.get_child(i); 07905 CPT(RenderState) next_state = state->compose(child->get_state()); 07906 r_find_all_texture_stages(child, next_state, texture_stages); 07907 } 07908 } 07909 07910 //////////////////////////////////////////////////////////////////// 07911 // Function: NodePath::r_unify_texture_stages 07912 // Access: Private 07913 // Description: 07914 //////////////////////////////////////////////////////////////////// 07915 void NodePath:: 07916 r_unify_texture_stages(PandaNode *node, TextureStage *stage) { 07917 // Look for a TextureAttrib on the state. 07918 const RenderAttrib *attrib = 07919 node->get_attrib(TextureAttrib::get_class_slot()); 07920 if (attrib != (const RenderAttrib *)NULL) { 07921 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07922 CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage); 07923 if (new_attrib != ta) { 07924 node->set_attrib(new_attrib); 07925 } 07926 } 07927 07928 if (node->is_geom_node()) { 07929 GeomNode *gnode; 07930 DCAST_INTO_V(gnode, node); 07931 07932 int num_geoms = gnode->get_num_geoms(); 07933 for (int i = 0; i < num_geoms; i++) { 07934 CPT(RenderState) state = gnode->get_geom_state(i); 07935 07936 // Look for a TextureAttrib on the state. 07937 const RenderAttrib *attrib = 07938 state->get_attrib(TextureAttrib::get_class_slot()); 07939 if (attrib != (const RenderAttrib *)NULL) { 07940 const TextureAttrib *ta = DCAST(TextureAttrib, attrib); 07941 CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage); 07942 if (new_attrib != ta) { 07943 CPT(RenderState) new_state = state->add_attrib(new_attrib); 07944 gnode->set_geom_state(i, new_state); 07945 } 07946 } 07947 } 07948 } 07949 07950 // Now consider children. 07951 PandaNode::Children cr = node->get_children(); 07952 int num_children = cr.get_num_children(); 07953 for (int i = 0; i < num_children; i++) { 07954 PandaNode *child = cr.get_child(i); 07955 r_unify_texture_stages(child, stage); 07956 } 07957 } 07958 07959 //////////////////////////////////////////////////////////////////// 07960 // Function: NodePath::r_find_material 07961 // Access: Private 07962 // Description: 07963 //////////////////////////////////////////////////////////////////// 07964 Material *NodePath:: 07965 r_find_material(PandaNode *node, const RenderState *state, 07966 const GlobPattern &glob) const { 07967 if (node->is_geom_node()) { 07968 GeomNode *gnode; 07969 DCAST_INTO_R(gnode, node, NULL); 07970 07971 int num_geoms = gnode->get_num_geoms(); 07972 for (int i = 0; i < num_geoms; i++) { 07973 CPT(RenderState) geom_state = 07974 state->compose(gnode->get_geom_state(i)); 07975 07976 // Look for a MaterialAttrib on the state. 07977 const RenderAttrib *attrib = 07978 geom_state->get_attrib(MaterialAttrib::get_class_slot()); 07979 if (attrib != (const RenderAttrib *)NULL) { 07980 const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib); 07981 if (!ta->is_off()) { 07982 Material *material = ta->get_material(); 07983 if (material != (Material *)NULL) { 07984 if (glob.matches(material->get_name())) { 07985 return material; 07986 } 07987 } 07988 } 07989 } 07990 } 07991 } 07992 07993 // Now consider children. 07994 PandaNode::Children cr = node->get_children(); 07995 int num_children = cr.get_num_children(); 07996 for (int i = 0; i < num_children; i++) { 07997 PandaNode *child = cr.get_child(i); 07998 CPT(RenderState) next_state = state->compose(child->get_state()); 07999 08000 Material *result = r_find_material(child, next_state, glob); 08001 if (result != (Material *)NULL) { 08002 return result; 08003 } 08004 } 08005 08006 return NULL; 08007 } 08008 08009 //////////////////////////////////////////////////////////////////// 08010 // Function: NodePath::r_find_all_materials 08011 // Access: Private 08012 // Description: 08013 //////////////////////////////////////////////////////////////////// 08014 void NodePath:: 08015 r_find_all_materials(PandaNode *node, const RenderState *state, 08016 NodePath::Materials &materials) const { 08017 if (node->is_geom_node()) { 08018 GeomNode *gnode; 08019 DCAST_INTO_V(gnode, node); 08020 08021 int num_geoms = gnode->get_num_geoms(); 08022 for (int i = 0; i < num_geoms; i++) { 08023 CPT(RenderState) geom_state = 08024 state->compose(gnode->get_geom_state(i)); 08025 08026 // Look for a MaterialAttrib on the state. 08027 const RenderAttrib *attrib = 08028 geom_state->get_attrib(MaterialAttrib::get_class_slot()); 08029 if (attrib != (const RenderAttrib *)NULL) { 08030 const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib); 08031 if (!ta->is_off()) { 08032 Material *material = ta->get_material(); 08033 if (material != (Material *)NULL) { 08034 materials.insert(material); 08035 } 08036 } 08037 } 08038 } 08039 } 08040 08041 // Now consider children. 08042 PandaNode::Children cr = node->get_children(); 08043 int num_children = cr.get_num_children(); 08044 for (int i = 0; i < num_children; i++) { 08045 PandaNode *child = cr.get_child(i); 08046 CPT(RenderState) next_state = state->compose(child->get_state()); 08047 r_find_all_materials(child, next_state, materials); 08048 } 08049 } 08050 08051 #ifdef HAVE_PYTHON 08052 //////////////////////////////////////////////////////////////////// 08053 // Function: py_decode_NodePath_from_bam_stream 08054 // Access: Published 08055 // Description: This wrapper is defined as a global function to suit 08056 // pickle's needs. 08057 //////////////////////////////////////////////////////////////////// 08058 NodePath 08059 py_decode_NodePath_from_bam_stream(const string &data) { 08060 return py_decode_NodePath_from_bam_stream_persist(NULL, data); 08061 } 08062 #endif // HAVE_PYTHON 08063 08064 08065 #ifdef HAVE_PYTHON 08066 //////////////////////////////////////////////////////////////////// 08067 // Function: py_decode_NodePath_from_bam_stream_persist 08068 // Access: Published 08069 // Description: This wrapper is defined as a global function to suit 08070 // pickle's needs. 08071 //////////////////////////////////////////////////////////////////// 08072 NodePath 08073 py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &data) { 08074 BamReader *reader = NULL; 08075 if (unpickler != NULL) { 08076 PyObject *py_reader = PyObject_GetAttrString(unpickler, "bamReader"); 08077 if (py_reader == NULL) { 08078 // It's OK if there's no bamReader. 08079 PyErr_Clear(); 08080 } else { 08081 DTOOL_Call_ExtractThisPointerForType(py_reader, &Dtool_BamReader, (void **)&reader); 08082 Py_DECREF(py_reader); 08083 } 08084 } 08085 08086 return NodePath::decode_from_bam_stream(data, reader); 08087 } 08088 #endif // HAVE_PYTHON 08089