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