00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00079
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
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
00146
00147
00148
00149
00150
00151
00152
00153
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
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
00183
00184
00185
00186
00187
00188
00189
00190 NodePath NodePath::
00191 __copy__() const {
00192 if (is_empty()) {
00193
00194 return *this;
00195 }
00196
00197
00198
00199 return NodePath(node()->__copy__());
00200 }
00201 #endif // HAVE_PYTHON
00202
00203 #ifdef HAVE_PYTHON
00204
00205
00206
00207
00208
00209
00210
00211
00212 PyObject *NodePath::
00213 __deepcopy__(PyObject *self, PyObject *memo) const {
00214 IMPORT_THIS struct Dtool_PyTypedObject Dtool_NodePath;
00215
00216
00217 PyObject *dupe = PyDict_GetItem(memo, self);
00218 if (dupe != NULL) {
00219
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
00245
00246
00247
00248
00249
00250
00251
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
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 PyObject *NodePath::
00274 __reduce_persist__(PyObject *self, PyObject *pickler) const {
00275
00276
00277
00278
00279
00280 BamWriter *writer = NULL;
00281 if (pickler != NULL) {
00282 PyObject *py_writer = PyObject_GetAttrString(pickler, "bamWriter");
00283 if (py_writer == NULL) {
00284
00285 PyErr_Clear();
00286 } else {
00287 DTOOL_Call_ExtractThisPointerForType(py_writer, &Dtool_BamWriter, (void **)&writer);
00288 Py_DECREF(py_writer);
00289 }
00290 }
00291
00292
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
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
00312
00313
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
00323
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
00342
00343
00344
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
00387
00388
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
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
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
00424
00425 nassertr(comp != (NodePathComponent *)NULL, NULL);
00426 comp = comp->get_next(pipeline_stage, current_thread);
00427 index--;
00428 }
00429
00430
00431
00432 nassertr(comp != (NodePathComponent *)NULL, NULL);
00433 return comp->get_node();
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
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
00455
00456 nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
00457 comp = comp->get_next(pipeline_stage, current_thread);
00458 index--;
00459 }
00460
00461
00462
00463 nassertr(comp != (NodePathComponent *)NULL, NodePath::fail());
00464
00465 NodePath result;
00466 result._head = comp;
00467 return result;
00468 }
00469
00470
00471
00472
00473
00474
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
00498
00499
00500
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
00525
00526
00527
00528
00529
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
00553
00554
00555
00556
00557
00558
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
00587
00588
00589
00590
00591
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
00609
00610
00611
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
00633
00634
00635
00636
00637
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
00650
00651
00652
00653
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
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
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
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
00700
00701
00702
00703
00704
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
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
00724
00725
00726
00727
00728
00729
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
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
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
00787
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
00793 bool reparented = PandaNode::reparent(other._head, new_instance._head,
00794 sort, false, pipeline_stage,
00795 current_thread);
00796 if (!reparented) {
00797
00798
00799
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
00809 nassertr(reparented, new_instance);
00810 }
00811
00812
00813
00814
00815
00816
00817 return new_instance;
00818 }
00819
00820
00821
00822
00823
00824
00825
00826
00827
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
00843
00844
00845
00846
00847
00848
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
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
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
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916 void NodePath::
00917 remove_node(Thread *current_thread) {
00918 nassertv(_error_type != ET_not_found);
00919
00920
00921
00922
00923
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
00932 int key = get_key();
00933 (*this) = NodePath::removed();
00934 _backup_key = key;
00935
00936 } else {
00937
00938 (*this) = NodePath::removed();
00939 }
00940 }
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
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
00975
00976
00977
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
01004
01005
01006
01007 const RenderState *NodePath::
01008 get_state(Thread *current_thread) const {
01009
01010
01011 nassertr_always(!is_empty(), RenderState::make_empty());
01012 return node()->get_state(current_thread);
01013 }
01014
01015
01016
01017
01018
01019
01020
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
01055
01056
01057
01058
01059
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
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
01081
01082
01083
01084 const TransformState *NodePath::
01085 get_transform(Thread *current_thread) const {
01086
01087
01088 nassertr_always(!is_empty(), TransformState::make_identity());
01089 return node()->get_transform(current_thread);
01090 }
01091
01092
01093
01094
01095
01096
01097
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
01136
01137
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
01147
01148
01149
01150
01151
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
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
01173
01174
01175
01176
01177
01178 const TransformState *NodePath::
01179 get_prev_transform(Thread *current_thread) const {
01180
01181
01182 nassertr_always(!is_empty(), TransformState::make_identity());
01183 return node()->get_prev_transform(current_thread);
01184 }
01185
01186
01187
01188
01189
01190
01191
01192
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
01227
01228
01229
01230
01231
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
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
01253
01254
01255
01256
01257
01258
01259
01260
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
01295
01296
01297
01298
01299
01300
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
01334
01335
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
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
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
01365
01366
01367
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
01409
01410
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
01422
01423
01424
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
01435
01436
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
01447
01448
01449
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
01487
01488
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
01499
01500
01501
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
01539
01540
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
01551
01552
01553
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
01567
01568
01569
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
01583
01584
01585
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
01598
01599
01600
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
01613
01614
01615
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
01628
01629
01630
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
01643
01644
01645
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
01658
01659
01660
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
01673
01674
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
01685
01686
01687
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
01702
01703
01704
01705
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
01720
01721
01722
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
01732
01733
01734
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
01744
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
01776
01777
01778
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
01788
01789
01790
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
01796
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
01803
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
01834
01835
01836
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
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856
01857
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
01867
01868
01869
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
01880
01881
01882
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
01896
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
01927
01928
01929
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
01941
01942
01943
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
01953
01954
01955
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
01969
01970 set_transform(other, rel_transform->set_quat(quat));
01971 }
01972 }
01973
01974
01975
01976
01977
01978
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
01989
01990
01991
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
02001
02002
02003
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
02017
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
02048
02049
02050
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
02061
02062
02063
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
02073
02074
02075
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
02089
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
02120
02121
02122
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
02133
02134
02135
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
02146
02147
02148
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
02162
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
02171
02172
02173
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
02184
02185
02186
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
02200
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
02209
02210
02211
02212
02213
02214
02215 void NodePath::
02216 set_hpr_scale(const NodePath &other, const LVecBase3 &hpr, const LVecBase3 &scale) {
02217
02218
02219
02220
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
02230
02231
02232
02233
02234
02235
02236 void NodePath::
02237 set_quat_scale(const NodePath &other, const LQuaternion &quat,
02238 const LVecBase3 &scale) {
02239
02240
02241
02242
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
02252
02253
02254
02255
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
02269
02270
02271
02272
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
02286
02287
02288
02289
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
02303
02304
02305
02306
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
02320
02321
02322
02323
02324
02325 LMatrix4 NodePath::
02326 get_mat(const NodePath &other) const {
02327 CPT(TransformState) transform = get_transform(other);
02328
02329
02330
02331
02332
02333 return transform->get_mat();
02334 }
02335
02336
02337
02338
02339
02340
02341
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
02352
02353
02354
02355
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
02366
02367
02368
02369
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
02380
02381
02382
02383
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
02401
02402
02403
02404
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
02423
02424
02425
02426
02427
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
02437
02438
02439
02440
02441
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
02451
02452
02453
02454
02455
02456
02457
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
02467
02468
02469
02470
02471
02472
02473 void NodePath::
02474 clear_color() {
02475 nassertv_always(!is_empty());
02476 node()->clear_attrib(ColorAttrib::get_class_slot());
02477 }
02478
02479
02480
02481
02482
02483
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
02493
02494
02495
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
02517
02518
02519
02520
02521
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
02531
02532
02533
02534
02535
02536
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
02546
02547
02548
02549
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
02563
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
02573 node()->set_attrib(ColorScaleAttrib::make(scale), priority);
02574 }
02575 }
02576
02577
02578
02579
02580
02581
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
02595
02596 node()->set_attrib(csa->set_scale(scale), priority);
02597
02598 } else {
02599
02600 node()->set_attrib(ColorScaleAttrib::make(scale), priority);
02601 }
02602 }
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
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
02628
02629
02630
02631
02632
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
02646
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
02652 node()->set_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, scale)), priority);
02653 }
02654 }
02655
02656
02657
02658
02659
02660
02661
02662
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
02676
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
02682 node()->set_attrib(ColorScaleAttrib::make(LVecBase4(scale, scale, scale, 1.0f)), priority);
02683 }
02684 }
02685
02686
02687
02688
02689
02690
02691
02692
02693
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
02711
02712
02713
02714
02715
02716
02717
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
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
02734
02735 node()->set_attrib(la->add_on_light(light), priority);
02736
02737 } else {
02738
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
02746 if (priority != 0) {
02747
02748
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
02759
02760 node()->set_effect(ple->add_light(light));
02761
02762 } else {
02763
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
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785
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
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
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
02822
02823
02824 node()->set_attrib(la->add_off_light(light), priority);
02825
02826 } else {
02827
02828
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
02840
02841
02842
02843
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
02854
02855
02856
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
02898
02899
02900
02901
02902
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
02935
02936
02937
02938
02939
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
02957
02958
02959
02960
02961
02962
02963
02964
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
02986
02987
02988
02989
02990
02991
02992
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
03006
03007 node()->set_attrib(la->add_on_plane(clip_plane), priority);
03008
03009 } else {
03010
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
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031
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
03041
03042
03043
03044
03045
03046
03047
03048
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
03063
03064
03065 node()->set_attrib(la->add_off_plane(clip_plane), priority);
03066
03067 } else {
03068
03069
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
03080
03081
03082
03083
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
03093
03094
03095
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
03124
03125
03126
03127
03128
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
03149
03150
03151
03152
03153
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
03171
03172
03173
03174
03175
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
03194
03195
03196
03197
03198
03199
03200
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
03212
03213 node()->set_effect(la->add_on_occluder(occluder));
03214
03215 } else {
03216
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
03227
03228
03229
03230
03231 void NodePath::
03232 clear_occluder() {
03233 nassertv_always(!is_empty());
03234 node()->clear_effect(OccluderEffect::get_class_type());
03235 }
03236
03237
03238
03239
03240
03241
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
03268
03269
03270
03271
03272
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
03293
03294
03295
03296
03297
03298
03299
03300
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
03309
03310
03311
03312
03313
03314
03315
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
03324
03325
03326
03327
03328
03329
03330
03331
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
03341
03342
03343
03344
03345
03346
03347
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
03356
03357
03358
03359
03360
03361
03362
03363
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
03374
03375
03376
03377
03378 void NodePath::
03379 clear_scissor() {
03380 clear_effect(ScissorEffect::get_class_type());
03381 }
03382
03383
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393 bool NodePath::
03394 has_scissor() const {
03395 return has_effect(ScissorEffect::get_class_type());
03396 }
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415
03416
03417
03418
03419
03420
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
03430
03431
03432
03433
03434 void NodePath::
03435 clear_bin() {
03436 nassertv_always(!is_empty());
03437 node()->clear_attrib(CullBinAttrib::get_class_slot());
03438 }
03439
03440
03441
03442
03443
03444
03445
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
03455
03456
03457
03458
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
03475
03476
03477
03478
03479
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
03496
03497
03498
03499
03500
03501
03502
03503
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
03514
03515
03516
03517
03518
03519
03520
03521
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
03534
03535 node()->set_attrib(tsa->add_on_stage(stage, tex, priority), sg_priority);
03536
03537 } else {
03538
03539 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
03540 node()->set_attrib(tsa->add_on_stage(stage, tex, priority));
03541 }
03542 }
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552
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
03562
03563
03564
03565
03566
03567
03568
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
03581
03582
03583 node()->set_attrib(tsa->add_off_stage(stage, priority), sg_priority);
03584
03585 } else {
03586
03587
03588 CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
03589 node()->set_attrib(tsa->add_off_stage(stage, priority));
03590 }
03591 }
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602 void NodePath::
03603 clear_texture() {
03604 nassertv_always(!is_empty());
03605 node()->clear_attrib(TextureAttrib::get_class_slot());
03606 }
03607
03608
03609
03610
03611
03612
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
03637
03638
03639
03640
03641
03642
03643
03644
03645 bool NodePath::
03646 has_texture() const {
03647 return get_texture() != (Texture *)NULL;
03648 }
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
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
03676
03677
03678
03679
03680
03681
03682
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
03699
03700
03701
03702
03703
03704
03705
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
03723
03724
03725
03726
03727
03728
03729
03730
03731
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
03748
03749
03750
03751
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
03768
03769
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
03784 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03785 node()->set_attrib(sa->set_shader(sha, priority));
03786 }
03787 }
03788
03789
03790
03791
03792
03793
03794 void NodePath::
03795 set_shader_off(int priority) {
03796 set_shader(NULL, priority);
03797 }
03798
03799
03800
03801
03802
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
03817 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03818 node()->set_attrib(sa->set_shader_auto(priority));
03819 }
03820 }
03821
03822
03823
03824
03825
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
03840 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03841 node()->set_attrib(sa->set_shader_auto(shader_switch, priority));
03842 }
03843 }
03844
03845
03846
03847
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
03863
03864
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
03880
03881
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
03894 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
03895 node()->set_attrib(sa->set_shader_input(inp));
03896 }
03897 }
03898
03899
03900
03901
03902
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
03919
03920
03921
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
03940
03941
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
03958
03959
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
03968
03969
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
03978
03979
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
03988
03989
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
03999
04000
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
04009
04010
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
04019
04020
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
04029
04030
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
04039
04040
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
04049
04050
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
04059
04060
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
04069
04070
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
04079
04080
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
04089
04090
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
04099
04100
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
04109
04110
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
04119
04120
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
04129
04130
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
04139
04140
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
04150
04151
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
04160
04161
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
04170
04171
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
04180
04181
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
04190
04191
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
04200
04201
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
04210
04211
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
04220
04221
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
04229
04230
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
04239
04240
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
04249
04250
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
04259
04260
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
04269
04270
04271
04272 void NodePath::
04273 clear_shader_input(const string &id) {
04274 clear_shader_input(InternalName::make(id));
04275 }
04276
04277
04278
04279
04280
04281
04282
04283
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
04296 CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
04297 node()->set_attrib(sa->set_instance_count(instance_count));
04298 }
04299 }
04300
04301
04302
04303
04304
04305
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
04317
04318 node()->set_attrib(tma->add_stage(stage, transform));
04319
04320 } else {
04321
04322 node()->set_attrib(TexMatrixAttrib::make(stage, transform));
04323 }
04324 }
04325
04326
04327
04328
04329
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
04339
04340
04341
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
04364
04365
04366
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
04384
04385
04386
04387
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
04405
04406
04407
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
04421
04422 state = state->add_attrib(tma->add_stage(stage, transform));
04423
04424 } else {
04425
04426 state = state->add_attrib(TexMatrixAttrib::make(stage, transform));
04427 }
04428
04429
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
04439
04440 node()->set_attrib(new_state->get_attrib(TexMatrixAttrib::get_class_slot()));
04441 }
04442
04443
04444
04445
04446
04447
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
04466
04467
04468
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
04493
04494
04495
04496
04497
04498
04499
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
04525
04526
04527
04528
04529
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
04555
04556
04557
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
04567
04568
04569
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
04592
04593
04594
04595
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
04613
04614
04615
04616
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
04634
04635
04636
04637
04638
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
04656
04657
04658
04659
04660
04661
04662
04663
04664
04665
04666
04667
04668
04669 void NodePath::
04670 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to,
04671 int lens_index) {
04672 nassertv_always(!is_empty());
04673
04674 const RenderEffect *effect =
04675 node()->get_effect(TexProjectorEffect::get_class_type());
04676
04677 CPT(TexProjectorEffect) tpe;
04678
04679 if (effect != (const RenderEffect *)NULL) {
04680 tpe = DCAST(TexProjectorEffect, effect);
04681
04682 } else {
04683 tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make());
04684 }
04685
04686 node()->set_effect(tpe->add_stage(stage, from, to, lens_index));
04687 }
04688
04689
04690
04691
04692
04693
04694
04695 void NodePath::
04696 clear_tex_projector(TextureStage *stage) {
04697 nassertv_always(!is_empty());
04698
04699 const RenderEffect *effect =
04700 node()->get_effect(TexProjectorEffect::get_class_type());
04701 if (effect != (const RenderEffect *)NULL) {
04702 CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect);
04703 tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage));
04704
04705 if (tpe->is_empty()) {
04706 node()->clear_effect(TexProjectorEffect::get_class_type());
04707
04708 } else {
04709 node()->set_effect(tpe);
04710 }
04711 }
04712 }
04713
04714
04715
04716
04717
04718
04719
04720 void NodePath::
04721 clear_tex_projector() {
04722 nassertv_always(!is_empty());
04723 node()->clear_effect(TexProjectorEffect::get_class_type());
04724 }
04725
04726
04727
04728
04729
04730
04731
04732 bool NodePath::
04733 has_tex_projector(TextureStage *stage) const {
04734 nassertr_always(!is_empty(), false);
04735
04736 const RenderEffect *effect =
04737 node()->get_effect(TexProjectorEffect::get_class_type());
04738 if (effect != (const RenderEffect *)NULL) {
04739 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04740 return tpe->has_stage(stage);
04741 }
04742
04743 return false;
04744 }
04745
04746
04747
04748
04749
04750
04751
04752
04753
04754
04755 NodePath NodePath::
04756 get_tex_projector_from(TextureStage *stage) const {
04757 nassertr_always(!is_empty(), NodePath::fail());
04758
04759 const RenderEffect *effect =
04760 node()->get_effect(TexProjectorEffect::get_class_type());
04761 if (effect != (const RenderEffect *)NULL) {
04762 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04763 return tpe->get_from(stage);
04764 }
04765
04766 return NodePath::not_found();
04767 }
04768
04769
04770
04771
04772
04773
04774
04775
04776
04777
04778 NodePath NodePath::
04779 get_tex_projector_to(TextureStage *stage) const {
04780 nassertr_always(!is_empty(), NodePath::fail());
04781
04782 const RenderEffect *effect =
04783 node()->get_effect(TexProjectorEffect::get_class_type());
04784 if (effect != (const RenderEffect *)NULL) {
04785 const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
04786 return tpe->get_to(stage);
04787 }
04788
04789 return NodePath::not_found();
04790 }
04791
04792
04793
04794
04795
04796
04797
04798
04799
04800 void NodePath::
04801 project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) {
04802 nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type()));
04803 set_texture(stage, tex);
04804 set_tex_gen(stage, TexGenAttrib::M_world_position);
04805 set_tex_projector(stage, NodePath(), projector);
04806 }
04807
04808
04809
04810
04811
04812
04813
04814
04815
04816
04817
04818
04819
04820
04821
04822
04823
04824
04825
04826
04827
04828
04829
04830 void NodePath::
04831 set_normal_map(Texture *normal_map, const string &texcoord_name,
04832 bool preserve_color) {
04833 clear_normal_map();
04834
04835
04836 PT(TextureStage) normal_map_ts = new TextureStage("__normal_map");
04837 normal_map_ts->set_texcoord_name(texcoord_name);
04838 normal_map_ts->set_sort(-20);
04839 normal_map_ts->set_mode(TextureStage::M_replace);
04840 set_texture(normal_map_ts, normal_map);
04841
04842
04843
04844 PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32);
04845 PT(TextureStage) normalization_map_ts = new TextureStage("__normalization_map");
04846 normalization_map_ts->set_combine_rgb
04847 (TextureStage::CM_dot3_rgb,
04848 TextureStage::CS_texture, TextureStage::CO_src_color,
04849 TextureStage::CS_previous, TextureStage::CO_src_color);
04850 normalization_map_ts->set_texcoord_name("light_vector");
04851 normalization_map_ts->set_sort(-15);
04852 set_texture(normalization_map_ts, normalization_map);
04853
04854
04855 set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector,
04856 texcoord_name, NodePath());
04857
04858 if (preserve_color) {
04859
04860 PT(TextureStage) orig_color_ts = new TextureStage("__orig_color");
04861 orig_color_ts->set_combine_rgb
04862 (TextureStage::CM_modulate,
04863 TextureStage::CS_primary_color, TextureStage::CO_src_color,
04864 TextureStage::CS_previous, TextureStage::CO_src_color);
04865 set_texture(orig_color_ts, normal_map);
04866 }
04867 }
04868
04869
04870
04871
04872
04873
04874
04875 void NodePath::
04876 clear_normal_map() {
04877
04878
04879
04880
04881 CPT(RenderAttrib) attrib =
04882 get_state()->get_attrib(TextureAttrib::get_class_slot());
04883 if (attrib != (const RenderAttrib *)NULL) {
04884 const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
04885 for (int i = 0; i < ta->get_num_on_stages(); i++) {
04886 TextureStage *stage = ta->get_on_stage(i);
04887 if (stage->get_name() == "__normal_map") {
04888 clear_texture(stage);
04889
04890 } else if (stage->get_name() == "__normalization_map") {
04891 clear_texture(stage);
04892 clear_tex_gen(stage);
04893
04894 } else if (stage->get_name() == "__orig_color") {
04895 clear_texture(stage);
04896 }
04897 }
04898 }
04899 }
04900
04901
04902
04903
04904
04905
04906
04907
04908
04909
04910
04911
04912 bool NodePath::
04913 has_vertex_column(const InternalName *name) const {
04914 nassertr_always(!is_empty(), false);
04915 return r_has_vertex_column(node(), name);
04916 }
04917
04918
04919
04920
04921
04922
04923
04924 InternalNameCollection NodePath::
04925 find_all_vertex_columns() const {
04926 nassertr_always(!is_empty(), InternalNameCollection());
04927 InternalNames vertex_columns;
04928 r_find_all_vertex_columns(node(), vertex_columns);
04929
04930 InternalNameCollection tc;
04931 InternalNames::iterator ti;
04932 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04933 tc.add_name(*ti);
04934 }
04935 return tc;
04936 }
04937
04938
04939
04940
04941
04942
04943
04944
04945
04946 InternalNameCollection NodePath::
04947 find_all_vertex_columns(const string &name) const {
04948 nassertr_always(!is_empty(), InternalNameCollection());
04949 InternalNames vertex_columns;
04950 r_find_all_vertex_columns(node(), vertex_columns);
04951
04952 GlobPattern glob(name);
04953
04954 InternalNameCollection tc;
04955 InternalNames::iterator ti;
04956 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04957 InternalName *name = (*ti);
04958 if (glob.matches(name->get_name())) {
04959 tc.add_name(name);
04960 }
04961 }
04962 return tc;
04963 }
04964
04965
04966
04967
04968
04969
04970
04971 InternalNameCollection NodePath::
04972 find_all_texcoords() const {
04973 nassertr_always(!is_empty(), InternalNameCollection());
04974 InternalNames vertex_columns;
04975 r_find_all_vertex_columns(node(), vertex_columns);
04976
04977 CPT(InternalName) texcoord_name = InternalName::get_texcoord();
04978
04979 InternalNameCollection tc;
04980 InternalNames::iterator ti;
04981 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
04982 if ((*ti)->get_top() == texcoord_name) {
04983 tc.add_name(*ti);
04984 }
04985 }
04986 return tc;
04987 }
04988
04989
04990
04991
04992
04993
04994
04995
04996
04997 InternalNameCollection NodePath::
04998 find_all_texcoords(const string &name) const {
04999 nassertr_always(!is_empty(), InternalNameCollection());
05000 InternalNames vertex_columns;
05001 r_find_all_vertex_columns(node(), vertex_columns);
05002
05003 GlobPattern glob(name);
05004 CPT(InternalName) texcoord_name = InternalName::get_texcoord();
05005
05006 InternalNameCollection tc;
05007 InternalNames::iterator ti;
05008 for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
05009 InternalName *name = (*ti);
05010 if (name->get_top() == texcoord_name) {
05011
05012
05013 int index = name->find_ancestor("texcoord");
05014 nassertr(index != -1, InternalNameCollection());
05015 string net_basename = name->get_net_basename(index - 1);
05016
05017 if (glob.matches(net_basename)) {
05018 tc.add_name(name);
05019 }
05020 }
05021 }
05022 return tc;
05023 }
05024
05025
05026
05027
05028
05029
05030
05031
05032
05033 Texture *NodePath::
05034 find_texture(const string &name) const {
05035 nassertr_always(!is_empty(), NULL);
05036 GlobPattern glob(name);
05037 return r_find_texture(node(), get_net_state(), glob);
05038 }
05039
05040
05041
05042
05043
05044
05045
05046
05047
05048 Texture *NodePath::
05049 find_texture(TextureStage *stage) const {
05050 nassertr_always(!is_empty(), NULL);
05051 return r_find_texture(node(), stage);
05052 }
05053
05054
05055
05056
05057
05058
05059
05060 TextureCollection NodePath::
05061 find_all_textures() const {
05062 nassertr_always(!is_empty(), TextureCollection());
05063 Textures textures;
05064 r_find_all_textures(node(), get_net_state(), textures);
05065
05066 TextureCollection tc;
05067 Textures::iterator ti;
05068 for (ti = textures.begin(); ti != textures.end(); ++ti) {
05069 tc.add_texture(*ti);
05070 }
05071 return tc;
05072 }
05073
05074
05075
05076
05077
05078
05079
05080
05081 TextureCollection NodePath::
05082 find_all_textures(const string &name) const {
05083 nassertr_always(!is_empty(), TextureCollection());
05084 Textures textures;
05085 r_find_all_textures(node(), get_net_state(), textures);
05086
05087 GlobPattern glob(name);
05088
05089 TextureCollection tc;
05090 Textures::iterator ti;
05091 for (ti = textures.begin(); ti != textures.end(); ++ti) {
05092 Texture *texture = (*ti);
05093 if (glob.matches(texture->get_name())) {
05094 tc.add_texture(texture);
05095 }
05096 }
05097 return tc;
05098 }
05099
05100
05101
05102
05103
05104
05105
05106
05107 TextureCollection NodePath::
05108 find_all_textures(TextureStage *stage) const {
05109 nassertr_always(!is_empty(), TextureCollection());
05110 Textures textures;
05111 r_find_all_textures(node(), stage, textures);
05112
05113 TextureCollection tc;
05114 Textures::iterator ti;
05115 for (ti = textures.begin(); ti != textures.end(); ++ti) {
05116 Texture *texture = (*ti);
05117 tc.add_texture(texture);
05118 }
05119 return tc;
05120 }
05121
05122
05123
05124
05125
05126
05127
05128
05129
05130
05131 TextureStage *NodePath::
05132 find_texture_stage(const string &name) const {
05133 nassertr_always(!is_empty(), NULL);
05134 GlobPattern glob(name);
05135 return r_find_texture_stage(node(), get_net_state(), glob);
05136 }
05137
05138
05139
05140
05141
05142
05143
05144 TextureStageCollection NodePath::
05145 find_all_texture_stages() const {
05146 nassertr_always(!is_empty(), TextureStageCollection());
05147 TextureStages texture_stages;
05148 r_find_all_texture_stages(node(), get_net_state(), texture_stages);
05149
05150 TextureStageCollection tc;
05151 TextureStages::iterator ti;
05152 for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
05153 tc.add_texture_stage(*ti);
05154 }
05155 return tc;
05156 }
05157
05158
05159
05160
05161
05162
05163
05164
05165
05166
05167
05168 void NodePath::
05169 unify_texture_stages(TextureStage *stage) {
05170 nassertv_always(!is_empty());
05171 r_unify_texture_stages(node(), stage);
05172 }
05173
05174
05175
05176
05177
05178
05179
05180
05181 TextureStageCollection NodePath::
05182 find_all_texture_stages(const string &name) const {
05183 nassertr_always(!is_empty(), TextureStageCollection());
05184 TextureStages texture_stages;
05185 r_find_all_texture_stages(node(), get_net_state(), texture_stages);
05186
05187 GlobPattern glob(name);
05188
05189 TextureStageCollection tc;
05190 TextureStages::iterator ti;
05191 for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
05192 TextureStage *texture_stage = (*ti);
05193 if (glob.matches(texture_stage->get_name())) {
05194 tc.add_texture_stage(texture_stage);
05195 }
05196 }
05197 return tc;
05198 }
05199
05200
05201
05202
05203
05204
05205
05206
05207
05208 Material *NodePath::
05209 find_material(const string &name) const {
05210 nassertr_always(!is_empty(), NULL);
05211 GlobPattern glob(name);
05212 return r_find_material(node(), get_net_state(), glob);
05213 }
05214
05215
05216
05217
05218
05219
05220
05221 MaterialCollection NodePath::
05222 find_all_materials() const {
05223 nassertr_always(!is_empty(), MaterialCollection());
05224 Materials materials;
05225 r_find_all_materials(node(), get_net_state(), materials);
05226
05227 MaterialCollection tc;
05228 Materials::iterator ti;
05229 for (ti = materials.begin(); ti != materials.end(); ++ti) {
05230 tc.add_material(*ti);
05231 }
05232 return tc;
05233 }
05234
05235
05236
05237
05238
05239
05240
05241
05242 MaterialCollection NodePath::
05243 find_all_materials(const string &name) const {
05244 nassertr_always(!is_empty(), MaterialCollection());
05245 Materials materials;
05246 r_find_all_materials(node(), get_net_state(), materials);
05247
05248 GlobPattern glob(name);
05249
05250 MaterialCollection tc;
05251 Materials::iterator ti;
05252 for (ti = materials.begin(); ti != materials.end(); ++ti) {
05253 Material *material = (*ti);
05254 if (glob.matches(material->get_name())) {
05255 tc.add_material(material);
05256 }
05257 }
05258 return tc;
05259 }
05260
05261
05262
05263
05264
05265
05266
05267
05268
05269
05270
05271 void NodePath::
05272 set_material(Material *mat, int priority) {
05273 nassertv_always(!is_empty());
05274 nassertv(mat != NULL);
05275 node()->set_attrib(MaterialAttrib::make(mat), priority);
05276 }
05277
05278
05279
05280
05281
05282
05283
05284
05285
05286
05287
05288 void NodePath::
05289 set_material_off(int priority) {
05290 nassertv_always(!is_empty());
05291 node()->set_attrib(MaterialAttrib::make_off(), priority);
05292 }
05293
05294
05295
05296
05297
05298
05299
05300
05301 void NodePath::
05302 clear_material() {
05303 nassertv_always(!is_empty());
05304 node()->clear_attrib(MaterialAttrib::get_class_slot());
05305 }
05306
05307
05308
05309
05310
05311
05312
05313 bool NodePath::
05314 has_material() const {
05315 nassertr_always(!is_empty(), false);
05316 const RenderAttrib *attrib =
05317 node()->get_attrib(MaterialAttrib::get_class_slot());
05318 if (attrib != (const RenderAttrib *)NULL) {
05319 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
05320 return !ma->is_off();
05321 }
05322
05323 return false;
05324 }
05325
05326
05327
05328
05329
05330
05331
05332
05333
05334
05335
05336
05337
05338 PT(Material) NodePath::
05339 get_material() const {
05340 nassertr_always(!is_empty(), NULL);
05341 const RenderAttrib *attrib =
05342 node()->get_attrib(MaterialAttrib::get_class_slot());
05343 if (attrib != (const RenderAttrib *)NULL) {
05344 const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
05345 return ma->get_material();
05346 }
05347
05348 return NULL;
05349 }
05350
05351
05352
05353
05354
05355
05356
05357 void NodePath::
05358 set_fog(Fog *fog, int priority) {
05359 nassertv_always(!is_empty());
05360 node()->set_attrib(FogAttrib::make(fog), priority);
05361 }
05362
05363
05364
05365
05366
05367
05368
05369
05370
05371
05372
05373 void NodePath::
05374 set_fog_off(int priority) {
05375 nassertv_always(!is_empty());
05376 node()->set_attrib(FogAttrib::make_off(), priority);
05377 }
05378
05379
05380
05381
05382
05383
05384
05385
05386
05387
05388 void NodePath::
05389 clear_fog() {
05390 nassertv_always(!is_empty());
05391 node()->clear_attrib(FogAttrib::get_class_slot());
05392 }
05393
05394
05395
05396
05397
05398
05399
05400
05401
05402
05403
05404 bool NodePath::
05405 has_fog() const {
05406 nassertr_always(!is_empty(), false);
05407 const RenderAttrib *attrib =
05408 node()->get_attrib(FogAttrib::get_class_slot());
05409 if (attrib != (const RenderAttrib *)NULL) {
05410 const FogAttrib *fa = DCAST(FogAttrib, attrib);
05411 return !fa->is_off();
05412 }
05413
05414 return false;
05415 }
05416
05417
05418
05419
05420
05421
05422
05423
05424
05425
05426
05427 bool NodePath::
05428 has_fog_off() const {
05429 nassertr_always(!is_empty(), false);
05430 const RenderAttrib *attrib =
05431 node()->get_attrib(FogAttrib::get_class_slot());
05432 if (attrib != (const RenderAttrib *)NULL) {
05433 const FogAttrib *fa = DCAST(FogAttrib, attrib);
05434 return fa->is_off();
05435 }
05436
05437 return false;
05438 }
05439
05440
05441
05442
05443
05444
05445
05446
05447
05448
05449
05450 Fog *NodePath::
05451 get_fog() const {
05452 nassertr_always(!is_empty(), NULL);
05453 const RenderAttrib *attrib =
05454 node()->get_attrib(FogAttrib::get_class_slot());
05455 if (attrib != (const RenderAttrib *)NULL) {
05456 const FogAttrib *fa = DCAST(FogAttrib, attrib);
05457 return fa->get_fog();
05458 }
05459
05460 return NULL;
05461 }
05462
05463
05464
05465
05466
05467
05468
05469 void NodePath::
05470 set_render_mode_wireframe(int priority) {
05471 nassertv_always(!is_empty());
05472 PN_stdfloat thickness = get_render_mode_thickness();
05473 bool perspective = get_render_mode_perspective();
05474 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, thickness, perspective), priority);
05475 }
05476
05477
05478
05479
05480
05481
05482
05483
05484 void NodePath::
05485 set_render_mode_filled(int priority) {
05486 nassertv_always(!is_empty());
05487 PN_stdfloat thickness = get_render_mode_thickness();
05488 bool perspective = get_render_mode_perspective();
05489 node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority);
05490 }
05491
05492
05493
05494
05495
05496
05497
05498
05499
05500
05501
05502
05503
05504
05505
05506
05507 void NodePath::
05508 set_render_mode_perspective(bool perspective, int priority) {
05509 nassertv_always(!is_empty());
05510 RenderModeAttrib::Mode mode = get_render_mode();
05511 PN_stdfloat thickness = get_render_mode_thickness();
05512 node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
05513 }
05514
05515
05516
05517
05518
05519
05520
05521
05522
05523
05524
05525
05526
05527
05528 void NodePath::
05529 set_render_mode_thickness(PN_stdfloat thickness, int priority) {
05530 nassertv_always(!is_empty());
05531 RenderModeAttrib::Mode mode = get_render_mode();
05532 bool perspective = get_render_mode_perspective();
05533 node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
05534 }
05535
05536
05537
05538
05539
05540
05541
05542
05543 void NodePath::
05544 set_render_mode(RenderModeAttrib::Mode mode, PN_stdfloat thickness, int priority) {
05545 nassertv_always(!is_empty());
05546
05547 node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority);
05548 }
05549
05550
05551
05552
05553
05554
05555
05556
05557
05558 void NodePath::
05559 clear_render_mode() {
05560 nassertv_always(!is_empty());
05561 node()->clear_attrib(RenderModeAttrib::get_class_slot());
05562 }
05563
05564
05565
05566
05567
05568
05569
05570
05571
05572 bool NodePath::
05573 has_render_mode() const {
05574 nassertr_always(!is_empty(), false);
05575 return node()->has_attrib(RenderModeAttrib::get_class_slot());
05576 }
05577
05578
05579
05580
05581
05582
05583
05584
05585 RenderModeAttrib::Mode NodePath::
05586 get_render_mode() const {
05587 nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged);
05588 const RenderAttrib *attrib =
05589 node()->get_attrib(RenderModeAttrib::get_class_slot());
05590 if (attrib != (const RenderAttrib *)NULL) {
05591 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05592 return ta->get_mode();
05593 }
05594
05595 return RenderModeAttrib::M_unchanged;
05596 }
05597
05598
05599
05600
05601
05602
05603
05604
05605 PN_stdfloat NodePath::
05606 get_render_mode_thickness() const {
05607 nassertr_always(!is_empty(), 0.0f);
05608 const RenderAttrib *attrib =
05609 node()->get_attrib(RenderModeAttrib::get_class_slot());
05610 if (attrib != (const RenderAttrib *)NULL) {
05611 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05612 return ta->get_thickness();
05613 }
05614
05615 return 1.0f;
05616 }
05617
05618
05619
05620
05621
05622
05623
05624
05625 bool NodePath::
05626 get_render_mode_perspective() const {
05627 nassertr_always(!is_empty(), 0.0f);
05628 const RenderAttrib *attrib =
05629 node()->get_attrib(RenderModeAttrib::get_class_slot());
05630 if (attrib != (const RenderAttrib *)NULL) {
05631 const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
05632 return ta->get_perspective();
05633 }
05634
05635 return false;
05636 }
05637
05638
05639
05640
05641
05642
05643
05644
05645
05646
05647 void NodePath::
05648 set_two_sided(bool two_sided, int priority) {
05649 nassertv_always(!is_empty());
05650
05651 CullFaceAttrib::Mode mode =
05652 two_sided ?
05653 CullFaceAttrib::M_cull_none :
05654 CullFaceAttrib::M_cull_clockwise;
05655
05656 node()->set_attrib(CullFaceAttrib::make(mode), priority);
05657 }
05658
05659
05660
05661
05662
05663
05664
05665
05666
05667
05668
05669
05670 void NodePath::
05671 clear_two_sided() {
05672 nassertv_always(!is_empty());
05673 node()->clear_attrib(CullFaceAttrib::get_class_slot());
05674 }
05675
05676
05677
05678
05679
05680
05681
05682
05683
05684
05685 bool NodePath::
05686 has_two_sided() const {
05687 nassertr_always(!is_empty(), false);
05688 return node()->has_attrib(CullFaceAttrib::get_class_slot());
05689 }
05690
05691
05692
05693
05694
05695
05696
05697
05698
05699
05700
05701
05702 bool NodePath::
05703 get_two_sided() const {
05704 nassertr_always(!is_empty(), false);
05705 const RenderAttrib *attrib =
05706 node()->get_attrib(CullFaceAttrib::get_class_slot());
05707 if (attrib != (const RenderAttrib *)NULL) {
05708 const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
05709 return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
05710 }
05711
05712 return false;
05713 }
05714
05715
05716
05717
05718
05719
05720
05721
05722
05723
05724 void NodePath::
05725 set_depth_test(bool depth_test, int priority) {
05726 nassertv_always(!is_empty());
05727
05728 DepthTestAttrib::PandaCompareFunc mode =
05729 depth_test ?
05730 DepthTestAttrib::M_less :
05731 DepthTestAttrib::M_none;
05732
05733 node()->set_attrib(DepthTestAttrib::make(mode), priority);
05734 }
05735
05736
05737
05738
05739
05740
05741
05742 void NodePath::
05743 clear_depth_test() {
05744 nassertv_always(!is_empty());
05745 node()->clear_attrib(DepthTestAttrib::get_class_slot());
05746 }
05747
05748
05749
05750
05751
05752
05753
05754
05755
05756
05757 bool NodePath::
05758 has_depth_test() const {
05759 nassertr_always(!is_empty(), false);
05760 return node()->has_attrib(DepthTestAttrib::get_class_slot());
05761 }
05762
05763
05764
05765
05766
05767
05768
05769
05770
05771
05772 bool NodePath::
05773 get_depth_test() const {
05774 nassertr_always(!is_empty(), false);
05775 const RenderAttrib *attrib =
05776 node()->get_attrib(DepthTestAttrib::get_class_slot());
05777 if (attrib != (const RenderAttrib *)NULL) {
05778 const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
05779 return (dta->get_mode() != DepthTestAttrib::M_none);
05780 }
05781
05782 return true;
05783 }
05784
05785
05786
05787
05788
05789
05790
05791
05792
05793
05794 void NodePath::
05795 set_depth_write(bool depth_write, int priority) {
05796 nassertv_always(!is_empty());
05797
05798 DepthWriteAttrib::Mode mode =
05799 depth_write ?
05800 DepthWriteAttrib::M_on :
05801 DepthWriteAttrib::M_off;
05802
05803 node()->set_attrib(DepthWriteAttrib::make(mode), priority);
05804 }
05805
05806
05807
05808
05809
05810
05811
05812 void NodePath::
05813 clear_depth_write() {
05814 nassertv_always(!is_empty());
05815 node()->clear_attrib(DepthWriteAttrib::get_class_slot());
05816 }
05817
05818
05819
05820
05821
05822
05823
05824
05825
05826
05827 bool NodePath::
05828 has_depth_write() const {
05829 nassertr_always(!is_empty(), false);
05830 return node()->has_attrib(DepthWriteAttrib::get_class_slot());
05831 }
05832
05833
05834
05835
05836
05837
05838
05839
05840
05841
05842 bool NodePath::
05843 get_depth_write() const {
05844 nassertr_always(!is_empty(), false);
05845 const RenderAttrib *attrib =
05846 node()->get_attrib(DepthWriteAttrib::get_class_slot());
05847 if (attrib != (const RenderAttrib *)NULL) {
05848 const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
05849 return (dta->get_mode() != DepthWriteAttrib::M_off);
05850 }
05851
05852 return true;
05853 }
05854
05855
05856
05857
05858
05859
05860
05861
05862
05863
05864
05865
05866
05867
05868
05869
05870 void NodePath::
05871 set_depth_offset(int bias, int priority) {
05872 nassertv_always(!is_empty());
05873
05874 node()->set_attrib(DepthOffsetAttrib::make(bias), priority);
05875 }
05876
05877
05878
05879
05880
05881
05882
05883 void NodePath::
05884 clear_depth_offset() {
05885 nassertv_always(!is_empty());
05886 node()->clear_attrib(DepthOffsetAttrib::get_class_slot());
05887 }
05888
05889
05890
05891
05892
05893
05894
05895
05896
05897
05898 bool NodePath::
05899 has_depth_offset() const {
05900 nassertr_always(!is_empty(), false);
05901 return node()->has_attrib(DepthOffsetAttrib::get_class_slot());
05902 }
05903
05904
05905
05906
05907
05908
05909
05910 int NodePath::
05911 get_depth_offset() const {
05912 nassertr_always(!is_empty(), 0);
05913 const RenderAttrib *attrib =
05914 node()->get_attrib(DepthOffsetAttrib::get_class_slot());
05915 if (attrib != (const RenderAttrib *)NULL) {
05916 const DepthOffsetAttrib *doa = DCAST(DepthOffsetAttrib, attrib);
05917 return doa->get_offset();
05918 }
05919
05920 return 0;
05921 }
05922
05923
05924
05925
05926
05927
05928
05929
05930 void NodePath::
05931 do_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
05932 nassertv_always(!is_empty());
05933
05934 CPT(TransformState) transform = camera.get_transform(get_parent());
05935 const LMatrix4 &rel_mat = transform->get_mat();
05936
05937 LVector3 up = LVector3::up();
05938 LVector3 rel_pos = -rel_mat.get_row3(3);
05939
05940 LQuaternion quat;
05941 ::heads_up(quat, rel_pos, up);
05942 set_quat(quat);
05943
05944
05945
05946 if (offset != 0.0f) {
05947 LVector3 translate = rel_mat.get_row3(3);
05948 translate.normalize();
05949 translate *= offset;
05950 set_pos(translate);
05951 }
05952 }
05953
05954
05955
05956
05957
05958
05959
05960
05961
05962
05963 void NodePath::
05964 do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
05965 nassertv_always(!is_empty());
05966
05967 CPT(TransformState) transform = camera.get_transform(get_parent());
05968 const LMatrix4 &rel_mat = transform->get_mat();
05969
05970 LVector3 up = LVector3::up() * rel_mat;
05971 LVector3 rel_pos = LVector3::forward() * rel_mat;
05972
05973 LQuaternion quat;
05974 ::look_at(quat, rel_pos, up);
05975 set_quat(quat);
05976
05977
05978
05979 if (offset != 0.0f) {
05980 LVector3 translate = rel_mat.get_row3(3);
05981 translate.normalize();
05982 translate *= offset;
05983 set_pos(translate);
05984 }
05985 }
05986
05987
05988
05989
05990
05991
05992
05993
05994 void NodePath::
05995 do_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
05996 nassertv_always(!is_empty());
05997
05998 CPT(TransformState) transform = camera.get_transform(get_parent());
05999 const LMatrix4 &rel_mat = transform->get_mat();
06000
06001 LVector3 up = LVector3::up();
06002 LVector3 rel_pos = -rel_mat.get_row3(3);
06003
06004 LQuaternion quat;
06005 ::look_at(quat, rel_pos, up);
06006 set_quat(quat);
06007
06008
06009
06010 if (offset != 0.0f) {
06011 LVector3 translate = rel_mat.get_row3(3);
06012 translate.normalize();
06013 translate *= offset;
06014 set_pos(translate);
06015 }
06016 }
06017
06018
06019
06020
06021
06022
06023
06024
06025
06026 void NodePath::
06027 set_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
06028 nassertv_always(!is_empty());
06029 CPT(RenderEffect) billboard = BillboardEffect::make
06030 (LVector3::up(), false, true,
06031 offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06032 node()->set_effect(billboard);
06033 }
06034
06035
06036
06037
06038
06039
06040
06041
06042
06043
06044 void NodePath::
06045 set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
06046 nassertv_always(!is_empty());
06047 CPT(RenderEffect) billboard = BillboardEffect::make
06048 (LVector3::up(), true, false,
06049 offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06050 node()->set_effect(billboard);
06051 }
06052
06053
06054
06055
06056
06057
06058
06059
06060
06061 void NodePath::
06062 set_billboard_point_world(const NodePath &camera, PN_stdfloat offset) {
06063 nassertv_always(!is_empty());
06064 CPT(RenderEffect) billboard = BillboardEffect::make
06065 (LVector3::up(), false, false,
06066 offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
06067 node()->set_effect(billboard);
06068 }
06069
06070
06071
06072
06073
06074
06075 void NodePath::
06076 clear_billboard() {
06077 nassertv_always(!is_empty());
06078 node()->clear_effect(BillboardEffect::get_class_type());
06079 }
06080
06081
06082
06083
06084
06085
06086
06087 bool NodePath::
06088 has_billboard() const {
06089 nassertr_always(!is_empty(), false);
06090 return node()->has_effect(BillboardEffect::get_class_type());
06091 }
06092
06093
06094
06095
06096
06097
06098
06099
06100
06101 void NodePath::
06102 set_compass(const NodePath &reference) {
06103 nassertv_always(!is_empty());
06104 node()->set_effect(CompassEffect::make(reference));
06105 }
06106
06107
06108
06109
06110
06111
06112 void NodePath::
06113 clear_compass() {
06114 nassertv_always(!is_empty());
06115 node()->clear_effect(CompassEffect::get_class_type());
06116 }
06117
06118
06119
06120
06121
06122
06123
06124 bool NodePath::
06125 has_compass() const {
06126 nassertr_always(!is_empty(), false);
06127 return node()->has_effect(CompassEffect::get_class_type());
06128 }
06129
06130
06131
06132
06133
06134
06135
06136
06137
06138 void NodePath::
06139 set_transparency(TransparencyAttrib::Mode mode, int priority) {
06140 nassertv_always(!is_empty());
06141
06142 node()->set_attrib(TransparencyAttrib::make(mode), priority);
06143 }
06144
06145
06146
06147
06148
06149
06150
06151
06152
06153
06154
06155 void NodePath::
06156 clear_transparency() {
06157 nassertv_always(!is_empty());
06158 node()->clear_attrib(TransparencyAttrib::get_class_slot());
06159 }
06160
06161
06162
06163
06164
06165
06166
06167
06168
06169
06170
06171 bool NodePath::
06172 has_transparency() const {
06173 nassertr_always(!is_empty(), false);
06174 return node()->has_attrib(TransparencyAttrib::get_class_slot());
06175 }
06176
06177
06178
06179
06180
06181
06182
06183
06184
06185
06186
06187
06188 TransparencyAttrib::Mode NodePath::
06189 get_transparency() const {
06190 nassertr_always(!is_empty(), TransparencyAttrib::M_none);
06191 const RenderAttrib *attrib =
06192 node()->get_attrib(TransparencyAttrib::get_class_slot());
06193 if (attrib != (const RenderAttrib *)NULL) {
06194 const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
06195 return ta->get_mode();
06196 }
06197
06198 return TransparencyAttrib::M_none;
06199 }
06200
06201
06202
06203
06204
06205
06206
06207 void NodePath::
06208 set_antialias(unsigned short mode, int priority) {
06209 nassertv_always(!is_empty());
06210
06211 node()->set_attrib(AntialiasAttrib::make(mode), priority);
06212 }
06213
06214
06215
06216
06217
06218
06219
06220 void NodePath::
06221 clear_antialias() {
06222 nassertv_always(!is_empty());
06223 node()->clear_attrib(AntialiasAttrib::get_class_slot());
06224 }
06225
06226
06227
06228
06229
06230
06231
06232
06233
06234
06235 bool NodePath::
06236 has_antialias() const {
06237 nassertr_always(!is_empty(), false);
06238 return node()->has_attrib(AntialiasAttrib::get_class_slot());
06239 }
06240
06241
06242
06243
06244
06245
06246
06247
06248 unsigned short NodePath::
06249 get_antialias() const {
06250 nassertr_always(!is_empty(), AntialiasAttrib::M_none);
06251 const RenderAttrib *attrib =
06252 node()->get_attrib(AntialiasAttrib::get_class_slot());
06253 if (attrib != (const RenderAttrib *)NULL) {
06254 const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib);
06255 return ta->get_mode();
06256 }
06257
06258 return AntialiasAttrib::M_none;
06259 }
06260
06261
06262
06263
06264
06265
06266
06267
06268
06269 bool NodePath::
06270 has_audio_volume() const {
06271 nassertr_always(!is_empty(), false);
06272 return node()->has_attrib(AudioVolumeAttrib::get_class_slot());
06273 }
06274
06275
06276
06277
06278
06279
06280
06281
06282
06283
06284 void NodePath::
06285 clear_audio_volume() {
06286 nassertv_always(!is_empty());
06287 node()->clear_attrib(AudioVolumeAttrib::get_class_slot());
06288 }
06289
06290
06291
06292
06293
06294
06295 void NodePath::
06296 set_audio_volume(PN_stdfloat volume, int priority) {
06297 nassertv_always(!is_empty());
06298
06299 const RenderAttrib *attrib =
06300 node()->get_attrib(AudioVolumeAttrib::get_class_slot());
06301 if (attrib != (const RenderAttrib *)NULL) {
06302 priority = max(priority,
06303 node()->get_state()->get_override(AudioVolumeAttrib::get_class_slot()));
06304 CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib);
06305
06306
06307
06308 node()->set_attrib(ava->set_volume(volume), priority);
06309
06310 } else {
06311
06312 node()->set_attrib(AudioVolumeAttrib::make(volume), priority);
06313 }
06314 }
06315
06316
06317
06318
06319
06320
06321
06322
06323
06324
06325
06326
06327
06328
06329
06330 void NodePath::
06331 set_audio_volume_off(int priority) {
06332 nassertv_always(!is_empty());
06333 node()->set_attrib(AudioVolumeAttrib::make_off(), priority);
06334 }
06335
06336
06337
06338
06339
06340
06341
06342
06343
06344 PN_stdfloat NodePath::
06345 get_audio_volume() const {
06346 const RenderAttrib *attrib =
06347 node()->get_attrib(AudioVolumeAttrib::get_class_slot());
06348 if (attrib != (const RenderAttrib *)NULL) {
06349 const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
06350 return ava->get_volume();
06351 }
06352
06353 return 1.0f;
06354 }
06355
06356
06357
06358
06359
06360
06361
06362 PN_stdfloat NodePath::
06363 get_net_audio_volume() const {
06364 CPT(RenderState) net_state = get_net_state();
06365 const RenderAttrib *attrib = net_state->get_attrib(AudioVolumeAttrib::get_class_slot());
06366 if (attrib != (const RenderAttrib *)NULL) {
06367 const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
06368 if (ava != (const AudioVolumeAttrib *)NULL) {
06369 return ava->get_volume();
06370 }
06371 }
06372
06373 return 1.0f;
06374 }
06375
06376
06377
06378
06379
06380
06381
06382
06383
06384 NodePath NodePath::
06385 get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const {
06386 int pipeline_stage = current_thread->get_pipeline_stage();
06387
06388 NodePathComponent *comp;
06389 for (comp = _head;
06390 comp != (NodePathComponent *)NULL;
06391 comp = comp->get_next(pipeline_stage, current_thread)) {
06392 PandaNode *node = comp->get_node();
06393 if (node->is_overall_hidden() ||
06394 ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
06395 NodePath result;
06396 result._head = comp;
06397 return result;
06398 }
06399 }
06400
06401 return not_found();
06402 }
06403
06404
06405
06406
06407
06408
06409
06410
06411
06412
06413
06414
06415
06416
06417
06418
06419 void NodePath::
06420 stash(int sort, Thread *current_thread) {
06421 nassertv_always(!is_singleton() && !is_empty());
06422 nassertv(verify_complete());
06423
06424 int pipeline_stage = current_thread->get_pipeline_stage();
06425 bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
06426 _head, sort, true, pipeline_stage,
06427 current_thread);
06428 nassertv(reparented);
06429 }
06430
06431
06432