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